Datadog のAWS監視にIAMロールを利用してみた

Datadog アイキャッチ

はじめに

AWSチームのすずきです。

AWSのIAMでは、サードパーティのAWSアカウントに対し自身のAWS環境へのアクセスを許可する、 クロスアカウントアクセス用ロールを作成することが可能です。

監視SaaSとして知られるDatadog、AWSのCloudwatch、CloudTrailの監視を行う AWS Integrationが、アクセスキーに加え、クロスアカウントアクセス用ロールに対応しました。

IAMロールを利用したDatadog Integration (Role Delegation)の設定について、紹介させて頂きます。

設定

Datadogの公式ドキュメントに準じ、AWS Integration、CloudTrail Integration の設定を行います。

外部IDの発行

  • Datadog AWS Integration の設定画面を開きます。

datadog-iam-role-01

  • AWSアカウントの設定画面を開き、AWS External IDを確認します。

datadog-iam-role-02

IAMロールの作成

  • AWS コンソール、IAMロール画面より「新しいロールの作成」を実行します

datadog-iam-role-03

  • ロール名は、公式ドキュメントに準じ「DatadogAWSIntegrationRole」とします

datadog-iam-role-04

  • ロールタイプの選択としてクロスアカウントアクセスのロールを指定し、「サードパーティの AWS アカウントの IAM ユーザーに、アカウントへのアクセスを許可します。」を選択します。

datadog-iam-role-05

  • 信頼性の確立で、DatadogのAWSアカウント(464622532012)を記入します。
  • 外部IDは、DatadogのAWS Integration画面で確認したAWS External IDを記入します
  • MFAが必要のオプションはチェックしません。

datadog-iam-role-06

  • ポリシーのアタッチは実施せず、次に進みます。
  • デフォルトで存在する 管理ポリシーは、ReadOnlyでも権限が強すぎる場合があるため、利用を避けます。

datadog-iam-role-07

  • 作成したIAMロール「DatadogAWSIntegrationRole」の変更画面を開きます。
  • Datadogが必要とするIAM権限、インラインポリシーで反映します。

datadog-iam-role-08

  • カスタムポリシーを指定し、PolicyEditorの使用を選択します

datadog-iam-role-09

  • ポリシー名は「DatadogAWSIntegrationPolicy」
  • ポリシードキュメントには 公式ドキュメント記載のJSONを反映します。

datadog-iam-role-10

  • DatadogAWSIntegrationPolicy (2016/7時点)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "autoscaling:Describe*",
        "cloudtrail:DescribeTrails",
        "cloudtrail:GetTrailStatus",
        "cloudwatch:Describe*",
        "cloudwatch:Get*",
        "cloudwatch:List*",
        "dynamodb:list*",
        "dynamodb:describe*",
        "ec2:Describe*",
        "ec2:Get*",
        "ecs:Describe*",
        "ecs:List*",
        "elasticache:Describe*",
        "elasticache:List*",
        "elasticloadbalancing:Describe*",
        "elasticmapreduce:List*",
        "elasticmapreduce:Describe*",
        "kinesis:List*",
        "kinesis:Describe*",
        "logs:Get*",
        "logs:Describe*",
        "logs:FilterLogEvents",
        "logs:TestMetricFilter",
        "rds:Describe*",
        "rds:List*",
        "route53:List*",
        "ses:Get*",
        "sns:List*",
        "sns:Publish",
        "sqs:GetQueueAttributes",
        "sqs:ListQueues",
        "sqs:ReceiveMessage",
        "support:*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
  • CloudTrail Integrationを利用するため、S3に保管されているログを参照するためのポリシーを、DatadogAWSIntegrationRoleに付与します。

  • CloudTrailのログ保管先のS3バケット「cloudtrail-<リージョン>-<アカウントID>」、「cloudtrail-*」にcloudtrail用途以外のバケットは無いものとして設定しました。可能であればバケット名の明示をお勧めします。

  • DatadogAWSCloudTrailReadOnlyAccessPolicy

{ "Statement": [
  {
    "Action": [
      "s3:ListBucket",
      "s3:GetBucketLocation",
      "s3:GetObject"
    ],
    "Effect": "Allow",
    "Resource": [
      "arn:aws:s3:::cloudtrail-*"
    ]
  } ]
}

datadog-iam-role-11

  • ロールARNの確認
  • アカウントIDと、ロール名を確認します。

datadog-iam-role-13

Datadog アカウント設定

  • AWS Account ID と、ロール名を記入します。
  • ロール情報入力後、「Account credentials are valid」と有効性が確認出来ない場合には、記入情報を見直します

datadog-iam-role-12

  • External IDが変更となった場合、IAMロール(DatadogAWSIntegrationRole)の信頼関係の編集で、Condition→StringEquals→sts:ExternalIdの値を差し替えます。

datadog-iam-role-14

