Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error "invalid selinux context" with template module and NFS #56243

Closed
netoarmando opened this issue May 8, 2019 · 14 comments · Fixed by #73625
Closed

Error "invalid selinux context" with template module and NFS #56243

netoarmando opened this issue May 8, 2019 · 14 comments · Fixed by #73625
Labels
affects_2.7 This issue/PR affects Ansible v2.7 bug This issue/PR relates to a bug. files Files category has_pr This issue has an associated PR. module This issue/PR relates to a module. python3 support:core This issue/PR relates to code supported by the Ansible Engineering Team. traceback This issue/PR includes a traceback.

Comments

@netoarmando
Copy link

SUMMARY
ISSUE TYPE
  • Bug Report
COMPONENT NAME

template module

ANSIBLE VERSION
ansible 2.7.10
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/neto/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.7.3 (default, Mar 27 2019, 13:41:07) [GCC 8.3.1 20190223 (Red Hat 8.3.1-2)]

CONFIGURATION

OS / ENVIRONMENT

Target host running Fedora 30 with SELinux permissive using Python 3 as interpreter

STEPS TO REPRODUCE
  1. Install Fedora 30
  2. Enable SELinux permissive mode
  3. Mount a NFS share
  4. Use template module to write a file in the mounted folder

Vagrant box used to reproduce this issue is available here: https://github.com/netoarmando/test-ansible-selinux

EXPECTED RESULTS

template module must succeed when writing files in NFS shares.

ACTUAL RESULTS
The full traceback is:
  File "/tmp/ansible_copy_payload_q0polhg6/ansible_copy_payload.zip/ansible/module_utils/basic.py", line 1172, in set_context_if_different
    rc = selinux.lsetfilecon(to_native(path), ':'.join(new_context))

fatal: [controller]: FAILED! => {
    "changed": false,
    "checksum": "03aa7e6652d3763d67a347f4ec38f4e80debd07e",
    "cur_context": [
        "system_u",
        "object_r",
        "nfs_t",
        "s0"
    ],
    "diff": [],
    "gid": 0,
    "group": "root",
    "input_was": [
        "system_u",
        "object_r",
        "default_t",
        "s0"
    ],
    "invocation": {
        "module_args": {
            "_original_basename": "ipa-test-config.yaml",
            "attributes": null,
            "backup": false,
            "checksum": "03aa7e6652d3763d67a347f4ec38f4e80debd07e",
            "content": null,
            "delimiter": null,
            "dest": "/vagrant/ipa-test-config.yaml",
            "directory_mode": null,
            "follow": false,
            "force": true,
            "group": null,
            "local_follow": null,
            "mode": null,
            "owner": null,
            "regexp": null,
            "remote_src": null,
            "selevel": null,
            "serole": null,
            "setype": null,
            "seuser": null,
            "src": "/root/.ansible/tmp/ansible-tmp-1556823099.449505-247067662862790/source",
            "unsafe_writes": null,
            "validate": null
        }
    },
    "mode": "0744",
    "msg": "invalid selinux context: [Errno 95] Operation not supported",
    "new_context": [
        "system_u",
        "object_r",
        "default_t",
        "s0"
    ],
    "owner": "root",
    "path": "/vagrant/.ansible_tmp06fx5ot7ipa-test-config.yaml",
    "secontext": "system_u:object_r:nfs_t:s0",
    "size": 607,
    "state": "file",
    "uid": 0
}

Possibly related to issues #29685 and #29728.

@ansibot
Copy link
Contributor

ansibot commented May 8, 2019

Files identified in the description:

If these files are inaccurate, please update the component name section of the description or use the !component bot command.

click here for bot help

@ansibot ansibot added affects_2.7 This issue/PR affects Ansible v2.7 bug This issue/PR relates to a bug. files Files category module This issue/PR relates to a module. needs_triage Needs a first human triage before being processed. python3 support:core This issue/PR relates to code supported by the Ansible Engineering Team. traceback This issue/PR includes a traceback. labels May 8, 2019
@jillr jillr added needs_verified This issue needs to be verified/reproduced by maintainer and removed needs_triage Needs a first human triage before being processed. labels May 16, 2019
@coltsixshooter
Copy link

Just upgraded to Red Hat 8.1 and using ansible 2.9.1 with python 3.6.8 and having the same issue writing (copy module) to NFS file system with SELinux. Anyone have a solution?

@tmiller02
Copy link

I seem to also be having this issue with Ansible 2.9.2 and Python 3.6.8 running on CentOS 8.

In my case I am seeing the same error message when attempting to template a file on a vagrant mount, ie a vboxsf filesystem, one of the 'special' SELinuxfs file systems already defined in DEFAULT_SELINUX_SPECIAL_FS.

I've had a bit of a look into this, my suspicion is that the is_special_selinux_path method is always returning a False tuple, even when it should be returning a True tuple.

When attempting to template a new file, the value of path_mount_point in the is_special_selinux_path method is set by:

