As we reevaluate how to best support and maintain Staging Ref in the future, we encourage development teams using this environment to highlight their use cases in the following issue: https://gitlab.com/gitlab-com/gl-infra/software-delivery/framework/software-delivery-framework-issue-tracker/-/issues/36.

Skip to content
Snippets Groups Projects
Unverified Commit 4919ec7a authored by Stan Hu's avatar Stan Hu
Browse files

gitlab-sshd: Add support for configuring host certificates

This adds support for specifying host certificates via the
`host_cert_files` option and advertises the signed key to the
client. This acts similarly to OpenSSH's `HostCertificate` parameter:
gitlab-sshd attempts to match a host key to its certificate, and then
substitutes the matching host key with a certificate signed by a
trusted certificate authority's key.

This is the first requirement to supporting SSH certificates. This
will enable the client to trust the server if both trust a common
certificate authority. The `TrustedUserCAKeys` option will need to be
supported later for the server to trust all user keys signed by this
certificate authority.

Relates to https://gitlab.com/gitlab-org/gitlab-shell/-/issues/495
parent 34ec4ec8
No related branches found
No related tags found
No related merge requests found
Showing
with 191 additions and 8 deletions
Loading
Loading
@@ -99,3 +99,7 @@ sshd:
- /run/secrets/ssh-hostkeys/ssh_host_rsa_key
- /run/secrets/ssh-hostkeys/ssh_host_ecdsa_key
- /run/secrets/ssh-hostkeys/ssh_host_ed25519_key
host_key_certs:
- /run/secrets/ssh-hostkeys/ssh_host_rsa_key-cert.pub
- /run/secrets/ssh-hostkeys/ssh_host_ecdsa_key-cert.pub
- /run/secrets/ssh-hostkeys/ssh_host_ed25519_key-cert.pub
Loading
Loading
@@ -36,6 +36,7 @@ type ServerConfig struct {
ReadinessProbe string `yaml:"readiness_probe"`
LivenessProbe string `yaml:"liveness_probe"`
HostKeyFiles []string `yaml:"host_key_files,omitempty"`
HostCertFiles []string `yaml:"host_cert_files,omitempty"`
MACs []string `yaml:"macs"`
KexAlgorithms []string `yaml:"kex_algorithms"`
Ciphers []string `yaml:"ciphers"`
Loading
Loading
Loading
Loading
@@ -39,17 +39,14 @@ var (
type serverConfig struct {
cfg *config.Config
hostKeys []ssh.Signer
hostKeyToCertMap map[string]*ssh.Certificate
authorizedKeysClient *authorizedkeys.Client
}
func newServerConfig(cfg *config.Config) (*serverConfig, error) {
authorizedKeysClient, err := authorizedkeys.NewClient(cfg)
if err != nil {
return nil, fmt.Errorf("failed to initialize GitLab client: %w", err)
}
func parseHostKeys(keyFiles []string) []ssh.Signer {
var hostKeys []ssh.Signer
for _, filename := range cfg.Server.HostKeyFiles {
for _, filename := range keyFiles {
keyRaw, err := os.ReadFile(filename)
if err != nil {
log.WithError(err).WithFields(log.Fields{"filename": filename}).Warn("Failed to read host key")
Loading
Loading
@@ -63,11 +60,70 @@ func newServerConfig(cfg *config.Config) (*serverConfig, error) {
hostKeys = append(hostKeys, key)
}
return hostKeys
}
func parseHostCerts(hostKeys []ssh.Signer, certFiles []string) map[string]*ssh.Certificate {
keyToCertMap := map[string]*ssh.Certificate{}
hostKeyIndex := make(map[string]int)
for index, hostKey := range hostKeys {
hostKeyIndex[string(hostKey.PublicKey().Marshal())] = index
}
for _, filename := range certFiles {
keyRaw, err := os.ReadFile(filename)
if err != nil {
log.WithError(err).WithFields(log.Fields{"filename": filename}).Warn("failed to read host certificate")
continue
}
publicKey, _, _, _, err := ssh.ParseAuthorizedKey(keyRaw)
if err != nil {
log.WithError(err).WithFields(log.Fields{"filename": filename}).Warn("failed to parse host certificate")
continue
}
cert, ok := publicKey.(*ssh.Certificate)
if !ok {
log.WithFields(log.Fields{"filename": filename}).Warn("failed to decode host certificate")
continue
}
hostRawKey := string(cert.Key.Marshal())
index, found := hostKeyIndex[hostRawKey]
if found {
keyToCertMap[hostRawKey] = cert
certSigner, err := ssh.NewCertSigner(cert, hostKeys[index])
if err != nil {
log.WithError(err).WithFields(log.Fields{"filename": filename}).Warn("the host certificate doesn't match the host private key")
continue
}
hostKeys[index] = certSigner
} else {
log.WithFields(log.Fields{"filename": filename}).Warnf("no matching private key for certificate %s", filename)
}
}
return keyToCertMap
}
func newServerConfig(cfg *config.Config) (*serverConfig, error) {
authorizedKeysClient, err := authorizedkeys.NewClient(cfg)
if err != nil {
return nil, fmt.Errorf("failed to initialize GitLab client: %w", err)
}
hostKeys := parseHostKeys(cfg.Server.HostKeyFiles)
if len(hostKeys) == 0 {
return nil, fmt.Errorf("No host keys could be loaded, aborting")
}
return &serverConfig{cfg: cfg, authorizedKeysClient: authorizedKeysClient, hostKeys: hostKeys}, nil
hostKeyToCertMap := parseHostCerts(hostKeys, cfg.Server.HostCertFiles)
return &serverConfig{cfg: cfg, authorizedKeysClient: authorizedKeysClient, hostKeys: hostKeys, hostKeyToCertMap: hostKeyToCertMap}, nil
}
func (s *serverConfig) getAuthKey(ctx context.Context, user string, key ssh.PublicKey) (*authorizedkeys.Response, error) {
Loading
Loading
Loading
Loading
@@ -5,6 +5,7 @@ import (
"crypto/dsa"
"crypto/rand"
"crypto/rsa"
"os"
"path"
"testing"
Loading
Loading
@@ -22,6 +23,45 @@ func TestNewServerConfigWithoutHosts(t *testing.T) {
require.Equal(t, "No host keys could be loaded, aborting", err.Error())
}
func TestHostKeyAndCerts(t *testing.T) {
testhelper.PrepareTestRootDir(t)
srvCfg := config.ServerConfig{
Listen: "127.0.0.1",
ConcurrentSessionsLimit: 1,
HostKeyFiles: []string{
path.Join(testhelper.TestRoot, "certs/valid/server.key"),
},
HostCertFiles: []string{
path.Join(testhelper.TestRoot, "certs/valid/server-cert.pub"),
path.Join(testhelper.TestRoot, "certs/valid/server2-cert.pub"),
path.Join(testhelper.TestRoot, "certs/invalid/server-cert.pub"),
path.Join(testhelper.TestRoot, "certs/invalid-path.key"),
path.Join(testhelper.TestRoot, "certs/invalid/server.crt"),
},
}
cfg, err := newServerConfig(
&config.Config{GitlabUrl: "http://localhost", User: "user", Server: srvCfg},
)
require.NoError(t, err)
require.Len(t, cfg.hostKeys, 1)
require.Len(t, cfg.hostKeyToCertMap, 1)
// Check that the entry is pointing to the server's public key
data, err := os.ReadFile(path.Join(testhelper.TestRoot, "certs/valid/server.pub"))
require.NoError(t, err)
publicKey, _, _, _, err := ssh.ParseAuthorizedKey(data)
require.NoError(t, err)
require.NotNil(t, publicKey)
cert, ok := cfg.hostKeyToCertMap[string(publicKey.Marshal())]
require.True(t, ok)
require.NotNil(t, cert)
require.Equal(t, cert, cfg.hostKeys[0].PublicKey())
}
func TestFailedAuthorizedKeysClient(t *testing.T) {
_, err := newServerConfig(&config.Config{GitlabUrl: "ftp://localhost"})
Loading
Loading
ssh-rsa-cert-v01@openssh.com AAAAB3NzaC1yc2EAAAADAQABAAABAQCa17cb94P6q5qbDIWX7aMSjyeBIBPQVZ5jlkDBG90XgWC1MEu9sB1OfKLukcx6wJJSTLFccc9rMzhINXq6K7ks0oXSLP81jvqsu0WipIZSDKBNkdVtno1FcI1RnQ+yUP3nA4Ja9L233GA1evLrqTz6Z9k2ET5wVB+s7+k3lak24bJZN8qVRDDk1UveahuPe1KMj7DNKls8y9tNCgGJn9UeTLJzXlh2tt4/AUHZ0lvET9eCzKT9PBZJQWcCzqLXHa37jbc0ib2sgNN1bZhgkle/cxRx0MjEmdjRt4Z48wjKaf1khFQm0r9lebAxvna/vT5hNywbru5KbfUJHyM23yql not_a_valid_cert.pub
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDchQE3zT8Ekbm631TbfwXAgYB8xlCg5dhsW2JBmj5T5x1sYmUQaBX4hOgY3vxgnKmRsrw2Km0ww6BZnx67oMIkw3GM9vt7ddgauYc96grln2KgRIPDRBKTEMh/AWgtKfHT56JdLXfzKkQ2AtP+E4yX5+augDvhmm+S8ikr5GgCjWqVYJa0Ds3KCRCRZGCecCPiOQMqr1pPWIcZr2dBgu5O1+JfeXfn+g44wkWsODttvkQecGwp7AOgDF2o1vGnhb+xDJQXg1s4UsbNFq8Dp41F87H1Rdx3LS/35SAKa73aduI+Y0Gj3BjcP2mvBcBZ61MzUHdkIOTWGohxdGDqk0E0L17YW5tyGz1NystpmmviSAW9N6QZyh/WbajMlNWVwgmUmnL3manW5fDFM9t9coY+8q7s2uhHZq+QAh/BGPkT/wfCuAMfav/i5E9p1ELH2GbfwcjWfpLhiuuyYv198tbpIJ8Qbpzv5RENCvXxWr1jLEya7T0QrtWUMNfQkzRRqfk= test@test.example.org
ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgNGUtD+qw0Xj5NU2uj4+4LoCWPcvXP54F9Adw/hWN5LAAAAADAQABAAABAQCa17cb94P6q5qbDIWX7aMSjyeBIBPQVZ5jlkDBG90XgWC1MEu9sB1OfKLukcx6wJJSTLFccc9rMzhINXq6K7ks0oXSLP81jvqsu0WipIZSDKBNkdVtno1FcI1RnQ+yUP3nA4Ja9L233GA1evLrqTz6Z9k2ET5wVB+s7+k3lak24bJZN8qVRDDk1UveahuPe1KMj7DNKls8y9tNCgGJn9UeTLJzXlh2tt4/AUHZ0lvET9eCzKT9PBZJQWcCzqLXHa37jbc0ib2sgNN1bZhgkle/cxRx0MjEmdjRt4Z48wjKaf1khFQm0r9lebAxvna/vT5hNywbru5KbfUJHyM23yqlAAAAAAAAAAAAAAACAAAABnNlcnZlcgAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAABlwAAAAdzc2gtcnNhAAAAAwEAAQAAAYEA3IUBN80/BJG5ut9U238FwIGAfMZQoOXYbFtiQZo+U+cdbGJlEGgV+IToGN78YJypkbK8NiptMMOgWZ8eu6DCJMNxjPb7e3XYGrmHPeoK5Z9ioESDw0QSkxDIfwFoLSnx0+eiXS138ypENgLT/hOMl+fmroA74ZpvkvIpK+RoAo1qlWCWtA7NygkQkWRgnnAj4jkDKq9aT1iHGa9nQYLuTtfiX3l35/oOOMJFrDg7bb5EHnBsKewDoAxdqNbxp4W/sQyUF4NbOFLGzRavA6eNRfOx9UXcdy0v9+UgCmu92nbiPmNBo9wY3D9prwXAWetTM1B3ZCDk1hqIcXRg6pNBNC9e2Fubchs9TcrLaZpr4kgFvTekGcof1m2ozJTVlcIJlJpy95mp1uXwxTPbfXKGPvKu7NroR2avkAIfwRj5E/8HwrgDH2r/4uRPadRCx9hm38HI1n6S4YrrsmL9ffLW6SCfEG6c7+URDQr18Vq9YyxMmu09EK7VlDDX0JM0Uan5AAABlAAAAAxyc2Etc2hhMi01MTIAAAGAapK5VzLDoRe88tnLORrH8VxLegTWPKGdn0k5Ye8tS5XUgd0N98gU669y4ErDNf0kPxlz40bjsfisEEtJ/N7m14IskCepScfZRh8w6QgPxbTOhmrc89xooqBUE50y5FU9hIIbzUrnEP+Dfu4IiFPToAguCa+KoAKiOX7lBQqEugV6uOWVZ2erPopEv+OiMLD8hXsuKKjQ+TomHZ/IjuXsFdXH7Vcl0VsPaAcxyCtDU7nCTJSTUoUZtMtwwpulp0e/zNmFrEn2Binz4jRaUlk3FM2fdbotviDQYeOY3npmxaWUvvQ/eKn0/DzUTAKAGr2LDa2XWnPhj51BS1XkNaUlnupdYmZ2Sok0R4U3bfVwokteREvAltGbXQSDtZwLS5NEY6vIdDrxpn5QRf9vGjqnc7piXxye9gcLne4YDUi24IhGyHrnWKCC0HjF7tuUhCOVKrqRdmHxRGWX3PlS8Xn6HHEPWU+YZnfT1V2W7LAFcDMozQbs4GPGzZdR3f3vCOJ8 server.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCa17cb94P6q5qbDIWX7aMSjyeBIBPQVZ5jlkDBG90XgWC1MEu9sB1OfKLukcx6wJJSTLFccc9rMzhINXq6K7ks0oXSLP81jvqsu0WipIZSDKBNkdVtno1FcI1RnQ+yUP3nA4Ja9L233GA1evLrqTz6Z9k2ET5wVB+s7+k3lak24bJZN8qVRDDk1UveahuPe1KMj7DNKls8y9tNCgGJn9UeTLJzXlh2tt4/AUHZ0lvET9eCzKT9PBZJQWcCzqLXHa37jbc0ib2sgNN1bZhgkle/cxRx0MjEmdjRt4Z48wjKaf1khFQm0r9lebAxvna/vT5hNywbru5KbfUJHyM23yql
ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg3XO30wn4+lFxc5fLsanH4Pvu0OuKGHoR94zZjxx7qAEAAAADAQABAAABgQDK4MvpmiZ0cLS4+p3YEwcCwo4kVbJPTEeiIMuoEI7KJ3yqAjKJuns6VpnC6aRgu3LmuM4uBHcimQi415ClBOm4+tFiVsVNcAksA+QuU8rTEC6xPs96y1Y/qC+/WQn6+uKp1+fAspWsLpig3VXSTfq+YAcxZfTdO/6ck0kHVvxX096Ye7D0mdq2lWbGwSBlAbzU1wX/Znv5hLZD4DSG1cIjA9vQ/fJ9pwclZiS0qQ1VXdoIUAvL9tTAKj295VGT2NMGGYZQAQ0vXtM1YHOMAZ4XoPL1oVFjVEZoLRD58a6Dpe4hY8QKe6X1w7zU1rr5vVYrz7MTUa5pzsUSOeUTc3kyKJrExVkoLyBgYQq8qW9kYk/Ox9zHwTAKw9vwiIs2Mwe6nlxJ7cw4zykMsxPK4z9HkbZoTFWy3phuPFqs/WQoCvHTKNjWPab7UAameM6Dn0N83BF21tCTMWjkRCvtZVGIGZ7Y4cAiiN0OPzQWDasJ/IKVDRguZJRn3kgHCMYCgokAAAAAAAAAAAAAAAIAAAAHc2VydmVyMgAAAAAAAAAAAAAAAP//////////AAAAAAAAAAAAAAAAAAABlwAAAAdzc2gtcnNhAAAAAwEAAQAAAYEA3IUBN80/BJG5ut9U238FwIGAfMZQoOXYbFtiQZo+U+cdbGJlEGgV+IToGN78YJypkbK8NiptMMOgWZ8eu6DCJMNxjPb7e3XYGrmHPeoK5Z9ioESDw0QSkxDIfwFoLSnx0+eiXS138ypENgLT/hOMl+fmroA74ZpvkvIpK+RoAo1qlWCWtA7NygkQkWRgnnAj4jkDKq9aT1iHGa9nQYLuTtfiX3l35/oOOMJFrDg7bb5EHnBsKewDoAxdqNbxp4W/sQyUF4NbOFLGzRavA6eNRfOx9UXcdy0v9+UgCmu92nbiPmNBo9wY3D9prwXAWetTM1B3ZCDk1hqIcXRg6pNBNC9e2Fubchs9TcrLaZpr4kgFvTekGcof1m2ozJTVlcIJlJpy95mp1uXwxTPbfXKGPvKu7NroR2avkAIfwRj5E/8HwrgDH2r/4uRPadRCx9hm38HI1n6S4YrrsmL9ffLW6SCfEG6c7+URDQr18Vq9YyxMmu09EK7VlDDX0JM0Uan5AAABlAAAAAxyc2Etc2hhMi01MTIAAAGANOKG8Tq7kp9B5+CQEyb+mEatJOoQRV+4rpemWlfEw6TuVwQN2wSXc6XKBHzSG4NRnFkwk6GgiPLQEf4lBBKA8VYQnDKuhrHJlU4DFCRPw/aceHfCwNOruyJmuf91W3yEO/kYAd6EhkQiW/K3ky7BuXCqR34T2fBZSCeYhNcXWxhEMLoAuj0kEdX+YMNBmiPtinPE13KMFGyIVBm/ojgSZa8j4WnhDcK0cWv0OSGTgJF6q3hENCWRz2E1HroKUiABOy5Nca6gPVAi4OTd7gwER8eh9MngVHYorAJ3N9HjUh640SbL3zCC8f/lqIztqsHY0u3olsQ0gLXpFain+430HeyJlmVlsDZgQKRb90Mm1viSCKvHGpmVDYMimE9y0DCQS1i0yRGF1uSIPtuQ0NCbhS/HPKsT3nYgGCEuoB8aGOu3aGB/tmUkYXW+pwXRKqw0f/zX088XWYWvA+AR4hmmr6DDMnf/4EHgJp3xHTEwOBHCVj69xvlOawBNlL2X0b2p server2.pub
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDK4MvpmiZ0cLS4+p3YEwcCwo4kVbJPTEeiIMuoEI7KJ3yqAjKJuns6VpnC6aRgu3LmuM4uBHcimQi415ClBOm4+tFiVsVNcAksA+QuU8rTEC6xPs96y1Y/qC+/WQn6+uKp1+fAspWsLpig3VXSTfq+YAcxZfTdO/6ck0kHVvxX096Ye7D0mdq2lWbGwSBlAbzU1wX/Znv5hLZD4DSG1cIjA9vQ/fJ9pwclZiS0qQ1VXdoIUAvL9tTAKj295VGT2NMGGYZQAQ0vXtM1YHOMAZ4XoPL1oVFjVEZoLRD58a6Dpe4hY8QKe6X1w7zU1rr5vVYrz7MTUa5pzsUSOeUTc3kyKJrExVkoLyBgYQq8qW9kYk/Ox9zHwTAKw9vwiIs2Mwe6nlxJ7cw4zykMsxPK4z9HkbZoTFWy3phuPFqs/WQoCvHTKNjWPab7UAameM6Dn0N83BF21tCTMWjkRCvtZVGIGZ7Y4cAiiN0OPzQWDasJ/IKVDRguZJRn3kgHCMYCgok=
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment