はじめに
私が所属するaslead DevOpsチームでは、日々変化するユーザの開発サーバ構成に対して、セキュリティを保ちつつ開発業務の効率化・自動化ができないかを検討しています。
この記事では、開発サーバなどのOSにsshでログインする際の方法についてご紹介します。そもそもセキュリティの観点では、OSに対してsshでログインせず操作できる状態が理想ではあります。しかしながら、テスト環境での利便性やレガシーシステムへの接続など、様々な事情でsshのログインを残さざるを得ないケースもあるかと思います。
そこで、Hashicorp社が提供しているVaultを利用し、sshログインするパスワードがランダムに払い出されることでセキュリティを向上させるアプローチを考えてみます。使い捨てのコードを用意する、ワンタイムパスワード(OTP)とは若干異なりますのでご注意下さい。
Vaultとは
(画像は https://medium.com/hashicorp-engineering/vault-enterprise%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6-%EF%BC%91-e5579c2fb8d5 より引用)
公式サイトより、Vaultは主に以下のような機能を持っています。
- Secret Management:様々な環境のパスワードのライフサイクルを管理する
- Data Encryption:データの暗号化/複合化を行う(データ自体は保持せず、変換だけ)
- Identity-based Access:同一人物の様々な環境上のアカウントを一つに取りまとめる
本記事ではSecret Managementに分類される機能を取り扱います。
想定するパスワード運用
以下のようなセキュリティに懸念がある運用ケースを想定し、解消を試みてみます。
- パスワードでsshログインしている
- 構築したOSに共通のパスワードを設定している
- パスワード一覧表をファイルサーバなどに置いて運用している
- 定期的にパスワード変更する運用があるが、規則性のあるパスワードで変更される
- 管理者権限ユーザのパスワードは作業で必要になったメンバに徐々に渡している
Vaultによる解決策
上記の課題に対し、今回は公式チュートリアルを参考にログインするたびにランダムにパスワードが変更されるアプローチをとってみます。
これにより、以下のようなメリットがもたらされます。
- パスワードの文字列を考える必要がなく、構築したどのOSも異なるパスワードになる
- パスワード一覧はVaultが保持し、Vault自体のログインはLDAPなど既存の認証の仕組みが利用できる
- 管理者権限を渡す必要があっても、一度しか使えないためチームごとの権限分割は保たれる
以下では具体的にVaultを構築し、ランダムなパスワードが発行される仕組みについて実装していきます。
実装
###実装する環境
今回は以下の環境で実装を行います。
AWSを利用していますが、ローカルでも確認可能な内容になっています。
- Vault:ver1.5.4
- OS:Amazon Linux 2
- IaaS:AWS EC2サービス
###OS部分の構築
本記事の主な解説対象ではないため、割愛します。
Acrovision社の記事などが参考になるかと思います。
以降は、Vaultが稼働するOSをvault
、ログイン対象OSをtarget
というホスト名で作成し、
お互いに任意の通信が可能な状態で構築された前提で進みます。
###Vaultのインストール
2020/07/24より、Linuxレポジトリからの取得が可能になりましたので、こちらを利用してvault
に対してインストールしていきます。
$ sudo yum install -y yum-utils
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
amzn2-core | 3.7 kB 00:00:00
Package yum-utils-1.1.31-46.amzn2.0.1.noarch already installed and latest version
Nothing to do
$ sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
adding repo from: https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo
grabbing file https://rpm.releases.hashicorp.com/AmazonLinux/hashicorp.repo to /etc/yum.repos.d/hashicorp.repo
repo saved to /etc/yum.repos.d/hashicorp.repo
$ sudo yum install -y vault
~中略~
Complete!
説明の簡便のため、起動は開発者モードで行います。
-dev-listen-address
はvault
のIPアドレスを含めて下さい。EC2の場合は下記のようにメタデータから取得することができます。
$ vault server -dev -dev-root-token-id="root" -dev-listen-address="$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4):8200"
==> Vault server configuration:
Api Address: http://172.31.39.141:8200
Cgo: disabled
Cluster Address: https://172.31.39.141:8201
Go Version: go1.14.7
Listener 1: tcp (addr: "172.31.39.141:8200", cluster address: "172.31.39.141:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
Log Level: info
Mlock: supported: true, enabled: false
Recovery Mode: false
Storage: inmem
Version: Vault v1.5.4
Version Sha: 1a730771ec70149293efe91e1d283b10d255c6d1
~中略~
==> Vault server started! Log data will stream in below:
~省略~
ブラウザからApi Address
に記載されたアドレス(上記ではhttp://172.31.39.141:8200
)にアクセスし、下記のようにログイン画面が表示されればインストールと起動は完了です。
パスワードのランダム化
vault
側の設定
パスワードのランダム化にはSSH Secret Engineという機能を利用します。
利用の仕方については後述するとして、本節では設定を行います。
先ほど開いたものとは別にvault
のターミナルを開きます。
$ export VAULT_ADDR="http://$(curl -s http://169.254.169.25
4/latest/meta-data/local-ipv4):8200"
$ vault secrets enable ssh
Success! Enabled the ssh secrets engine at: ssh/
$ vault write ssh/roles/otp_key_role key_type=otp \
> default_user=ec2-user \
> cidr_list=0.0.0.0/0
Success! Data written to: ssh/roles/otp_key_role
ブラウザからvault
に8200ポートでアクセスし、Tokenにroot
を入力してログイン、Secrets>ssh
にアクセスし、otp_key_role
が表示されれば設定は成功です。
target
側の設定
Vaultにパスワードを照合するVault SSH Helper
を配置します。
target
がインターネットにアクセスできない場合は、アクセス可能な端末で取得し転送して下さい。
$ wget https://releases.hashicorp.com/vault-ssh-helper/0.1.6/vault-ssh-helper_0.1.6_linux_amd64.zip
$ sudo unzip -q vault-ssh-helper_0.1.6_linux_amd64.zip -d /usr/local/bin
$ sudo chmod 0755 /usr/local/bin/vault-ssh-helper
$ sudo chown root:root /usr/local/bin/vault-ssh-helper
Vault SSH Helper
の設定ファイルを作成します。
vault_addr
のIPアドレスはvault
のものを使用します。
tls_skip_verify
でTLS証明書の検証はスキップしていますが、本格利用ではスキップしないことを推奨します。
$ sudo mkdir /etc/vault-ssh-helper.d/
$ sudo tee /etc/vault-ssh-helper.d/config.hcl <<EOF
vault_addr = "http://172.31.39.141:8200"
tls_skip_verify = false
ssh_mount_point = "ssh"
allowed_roles = "*"
EOF
Linuxの認証モジュールであるPAMの設定ファイルを修正し、Vault SSH Helper
を利用した認証を定義します。
$ sudo cp /etc/pam.d/sshd /etc/pam.d/sshd.orig
$ sudo vi /etc/pam.d/sshd
## 以下をコメントアウト
#auth required pam_sepermit.so
#auth substack password-auth
#auth include postlogin
# Used with polkit to reauthorize users in remote sessions
#-auth optional pam_reauthorize.so prepare
## 以下を追記
auth requisite pam_exec.so quiet expose_authtok log=/var/log/vault-ssh.log /usr/local/bin/vault-ssh-helper -dev -config=/etc/vault-ssh-helper.d/config.hcl
auth optional pam_unix.so not_set_pass use_first_pass nodelay
sshdの設定ファイルを修正します。
パスワードではなくチャレンジレスポンス形式で、PAMを使って認証するようにします。
EC2を利用する場合には公式チュートリアルから追加で設定が必要な項目があることに注意して下さい。
$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig
$ sudo vi /etc/ssh/sshd_config
## 以下の設定項目になるように修正
ChallengeResponseAuthentication yes
UsePAM yes
PasswordAuthentication no
## 以下はEC2の場合に設定とコメントアウトが必要
PubkeyAuthentication no
#AuthorizedKeysCommand /opt/aws/bin/eic_run_authorized_keys %u %f
#AuthorizedKeysCommandUser ec2-instance-connect
$ sudo systemctl restart sshd
検証コマンドを実行し、以下のような出力がされていれば設定は完了です。
$ vault-ssh-helper -verify-only -dev -config /etc/vault-ssh-helper.d/config.hcl
==> WARNING: Dev mode is enabled!
[INFO] using SSH mount point: ssh
[INFO] using namespace: us
[INFO] vault-ssh-helper verification successful!
ランダムパスワードでのログイン
(画像は https://learn.hashicorp.com/vault/secrets-management/sm-ssh-otp より引用)
ブラウザからvault
に8200ポートでアクセスし、Tokenにroot
を入力してログインします。
ログイン後、 Secrets>ssh
にアクセスし、otp_key_role
の右にある三点リーダーをクリックします。
表示されたメニューから、 Generate Credential
をクリックします
Username
にはログインしたいユーザを入力します。ここではec2-user
にしています。
IP Address
にはtarget
のIPアドレスを入力します。ここでは172.31.32.67
にしています。
ユーザとIPアドレスを入力したら、Generate
ボタンをクリックします。
target
に対して先ほど控えたパスワードでsshログインするとログインに成功します。
$ ssh ec2-user@172.31.32.67
Password:
先ほどと同じパスワードでもう一度ログインしようとすると、失敗します。
$ ssh ec2-user@172.31.32.67
Password:
Password:
まとめ
本記事で伝えたかったことは以下の2点です。
- 固定のsshログインパスワードや一覧表などの運用はセキュリティに懸念がある
- Hashicorp Vaultによりログインごとにパスワードを払い出すことができる