0

I have an Ansible playbook where one task adds a SELinux file context and the following tasks is supposed to use that new context - i.e. fix the file context of a directory if necessary.

When I run the playbook it looks like the second task still uses the old file context policy. That means it doesn't fix the directory's context as expected. Only after I run the playback a second time the context is fixed.

Example output from first run:

TASK [web : add file contexts] ****
# Addition to semanage file context mappings
+/srv/fubar(/.*)?      a      system_u:object_r:httpd_sys_content_t:s0
changed: [example.org]

TASK [create webroot] **********
--- before
+++ after
@@ -1,7 +1,7 @@
 {
     "path": "/srv/fubar",
     "secontext": [
-        "unconfined_u",
+        "system_u",
         "object_r",
         "var_t",
         "s0"

changed: [example.org]

Whereas the immediate playbook re-execution yields:

TASK [web : add file contexts] ****
ok: [example.org]

TASK [create webroot] *******
--- before
+++ after
@@ -3,7 +3,7 @@
     "secontext": [
         "system_u",
         "object_r",
-        "var_t",
+        "httpd_sys_content_t",
         "s0"
     ]
 }

changed: [example.org]

Further executions don't yield any changes, as expected.

The Ansible tasks look like this:

- name: add file contexts
  sefcontext:
      target: '/srv/fubar(/.*)?'
      setype: httpd_sys_content_t
      state: present

- name: create webroot
  file:
      state: directory
      dest: /srv/fubar
      owner: juser
      group: juser
      mode: '0755'
      setype: _default
      seuser: _default

What am I missing here?

Is there some race-condition when updating the SELinux file contexts like that, in general?

When looking it the log files, there is some SELinux message saying that the policy was reloaded - right before the next task is executed, though. This matches also the sefcontext module documentation which states that SELinux policy reload is enabled, by default.

0

It really depends on how Ansible is invoked.

Even with SSH multiplexing (enabled by default) and SSH-pipelining (often recommended), Ansible (as of 2.9.11) re-logins and runs each task in a new Python process.

In that environment, the added file context is immediately visible in the file task.

However, when you run the playbook with the Mitogen connection plugin enabled, the consecutive tasks are executed in the same Python process. And then the file context change is actually cached at the process level.

It's cached because Ansible calls selinux.matchpathcon() (in selinux_default_context(), module_utils/basic.py) to get the default file context. It turns out that matchpathcon() is deprecated and internally caches all file contexts on the first call. A possible fix would be for the sefcontext module to call selinux.matchpathcon_fini() after it invokes the policy reload.

This happens with the Mitogen connection plugin because it's very good at reusing ssh connections and python processes. Which is a good thing because this dramatically speeds up playbook execution.

See Also

Similar issue in Puppet - since Puppet runs as an agent - all tasks always run in the same process - and Puppet also used the matchpathcon() API without flushing its cache when file contexts changed in the system's SELinux policy.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.