SELinux and Puppet Subcommands

162 views
Skip to first unread message

Joshua Partlow

unread,
Aug 27, 2014, 3:00:49 PM8/27/14
to puppe...@googlegroups.com
Hi everyone,

There is a PR for Puppet to address difficulties setting security contexts in SELinux for specific puppet subcommands (https://github.com/puppetlabs/puppet/pull/2997). The contributer (Lukáš Zapletal) originally was looking to add additional wrapper scripts around subcommands so that a puppet_exec_t could be set for these files.  There is general concern about the confusion caused by reintroducing separate commands, and Dominic Cleal suggested making use of Ruby's SELinux bindings (specifically Puppet::Util::SELinux.setcon in Puppet) to instead handle the context switch internally.

Talking this over during the triage today, this seems like a reasonable approach, but we're lacking SELinux experience, and were wondering if there were additional Puppet/SELinux users out there who might weigh in on this?

thanks,
Josh

--
Josh Partlow
jpar...@puppetlabs.com
Developer, Puppet Labs

Join us at PuppetConf 2014, September 20-24 in San Francisco
Register by September 8th to take advantage of the Final Countdown —save $149!

Dominic Cleal

unread,
Aug 28, 2014, 5:01:18 AM8/28/14
to puppe...@googlegroups.com
On 27/08/14 20:00, Joshua Partlow wrote:
> Hi everyone,
>
> There is a PR for Puppet to address difficulties setting security
> contexts in SELinux for specific puppet subcommands
> (https://github.com/puppetlabs/puppet/pull/2997). The contributer (Lukáš
> Zapletal) originally was looking to add additional wrapper scripts
> around subcommands so that a puppet_exec_t could be set for these files.
> There is general concern about the confusion caused by reintroducing
> separate commands, and Dominic Cleal suggested making use of Ruby's
> SELinux bindings (specifically Puppet::Util::SELinux.setcon in Puppet)
> to instead handle the context switch internally.

If taking this approach, I think there are two important points.

1. the context switch should be made as soon as possible, to minimise
the window when running unconfined. In particular I think we should
avoid reading in config files at this stage, if that's possible.

It looks like the Puppet::Util::CommandLine code isn't going to load
configs yet, so changing context within here (e.g.
ApplicationSubcommand) or perhaps inside Puppet::Application is possible.

2. names of SELinux domains are most likely governed by the distribution
rather than the Puppet project, as at least in Fedora and EL, an SELinux
policy for Puppet is shipped as part of the base targeted policy and not
as part of Puppet.

This means that Puppet should probably ship with a sane suggestion of
SELinux domains to transition to (e.g. the master application runs in
the puppetmaster_t domain), but packagers may want to be able to
override it relatively easily - perhaps this is a patch, but perhaps
something more like a config file containing a lookup table would be
easier to maintain.

Cheers,

--
Dominic Cleal
Red Hat Engineering

Dominic Cleal

unread,
Aug 28, 2014, 5:13:14 AM8/28/14
to puppe...@googlegroups.com
On 28/08/14 10:01, Dominic Cleal wrote:
> 2. names of SELinux domains are most likely governed by the distribution
> rather than the Puppet project, as at least in Fedora and EL, an SELinux
> policy for Puppet is shipped as part of the base targeted policy and not
> as part of Puppet.
>
> This means that Puppet should probably ship with a sane suggestion of
> SELinux domains to transition to (e.g. the master application runs in
> the puppetmaster_t domain), but packagers may want to be able to
> override it relatively easily - perhaps this is a patch, but perhaps
> something more like a config file containing a lookup table would be
> easier to maintain.

An addendum: if a user installs Puppet from a gem or source (for
instance) onto an OS release that doesn't have a working policy for that
version of Puppet, they will probably want to disable the context
switch. Config of this sort, or a command line argument might work?

Lukáš Zapletal

unread,
Aug 28, 2014, 3:39:11 PM8/28/14
to puppe...@googlegroups.com
An addendum: if a user installs Puppet from a gem or source (for
instance) onto an OS release that doesn't have a working policy for that
version of Puppet, they will probably want to disable the context
switch.  Config of this sort, or a command line argument might work?

This is contradictory to your context switch before reading config suggestion.

I think when using a gem install, no SELinux transition should be ever commited. It is not expected to have SELinux protection for gems. So by default this would be turned off and distributions would turn this on.

As you suggest, if this (and the domains to transition into) are in a separate "support" file, this would make distribution patching piece of cake. This would require three "echo" commands in a SPEC file (turn on, domain for puppet master, domain for puppet ca).

This could be easily leveraged in Puppet Enterprise as well.

LZ

Dominic Cleal

unread,
Aug 29, 2014, 3:41:04 AM8/29/14
to puppe...@googlegroups.com
On 28/08/14 20:39, Lukáš Zapletal wrote:
> An addendum: if a user installs Puppet from a gem or source (for
> instance) onto an OS release that doesn't have a working policy for
> that
> version of Puppet, they will probably want to disable the context
> switch. Config of this sort, or a command line argument might work?
>
>
> This is contradictory to your context switch before reading config
> suggestion.

Indeed, to an extent. I was thinking of something more hard coded for
SELinux contexts, while ensuring a context switch before "puppet ...
--config [path]" allowed reading of arbitrary files

> I think when using a gem install, no SELinux transition should be ever
> commited. It is not expected to have SELinux protection for gems. So by
> default this would be turned off and distributions would turn this on.
>
> As you suggest, if this (and the domains to transition into) are in a
> separate "support" file, this would make distribution patching piece of
> cake. This would require three "echo" commands in a SPEC file (turn on,
> domain for puppet master, domain for puppet ca).

Yeah, that makes sense I think.

Lukáš Zapletal

unread,
Aug 29, 2014, 4:57:22 AM8/29/14
to puppe...@googlegroups.com
Indeed, to an extent.  I was thinking of something more hard coded for
SELinux contexts, while ensuring a context switch before "puppet ...
--config [path]" allowed reading of arbitrary files

I see. Let's see what folks like and I can work on the patch. We can do both so ditributors can specify sane defaults and users can fine-tune the transitions or turn them off.

LZ

Lukáš Zapletal

unread,
Sep 9, 2014, 11:03:11 AM9/9/14
to puppe...@googlegroups.com
Hello,

I filed a pull request with a draft code which is alighed with what Dominic proposed:


It does not introduce any new global command line parameters because I think it's an overkill. There are three env. variables which can be used to tune this up, but I think this would be rare cases.

LZ

Melissa Stone

unread,
Mar 26, 2015, 3:25:38 PM3/26/15
to puppe...@googlegroups.com
Hi all,

I just wanted to point out that Adrien brought up some interesting comments in the ticket for this discussion. So that response gets more exposure, I wanted to post it here:

From Adrien Thebo:

I've reviewed PR 3627 and the puppet-dev mailing list thread, and I think that this issue could use more discussion before we start merging things.

First off, it doesn't seem like a lot of other projects have to deal with this concern. Is this because the executable itself has a context set and the process itself doesn't need to know about the context?

Secondly, how will this impact the JVM? Since (AFAIK) the JVM runs as a single process with multiple services running in that process, is it even possible to switch the SELinux context without breaking everything else inside of the JVM?

And now for more implementation oriented questions:

SELinux domains

What domains do we need for Puppet + SELinux? What resources do they need access to?

Configuration via environment variables

The current pull request uses the following environment variables:

  • NO_PUPPET_SELINUX_DTRANS
  • PUPPET_SELINUX_MASTER_DOMAIN
  • PUPPET_SELINUX_CA_DOMAIN

Right now Puppet doesn't use ENV for configuration; it has a few trivial things like looking at 'PATH' and 'HOME' but doesn't read values out in order to configure itself. Using the environment to configure the SELinux context means that we have a new configuration mechanism that will not be documented along with other settings. Using environment variables for configuration means that if different values are needed, they won't "stick" - there's no way to always apply these settings without modifying init scripts or /etc/profile or the like.

This leads into...

Environment variables vs configuration via a file

Dominic Cleal indicated that we should change the SELinux context before we read any configuration files, which makes us need an alternate method of configuring SELinux, which the reason of running unconfined for as little time as possible. Why? Doing so makes it more challenging to handle configuration. Is it really that risky to run unconfined until we can read a config file to get SELinux settings? If we do run unconfined long enough to read a config file, what are the potential ramifications of running unconfined for this period?

Switching contexts for packaged installs vs gem installs

It was proposed that we don't switch SELinux contexts if Puppet was installed via a gem or run from source. This seems really challenging to implement.

Switching contexts for different users

If I'm developing on Puppet and standing up a test master as my own user, I really don't want SELinux turning itself on. How can we prevent this?

Opt-out vs opt-in

The current approach takes an opt-out approach to SELinux; if it's opt-in we avoid the issue of switching contexts for packaged installs vs gem installs. Is this a viable option?

Default values for SELinux domains

It was mentioned that we can isolate the default values for SELinux domains to an isolated file so that downstream vendors can just patch that file; I think this is a great idea. It seems a lot simpler than using environment variables.

Dominic Cleal

unread,
Mar 27, 2015, 5:49:14 AM3/27/15
to puppe...@googlegroups.com
On 26/03/15 19:25, Melissa Stone wrote:
> Hi all,
>
> I just wanted to point out that Adrien brought up some interesting
> comments in the ticket for this discussion. So that response gets more
> exposure, I wanted to post it here:
>
> From Adrien Thebo:
>
> I've reviewed PR 3627 and the puppet-dev mailing list thread, and I
> think that this issue could use more discussion before we start merging
> things.
>
> First off, it doesn't seem like a lot of other projects have to deal
> with this concern. Is this because the executable itself has a context
> set and the process itself doesn't need to know about the context?

Yes, that's the most common way. Having separate binaries helps a lot,
as they can be labelled differently.

> Secondly, how will this impact the JVM? Since (AFAIK) the JVM runs as a
> single process with multiple services running in that process, is it
> even possible to switch the SELinux context without breaking everything
> else inside of the JVM?

Indeed, I think a lot of these ideas are obsolete with a move towards
Puppet Server and the JVM as the process startup obviously changes
significantly. It probably isn't worth trying to confine the older Ruby
"puppet" binary now.

The SELinux context will be process-wide, so affects all services within
the JVM, so any policy that would be created would have to cover all
services that might run inside it.

> And now for more implementation oriented questions:
>
>
> SELinux domains
>
> What domains do we need for Puppet + SELinux? What resources do they
> need access to?

Confining anything that listens on the network should probably be the
priority, i.e. the master, as that's the main attack surface. A policy
would have to give access to any local state files it uses, config
files, modules, through to any network connections it makes too.

>
> Configuration via environment variables
>
> The current pull request uses the following environment variables:
>
> * NO_PUPPET_SELINUX_DTRANS
> * PUPPET_SELINUX_MASTER_DOMAIN
> * PUPPET_SELINUX_CA_DOMAIN
>
> Right now Puppet doesn't use ENV for configuration; it has a few trivial
> things like looking at 'PATH' and 'HOME' but doesn't read values out in
> order to configure itself. Using the environment to configure the
> SELinux context means that we have a new configuration mechanism that
> will not be documented along with other settings. Using environment
> variables for configuration means that if different values are needed,
> they won't "stick" - there's no way to always apply these settings
> without modifying init scripts or /etc/profile or the like.
>
> This leads into...
>
>
> Environment variables vs configuration via a file
>
> Dominic Cleal indicated that we should change the SELinux context before
> we read any configuration files, which makes us need an alternate method
> of configuring SELinux, which the reason of running unconfined for as
> little time as possible. Why? Doing so makes it more challenging to
> handle configuration. Is it really that risky to run unconfined until we
> can read a config file to get SELinux settings? If we do run unconfined
> long enough to read a config file, what are the potential ramifications
> of running unconfined for this period?

I suppose what we would want to avoid is a period in which something
external, such as a user on the network (probably not an issue) or some
untrusted code is loaded or executed that could access resources that
the server wouldn't have access to when confined.

As a hand waving example, if we loaded environments and executed custom
types, or configuration somehow referenced another file (/etc/shadow for
argument's sake) which was read before confining the server, then this
wouldn't be ideal. Confining the process earlier would help.

> Switching contexts for packaged installs vs gem installs
>
> It was proposed that we don't switch SELinux contexts if Puppet was
> installed via a gem or run from source. This seems really challenging to
> implement.
>
>
> Switching contexts for different users
>
> If I'm developing on Puppet and standing up a test master as my own
> user, I really don't want SELinux turning itself on. How can we prevent
> this?
>
>
> Opt-out vs opt-in
>
> The current approach takes an opt-out approach to SELinux; if it's
> opt-in we avoid the issue of switching contexts for packaged installs vs
> gem installs. Is this a viable option?

Indeed, opt-in makes sense to fix those problems. Or, if the entire
process can be confined by using filesystem labels or a systemd unit
file (SELinuxContext) then it's even easier, as that happens in policy
or packaging only, which wouldn't affect gem or source usage.

Trevor Vaughan

unread,
Mar 27, 2015, 7:03:13 AM3/27/15
to puppe...@googlegroups.com
Just out of curiosity, are you going to double wrap this in a Java Security Policy for those systems that don't have SELinux?

Thanks,

Trevor

--
You received this message because you are subscribed to the Google Groups "Puppet Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-dev+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-dev/55152795.3070300%40redhat.com.
For more options, visit https://groups.google.com/d/optout.



--
Trevor Vaughan
Vice President, Onyx Point, Inc
(410) 541-6699
tvau...@onyxpoint.com

-- This account not approved for unencrypted proprietary information --

Lukas Zapletal

unread,
Mar 27, 2015, 9:32:37 AM3/27/15
to puppe...@googlegroups.com
Just out of curiosity, are you going to double wrap this in a Java Security Policy for those systems that don't have SELinux?

IFAIK JSP and SELinux are two different technologies with different goals. JSP can't protect you from security bugs in JVM and the granulality is much lower than syscall-based SELinux.

My ultimate goal is to do minimum work required in Puppet upstream to be able to build SELinux policies around it.

The main reason why we discuss this here is because puppet has one command (binary file) to do variulous things - one subcommand spawns Puppet Master server (subject of SELinux confinement) and also spawns agent or helper sub-commands which are not subject of this. If there are subbinaries like in with (git -> git-commit or git-push) there is no need of patching Puppet binary at all.

-- 
S pozdravem / Best regards
  Lukas Zapletal

Adrien Thebo

unread,
Mar 27, 2015, 1:43:20 PM3/27/15
to puppe...@googlegroups.com
[snip]

>
>       Environment variables vs configuration via a file
>
> Dominic Cleal indicated that we should change the SELinux context before
> we read any configuration files, which makes us need an alternate method
> of configuring SELinux, which the reason of running unconfined for as
> little time as possible. Why? Doing so makes it more challenging to
> handle configuration. Is it really that risky to run unconfined until we
> can read a config file to get SELinux settings? If we do run unconfined
> long enough to read a config file, what are the potential ramifications
> of running unconfined for this period?

I suppose what we would want to avoid is a period in which something
external, such as a user on the network (probably not an issue) or some
untrusted code is loaded or executed that could access resources that
the server wouldn't have access to when confined.

As a hand waving example, if we loaded environments and executed custom
types, or configuration somehow referenced another file (/etc/shadow for
argument's sake) which was read before confining the server, then this
wouldn't be ideal.  Confining the process earlier would help.

That's what I was thinking as well; thanks for clarifying.

I think that we can split the difference here - that is, we can store SELinux configuration in the main puppet.conf and still run in a confined manner when we're exposed to user operations. In order to run in a manner that could have security implications, we wind up having to read puppet.conf anyways - for the agent, we need to know which server to connect to, and for the webrick server we need to determine which interface/port we need to listen on. In each case we have to load configuration before exposing the process to security threats; this means that we can read SELinux configuration from puppet.conf, change the SELinux domain as necessary, and then start normal operations. Taking this approach takes away one of my bigger concerns about the existing pull request - the secondary configuration mechanism. Treating SELinux configuration as just another set of configuration options is consistent and unsurprising.

One downside of this approach is that if a user runs Puppet with a custom confdir and bypasses the SELinux configuration then that security is gone, but using environment variables doesn't make this any better.

In the case where Puppet is running under Passenger, is it safe to assume that any SELinux domain transitions have already occurred?

As a general note, we should make sure that the result of this conversation makes it back onto the JIRA ticket so we have a record of the design when we go into actually writing something.

--
Adrien Thebo | Puppet Labs

John Bollinger

unread,
Mar 30, 2015, 9:56:56 AM3/30/15
to puppe...@googlegroups.com


On Thursday, March 26, 2015 at 2:25:38 PM UTC-5, Melissa Stone wrote:
 

The current pull request uses the following environment variables:

  • NO_PUPPET_SELINUX_DTRANS
  • PUPPET_SELINUX_MASTER_DOMAIN
  • PUPPET_SELINUX_CA_DOMAIN


Maybe it's just a knee-jerk reaction, but I'm having trouble with the idea that relying on data from the environment could possibly serve a valid system security objective.  That's more usually considered a weakness, and environment-based exploits are legion.

Do the contexts used need to be configurable in Puppet at all? Couldn't they be hard-coded, in which case it becomes a matter of system SELinux policy, rather than Puppet configuration, to grant appropriate access to the contexts in which the various subcommands run?

Switching contexts for packaged installs vs gem installs

It was proposed that we don't switch SELinux contexts if Puppet was installed via a gem or run from source. This seems really challenging to implement.



What if there were a command-line option that controlled whether Puppet would attempt to perform a context switch, with a default value configurable at build time?  A default build might default to not switching, yet still have the option for the user to request a switch, whereas, say, the RPM build would default to switching (but have the option to suppress a switch).

Switching contexts for different users

If I'm developing on Puppet and standing up a test master as my own user, I really don't want SELinux turning itself on. How can we prevent this?



Why would SELinux "turn itself on"?  Do you mean the SELinux subsystem itself, or Puppet's use of it?  For the latter, I'm still liking a controlling command-line option, whose default value is configurable at build / install time.

Opt-out vs opt-in

The current approach takes an opt-out approach to SELinux; if it's opt-in we avoid the issue of switching contexts for packaged installs vs gem installs. Is this a viable option?



Opt-in seems viable to me, both as a build/install choice and as a runtime choice.  It must be understood, of course, that with some system configurations, refusing to opt in will mean that Puppet will not be able to do some of the work you may ask it to do.

Default values for SELinux domains

It was mentioned that we can isolate the default values for SELinux domains to an isolated file so that downstream vendors can just patch that file; I think this is a great idea. It seems a lot simpler than using environment variables.



If the various subcommands operated in predetermined, standard contexts, then wouldn't that make it so that downstream vendors just need to write or patch a policy module?


John

Lukas Zapletal

unread,
Mar 30, 2015, 2:47:38 PM3/30/15
to puppe...@googlegroups.com
Maybe it's just a knee-jerk reaction, but I'm having trouble with the idea that relying on data from the environment could possibly serve a valid system security objective.  That's more usually considered a weakness, and environment-based exploits are legion.

Do the contexts used need to be configurable in Puppet at all? Couldn't they be hard-coded, in which case it becomes a matter of system SELinux policy, rather than Puppet configuration, to grant appropriate access to the contexts in which the various subcommands run?

Valid concern, but the application is already constrained by the policy itself. Even if you modify the domain via configuration, SELinux policy must allow that kind of transition. The conifguration is solely for linux distributors and it is not expected to be modified by end users.


What if there were a command-line option that controlled whether Puppet would attempt to perform a context switch, with a default value configurable at build time?  A default build might default to not switching, yet still have the option for the user to request a switch, whereas, say, the RPM build would default to switching (but have the option to suppress a switch).


I am with you with build time configuration, that was in my initial proposal.
Reply all
Reply to author
Forward
0 new messages