Это файл сертификата SSH, используемый для реализации аутентификации пользователя на основе сертификата SSH . Это проверяет подлинность пользователя при входе в систему путем проверки действительной подписи доверенного центра сертификации в иерархии открытых ключей. Этот подход предлагает различные преимущества по сравнению со стандартной аутентификацией на основе ключей SSH (с файлами authorized_keys
), например:
- контроль над выдачей файлов ключей (кто-то, имеющий доступ к главному ключу ЦС, должен подписывать новые сертификаты, а не пользователи, выдающие свои собственные с
ssh-keygen
)
- срок действия файла ключа
- сокращение накладных расходов на администрирование при добавлении или ротации сертификатов, поскольку для проверки сертификата требуется только открытый ключ ЦС; больше нет необходимости заполнять файл
authorized_keys
для каждого пользователя на каждом хосте
- упрощенная поддержка отзыва сертификатов при изменении отношений с пользователем
Предполагая, что вы используете встроенную библиотеку golang.org/x/crypto/ssh
, вы можете реализовать это следующим образом:
- чтение и анализ вашего подписанного сертификата открытого ключа вместе с закрытым ключом
- создание подписанта из закрытого ключа
- создание лица, подписывающего сертификат, с использованием открытого ключа и соответствующего лица, подписывающего закрытый ключ
Указанный формат сертификатов открытого ключа OpenSSH аналогичен файлу authorized_keys
. Функция ParseAuthorizedKeys
библиотеки Go будет анализировать этот файл и возвращать соответствующий ключ как экземпляр интерфейса ssh.PublicKey
; для сертификатов это конкретно экземпляр структуры ssh.Certificate
.
См. Пример кода (примечание: я добавил HostKeyCallback
к вашему ClientConfig
, чтобы установить соединение с тестовой коробкой - однако он использует проверку InsecureIgnoreHostKey
, которую я не рекомендую в производстве!).
package main
import (
"bytes"
"io/ioutil"
"log"
"golang.org/x/crypto/ssh"
)
func main() {
key, err := ioutil.ReadFile("/tmp/mycert")
if err != nil {
log.Fatalf("unable to read private key: %v", err)
}
// Create the Signer for this private key.
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
log.Fatalf("unable to parse private key: %v", err)
}
// Load the certificate
cert, err := ioutil.ReadFile("/tmp/mycert-cert.pub")
if err != nil {
log.Fatalf("unable to read certificate file: %v", err)
}
pk, _, _, _, err := ssh.ParseAuthorizedKey(cert)
if err != nil {
log.Fatalf("unable to parse public key: %v", err)
}
certSigner, err := ssh.NewCertSigner(pk.(*ssh.Certificate), signer)
if err != nil {
log.Fatalf("failed to create cert signer: %v", err)
}
config := &ssh.ClientConfig{
User: "user",
Auth: []ssh.AuthMethod{
// Use the PublicKeys method for remote authentication.
ssh.PublicKeys(certSigner),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
// Connect to the remote server and perform the SSH handshake.
client, err := ssh.Dial("tcp", "host.com:22", config)
if err != nil {
log.Fatalf("unable to connect: %v", err)
}
defer client.Close()
}
Если вы хотите написать более общий клиент подключения, который поддерживает сертификаты и несертификаты, вам, очевидно, потребуется дополнительная логика для обработки других типов открытого ключа. Как было написано, я ожидаю, что утверждение типа pk.(*ssh.Certificate)
завершится неудачно для файлов открытого ключа без сертификата! (Действительно, для соединений без сертификатов вам, вероятно, не нужно для чтения открытого ключа вообще.)