【Python2】AWS Secrets Manager 経由で Datadog のシークレット値を取得してみる

記事タイトルとURLをコピーする

はじめに

Datadog で Mysql の接続監視をする際、
設定ファイルに DB パスワードを直書きしたくないなーと思っていたところ、どうやら以下の「Secrets Management」機能でシークレット値を取得できるとのことなのでやってみました。

公式ドキュメントはこちら

記事目安...15分

「Secrets Management」機能

「Secrets Management」機能をざっくり説明すると、Datadog 起動時に設定ファイル外から値を取得してくれる機能です。

メリットは、設定ファイルに値を直書きすることを防げるので機密情報をセキュアに管理できます。

仕組みとしては、datadog-agent の起動時に「dd-agent」ユーザがスクリプトを実行して値をメモリに格納してるらしいです。

スクリプトについて

#!/bin/python
# coding: utf-8
import json
import os.path
import sys
import boto3
import ast

region_name = "ap-northeast-1"

session = boto3.session.Session()
secrets_manager = session.client(
    service_name='secretsmanager',
    region_name=region_name
)

def create_output_from(secret_names):
    """Datadog に渡すシークレット情報を作成する。
    Args:
        secret_names (list): シークレットキーの配列
    Returns:
        dict: Datadog に渡すシークレット情報
    """
    output = {}
    for s in secret_names:
       try:
            secret_value = get_secrets(s)
            output[s] = {"value": secret_value}
       except ValueError as e:
           output[s] = {"error": str(e)}
    return output

def list_secret_names(input_json):
    """シークレットキーを取得する
    Args:
        input_json (json): Datadog からの入力 JSON
    Raises:
        ValueError: プロトコルバージョンエラー
        ValueError: シークレットキーが配列でない
    Returns:
        list: シークレットキーの配列
    """
    query = json.loads(input_json)
    version = query["version"].split(".")
    if version[0] != "1":
        raise ValueError("incompatible protocol version {}".format(query["version"]))

    names = query["secrets"]
    if type(names) is not list:
        raise ValueError("the secrets field should be an array: {}".format(names))

    return names


def get_secrets(secret_key):
    """AWS Secrets Manager から シークレット値取得する。
    Args:
        secret_key (string): シークレットキー
    Returns:
        [string]: シークレットキーに対応する値
    """
    res = secrets_manager.get_secret_value(
        SecretId=secret_key
    )
    SecretString = res.get('SecretString')
    secret_value = ast.literal_eval(SecretString).get(secret_key)

    return secret_value

def main(input_json):
    """メイン関数
    Args:
        input_json (json): Datadog からの入力 JSON
    Returns:
        dict: Datadog に渡すシークレット情報
    """
    try:
        secret_names = list_secret_names(input_json)
    except ValueError as e:
        sys.exit('Cannot parse input: ' + str(e))

    output = create_output_from(secret_names)
    return output

if __name__ == '__main__':
    input_json = sys.stdin.read()
    output = main(input_json)
    print json.dumps(output)

概要

Datadog から受け取ったシークレットキーを基に、シークレット値を標準出力するスクリプトです。
シークレット値は AWS Secrets Manager から取得します。

Datadog の「シークレット管理」については、以下ドキュメントを参照ください。

参考: Datadog-SecretsManagement

動作環境

# python -V
Python 2.7.18

使い方

シークレットキーの登録

設定ファイルに ENC[hogehoge] で登録します。

Example:

instances:
  - server: db_prod
    # two valid secret handles
    user: "ENC[db_prod_user]"
    password: "ENC[db_prod_password]"

    # The `ENC[]` handle must be the entire YAML value, which means that
    # the following is NOT detected as a secret handle:
    password2: "db-ENC[prod_password]"

AWS Secrets Manager との連携

  1. AWS Secrets Manager にシークレット値を格納します。登録時のシークレットキーは、設定ファイルのシークレットキーと同じにしてください。
    ex) "ENC[hogehoge]" の場合、AWS Secrets Manager のシークレットキーは "hogehoge"
  2. スクリプトを設置するサーバーが、AWS Secrets Manager から シークレット値を取得できる権限を持ってることを確認してください

pythonモジュールのインストール

$ pip install boto3

スクリプトの配置

  1. スクリプト用のフォルダを作成します。
    ※ ここでは /usr/loca/bin/ に設置
$ cd /usr/local/bin
$ mkdir get-datadog-secrets
  1. スクリプトを設置してください。設置後は権限も修正します。
$ cd get-datadog-secrets
$ wget https://raw.githubusercontent.com/sugaya0204/blog/Public/Tips/Datadog/get-datadog-secrets/src/main.py
$ chmod 700 main.py
$ chown dd-agent:dd-agent main.py
  1. スクリプト内のリージョンが正しいかを確認してください
region_name = "ap-northeast-1"

実行スクリプトの登録

/etc/datadog-agent/datadog.yaml 内の secret_backend_command に実行スクリプトのファイルパスを入力します。

$ vi /etc/datadog-agent/datadog.yaml

■ 修正内容

# secret_backend_command: <COMMAND_PATH>
→ secret_backend_command: /usr/local/bin/get-datadog-secrets/main.py

引用元: Datadog-SecretsManagement

Datadog Agent の再起動

スクリプトを読み込むために再起動します。

$ sudo systemctl restart datadog-agent
$ sudo systemctl status datadog-agent

動作確認

以下コマンドで

  1. 実行スクリプトの権限が正しいか
  2. シークレット値が正しく取得で来ているか

確認できます。

$ sudo -u dd-agent -- datadog-agent secret

(Tips)トラブルシューティング

スクリプトの実行エラーは /var/log/datadog/agent.log に吐き出されます。

まとめ

このスクリプトを使えばセキュアな運用が出来るので、参考にしてみてください~

参考

* https://github.com/Sho2010/datadog-env-secret

菅谷 歩 (記事一覧)