linuxのrootをSSHの証明書認証を使って共有し CERT IDで個々のユーザーを識別する
Linuxのユーザーの管理で何かより良い方法がないかと検索していたら Scalable and secure access with SSH - Facebook CodeでSSHの証明書認証を使った方法が紹介されていたので検証してみました。
上記の記事をざっくりまとめると
- rootを共通アカウントとして使用する
- 証明書認証のCERT IDを使用し個々のユーザーを識別する
- ログは全て集約しているので簡単に分析できる
- AuthorizedPrincipalsFileを使ってアクセス制御を行う
といった感じでしょうか。
証明書認証には以下の理由からHashicorpのVaultを使ってみることにしました。
- 署名に必要な秘密鍵を公開しなくて済むので、ユーザーに公開鍵への署名を任せられます。
- ldap auth methodを使いActive Directoryに認証を任せると、token_display_name(今回の場合はldap-usernameという形式)がCERT IDにセットされるようになり、ユーザーがCERT IDを変更することが出来なくなります。
- Policyで証明書発行時に必要なroleへのアクセスを制限可能になります。
以下を参考に環境を構築しておきます。
Signed SSH Certificates - SSH - Secrets Engines - Vault by HashiCorp
LDAP - Auth Methods - Vault by HashiCorp
ttlの変更
tokenのttlが長すぎなので短くしておきます。
[root@localhost ~]# vault read sys/auth/ldap/tune Key Value --- ----- default_lease_ttl 768h force_no_cache false max_lease_ttl 768h token_type default-service [root@localhost ~]# vault write sys/auth/ldap/tune default_lease_ttl=10m max_lease_ttl=30m Success! Data written to: sys/auth/ldap/tune [root@localhost ~]# vault read sys/auth/ldap/tune Key Value --- ----- default_lease_ttl 10m force_no_cache false max_lease_ttl 30m token_type default-service [root@localhost ~]#
roleの作成
rootというロールを作成し登録します。allow_user_key_idsをtrueにするとCERT IDをユーザーが更新できてしまうのでfalseにしておきます。
allow_usersにはリモートログイン先のユーザー名を指定します。defaultのままだと"*"となりリモートからログイン可能なユーザー全てを指定出来てしまうので注意が必要です。
有効期限は1時間としました。
[root@localhost ~]# vault write ssh-client-signer/roles/root -<<"EOH" { "allow_user_certificates": true, "allow_user_key_ids": "false", "allowed_users": "root", "default_extensions": [ { "permit-pty": "" } ], "key_type": "ca", "default_user": "root", "ttl": "1h" } EOH Success! Data written to: ssh-client-signer/roles/root [root@localhost vault.d]# vault read ssh-client-signer/roles/root Key Value --- ----- allow_bare_domains false allow_host_certificates false allow_subdomains false allow_user_certificates true allow_user_key_ids false allowed_critical_options n/a allowed_domains n/a allowed_extensions n/a allowed_users root default_critical_options map[] default_extensions map[permit-pty:] default_user root key_bits 0 key_id_format n/a key_type ca max_ttl 0s ttl 1h [root@localhost vault.d]#
ポリシーの割り当て
上で作成したロールに対するポリシーを設定し、Active Directoryのmnishikizawaユーザーにポリシーを割り当てます。
[root@localhost ~]# vault policy write ssh-user-root -<<"EOH" > path "ssh-client-signer/sign/root" > { > capabilities = ["update"] > } > EOH Success! Uploaded policy: ssh-user-root [root@localhost vault.d]# vault policy read ssh-user-root # Write ssh certificates path "ssh-client-signer/sign/root" { capabilities = ["update"] } [root@localhost vault.d]# vault write auth/ldap/users/mnishikizawa policies=ssh-user-root Success! Data written to: auth/ldap/users/mnishikizawa [root@localhost vault.d]# vault read auth/ldap/users/mnishikizawa Key Value --- ----- groups n/a policies [ssh-user-root]
証明書の発行
Active Directoryで認証を行い証明書を発行してからrootでSSHログインしてみます。
[vagrant@localhost ~]$ vault login -method=ldap username=mnishikizawa Password (will be hidden): Success! You are now authenticated. The token information displayed below is already stored in the token helper. You do NOT need to run "vault login" again. Future Vault requests will automatically use this token. Key Value --- ----- token s.n0SrSqKIK5LxXyg3eGkCrxX6 token_accessor WzMbzaSQGrD0MRjoKceF0fEO token_duration 10m token_renewable true token_policies ["default" "ssh-user-root"] identity_policies [] policies ["default" "ssh-user-root"] token_meta_username mnishikizawa [vagrant@localhost ~]$ vault token lookup Key Value --- ----- accessor WzMbzaSQGrD0MRjoKceF0fEO creation_time 1549593890 creation_ttl 10m display_name ldap-mnishikizawa entity_id 935ade7e-d2f6-5cc1-9e27-6490a7f38441 expire_time 2019-02-08T02:54:50.066232798Z explicit_max_ttl 0s id s.n0SrSqKIK5LxXyg3eGkCrxX6 issue_time 2019-02-08T02:44:50.066232489Z meta map[username:mnishikizawa] num_uses 0 orphan true path auth/ldap/login/mnishikizawa policies [default ssh-user-root] renewable true ttl 9m58s type service [vagrant@localhost ~]$ vault write -field=signed_key ssh-client-signer/sign/root public_key=@$HOME/.ssh/id_rsa.pub > ~/.ssh/id_rsa-cert.pub [vagrant@localhost ~]$ ssh-keygen -Lf .ssh/id_rsa-cert.pub .ssh/id_rsa-cert.pub: Type: ssh-rsa-cert-v01@openssh.com user certificate Public key: RSA-CERT SHA256:3c7XiI1ULfNbrCqk1icCG0KtuEeew4bBbi1I6gO5mSM Signing CA: RSA SHA256:4LJnUxaq/OiEIRd1TuEjEhyoV/J73Daep/VNVaQMmvc Key ID: "vault-ldap-mnishikizawa-ddced7888d542df35bac2aa4d627021b42adb8479ec386c16e2d48ea03b99923" Serial: 2420534201198412456 Valid: from 2019-02-20T01:33:06 to 2019-02-20T02:33:36 Principals: root Critical Options: (none) Extensions: permit-pty [vagrant@localhost ~]$ ssh root@localhost Last login: Wed Feb 20 01:34:35 2019 [root@localhost ~]# tail /var/log/secure Feb 20 01:34:48 localhost sshd[9396]: Accepted publickey for root from ::1 port 47374 ssh2: RSA-CERT ID vault-ldap-mnishikizawa-ddced7888d542df35bac2aa4d627021b42adb8479ec386c16e2d48ea03b99923 (serial 2420534201198412456) CA RSA SHA256:4LJnUxaq/OiEIRd1TuEjEhyoV/J73Daep/VNVaQMmvc
secureログには
RSA-CERT ID vault-ldap-mnishikizawa-xxxxxx
が記録されrootを共有アカウントとしても個々のユーザーを識別できそうです。
principalsを使ったアクセス制限
AuthorizedPrincipalsFileを使って、設定されたprincipalのみアクセス可能なのか確認してみます。
SSH - Secrets Engines - HTTP API - Vault by HashiCorp
・ default_user (string: "") For the CA type, if you wish this to be a valid principal, it must also be in allowed_users.
この説明通りdefault_userとallowed_usersに同じ値を設定します。
[root@localhost ~]# vault write ssh-client-signer/roles/root -<<"EOH" > { > "allow_user_certificates": true, > "allow_user_key_ids": "false", > "allowed_users": "root,zone-webservers,zone-databases", > "default_extensions": [ > { > "permit-pty": "" > } > ], > "key_type": "ca", > "default_user": "root,zone-webservers,zone-databases", > "ttl": "1h" > } > EOH Success! Data written to: ssh-client-signer/roles/root [root@localhost ~]# vault read ssh-client-signer/roles/root Key Value --- ----- allow_bare_domains false allow_host_certificates false allow_subdomains false allow_user_certificates true allow_user_key_ids false allowed_critical_options n/a allowed_domains n/a allowed_extensions n/a allowed_users root,zone-webservers,zone-databases default_critical_options map[] default_extensions map[permit-pty:] default_user root,zone-webservers,zone-databases key_bits 0 key_id_format n/a key_type ca max_ttl 0s ttl 1h [root@localhost ~]#
principalsがある場合とない場合
[vagrant@localhost ~]$ ssh-keygen -Lf .ssh/id_rsa-cert.pub .ssh/id_rsa-cert.pub: Type: ssh-rsa-cert-v01@openssh.com user certificate Public key: RSA-CERT SHA256:3c7XiI1ULfNbrCqk1icCG0KtuEeew4bBbi1I6gO5mSM Signing CA: RSA SHA256:4LJnUxaq/OiEIRd1TuEjEhyoV/J73Daep/VNVaQMmvc Key ID: "vault-ldap-mnishikizawa-ddced7888d542df35bac2aa4d627021b42adb8479ec386c16e2d48ea03b99923" Serial: 13444262937296389838 Valid: from 2019-02-20T05:16:42 to 2019-02-20T06:17:12 Principals: root zone-databases zone-webservers Critical Options: (none) Extensions: permit-pty [vagrant@localhost ~]$ sudo cat /etc/ssh/auth_principals/root zone-webservers zone-databases [vagrant@localhost ~]$ ssh root@localhost Last login: Wed Feb 20 05:31:38 2019 from ::1 [root@localhost ~]# tail /var/log/secure Feb 20 05:32:33 localhost sshd[11072]: Accepted publickey for root from ::1 port 47498 ssh2: RSA-CERT ID vault-ldap-mnishikizawa-ddced7888d542df35bac2aa4d627021b42adb8479ec386c16e2d48ea03b99923 (serial 13444262937296389838) CA RSA SHA256:4LJnUxaq/OiEIRd1TuEjEhyoV/J73Daep/VNVaQMmvc [root@localhost ~]# logout Connection to localhost closed. [vagrant@localhost ~]$ sudo cat /etc/ssh/auth_principals/root root-everywhere [vagrant@localhost ~]$ ssh root@localhost no such identity: /home/vagrant/.ssh/id_ed25519: No such file or directory Permission denied (publickey,gssapi-keyex,gssapi-with-mic). [vagrant@localhost ~]$ sudo tail /var/log/secure Feb 20 05:33:38 localhost sshd[11135]: error: Certificate does not contain an authorized principal Feb 20 05:33:38 localhost sshd[11135]: Connection closed by ::1 port 47500 [preauth] [vagrant@localhost ~]$
期待通りの動作ですがzone-webservers,zone-databasesというユーザーが存在した場合、そのユーザーでログインできてしまうのが残念です。
まとめ
- SSHアカウントを共有してもCERT IDで個々のユーザーを識別できる。
- ユーザーをサーバー毎に個別に作成しなくてすむ。
- secureログ、auditログの分析基盤があればアカウントを共有しても個々のユーザーのログイン情報を分析可能となり運用も楽になると思う。
参考
SSH - Secrets Engines - HTTP API - Vault by HashiCorp