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

[JENKINS-64913] Label private key files on SELinux #673

Merged
merged 8 commits into from
Mar 1, 2021

Conversation

jimklimov
Copy link
Contributor

@jimklimov jimklimov commented Feb 22, 2021

JENKINS-64913 - SSH on SELinux enforced systems does not trust unlabeled key files

As detailed in the JIRA ticket, on modern Linux systems which do activate SELinux used as Jenkins controller or build agents, it refuses to check out over git+ssh in setups that work otherwise when SELinux is not enforced. This PR explores active labeling of the temporary private key file so the ssh client would not refuse to read it on such systems.

At least initially, no unit tests are added because hitting this situation requires that a testing system is a modern Linux where root (human admin or their distro maintainer) ran setenforce 1 and possibly other configuration activities.

The trigger for added logic is existence of /usr/bin/chcon (hardcoded at the moment, per common Linux distros I could look at), and it should be an inexpensive operation - useless but harmless if SELinux is not currently active on the box (which is something that can be toggled at run-time externally to Jenkins).

Checklist

  • I have read the CONTRIBUTING doc
  • I have referenced the Jira issue related to my changes in one or more commit messages
  • I have added tests that verify my changes
  • Unit tests pass locally with my changes
  • I have added documentation as necessary
  • No Javadoc warnings were introduced with my changes
  • No spotbugs warnings were introduced with my changes
  • I have interactively tested my changes

Types of changes

What types of changes does your code introduce?

  • Bug fix (non-breaking change which fixes an issue)

Further comments

The change is not very big, but rather complicated research led to it. It is detailed in the JIRA ticket.

…th SELinux, label it (SuppressFBWarnings work with absolute path to /usr/bin/chcon)
…th SELinux, label it (make use of stdout/stderr/status to quiesce FindBugs and convey errors to users)
@jimklimov
Copy link
Contributor Author

Solution as currently is was verified to fix the situation for private keys stored without a passphrase in Jenkins Credentials. It still fails for keys with a passphrase:

Command "git..." returned status code 128:
stderr: ssh_askpass: exec(/home/jenkins-worker/jenkins/workspace/jobname/subrepo@tmp/jenkins-gitclient-pass123123.sh): Permission denied

Probably that needs some other permission label...

@jimklimov
Copy link
Contributor Author

jimklimov commented Feb 22, 2021

Getting the executable labels like ssh_exec_t or bin_t proved much harder: chcon says "Permission denied" to those attempts for the running Jenkins agent so the scripts stay in user_home_t context; however same commands work (and do impact executability of ssh-askpass script wrapper by SE-cured ssh client) in interactive shell. But that has a different context (staff_u vs user_u), if that matters...

...this change is currently just noisily rejected by the OS

and as discussed, the better way forward is to generate
passphraseless temporary key files and so not rely on askpass
@jimklimov
Copy link
Contributor Author

That last CI fault was unrelated to code:

Caused by: java.net.ConnectException: Connect to github.com:443 [github.com/140.82.112.3] failed: Connection timed out (Connection timed out) github.com

@jimklimov
Copy link
Contributor Author

jimklimov commented Feb 23, 2021

Regarding the executable context, had a fruitful discussion on #selinux freenode channel with "grift", where it was confirmed that by design of security model, an agent.jar running from a logged-in SSH session gets a "user_t" context with little abilities and can not arbitrarily elevate. In that context, ssh (and its SELinux rule template) indeed chooses to not allow exec'ing arbitrary code editable by arbitrary users - such as "not an askpass program from a system location", and a low-privilege "user_t" has no rights to "relabel" that arbitrary code in random location to allow ssh to run it.

A proper way forward would be to define a SELinux template (set of roles, transitions, etc.) that could be assigned to Jenkins JVMs, automatically by SELinux after the sysadmin registers the ruleset, and inherited by its child processes, so that the master or agent can modify contexts of files in their namespace (e.g. under "workspace" directory). Such template could be a required pre-installable (package) to make a SELinux enforcing machine usable by Jenkins or its agents with whatever means of launching they would use, so sounds like quite a productizable DRY solution. To the point that it may be upstreamed into SELinux policies, if done right, so all impacted modern systems would just have it regardless of preparations for Jenkins in particular.

On a side note, my Jenkins master JVM runs from a system service (autogenerated per init-script from the RPM package) and has a process context of system_u:system_r:initrc_t:s0; during a git-checkout (such as Jenkinsfile lightweights) it manipulates data in /var/lib/jenkins/cache/git-*{,@tmp} directories which are labeled as system_u:object_r:var_lib_t:s0 and this setup apparently has no problems using the wrapper scripts and assigning new chcon contexts to them, and even without assigning the contexts (I guess by virtue of being a highly privileged system_u). Probably other service-based agents (swarm, jnlp, docker, ...) can (be configured to?..) enjoy such setup as well. From what I gather, an unconfined context should allow the privileges we want.

