『タグなしポイ捨てリソース、ダメ絶対!!』Config非準拠判定でSNSメール通知構築ハンズオン

## はじめに
年末の大掃除ということで、会社内の検証環境を改めて確認しました。メンバーが多くなると仕方ない部分かとは思いますが、タグが付与されていない野良リソースとも言える、どこで誰がなんの目的でつくったかも分からない放置リソースが多く目立ちます。

`タグなしポイ捨てリソース、ダメ絶対`というこで、リソースの片付け第一弾として、Configルールを利用して非準拠判定が出たらSNSでメンバーに通知が行くような構築をしていきたいと思います。

------------

## 構成図
![](https://cloud5.jp/wp-content/uploads/2022/12/スクリーンショット-2022-12-24-14.36.00-640x186.png)

------------

## ハンズオン
### 構築の流れ
#### 1.SNS作成
#### 2.AWS Config作成
#### 3.EventBridge作成
#### 上記の順番で構築を行なっていきます。
最終的には、CFnのスタックにタグが付与されていないことをConfigのルールで検知して、その検知したことをEventBridge経由でSNSを利用してメールを送信します。
![](https://cloud5.jp/wp-content/uploads/2022/12/スクリーンショット-2022-12-24-11.00.23-640x111.png)

-----------

### 1.SNS作成
##### 1.1 SNSを構築する
Configで非準拠判定された場合に通知する、SNSトピックを構築します。
`TopicPolicy`部分は、検証のため制限していません。
構築後サブスクリプション

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: SNS Create

# ------------------------------------------------------------#
#  Metadata
# ------------------------------------------------------------#
Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "SNS Configuration"
        Parameters:
        - TopicName
        - Endpoint
    
    ParameterLabels:
      TopicName:
        default: "TopicName"
      Endpoint:
        default: "MailAddress"

# ------------------------------------------------------------#
#  InputParameters
# ------------------------------------------------------------#
Parameters:
  TopicName:
    Type: String
    Default: "cfn-sns-topic-inamura"
  Endpoint:
    Type: String
    Default: "XXXXXXXXXX@gmail.com"
  TagsValueUserName:
    Type: String
    Default: "inamura"

# ------------------------------------------------------------#
#  Resources
# ------------------------------------------------------------#
Resources:
  SNSTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: !Ref TopicName
      Subscription:
        - Endpoint: !Ref Endpoint
          Protocol: email
      Tags:
        - Key: "User"
          Value: !Ref TagsValueUserName    

  TopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties:
      Topics:
        - !Ref SNSTopic
      PolicyDocument:
        Id: !Ref SNSTopic
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              AWS: "*"
            Action: SNS:Publish
            Resource: !Ref SNSTopic

# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#                
Outputs:
  SNSArn:
    Value: !Ref SNSTopic
    Export:
      Name: !Sub "${TopicName}-arn"
  SNSTopicName:
    Value: !Ref TopicName
    Export:
      Name: !Ref TopicName
```

#### 1.2 上記設定後に、SNSから送られてきたメールのサブスクリプションを押下する
①送られてきたメールの赤枠部分をクリックする
![](https://cloud5.jp/wp-content/uploads/2022/11/スクリーンショット-2022-11-26-14.13.42-640x157.png)

②画面が遷移して下記画面が表示されると、サブスクリプションが開始される
![](https://cloud5.jp/wp-content/uploads/2022/11/スクリーンショット-2022-11-26-14.15.17.png)
※上記青枠部分をクリックすると、サブスクリプションが解除される


### 2.AWS Config作成
運用している状況によりますが、今回は`tag1Key`で付与しなければいけないタグのみを設定します（この`tag1Key`が付与されていないと非準拠判定される）
適応可能なAWSリソースの詳細は、[AWS Configデベロッパーガイド > required-tags
 ](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/required-tags.html)に記載されていますが、今回はその中のCFnのスタックにタグが付与されていない場合のみ反応するよう、不要リソース部分はコメントアウトしています。

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Description:
  Config Rule required-tags check
# ------------------------------------------------------------#
#  Metadata
# ------------------------------------------------------------#
Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "AWS Config Configuration"
        Parameters:
          - ConfigRuleName
          - tag1Key
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  ConfigRuleName:
    Description: "config rule(required-tags) name"
    Type: String
    Default: cfn-con-requiredtags-inamura
  tag1Key:
    Description: "Key of the required tag."
    Type: String
    Default: User

# ------------------------------------------------------------#
#  Resource
# ------------------------------------------------------------#
Resources:
  ConfigRule:
    Type: AWS::Config::ConfigRule
    Properties: 
      ConfigRuleName: !Ref ConfigRuleName
      Description: "リソースに、指定するタグがリソースにあるかどうかを確認します。例えば、'Name'タグが EC2 インスタンスに存在するかどうかを確認できます。複数の値はカンマで区切ります。"
      Source: 
        Owner: AWS
        SourceIdentifier: REQUIRED_TAGS
      InputParameters: 
        tag1Key: !Ref tag1Key
      Scope:
        ComplianceResourceTypes: 
          # - "AWS::ACM::Certificate"
          # - "AWS::AutoScaling::AutoScalingGroup"
          - "AWS::CloudFormation::Stack"
          # - "AWS::CodeBuild::Project"
          # - "AWS::DynamoDB::Table"
          # - "AWS::EC2::CustomerGateway"
          # - "AWS::EC2::Instance"
          # - "AWS::EC2::InternetGateway"
          # - "AWS::EC2::NetworkAcl"
          # - "AWS::EC2::NetworkInterface"
          # - "AWS::EC2::RouteTable"
          # - "AWS::EC2::SecurityGroup"
          # - "AWS::EC2::Subnet"
          # - "AWS::EC2::Volume"
          # - "AWS::EC2::VPC"
          # - "AWS::EC2::VPNConnection"
          # - "AWS::EC2::VPNGateway"
          # - "AWS::ElasticLoadBalancing::LoadBalancer"
          # - "AWS::ElasticLoadBalancingV2::LoadBalancer"
          # - "AWS::RDS::DBInstance"
          # - "AWS::RDS::DBSecurityGroup"
          # - "AWS::RDS::DBSnapshot"
          # - "AWS::RDS::DBSubnetGroup"
          # - "AWS::RDS::EventSubscription"
          # - "AWS::Redshift::Cluster"
          # - "AWS::Redshift::ClusterParameterGroup"
          # - "AWS::Redshift::ClusterSecurityGroup"
          # - "AWS::Redshift::ClusterSnapshot"
          # - "AWS::Redshift::ClusterSubnetGroup"
          # - "AWS::S3::Bucket"
```

### 3.EventBridge作成
デフォルトのメッセージが送られてくるのも味気ないので`InputTransformer`部分を記述することで、いつ発生したのか？や、Config画面へアクセスして詳細がわかるようなURLなどが、SNSの内容に盛り込まれるようにしています。

EventBridgeに対してのタグは[ユーザーガイド AWS::Events::Rule Tag]より出来ないようです。(https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-tag.html)
![](https://cloud5.jp/wp-content/uploads/2022/12/スクリーンショット-2022-12-24-14.23.22-640x57.png)

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description:
  Using Config Tag Rules,use by EventBridge and email by SNS
# ------------------------------------------------------------#
#  Metadata
# ------------------------------------------------------------#
Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "Eventbridge Configuration"
        Parameters:
          - Name
          - EventBusName
          - State
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  EventBusName:
    Type: String
    Default: "default"
  Name:
    Type: String
    Default: "cfn-evb-tagrule-inamura"
  State:
    Type: String
    Default: "ENABLED"

# ------------------------------------------------------------#
#  EventBridge
# ------------------------------------------------------------#
Resources:
  EventsRule:
    Type: AWS::Events::Rule
    Properties:
      Description: "Using Config Tag Rules,use by EventBridge and email by SNS"
      EventBusName: !Ref EventBusName
      Name: !Ref Name
      State: !Ref State
      EventPattern:
        source: 
          - aws.config
        detail-type:
          - Config Rules Compliance Change
        detail:
          messageType:
            - ComplianceChangeNotification
          configRuleName:
            - cfn-con-requiredtags-inamura
          newEvaluationResult:
            complianceType: 
              - NON_COMPLIANT

      Targets:
        - Arn: !ImportValue cfn-sns-topic-inamura-arn
          Id: "cfn-sns-topic-transfer"
          InputTransformer:
            InputPathsMap:
              "awsRegion": "$.detail.awsRegion"
              "resourceType": "$.detail.resourceType"
              "resourceId": "$.detail.resourceId"
              "time": "$.detail.newEvaluationResult.resultRecordedTime"
              "compliance": "$.detail.newEvaluationResult.complianceType"
              "rule": "$.detail.configRuleName"
            InputTemplate: |
              "Userタグのないリソースが作成されました!"
              "発生時間       : <time>"
              "ルール名       : <rule>"
              "リソースタイプ : <resourceType>"
              "リソースID     : <resourceId>"

              "上記リソースが <compliance> 判定となりました。"
              "詳細は以下URLよりご確認ください。"
              "https://<awsRegion>.console.aws.amazon.com/config/home?region=<awsRegion>#/resources/details?resourceId=<resourceId>&resourceType=<resourceType>"

```

### 挙動の確認
#### ①CFnで`タグ`をつけず構築する
![](https://cloud5.jp/wp-content/uploads/2022/12/スクリーンショット-2022-12-24-11.35.49-640x220.png)
#### ②SNSでメールが受信できる
デフォルトの通知よりは見やすくて、詳細にアクセスできるのも助かるかと思います。
![](https://cloud5.jp/wp-content/uploads/2022/12/スクリーンショット-2022-12-24-11.43.28-640x248.png)

------------

## さいごに
`タグなしポイ捨てリソース、ダメ絶対`とはいえConfigでは、対象にできるAWSリソースが少ないのも現実なので、もっと改善していかなければいけないなと。
とはいえ、まずは小さいことから少しずつ始めて、年末のリソース大掃除をしていきたいと思います。