path_mount_point = self.find_mount_point(path)

It seems that when templating a new file, this variable appears to be in bytes (for my particular case this was b'/opt/my_project_backend/current').

However, the values of mount_point that are obtained from reading /proc/mounts are strings (in my case this is '/opt/my_project_backend/current').

So the conditional that determines whether the mounts match (if path_mount_point == mount_point) appears to always be false, since it's making a direct comparison between bytes and strings.

Once I hacked this method to coerce path_mount_point into a string, ie:

if isinstance(path_mount_point, bytes):
    path_mount_point = path_mount_point.decode('utf-8') 
if path_mount_point == mount_point:
   ...

then this appears to fix the invalid selinux context: [Errno 95] Operation not supported error I was encountering, and I could then write the templated file into the vagrant mount successfully.

Interestingly enough, path_mount_point only appears to be bytes when writing a new template. When running this task a second time once the templated file has been added to the host, then this variable does appear to be a string.

@tmiller02
Copy link

One workaround for this issue seems to be to ensure that the destination file already exists before using the 'template' module, eg:

- name: ensure file already exists at template dest to work around 'invalid selinux context' issue
  file:
    path: "/opt/my_project_backend/current/settings.env"
    state: touch

- name: template settings into the new release path
  template:
    src: settings.env.j2
    dest: "/opt/my_project_backend/current/settings.env"

This seems to work for me with both vboxsf and nfs mount types.

I suspect one other workaround to investigate could be to try running ansible using python 2 if your operating system still has that available.

@tervor
Copy link

tervor commented Jan 2, 2020

@tmiller02 Thanks for the workaround. This also helped me to work around the issue. Can you possibly create a pull request with the changes mentioned above in the code?

@lexxxel
Copy link

lexxxel commented Mar 24, 2020

I do have the same issue with awx under centos 7

@bluikko
Copy link
Contributor

bluikko commented Apr 8, 2020

@tmiller02 in CentOS 7, for me this problem happens only with python 3. It works normally with python 2.

I cannot believe that this bug has not gotten higher attention. For almost 1 year the template module needs a workaround to create the file first?
Either python 3 is not used much or people have turned SELinux off are the only reasons I can think of.

@bluikko
Copy link
Contributor

bluikko commented Apr 13, 2020

I do not think this SELinux problem is restricted to NFS.

Any file that I am creating with the template module does not get labeled according to SELinux file contexts -- they always get the same context from the temporary file location: admin_home_t.

@ansibot ansibot added the has_pr This issue has an associated PR. label Apr 13, 2020
@ansibot
Copy link
Contributor

ansibot commented May 16, 2020

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.

click here for bot help

@gdsotirov
Copy link

For the record I just had this problem with Ansible 2.9.12 and Python 3.6.8 on CentOS 8.2.2004 - trying to create a README file with some content using the copy module after disabling SELinux with selinux module fails with error "invalid selinux context: [Errno 95] Operation not supported". Doing the same operation on the console does not fail. The workaround suggested by @tmiller02 works from me, but I wonder why this problem was not paid more attention and it's strange for me that it's still not fixed.

@bluikko
Copy link
Contributor

bluikko commented Oct 16, 2020

Move fast, break things......

@jnm27
Copy link

jnm27 commented Feb 16, 2021

What is the ETA on this fix?

@bcoca
Copy link
Member

bcoca commented Feb 16, 2021

does this patch fix the issue?

diff --git a/lib/ansible/module_utils/basic.py b/lib/ansible/module_utils/basic.py
index ad608415d8..28a8ed89cf 100644
--- a/lib/ansible/module_utils/basic.py
+++ b/lib/ansible/module_utils/basic.py
@@ -735,17 +735,12 @@ class AnsibleModule(object):
         return (uid, gid)

     def find_mount_point(self, path):
-        path_is_bytes = False
-        if isinstance(path, binary_type):
-            path_is_bytes = True
+        ''' returns unicode string of mount point '''

         b_path = os.path.realpath(to_bytes(os.path.expanduser(os.path.expandvars(path)), errors='surrogate_or_strict'))
         while not os.path.ismount(b_path):
             b_path = os.path.dirname(b_path)

-        if path_is_bytes:
-            return b_path
-
         return to_text(b_path, errors='surrogate_or_strict')

     def is_special_selinux_path(self, path):```

@jnm27
Copy link

jnm27 commented Feb 16, 2021

Yes it does. Thank you!

@ansible ansible locked and limited conversation to collaborators Mar 24, 2021
@sivel sivel removed the needs_verified This issue needs to be verified/reproduced by maintainer label Feb 3, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affects_2.7 This issue/PR affects Ansible v2.7 bug This issue/PR relates to a bug. files Files category has_pr This issue has an associated PR. module This issue/PR relates to a module. python3 support:core This issue/PR relates to code supported by the Ansible Engineering Team. traceback This issue/PR includes a traceback.
Projects
None yet
Development

Successfully merging a pull request may close this issue.