Carpe Diem

備忘録

VaultでSSHをCA認証に

背景

AWSを運用しているとEC2のsshのキーペア管理が難しいです。
GCPであればアカウントを持てば自動で各ノードにsshできる仕組みがありますが、AWSは各インスタンスsshのキーペアを1つだけ登録するようになっているため、複数人で運用するにはぱっと以下の方法が浮かびます。

  • 複数人でキーペアの秘密鍵を共有
  • authorized_keysに全員の公開鍵を登録
  • adduserで各メンバーのsshを設定

しかしそれぞれ問題があります。秘密鍵の共有はセキュリティ的に大きな問題がありますし、後の2つは起動時に設定するのが非常に手間です。
仮にLambdaなどで新規サーバに対して設定する処理を自動化しても、あとからジョインしたメンバーは別途対応しなくてはいけません。

そこでsshを公開鍵認証でなく、CA認証を使うことで複数のメンバーでも管理しやすくします。
CA認証は以下の記事で非常に分かりやすく説明されています。

SSH CA認証まとめ

今回このCA認証を、Vaultを使って簡単&セキュアに構築します。

環境

  • Vault 0.10.3

設定

Vault Server

Secret Engineをマウントします。ドキュメントに合わせてssh-client-signerとします。これは任意です。

$ vault secrets enable -path=ssh-client-signer ssh
Success! Enabled the ssh secrets engine at: ssh-client-signer/

CA(認証局)の用意

次にCA(認証局)を用意します。CA用の秘密鍵と公開鍵が生成されます。

$ vault write ssh-client-signer/config/ca generate_signing_key=true
Key           Value
---           -----
public_key    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAA...

roleの設定

sshユーザ与えるroleの設定です。my-roleの部分は任意の値です。

$ vault write ssh-client-signer/roles/my-role -<<"EOH"
{
  "allow_user_certificates": true,
  "allowed_users": "*",
  "default_extensions": [
    {
      "permit-pty": ""
    }
  ],
  "key_type": "ca",
  "default_user": "ubuntu",
  "ttl": "30m0s"
}
EOH

Success! Data written to: ssh-client-signer/roles/my-role

今回はサンプルのため署名後30分間のみ有効にするという設定にしています。
permit-ptyというのはpty(=sshターミナル)を許可するという設定です。
他にもいろんなextensionsがあるので、必要であれば設定してください。

ホスト側

各ホストはvault clientをインストールしない前提で進めます。

各ホストにCAの公開鍵を配置

CA認証(あとで発行するデジタル証明書の検証)用のCA公開鍵を各ホストに置くことになるので、curlで取得します。

# curl -o /etc/ssh/trusted-user-ca-keys.pem http://{vault_addr}:8200/v1/ssh-client-signer/public_key

ちなみにvault clientでも取得できますが、その場合はvault client自体が必要ですし、HTTP APIと違ってトークンも必要なので各サーバに置くケースには向いてません。
なのでcurlをお勧めします。

/etc/ssh/sshd_config

取得した公開鍵を/etc/ssh/sshd_configTrustedUserCAKeysに指定します。

TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem

設定したらsshdを再起動してください。

クライアント側

クライアント側はvault clientをインストール済みと想定します。

クライアントの公開鍵に対しvaultのCAに署名してもらう

先程設定したroleを指定して署名をしてデジタル証明書(署名された公開鍵)を発行します。

vault write ssh-client-signer/sign/my-role \
    public_key=@$HOME/.ssh/id_rsa.pub

Key              Value
---              -----
serial_number    3bf4efaf2cc7fd6d
signed_key       ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2Vyd...

signed_keyをコピペしてデジタル証明書を保存してもいいですし、以下のように直接保存するのもOKです。

vault write -field=signed_key ssh-client-signer/sign/my-role \
    public_key=@$HOME/.ssh/id_rsa.pub > ~/.ssh/signed-cert.pub

ちなみにこの証明書の発行がwriteコマンドしかないのは、おそらくはvaultがデータを保存せずに単に署名結果をstdoutに出しているだけだからです。

Transit - Secrets Engines - Vault by HashiCorp も同じようにデータは保持せず、暗号化・復号をstdoutに出力します。

証明書の確認

証明書の有効期限などを確認します。

$ ssh-keygen -Lf ~/.ssh/signed-cert.pub
/Users/jun06t/.ssh/signed-cert.pub:
        Type: ssh-rsa-cert-v01@openssh.com user certificate
        Public key: RSA-CERT SHA256:cx2J6jOv6YKT0Wu3rJkyRiKjqZcBng3t7bLT9bNhczc
        Signing CA: RSA SHA256:VmdOfyA6D01mzdkhEZVBhQgrjzhOFMADmpFgj7ToteY
        Key ID: "vault-token-731d89ea33afe98293d16bb7ac99324622a3a997019e0dededb2d3f5b3617337"
        Serial: 1152433828803108559
        Valid: from 2018-07-10T17:13:20 to 2018-07-10T17:43:50
        Principals: 
                ubuntu
        Critical Options: (none)
        Extensions: 
                permit-pty

roleで設定した通り30分間のみ有効ですね。

動作確認

ローカルの秘密鍵と、先程のデジタル証明書(vaultのCAで署名済みな公開鍵)を使ってsshします。

$ ssh -i ~/.ssh/signed-cert.pub -i ~/.ssh/id_rsa ubuntu@{vaultのCAの公開鍵を置いたホスト}

Welcome to Ubuntu 16.04.4 LTS (GNU/Linux 4.4.0-1062-aws x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

8 packages can be updated.
0 updates are security updates.

ログインできました!!

両方指定がちょっと手間かも

ちなみにsigned-cert.pub秘密鍵と同じ名前+-cert.pubにすれば(id_rsa-cert.pub)指定は省けます。

$ ssh -i ~/.ssh/id_rsa ubuntu@{vaultのCAの公開鍵を置いたホスト}

有効期限過ぎたら?

デジタル証明書の有効期限が過ぎるとsshできなくなります。

$ ssh -i ~/.ssh/signed-cert.pub -i ~/.ssh/id_rsa ubuntu@{vaultのCAの公開鍵を置いたホスト}
Permission denied (publickey).

メリット

以下のようなチーム開発であるあるなケースに対応できます。

サーバが増えた

CA公開鍵を登録するだけでOK。
登録済みのAMIを作れば簡単。

メンバーが増えた

新規メンバーの公開鍵をCAで署名(デジタル証明書の発行)すればOK

メンバーが退職した

デジタル証明書には有効期限があり、そのうち使えなくなるのでOK。
既存メンバーの有効期限はvaultコマンドでサクッと更新可能。

まとめ

vaultを使ったsshのCA認証方法を説明しました。
CA認証を使えば、サーバへの設定は最小かつメンバーは自分の鍵を使えるのでチーム開発でのsshがよりセキュアになります。

ソース