LoginSignup
4
2

More than 1 year has passed since last update.

【CDK】本番環境以外のAuroraClusterを自動で起動停止させる

Last updated at Posted at 2022-03-30

はじめに

本番以外の環境ではスケジュールに応じてDBを起動停止させるなんてのはよくあるシチュエーションで、Lambdaを用いて制御するのがメジャーですが、Systems Managerでも出来るよということでCDKで実装してみました。

今回使うのはSystems Manager Automationの「AWS-StartStopAuroraCluster」というドキュメントをEventBridgeを使って指定した日時に実行させようと思います。

※Systems ManagerをターゲットとしたのEventBridgeのCDK-L2コンストラクタがまだサポートされていなかったのでL1で記述しています。

Systems Manager Automation

Automationは、AWS のサービス(EC2、RDSなど)でのメンテナンスやデプロイ、修復に関するタスクを簡素化するための、AWS Systems Manager の機能の1つ。「AWS-StartStopAuroraCluster」以外にも「AWS-StartEC2Instance」や「AWSSupport-CollectECSInstanceLogs」など様々なドキュメントが標準で用意されています。

CDK

cdk.json

cdk.json
{
  "app": "npx ts-node --prefer-ts-exts bin/src.ts",
  "watch": {
    "include": [
      "**"
    ],
    "exclude": [
      "README.md",
      "cdk*.json",
      "**/*.d.ts",
      "**/*.js",
      "tsconfig.json",
      "package*.json",
      "yarn.lock",
      "node_modules",
      "test"
    ]
  },
  "context": {
    "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
    "@aws-cdk/core:stackRelativeExports": true,
    "@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
    "@aws-cdk/aws-lambda:recognizeVersionProps": true,
    "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
    "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
    "@aws-cdk/core:target-partitions": [
      "aws",
      "aws-cn"
    ],
    "prefix": "eventtest",
    "env": "stg",
    "prod": {
      "aurora": {
        "instances": 2,
        "instanceType": "r5.large"
      }
    },
    "stg": {
      "aurora": {
        "instances": 2,
        "instanceType": "t3.small"
      }
    },
    "dev": {
      "aurora": {
        "instances": 1,
        "instanceType": "t3.small"
      }
    }
  }
}

app

bin/src.ts内の以下の部分でenvがprod以外の場合のみ、eventStackを走らせるようにしてます。

if (`${env}` != 'prod') {
  const eventStack = new EventStack(app, `${prefix}-${env}-event`, rdsStack)
  eventStack.addDependency(rdsStack);
}
bin/src.ts
#!/usr/bin/env node
import * as cdk from "aws-cdk-lib";
import { VPCStack } from "../lib/vpc-stack";
import { RDSStack } from "../lib/aurora-stack";
import { EventStack } from "../lib/event-stack";

const app = new cdk.App();

// contest取得
const prefix = app.node.tryGetContext("prefix");
const env = app.node.tryGetContext("env");

const vpcStack = new VPCStack(app, `${prefix}-${env}-vpc`)
const rdsStack = new RDSStack(app, `${prefix}-${env}-aurora`, vpcStack)

// envがprod以外の場合のみ実行
if (`${env}` != 'prod') {
  const eventStack = new EventStack(app, `${prefix}-${env}-event`, rdsStack)
  eventStack.addDependency(rdsStack);
}

rdsStack.addDependency(vpcStack);

stack

vpc、aurora、eventの3つのstackを用意
envがprodの場合は、event-stackが実行されずにvpcとaruroraの2つが展開されるようになります。

lib/vpc-stack.ts
import * as cdk from 'aws-cdk-lib'
import * as ec2 from 'aws-cdk-lib/aws-ec2'

export interface VPCStackProps {
  readonly vpc: ec2.Vpc
}

export class VPCStack extends cdk.Stack implements VPCStackProps {
  public readonly vpc: ec2.Vpc

  // vpc
  private createVpc(name: string): ec2.Vpc {

    const vpc = new ec2.Vpc(this, `${name}`, {
      cidr: "10.0.0.0/16",
      maxAzs: 2,
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: 'Public',
          subnetType: ec2.SubnetType.PUBLIC,
        },
        {
          cidrMask: 24,
          name: 'Private',
          subnetType: ec2.SubnetType.PRIVATE_WITH_NAT,
        },
      ]
    })
    return vpc;
  }

  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props)

    const prefix = this.node.tryGetContext('prefix')
    const env = this.node.tryGetContext('env')

    this.vpc = this.createVpc(`${prefix}-${env}-vpc`)
  }
}
lib/aurora-stack.ts
import * as cdk from 'aws-cdk-lib'
import * as ec2 from 'aws-cdk-lib/aws-ec2'
import * as rds from 'aws-cdk-lib/aws-rds'
import type { VPCStackProps } from "./vpc-stack"

