はじめに

AWSインテグレーションを行う際にはいくつかの作業が必要になりますが、管理対象のNew Relic / Amazon Web Serviceアカウントが増えてくると、UIから都度設定を行うのは大変かと思います。
本記事ではインテグレーションのコード化したい方に向け、Terraformを使用しサンプルコードに対する解説及び、設定方法を紹介します。
また、本記事を通してAWSインテグレーションが何によって構成されているかを知り、New Relic : AWS が 1 : 多となるようなより複雑な環境での構成管理の足がかりになりますと幸いです。

Terraformの実行環境を準備する

本記事ではTerraformがインストールされたことが前提となります。
インストールされていない方は、こちらからインストールを実施しています。

本記事執筆時点での確認は下記のバージョンで行っています。
今後の機能変更などにより掲載の設定が機能しなくなった場合はご了承ください。

Terraform v1.4.2
on darwin_arm64
+ provider registry.terraform.io/hashicorp/aws v4.60.0
+ provider registry.terraform.io/hashicorp/random v3.4.3
+ provider registry.terraform.io/newrelic/newrelic v3.18.1

サンプルコード実行環境の準備

それでは早速AWSインテグレーションのサンプルコードをダウンロードし、準備していきましょう。
サンプルコード実行にあたり、New Relic / AWS providerの設定が必要になります。
準備したサンプルコードcloud-integrations-aws.tfと同じディレクトリに任意の名前(例: provider.tf )でファイルを作成します。
※New RelicおよびAWSのリージョンにつきましては、ご利用の環境にあわせ設定ください。

# Configure terraform
terraform {
  required_providers {
    newrelic = {
      source = "newrelic/newrelic"
    }
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
}

# Configure the New Relic provider
provider "newrelic" {
  account_id = var.NEW_RELIC_ACCOUNT_ID
  region     = "US"                               # Valid regions are US and EU
}

provider "aws" {
  region = "us-west-2"
}

Terraform実行しリソースを作成する

Terraformを初期化(init)後にplanを実行し、問題ないようであれば実行(apply)します。
terraform plan/apply実行に際し、対象New RelicアカウントのアカウントID及びユーザーAPI key(NRAKからはじまるkey)の入力を促されますので、前もって準備しておく必要になります。

 

$ terraform plan
var.NEW_RELIC_ACCOUNT_ID
  Enter a value: *******

provider.newrelic.api_key
  Enter a value: NRAK-****************************

AWSインテグレーション設定の流れ

AWSインテグレーションは下記の操作によって実現されています。
本記事では、これらを順を追ってTerraformで実行します。

  1. New Relicと対象プロジェクト間で連携に使用するIAMロールを作成する
  2. New Relicと対象AWSアカウントの間でStream連携を行う
  3. New Relic Ingest License Keyを作成する
  4. AWS Kinesis Data FirehoseからNew Relicに対するデータ送信設定を行う
  5. AWS CloudWatch Metric Streamsを設定する
  6. New Relicと対象AWSアカウントの間でAPI polling連携を行う
  7. AWS Cloud IntegrationでAPI pollingの設定を行う

サンプルコード解説

それでは、AWSインテグレーション設定の流れに沿ってサンプルコードについて解説していきます。
 

1. New Relicと対象プロジェクト間でのIAMロールを作成する

IAMロールを作成したうえで、ポリシーを付与します。
アクセス許可を最小限に抑えたい場合は、resource aws_iam_policy.newrelic_aws_permissionsを調整いただく形となります。

data "aws_iam_policy_document" "newrelic_assume_policy" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "AWS"
      // This is the unique identifier for New Relic account on AWS, there is no need to change this
      identifiers = [754728514883]
    }

    condition {
      test     = "StringEquals"
      variable = "sts:ExternalId"
      values   = [var.NEW_RELIC_ACCOUNT_ID]
    }
  }
}

resource "aws_iam_role" "newrelic_aws_role" {
  name               = "NewRelicInfrastructure-Integrations"
  description        = "New Relic Cloud integration role"
  assume_role_policy = data.aws_iam_policy_document.newrelic_assume_policy.json
}

resource "aws_iam_policy" "newrelic_aws_permissions" {
  name        = "NewRelicCloudStreamReadPermissions"
  description = ""
  policy      = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "budgets:ViewBudget",
        "cloudtrail:LookupEvents",
        "config:BatchGetResourceConfig",
        "config:ListDiscoveredResources",
        "ec2:DescribeInternetGateways",
        "ec2:DescribeVpcs",
        "ec2:DescribeNatGateways",
        "ec2:DescribeVpcEndpoints",
        "ec2:DescribeSubnets",
        "ec2:DescribeNetworkAcls",
        "ec2:DescribeVpcAttribute",
        "ec2:DescribeRouteTables",
        "ec2:DescribeSecurityGroups",
        "ec2:DescribeVpcPeeringConnections",
        "ec2:DescribeNetworkInterfaces",
        "ec2:DescribeVpnConnections",
        "health:DescribeAffectedEntities",
        "health:DescribeEventDetails",
        "health:DescribeEvents",
        "tag:GetResources",
        "xray:BatchGet*",
        "xray:Get*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "newrelic_aws_policy_attach" {
  role       = aws_iam_role.newrelic_aws_role.name
  policy_arn = aws_iam_policy.newrelic_aws_permissions.arn
}

2. New Relicと対象AWSアカウントの間でMetric Streams連携を行う

手順1で作成したIAMロールを対象に、Metric Streams連携の設定を行います。
Metric Streams連携を行うと、インテグレーション Production Push が作成されます。
 

