MackerelのAWSインテグレーションで必要なRoleをCloudFormation一撃で作ってみる

AWS事業本部 梶原@福岡オフィスです。 先日、MackerelでAWSのLambdaとAPI-GatewayをMackerelで監視する機会があったんですが 実は初めて、MackerelのAWSインテグレーションで監視設定を実施しました。

が!てっきりポチポチっと行けるものだと思ったんですが、 Mackerelに対して、アカウントIDだけ渡せば、監視してくれるとかそんなことは無く(当たり前
IAM RoleとかPolicyとか信頼関係とかを考慮して慎重に作成する必要があります。
でも、これってコンソールの画面からポチポチ,IAMつくると結構めんどいですよね。(個人の意見です
信頼関係まちがったりしたら大変なことになってしまいます。
ということで、そんなあなたにCloudFormationということで、相変わらずCloudFormation1撃シリーズに加えました。

自分はMackerelで監視するのは、LambdaとAPI-Gatewayだけで良かったんですが、どこからか他のサービスも!という声が聞こえてきたので 今(2019/04/05)時点で、監視できる分はまとめてReadOnly権限つけました! とかはしません!
セキュリティ的にどうなの?と思ったので、(ポリシーの上限超えてできなかったとかじゃないよ

Mackerelで自分が監視したいサービスのReadOnly権限を選んで作成できるCloudFormationテンプレートを作りました!!! そう、後から別のサービスの監視追加したいとか言うときは、テンプレートの更新をしてパラメータを変更すればいいだけです。(すばら

割り当てるロールの権限などはMackerelの公式ドキュメントに沿っています。 https://mackerel.io/ja/docs/entry/integrations/aws

ということで、相変わらず前置きが長いですが、さくさく行きます。

※API Gatewayのリソースは東京リージョン(ap-northeast-1::/*)としてますので、他のリージョンの場合は適時変更ください

MackerelのAWSインテグレーションの作成

1. AWSコンソールにログイン

https://ap-northeast-1.console.aws.amazon.com/console/home?region=ap-northeast-1#

2. このボタンをポチっとする。

3. CloudFormationのパラメータで監視が必要なサービスを選択(true)にする。

パラメータのデフォルト設定ではEC2, RDS, Redshift, CloudFront, Lambdaを有効にしています ので、監視したいサービスをtrueまたは、監視しない(権限を渡したくない)場合はfalseに変更してください

※全部選んで(10くらい)、エラーが発生した場合は、ポリシーの上限緩和を実施しているかご確認ください。また、必要に応じて上限緩和をおこなってください。

4. CloudFormationの実行をします。

□AWS CloudFormation によって IAM リソースがカスタム名で作成される場合があることを承認します。
のチェックをいれてください

5. OutputにMackerel用のRoleのArnがでてくる

メモります。

5. MackerelのAWSインテグレーションの作成時にOutputのRoleのArnを設定します。

ここで作成 -> https://mackerel.io/my?tab=awsIntegration

上でコピーしたARNを入れます。

6. 監視する

で、後は、Mackerelで、いい感じに監視しちゃってください!

監視方法はdevelopre.IOのMackerel特集などをご参考に https://dev.classmethod.jp/?s=mackerel

まとめ

割り当てるロールの権限などはMackerelの公式ドキュメントに沿っています。 https://mackerel.io/ja/docs/entry/integrations/aws

Mackerelは更新が速いので、新しい監視サービスがでたらコメントくれるかご自分でカスタマイズしてください。

自分でRoleつくるって、ちょっとハードル高いと思ってるので、少し低くできたらなら幸いです。 Cloudfromtaionのパラメータでの条件設定、Role作成の分岐などもご参考になれば。

テンプレートはこちら

AWSTemplateFormatVersion: "2010-09-09"
Description: "IAM Assume Role for Mackerel"
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "Compute"
        Parameters:
          - AmazonEC2ReadOnlyAccess
          - ECSReadOnlyAccess
          - AWSLambdaReadOnlyAccess
      - Label:
          default: "Storage"
        Parameters:
          - AmazonS3ReadOnlyAccess
      - Label:
          default: "Database"
        Parameters:
          - AmazonRDSReadOnlyAccess
          - AmazonDynamoDBReadOnlyAccess
          - AmazonElastiCacheReadOnlyAccess
          - AmazonRedshiftReadOnlyAccess
      - Label:
          default: "Networking & Content Delivery"
        Parameters:
          - CloudFrontReadOnlyAccess
          - APIGatewayReadOnlyAccess
      - Label:
          default: "Analytics"
        Parameters:
          - AmazonKinesisReadOnlyAccess
          - AmazonESReadOnlyAccess
      - Label:
          default: "Application Integration"
        Parameters:
          - AmazonSQSReadOnlyAccess
      - Label:
          default: "Management & Governance"
        Parameters:
          - CloudWatchReadOnlyAccess
    ParameterLabels:
      AmazonEC2ReadOnlyAccess:
        default: "EC2, ELB (CLB), ALB, NLB"
      ECSReadOnlyAccess:
        default: "ECS"
      AWSLambdaReadOnlyAccess:
        default: "Lambda"
      AmazonS3ReadOnlyAccess:
        default: "S3"
      AmazonRDSReadOnlyAccess:
        default: "RDS"
      AmazonDynamoDBReadOnlyAccess:
        default: "DynamoDB"
      AmazonElastiCacheReadOnlyAccess:
        default: "ElastiCache"
      AmazonRedshiftReadOnlyAccess:
        default: "Redshift"
      CloudFrontReadOnlyAccess:
        default: "CloudFront"
      APIGatewayReadOnlyAccess:
        default: "API Gateway"
      AmazonKinesisReadOnlyAccess:
        default: "Kinesis"
      AmazonESReadOnlyAccess:
        default: "ES"
      AmazonSQSReadOnlyAccess:
        default: "SQS"
      CloudWatchReadOnlyAccess:
        default: "CloudWatch"
Parameters:
  AmazonEC2ReadOnlyAccess: 
    Description: Monitoring EC2
    Type: String
    Default: yes
    AllowedValues: [yes, no]
  AmazonRDSReadOnlyAccess: 
    Description: Monitoring RDS
    Type: String
    Default: yes
    AllowedValues: [yes, no]
  AmazonElastiCacheReadOnlyAccess: 
    Description: Monitoring ElastiCache
    Type: String
    Default: yes
    AllowedValues: [yes, no]
  AmazonRedshiftReadOnlyAccess: 
    Description: Monitoring Redshift
    Type: String
    Default: no
    AllowedValues: [yes, no]
  AWSLambdaReadOnlyAccess: 
    Description: Monitoring AWS Lambda
    Type: String
    Default: no
    AllowedValues: [yes, no]
  AmazonSQSReadOnlyAccess:
    Description: Monitoring SQS
    Type: String
    Default: no
    AllowedValues: [yes, no]
  AmazonDynamoDBReadOnlyAccess:
    Description: Monitoring DynamoDB
    Type: String
    Default: no
    AllowedValues: [yes, no]
  CloudFrontReadOnlyAccess:
    Description: Monitoring CloudFront
    Type: String
    Default: no
    AllowedValues: [yes, no]
  APIGatewayReadOnlyAccess:
    Description: Monitoring API Gateway (apigateway:GET, apigateway:OPTIONS)
    Type: String
    Default: no
    AllowedValues: [yes, no]
  AmazonKinesisReadOnlyAccess:
    Description: Monitoring Kinesis
    Type: String
    Default: no
    AllowedValues: [yes, no]
  AmazonS3ReadOnlyAccess:
    Description: Monitoring S3
    Type: String
    Default: no
    AllowedValues: [yes, no]
  AmazonESReadOnlyAccess:
    Description: Monitoring ES
    Type: String
    Default: no
    AllowedValues: [yes, no]
  ECSReadOnlyAccess:
    Description: Monitoring ECS (ecs:Describe*, ecs:List*)
    Type: String
    Default: no
    AllowedValues: [yes, no]
  CloudWatchReadOnlyAccess:
    Description: Monitoring CloudWatch (if CloudFront only, API Gateway only, Kinesis only, S3 only, ES only, ECS only)
    Type: String
    Default: no
    AllowedValues: [yes, no]
Conditions:
  AmazonEC2ReadOnlyAccess: !Equals [ !Ref AmazonEC2ReadOnlyAccess, yes ]
  AmazonRDSReadOnlyAccess: !Equals [ !Ref AmazonRDSReadOnlyAccess, yes ]
  AmazonElastiCacheReadOnlyAccess: !Equals [ !Ref AmazonElastiCacheReadOnlyAccess, yes ]
  AmazonRedshiftReadOnlyAccess: !Equals [ !Ref AmazonRedshiftReadOnlyAccess, yes ]
  AWSLambdaReadOnlyAccess: !Equals [ !Ref AWSLambdaReadOnlyAccess, yes ]
  AmazonSQSReadOnlyAccess: !Equals [ !Ref AmazonSQSReadOnlyAccess, yes ]
  AmazonDynamoDBReadOnlyAccess: !Equals [ !Ref AmazonDynamoDBReadOnlyAccess, yes ]
  CloudFrontReadOnlyAccess: !Equals [ !Ref CloudFrontReadOnlyAccess, yes ]
  APIGatewayReadOnlyAccess: !Equals [ !Ref APIGatewayReadOnlyAccess, yes ]
  AmazonKinesisReadOnlyAccess: !Equals [ !Ref AmazonKinesisReadOnlyAccess, yes ]
  AmazonS3ReadOnlyAccess: !Equals [ !Ref AmazonS3ReadOnlyAccess, yes ]
  AmazonESReadOnlyAccess: !Equals [ !Ref AmazonESReadOnlyAccess, yes ]
  ECSReadOnlyAccess: !Equals [ !Ref ECSReadOnlyAccess, yes ]
  CloudWatchReadOnlyAccess: !Equals [ !Ref CloudWatchReadOnlyAccess, yes ]
Resources: 
  MackerelAWSIntegrationRole: 
    Type: AWS::IAM::Role
    Properties: 
      RoleName: "MackerelAWSIntegrationRole"
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
        - Action: "sts:AssumeRole"
          Effect: "Allow"
          Principal: 
              AWS: "arn:aws:iam::217452466226:root"
          Condition:
            StringEquals:
              sts:ExternalId: "Mackerel-AWS-Integration"
      ManagedPolicyArns: 
        - !If [AmazonEC2ReadOnlyAccess, "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess", !Ref "AWS::NoValue"]
        - !If [AmazonRDSReadOnlyAccess, "arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess", !Ref "AWS::NoValue"]
        - !If [AmazonElastiCacheReadOnlyAccess, "arn:aws:iam::aws:policy/AmazonElastiCacheReadOnlyAccess", !Ref "AWS::NoValue"]
        - !If [AmazonRedshiftReadOnlyAccess, "arn:aws:iam::aws:policy/AmazonRedshiftReadOnlyAccess", !Ref "AWS::NoValue"]
        - !If [AWSLambdaReadOnlyAccess, "arn:aws:iam::aws:policy/AWSLambdaReadOnlyAccess", !Ref "AWS::NoValue"]
        - !If [AmazonSQSReadOnlyAccess, "arn:aws:iam::aws:policy/AmazonSQSReadOnlyAccess", !Ref "AWS::NoValue"]
        - !If [AmazonDynamoDBReadOnlyAccess, "arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess", !Ref "AWS::NoValue"]
        - !If [CloudFrontReadOnlyAccess, "arn:aws:iam::aws:policy/CloudFrontReadOnlyAccess", !Ref "AWS::NoValue"]
        - !If [AmazonKinesisReadOnlyAccess, "arn:aws:iam::aws:policy/AmazonKinesisReadOnlyAccess", !Ref "AWS::NoValue"]
        - !If [AmazonS3ReadOnlyAccess, "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess", !Ref "AWS::NoValue"]
        - !If [AmazonESReadOnlyAccess, "arn:aws:iam::aws:policy/AmazonESReadOnlyAccess", !Ref "AWS::NoValue"]
        - !If [CloudWatchReadOnlyAccess, "arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess", !Ref "AWS::NoValue"]
  APIGatewayGetPolicy:
    Condition: APIGatewayReadOnlyAccess
    Type: AWS::IAM::Policy
    Properties: 
      PolicyName: "APIGatewayGetPolicy"
      PolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - Effect: Allow
            Action:
              - apigateway:GET
              - apigateway:OPTIONS
            Resource: arn:aws:apigateway:ap-northeast-1::/*
      Roles: 
        - !Ref MackerelAWSIntegrationRole
  ECSDescribePolicy:
    Condition: ECSReadOnlyAccess
    Type: AWS::IAM::Policy
    Properties: 
      PolicyName: "ECSDescribePolicy"
      PolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - Effect: Allow
            Action:
              - ecs:Describe*
              - ecs:List*
            Resource: "*"
      Roles: 
        - !Ref MackerelAWSIntegrationRole
Outputs:
  MackerelAWSIntegrationRoleArn:
    Value: !GetAtt MackerelAWSIntegrationRole.Arn

参考URL