Datadogへログを送るLambdaをTerraformでシンプルに構築する
こんにちは、株式会社スマートラウンドSREの@shonansurvivorsです。
当社はインフラにAWSを使っており、ALBのログはS3バケットに保存するようにしています。
S3に保存したALBログはAthenaなどを使って分析することもできるのですが、Datadogに送ることで非常に簡単に可視化することができ、パフォーマンス分析などに大いに役立っています。
下図のような、Datadogにログを送るLambdaのことをDatadog公式ではDatadog Forwarderと呼んでいます。
このDatadog Forwarderおよび一連の関連リソースを構築する手段として、Datadog公式からはCloudFormationテンプレートが提供されています。また、このCloudFormationテンプレートをTerraformでラップして使用する方法についても解説されています。
当社はIaCにTerraformを採用しており、Datadog ForwarderもTerraformで構築したのですが、公式とは少し違う方法で構築しました。
よりシンプルかつ運用しやすいコードになったと思うので本記事で解説させていただきます。
工夫したポイント
- Datadog APIキーの保存先のSecrets Managerを自作せず、Datadog公式のCloudFormationで作らせた
- Datadog APIキーをTerraformのコードに含めないようにした
環境
- Datadog Forwarder 3.51.0
- Terraform 1.1.7
- AWS Provider 4.8.0
サンプルコード
resource "aws_cloudformation_stack" "datadog_forwarder" {
name = "datadog-forwarder"
capabilities = ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND"]
parameters = {
DdApiKey = "dummy" # 今回の記事のポイント その1
DdSite = "app.datadoghq.com" # 使用中のDatadogサイトに合わせて、us3.datadoghq.com, us5.datadoghq.comなどに適宜変更してください
FunctionName = "datadog-forwarder"
DdTags = "env:${var.env}" # ログに環境名などのタグを付けたい場合は追加してください
}
template_url = "https://datadog-cloudformation-template.s3.amazonaws.com/aws/forwarder/3.51.0.yaml" # バージョンは固定しました
lifecycle {
ignore_changes = [
parameters["DdApiKey"] # 今回の記事のポイント その2
]
}
}
解説
Datadog公式の方法
まず、当社の方法ではなく、Datadog公式の方法から解説します。
Datadog公式では、最初にSecrets Managerを作成する流れとなっています。
# Store Datadog API key in AWS Secrets Manager
variable "dd_api_key" {
type = string
description = "Datadog API key"
}
resource "aws_secretsmanager_secret" "dd_api_key" {
name = "datadog_api_key"
description = "Encrypted Datadog API Key"
}
resource "aws_secretsmanager_secret_version" "dd_api_key" {
secret_id = aws_secretsmanager_secret.dd_api_key.id
secret_string = var.dd_api_key
}
output "dd_api_key" {
value = aws_secretsmanager_secret.dd_api_key.arn
}
このコードをterraform apply
すると、以下のように変数dd_api_key
の値を聞かれますので、Datadog APIキーの値をコンソールに入力します。
var.dd_api_key
Datadog API key
Enter a value:
applyが完了したら、以下のコードのDdApiKeySecretArn
に前述のSecrets ManagerのARNを渡した上で、こちらもapplyします。
resource "aws_cloudformation_stack" "datadog_forwarder" {
name = "datadog-forwarder"
capabilities = ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND"]
parameters = {
DdApiKeySecretArn = "REPLACE ME WITH THE SECRETS ARN"
DdSite = "datadoghq.com"
FunctionName = "datadog-forwarder"
}
template_url = "https://datadog-cloudformation-template.s3.amazonaws.com/aws/forwarder/latest.yaml"
}
なお、公式では前述の2つのTerraformコードを別ディレクトリに配置することを想定しているようです。
Separating the configurations of the API key and the forwarder means that you don’t need to provide the Datadog API key when updating the forwarder.
https://docs.datadoghq.com/logs/guide/forwarder/#terraform
そうすることで、以後CloudFormation側のコードをplan/applyする必要が生じた際に、変数dd_api_key
の値を毎回聞かれるということが無くなります。
当社の方法: DdApiKeySecretArnではなくDdApiKeyを指定する
このような公式の方法に対し、当社ではDdApiKeySecretArn
ではなくDdApiKey
を指定するようにしました。
そうすることで、このCloudFormationはDdApiKey
に渡された値を持つSecrets Managerを作成してくれます(興味のある方はCloudFormationテンプレートの中身を追ってみてください)。
なお、DdApiKey
には実際のAPIキーの値を記述するのではなく、"dummy"
にしておきます。これはAPIキーのような機微情報をTerraformのコード上に含めたくないためです。
resource "aws_cloudformation_stack" "datadog_forwarder" {
name = "datadog-forwarder"
capabilities = ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND"]
parameters = {
DdApiKey = "dummy" # DdApiKeySecretArnではなく、DdApiKeyを指定する
DdSite = "app.datadoghq.com"
FunctionName = "datadog-forwarder"
}
template_url = "https://datadog-cloudformation-template.s3.amazonaws.com/aws/forwarder/3.51.0.yaml"
lifecycle {
ignore_changes = [
parameters["DdApiKey"]
]
}
}
上記をapplyしたら、マネジメントコンソールかAWS CLIを使って、作成されたSecrets Managerの値をAPIキーの値で別途上書きします。
上書きしたことでAWS上のSecrets Managerの値と、Terraformコード上のDdApiKey
の値に差異が生まれますが、lifecycleブロックのignore_changesを指定しているので、次回以降のplan/apply時に差分として検知されることはありません。
以上の方法により、公式のように別ディレクトリにSecrets Managerのコードを書く必要は無くなり、シンプルな構成になりました。
おまけ: S3からLambdaを起動するための設定
ついでに、ログ保存先のS3からLambdaを起動するためのAWSリソースのコードも載せておきます。
こちらをapplyした上でSecrets Managerの値を上書きしてもらえれば、Datadogへのログ転送をすぐに開始できると思います。参考にしてみてください。
resource "aws_cloudformation_stack" "datadog_forwarder" {
name = "datadog-forwarder"
capabilities = ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND"]
parameters = {
DdApiKey = "dummy"
DdSite = "app.datadoghq.com" # 使用中のDatadogサイトに合わせて、us3.datadoghq.com, us5.datadoghq.comなどに適宜変更してください
FunctionName = "datadog-forwarder"
DdTags = "env:${var.env}" # ログに環境名などのタグを付けたい場合は追加してください
}
template_url = "https://datadog-cloudformation-template.s3.amazonaws.com/aws/forwarder/3.51.0.yaml" # バージョンは固定しました
lifecycle {
ignore_changes = [
parameters["DdApiKey"]
]
}
}
data "aws_s3_bucket" "alb_access_logs" {
bucket = "ALBログを保存しているS3バケット名"
}
resource "aws_s3_bucket_notification" "alb_access_logs" {
bucket = data.aws_s3_bucket.alb_access_logs.id
lambda_function {
id = "datadog-forwarder"
events = [
"s3:ObjectCreated:Put"
]
lambda_function_arn = aws_cloudformation_stack.datadog_forwarder.outputs.DatadogForwarderArn
}
}
resource "aws_lambda_permission" "datadog_forwarder_s3_alb_access_logs" {
action = "lambda:InvokeFunction"
function_name = aws_cloudformation_stack.datadog_forwarder.outputs.DatadogForwarderArn
principal = "s3.amazonaws.com"
source_account = "AWSアカウントID"
source_arn = data.aws_s3_bucket.alb_access_logs.arn
statement_id = "datadog-forwarder-s3-alb-access-logs"
}
おわりに
以上、Datadog ForwarderをTerraformでシンプルに構築する方法の解説でした。これからDatadogのLog Managementの機能を利用しようと考えている方の参考になれば幸いです。
採用情報
株式会社スマートラウンドではエンジニアを募集中です!正社員はもちろん、副業でのジョインも歓迎です。少しでもご興味あればお気軽にご応募ください。Meetyでのカジュアル面談も可能です。
Discussion