「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート - ⑦デフォルトセキュリティグループを無効化する

# はじめに

AWSにはアカウントやリソースへの脅威検知に対応した、**AWS IAM Access Analyzer**, **AWS Security Hub**, **Amazon Detective**, **Amazon Inspector**, **Amazon GuardDuty**, **AWS CloudTrail**, **AWS Config** などのサービスが用意されています。

また、**AWS Security Hub** では、[**CIS AWS Foundations Standard**](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-cis.html) , [**Payment Card Industry Data Security Standard**](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-pcidss.html) , [**AWS Foundational Security Best Practices Standard**](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp.html) などのセキュリティ標準が公開されており、このガイドラインは、**AWSアカウントをセキュアに保つために必要なAWSのセキュリティ設定**を集めた**ベストプラクティス集**として活用できます。

本記事では、アカウントやリソースへの**脅威検知が可能なAWSサービスを有効化**するとともに、上記のセキュリティ標準に限りなく準拠することで、セキュアで堅牢なAWSアカウントを実現します。また、これらを**お手軽に実現できるCloudFormationテンプレートを公開**しています。

+ [**aws-cloudformation-templates/security - GitHub**](https://github.com/eijikominami/aws-cloudformation-templates/blob/master/security/)

このCloudFormationテンプレートの実行はこちらから。

[![cloudformation-launch-stack](https://raw.githubusercontent.com/eijikominami/aws-cloudformation-templates/master/images/cloudformation-launch-stack.png)](https://console.aws.amazon.com/cloudformation/home?region=ap-northeast-1#/stacks/create/review?stackName=DefaultSecuritySettings&templateURL=https://eijikominami.s3-ap-northeast-1.amazonaws.com/aws-cloudformation-templates/security/template.yaml) 

![](https://raw.githubusercontent.com/eijikominami/aws-cloudformation-templates/master/images/architecture-default-security-settings.png)

# デフォルトセキュリティグループを制限する

インスタンスの **仮想ファイアウォール** として機能する VPC の **セキュリティグループ** には、 [**デフォルトセキュリティグループ**](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_SecurityGroups.html#DefaultSecurityGroup) と呼ばれる **特殊なセキュリティグループ** が存在します。このデフォルトセキュリティグループは、 **AWSアカウント作成時から存在**し、明示的にセキュリティグループを指定せずにインスタンスを作成した場合は、この **デフォルトセキュリティグループが自動的にインスタンスに関連付け** られます。

``CIS AWS Foundations Standard``, ``Payment Card Industry Data Security Standard`` , ``AWS Foundational Security Best Practices Standard`` の各セキュリティ標準では、 **セキュリティグループに意図した設定を適用するために、デフォルトセキュリティグループの無効化** とデフォルトセキュリティグループ以外のセキュリティグループの利用を奨励しており、 **デフォルトセキュリティグループのインバウンドルールおよびアウトバウンドルールの全てを削除** することが求められています。

| セキュリティ標準 | No. | 内容 |
| --- | --- | --- |
| CIS AWS Foundations Standard | 4.3 | **すべての VPC のデフォルトセキュリティグループがすべてのトラフィックを制限するようにします** |
| Payment Card Industry Data Security Standard | PCI.EC2.2 | **VPC のデフォルトのセキュリティグループでは、インバウンドトラフィックとアウトバウンドトラフィックが禁止されます** |
| AWS Foundational Security Best Practices Standard | EC2.2 | **VPC のデフォルトのセキュリティグループでは、インバウンドトラフィックとアウトバウンドトラフィックが禁止されます** |

この規定に準拠するために、このCloudFormationテンプレートでは、以下の設定を行います。

1. **セキュリティグループ** が上記のポリシーに準拠しているか **チェック** を行う
2. 非準拠であった場合には、`AWS Config` が `SSM Automation` を自動起動する
3. `SSM Automation` を用いて **インバウンドルールおよびアウトバウンドルールを削除** する

それぞれの設定について、順を追って説明します。

## 1. AWS Configの有効化

`AWS Config` を有効化する手順については、[過去の記事](https://qiita.com/eijikominami/items/53f3a1d83df31981ad86#aws-config) をご覧ください。

### サービスにリンクされたロールの作成

``AWS Config`` で使用する ``Service-Linked Role`` を作成します。この ``Service-Linked Role`` は、 **AWSリソースへの読み込み権限** と **S3への書き込み権限** を ``Config`` に、また、**IAMとSystemManagerへの書き込み権限** を ``Config Remediation`` にそれぞれ付与します。

```yaml
Resources:
  ServiceLinkedRoleForConfig:
    Type: AWS::IAM::ServiceLinkedRole
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
    Properties: 
      AWSServiceName: config.amazonaws.com
      Description: A service-linked role required for AWS Config to access your resources.
  ServiceLinkedRoleForConfigRemediation:
    Type: AWS::IAM::ServiceLinkedRole
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
    Properties: 
      AWSServiceName: remediation.config.amazonaws.com 
      Description: A service-linked role required for AWS Config Remediation to access your resources.
```

### AWS Configの有効化

``AWS Config`` の ``DeliveryChannel`` と ``ConfigurationRecorder`` を作成します。

```yaml
Resources:
  ConfigDeliveryChannel:
    Type: AWS::Config::DeliveryChannel
    Properties:
      Name: default
      S3BucketName: !Ref S3ForConfig
  ConfigConfigurationRecorder:
    Type: AWS::Config::ConfigurationRecorder
    Properties:
      Name: default
      RecordingGroup:
        AllSupported: true
        IncludeGlobalResourceTypes: true
      RoleARN: !Sub arn:aws:iam::DefaultSecuritySettings:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
```

### Amazon S3 バケットを作成

**設定情報 （履歴ファイルやスナップショット）** を保存するために使用する、``Amazon S3`` **バケット**と、それに紐づく**バケットポリシー**を作成します。

```yaml
Resources:
  S3ForConfig:
    Type: 'AWS::S3::Bucket'
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration: 
          - ServerSideEncryptionByDefault: 
              SSEAlgorithm: AES256
      BucketName: !Sub defaultsecuritysettings-config-${AWS::Region}-${AWS::AccountId}
      LifecycleConfiguration:
        Rules:
          - Id: ExpirationInDays
            ExpirationInDays: 60
            Status: Enabled
      PublicAccessBlockConfiguration: 
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
  S3BucketPolicyForConfig:
    Type: AWS::S3::BucketPolicy
    Properties: 
      Bucket: !Ref S3ForConfig
      PolicyDocument:
        Version: 2012-10-17
        Id: !Ref S3ForConfig
        Statement:
          - Effect: Allow
            Principal:
              Service: config.amazonaws.com
            Action:
              - 's3:GetBucketAcl'
              - 's3:ListBucket'
            Resource:
              - !GetAtt S3ForConfig.Arn
          - Effect: Allow
            Principal:
              Service: config.amazonaws.com
            Action:
              - 's3:PutObject'
            Resource:
              - !Join
                - ''
                - - !GetAtt S3ForConfig.Arn
                  - /AWSLogs/
                  - !Sub ${AWS::AccountId}
                  - /Config/*
            Condition:
              StringEquals:
                s3:x-amz-acl: bucket-owner-full-control
          - Effect: Deny
            Principal: '*'
            Action: 's3:*'
            Resource: 
              - !GetAtt S3ForConfig.Arn
              - !Join
                - ''
                - - !GetAtt S3ForConfig.Arn
                  - /*
            Condition:
              Bool: 
                aws:SecureTransport: false
```

## 2. AWS Configを用いたチェック

インバウンドルールおよびアウトバウンドルールが存在するかどうかの確認には、あらかじめ `AWS Config` に用意されている `VPC_DEFAULT_SECURITY_GROUP_CLOSED` マネージドルールを使用します。これは、**VPCのデフォルトのセキュリティグループでもインバウンドとアウトバウンドのいずれのトラフィックも許可しないことを確認するルール** です。

なお、この `Config Rule` を設定する前に `ConfigurationRecorder` を生成しておく必要があります。そこで、`DependsOn` 属性に `ConfigurationRecorder` リソースを設定しています。

```yaml
Resources:
  ConfigVpcDefaultSecurityGroupClosed:
    DependsOn:
      - ConfigConfigurationRecorder
    Type: 'AWS::Config::ConfigRule'
    Properties:
      ConfigRuleName: vpc-default-security-group-closed
      Description: いずれの Amazon Virtual Private Cloud (VPC) のデフォルトのセキュリティグループでもインバウンドとアウトバウンドのいずれのトラフィックも許可しないことを確認します。
      Source:
        Owner: AWS
        SourceIdentifier: VPC_DEFAULT_SECURITY_GROUP_CLOSED 
```

## 3. SSM Automation を用いた自動修復

``Systems Manager Automation`` は、``AWS Config`` で **直接指定できる、現時点で唯一の自動修復手段** となっています。そこで、インバウンドルールおよびアウトバウンドルールを削除する ``Systems Manager Automation`` **ドキュメント** を作成し、``AWS Config`` との紐付けを行います。

下の``Systems Manager Automation`` ドキュメントは、``EC2`` の ``RevokeSecurityGroupIngress`` および ``RevokeSecurityGroupEgress`` を実行して、デフォルトセキュリティグループのインバウンドルールおよびアウトバウンドルールを削除します。

```yaml
Resources:
  SSMAutomationRevokeDefaultSecurityGroup:
    Type: 'AWS::SSM::Document'
    Properties: 
      Content:
        schemaVersion: "0.3"
        assumeRole: "{{ AutomationAssumeRole }}"
        description: Revoke Default Security Group.
        mainSteps:
          - name: DescribeSecurityGroups
            action: aws:executeAwsApi
            onFailure: Abort
            inputs:
              Service: ec2
              Api: DescribeSecurityGroups
              GroupIds: ["{{ GroupId }}"]
            outputs:
              - Name: IpPermissionsIngress
                Selector: $.SecurityGroups[0].IpPermissions
                Type: MapList
              - Name: IpPermissionsEgress
                Selector: $.SecurityGroups[0].IpPermissionsEgress
                Type: MapList
          - name: RevokeSecurityGroupIngress
            action: aws:executeAwsApi
            onFailure: Continue
            inputs:
              Service: ec2
              Api: RevokeSecurityGroupIngress
              GroupId: "{{ GroupId }}"
              IpPermissions: "{{ DescribeSecurityGroups.IpPermissionsIngress }}"
          - name: RevokeSecurityGroupEgress
            action: aws:executeAwsApi
            onFailure: Continue
            inputs:
              Service: ec2
              Api: RevokeSecurityGroupEgress
              GroupId: "{{ GroupId }}"
              IpPermissions: "{{ DescribeSecurityGroups.IpPermissionsEgress }}"
        parameters:
          AutomationAssumeRole:
            type: String
            description: Automation Assume Role Arn
          GroupId:
            type: String
            description: Group Id
      DocumentType: Automation
```

## 4. AWS Config と SSM Automation の紐付け

``Systems Manager Automation`` ドキュメントは、上述の通り ``EC2`` の ``RevokeSecurityGroupIngress`` および ``RevokeSecurityGroupEgress`` （および ``DescribeSecurityGroups``）を実行する必要があるため、このAWS API アクションを ``Systems Manager Automation`` から呼び出すことを可能とする **IAM Role** を作成します。

```yaml
Resources:
  IAMRoleForSSM:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ssm.amazonaws.com
            Action: 'sts:AssumeRole'
      Description: A role required for SSM to access IAM.
      Policies:
        - PolicyName: !Sub 'DefaultSecuritySettings-AWSSystemManagerIAMRole-${AWS::Region}'
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'ec2:RevokeSecurityGroupIngress'
                  - 'ec2:RevokeSecurityGroupEgress'
                  - 'ec2:DescribeSecurityGroups'
                Resource:
                  - '*'
      RoleName: !Sub 'DefaultSecuritySettings-SSM-${AWS::Region}'
```

このIAM RoleのARNは、``AWS Config`` から ``Systems Manager Automation`` へ渡されるパラメータの1つとして規定されます。 ``AWS::Config::RemediationConfiguration`` は、**非準拠（NON_COMPLIANT）と判定された場合の自動修復方法を規定**し、``Config Rule`` と ``Systems Manager Automation`` との紐付けや、受け渡されるパラメータの規定を行います。自動修復を行う場合は、**AutomationAssumeRole, MaximumAutomaticAttempts, RetryAttemptSeconds** の各パラメータの入力が必須です。

```yaml
Resources:
  ConfigVpcDefaultSecurityGroupClosedRemediationConfiguration:
    Type: 'AWS::Config::RemediationConfiguration'
    Properties:
      Automatic: true
      ConfigRuleName: !Ref ConfigVpcDefaultSecurityGroupClosed
      MaximumAutomaticAttempts: 1
      Parameters:
        AutomationAssumeRole:
          StaticValue:
            Values:
              - !GetAtt IAMRoleForSSM.Arn
        GroupId:
          ResourceValue:
            Value: RESOURCE_ID
      RetryAttemptSeconds: 30
      TargetId: !Ref SSMAutomationRevokeDefaultSecurityGroup
      TargetType: SSM_DOCUMENT
```

以上で、デフォルトセキュリティグループのインバウンドルールおよびアウトバウンドルールの全てを削除することができました。

# 関連リンク
1. [**サービスの有効化** - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート](https://qiita.com/eijikominami/items/53f3a1d83df31981ad86)
2. [**パスワードポリシーの自動修復** - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート](https://qiita.com/eijikominami/items/85acced082d0dc8d9901)
3. [**モニタリングと通知の設定** - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート](https://qiita.com/eijikominami/items/1887d19ce3bb33f716ba)
4. [**アクセスキーのローテーションと削除** - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート](https://qiita.com/eijikominami/items/eba16015e8e27e42fc36)
5. [**全てのVPCでフローログを有効化する** - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート](https://qiita.com/eijikominami/items/e5f7fcc7fd91fc4355be)
6. [**SSHとRDPのアクセスを制限する** - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート](https://qiita.com/eijikominami/items/936912ee715079606e55)
7. **デフォルトセキュリティグループを無効化する** - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート
8. [**S3バケットのサーバサイド暗号化** - セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート](https://qiita.com/eijikominami/items/581a8e0e424117322125)