Как включить id_ed25519-cert.pub в клиент go ssh?

Я могу SSH (используя клиент openssh) подключиться к своему серверу, используя два файла: ~/.ssh/id_ed25519{,-cert.pub}

debug1: Trying private key: /home/xavier/.ssh/id_ed25519                        
debug1: Authentications that can continue: publickey,keyboard-interactive      
debug1: Offering ED25519-CERT public key: /home/xavier/.ssh/id_ed25519          
debug1: Server accepts key: pkalg [email protected] blen 441    
debug1: sign_and_send_pubkey: no separate private key for certificate "/home/xavier/.ssh/id_ed25519"
debug1: Authentication succeeded (publickey).

Мне нужен клиент go, который делает то же самое, но я не знаю, как включить файл id_ed25519-cert.pub в пример по адресу https://godoc.org/golang.org/x/crypto/ssh.#example-PublicKeys

key, err := ioutil.ReadFile("/home/xavier/.ssh/id_ed25519")
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)
}

config := &ssh.ClientConfig{
    User: "user",
    Auth: []ssh.AuthMethod{
        // Use the PublicKeys method for remote authentication.
        ssh.PublicKeys(signer),
    },
}

// 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()

Часть проблемы в том, что я не знаю, что это за файл (PublicKey? Сертификат?), часть проблемы в том, что даже если бы я знал, я не понимаю, какую цель он играет в этом обмене.

Я подтвердил, что этот файл необходим: его удаление приводит к сбою интерфейса командной строки ssh.


person Xavier Shay    schedule 31.08.2018    source источник
comment
Вещи, которые, как мне кажется, я усвоил: файл pub — это открытый ключ, подписанный ЦС, о котором знает сервер. На сервере нет файла authorized_keys, как можно было бы ожидать в типичной настройке SSH. Вместо этого он сверяет открытый ключ, предоставленный клиентом, с этим ЦС. Я до сих пор не знаю, как написать соответствующий код go;)   -  person Xavier Shay    schedule 01.09.2018
comment
Какую ssh библиотеку вы используете?   -  person Cosmic Ossifrage    schedule 02.09.2018


Ответы (1)


Это файл сертификата 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) потерпит неудачу для файлов открытого ключа без сертификата! (Действительно, для соединений без сертификата вам, вероятно, вообще не нужно нужно читать открытый ключ.)

person Cosmic Ossifrage    schedule 02.09.2018
comment
Спасибо как за четкое объяснение концепции, так и за рабочий код. Я смог успешно использовать это для решения моей проблемы. - person Xavier Shay; 03.09.2018
comment
Удивительно @XavierShay, приятно слышать. Спасибо за ответ! - person Cosmic Ossifrage; 03.09.2018