export interface RDSStackProps {
  readonly subnetgroup: rds.SubnetGroup
  readonly cluster: rds.DatabaseCluster
}

export class RDSStack extends cdk.Stack implements RDSStackProps {
  public readonly subnetgroup: rds.SubnetGroup
  public readonly cluster: rds.DatabaseCluster

  //SubnetGroup
  private creatersubnetGroup(name: string, vpc: ec2.Vpc): rds.SubnetGroup {

    const subnetgroup = new rds.SubnetGroup(this, `SubnetGroup`, {
      vpc,
      description: `${name}`,
      subnetGroupName: name,
      vpcSubnets: {subnetType: ec2.SubnetType.PRIVATE_WITH_NAT},
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    })
    return subnetgroup;
  }

  // rds
  private createrdsCluster(name: string, vpc: ec2.Vpc, subnetgroup: rds.SubnetGroup): rds.DatabaseCluster {
    const env = this.node.tryGetContext('env')
    const context = this.node.tryGetContext(env);

    const cluster = new rds.DatabaseCluster(this, `Database`, {
      engine: rds.DatabaseClusterEngine.AURORA_MYSQL,
      clusterIdentifier: `${name}-cluster`,
      instanceIdentifierBase: `${name}-instance`,
      instances: context.aurora.instances, // contextよりinstance数を取得
      subnetGroup: subnetgroup,
      instanceProps: { 
        vpc,
        instanceType: context.aurora.instanceType, // contextよりinstanceTypeを取得
        autoMinorVersionUpgrade: false,
      },
      storageEncrypted: true,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    })
    return cluster;
  }

  constructor(scope: cdk.App, id: string, VPCStack: VPCStackProps, props?: cdk.StackProps) {
    super(scope, id, props)

    const prefix = this.node.tryGetContext('prefix')
    const env = this.node.tryGetContext('env')

    this.subnetgroup = this.creatersubnetGroup(`${prefix}-${env}-subnetgroup`, VPCStack.vpc)
    this.cluster = this.createrdsCluster(`${prefix}-${env}`, VPCStack.vpc, this.subnetgroup)
  }
}
lib/event-stack.ts
import * as cdk from "aws-cdk-lib";
import * as iam from 'aws-cdk-lib/aws-iam';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as events from "aws-cdk-lib/aws-events";
import type { RDSStackProps } from "./aurora-stack";

export interface EventStackProps {
  readonly role: iam.Role;
}

export class EventStack extends cdk.Stack {
  public readonly role: iam.Role;

