Allow sshd fast SSH key lookup under SELinux
What does this MR do?
Fixes fast SSH key lookup (AuthorizedKeysCommand) failing on EL 9 and EL 10 with SELinux enforcing. This is the minimal "Part A" split-out requested by @lucus.li in !9541 (comment 3780242022).
Root cause
The AVC denial that breaks gitlab-shell-authorized-keys-check:
type=AVC msg=audit(...): avc: denied { connectto }
for pid=... comm="gitlab-shell-au"
scontext=system_u:system_r:sshd_t:s0-s0:c0.c1023
tcontext=system_u:system_r:unconfined_service_t:s0
tclass=unix_stream_socket permissive=0sock_file write on the workhorse socket already passes (that permission was granted in an earlier module). The only missing permission was connectto on the unix_stream_socket class — the IPC-level handshake that actually establishes the connection.
Why no new types or fcontext changes are needed
The workhorse socket is already labelled unconfined_service_t by the system policy. No fcontext relabelling is required. No new SELinux types are introduced. selinux_helper.rb gains one helper method (see 3) but no fcontext logic changes.
Changes
1. files/gitlab-selinux/gitlab-10.5.0-ssh-authorized-keys.te (bumped to 1.1)
This module already holds the other fast-lookup grants (http_cache_port_t name_connect and var_log_t open for sshd_t). Added:
allow sshd_t unconfined_service_t:unix_stream_socket connectto;— the core bug fix for EL 9.allow sshd_t var_log_t:file { open append };—openwas already present;appendis added sogitlab-shell.logwrites succeed.- Two
optional {}blocks (raw, no m4 macros — pattern copied fromgitlab-19.4.0-sshd-session.te) forsshd_session_t(OpenSSH 9.8+/EL10) andsshd_auth_t(OpenSSH 10+/Fedora 43), each granting:unconfined_service_t:unix_stream_socket connecttohttp_cache_port_t:tcp_socket name_connect(TCP transport for key lookup, currently missing for these domains)var_log_t:file { open append }(fixesgitlab-shell.logopen denial forsshd_session_ton EL10)
2. files/gitlab-selinux/gitlab.te (unified policy, bumped to 1.2.0)
Mirrors exactly the same additions: connectto for all three domains, name_connect and var_log_t { open append } for the sshd_session_t/sshd_auth_t optional blocks. Only rules that were previously absent are added.
3. Reload the module on upgraded hosts (selinux.rb + SELinuxHelper.module_installed_and_current?)
The semodule -i execute resources for gitlab-10.5.0-ssh-authorized-keys and the unified gitlab module were guarded with a name-only check:
not_if "semodule -l | grep -E '^#{module_name}([[:space:]]|$)'"A host that already has the module installed at an older version would therefore never reload the updated .pp, and the connectto fix would be inert on upgraded hosts.
A version-aware semodule -l grep is not an option: on libsemanage >= 2.4 (EL 8+) semodule -l prints module names only, so such a guard never matches and semodule -i rebuilds the policy on every reconfigure (as observed on AlmaLinux 9 in the review).
Instead, SELinuxHelper.module_installed_and_current?(name, pp_path) runs semodule -E <name> in a temporary directory to extract the installed module's original .pp and byte-compares it with the shipped one under /opt/gitlab/embedded/selinux/:
not_if { SELinuxHelper.module_installed_and_current?(module_name, "#{selinux_policy_dir}/#{module_name}.pp") }- Module missing or different from the shipped
.pp:semodule -iruns once. - Module byte-identical: skipped, so reconfigure stays idempotent.
- No version strings are duplicated into the recipe; the
.teremains the single source of truth.checkmoduleoutput is deterministic, so an unchanged.tenever triggers a spurious reinstall. - The temporary directory is removed when the check completes; nothing is written to the policy store or
/var/opt/gitlab.
All other modules (no policy change in this MR) retain the name-only guard to keep the change targeted.
4. Specs
spec/chef/cookbooks/package/libraries/helpers/selinux_helper_spec.rb: unit tests formodule_installed_and_current?(identical, differing, missing module,semoduleunavailable, missing shipped.pp).spec/chef/cookbooks/gitlab/recipes/selinux_spec.rbandspec/chef_helper.rb: stub the helper and verify that the module is not reinstalled when it matches the shipped package and is reinstalled when it is missing or differs.
Backport notes
gitlab-10.5.0-ssh-authorized-keys.te and gitlab.te exist on all four stable branches (19.0–19.3), so this MR backports cleanly with no prerequisite MRs for the EL 9 fix.
For EL 10 (the sshd_session_t path), the baseline SSH git access additionally requires !9672 (merged) / issue #10048 (closed) on stable branches; that is separately backportable. The EL 9 fix (sshd_t connectto) stands alone.
Manual verification
EL 9 (sshd_t path):
# /etc/ssh/sshd_config snippet
AuthorizedKeysCommand /opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell-authorized-keys-check git %u %k
AuthorizedKeysCommandUser git
# After package upgrade:
sudo gitlab-ctl reconfigure
# Expected: execute[semodule -i /opt/gitlab/embedded/selinux/gitlab-10.5.0-ssh-authorized-keys.pp] action run (once)
sudo gitlab-ctl reconfigure
# Expected: the same resource is skipped (up to date); no policy rebuild
# Installed module matches the shipped package:
cd "$(mktemp -d)" && sudo semodule -E gitlab-10.5.0-ssh-authorized-keys && cmp gitlab-10.5.0-ssh-authorized-keys.pp /opt/gitlab/embedded/selinux/gitlab-10.5.0-ssh-authorized-keys.pp && echo identical
ssh -T git@<host>
# Expected: Welcome to GitLab, @<user>!
sudo ausearch -m avc -ts recent | grep sshd
# Expected: no output (no denials)EL 10 (sshd_session_t path, requires !9672 (merged) on stable):
cd "$(mktemp -d)" && sudo semodule -E gitlab && cmp gitlab.pp /opt/gitlab/embedded/selinux/gitlab.pp && echo identical
# Expected: identical (unified policy path)
ssh -T git@<host>
# Expected: Welcome to GitLab, @<user>!
sudo ausearch -m avc -ts recent | grep sshd
# Expected: no outputRelated issues
Closes gitlab#438140 (closed)
Checklist
See Definition of done.
For anything in this list which will not be completed, please provide a reason in the MR discussion.
Required
- MR title and description are up to date, accurate, and descriptive.
- MR targeting the appropriate branch.
- Latest Merge Result pipeline is green.
- When ready for review, MR is labeled workflowready for review per the Distribution MR workflow.
For GitLab team members
If you don't have access to this, the reviewer should trigger these jobs for you during the review process.
- The manual
Trigger:ee-packagejobs have a green pipeline running against latest commit.- To debug QA failures, refer to the Investigate QA failures section.
- If
config/softwareorconfig/patchesdirectories are changed, make sure thebuild-package-on-all-osjob within theTrigger:ee-packagedownstream pipeline succeeded. - If you are changing anything SSL related, then the
Trigger:package:fipsmanual job within theTrigger:ee-packagedownstream pipeline must succeed. - If CI configuration is changed, the branch must be pushed to
dev.gitlab.orgto confirm regular branch builds aren't broken.
Expected (please provide an explanation if not completing)
- Test plan indicating conditions for success has been posted and passes.
- Documentation created/updated. N/A — SELinux policy change, no user-facing docs needed.
- Tests added.
✅ selinux_helper_spec.rb and selinux_spec.rb updated. - Integration tests added to GitLab QA. N/A — SELinux policy, not testable in QA suite.
- Equivalent MR/issue for the GitLab Chart opened. N/A — Kubernetes deployments do not use SELinux modules.
- Validate potential values for new configuration settings. N/A — no new configuration settings.