(連載) HashiCorp活用例2: 動的なバックエンドSSL証明書の生成・管理
東京エレクトロンデバイスではHashiCorp社製品とその他各社製品とのマルチベンダー連携を通じて、お客様のWebアプリやクラウド、ITインフラなどの展開から運用までを効率化できるソリューション開発に取り組んでいます。さまざまな活用例をご紹介することで、HashiCorp社製品の提供する価値や可能性を発信していきたいと思っております。
はじめに
本記事で取り扱うのは動的なバックエンドSSL証明書の管理となります。
前回の記事で取り上げたユースケースに基づいて記載しておりますので、ユースケースの詳細につきましては前回の記事をご参照ください。
連載記事一覧:
- Webアプリ用マルチベンダーインフラの自動構築
- 動的なバックエンドSSL証明書の管理 ←本記事
- 動的なDNSレコード管理
- 動的なロードバランサの構築
- プライベートネットワークでのIaC
- 一連のWebアプリ用のマルチベンダーインフラ展開を効率化
動的なバックエンドSSL証明書の利用
本ユースケースの構成ではバックエンド通信においてもSSL通信を有効としています。つまり、それぞれのアプリケーションVMにもSSL証明書を設置する必要があります。
しかしながらバックエンドで稼働するアプリケーションVM群は負荷状況に応じて増減(スケールアウト/イン)することを考えなければなりません。数台規模であれば手動の作業でも間に合うかもしれませんが、数十台、数百台と構成の規模が大きくなると手動での管理は煩雑なものになってしまいます。
今回の記事ではそういった各VMへSSL証明書の設置・管理をVaultサーバーとVault エージェントを用いて自動化する手法について解説していきます。
Vaultサーバー と Vaultエージェント
VaultはHashiCorp社にて提供されているシークレット管理を行うためのアプリケーションです。ここで取り扱うシークレットというのはシステムにおけるパスワード、証明書、トークン等の外部に漏れては困る情報全般を指します。
Vaultをシステムに組み込むことでシークレットはVaultサーバーで集中管理できることになります。
また、Vaultではシークレット管理だけではなく発行も可能です。シークレットのローテーションや、期限付きシークレットの発行を用いることで更新漏れや作りっぱなしという状態を防ぎ適切な管理を実現することができます。
VaultエージェントはVaultサーバーと通信するためのクライアントツールです。今回の構成ではアプリケーションが稼働するVM上で稼働させる想定となります。
Vaultエージェントを用いることでVaultサーバーとの通信を容易にし、VM側に必要なシークレットの取得や更新の負荷を軽減することが可能となります。どういった設定が必要になるのかという解説は次項で記載致します。
参考サイト:
バックエンド用SSLサーバー証明書の自動発行
以下の流れで設定を進めます。
- Vaultサーバーの設定
- Vault認証ID/シークレットの発行
- Vaultエージェントの設定
Vaultサーバーの設定
今回の構成では、各アプリケーションVM用の認証設定を初期構築時から有効になるようTerraformを使って設定・構築しています。
以下の条件を前提にVaultを設定していきます。
- Vaultエージェントの認証方法はAppRoleを使用
- SSLサーバー証明書発行のため、自己署名ルートCA、同中間CAを作成
AppRoleの設定(Vaultサーバー側)
※Terraform構成ファイルの記述サンプル
◆Vaultサーバーの認証設定 AppRoleの宣言
resource "vault_auth_backend" "approle" {
namespace = 許可する名前空間
path = 認証メソッドのパス
type = "approle" ←認証メソッドのタイプ
}
◆AppRole認証に用いるバックエンドロールの設定
resource "vault_approle_auth_backend_role" "fakeservice" {
backend = 設定するシークレットバックエンド名
token_policies = 生成されたトークンにエンコードするポリシーリスト
}
◆AppRole認証バックエンド シークレットIDの設定
resource "vault_approle_auth_backend_role_secret_id" "fakeservice" {
role_name = シークレットIDを作成するためロール
backend = 設定するシークレットバックエンド名
}
証明書の設定と自己署名ルートCA、中間CAの作成(Vaultサーバー側)
※Terraform構成ファイルの記述サンプル
◆自己認証局の作成(ルートCA)
resource "vault_mount" "root_ca" {
namespace = 許可する名前空間
path = シークレットバックエンドのパス
type = "pki" ←バックエンドのタイプ
description = 説明文
default_lease_ttl_seconds = トークンおよびシークレットのデフォルトリース期間(秒)
max_lease_ttl_seconds = トークンおよびシークレットの最大リース可能時間(秒)
}
◆発行証明書エンドポイント、CRL配布ポイントを設定(ルートCA)
resource "vault_pki_secret_backend_config_urls" "root_ca" {
namespace = 許可する名前空間
backend = シークレットバックエンドの指定
issuing_certificates = 証明書のURL
crl_distribution_points = CRL配布ポイントのURL
}
◆PKIシークレットバックエンド用自己署名CA証明書と秘密鍵の生成
resource "vault_pki_secret_backend_root_cert" "root_ca" {
namespace = 許可する名前空間
backend = リソースが属するPKIシークレットバックエンド
type = "internal" ←作成する中間体の形式
common_name = コモンネーム
}
◆自己認証局の作成(中間CA)
resource "vault_mount" "inter_ca" {
namespace = 許可する名前空間
path = シークレットバックエンドのパス
type = "pki" ←バックエンドのタイプ
description = 説明文
default_lease_ttl_seconds = トークンおよびシークレットのデフォルトリース期間(秒)
max_lease_ttl_seconds = トークンおよびシークレットの最大リース可能時間(秒)
}
◆発行証明書エンドポイント、CRL配布ポイントを設定(中間CA)
resource "vault_pki_secret_backend_config_urls" "inter_ca" {
namespace = 許可する名前空間
backend = シークレットバックエンドの指定
issuing_certificates = 証明書のURL
crl_distribution_points = CRL配布ポイントのURL
}
◆PKI Secret Backend に署名するための新しい秘密鍵と CSR を生成(中間CA)
resource "vault_pki_secret_backend_intermediate_cert_request" "inter_ca" {
namespace = 許可する名前空間
backend = リソースが属するPKIシークレットバックエンド
type = 作成する形式。"exported" or "internal" or "kms"
common_name = コモンネーム
}
◆ルートCAがサインした中間CAの証明書生成(中間CA)
resource "vault_pki_secret_backend_root_sign_intermediate" "inter_ca" {
namespace = 許可する名前空間
backend = リソースが属する PKI シークレット バックエンド
csr = CSR
common_name = コモンネーム
exclude_cn_from_sans = true ←SANからコモンネームを除外する設定
revoke = true ←リソース削除時に証明書を失効する
format = "pem_bundle" ←データ形式
}
◆中間CAの証明書を PKI Secret Backend に紐づける(中間CA)
resource "vault_pki_secret_backend_intermediate_set_signed" "inter_ca" {
namespace = 許可する名前空間
backend = リソースが属する PKI シークレット バックエンド
certificate = 設定する証明書
}
◆証明書を利用するロールを作成(中間CA)
resource "vault_pki_secret_backend_role" "inter_ca" {
namespace = 許可する名前空間
backend =
name = ロール名
max_ttl = 最大リースTTL
ttl = TTL
allow_ip_sans = true ←IP SANの許可
allowed_domains = 証明書に許可されるドメインリスト
allow_subdomains = true ←サブドメインの許可
generate_lease = true ←リースの作成許可
allow_localhost = false ←localhostからの許可
key_usage = ["DigitalSignature", "KeyAgreement", "KeyEncipherment"] ←証明書について許容される鍵の使用制約
key_bits = 4096 ←鍵作成に用いるビット数
}
Vault認証ID/シークレットの発行
VaultエージェントがVaultサーバーへアクセスするために利用する認証情報として、AppRole IDとSecret IDをVaultサーバーから生成し、取得します。
AppRole IDとSecret IDの取得(Vaultサーバー側)
※Terraform構成ファイルの記述サンプル
◆AppRole IDの取得
resource "vault_approle_auth_backend_role" "fakeservice" {
backend = 設定するシークレットバックエンド名
role_name = シークレットIDを作成するためロール
token_policies = 生成されたトークンにエンコードするポリシーリスト
}
◆上記AppRole IDに紐づくSecret IDの取得
resource "vault_approle_auth_backend_role_secret_id" "fakeservice" {
backend = 設定するシークレットバックエンド名
role_name = シークレットIDを作成するためロール
}
Vaultエージェントの設定
アクセスするVaultサーバーの情報やVaultサーバーと連携するために利用するRole、シークレットIDを定義しています。
◆Vaultエージェントの設定
※Vaultエージェント設定ファイル(HCL)の記述サンプル
vault {
address = "https://192.168.1.1:8200" ←Vaultサーバーのアクセス先
ca_cert = "./config/ca.pem" ←VaultサーバーへHTTPSアクセスするためのCA証明書
}
auto_auth {
method "approle" {
mount_path = 認証メソッド(ここではAppRole)のパス
config = {
role_id_file_path = "./config/roleID" ←上記で取得したAppRole IDを記述したファイル
secret_id_file_path = "./config/secretID" ←上記で取得したSecret IDを記述したファイル
remove_secret_id_file_after_reading = false
}
}
sink "file" {
config = {
path = "./config/approleToken"
}
}
}
Vaultサーバーにポリシーが作成されたうえで、Vaultエージェント環境(アプリケーションVM)が起動すると起動後にVaultエージェントが設定されているVaultサーバーと通信を行い、ポリシーで設定されている証明書を自動で取得することができます。
エージェントを起動するには、下記のようなコマンドで起動できます。
◆Vaultエージェント起動コマンド
vault agent -config="Vaultエージェント設定ファイル(HCL)"
次回案内
本記事では、動的なバックエンドSSL証明書の管理についてご紹介しました。
動的な構成において煩雑になりがちな証明書管理やセキュリティ管理の負荷をVaultを用いることで軽減でき、かつセキュリティの品質を十分に保てることをご理解いただけたと思います。
次回は、動的なDNSレコード管理の実装についてご紹介します。
ここまで読んでいただきありがとうございました。