Skip to content

fixSELinuxLabel() relabels SSH key files to ssh_home_t, breaking access for ssh running under `container_t #1764

Description

@Ansible-man

Jenkins and plugins versions report

Newest LTS Jenkins version and Newest git-client-plugin

What Operating System are you using (both controller, and any agents involved in the problem)?

RHEL 9
RKE 2 1.34.6

Reproduction steps

Inside a Jenkins container (controller or agent):

touch /tmp/test && chmod 400 /tmp/testt
ls -lZ /tmp/test                            # container_file_t  readable
chcon --type=ssh_home_t /tmp/test; echo $?  # exits 0
ls /tmp/test                                # Permission denied

After the relabel succeeds, the calling process can no longer access its own file. ls -l from the calling context shows ?????????? for the file mode, because stat() is denied.

When the git-client-plugin runs this same chcon against the temporary key it writes to tmp/jenkins-gitclient-ssh*.key, the subsequent ssh invocation fails with:

Warning: Identity file …/jenkins-gitclient-ssh….key not accessible: Permission denied.

and the git operation failss

On some runs on some clusters we have also seen the relabel itself be denied by the kernel generating an AVC like:

type=AVC msg=audit(...): avc: denied { relabelto } for pid=... comm="chcon"
  name="jenkins-gitclient-ssh...key"
  scontext=system_u:system_r:container_t:s0:c290,c1002
  tcontext=system_u:object_r:ssh_home_t:s0:c290,c1002
  tclass=file permissive=0

In that case the file keeps its container_file_t label and the build often succeeds despite the [WARNING] Failed (1) performing chcon helper command for SELinux log line. Whether a given run takes the "relabel denied" path or the "relabel succeeds, subsequent reads denied" path appears to depend on the underlying filesystem and host policy root cause of the variation is still under investigaton on our side.

Expected Results

The plugin does not relabel files to a type that the calling process cannot then read

Actual Results

Summary

fixSELinuxLabel() runs chcon --type='ssh_home_t on the temporary SSH key file when it detects a labeled security context. This is correct when the ssh client that will read the key runs under sshd_t (or another domain for which ssh_home_t is the expected file tyype).

When Jenkins runs inside a container under the standard container-selinux policy (Kubernetes pods labeled container_t, including RKE2, OpenShift, plain containerd/CRI-O), the ssh client invoked by git also runs as container_t. Under that policy:

  • container_t can read container_file_t (the default workspace label).
  • container_t cannot getattr/read/open files labeled ssh_home_t.

So relabeling the tmp key to `ssh_home_t makes it unreadable to the same process that needs to read it.

We have observed this failure on RKE2 with rke2-selinux and container-selinux installed and SELinux enforcing, with the Jenkins controller and inbound agent containers both running as container_t.

Anything else?

The function currently checks:

  1. `/proc/self/attr/current contains a labeled context.
  2. /sys/fs/selinux/enforce reads as 1.

Neither check answers the question that actually matters: is the process domain one for which ssh_home_t is the correct file type? A process running as container_t will not benefit from the relabel and will be actively hamed by it.

Suggested fixes

  1. Add a system property to skip the relabel. Somthing loke skipSELinuxRelabeldefaulting tofalse` to preserve existing behavior, settable by operators who know their environment doesn't need or want it. Lowest-risk change and allows site self-mitigation without rebuilding base images.

  2. Detect the calling SELinux domain and skip the relabel for container domains. Read the type from /proc/self/attr/current; if it's container_t (or matches a list of container-family domains: container_init_t, container_user_t, etc.), skip the chcon. The temp key keeps its container_file_t label, which container_t ssh can already read.

  3. Verify after relabel. After chcon exits 0, do a Files.isReadable(key) (or equivalent) check from the plugin. If the file is no longer readable, revert the label or surface a clear error explaining what happened

  4. Document the failure mode. Note in the plugin docs that on systems where Jenkins runs under container_t, the chcon step is at best a no-op and at worst breaks the build, and that shimming chcon to exit 0 inside the image is a known workaround.

Workaround we're using

RUN printf '#!/bin/sh\nexit 0\n' > /usr/local/bin/chcon && chmod 0755 /usr/local/bin/chcon

Placed in both controller and agent images. Verified to fix the failure across all affected clusters.

Are you interested in contributing a fix?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Fields

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions