doc/administration/operations/gitlab_sshd_ssh_certificates.md
{{< details >}}
{{< /details >}}
{{< history >}}
{{< /history >}}
If your GitLab Self-Managed instance uses gitlab-sshd, you can configure
instance-level SSH certificate authentication.
This approach is the gitlab-sshd equivalent of the OpenSSH
TrustedUserCAKeys directive and is an alternative to the
OpenSSH-based SSH certificate setup.
gitlab_sshd authentication workflowThe gitlab_sshd authentication workflow follows this process.
sshd.trusted_user_ca_keys to config.yml.KeyId is set to the user's GitLab username.gitlab-sshd validates the certificate signature and expiry.gitlab-sshd extracts the KeyId and uses it as the GitLab username.The gitlab-sshd process does not need a Rails API or database call for
the certificate validation itself. The /allowed endpoint is
still called for authorization, as with any SSH connection.
GitLab supports several SSH certificate authentication approaches:
| Feature | Instance-level (gitlab-sshd) | Instance-level (OpenSSH) | Group-level |
|---|---|---|---|
| Configuration location | config.yml | sshd_config | GitLab API/UI |
| SSH server | gitlab-sshd | OpenSSH | gitlab-sshd |
| Offering | GitLab Self-Managed | GitLab Self-Managed | GitLab.com |
| Tier | Free, Premium, Ultimate | Free, Premium, Ultimate | Premium, Ultimate |
| Scope | Instance-wide (no namespace restriction) | Instance-wide (no namespace restriction) | Top-level group |
| Username mapping | Certificate KeyId | Certificate Key ID through AuthorizedPrincipalsCommand | Certificate identity through API |
| Enterprise user requirement | No | No | Yes |
| Documentation | This page | OpenSSH AuthorizedPrincipalsCommand | Group SSH certificates |
Before you configure instance-level SSH certificates:
gitlab-sshd
enabled. For more information, see
Enable gitlab-sshd.config.yml.KeyId field of the SSH certificate must match the exact
GitLab username.To configure instance-level SSH certificate authentication:
Generate a CA key pair:
ssh-keygen -t ed25519 -f ssh_user_ca -C "GitLab SSH User CA"
When prompted, enter a strong passphrase to protect the CA private key.
This command creates two files:
ssh_user_ca: The CA private key.ssh_user_ca.pub: The CA public key.Copy only the public key to the GitLab server:
sudo cp ssh_user_ca.pub /etc/gitlab/ssh_user_ca.pub
Store the CA private key in a secure location, ideally on an offline system that is not the GitLab server. The private key is needed only to sign user certificates.
Add the CA public key file path to the gitlab-sshd
configuration.
{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
Edit /etc/gitlab/gitlab.rb:
gitlab_sshd['trusted_user_ca_keys'] = ['/etc/gitlab/ssh_user_ca.pub']
Save the file and reconfigure GitLab:
sudo gitlab-ctl reconfigure
{{< /tab >}}
{{< tab title="Helm chart (Kubernetes)" >}}
Create a Kubernetes Secret containing the CA public key:
kubectl create secret generic my-ssh-ca-keys \
--from-file=ca.pub=ssh_user_ca.pub
Export the Helm values:
helm get values gitlab > gitlab_values.yaml
Edit gitlab_values.yaml to reference the secret:
gitlab:
gitlab-shell:
sshDaemon: gitlab-sshd
config:
trustedUserCAKeys:
secret: my-ssh-ca-keys
keys:
- ca.pub
Save the file and apply the new values:
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
For more information about the Helm chart configuration, see the GitLab Shell chart documentation.
{{< /tab >}}
{{< /tabs >}}
Verify gitlab-sshd started successfully by checking the
logs for:
Loaded trusted user CA keys for instance-level SSH certificates count=1
After you configure trusted CA keys, issue certificates for your users:
Obtain the user's public SSH key
(for example, id_ed25519.pub).
Sign the user's public key with the CA, setting the -I
(identity/KeyId) flag to the user's exact GitLab username:
ssh-keygen -s ssh_user_ca -I <gitlab-username> -V +1d user-key.pub
This command creates a certificate file
(for example, user-key-cert.pub) that is valid for one day.
To set a longer validity period, adjust the -V flag.
For example, -V +30d for 30 days or -V +52w for
one year.
Distribute the certificate file to the user.
The user connects using their certificate:
ssh [email protected]
If the certificate file follows the default naming convention
(<key>-cert.pub alongside <key>), SSH uses it
automatically. Otherwise, specify the certificate explicitly:
ssh -o CertificateFile=~/.ssh/id_ed25519-cert.pub [email protected]
You can specify multiple CA public key files for CA rotation or multi-CA setups.
{{< tabs >}}
{{< tab title="Linux package (Omnibus)" >}}
Edit /etc/gitlab/gitlab.rb:
gitlab_sshd['trusted_user_ca_keys'] = [
'/etc/gitlab/ssh_user_ca_current.pub',
'/etc/gitlab/ssh_user_ca_next.pub'
]
Save the file and reconfigure GitLab:
sudo gitlab-ctl reconfigure
{{< /tab >}}
{{< tab title="Helm chart (Kubernetes)" >}}
Create a Kubernetes Secret containing both CA public keys:
kubectl create secret generic my-ssh-ca-keys \
--from-file=ca_current.pub=ssh_user_ca_current.pub \
--from-file=ca_next.pub=ssh_user_ca_next.pub
Export the Helm values:
helm get values gitlab > gitlab_values.yaml
Edit gitlab_values.yaml to reference the secret:
gitlab:
gitlab-shell:
sshDaemon: gitlab-sshd
config:
trustedUserCAKeys:
secret: my-ssh-ca-keys
keys:
- ca_current.pub
- ca_next.pub
Save the file and apply the new values:
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
{{< /tab >}}
{{< /tabs >}}
A single file can also contain multiple CA public keys, one per
line. gitlab-sshd automatically deduplicates keys across files.
Instance-level SSH certificates grant authentication authority to anyone who holds the CA private key. Review the following security considerations before you deploy.
[!warning] Anyone with access to the CA private key can sign certificates for any GitLab user on the instance. Protect the CA private key with appropriate access controls, such as restrictive file permissions, hardware security modules (HSMs), or an offline environment.
gitlab-sshd does not include a built-in certificate revocation
mechanism. If a certificate or CA key is compromised, remove the
CA from the trusted_user_ca_keys configuration and reissue
certificates with a new CA. Use short-lived certificates
(for example, 24 hours) to minimize the window of exposure.
GitLab does not record changes to trusted_user_ca_keys in
config.yml as audit events. Monitor changes to this
configuration file by using your infrastructure monitoring tools.
gitlab-sshd logs successful and failed SSH certificate
authentication attempts with fields including ssh_user,
public_key_fingerprint, signing_ca_fingerprint,
certificate_identity, and certificate_username.
In environments with multiple gitlab-sshd nodes, synchronize
the configuration and CA public key files across all nodes.
Inconsistent configurations can cause intermittent
authentication failures. For Helm chart deployments, the
Kubernetes Secret is shared across pods automatically.
gitlab-sshd fails to start after adding CA keysIf a CA key file cannot be read or contains content that's not valid,
gitlab-sshd does not start. Check the log output for error
messages such as:
failed to load trusted user CA keys: The file could not be
read. Verify the file exists and has correct permissions
(readable by the git user).failed to parse trusted user CA key in file: The file
content is not a valid SSH public key. Verify the file
contains a valid public key in OpenSSH format.trusted_user_ca_keys configured but no valid CA keys were loaded:
The configuration lists CA key files but none contained
valid keys.certificate rejected: not a user certificateThe certificate was generated as a host certificate instead of
a user certificate. Do not use the -h flag when signing with
ssh-keygen.
certificate KeyId does not match GitLab username formatThe KeyId in the certificate does not conform to GitLab
username rules. Verify the -I value used during signing
matches the exact GitLab username.
ssh: cert has expiredThe certificate validity period has passed. Issue a new
certificate with an appropriate validity window by using the
-V flag.