Instance-level SSH certificates with gitlab-sshd
- Tier: Free, Premium, Ultimate
- Offering: GitLab Self-Managed
If your GitLab Self-Managed instance uses gitlab-sshd, you can configure
instance-level SSH certificate authentication.
- Use Certificate Authority (CA) certificates to centrally manage SSH authentication.
- No Rails API calls or database changes are required.
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 workflow
The gitlab_sshd authentication workflow follows this process.
- The administrator generates a CA key pair.
- The administrator adds the CA public key file path under
sshd.trusted_user_ca_keystoconfig.yml. - The administrator signs users’ SSH public keys with the CA private key.
The certificate
KeyIdis set to the user’s GitLab username. - When the user connects with a certificate:
gitlab-sshdvalidates the certificate signature and expiry.gitlab-sshdextracts theKeyIdand uses it as the GitLab username.- Standard GitLab access checks proceed (user existence, project permissions).
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.
Comparison with other SSH certificate methods
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 |
Prerequisites
Before you configure instance-level SSH certificates:
- Your GitLab Self-Managed instance must have
gitlab-sshdenabled. For more information, see Enablegitlab-sshd. - You must have access to the server file system to create CA
keys and edit
config.yml. - The
KeyIdfield of the SSH certificate must match the exact GitLab username.
Configure trusted CA keys
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.pubStore 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-sshdconfiguration.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
Create a Kubernetes Secret containing the CA public key:
kubectl create secret generic my-ssh-ca-keys \ --from-file=ca.pub=ssh_user_ca.pubExport the Helm values:
helm get values gitlab > gitlab_values.yamlEdit
gitlab_values.yamlto reference the secret:gitlab: gitlab-shell: sshDaemon: gitlab-sshd config: trustedUserCAKeys: secret: my-ssh-ca-keys keys: - ca.pubSave the file and apply the new values:
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlabFor more information about the Helm chart configuration, see the GitLab Shell chart documentation.
Verify
gitlab-sshdstarted successfully by checking the logs for:Loaded trusted user CA keys for instance-level SSH certificates count=1
Issue SSH certificates for users
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.pubThis 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
-Vflag. For example,-V +30dfor 30 days or-V +52wfor one year.Distribute the certificate file to the user.
The user connects using their certificate:
ssh git@gitlab.example.comIf the certificate file follows the default naming convention (
<key>-cert.pubalongside<key>), SSH uses it automatically. Otherwise, specify the certificate explicitly:ssh -o CertificateFile=~/.ssh/id_ed25519-cert.pub git@gitlab.example.com
Use multiple certificate authorities
You can specify multiple CA public key files for CA rotation or multi-CA setups.
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
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.pubExport the Helm values:
helm get values gitlab > gitlab_values.yamlEdit
gitlab_values.yamlto reference the secret:gitlab: gitlab-shell: sshDaemon: gitlab-sshd config: trustedUserCAKeys: secret: my-ssh-ca-keys keys: - ca_current.pub - ca_next.pubSave the file and apply the new values:
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
A single file can also contain multiple CA public keys, one per
line. gitlab-sshd automatically deduplicates keys across files.
Security considerations
Instance-level SSH certificates grant authentication authority to anyone who holds the CA private key. Review the following security considerations before you deploy.
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.
No certificate revocation
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.
No audit events for CA configuration changes
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.
Clustered deployments
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.
Troubleshooting
gitlab-sshd fails to start after adding CA keys
If 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 thegituser).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 certificate
The 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 format
The 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 expired
The certificate validity period has passed. Issue a new
certificate with an appropriate validity window by using the
-V flag.