サイトアイコン 協栄情報ブログ

RDSイベントを取得してCloudWatchLogsに出力するハンズオン


この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので十分ご注意ください。

はじめに

RDSのイベントについてもログで管理したいという思いから、EventBridgeを利用して、RDSのイベントが発生したログをCloudWatchLogsに出力するまでの構築をCFnで構築してみました。


構成図

①VPC作成
②RDS作成
③EventBridge及びCloudWatchLogs作成
上記順番で構築をしていきます。


ハンズオン

1.VPC作成

以前記載したブログCloudFormationを使ってVPC構築に沿って、VPCを構築していきます。
後続の作業でVPCのCIDRが必要になるので、Outputsに下記追加部分を足しておきます。

Outputs:
# VPC
  VPC:
    Value: !Ref VPC
    Export:
      Name: !Sub "${PJName}-vpc"
###追加部分##############################
 VpcCidr:
    Value: !Ref VpcCidr
    Export:
      Name: !Sub "${PJName}-vpc-cidr"
###ここまで###############################

2.RDS作成

検証用のMySQLを作成していきます。
そのためDBインスタンスクラスもdb.t2.microと最小限です。
ただし今後もテンプレートは活用できそうなので、拡張できるようパラメータなどの記載は多め。

AWSTemplateFormatVersion: "2010-09-09"
Description:
  RDS for  MySQL Create

# ------------------------------------------------------------#
# Metadatas
# ------------------------------------------------------------# 
Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "Project Name Prefix"
        Parameters:
          - PJPrefix
      - Label:
          default: "RDS Configuration"
        Parameters:
          - DBInstanceName
          - MySQLMajorVersion
          - MySQLMinorVersion
          - DBInstanceClass
          - DBInstanceStorageSize
          - DBInstanceStorageType
          - DBName
          - DBMasterUserName
          - DBPassword
          - MultiAZ
    ParameterLabels:
      DBInstanceName:
        default: "DBInstanceName"
      MySQLMajorVersion:
        default: "MySQLMajorVersion"
      MySQLMinorVersion:
        default: "MySQLMinorVersion"
      DBInstanceClass:
        default: "DBInstanceClass"
      DBInstanceStorageSize:
        default: "DBInstanceStorageSize"
      DBInstanceStorageType:
        default: "DBInstanceStorageType"
      DBName:
        default: "DBName"
      DBMasterUserName:
        default: "DBUserName"
      DBPassword:
        default: "DBPassword"
      MultiAZ:
        default: "MultiAZ"
      CopyTagsToSnapshot:
        default: "CopyTagsToSnapshot"

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  PJPrefix:
    Type: String
    Default: "cfn-inamura"
  DBInstanceName:
    Type: String
    Default: "mysql"
  MySQLMajorVersion:
    Type: String
    Default: "8.0"
  MySQLMinorVersion:
    Type: String
    Default: "28"
    AllowedValues: [ "31", "30", "28", "27", "26", "25", "23" ]
  DBInstanceClass:
    Type: String
    Default: "db.t2.micro" 
  DBInstanceStorageSize:
    Type: String
    Default: "20"
  DBInstanceStorageType:
    Type: String
    Default: "gp2"
  DBName:
    Type: String
    Default: "db"
  DBMasterUserName:
    Type: String
    Default: "dbuser"
    NoEcho: true
    MinLength: 1
    MaxLength: 16
    AllowedPattern: "[a-zA-Z][a-zA-Z0-9]*"
    ConstraintDescription: "must begin with a letter and contain only alphanumeric characters."
  DBPassword: 
    Default: "dbpassword"
    NoEcho: true
    Type: String
    MinLength: 8
    MaxLength: 41
    AllowedPattern: "[a-zA-Z0-9]*"
    ConstraintDescription: "must contain only alphanumeric characters."
  MultiAZ: 
    Default: "false"
    Type: String
    AllowedValues: [ "true", "false" ]
  CopyTagsToSnapshot:
    Default: "false"
    Type: String
    AllowedValues: [ "true", "false" ]

Resources: 
# ------------------------------------------------------------#
#  DBInstance MySQL
# ------------------------------------------------------------#
  DBInstance: 
    Type: "AWS::RDS::DBInstance"
    Properties: 
      DBInstanceIdentifier: !Sub "${PJPrefix}-${DBInstanceName}"
      Engine: MySQL
      EngineVersion: !Sub "${MySQLMajorVersion}.${MySQLMinorVersion}"
      DBInstanceClass: !Ref DBInstanceClass
      AllocatedStorage: !Ref DBInstanceStorageSize
      StorageType: !Ref DBInstanceStorageType
      DBName: !Ref DBName
      MasterUsername: !Ref DBMasterUserName
      MasterUserPassword: !Ref DBPassword
      DBSubnetGroupName: !Ref DBSubnetGroup
      PubliclyAccessible: false
      MultiAZ: !Ref MultiAZ
      PreferredBackupWindow: "18:00-18:30"
      PreferredMaintenanceWindow: "sat:19:00-sat:19:30"
      AutoMinorVersionUpgrade: false
      DBParameterGroupName: !Ref DBParameterGroup  
      VPCSecurityGroups:
        - !Ref RDSSecurityGroup
      CopyTagsToSnapshot: !Ref CopyTagsToSnapshot
      BackupRetentionPeriod: 7
      Tags: 
        - Key: "Name"
          Value: !Ref DBInstanceName
    DeletionPolicy: "Delete"

