はじめに
AWS Secrets Managerは皆さん使っていますでしょうか。
AWS上のRDSをより安全でセキュアに使っていくにあたって、このサービスが大いに役に立ちます。
簡単によくある使い道を説明すると、RDSへの接続は、直接パスワードやRDSエンドポイント等の情報をそのままコードに埋め込むではなく、Secrets Managerを経由して必要な情報を取得し、接続していくパターンになります。
さらに、AWS Secrets Managerは、Lambda経由してパスワードをローテーションさせることができるので、パスワード管理などは大変便利になります。
早速、個人が使い方をまとめましたので、当手順を公開していきます。
構成図
全体構成図は下記になります。ポイントをざっくり解説します。
・EC2にSecrets Managerをアクセスできるように、適切なロールを付与します。
・Secrets Managerにシークレット情報を暗号化するために、KMSで暗号化をかけています。
・VPC内にLmabdaがあり、Secrets Managerと通信できるように、VPCエンドポイントを作成しています。
・Secrets ManagerでRDS等の接続情報を管理しており、Lambda経由でRDS接続用のパスワードを定期的にローテーションさせる役割を果たしています。
1.EC2の設定
今回私が使っているEC2は Amazon Linux 2になります。
あらかじめ下記のミドルウェア等をインストールしておきましょう。
①EPEL リポジトリ
$ sudo amazon-linux-extras install epel -y
参考URL:
②AWS CLI
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
$ unzip awscliv2.zip
$ sudo ./aws/install
参考URL:
③jq
$ sudo yum install jq -y
④postgresql
$ sudo yum install postgresql -y
⑤EC2にIAMロールを付与
・SecretsManagerReadWrite
・AmazonEC2RoleforSSM
なお、SSMロールは個人的にSSM Agentを利用するため付与したロールです。
実際Secrets Managerだけを使うのであれば、「SecretsManagerReadWrite」だけで十分です。
2.RDSの作成
今回私が作成したRDSはPostgreSQLです。
RDS作成手順はここで割愛させていただきます。
3.Secrets Managerの作成
上記「2.RDSの作成」で作成されたRDSの「ユーザー名」と「パスワード」を入力します。
暗号化キーは今回「DefaultEncryptionKey」を選択します。
※なお、暗号化キーにKMSカスタマーキーも設定できるが、今回はデフォルを選択します。
「自動ローテーションを有効にする」を選択します。
私は今回ローテーション間隔は30日間と設定します。
「ローテーションを実行するための新しいLambda関数を作成します」を選択します。
「新しいAWS Lambda関数名」に関数名を入れておきます。
「ローテーションの実行に使用するシークレットを選択してください」に「このシークレットを使う」を選択します。
最後はレビューでもう一回チェックをし、問題がなければ作成ボタンを押していきます。
作成後に、合わせてAWSがLambda関数を作成してくれるので、Lambdaで確認できます。
4.セキュリティグループの設定
EC2用のセキュリティグループとほかに、以下三つのセキュリティグループを作成または編集する必要があります。
・Secret Manager VPCエンドポイント用セキュリティグループ
・RDS用セキュリティグループ
・Lmabda用セキュリティグループ
①Secret Manager VPCエンドポイント用セキュリティグループ、VPC CIDR でTCP 443ポートを許可します。今回私が使っている VPC CIDR は 10.0.0.0/16 なので、10.0.0.0/16を開放します。
②Lmabda用セキュリティグループに、Secret Manager エンドポイント用セキュリティグループを追加します。ポートは TCP 443 です。
③RDS用セキュリティグループに、Lmabda用セキュリティグループを追加します。ポートは TCP 5432です。
④上記「3.Secrets Managerの作成」で作成されたLambda関数のセキュリティグループを編集します。
自動作成されたLambda関数では、デフォルセキュリティグループを使用します。
デフォルセキュリティグループを、Lambda用のセキュリティグループに置き換えていきます。
5.Secrets Manager 用 VPC エンドポイント作成
VPC→エンドポイントで、Secrets Manager 用 VPC エンドポイント作成していきます。
エンドポイントサービス名:com.amazonaws.ap-northeast-1.secretsmanager
セキュリティグループに、上記設定した Secret Manager VPCエンドポイント用セキュリティグループを選択します。
ポリシー欄は一旦このままでよいので、作成後に編集していきます。
エンドポイントの作成を押してください。
エンドポイント作成後に、必ずエンドポイントのポリシーを変更してください。
下記のようなポリシーを使用するには、AWS アカウント ID と VPC エンドポイント ID のプレースホルダーを、ご自身の有効な値で置き換えます。
このエンドポイントのポリシーの意味は下記となります:
ユーザーがSecrets Manager にリクエストを送信すると、Secrets Manager はリクエストの VPC エンドポイント ID をaws:sourceVpce条件キーの値を指定します。これらが一致しない場合、Secrets Manager はリクエストを拒否します。
参考URL:
{
"Id": "example-policy-1",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnableSecretsManagerpermissions",
"Effect": "Allow",
"Principal": {"AWS":["XXXXXXXXXXX"]},
"Action": ["secretsmanager:*"],
"Resource": "*"
},
{
"Sid": "RestrictGetSecretValueoperation",
"Effect": "Deny",
"Principal": "*",
"Action": ["secretsmanager:GetSecretValue"],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:sourceVpce": "vpce-XXXXXXXXXXXXXX"
}
}
}
]
}
5.パスワードをローテーションさせる
パスワード変更前:
sh-4.2$ aws secretsmanager get-secret-value --secret-id a-test-postgresql-key --region ap-northeast-1 | jq .SecretString | jq fromjson
{
"username": "admindadada",
"password": "tX9Vbx5A",
"engine": "postgres",
"host": "secret-manager-test.XXXXXXXXXXXXX.ap-northeast-1.rds.amazonaws.com",
"port": 5432,
"dbname": "dadada",
"dbInstanceIdentifier": "secret-manager-test"
}
Secrets Managerで、「すぐにシークレットをローテーションさせる」押してください。
すると、パスワードが変更されたことを確認できました。
sh-4.2$ aws secretsmanager get-secret-value --secret-id a-test-postgresql-key --region ap-northeast-1 | jq .SecretString | jq fromjson
{
"username": "admindadada",
"password": "_DDFpe$EFcby>ZS(3Q-]jGhbb!x]zbkz",
"engine": "postgres",
"host": "secret-manager-test.XXXXXXXXXXXXX.ap-northeast-1.rds.amazonaws.com",
"port": 5432,
"dbname": "dadada",
"dbInstanceIdentifier": "secret-manager-test"
}
6.まとめ
このように、AWS Secrets Managerを使うことによって、コード内に直接RDSのエンドポイントやパスワード等の情報を埋め込まずに済みました。
さらにLambdaでローテーションさせることで、安全性を一層高めることが出来ます。
ちなみに、jqを使って、RDSの諸情報をフィルターできます。
下記フィルターの例になります。
RDSのユーザー:
aws secretsmanager get-secret-value --secret-id XXXXXXXXXXX --region ap-northeast-1 | jq .SecretString | jq fromjson | jq -r .username
RDSのパスワード:
aws secretsmanager get-secret-value --secret-id XXXXXXXXXXX --region ap-northeast-1 | jq .SecretString | jq fromjson | jq -r .password
RDSのエンドポイント:
aws secretsmanager get-secret-value --secret-id XXXXXXXXXXX --region ap-northeast-1 | jq .SecretString | jq fromjson | jq -r .host
RDSのポート:
aws secretsmanager get-secret-value --secret-id XXXXXXXXXXX --region ap-northeast-1 | jq .SecretString | jq fromjson | jq -r .port
今回クラスメソッドさんの記事が大変参考になりました。
参考資料: