Ubuntu20.04でHashiCorpVaultを使用してシークレットを安全に管理する方法
序章
Vault は、APIキー、アクセストークン、パスワードなどのシークレットを保存および配布するための安全で信頼性の高い方法を提供するオープンソースツールです。 Vaultのようなソフトウェアは、シークレットや機密データの使用を必要とするアプリケーションを展開するときに非常に重要になる可能性があります。
このチュートリアルでは、次のことを行います。
- Vaultをインストールし、システムサービスとして構成します
- 暗号化されたオンディスクデータストアを初期化します
- TLSを介して機密値を安全に保存および取得する
いくつかの追加ポリシーを設定すると、Vaultを使用して、さまざまなアプリケーションやツールの機密データを安全に管理できるようになります。
機密情報を管理する他のサービスと同様に、本番環境のような環境で使用する前に、Vaultの導入のベストプラクティスに関する追加のドキュメントを読むことを検討する必要があります。 たとえば、 Vaultの本番強化ガイドは、ポリシー、ルートトークン、監査などのトピックをカバーしています。
前提条件
このガイドを開始する前に、次のものが必要です。
- Ubuntu 20.04の初期セットアップガイドに従ってセットアップされた1つのUbuntu20.04サーバー(sudo非rootユーザーとファイアウォールを含む)。
- VaultのHTTPAPIを保護するために使用するTLS証明書。 Ubuntu20.04用のこのCertbotスタンドアロンモードチュートリアルに従って無料で入手できます。
注:パッケージを初めてインストールすると、Vaultは自己署名TLS証明書を生成します。 Vaultで使用するドメイン名またはTLS証明書がないが、このチュートリアルの手順を実行したい場合は、このチュートリアルのコマンドに-tls-skip-verify
フラグを追加するか、次の方法でTLS検証をスキップできます。 VAULT_SKIP_VERIFY
環境変数を定義します。
このオプションは、Vaultの実験にのみ適しており、実稼働環境では使用しないでください。
ステップ1—Vaultをインストールする
HashiCorpはVaultを典型的なDebian/Ubuntuパッケージとして提供しているため、サーバーのパッケージソースのリストにパッケージリポジトリを追加する通常の手順を実行します。
まず、Hashicorpの GPGキーをパッケージマネージャーに追加して、システムがパッケージリポジトリを信頼するようにします。
- curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
次に、リポジトリ自体をパッケージソースのリストに追加して、定期的な更新がチェックされるようにします。
- sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
次に、パッケージをインストールします。
- sudo apt install vault
これで、vault
コマンドを使用できます。 Vaultのバージョンをチェックして、動作することを確認してください。
- vault --version
OutputVault v1.8.5 (647eccfe0bd5817bdd8628f3c3171402dfc8a8fc)
Vault実行可能ファイルはサーバーにインストールされているため、次のステップは、システムサービスとして実行するようにVault実行可能ファイルを構成することです。
ステップ2—Vaultを構成する
Vaultパッケージをインストールすると、システムにvault
vault ユーザーが自動的に作成され、Vaultをバックグラウンドで実行するためのシステムサービスがセットアップされます。 Let’s Encryptによって生成されたHTTPS証明書を使用するには、デフォルトの構成にいくつかの変更を加える必要があります。
注:このチュートリアルでは、デフォルトで、Vaultはファイルシステムバックエンドを使用して、暗号化されたシークレットを/opt/vault
のローカルファイルシステムに保存します。 これは、複製する必要のないローカルまたは単一サーバーのデプロイメントに適しています。 Consulバックエンドなどの他のVaultバックエンドは、暗号化されたシークレットを分散キー/値ストア内に保存します。
Vaultのデフォルト設定は/etc/vault.d/vault.hcl
に保存されます。 このファイルを使用して、暗号化されたシークレットが保存されている場所など、Vaultのさまざまなオプションを制御します。
nano
またはお好みのテキストエディタを使用してvault.hcl
を開きます。
- sudo nano /etc/vault.d/vault.hcl
このブロックを含むファイルのlistener "tcp"
セクションを見つけます。 nano
を使用している場合は、Ctrl+W
を押してから、listener “tcp”
と入力して、その行を直接検索できます。
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/opt/vault/tls/tls.crt"
tls_key_file = "/opt/vault/tls/tls.key"
...
}
tls_cert_file
行とtls_key_file
行を編集して、Let’sEncryptの証明書とキーファイルを指すようにします。 各行の強調表示されたyour_domain
部分の代わりに、独自のドメイン名に置き換えることを忘れないでください。
listener "tcp" {
...
tls_cert_file = "/etc/letsencrypt/live/your_domain/fullchain.pem"
tls_key_file = "/etc/letsencrypt/live/your_domain/privkey.pem"
}
注:このサーバーへの外部接続を今のところ防ぐために、address = "0.0.0.0:8200"
もaddress = “127.0.0.1:8200”
に変更する必要があります。 127.0.0.1
は、ローカルホスト専用の予約済みアドレスです。 これは、サービスが適切に保護される前に、サービスがパブリックインターネットに公開されないようにするためです。 これは後で更新できますが、今のところ、この構成変更により、vault
コマンドを使用して、HTTPSで保護されたドメイン名を正しく解決できるようになります。
ファイルを保存して閉じます。 nano
を使用している場合は、Ctrl+X
を押し、ファイルの保存を求めるメッセージが表示されたらY
を押し、Enter
を押して確認します。
次に、vault
システムユーザーにも、これらの証明書を読み取るためのアクセス許可が必要です。 デフォルトでは、これらの証明書と秘密鍵にはroot
からのみアクセスできます。 これらを安全に利用できるようにするために、これらのファイルにアクセスするためのpki
という特別なグループを作成します。 グループを作成し、vault
ユーザーを追加します。
- sudo groupadd pki
/etc/letsencrypt
ディレクトリ内の2つのディレクトリのアクセス許可を更新して、pki
グループのメンバーがコンテンツを読み取れるようにします。
- sudo chgrp -R pki /etc/letsencrypt/archive
- sudo chgrp -R pki /etc/letsencrypt/live
- sudo chmod -R g+rx /etc/letsencrypt/archive
- sudo chmod -R g+rx /etc/letsencrypt/live
次に、vault
ユーザーをpki
グループに追加します。 これにより、Vaultが証明書にアクセスできるようになり、HTTPSを介して安全にリクエストを処理できるようになります。
- sudo usermod -a -G pki vault
便宜上の最後のステップとして、/etc/hosts
にルールを追加して、Vaultへのリクエストをlocalhost
に送信します。
次のコマンドのyour_domain
を、Let’sEncrypt証明書を取得したドメインに置き換えます。
- echo 127.0.0.1 your_domain.com | sudo tee -a /etc/hosts
このコマンドは、127.0.0.1 your_domain.com
行を/etc/hosts
に追加して、Vaultサーバーでyour_domain.com
に対して行うHTTP要求はDNSを無視し、localhost
に直接送信されるようにします。 。
Vaultサービスがセットアップされ、Vault構成ファイルが完成したら、Vaultを起動してシークレットストアを初期化する準備が整いました。
ステップ3—Vaultを初期化する
Vaultを最初に起動すると、初期化されません。つまり、データを受信して保存する準備ができていません。 チュートリアルのこのセクションでは、Vaultサーバーを起動し、Vaultのシークレットストアを開封(開く)するために使用される一連のシークレットキーを使用してサーバーを初期化します。
Vaultを初めて起動すると、暗号化されたシークレットを実際に保存するバックエンドも初期化されません。 Vaultシステムサービスを開始してバックエンドを初期化し、Vault自体の実行を開始します。
- sudo systemctl start vault.service
クイックチェックを実行して、サービスが正常に開始されたことを確認できます。
- sudo systemctl status vault.service
次のような出力が表示されます。
Output● vault.service - "HashiCorp Vault - A tool for managing secrets"
Loaded: loaded (/lib/systemd/system/vault.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2021-11-16 21:55:13 UTC; 22s ago
Docs: https://www.vaultproject.io/docs/
Main PID: 104207 (vault)
Tasks: 7 (limit: 1137)
Memory: 179.3M
CGroup: /system.slice/vault.service
└─104207 /usr/bin/vault server -config=/etc/vault.d/vault.hcl
そのコマンドの出力には、プロセスIDやリソースの使用状況など、実行中のサービスに関するいくつかの情報が含まれている必要があります。 次の行が出力に含まれていることを確認してください。これは、サービスが正しく実行されていることを示しています。
Output. . .
Active: active (running)
. . .
サービスがアクティブでない場合は、コマンドの出力の最後にある付随するログ行を調べて、Vaultの出力を確認してください。これは、問題を特定するのに役立ちます。
次に、vault
コマンドにVaultサーバーへの接続方法を指示する環境変数を設定します。 ステップ1で、ローカルループバックインターフェイスでのみリッスンするようにVaultを構成したため、VAULT_ADDR
環境変数をローカルHTTPSエンドポイントに設定します。
- export VAULT_ADDR=https://your_domain:8200
vault
コマンドがデーモンと通信できるようになりました。 HTTPS証明書を適切に検証するには、単にlocalhost
または127.0.0.1
ではなく実際のホスト名を定義する必要があることに注意してください。
ボールトサーバーのステータスを確認して、ボールトサーバーが初期化されていない状態になっていることを確認します。
- vault status
サーバーは、機能しているがまだ初期化されていないことがわかるように、出力を返す必要があります。
Key Value
--- -----
Seal Type shamir
Initialized false
Sealed true
Total Shares 0
Threshold 0
Unseal Progress 0/0
Unseal Nonce n/a
Version 1.8.5
Storage Type file
HA Enabled false
Vaultが初期化時に公開する情報は2つあり、他の時点では利用できません。
- 初期ルートトークン。 これは、Vault展開に対するルート権限に相当し、すべてのVaultポリシー、マウント、およびシークレットの管理を可能にします。
- キーを開封します。 これらは、デーモンの起動時にVaultのシールを解除するために使用されます。これにより、Vaultデーモンがバックエンドシークレットストアを復号化できるようになります。
より具体的には、Vaultの開封プロセスは、キー共有によって形成されたキーを使用してバックエンドを復号化します。 Vaultを最初に初期化するときに、作成するアンシールキーの数と、Vaultを正常にアンシールするためにアンシール時に必要な数を選択できます。 Vaultのシーリングメカニズムの詳細については、Vaultのドキュメントを参照してください。
アンシールパラメータの一般的な構成は、3つのキーを作成し、アンシール時にそれらのキーのうち少なくとも2つを必要とすることです。 これにより、重要なキー共有を分離して別々の場所に保存し、侵害したキー共有がVaultの開封に十分でないことを確認できます。
つまり、Vaultを起動するたびに、サービスを使用可能にして使用できるようにするために、少なくとも2つの開封キーが必要になります。 封印されている間、実際の秘密の値を保存するファイルは暗号化されたままになり、アクセスできなくなります。
-key-shares=3
オプションを使用して3つの開封キーでボールトを初期化し、-key-threshold=2
フラグでボールトを開封するには少なくとも2つのキーが必要です::
- vault operator init -key-shares=3 -key-threshold=2
次のような出力が表示されます。
OutputUnseal Key 1: eZcJeydRrqeSMZ1zTN+VVll9TFT2KvJy7VlnxUgtvuz5
Unseal Key 2: ntmqCKq8rgNnKT1YSLCjVmCCZBAA3NwUeqxIyRpYD4Wm
Unseal Key 3: 3FK1+Hsorh4p8/L9mki3VskaEU2eQhLqGOI/pJkTHMbx
Initial Root Token: s.hY0ieybfDqCadz7JpL88uO3x
必ず各開封トークンと最初のルートトークンを安全な方法で保存してください。 これらのキーとルートトークンを再度取得することはできなくなります。 たとえば、1つのオプションは、1つの開封キーをパスワードマネージャーに保存し、別のキーをUSBドライブに保存し、別のキーをGPG暗号化ファイルに保存することです。
vault status
をもう一度調べると、Initialized
ステータスがtrue
に設定され、Total Shares
とThreshold
の値にボールトを開封するために必要なキーシャードの数とキーの最小数。
- vault status
Output. . .
Initialized true
Sealed true
Total Shares 3
Threshold 2
Unseal Progress 0/2
. . .
Unseal Progess
行に値0/2
が表示されていることに注意してください。 新しく作成した開封トークンを使用して、Vaultの開封を開始します。 vault operator unseal
コマンドを実行し、プロンプトが表示されたら任意のキーを入力します。
- vault operator unseal
コマンドは、開封トークンを要求します。
OutputKey (will be hidden):
入力後、コマンドからの出力は、開封が進行中であることを示しますが、Vaultを使用する準備ができるまでにもう1つの開封キーが必要です。
OutputKey Value
--- -----
Seal Type shamir
Initialized true
Sealed true
Total Shares 3
Threshold 2
Unseal Progress 1/2
Unseal Nonce 0f3a328b-e0c6-6294-d6a2-56da49271dff
Version 1.8.5
Storage Type file
HA Enabled false
Unseal Progress 1/2
行が出力でどのように変化したかに注目してください。 unseal
コマンドを再実行してください。
- vault operator unseal
そして、すでに使用したものとは異なるキーを入力します。
OutputKey (will be hidden):
コマンドの出力は、開封プロセスが正常に完了したことを示しています。
OutputKey Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 3
Threshold 2
Version 1.8.5
Storage Type file
Cluster Name vault-cluster-3042c7bc
Cluster ID c3e9d814-cf2a-2901-f0e4-ebc52d29e5cc
HA Enabled false
これでVaultは開封され、使用できるようになりました。 これらの開封手順は、Vaultを起動または再起動するたびに必要です。
ただし、開封は、トークンによって認証されるVaultとの通常の相互作用(値の読み取りや書き込みなど)とは異なるプロセスです。 次の手順では、シークレット値を格納し、Vaultの特定のパスに対して読み取り/書き込みを行うために必要なアクセストークンとポリシーを作成します。
ステップ4—秘密の読み取りと書き込み
Vaultで使用できるシークレットバックエンドはいくつかありますが、この例では、kvシークレットバックエンドを使用します。 このバックエンドは、単純なキーと値のペアをVaultに格納します。 ただし、デフォルトでは有効になっていません。
チュートリアルのこのセクションでは、kv
シークレットバックエンドを有効にしてから、シークレットの読み取りと書き込みの方法を学習します。
まず、使いやすさのために、以前に生成されたルートトークンをシェル変数に保存します。
- root_token=your_root_token_here
次に、ルートトークンで認証しているときに、kv
バックエンドを有効にします。
- VAULT_TOKEN=$root_token vault secrets enable kv
コマンドが成功すると、次のような出力が表示されます。
OutputSuccess! Enabled the kv secrets engine at: kv/
次に、それが利用可能なシークレットバックエンドのローカルリストに追加されていることを確認できます。
- VAULT_TOKEN=$root_token vault secrets list
次のような出力を受け取るはずです。
OutputPath Type Accessor Description
---- ---- -------- -----------
cubbyhole/ cubbyhole cubbyhole_abc1631b per-token private secret storage
identity/ identity identity_631fe262 identity store
kv/ kv kv_4d5855c8 n/a
sys/ system system_79b13f2f system endpoints used for control, policy and debugging
新しいkv
バックエンドが有効になっていることを示す強調表示された行に注意してください。 これで、このバックエンドを使用していくつかのデータを保存できます。
- VAULT_TOKEN=$root_token vault write kv/message value=mypassword
このコマンドでは、強調表示されたkv/
プレフィックスは、kv
パスにマウントされたkv
バックエンドに書き込み、キーvalue
を格納していることを示します。パスmessage
で、値はmypassword
です。 スーパーユーザー権限を持つルートトークンを使用して、一般的なシークレットを記述しました。
vault read
コマンドを使用して作成したシークレットを確認してください。
- VAULT_TOKEN=$root_token vault read kv/message
作成したシークレットの内容とともに、次のような出力を受け取るはずです。
OutputKey Value
--- -----
refresh_interval 768h
value mypassword
ただし、ルートトークンのみを使用してVaultを作成、読み取り、またはその他の方法で操作することは、安全ではなく、チーム設定でスケーラブルであり、シークレットへのきめ細かいアクセス制御を許可しません。 次のセクションでは、ポリシーを定義し、追加のアクセストークンを作成して、ユーザーがVaultを操作する方法を制限する方法を学習します。
ステップ5—承認ポリシーを作成する
実際のシナリオでは、外部ツールが使用できるAPIキーやパスワードなどの値を保存できます。 ルートトークンを使用してシークレット値を再度読み取ることもできますが、単一のシークレットに対する読み取り専用のアクセス許可を持つ特権の低いトークンを生成することを示しています。
チュートリアルのこのセクションでは、シークレットへの読み取り専用アクセスを強制するVaultポリシーを作成します。 ポリシーを作成するには、ファイルを編集してから、vault policy
コマンドを使用してVaultにロードする必要があります。
ポリシーの作成を開始するには、nano
またはお好みのエディターを使用して、policy.hcl
というファイルを開きます。
- nano policy.hcl
シークレットパスへの読み取り専用アクセスを定義する次のVaultポリシーをファイルに入力します。
path "kv/message" {
capabilities = ["read"]
}
ファイルを保存して閉じてから、このポリシーをVaultに書き込みます。 次のコマンドは、policy.hcl
ファイルをVaultにロードし、読み取り専用機能を備えたmessage-readonly
という名前のポリシーを作成します。
- VAULT_TOKEN=$root_token vault policy write message-readonly policy.hcl
次に、Vaultへの読み取り専用アクセスに使用するトークンを作成します。 -policy=”message-readonly”
フラグをvault token create
コマンドに追加して、作成した新しいポリシーを使用します。
- VAULT_TOKEN=$root_token vault token create -policy="message-readonly"
出力は次のようになります。
OutputKey Value
--- -----
token your_token_value
token_accessor your_token_accessor
token_duration 768h0m0s
token_renewable true
token_policies ["default" "message-readonly"]
identity_policies []
policies ["default" "message-readonly"]
強調表示されたyour_token_value
値をapp_token
という環境変数に保存します。
- app_token=your_token_value
app_token
の値を使用して、パスkv/message
に格納されているデータにアクセスできます(Vaultには他の値はありません)。
- VAULT_TOKEN=$app_token vault read kv/message
OutputKey Value
--- -----
refresh_interval 768h0m0s
value mypassword
この非特権トークンが、Vaultにシークレットを一覧表示するなど、他の操作を実行できないことをテストすることもできます。
- VAULT_TOKEN=$app_token vault list kv/
OutputError reading kv/: Error making API request.
URL: GET https://your_domain:8200/v1/secret?list=true
Code: 403. Errors:
* 1 error occurred:
* permission denied
これにより、特権の低いアプリトークンが、Vaultポリシーで明示的に指定されているもの以外の破壊的なアクションを実行したり、他の秘密の値にアクセスしたりできないことが確認されます。 読み取り専用トークンを引き続き使用する場合は、将来使用できるように安全な場所に記録してください。
結論
この記事では、Ubuntu 20.04にVaultをインストール、構成、およびデプロイしました。 また、Vaultを開封するためのシャードキーを作成し、kv
バックエンドシークレットストアを有効にし、ユーザーがVaultシークレットを操作する方法を制限する読み取り専用ポリシーを定義しました。
このチュートリアルでは、非特権トークンの使用方法のみを示しましたが、Vaultのドキュメントには、シークレットを保存およびアクセスするための追加の方法と代替認証方法の例がさらにあります。
これらの手順は、Vaultのコア機能のいくつかを展開して使用する方法を示しています。 ニーズによっては、他の構成変更やより複雑なポリシーが必要になる場合があります。 必ずVaultのドキュメントを読み、必要に応じて適切な構成変更を行ってください。 本番環境に対応した変更には、次のものが含まれる場合があります。
-
日常的に使用するための特権の低いトークンを生成します。 これらのトークンが使用する必要のある特定のポリシーは、特定のユースケースによって異なりますが、このチュートリアルの例
app_token
は、制限付き特権のトークンとポリシーを作成する方法を示しています。 -
チームが使用するサービスの一部としてVaultを展開する場合は、各チームメンバーの封印解除キーを使用してVaultを初期化します。 このアプローチにより、Vaultのストレージは、複数のチームメンバーがプロセスに参加している場合にのみ復号化されます。