# ------------------------------------------------------------#
#  DBParameterGroup
# ------------------------------------------------------------#
  DBParameterGroup:
    Type: "AWS::RDS::DBParameterGroup"
    Properties:
      Family: !Sub "MySQL${MySQLMajorVersion}"
      Description: !Sub "${PJPrefix}-${DBInstanceName}-parm"

# ------------------------------------------------------------#
#  SecurityGroup for RDS(MySQL)
# ------------------------------------------------------------#
  RDSSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: !ImportValue cfn-inamura-vpc
      GroupName: !Sub "${PJPrefix}-${DBInstanceName}-sg"
      GroupDescription: "-"
      Tags:
        - Key: "Name"
          Value: !Sub "${PJPrefix}-${DBInstanceName}-sg"
# Rule
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3306
          ToPort: 3306
          CidrIp: !ImportValue cfn-inamura-vpc-cidr

# ------------------------------------------------------------#
#  DBSubnetGroup
# ------------------------------------------------------------#
  DBSubnetGroup: 
    Type: "AWS::RDS::DBSubnetGroup"
    Properties: 
      DBSubnetGroupName: !Sub "${PJPrefix}-${DBInstanceName}-subnet"
      DBSubnetGroupDescription: "-"
      SubnetIds: 
        - !ImportValue cfn-inamura-private-subneta
        - !ImportValue cfn-inamura-private-subnetc

# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#                
Outputs:
#DBInstance
  DBInstanceID:
    Value: !Ref DBInstance
    Export:
      Name: !Sub "${PJPrefix}-${DBInstanceName}-id"

  DBInstanceEndpoint:
    Value: !GetAtt DBInstance.Endpoint.Address
    Export:
      Name: !Sub "${PJPrefix}-${DBInstanceName}-endpoint"

  DBName:
    Value: !Ref DBName
    Export:
      Name: !Sub "${PJPrefix}-${DBInstanceName}-dbname"

3.EventBridge、ログ出力先CloudwatchLogs作成

リソースポリシーを作成してEventBridgeに、CloudWatchlogsへログを出力させます。
当初はIAMロールをつくって、どうしたらいいのか分からずハマりました。

AWS公式:AWS::Logs::ResourcePolicy

AWSTemplateFormatVersion: "2010-09-09"
Description:
  EventBridge gets RDS events and sends them to CloudWatchlogs

# ------------------------------------------------------------#
# Metadatas
# ------------------------------------------------------------# 
Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "Project Name Prefix"
        Parameters:
          - PJPrefix
      - Label:
          default: "CloudWatchLogs Configuration"
        Parameters:
          - LogGroupName
      - Label:
          default: "EventBridge Configuration"
        Parameters:
          - EventBridgeRuleName
          - TargetRDSName

    ParameterLabels:
      LogGroupName:
        default: "LogGroupName"

      EventBridgeRuleName:
        default: "EventBridgeRuleName"

      TargetRDSName:
        default: "TargetRDSName"

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  PJPrefix:
    Type: String
    Default: "cfn-inamura"

  LogGroupName:
    Type: String
    Default: "/aws/events/rdbevents"

  EventBridgeRuleName:
    Type: String
    Default: "SendCloudWatchlogs"

  TargetRDSName:
    Type: String
    Default: "cfn-inamura-mysql"

# ------------------------------------------------------------#
#  ResourcePolicy
# ------------------------------------------------------------#
Resources:
  ResourcePolicyForEventsToLogs:
    Type: AWS::Logs::ResourcePolicy
    Properties:
      PolicyName: !Sub "${PJPrefix}-evb-resourcepolicy"
      PolicyDocument: !Sub 
        - |
          {
            "Version": "2012-10-17",
            "Statement": [
              {
                "Effect": "Allow",
                "Principal": {
                  "Service": "events.amazonaws.com"
                },
                "Action": [
                  "logs:CreateLogStream",
                  "logs:PutLogEvents"
                ],
                "Resource": "${CloudWatchLogsLogGroupArn}"
              }
            ]
          }
        - CloudWatchLogsLogGroupArn: !GetAtt RDSEventsLogGroup.Arn

# ------------------------------------------------------------#
#  CloudWatchLogs
# ------------------------------------------------------------#
  RDSEventsLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "${LogGroupName}"

# ------------------------------------------------------------#
#  EventBridge
# ------------------------------------------------------------#
  RDSEventsRule:
    Type: AWS::Events::Rule
    DependsOn: ResourcePolicyForEventsToLogs
    Properties:
      Name: !Sub "${PJPrefix}-evb-${EventBridgeRuleName}"
      Description: "Get RDS events and send them to CloudWatchlogs"
      State: ENABLED
      EventPattern:
        source: 
          - aws.rds
        detail-type:
          - "RDS DB Instance Event"
        resources:
          -  !Sub "arn:${AWS::Partition}:rds:${AWS::Region}:${AWS::AccountId}:db:${TargetRDSName}"
      Targets:
        - Arn: !GetAtt RDSEventsLogGroup.Arn
          Id: !Sub "RDSEventsLogGroup"

挙動の確認

①RDBを再起動する

②再起動後CloudWatchLogsの/aws/events/rdbeventsを確認すると、ログストリームに2つのログが確認できる。

・下記画面は、新しいタイムスタンプ詳細内容を表示したもので"Message": "DB instance restarted"のイベント内容が確認できる。

③EventBridgeのモニタリング(CloudWatchメトリクス)でもオレンジ点で起動していることを確認できる。


さいごに

リソースポリシーの構築及び、CFnの書き方など勉強すべき部分は多々あるので、こういった構築の方法をを自分で考えながら手を動かして作っていくようにしていきます。

参考

CloudWatch Logsのリソースポリシー作成がCloudFormationに対応していた!

モバイルバージョンを終了