Datadog-Cloudformation Integration using Serverless Framework
Tags: datadog, aws, serverless
Published: 2023-08-31 09:39:14

## 🤓 Introduction

[Datadog](https://www.datadoghq.com/) is a cloud monitoring service provider which helps to track and analyse your cloud services from a health and operations perspective and providing support for debugging issues.

Datadog provides different integrations with multiple cloud providers like AWS, GCP, and Azure. In this blog we will be seeing Datadog integration with AWS using one of the AWS [Cloudformation service](https://docs.aws.amazon.com/cloudformation/index.html) with the help of Serverless framework.

# 📄 Pre Requisites

You will need AWS and Datadog account and knowledge of AWS services like IAMRole, Cloudformation and Serverless framework.

> Note: *Here we are using Serverless framework with TypeScript and [`Serverless Compose`](https://www.serverless.com/framework/docs/guides/compose) to deploy multiple different stack.*
> 

---

# 🛠 Datadog Cloudformation Setup

In order to create Datadog Resources using Cloudformation, Datadog needs Cloudformation Extension Plugins to be activated, so our first step is to start with adding an activation stack to our Serverless application. These extension plugins needs IAM roles to be attached in order to execute the Cloudformation events. You can find more details regarding this in [Datadog Amazon Cloudformation Documentation](https://docs.datadoghq.com/integrations/guide/amazon_cloudformation/)

> Note: *Here you can find a basic setup guide for Datadog-Cloudformation Integration*
> 

> We'll create two service stack in the Serverless application, one for the `Extensions Activation` which contains Cloudformation extension activation (as we'll only deploy it once because we can not deploy it multiple times to activate the same resources) and one for the `Infra Resources` (To create different Datadog monitors and dashboards).
> 

---

# 🧩 Setting Up the Extension Activation Stack

Let's create a IAM Role for the Role Delegation and Extensions Executions Role.

### 🧮 Setting Up the IAM Role

We are providing access to Datadog AWS account (`464622532012`) using [Role Delegation](https://docs.datadoghq.com/integrations/guide/aws-manual-setup/?tab=roledelegation) to our **IAMRole** with necessary permissions.

```jsx
DatadogExecutionRole: {
    Type: "AWS::IAM::Role",
    Properties: {
      Path: "/",
      RoleName: `DatadogAWSIntegrationRole`,
      Description: "IAM Role to integrate Datadog using Cloudformation",
      MaxSessionDuration: 8400,
      AssumeRolePolicyDocument: {
        Version: "2012-10-17",
        Statement: [
          {
            Effect: "Allow",
            Principal: {
              AWS: "arn:aws:iam::464622532012:root",
            },
            Action: "sts:AssumeRole",
            Condition: {
              StringEquals: {
                "sts:ExternalId": ["${ssm:/datadog/integration/externalId}"],
              },
            },
          },
          {
            Effect: "Allow",
            Principal: {
              Service: [
                "hooks.cloudformation.amazonaws.com",
                "resources.cloudformation.amazonaws.com",
              ],
            },
            Action: "sts:AssumeRole",
          },
        ],
      },
      Policies: [
        {
          PolicyName: `DatadogIntegrationRolePolicy`,
          PolicyDocument: {
            Version: "2012-10-17",
            Statement: [
              {
                Sid: "VisualEditor0",
                Effect: "Allow",
                Action: [
                  "health:DescribeAffectedEntities",
                  "budgets:ViewBudget",
                  "logs:DeleteSubscriptionFilter",
                  "states:ListStateMachines",
                  "states:DescribeStateMachine",
                  "tag:GetTagValues",
                  "logs:DescribeSubscriptionFilters",
                  "cloudtrail:GetTrailStatus",
                  "codedeploy:List*",
                  "es:ListTags",
                  "cloudwatch:Describe*",
                  "elasticmapreduce:Describe*",
                  "dynamodb:Describe*",
                  "rds:Describe*",
                  "route53:List*",
                  "elasticloadbalancing:Describe*",
                  "logs:FilterLogEvents",
                  "cloudfront:GetDistributionConfig",
                  "apigateway:GET",
                  "ses:Get*",
                  "cloudtrail:LookupEvents",
                  "fsx:ListTagsForResource",
                  "support:DescribeTrustedAdvisor*",
                  "events:CreateEventBus",
                  "lambda:List*",
                  "dynamodb:List*",
                  "s3:GetBucketNotification",
                  "cloudtrail:DescribeTrails",
                  "s3:PutBucketNotification",
                  "organizations:Describe*",
                  "organizations:List*",
                  "logs:PutSubscriptionFilter",
                  "fsx:DescribeFileSystems",
                  "kinesis:Describe*",
                  "codedeploy:BatchGet*",
                  "autoscaling:Describe*",
                  "s3:GetBucketTagging",
                  "tag:GetResources",
                  "logs:DescribeLogStreams",
                  "rds:List*",
                  "s3:GetBucketLogging",
                  "tag:GetTagKeys",
                  "elasticmapreduce:List*",
                  "backup:List*",
                  "sns:Publish",
                  "elasticache:List*",
                  "redshift:DescribeLoggingStatus",
                  "cloudwatch:Get*",
                  "support:RefreshTrustedAdvisorCheck",
                  "elasticfilesystem:DescribeFileSystems",
                  "es:DescribeElasticsearchDomains",
                  "xray:GetTraceSummaries",
                  "ecs:List*",
                  "health:DescribeEvents",
                  "sqs:ListQueues",
                  "logs:DescribeLogGroups",
                  "kinesis:List*",
                  "ecs:Describe*",
                  "health:DescribeEventDetails",
                  "cloudwatch:List*",
                  "logs:TestMetricFilter",
                  "elasticfilesystem:DescribeAccessPoints",
                  "elasticache:Describe*",
                  "sns:List*",
                  "xray:BatchGetTraces",
                  "ec2:Describe*",
                  "directconnect:Describe*",
                  "es:ListDomainNames",
                  "elasticfilesystem:DescribeTags",
                  "s3:ListAllMyBuckets",
                  "cloudfront:ListDistributions",
                  "redshift:DescribeClusters",
                  "s3:GetBucketLocation",
                  "lambda:GetPolicy",
                  "secretsmanager:CreateSecret",
                  "secretsmanager:DeleteSecret",
                  "secretsmanager:DescribeSecret",
                ],
                Resource: "*",
              },
            ],
          },
        },
      ],
    },
  }
```

> Note: *This role will work as extension execution role as well, if you need to have separate roles than you can create separate roles as well.*
> 

---


Now we'll create four **AWS::CloudFormation::TypeActivation** resources to attach to Activation Stack which will include.

1. `Datadog::Dashboards::Dashboard` - to create and manage Datadog Dashboards
2. `Datadog::Monitors::Monitor` - to create and manage Datadog Monitors
3. `Datadog::Monitors::Downtime` - to create and manage Monitors Downtime
4. `Datadog::Integrations::AWS` - to create integration between AWS and Datadog

> *Please refer to the [Cloudformation Extension - Activation Guide](https://dev.to/distinction-dev/cloudformation-extension-activation-guide-59gj) on how to activate the Cloudformation extensions*
> 

If we deploy this `Activation Stack` we will be able to create the IAMRole along with the Cloudformation Extension Activation. *(Note: We'll need to deploy this stack only once)*

> To use the activated extensions, you will need to set the Type Configurations for each extensions plugins using below code block. Also helpful if you are creating different stages and account for deployment with same AWS account.
> 

```bash
aws cloudformation set-type-configuration --type-name "Datadog::Monitors::Monitor" --type RESOURCE --configuration-alias ConfigurationName --configuration '{"DatadogCredentials": {"ApiKey": "DATADOG_API_KEY_PROD", "ApplicationKey": "DATADOG_APPLICATION_KEY_PROD", "ApiURL": "https://api.datadoghq.eu" }}'
```

---

Now we move on to creating the Datadog Resources such as Integration, Monitors and Dashboards.

# 🏗 Creating Infra Stack

We'll create a different Serverless service stack to deploy the datadog resources.

### ⚙️ Datadog AWS Integration

Here you will need to provide your AWS Account ID so that Datadog account can do the integration between the two AWS accounts.

`RoleName` would be the same as we have created in the `Activation Stack` before.

> Note:- *`ExternalIDSecretName` should be unique in your account Secret Manager and will be used to store the external ID by the extension.*
> 

```jsx
DatadogAWSIntegration: {
    Type: "Datadog::Integrations::AWS",
    Properties: {
      AccountID: "AWS_ACCOUNT_ID", // your AWS account ID
      ExternalIDSecretName: "DatadogIntegrationExternalID",
      RoleName: "DatadogAWSIntegrationRole",
    },
},
```

### 📊 Datadog Dashboards

Dashboards are helpful to monitor the services and different widgets for any services. Find more about Dashboards in [`Datadog Dashboards Documentation`](https://docs.datadoghq.com/dashboards/)

```jsx
Dashboard: {
    Type: "Datadog::Dashboards::Dashboard",
    Properties: {
      DashboardDefinition: "", // stringified object with  dashboard configurations and definitions.
    },
},
```

### ⏱ Datadog Monitor

Monitors are to create and capture events for any particular services. You can find more about monitors in [`Datadog Monitors Documentation`](https://docs.datadoghq.com/monitors/)

```jsx
Monitor: {
  Type: "Datadog::Monitors::Monitor",
  Properties: {
    Type: "event-v2 alert", // type of the monitor
    Query: "defines the query of the monitor to capture specific triggered events",
    Name: "monitor-name",
    Message: "message body which will be sent to the communication channel",
    Tags: [], // array of tags assigned to the monitor
    Options: {
      NotifyAudit: false,
      Locked: false,
      EnableLogsSample: false,
      Thresholds: {
        Critical: 1,
        CriticalRecovery: 0.5,
        Warning: 0.75,
      },
      NewHostDelay: 300,
      NotifyNoData: false,
      IncludeTags: true,
      EscalationMessage: "",
    },
    Priority: 1, // priority level - critical
  }
```

---

Hope this has been a worthwhile reading! ✨

Furthermore you can explore many more solutions and services that Datadog provides like [Logs Forwarding](https://docs.datadoghq.com/logs/guide/forwarder/?tab=cloudformation), Cloud Security, Tracing, etc.