sorta kinda...

主にAWS関連ですが、これに限らずいろいろ勉強したことや思ったことを書いていきます。

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 つの値を登録します。
f:id:nasrinjp1:20180907062727p:plain

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 の情報を追加します。
f:id:nasrinjp1:20180907063827p:plain

 

テストしてみよう

上記のように変更して動作テストをしてみます。今回は alert_type を warning で検知したものを backlog に優先度「中」で登録できるかも一緒に確認しましょう。

対象の EC2 インスタンスに負荷をかけていくと Warning で CPU 負荷異常を検知しました。
f:id:nasrinjp1:20180907064749p:plain

と同時に Backlog にも課題登録され、優先度は中で登録されていました。Lambda の severity 指定部分の処理も ok ですね。 f:id:nasrinjp1:20180907064758p:plain

 

まとめ

これでスクリプトgithub 等で公開しても大丈夫な状態になりましたね。IAM ポリシーとかをもうちょっと調整したら公開しようと思います。