動作確認

  • AWS Integrationの設定後、30分〜1時間後位をめどに確認を実施します。
  • DatadogのMetrics→Summary画面より「aws」、AWS Integrationのメトリックを確認します

datadog-iam-role-15

  • ロールを追加したアカウントに該当する項目をタグなどで選択し、グラフ表示を確認します。

datadog-iam-role-16

アクセスキーの撤去

  • 従来Datadogで利用していたIAMユーザを選択し、アクセスキーの管理を開きます。

datadog-iam-role-18

  • ステータス欄が「Active」なキーを「無効化」、または「削除」します。

datadog-iam-role-19

  • Datadog専用のIAMユーザを作成されていた場合には、IAMユーザごとの撤去がお勧めです。

まとめ

IAMアクセスキーを利用する場合、アクセスキー、シークレットキーが悪意をもった第三者に漏れた場合の対策を 常に意識することが必要でした。

適切なクロスアカウントアクセス設定を施したIAMロールの利用により、キーが不正利用されるリスクを大きく軽減でき、 シークレットキーの隠匿や、定期的なアクセスキー、シークレットキーの更新運用などからも開放されます。

今回、DatadogのAWS IntegrationでもIAMロールの利用が可能となりました。 新規導入の環境だけでなく、従来のアクセスキーを登録されている環境も、 IAMロールによる認証 (Role Delegation) へ切り替える事をおすすめします。

参考

CloudFormation

  • Datadog用のIAMロールを作成するテンプレートを用意しました。
  • Datadogに反映する設定値は、CreateStack実行後、Outputsで確認可能です

datadog-iam-role-17

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Parameters": {
    "DatadogExternalID": {
      "Default": "ExternalID",
      "Description": "Datadog AWS External ID",
      "Type": "String"
    }
  },
  "Resources": {
    "DatadogAWSIntegrationRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": "sts:AssumeRole",
              "Effect": "Allow",
              "Condition": {
                "StringEquals": {
                  "sts:ExternalId": {
                    "Ref": "DatadogExternalID"
                  }
                }
              },
              "Principal": {
                "AWS": "arn:aws:iam::464622532012:root"
              }
            }
          ]
        },
        "Path": "/"
      }
    },
    "DatadogAWSIntegrationPolicy": {
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "DatadogAWSIntegration",
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": [
                "autoscaling:Describe*",
                "cloudtrail:DescribeTrails",
                "cloudtrail:GetTrailStatus",
                "cloudwatch:Describe*",
                "cloudwatch:Get*",
                "cloudwatch:List*",
                "dynamodb:list*",
                "dynamodb:describe*",
                "ec2:Describe*",
                "ec2:Get*",
                "ecs:Describe*",
                "ecs:List*",
                "elasticache:Describe*",
                "elasticache:List*",
                "elasticloadbalancing:Describe*",
                "elasticmapreduce:List*",
                "elasticmapreduce:Describe*",
                "kinesis:List*",
                "kinesis:Describe*",
                "logs:Get*",
                "logs:Describe*",
                "logs:FilterLogEvents",
                "logs:TestMetricFilter",
                "rds:Describe*",
                "rds:List*",
                "route53:List*",
                "ses:Get*",
                "sns:List*",
                "sns:Publish",
                "sqs:GetQueueAttributes",
                "sqs:ListQueues",
                "sqs:ReceiveMessage",
                "support:*"
              ],
              "Effect": "Allow",
              "Resource": "*"
            }
          ]
        },
        "Roles": [
          {
            "Ref": "DatadogAWSIntegrationRole"
          }
        ]
      }
    },
    "DatadogAWSCloudTrailReadOnlyAccessPolicy": {
      "Type": "AWS::IAM::Policy",
      "Properties": {
        "PolicyName": "DatadogAWSCloudTrailReadOnlyAccess",
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation",
                "s3:GetObject"
              ],
              "Effect": "Allow",
              "Resource": "arn:aws:s3:::cloudtrail-*"
            }
          ]
        },
        "Roles": [
          {
            "Ref": "DatadogAWSIntegrationRole"
          }
        ]
      }
    }
  },
  "Outputs": {
    "RoleName": {
      "Description": "The IAM Role to share with Datadog (Name)",
      "Value": {
        "Ref": "DatadogAWSIntegrationRole"
      }
    },
    "RoleArn": {
      "Description": "The IAM Role to share with Datadog (ARN)",
      "Value": {
        "Fn::GetAtt": [
          "DatadogAWSIntegrationRole",
          "Arn"
        ]
      }
    },
    "DatadogExternalID": {
      "Description": "Datadog AWS External ID",
      "Value": {
        "Ref": "DatadogExternalID"
      }
    },
    "AwsAccoutID": {
      "Description": "AWS Account ID",
      "Value": {
        "Ref": "AWS::AccountId"
      }
    }
  }
}