  // Role
  private createRole(name: string, aurora: rds.DatabaseCluster): iam.Role {
    const accountId = cdk.Stack.of(this).account;
    const region = cdk.Stack.of(this).region;

    const role = new iam.Role(this, `${name}-aurora-startstop`, {
      roleName: name,
      assumedBy: new iam.ServicePrincipal('events.amazonaws.com'),
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AmazonSSMAutomationRole'),
      ]
    });
    role.addToPolicy(new iam.PolicyStatement({
      sid: `AuroraStartStop`,
      effect: iam.Effect.ALLOW,
      actions: [
        "rds:DescribeDBInstances",
        "rds:DescribeDBClusters",
        "rds:StartDBCluster",
        "rds:StopDBCluster"
      ],
      resources: [
        `arn:aws:rds:${region}:${accountId}:cluster:${aurora.clusterIdentifier}`,
        `arn:aws:rds:${region}:${accountId}:db:${aurora.instanceIdentifiers[0]}`,
        `arn:aws:rds:${region}:${accountId}:db:${aurora.instanceIdentifiers[1]}`
      ]
    }))
  return role;
  }

  // EventBridge Auto Stop
  private createStopEvent(name: string, aurora: rds.DatabaseCluster, role: iam.Role): void {
    const region = cdk.Stack.of(this).region;

    const autoStopRule = new events.CfnRule(this, `${name}-AuroraAutoStopRule`, {
      name: `${name}-AuroraAutoStopRule`,
      scheduleExpression: 'cron(0 11 ? * MON-FRI *)', // 20:00(JST)に停止
      targets: [{
        arn: `arn:aws:ssm:${region}::automation-definition/AWS-StartStopAuroraCluster:$DEFAULT`,
        id: 'AuroraClusterAutoStop',
        input: `{"Action":["Stop"],"ClusterName":["${aurora.clusterIdentifier}"]}`,
        roleArn: role.roleArn
      }]
    })
  }

  // EventBridge Auto Start
  private createStartEvent(name: string, aurora: rds.DatabaseCluster, role: iam.Role): void {
    const region = cdk.Stack.of(this).region;

    const autoStartRule = new events.CfnRule(this, `${name}-AuroraAutoStartRule`, {
      name: `${name}-AuroraAutoStartRule`,
      scheduleExpression: 'cron(0 1 ? * MON-FRI *)', // 10:00(JST)に起動
      targets: [{
        arn: `arn:aws:ssm:${region}::automation-definition/AWS-StartStopAuroraCluster:$DEFAULT`,
        id: 'AuroraClusterAutoStart',
        input: `{"Action":["Start"],"ClusterName":["${aurora.clusterIdentifier}"]}`,
        roleArn: role.roleArn
      }]
    })
  }

  constructor(scope: cdk.App, id: string, auroraStack: RDSStackProps, props?: cdk.StackProps) {
    super(scope, id, props);

    const env = this.node.tryGetContext("env"); // Contextで指定したprefixを取得
    const prefix = this.node.tryGetContext("prefix"); // Contextで指定したprefixを取得

    this.role = this.createRole(`${prefix}-${env}-event-role`, auroraStack.cluster)
    this.createStopEvent(`${prefix}-${env}`, auroraStack.cluster, this.role);
    this.createStartEvent(`${prefix}-${env}`, auroraStack.cluster, this.role);
  }
}

動作確認

デプロイが完了してVPCなどのNW、AuroraCluster、EventBridge、IAMRoleがそれぞれ作成されました。

Aurora

スクリーンショット 2022-03-30 3.06.03.png (73.2 kB)

IamRole

SSMAutoAutomationRoleとAuroraへの権限を付与したポリシーがアタッチされたRoleが作成されます。
スクリーンショット 2022-03-30 12.03.43.png (74.1 kB)

AuroraClusterに対するStart/Stop権限を付与したポリシー
スクリーンショット_2022-03-30_12_03_57.png (75.0 kB)

EventBridge

AutoStartRuleとAutoStopRuleの2種類が作成
スクリーンショット 2022-03-30 3.09.59.png (39.5 kB)

Rule内では指定したcron通りのスケジュールが組まれてます。
スクリーンショット_2022-03-30_3_10_40.png (74.9 kB)

Eventのターゲットを見るとSystem Maneger オートメーションの「AWS-StartStopAuroraCluster」が指定され、入力定数のActionにはStartStopClusterNameAuroraClusterの識別子がそれぞれ指定されています。Roleもちゃんと適用されてますね。
スクリーンショット 2022-03-30 3.10.59.png (40.5 kB)

スクリーンショット 2022-03-30 3.11.07.png (20.6 kB)

AuroraCluster自動停止起動確認

イベントスケジュールを適当な時刻に合わせて自動停止/起動を検証したところ、問題なく実行されました。
スクリーンショット_2022-03-30_12_23_35.png (60.0 kB)

スクリーンショット_2022-03-30_12_23_46.png (96.0 kB)

CloudTrail上でも、発信元IPアドレスがevents.amazonaws.comによるStopDBClusterStartDBClusterがそれぞれ履歴として記録されていますね。

スクリーンショット 2022-03-30 12.19.37.png (57.9 kB)

envをprodとdevにそれぞれ指定してdiffを確認

検証ではstgを指定してデプロイしたので、それ以外を指定した場合とで展開されるStackを比較します。
※各リソースの命名にenv区分を設けているのでdiffの結果がそのまま展開されるリソースということになります。

devの場合

devの場合はeventtest-dev-vpceventtest-dev-auroraeventtest-dev-eventがstgの差分として出力されています。

% cdk diff -c env=dev                                                       ?[logalert]
Stack eventtest-dev-vpc
Parameters
[+] Parameter BootstrapVersion BootstrapVersion: {"Type":"AWS::SSM::Parameter::Value<String>","Default":"/cdk-bootstrap/hnb659fds/version","Description":"Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"}

