AnsibleModule.preserved_copy() results in module fail: Error while setting attributes: /usr/bin/chattr: Inappropriate ioctl for device while reading flags on /tmp/id_rsa_test
Summary
(See also https://github.com/ansible-collections/community.crypto/issues/416.)
When AnsibleModule.preserved_copy() is used to copy /home/$USER/.ansible/tmp/ansible-moduletmp-1646554294.130125-ln2tz3k4/id_rsa_test to /tmp/id_rsa_test, while the former is on a regular ext4 filesystem and the latter on tmpfs, the Set the attributes step of preserved_copy() fails with Error while setting attributes: /usr/bin/chattr: Operation not supported while reading flags on /tmp/id_rsa_test\n while trying to execute /usr/bin/chattr =e /tmp/id_rsa_test.
Issue Type
Bug Report
Component Name
lib/ansible/module_utils/basic.py
Ansible Version
latest devel branch
Configuration
nothing changed
OS / Environment
Arch Linux, apparently also happens on Fedora 34
Steps to Reproduce
Make sure that /tmp is a tmpfs; if not, adjust the path to something that's on a tmpfs!
- hosts: localhost
gather_facts: false
vars:
ssh_key_path: "/tmp/id_rsa_test" # must be on a tmpfs!
tasks:
- file:
path: "{{ item }}"
state: absent
loop:
- "{{ ssh_key_path }}"
- "{{ ssh_key_path }}.pub"
- name: Generate temporary ssh keys
openssh_keypair:
path: "{{ ssh_key_path }}"
(Requires community.crypto.)
I don't see how to reproduce this with ansible-core only, since preserved_copy() isn't used in any ansible-core module or plugin (except indirectly in backup_local(), but there the copy is inside the same directory, i.e. not across filesystems).
Expected Results
Runs through.
Actual Results
TASK [Generate temporary ssh keys] ***********************************************************************************************************************************************************
task path: /path/to/test-openssh-failure.yml:12
redirecting (type: modules) ansible.builtin.openssh_keypair to community.crypto.openssh_keypair
Using module file /path/to/ansible_collections/community/crypto/plugins/modules/openssh_keypair.py
Pipelining is enabled.
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: me
<localhost> EXEC /bin/sh -c '/usr/bin/python3.10 && sleep 0'
The full traceback is:
Traceback (most recent call last):
File "/tmp/ansible_openssh_keypair_payload_pwkqx5x0/ansible_openssh_keypair_payload.zip/ansible/module_utils/basic.py", line 1002, in set_attributes_if_different
raise Exception("Error while setting attributes: %s" % (out + err))
Exception: Error while setting attributes: /usr/bin/chattr: Operation not supported while reading flags on /tmp/id_rsa_test
fatal: [localhost]: FAILED! => {
"changed": false,
"details": "Error while setting attributes: /usr/bin/chattr: Operation not supported while reading flags on /tmp/id_rsa_test\n",
"gid": 1000,
"group": "me",
"invocation": {
"module_args": {
"attributes": null,
"backend": "auto",
"comment": null,
"force": false,
"group": null,
"mode": null,
"owner": null,
"passphrase": null,
"path": "/tmp/id_rsa_test",
"private_key_format": "auto",
"regenerate": "partial_idempotence",
"selevel": null,
"serole": null,
"setype": null,
"seuser": null,
"size": null,
"state": "present",
"type": "rsa",
"unsafe_writes": false
}
},
"mode": "0600",
"msg": "chattr failed",
"owner": "me",
"path": "/tmp/id_rsa_test",
"size": 3357,
"state": "file",
"uid": 1000
}
Code of Conduct
- [X] I agree to follow the Ansible Code of Conduct
Files identified in the description:
If these files are incorrect, please update the component name section of the description or use the !component bot command.
I verified that copying from tmpfs to itself does not fail, both with copy's backup functionality and by setting ansible_remote_tmp to /tmp for the reproducer.
@felixfontein Do you have any thoughts on how this should be fixed?
I think maybe just a documentation update to indicate that this method is not guaranteed to succeed for cross-filesystem file copies would be fine (since it preserves features which are outside the scope of POSIX compliance). In the case of community.crypto.openssh_keypair I don't really require the full feature set of preserved_copy so I can implement a limited version there.
Is there any activity on this issue?
may be fixed by https://github.com/ansible/ansible/pull/78707?
@nitzmahone maybe in some very specific situations, but in general it is not. I've just tried running ansible-test integration --docker alpine3 openssh_cert in community.crypto with d0d99c31b0001f3df9828cace1e5b0f176c0b04f reverted, and with 78707 applied to ansible-core, and it is still failing.
Sounds like we might just need to make the extended attributes part "best effort", since IIUC there's no definitive and portable way to ensure that the underlying filesystem and security environment allows extended attributes without just setting one. For most one-way cases I doubt this would be a problem, but if a module expects to round-trip changes through a tempdir this way (eg, copy to tempdir preserving attributes, make changes, copy back), it could be a big problem.
In the round-trip case, the existing API is insufficient- it just can't be done atomically without silently ignoring attribute loss. This could be done generically though with a context manager that samples the source file attributes, yields to $code_hacking_on_temp_copy, then copies it back on successful exit and reapplies the stored attributes in place.
reproduces too. MacOs BigSur ansible core 2.14.4 community.crypto 2.12.0