While such change can be eventually needed for a general solution, for the short problem of git checkouts it seems easier to just put temporary pre-unencrypted key files and be done with it. Or use ssh-agent (and ssh-add) which is also usable with the low privileged processes. But then there's also a "standard" askpass mode - and helper scripts - for username/password logins... maybe can break into git config to place an auth helper at that point.

Copy link
Contributor

@MarkEWaite MarkEWaite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jimklimov this seems ready to me. Any concerns from you that would prevent me from merging it?

@jimklimov
Copy link
Contributor Author

jimklimov commented Feb 28, 2021 via email

@MarkEWaite MarkEWaite changed the title CliGitAPIImpl.java: if using a temporary private key file on SELinux… [JENKINS-64913] Label private key files on SELinux Mar 1, 2021
@MarkEWaite MarkEWaite merged commit 9b92e5a into jenkinsci:master Mar 1, 2021
@MarkEWaite
Copy link
Contributor

Merged as a reasonable first step forward. Not the end of steps forward, but a good step. Thanks @jimklimov

@MarkEWaite
Copy link
Contributor

@jimklimov I'm considering reverting this pull request due to the noise it adds to console logs for all users of the git plugin. Since the fetch process fails without this change on SELinux, I believe that indicates very few users are running agents on SELinux. Yet, all users will have entries in their build logs like this:

15:57:33   > git /usr/bin/chcon --type=ssh_home_t /tmp/jenkins-gitclient-ssh2105122448559165972.key
15:57:33  [WARNING] Failed (1) performing chcon helper command: git /usr/bin/chcon --type=ssh_home_t /tmp/jenkins-gitclient-ssh2105122448559165972.key:
15:57:33  === STDERR:
15:57:33  /usr/bin/chcon: can't apply partial context to unlabeled file '/tmp/jenkins-gitclient-ssh2105122448559165972.key'
15:57:33  
15:57:33  ====
15:57:33  IMPACT: if SELinux is enabled, access to temporary key file may be denied for git+ssh below

and entries like this:

15:57:33   > git /usr/bin/chcon --type=ssh_home_t /var/jenkins_home/workspace/nch-pipeline-gitea_JENKINS-35687@libs/globalPipelineLibraryMarkEWaite@tmp/jenkins-gitclient-ssh654677047516219217.key
15:57:33  [WARNING] Failed (1) performing chcon helper command: git /usr/bin/chcon --type=ssh_home_t /var/jenkins_home/workspace/nch-pipeline-gitea_JENKINS-35687@libs/globalPipelineLibraryMarkEWaite@tmp/jenkins-gitclient-ssh654677047516219217.key:
15:57:33  === STDERR:
15:57:33  /usr/bin/chcon: can't apply partial context to unlabeled file '/var/jenkins_home/workspace/nch-pipeline-gitea_JENKINS-35687@libs/globalPipelineLibraryMarkEWaite@tmp/jenkins-gitclient-ssh654677047516219217.key'
15:57:33  
15:57:33  ====
15:57:33  IMPACT: if SELinux is enabled, access to temporary key file may be denied for git+ssh below

That's a lot of log noise for 250 000 users when very few will benefit from the change that generates that log noise. My apologies that I didn't comment on that log noise before merging the change. I hadn't experimented with the change interactively and had not read the change carefully enough to assure that the build log would be well-behaved for typical users.

I'd like to release the git client plugin shortly after the March 17, 2021 release of JGit 5.11.0. Do you have time to remove that build log noise for typical users before that planned release date? If not, I'll revert this merge, deliver the git client plugin 3.7.0 release, then merge it again with the assumption that you or I will remove the log noise before it is delivered to users.

@jimklimov
Copy link
Contributor Author

jimklimov commented Mar 14, 2021 via email

@jimklimov
Copy link
Contributor Author

jimklimov commented Mar 14, 2021 via email

@MarkEWaite
Copy link
Contributor

At least, this peppering with prints did collect the info :-)

Agreed wholeheartedly. The system reporting that message is a Debian container running Jenkins 2.277.1. I thought that SELinux was purely a CentOS / Red Hat thing, but apparently the core utilities to implement it are also included in Debian.

@jimklimov
Copy link
Contributor Author

Exploring a remedy in another PR #690.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Incorrect or flawed behavior
Projects
None yet
2 participants