Conditions
[+] Condition CDKMetadata/Condition CDKMetadataAvailable: {"Fn::Or":[{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"af-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ca-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-northwest-1"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-3"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"me-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"sa-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-2"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-2"]}]}]}

Resources
[+] AWS::EC2::VPC eventtest-dev-vpc eventtestdevvpcF1C58DDB 
[+] AWS::EC2::Subnet eventtest-dev-vpc/PublicSubnet1/Subnet eventtestdevvpcPublicSubnet1Subnet3A2F729B 
[+] AWS::EC2::RouteTable eventtest-dev-vpc/PublicSubnet1/RouteTable eventtestdevvpcPublicSubnet1RouteTable3CD01344 
[+] AWS::EC2::SubnetRouteTableAssociation eventtest-dev-vpc/PublicSubnet1/RouteTableAssociation eventtestdevvpcPublicSubnet1RouteTableAssociationF26CBE1A 
[+] AWS::EC2::Route eventtest-dev-vpc/PublicSubnet1/DefaultRoute eventtestdevvpcPublicSubnet1DefaultRoute72DD17B7 
[+] AWS::EC2::EIP eventtest-dev-vpc/PublicSubnet1/EIP eventtestdevvpcPublicSubnet1EIPB98AA85A 
[+] AWS::EC2::NatGateway eventtest-dev-vpc/PublicSubnet1/NATGateway eventtestdevvpcPublicSubnet1NATGatewayF5E1273E 
[+] AWS::EC2::Subnet eventtest-dev-vpc/PublicSubnet2/Subnet eventtestdevvpcPublicSubnet2SubnetD6AD1270 
[+] AWS::EC2::RouteTable eventtest-dev-vpc/PublicSubnet2/RouteTable eventtestdevvpcPublicSubnet2RouteTable59DEEA55 
[+] AWS::EC2::SubnetRouteTableAssociation eventtest-dev-vpc/PublicSubnet2/RouteTableAssociation eventtestdevvpcPublicSubnet2RouteTableAssociation9286CEF4 
[+] AWS::EC2::Route eventtest-dev-vpc/PublicSubnet2/DefaultRoute eventtestdevvpcPublicSubnet2DefaultRoute03E3B042 
[+] AWS::EC2::EIP eventtest-dev-vpc/PublicSubnet2/EIP eventtestdevvpcPublicSubnet2EIPEAD4B0BE 
[+] AWS::EC2::NatGateway eventtest-dev-vpc/PublicSubnet2/NATGateway eventtestdevvpcPublicSubnet2NATGateway7CAA7494 
[+] AWS::EC2::Subnet eventtest-dev-vpc/PrivateSubnet1/Subnet eventtestdevvpcPrivateSubnet1SubnetDA7C0851 
[+] AWS::EC2::RouteTable eventtest-dev-vpc/PrivateSubnet1/RouteTable eventtestdevvpcPrivateSubnet1RouteTableB25FFB72 
[+] AWS::EC2::SubnetRouteTableAssociation eventtest-dev-vpc/PrivateSubnet1/RouteTableAssociation eventtestdevvpcPrivateSubnet1RouteTableAssociationAD7C5CC1 
[+] AWS::EC2::Route eventtest-dev-vpc/PrivateSubnet1/DefaultRoute eventtestdevvpcPrivateSubnet1DefaultRoute32EA15BD 
[+] AWS::EC2::Subnet eventtest-dev-vpc/PrivateSubnet2/Subnet eventtestdevvpcPrivateSubnet2SubnetF92CED9F 
[+] AWS::EC2::RouteTable eventtest-dev-vpc/PrivateSubnet2/RouteTable eventtestdevvpcPrivateSubnet2RouteTable20C7ABC4 
[+] AWS::EC2::SubnetRouteTableAssociation eventtest-dev-vpc/PrivateSubnet2/RouteTableAssociation eventtestdevvpcPrivateSubnet2RouteTableAssociationAD13C64F 
[+] AWS::EC2::Route eventtest-dev-vpc/PrivateSubnet2/DefaultRoute eventtestdevvpcPrivateSubnet2DefaultRoute8DB548F6 
[+] AWS::EC2::InternetGateway eventtest-dev-vpc/IGW eventtestdevvpcIGW31EDB392 
[+] AWS::EC2::VPCGatewayAttachment eventtest-dev-vpc/VPCGW eventtestdevvpcVPCGWB4BD99D3 

Outputs
[+] Output Exports/Output{"Ref":"eventtestdevvpcPrivateSubnet1SubnetDA7C0851"} ExportsOutputRefeventtestdevvpcPrivateSubnet1SubnetDA7C0851A86E0B9D: {"Value":{"Ref":"eventtestdevvpcPrivateSubnet1SubnetDA7C0851"},"Export":{"Name":"eventtest-dev-vpc:ExportsOutputRefeventtestdevvpcPrivateSubnet1SubnetDA7C0851A86E0B9D"}}
[+] Output Exports/Output{"Ref":"eventtestdevvpcPrivateSubnet2SubnetF92CED9F"} ExportsOutputRefeventtestdevvpcPrivateSubnet2SubnetF92CED9FCB2379A6: {"Value":{"Ref":"eventtestdevvpcPrivateSubnet2SubnetF92CED9F"},"Export":{"Name":"eventtest-dev-vpc:ExportsOutputRefeventtestdevvpcPrivateSubnet2SubnetF92CED9FCB2379A6"}}
[+] Output Exports/Output{"Ref":"eventtestdevvpcF1C58DDB"} ExportsOutputRefeventtestdevvpcF1C58DDB38C33E3E: {"Value":{"Ref":"eventtestdevvpcF1C58DDB"},"Export":{"Name":"eventtest-dev-vpc:ExportsOutputRefeventtestdevvpcF1C58DDB38C33E3E"}}

Other Changes
[+] Unknown Rules: {"CheckBootstrapVersion":{"Assertions":[{"Assert":{"Fn::Not":[{"Fn::Contains":[["1","2","3","4","5"],{"Ref":"BootstrapVersion"}]}]},"AssertDescription":"CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."}]}}

Stack eventtest-dev-aurora
Security Group Changes
┌───┬───────────────────────────────────┬─────┬────────────┬─────────────────┐
│   │ Group                             │ Dir │ Protocol   │ Peer            │
├───┼───────────────────────────────────┼─────┼────────────┼─────────────────┤
│ + │ ${Database/SecurityGroup.GroupId} │ Out │ Everything │ Everyone (IPv4) │
└───┴───────────────────────────────────┴─────┴────────────┴─────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Parameters
[+] Parameter BootstrapVersion BootstrapVersion: {"Type":"AWS::SSM::Parameter::Value<String>","Default":"/cdk-bootstrap/hnb659fds/version","Description":"Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"}

Conditions
[+] Condition CDKMetadata/Condition CDKMetadataAvailable: {"Fn::Or":[{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"af-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ca-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-northwest-1"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-3"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"me-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"sa-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-2"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-2"]}]}]}

Resources
[+] AWS::RDS::DBSubnetGroup SubnetGroup SubnetGroup 
[+] AWS::EC2::SecurityGroup Database/SecurityGroup DatabaseSecurityGroup5C91FDCB 
[+] AWS::SecretsManager::Secret Database/Secret DatabaseSecret3B817195 
[+] AWS::SecretsManager::SecretTargetAttachment Database/Secret/Attachment DatabaseSecretAttachmentE5D1B020 
[+] AWS::RDS::DBCluster Database DatabaseB269D8BB 
[+] AWS::RDS::DBInstance Database/Instance1 DatabaseInstance1844F58FD 

Outputs
[+] Output Exports/Output{"Ref":"DatabaseB269D8BB"} ExportsOutputRefDatabaseB269D8BB88F4B1C4: {"Value":{"Ref":"DatabaseB269D8BB"},"Export":{"Name":"eventtest-dev-aurora:ExportsOutputRefDatabaseB269D8BB88F4B1C4"}}
[+] Output Exports/Output{"Ref":"DatabaseInstance1844F58FD"} ExportsOutputRefDatabaseInstance1844F58FDF162DF73: {"Value":{"Ref":"DatabaseInstance1844F58FD"},"Export":{"Name":"eventtest-dev-aurora:ExportsOutputRefDatabaseInstance1844F58FDF162DF73"}}

Other Changes
[+] Unknown Rules: {"CheckBootstrapVersion":{"Assertions":[{"Assert":{"Fn::Not":[{"Fn::Contains":[["1","2","3","4","5"],{"Ref":"BootstrapVersion"}]}]},"AssertDescription":"CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."}]}}

Stack eventtest-dev-event
IAM Statement Changes
┌───┬──────────────────────┬────────┬──────────────────────┬──────────────────────┬───────────┐
│   │ Resource             │ Effect │ Action               │ Principal            │ Condition │
├───┼──────────────────────┼────────┼──────────────────────┼──────────────────────┼───────────┤
│ + │ ${eventtest-dev-even │ Allow  │ sts:AssumeRole       │ Service:events.amazo │           │
│   │ t-role-aurora-starts │        │                      │ naws.com             │           │
│   │ top.Arn}             │        │                      │                      │           │
├───┼──────────────────────┼────────┼──────────────────────┼──────────────────────┼───────────┤
│ + │ arn:aws:rds:${AWS::R │ Allow  │ rds:DescribeDBCluste │ AWS:${eventtest-dev- │           │
│   │ egion}:${AWS::Accoun │        │ rs                   │ event-role-aurora-st │           │
│   │ tId}:cluster:{"Fn::I │        │ rds:DescribeDBInstan │ artstop}             │           │
│   │ mportValue":"eventte │        │ ces                  │                      │           │
│   │ st-dev-aurora:Export │        │ rds:StartDBCluster   │                      │           │
│   │ sOutputRefDatabaseB2 │        │ rds:StopDBCluster    │                      │           │
│   │ 69D8BB88F4B1C4"}     │        │                      │                      │           │
│   │ arn:aws:rds:${AWS::R │        │                      │                      │           │
│   │ egion}:${AWS::Accoun │        │                      │                      │           │
│   │ tId}:db:undefined    │        │                      │                      │           │
│   │ arn:aws:rds:${AWS::R │        │                      │                      │           │
│   │ egion}:${AWS::Accoun │        │                      │                      │           │
│   │ tId}:db:{"Fn::Import │        │                      │                      │           │
│   │ Value":"eventtest-de │        │                      │                      │           │
│   │ v-aurora:ExportsOutp │        │                      │                      │           │
│   │ utRefDatabaseInstanc │        │                      │                      │           │
│   │ e1844F58FDF162DF73"} │        │                      │                      │           │
└───┴──────────────────────┴────────┴──────────────────────┴──────────────────────┴───────────┘
IAM Policy Changes
┌───┬────────────────────────────────────────────┬────────────────────────────────────────────┐
│   │ Resource                                   │ Managed Policy ARN                         │
├───┼────────────────────────────────────────────┼────────────────────────────────────────────┤
│ + │ ${eventtest-dev-event-role-aurora-startsto │ arn:${AWS::Partition}:iam::aws:policy/serv │
│   │ p}                                         │ ice-role/AmazonSSMAutomationRole           │
└───┴────────────────────────────────────────────┴────────────────────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Parameters
[+] Parameter BootstrapVersion BootstrapVersion: {"Type":"AWS::SSM::Parameter::Value<String>","Default":"/cdk-bootstrap/hnb659fds/version","Description":"Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"}

Conditions
[+] Condition CDKMetadata/Condition CDKMetadataAvailable: {"Fn::Or":[{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"af-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ca-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-northwest-1"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-3"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"me-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"sa-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-2"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-2"]}]}]}

Resources
[+] AWS::IAM::Role eventtest-dev-event-role-aurora-startstop eventtestdeveventroleaurorastartstop954CBEF0 
[+] AWS::IAM::Policy eventtest-dev-event-role-aurora-startstop/DefaultPolicy eventtestdeveventroleaurorastartstopDefaultPolicy79B7D1C5 
[+] AWS::Events::Rule eventtest-dev-AuroraAutoStopRule eventtestdevAuroraAutoStopRule 
[+] AWS::Events::Rule eventtest-dev-AuroraAutoStartRule eventtestdevAuroraAutoStartRule 

Other Changes
[+] Unknown Rules: {"CheckBootstrapVersion":{"Assertions":[{"Assert":{"Fn::Not":[{"Fn::Contains":[["1","2","3","4","5"],{"Ref":"BootstrapVersion"}]}]},"AssertDescription":"CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."}]}}

prodの場合

一方でprodの場合の展開されるであろうstackはeventtest-prod-auroraeventtest-prod-auroraだけであることが分かります。event-stackが実行されないことが確認できましたね。

% cdk diff -c env=prod                                                      ?[logalert]
Stack eventtest-prod-vpc
Parameters
[+] Parameter BootstrapVersion BootstrapVersion: {"Type":"AWS::SSM::Parameter::Value<String>","Default":"/cdk-bootstrap/hnb659fds/version","Description":"Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"}

Conditions
[+] Condition CDKMetadata/Condition CDKMetadataAvailable: {"Fn::Or":[{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"af-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ca-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-northwest-1"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-3"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"me-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"sa-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-2"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-2"]}]}]}

Resources
[+] AWS::EC2::VPC eventtest-prod-vpc eventtestprodvpc60BD6525 
[+] AWS::EC2::Subnet eventtest-prod-vpc/PublicSubnet1/Subnet eventtestprodvpcPublicSubnet1Subnet933DD4F9 
[+] AWS::EC2::RouteTable eventtest-prod-vpc/PublicSubnet1/RouteTable eventtestprodvpcPublicSubnet1RouteTable3AA66A4B 
[+] AWS::EC2::SubnetRouteTableAssociation eventtest-prod-vpc/PublicSubnet1/RouteTableAssociation eventtestprodvpcPublicSubnet1RouteTableAssociation8A44C4DD 
[+] AWS::EC2::Route eventtest-prod-vpc/PublicSubnet1/DefaultRoute eventtestprodvpcPublicSubnet1DefaultRoute1D5C14B5 
[+] AWS::EC2::EIP eventtest-prod-vpc/PublicSubnet1/EIP eventtestprodvpcPublicSubnet1EIPE51ED220 
[+] AWS::EC2::NatGateway eventtest-prod-vpc/PublicSubnet1/NATGateway eventtestprodvpcPublicSubnet1NATGateway0D921433 
[+] AWS::EC2::Subnet eventtest-prod-vpc/PublicSubnet2/Subnet eventtestprodvpcPublicSubnet2Subnet4D4F7879 
[+] AWS::EC2::RouteTable eventtest-prod-vpc/PublicSubnet2/RouteTable eventtestprodvpcPublicSubnet2RouteTable8B22DBC8 
[+] AWS::EC2::SubnetRouteTableAssociation eventtest-prod-vpc/PublicSubnet2/RouteTableAssociation eventtestprodvpcPublicSubnet2RouteTableAssociation76235E9E 
[+] AWS::EC2::Route eventtest-prod-vpc/PublicSubnet2/DefaultRoute eventtestprodvpcPublicSubnet2DefaultRoute2853AEE3 
[+] AWS::EC2::EIP eventtest-prod-vpc/PublicSubnet2/EIP eventtestprodvpcPublicSubnet2EIP0C3871BE 
[+] AWS::EC2::NatGateway eventtest-prod-vpc/PublicSubnet2/NATGateway eventtestprodvpcPublicSubnet2NATGateway1B31C15E 
[+] AWS::EC2::Subnet eventtest-prod-vpc/PrivateSubnet1/Subnet eventtestprodvpcPrivateSubnet1Subnet5F692D49 
[+] AWS::EC2::RouteTable eventtest-prod-vpc/PrivateSubnet1/RouteTable eventtestprodvpcPrivateSubnet1RouteTable2A9B119A 
[+] AWS::EC2::SubnetRouteTableAssociation eventtest-prod-vpc/PrivateSubnet1/RouteTableAssociation eventtestprodvpcPrivateSubnet1RouteTableAssociation61E30962 
[+] AWS::EC2::Route eventtest-prod-vpc/PrivateSubnet1/DefaultRoute eventtestprodvpcPrivateSubnet1DefaultRouteF60E052F 
[+] AWS::EC2::Subnet eventtest-prod-vpc/PrivateSubnet2/Subnet eventtestprodvpcPrivateSubnet2Subnet53F01FAA 
[+] AWS::EC2::RouteTable eventtest-prod-vpc/PrivateSubnet2/RouteTable eventtestprodvpcPrivateSubnet2RouteTable2CD271B8 
[+] AWS::EC2::SubnetRouteTableAssociation eventtest-prod-vpc/PrivateSubnet2/RouteTableAssociation eventtestprodvpcPrivateSubnet2RouteTableAssociation90AA9E8E 
[+] AWS::EC2::Route eventtest-prod-vpc/PrivateSubnet2/DefaultRoute eventtestprodvpcPrivateSubnet2DefaultRoute1FA2B890 
[+] AWS::EC2::InternetGateway eventtest-prod-vpc/IGW eventtestprodvpcIGW8A932F50 
[+] AWS::EC2::VPCGatewayAttachment eventtest-prod-vpc/VPCGW eventtestprodvpcVPCGW6767810A 

Outputs
[+] Output Exports/Output{"Ref":"eventtestprodvpcPrivateSubnet1Subnet5F692D49"} ExportsOutputRefeventtestprodvpcPrivateSubnet1Subnet5F692D49ECB47F1A: {"Value":{"Ref":"eventtestprodvpcPrivateSubnet1Subnet5F692D49"},"Export":{"Name":"eventtest-prod-vpc:ExportsOutputRefeventtestprodvpcPrivateSubnet1Subnet5F692D49ECB47F1A"}}
[+] Output Exports/Output{"Ref":"eventtestprodvpcPrivateSubnet2Subnet53F01FAA"} ExportsOutputRefeventtestprodvpcPrivateSubnet2Subnet53F01FAA21084046: {"Value":{"Ref":"eventtestprodvpcPrivateSubnet2Subnet53F01FAA"},"Export":{"Name":"eventtest-prod-vpc:ExportsOutputRefeventtestprodvpcPrivateSubnet2Subnet53F01FAA21084046"}}
[+] Output Exports/Output{"Ref":"eventtestprodvpc60BD6525"} ExportsOutputRefeventtestprodvpc60BD65256808C09B: {"Value":{"Ref":"eventtestprodvpc60BD6525"},"Export":{"Name":"eventtest-prod-vpc:ExportsOutputRefeventtestprodvpc60BD65256808C09B"}}

Other Changes
[+] Unknown Rules: {"CheckBootstrapVersion":{"Assertions":[{"Assert":{"Fn::Not":[{"Fn::Contains":[["1","2","3","4","5"],{"Ref":"BootstrapVersion"}]}]},"AssertDescription":"CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."}]}}

Stack eventtest-prod-aurora
Security Group Changes
┌───┬───────────────────────────────────┬─────┬────────────┬─────────────────┐
│   │ Group                             │ Dir │ Protocol   │ Peer            │
├───┼───────────────────────────────────┼─────┼────────────┼─────────────────┤
│ + │ ${Database/SecurityGroup.GroupId} │ Out │ Everything │ Everyone (IPv4) │
└───┴───────────────────────────────────┴─────┴────────────┴─────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Parameters
[+] Parameter BootstrapVersion BootstrapVersion: {"Type":"AWS::SSM::Parameter::Value<String>","Default":"/cdk-bootstrap/hnb659fds/version","Description":"Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"}

Conditions
[+] Condition CDKMetadata/Condition CDKMetadataAvailable: {"Fn::Or":[{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"af-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ca-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-northwest-1"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-3"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"me-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"sa-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-2"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-2"]}]}]}

Resources
[+] AWS::RDS::DBSubnetGroup SubnetGroup SubnetGroup 
[+] AWS::EC2::SecurityGroup Database/SecurityGroup DatabaseSecurityGroup5C91FDCB 
[+] AWS::SecretsManager::Secret Database/Secret DatabaseSecret3B817195 
[+] AWS::SecretsManager::SecretTargetAttachment Database/Secret/Attachment DatabaseSecretAttachmentE5D1B020 
[+] AWS::RDS::DBCluster Database DatabaseB269D8BB 
[+] AWS::RDS::DBInstance Database/Instance1 DatabaseInstance1844F58FD 
[+] AWS::RDS::DBInstance Database/Instance2 DatabaseInstance2AA380DEE 

Other Changes
[+] Unknown Rules: {"CheckBootstrapVersion":{"Assertions":[{"Assert":{"Fn::Not":[{"Fn::Contains":[["1","2","3","4","5"],{"Ref":"BootstrapVersion"}]}]},"AssertDescription":"CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."}]}}

さいごに

今回はEventBridgeとSystem Manger Automationを使ってAuroraClusterの自動停止起動を検証してみました。
コンソール上でも比較的簡単に出来るのは勿論ですが、CDKでも定義出来る事が確認出来たのでシーンによってさっと使えるようにストックしておくのはありですね。

EventBridgeは、AWS内をターゲットとしたのものだけでなくAuth0やDatadog、Shopify、Zendeskなどの外部SaaSとの統合がサポートされており可能性を秘めたサービスなので、機会があったらそちらも試してみたいですね。

参考

https://aws.amazon.com/jp/eventbridge/integrations/
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-automation.html
https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_events-readme.html

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2