Secrets Manager を使ってスクリプト内に秘密情報を書かないようにしよう
スクリプトを書いてるとあっという間に時間が過ぎます、那須です。
先日、Datadog から Slack と Backlog に障害通知する記事を書きました。今日の記事は↓の続編になりますので、まだ読んでない方は先に読んだ方が全体の流れはわかると思います。
nasrinjp1.hatenablog.com
Lambda の Python スクリプトに直接 apikey などの情報を書いてしまっていたので、スクリプトの汎用性を高めると同時にセキュリティ的に github にあげても問題ない内容に更新しました。今回はその変更点についてです。
変更したポイント
- apiKey、projectId、issueTypeId の値を Secrets Manager から取得する流れにした
- API Gateway の URL と Secrets Manager で作成したシークレット名は Datadog Webhooks に仕込んだ
Secrets Manager への値の登録
post_on_backlog というシークレットを作成して、そこに apiKey、projectId、issueTypeId の 3 つの値を登録します。
Secrets Manager へのシークレットの登録の流れは、この記事で書いていますので参考にしてください。
nasrinjp1.hatenablog.com
Lambda function の変更
↓書き直したスクリプトです。ざっくりですがコメントいれてます。
# coding: utf-8 import json import requests import boto3 from botocore.exceptions import ClientError def lambda_handler(event, context): title = event['title'] description = event['body'] secret_name = event['secret_name'] # Datadog から値を取得する流れに url = event['url'] # Datadog から値を取得する流れに if event['alert_type'] == 'warning': severity = 3 else: severity = 2 return add_issue(title, description, severity, secret_name, url) def add_issue(title,description,severity,secret_name,url): secret_info = get_secret(secret_name) # ここにあった秘密の情報は Secrets Manager から JSON で取得する流れに payload={ "apiKey" : secret_info['apikey'], # 取得した JSON から値を取り出す "projectId" : secret_info['project_id'], # 取得した JSON から値を取り出す "issueTypeId" : secret_info['issuetype_id'], # 取得した JSON から値を取り出す "priorityId" : severity, "summary" : title, "description" : description, } response = requests.post(url, params=payload) return response.json() # Secrets Manager から値をとってくる関数を追加(Secrets Manager コンソールのサンプルほぼそのまま) def get_secret(secret_name): endpoint_url = "https://secretsmanager.ap-northeast-1.amazonaws.com" region_name = "ap-northeast-1" session = boto3.session.Session() client = session.client( service_name='secretsmanager', region_name=region_name, endpoint_url=endpoint_url ) try: get_secret_value_response = client.get_secret_value( SecretId=secret_name ) except ClientError as e: if e.response['Error']['Code'] == 'ResourceNotFoundException': print("The requested secret " + secret_name + " was not found") elif e.response['Error']['Code'] == 'InvalidRequestException': print("The request was invalid due to:", e) elif e.response['Error']['Code'] == 'InvalidParameterException': print("The request had invalid params:", e) else: secret_value = json.loads(get_secret_value_response['SecretString']) return secret_value
あと、Secrets Manager から値を取得するための IAM ポリシーが必要になるので、Lambda function にアタッチしている IAM ロールに下記のアクションを許可するようにポリシー追加します。* を使わない方がいいとは思いますが、ひとまずこれで。kms:Decrypt アクションは、KMS でデフォルトのものではなく CMK を使ってシークレット情報を暗号化している場合は必要になります。
docs.aws.amazon.com
{ "Effect": "Allow", "Action": [ "secretsmanager:Describe*", "secretsmanager:Get*", "secretsmanager:List*", "kms:Decrypt" ], "Resource": "*" }
Datadog webhooks 設定で API Gateway に投げる情報を追加
Custom Payload に secret_name と url の情報を追加します。
テストしてみよう
上記のように変更して動作テストをしてみます。今回は alert_type を warning で検知したものを backlog に優先度「中」で登録できるかも一緒に確認しましょう。
対象の EC2 インスタンスに負荷をかけていくと Warning で CPU 負荷異常を検知しました。
と同時に Backlog にも課題登録され、優先度は中で登録されていました。Lambda の severity 指定部分の処理も ok ですね。
まとめ
これでスクリプトを github 等で公開しても大丈夫な状態になりましたね。IAM ポリシーとかをもうちょっと調整したら公開しようと思います。