resource "newrelic_cloud_aws_link_account" "newrelic_cloud_integration_push" {
  arn = aws_iam_role.newrelic_aws_role.arn
  metric_collection_mode = "PUSH"
  name = "${var.NEW_RELIC_ACCOUNT_NAME} Push"
  depends_on = [aws_iam_role_policy_attachment.newrelic_aws_policy_attach]
}
Metric Streams

3. New Relic Ingest License Keyを作成する

AWSからNew Relicへデータを送信する際に必要なIngest License Keysを作成します。

resource "newrelic_api_access_key" "newrelic_aws_access_key" {
  account_id  = var.NEW_RELIC_ACCOUNT_ID
  key_type    = "INGEST"
  ingest_type = "LICENSE"
  name        = "Ingest License key"
  notes       = "AWS Cloud Integrations Firehost Key"
}

4. AWS Kinesis Data FirehoseからNew Relicに対するデータ送信設定を行う

Kinesis Data Firehoseに関連する下記のリソースを作成します。

  • Firehose用IAMロール作成
  • S3バケット作成
  • Data Firehose 配信ストリーム作成
resource "aws_iam_role" "firehose_newrelic_role" {
  name = "firehose_newrelic_role"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "firehose.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "random_string" "s3-bucket-name" {
  length = 8
  special = false
  upper = false
}

resource "aws_s3_bucket" "newrelic_aws_bucket" {
  bucket = "newrelic-aws-bucket-${random_string.s3-bucket-name.id}"
}

resource "aws_s3_bucket_acl" "newrelic_aws_bucket_acl" {
  bucket = aws_s3_bucket.newrelic_aws_bucket.id
  acl    = "private"
}

resource "aws_kinesis_firehose_delivery_stream" "newrelic_firehost_stream" {
  name        = "newrelic_firehost_stream"
  destination = "http_endpoint"

  s3_configuration {
    role_arn           = aws_iam_role.firehose_newrelic_role.arn
    bucket_arn         = aws_s3_bucket.newrelic_aws_bucket.arn
    buffer_size        = 10
    buffer_interval    = 400
    compression_format = "GZIP"
  }

  http_endpoint_configuration {
    url                = var.NEW_RELIC_CLOUDWATCH_ENDPOINT
    name               = "New Relic"
    access_key         = newrelic_api_access_key.newrelic_aws_access_key.key
    buffering_size     = 1
    buffering_interval = 60
    role_arn           = aws_iam_role.firehose_newrelic_role.arn
    s3_backup_mode     = "FailedDataOnly"

    request_configuration {
      content_encoding = "GZIP"
    }
  }
}
Data Firehose Stream

5. AWS CloudWatch Metric Streamsを設定する

CloudWatch Metric Streamsに関連する下記のリソースを作成します。
送信する名前空間を制御する場合は、aws_cloudwatch_metric_stream.newrelic_metric_streamにて exclude_filter ないし include_filter を設定します。
詳細はドキュメントをご参照ください。

  • IAMロール
  • Metric Streams
resource "aws_iam_role" "metric_stream_to_firehose" {
  name = "metric_stream_to_firehose_role"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "streams.metrics.cloudwatch.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "metric_stream_to_firehose" {
  name = "default"
  role = aws_iam_role.metric_stream_to_firehose.id

  policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "firehose:PutRecord",
                "firehose:PutRecordBatch"
            ],
            "Resource": "${aws_kinesis_firehose_delivery_stream.newrelic_firehost_stream.arn}"
        }
    ]
}
EOF
}

resource "aws_cloudwatch_metric_stream" "newrelic_metric_stream" {
  name          = "newrelic-metric-stream"
  role_arn      = aws_iam_role.metric_stream_to_firehose.arn
  firehose_arn  = aws_kinesis_firehose_delivery_stream.newrelic_firehost_stream.arn
  output_format = "opentelemetry0.7"
}

6. New Relicと対象AWSアカウントの間でAPI polling連携を行う

手順1で作成したIAMロールを対象に、API polling連携の設定を行います。
Metric Streams連携を行うと、インテグレーション Production Pull が作成されます。
※Production Push/Pullの切り替えはプルダウンメニューで行います。

resource "newrelic_cloud_aws_link_account" "newrelic_cloud_integration_pull" {
  account_id = var.NEW_RELIC_ACCOUNT_ID
  arn = aws_iam_role.newrelic_aws_role.arn
  metric_collection_mode = "PULL"
  name = "${var.NEW_RELIC_ACCOUNT_NAME} Pull"
  depends_on = [aws_iam_role_policy_attachment.newrelic_aws_policy_attach]
}
API polling

7. AWS Cloud IntegrationでAPI pollingの設定を行う

Metric Streamsでは取得できない下記サービスの情報を統合管理したい場合は、対象サービスを設定します。

  • AWS Billing

  • AWS CloudTrai

  • AWS Health

  • AWS Trusted Advisor

  • AWS X-Ray

resource "newrelic_cloud_aws_integrations" "foo" {
  account_id = var.NEW_RELIC_ACCOUNT_ID
  linked_account_id = newrelic_cloud_aws_link_account.newrelic_cloud_integration_pull.id
  billing {}
  cloudtrail {}
  health {}
  trusted_advisor {}
  vpc {}
  x_ray {}
}
polling target

おわりに

以上、駆け足となりましたが各スタックに対しての作成方法となります。
AWSインテグレーション設定を行う際はNew Relic UIとAWS UIを行き来するなど煩雑な操作が必要になりますが、コード化することにより一括して設定を行うことができます。
多数のNew Relic / AWSアカウントを運用される方の助けになりますと幸いです。