VPC内のLambdaからVPCエンドポイント経由でSecrets Managerを使う
2021/05/18
InternetGatewayのないVPCでMySQLに対して一日数回のレポーティングのための抽出処理をするLambdaがあるとします。
MySQLのパスワードは定期更新が必要で、パスワード管理もしたくないので、AWS Secrets Managerを使いたいとします。
そうなると、VPCエンドポイントを使うことになると思いますので、上記の構成を試しました。
目次
MySQL(Aurora Serverless)の準備
MySQLはAurora Serverlessを使ってみました。
作業用のEC2から、SQLコマンドでサンプルテーブルとレコードを作成しました。
1 2 3 4 |
create table demo.user (user_id int, user_name varchar(20)); insert into demo.user(user_id, user_name) values(1, ‘yamashita’); insert into demo.user(user_id, user_name) values(2, ‘mitsuhiro’); |
VPCエンドポイントの作成
VPCエンドポイントを作成する前に、Secrets ManagerのエンドポイントのDNSを確認しておきました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
$ dig secretsmanager.us-east-1.amazonaws.com ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.amzn2.4 <<>> secretsmanager.us-east-1.amazonaws.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28189 ;; flags: qr rd ra; QUERY: 1, ANSWER: 8, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;secretsmanager.us-east-1.amazonaws.com. IN A ;; ANSWER SECTION: secretsmanager.us-east-1.amazonaws.com. 31 IN A 35.169.248.1 secretsmanager.us-east-1.amazonaws.com. 31 IN A 52.7.193.36 secretsmanager.us-east-1.amazonaws.com. 31 IN A 34.225.31.232 secretsmanager.us-east-1.amazonaws.com. 31 IN A 3.82.253.127 secretsmanager.us-east-1.amazonaws.com. 31 IN A 3.88.73.100 secretsmanager.us-east-1.amazonaws.com. 31 IN A 34.199.80.66 secretsmanager.us-east-1.amazonaws.com. 31 IN A 18.207.89.194 secretsmanager.us-east-1.amazonaws.com. 31 IN A 34.192.69.250 ;; Query time: 0 msec ;; SERVER: 172.31.0.2#53(172.31.0.2) ;; WHEN: Fri May 07 04:12:26 UTC 2021 ;; MSG SIZE rcvd: 195 |
パブリックIPアドレスが引けました。
Secrets Manager用のVPCエンドポイントを作成しました。
作成完了して利用可能になったあと、もう一度DNSを確認しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
$ dig secretsmanager.us-east-1.amazonaws.com ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.amzn2.4 <<>> secretsmanager.us-east-1.amazonaws.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16179 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;secretsmanager.us-east-1.amazonaws.com. IN A ;; ANSWER SECTION: secretsmanager.us-east-1.amazonaws.com. 60 IN A 172.31.28.115 secretsmanager.us-east-1.amazonaws.com. 60 IN A 172.31.44.233 ;; Query time: 1 msec ;; SERVER: 172.31.0.2#53(172.31.0.2) ;; WHEN: Fri May 07 04:01:27 UTC 2021 ;; MSG SIZE rcvd: 99 |
プライベートIPアドレスが引けました。
Secrets Managerシークレットの作成
「RDSデータベースの認証情報」としてシークレットを作成しました。
Auroraインスタンスを選択して、ローテーション構成を設定するだけでした。
Lambdaのサンプルコード
LambdaでVPC起動を指定して作りました。
IAMロールに設定したSecrets Manager向けのIAMポリシーはこちらです。
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "secretsmanager:GetSecretValue", "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:demo/aurora-3yev7i" } ] } |
ランタイムはPython 3.8です。
pymysqlはレイヤーから使っています。
シークレットを作成すると、サンプルコードが生成されているので、それを使いまわしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
import boto3 import base64 import json import pymysql from botocore.exceptions import ClientError def get_secret(): secret_name = "demo/aurora" region_name = "us-east-1" session = boto3.session.Session() client = session.client( service_name='secretsmanager', region_name=region_name ) try: get_secret_value_response = client.get_secret_value( SecretId=secret_name ) except ClientError as e: print(e.response['Error']['Code']) if e.response['Error']['Code'] == 'DecryptionFailureException': raise e elif e.response['Error']['Code'] == 'InternalServiceErrorException': raise e elif e.response['Error']['Code'] == 'InvalidParameterException': raise e elif e.response['Error']['Code'] == 'InvalidRequestException': raise e elif e.response['Error']['Code'] == 'ResourceNotFoundException': raise e else: if 'SecretString' in get_secret_value_response: secret = get_secret_value_response['SecretString'] else: secret = base64.b64decode(get_secret_value_response['SecretBinary']) return secret def lambda_handler(event, context): secret_dict = json.loads(get_secret()) print(secret_dict['password']) # デモ用につき本番環境ではやっちゃだめ connection = pymysql.connect( host=secret_dict['host'], user=secret_dict['username'], password=secret_dict['password'], db='demo', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor) try: with connection.cursor() as cursor: sql = "SELECT * FROM user" cursor.execute(sql) dbdata = cursor.fetchall() for rows in dbdata: print(rows) finally: connection.close() |
途中でパスワードをprintしてますが、これはローテーションの動作確認のためなので、本番でやっちゃうとだめですね。
せっかくパスワードを知らなくてもいい運用にしているのに、CloudWatch Logsにパスワードが記録されてしまいます。
このコードを実行しました。
テーブルに保存されたレコードを取得できました。
パスワードは初期に設定した “demo-password”なことがわかりました。
パスワードのローテーション
パスワードをローテーションするためのLambdaが自動的に作成されているのですが、これVPC設定されてないので、このままだとデータベースに接続できません。
昔作ったときは自動的に設定されていたと思うのですが、今回は環境上のなんらかの条件が違ったのかもしれません。
なにはともあれ、データベースに対して接続できないとパスワード更新もできませんので、VPCの設定をします。
もちろんセキュリティグループIDはAurora側のセキュリティグループでインバウンド許可のソースにする必要があります。
そしてSecrets Managerの[すぐにシークレットをローテーションさせる]を実行しました。
そして、Lambda関数を[テスト]ボタンから再実行しました。
ローテーションにより更新されたパスワードでデータベースに接続できたことがわかりました。
最後までお読みいただきましてありがとうございました!
「AWS認定資格試験テキスト&問題集 AWS認定ソリューションアーキテクト - プロフェッショナル 改訂第2版」という本を書きました。
「AWS認定資格試験テキスト AWS認定クラウドプラクティショナー 改訂第3版」という本を書きました。
「ポケットスタディ AWS認定 デベロッパーアソシエイト [DVA-C02対応] 」という本を書きました。
「要点整理から攻略するAWS認定ソリューションアーキテクト-アソシエイト」という本を書きました。
「AWSではじめるLinux入門ガイド」という本を書きました。
開発ベンダー5年、ユーザ企業システム部門通算9年、ITインストラクター5年目でプロトタイプビルダーもやりだしたSoftware Engineerです。
質問はコメントかSNSなどからお気軽にどうぞ。
出来る限りなるべく答えます。
このブログの内容/発言の一切は個人の見解であり、所属する組織とは関係ありません。
このブログは経験したことなどの共有を目的としており、手順や結果などを保証するものではありません。
ご参考にされる際は、読者様自身のご判断にてご対応をお願いいたします。
また、勉強会やイベントのレポートは自分が気になったことをメモしたり、聞いて思ったことを書いていますので、登壇者の意見や発表内容ではありません。
ad
ad
関連記事
-
S3をトリガーにしたときのLambdaのリソースベースポリシー
LambdaのトリガーでS3を設定したとき、自動的にLambdaのリソースベース …
-
「JAWS-UG Osaka 第22回勉強会 東西の中の人が語る!!! Microservices × Serverless On AWS」で運営と懇親会LTをしてきました
「JAWS-UG Osaka 第22回勉強会 東西の中の人が語る!!! Micr …
-
AWS EC2 インスタンスステータスのチェックで失敗 原因はPHP-FPMのOOM-KILLER
先週に引き続きEC2のインスタンスステータスチェックで失敗 再起動するも失敗する …
-
Amazon CloudSearchにAWS Lambda(Python)からデータをアップロードする
このブログはゆるっとアドベントカレンダー Advent Calendar 201 …
-
試そうとしてたらSavings Plans買っちゃいました
Savings Plansの購入画面を確認していました。 画面遷移も確認しようと …
-
AWS Transfer Family S3向けのSFTP対応サーバー
S3バケットは作成済です。 IAMロールの作成 [crayon-66de1cf3 …
-
AWSのアカウントを新規作成と、最低限やっておいた方がいいMFAの設定
AWSのアカウントを新規作成する手順を書き出しておきます。 ※2017年8月6日 …
-
Amazon Linux2のジャンボフレーム
ユーザーガイドのEC2 インスタンスのネットワークの最大送信単位 (MTU)を試 …
-
「JAWS-UG 名古屋 2022年 “re:Invent”の復習~忘年会~」に参加しました
re:Inventのおみやげも飲み物、ピザ、お寿司もたくさん。 コラボベースさん …
-
Amazon VPCにオンプレミス検証環境想定プライベートDNSサーバー(BIND)をEC2で起動する
オンプレミス想定の検証で使うために、Amazon VPCにプライベート向けDNS …