AWS CloudTrail(2)CIS AWS Foundations Benchmarkに準拠するための通知設定

IAMパスワードポリシーの自動修復

CIS AWS Foundations Benchmark というセキュリティガイドラインが公開されており、このガイドラインは、AWSアカウントをセキュアに保つために必要なAWSのセキュリティ設定を集めたベストプラクティス集として活用できる。

この CIS AWS Foundations Benchmarkでは、CloudTrailによって検知された特定のイベントに対して以下のような対応を求めている。

  • 3.1 不正な API 呼び出しに対してログメトリクスフィルタとアラームが存在することを確認します
  • 3.2 MFA なしの AWS マネジメントコンソール サインインに対してログメトリクスフィルタとアラームが存在することを確認します
  • 3.3 「ルート」アカウントに対してログメトリクスフィルタとアラームが存在することを確認します
  • 3.4 MFA なしの IAM ポリシーの変更に対してログメトリクスフィルタとアラームが存在することを確認します
  • 3.5 MFA なしの CloudTrail 設定の変更に対してログメトリクスフィルタとアラームが存在することを確認します
  • 3.6 AWS マネジメントコンソール 認証の失敗に対してログメトリクスフィルタとアラームが存在することを確認します
  • 3.7 カスタマー作成の CMK の無効化またはスケジュールされた削除に対してログメトリクスフィルタとアラームが存在することを確認します
  • 3.8 S3 バケットの変更に対してログメトリクスフィルタとアラームが存在することを確認します
  • 3.9 AWS Config 設定の変更に対してログメトリクスフィルタとアラームが存在することを確認します
  • 3.10 セキュリティグループの変更に対するメトリクスフィルタとアラームが存在することを確認します
  • 3.11 ネットワークアクセスコントロールリスト (NACL) への変更に対するログメトリクスとアラームが存在することを確認します
  • 3.12 ネットワークゲートウェイへの変更に対するログメトリクスとアラームが存在することを確認します
  • 3.13 ルートテーブルの変更に対してログメトリクスフィルタとアラームが存在することを確認します
  • 3.14 VPC の変更に対してログメトリクスフィルタとアラームが存在することを確認します

上述のログメトリクスフィルタとアラームを設定し、CIS AWS Foundations Benchmark準拠するために以下の設定を行う。

  1. CloudWatch Logs の MetricFilter を作成する
  2. 上のメトリクスに対する CloudWatch Alarm を作成する
  3. 閾値を超えた場合にAmazon SNSに通知を送る
Resources:
  # CIS 3.1 a log metric filter and alarm exist for unauthorized API calls 
  CloudWatchLogsMetricFilterCloudTrailUnauthorizedAPICalls:
    Type: 'AWS::Logs::MetricFilter'
    Properties:
      FilterPattern: '{($.errorCode="*UnauthorizedOperation") || ($.errorCode="AccessDenied*")}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: UnauthorizedAPICalls 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailUnauthorizedAPICalls:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *不正なAPIコールを検知* しました。'
      AlarmName: !Sub 'Warning-${AWS::StackName}-CloudTrail-Unauthorized-API-Calls'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      DatapointsToAlarm: 6
      EvaluationPeriods: 60
      MetricName: UnauthorizedAPICalls
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.2 a log metric filter and alarm exist for AWS Management Console sign-in without MFA
  CloudWatchLogsMetricFilterCloudTrailLoginWithoutMFA:
    Type: 'AWS::Logs::MetricFilter'
    Properties:
      FilterPattern: '{($.eventName="ConsoleLogin") && ($.additionalEventData.MFAUsed !="Yes")}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: LoginWithoutMFA 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailLoginWithoutMFA:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *MFAなしのログインを検知* しました。'
      AlarmName: !Sub 'Warning-${AWS::StackName}-CloudTrail-Login-Without-MFA'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: LoginWithoutMFA
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.3 a log metric filter and alarm exist for usage of "root" account 
  CloudWatchLogsMetricFilterCloudTrailForRootAcount:
    Type: 'AWS::Logs::MetricFilter'
    Properties:
      FilterPattern: '{$.userIdentity.type="Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType !="AwsServiceEvent"}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: ForRootAcount 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailForRootAcount:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *ルートアカウントに対する変更を検知* しました。'
      AlarmName: !Sub 'Warning-${AWS::StackName}-CloudTrail-For-RootAcount'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: ForRootAcount
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.4 a log metric filter and alarm exist for IAM policy changes 
  CloudWatchLogsMetricFilterCloudTrailIamPolicyChanges:
    Type: 'AWS::Logs::MetricFilter'
    Properties:
      FilterPattern: '{($.eventName=DeleteGroupPolicy) || ($.eventName=DeleteRolePolicy) || ($.eventName=DeleteUserPolicy) || ($.eventName=PutGroupPolicy) || ($.eventName=PutRolePolicy) || ($.eventName=PutUserPolicy) || ($.eventName=CreatePolicy) || ($.eventName=DeletePolicy) || ($.eventName=CreatePolicyVersion) || ($.eventName=DeletePolicyVersion) || ($.eventName=AttachRolePolicy) || ($.eventName=DetachRolePolicy) || ($.eventName=AttachUserPolicy) || ($.eventName=DetachUserPolicy) || ($.eventName=AttachGroupPolicy) || ($.eventName=DetachGroupPolicy)}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: IamPolicyChanges 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailIamPolicyChanges:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *IAMポリシーの変更を検知* しました。'
      AlarmName: !Sub 'Warning-${AWS::StackName}-CloudTrail-IamPolicy-Changes'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: IamPolicyChanges
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.5 a log metric filter and alarm exist for CloudTrail configuration changes 
  CloudWatchLogsMetricFilterCloudTrailCloudTrailConfigurationChanges:
    Type: 'AWS::Logs::MetricFilter'
    Properties:
      FilterPattern: '{($.eventName=CreateTrail) || ($.eventName=UpdateTrail) || ($.eventName=DeleteTrail) || ($.eventName=StartLogging) || ($.eventName=StopLogging)}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: CloudTrailConfigurationChanges 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailCloudTrailConfigurationChanges:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *CloudTrailの設定変更を検知* しました。'
      AlarmName: !Sub 'Warning-${AWS::StackName}-CloudTrail-CloudTrailConfiguration-Changes'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: CloudTrailConfigurationChanges
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.6 a log metric filter and alarm exist for AWS Management Console authentication failures
  CloudWatchLogsMetricFilterCloudTrailAuthenticationFailuresDetected:
    Type: 'AWS::Logs::MetricFilter'
    Properties:
      FilterPattern: '{($.eventName=ConsoleLogin) && ($.errorMessage="Failed authentication")}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: AuthenticationFailuresDetected 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailAuthenticationFailuresDetected:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *ログイン認証失敗を検知* しました。'
      AlarmName: !Sub 'Warning-${AWS::StackName}-CloudTrail-AuthenticationFailures-Detected'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: AuthenticationFailuresDetected
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.7 a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs 
  CloudWatchLogsMetricFilterCloudTrailCustomerCreatedCMKsChanges:
    Type: 'AWS::Logs::MetricFilter'
    Properties:
      FilterPattern: '{($.eventSource=kms.amazonaws.com) && (($.eventName=DisableKey) || ($.eventName=ScheduleKeyDeletion))}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: CustomerCreatedCMKsChanges 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailCustomerCreatedCMKsChanges:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *カスタマー作成CMKの無効化もしくは削除を検知* しました。'
      AlarmName: !Sub 'Warning-${AWS::StackName}-CloudTrail-CustomerCreatedCMKs-Changes'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: CustomerCreatedCMKsChanges
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.8 a log metric filter and alarm exist for S3 bucket policy changes 
  CloudWatchLogsMetricFilterCloudTrailS3BucketPolicyChanges:
    Type: 'AWS::Logs::MetricFilter'
    Properties:
      FilterPattern: '{($.eventSource=s3.amazonaws.com) && (($.eventName=PutBucketAcl) || ($.eventName=PutBucketPolicy) || ($.eventName=PutBucketCors) || ($.eventName=PutBucketLifecycle) || ($.eventName=PutBucketReplication) || ($.eventName=DeleteBucketPolicy) || ($.eventName=DeleteBucketCors) || ($.eventName=DeleteBucketLifecycle) || ($.eventName=DeleteBucketReplication))}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: S3BucketPolicyChanges 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailS3BucketPolicyChanges:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *S3のバケットポリシーの変更を検知* しました。'
      AlarmName: !Sub 'Notice-${AWS::StackName}-CloudTrail-S3BucketPolicy-Changes'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: S3BucketPolicyChanges
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.9 a log metric filter and alarm exist for AWS Config configuration changes 
  CloudWatchLogsMetricFilterCloudTrailConfigConfigurationChanges:
    Type: 'AWS::Logs::MetricFilter'
    Properties: 
      FilterPattern: '{($.eventSource=config.amazonaws.com) && (($.eventName=StopConfigurationRecorder) || ($.eventName=DeleteDeliveryChannel) || ($.eventName=PutDeliveryChannel) || ($.eventName=PutConfigurationRecorder))}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: ConfigConfigurationChanges 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailConfigConfigurationChanges:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *Configの設定変更を検知* しました。'
      AlarmName: !Sub 'Warning-${AWS::StackName}-CloudTrail-ConfigConfiguration-Changes'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: ConfigConfigurationChanges
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.10 a log metric filter and alarm exist for changes to Security Group 
  CloudWatchLogsMetricFilterCloudTrailSecurityGroupChanges:
    Type: 'AWS::Logs::MetricFilter'
    Properties: 
      FilterPattern: '{($.eventName=AuthorizeSecurityGroupIngress) || ($.eventName=AuthorizeSecurityGroupEgress) || ($.eventName=RevokeSecurityGroupIngress) || ($.eventName=RevokeSecurityGroupEgress) || ($.eventName=CreateSecurityGroup) || ($.eventName=DeleteSecurityGroup)}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: SecurityGroupChanges 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailSecurityGroupChanges:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *セキュリティグループの変更を検知* しました。'
      AlarmName: !Sub 'Warning-${AWS::StackName}-CloudTrail-SecurityGroup-Changes'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: SecurityGroupChanges
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.11 a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) 
  CloudWatchLogsMetricFilterCloudTrailNACLChanges:
    Type: 'AWS::Logs::MetricFilter'
    Properties: 
      FilterPattern: '{($.eventName=CreateNetworkAcl) || ($.eventName=CreateNetworkAclEntry) || ($.eventName=DeleteNetworkAcl) || ($.eventName=DeleteNetworkAclEntry) || ($.eventName=ReplaceNetworkAclEntry) || ($.eventName=ReplaceNetworkAclAssociation)}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: NACLChanges 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailNACLChanges:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *NACLの変更を検知* しました。'
      AlarmName: !Sub 'Notice-${AWS::StackName}-CloudTrail-NACL-Changes'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: NACLChanges
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.12 a log metric filter and alarm exist for changes to network gateways
  CloudWatchLogsMetricFilterCloudTrailNetworkGatewayChanges:
    Type: 'AWS::Logs::MetricFilter'
    Properties: 
      FilterPattern: '{($.eventName=CreateCustomerGateway) || ($.eventName=DeleteCustomerGateway) || ($.eventName=AttachInternetGateway) || ($.eventName=CreateInternetGateway) || ($.eventName=DeleteInternetGateway) || ($.eventName=DetachInternetGateway)}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: NetworkGatewayChanges 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailNetworkGatewayChanges:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *ネットワークゲートウェイの変更を検知* しました。'
      AlarmName: !Sub 'Notice-${AWS::StackName}-CloudTrail-NetworkGateway-Changes'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: NetworkGatewayChanges
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.13 a log metric filter and alarm exist for route table changes
  CloudWatchLogsMetricFilterCloudTrailRouteTableChanges:
    Type: 'AWS::Logs::MetricFilter'
    Properties: 
      FilterPattern: '{($.eventName=CreateRoute) || ($.eventName=CreateRouteTable) || ($.eventName=ReplaceRoute) || ($.eventName=ReplaceRouteTableAssociation) || ($.eventName=DeleteRouteTable) || ($.eventName=DeleteRoute) || ($.eventName=DisassociateRouteTable)}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: RouteTableChanges 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailRouteTableChanges:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *ルートテーブルの変更を検知* しました。'
      AlarmName: !Sub 'Notice-${AWS::StackName}-CloudTrail-RouteTable-Changes'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: RouteTableChanges
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching
  # CIS 3.14 a log metric filter and alarm exist for VPC changes 
  CloudWatchLogsMetricFilterCloudTrailVpcChanges:
    Type: 'AWS::Logs::MetricFilter'
    Properties: 
      FilterPattern: '{($.eventName=CreateVpc) || ($.eventName=DeleteVpc) || ($.eventName=ModifyVpcAttribute) || ($.eventName=AcceptVpcPeeringConnection) || ($.eventName=CreateVpcPeeringConnection) || ($.eventName=DeleteVpcPeeringConnection) || ($.eventName=RejectVpcPeeringConnection) || ($.eventName=AttachClassicLinkVpc) || ($.eventName=DetachClassicLinkVpc) || ($.eventName=DisableVpcClassicLink) || ($.eventName=EnableVpcClassicLink)}'
      LogGroupName: !Ref CloudWatchLogsGroupForCloudTrail
      MetricTransformations:
        - MetricName: VpcChanges 
          MetricNamespace: LogMetrics
          MetricValue: '1'
  CloudWatchAlarmMetricFilterCloudTrailVpcChanges:
    Type: 'AWS::CloudWatch::Alarm'
    Properties:
      ActionsEnabled: true
      AlarmActions:
        - !Ref SnsTopicARN
      AlarmDescription: '*CloudTrail* が *VPCの変更を検知* しました。'
      AlarmName: !Sub 'Notice-${AWS::StackName}-CloudTrail-Vpc-Changes'
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      MetricName: VpcChanges
      Namespace: LogMetrics
      OKActions:
        - !Ref SnsTopicARN
      Period: 60
      Statistic: Maximum
      Threshold: 1
      TreatMissingData: notBreaching

また、これらのメトリクスのアラーム通知先となる、Amazon SNSTopic Policy を作成する。

Resources:
  SNSAlert:
    Type: 'AWS::SNS::Topic'
    Properties:
      DisplayName: !Sub 'System Notifications from ${AWS::StackName}'
      TopicName: !Sub '${AWS::StackName}-system-notifications'
  SNSAlertTopicPolicy:
    Type: 'AWS::SNS::TopicPolicy'
    Properties:
      Topics: 
        - !Ref SNSAlert
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            # All AWS Services
            Principal:
              AWS: '*'
            Resource: '*'
            Action: 'SNS:Publish'

AWS CloudTrail(1)CloudTrailの概要

CloudTrailとは

CloudTrailは、AWS アカウントの ガバナンスコンプライアンス運用監査リスク監査を行うためのサービス。AWSマネージメントコンソールやAWS CLI、SDK、APIで実行されたアクションを、ログに記録する。API アクティビティに特化した機能であり、パフォーマンスのモニタリングとシステムの正常性をモニタリングできるCloudWatchとは用途が異なる。

CloudTrailは、AWSアカウントを作成した際に自動的に有効になる。イベントとして記録された証跡と呼ばれるこれらのデータは、過去90日分を表示、検索、ダウンロード、アーカイブ、分析等を行うことができる。

証跡はサーバサイド暗号化を使用してS3バケットへ配信、およびAmazon CloudWatch Logs 、Amazon CloudWatch Eventsなどを用いて配信や分析を行うことができる。ログは、 1時間に複数回、約5分ごとに発行され、イベント発生から15分以内に配信される。CloudTrailには、設定変更などを含む管理イベントと情報の取得などを含むデータイベントの2つの種類のイベントが保存できるが、標準では管理イベントのみが保存される。設定により、S3およびLambdaのデータイベントを証跡に含ませることができる。なお、CloudTrailは全てのリージョンに適用可能であるが、イベントをログに記録するリージョンのみで表示することができる

セキュリティ

以下の手段を用いることで、CloudTrailが生成した証跡を適切に保全し、インシデント発生時のフォレンジックを正常に遂行することができる。

データ保護

  • 診断ログに機密情報が残ることを避けるため、名前フィールドなどに機密情報を載せることはしない

検出

  • 全てのリージョンで証跡を有効化する
  • 証跡を保存するS3バケットは、サーバサード暗号化を行う
  • CloudWatch Logsとの統合を行い、イベントの監視を行う

予防

  • 証跡を保存するS3バケットは、専用のAWSアカウントに保存する
  • 証跡を保存するS3バケットには、最低限のアクセス権限のみ付与する。
  • 証跡を保存するS3バケットに対して、MFA Deleteを有効化する

AWS CloudTrail のセットアップ

CloudRrailはCloudFormationに対応しているため、CloudFormation経由でGuardDutyをセットアップすることができる。

IAM Roleの有効化

CloudTrailにCloudWatch Logsへのアクセス権限を付与する。

Resources:
  IAMRoleForCloudTrail:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: cloudtrail.amazonaws.com
            Action: 'sts:AssumeRole'
      Description: A role required for CloudTrail to access CloudWatch Logs.
      Policies:
        - PolicyName: !Sub '${AWS::StackName}-AWSCloudTrailCloudWatchLogsPolicy-${AWS::Region}'
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'logs:PutLogEvents'
                  - 'logs:CreateLogStream'
                Resource:
                  - !GetAtt CloudWatchLogsGroupForCloudTrail.Arn
      RoleName: !Sub '${AWS::StackName}-CloudTrail-${AWS::Region}'

S3バケットの作成

証跡を保存するS3バケットと、CloudTrailからS3バケットへのアクセスを許可する、バケットポリシーを作成する。適切なバケットポリシーを設定しないと、 InsufficientS3BucketPolicyException エラーが発生する。

Resouces:
  S3ForCloudTrail:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration: 
          - ServerSideEncryptionByDefault: 
              SSEAlgorithm: aws:kms
      BucketName: !Sub defaultsecuritysettings-cloudtrail-${AWS::Region}-${AWS::AccountId}
      LifecycleConfiguration:
        Rules:
          - Id: ExpirationInDays
            ExpirationInDays: 60
            Status: Enabled
      LoggingConfiguration:
        DestinationBucketName: !Ref LogBacketName
        LogFilePrefix: CloudTrail/
      PublicAccessBlockConfiguration: 
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
  S3BucketPolicyForCloudTrail:
    Type: 'AWS::S3::BucketPolicy'
    Properties: 
      Bucket: !Ref S3ForCloudTrail
      PolicyDocument:
        Version: 2012-10-17
        Id: !Ref S3ForCloudTrail
        Statement:
          - Effect: Allow
            Principal:
              Service: cloudtrail.amazonaws.com
            Action:
              - 's3:GetBucketAcl'
            Resource:
              - !GetAtt S3ForCloudTrail.Arn
          - Effect: Allow
            Principal:
              Service: cloudtrail.amazonaws.com
            Action:
              - 's3:PutObject'
            Resource:
              - !Join
                - ''
                - - !GetAtt S3ForCloudTrail.Arn
                  - /AWSLogs/
                  - !Sub ${AWS::AccountId}
                  - /*
            Condition:
              StringEquals:
                s3:x-amz-acl: bucket-owner-full-control

CloudWatch Logsの作成

CloudWatch Logs の Log Group を作成する。

Resources:
  CloudWatchLogsGroupForCloudTrail:
    Type: 'AWS::Logs::LogGroup'
    Properties:
      LogGroupName: !Sub '/aws/cloudtrail/${AWS::StackName}'
      RetentionInDays: 365

CloudTrailの有効化

CloudTrail を有効化する。先ほど作成したS3バケットとCloudWatch Logsを証跡の出力先に指定する。通常は、データイベントの保存は行わないが、以下のテンプレートでは、S3とLambdaのデータイベントも保存している。

Resources:
  CloudTrail:
    DependsOn:
      - S3BucketPolicyForCloudTrail
    Condition: CreateCentralizedResources
    Type: 'AWS::CloudTrail::Trail'
    Properties:
      CloudWatchLogsLogGroupArn: !GetAtt CloudWatchLogsGroupForCloudTrail.Arn
      CloudWatchLogsRoleArn: !GetAtt IAMRoleForCloudTrail.Arn
      EnableLogFileValidation: true
      EventSelectors:
        - DataResources: 
            # All S3 buckets
            - Type: AWS::S3::Object
              Values: 
                - arn:aws:s3
            # All Lambda functions
            - Type: AWS::Lambda::Function
              Values: 
                - arn:aws:lambda
      IncludeGlobalServiceEvents: true
      IsLogging: true
      IsMultiRegionTrail: true
      S3BucketName: !Ref S3ForCloudTrail
      SnsTopicName: !Ref SnsTopicName
      TrailName: !Sub ${AWS::StackName}

CloudFormation Launch Stack URL

以下のボタンから上のCloudFormationテンプレートを実行することが可能である。ソースコードは、aws-cloudformation-templates/security – GitHub にて公開。

作成されるAWSサービス CloudFormationテンプレート
セキュリティサービス全般 cloudformation-launch-stack
CloudTrailのみ cloudformation-launch-stack

AWS Config(6)デフォルトセキュリティグループの無効化

デフォルトセキュリティグループ

CIS AWS Foundations Benchmark というセキュリティガイドラインが公開されており、このガイドラインは、AWSアカウントをセキュアに保つために必要なAWSのセキュリティ設定を集めたベストプラクティス集として活用できる。

この CIS AWS Foundations Benchmarkでは、デフォルトセキュリティグループについて、以下の設定とすることが奨励されている。

  • 4.3 IAM すべての VPC のデフォルトセキュリティグループがすべてのトラフィックを制限するようにします

この CIS AWS Foundations Benchmark準拠していないデフォルトセキュリティグループSSM Automation を用いて 自動修復 するために以下の設定を行う。

  1. 上記のポリシーに準拠しているか AWS Config を用いて定期的にチェックを行う
  2. 非準拠であった場合には、AWS ConfigSSM Automation自動起動する
  3. SSM Automation非準拠のデフォルトセキュリティグループの設定を自動修復する

1. AWS Configの有効化

AWS Configを有効化する手順については、こちら

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

デフォルトセキュリティグループ設定のチェックには、あらかじめAWS Configに用意されている vpc-default-security-group-closed マネージドルールを使用する。デフォルトセキュリティグループがこの条件を満たしていない場合、このリソースはルールに 非準拠(NON_COMPLIANT) であると判定される。

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

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 ドキュメントは、EC2RevokeSecurityGroupIngress, RevokeSecurityGroupEgress, DescribeSecurityGroups を実行して、デフォルトセキュリティグループの設定を自動修復する。

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 ドキュメントは、上述の通り IAMRevokeSecurityGroupIngress などを実行する必要があるため、このAWS API アクションを Systems Manager Automation から呼び出すことを可能とする IAM Role を作成する。

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 '${PrefixOfLogicalName}-AWSSystemManagerIAMRole-${AWS::Region}'
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'ec2:RevokeSecurityGroupIngress'
                  - 'ec2:RevokeSecurityGroupEgress'
                  - 'ec2:DescribeSecurityGroups'
                Resource:
                  - '*'
      RoleName: !Sub '${AWS::StackName}-SSM-${AWS::Region}'

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

Resources:
  ConfigVpcDefaultSecurityGroupClosedRemediationConfiguration:
    Condition: CreateRemediationResources
    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

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

AWS Config(5)外部からのSSHおよびRDPアクセスを制限する

セキュリティグループの自動修復

CIS AWS Foundations Benchmark というセキュリティガイドラインが公開されており、このガイドラインは、AWSアカウントをセキュアに保つために必要なAWSのセキュリティ設定を集めたベストプラクティス集として活用できる。

この CIS AWS Foundations Benchmarkでは、EC2/VPCのセキュリティグループについて、以下の設定とすることが奨励されている。

  • 4.1 どのセキュリティグループでも 0.0.0.0/0 からポート 22 への入力を許可しないようにします
  • 4.2 どのセキュリティグループでも 0.0.0.0/0 からポート 3389 への入力を許可しないようにします

この CIS AWS Foundations Benchmark準拠していないセキュリティグループSSM Automation を用いて 自動修復 するために以下の設定を行う。

  1. 上記のポリシーに準拠しているか AWS Config を用いて定期的にチェックを行う
  2. 非準拠であった場合には、AWS ConfigSSM Automation自動起動する
  3. SSM Automation奨励されたセキュリティグループ設定となるように設定を自動修復する

1. AWS Configの有効化

AWS Configを有効化する手順については、こちら

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

セキュリティグループの設定のチェックには、あらかじめAWS Configに用意されている vpc-default-security-group-closed マネージドルールを使用する。セキュリティグループがこの条件を満たしていない場合、このリソースはルールに 非準拠(NON_COMPLIANT) であると判定される。

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

Resources:
  ConfigSVpcSgOpenOnlyToAuthorizedPorts:
    DependsOn:
      - ConfigConfigurationRecorder
    Type: 'AWS::Config::ConfigRule'
    Properties:
      ConfigRuleName: vpc-sg-open-only-to-authorized-ports
      Description: いずれかの 0.0.0.0/0 Amazon Virtual Private Cloud (Amazon VPC) を持つセキュリティグループで、特定のインバウンド TCP または UDP トラフィックのみが許可されるかどうかを確認します。
      InputParameters:
        authorizedTcpPorts: 1-21,23-3388,3390-65535
        authorizedUdpPorts: 1-21,23-3388,3390-65535
      Source:
        Owner: AWS
        SourceIdentifier: VPC_SG_OPEN_ONLY_TO_AUTHORIZED_PORTS 

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

Systems Manager Automation は、AWS Config直接指定できる、現時点で唯一の自動修復手段 となっている。そこで、セキュリティグループ を修復する Systems Manager Automation ドキュメントAWS Config との紐付けを行う。

修復には、あらかじめ用意されている AWS-DisablePublicAccessForSecurityGroup ドキュメントを使用する。このドキュメントは、すべての IP アドレスに対して開かれているデフォルトの SSH および RDP ポートを無効にする。

Resources:
  ConfigVpcSgOpenOnlyToAuthorizedPortsRemediationConfiguration:
    Condition: CreateRemediationResources
    Type: 'AWS::Config::RemediationConfiguration'
    Properties:
      # NOTE: AutomationAssumeRole, MaximumAutomaticAttempts and RetryAttemptSeconds are Required if Automatic is true.
      Automatic: true
      ConfigRuleName: !Ref ConfigSVpcSgOpenOnlyToAuthorizedPorts
      MaximumAutomaticAttempts: 1
      Parameters:
        AutomationAssumeRole:
          StaticValue:
            Values:
              - !GetAtt IAMRoleForSSM.Arn
        GroupId:
          ResourceValue:
            Value: RESOURCE_ID
      RetryAttemptSeconds: 30
      TargetId: AWS-DisablePublicAccessForSecurityGroup
      TargetType: SSM_DOCUMENT

以上で、すべての IP アドレスに対して開かれているデフォルトの SSH および RDP ポートを無効にすることができた。

AWS Config(4)VPCフローログの自動生成

VPCフローログ

CIS AWS Foundations Benchmark というセキュリティガイドラインが公開されており、このガイドラインは、AWSアカウントをセキュアに保つために必要なAWSのセキュリティ設定を集めたベストプラクティス集として活用できる。

この CIS AWS Foundations Benchmarkでは、VPCフローログについて以下のように定められている。

  • 2.9 すべての VPC で VPC フローログ記録が有効になっていることを確認します

この CIS AWS Foundations Benchmark準拠していないVPCが存在した場合SSM Automation を用いて VPCフローログを自動作成 するために以下の設定を行う。

  1. 上記のポリシーに準拠しているか AWS Config を用いて定期的にチェックを行う
  2. 非準拠であった場合には、AWS ConfigSSM Automation自動起動する
  3. SSM AutomationVPCフローログを自動作成する

1. AWS Configの有効化

AWS Configを有効化する手順については、こちら

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

VPCフローログの存在確認には、あらかじめAWS Configに用意されている vpc-flow-logs-enabled マネージドルールを使用する。VPCフローログが設定されていない場合、このVPCはルールに 非準拠(NON_COMPLIANT) であると判定される。

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

Resources:
  ConfigVpcFlowLogsEnabled:
    DependsOn:
      - ConfigConfigurationRecorder
    Type: 'AWS::Config::ConfigRule'
    Properties:
      ConfigRuleName: vpc-flow-logs-enabled
      Description: Amazon Virtual Private Cloud フローログが見つかり、Amazon VPC に対して有効になっているかどうかを確認します。
      Source:
        Owner: AWS
        SourceIdentifier: VPC_FLOW_LOGS_ENABLED 

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

Systems Manager Automation は、AWS Config直接指定できる、現時点で唯一の自動修復手段 となっている。そこで、VPCフローログ を生成する Systems Manager Automation ドキュメント を作成し、AWS Config との紐付けを行う。

下のSystems Manager Automation ドキュメントは、EC2CreateFlowLogs を実行して、IAM パスワードポリシーの設定を自動修復する。

Resources:
  SSMAutomationCreateFlowLogs:
    Type: 'AWS::SSM::Document'
    Properties: 
      Content:
        schemaVersion: "0.3"
        assumeRole: "{{ AutomationAssumeRole }}"
        description: Create VPC flow logs.
        mainSteps:
          - name: CreateLogGroup
            action: aws:executeAwsApi
            inputs:
              Service: cloudwatch
              Api: CreateLogGroup
              logGroupName: "/aws/vpc/{{ ResourceId }}"
          - name: PutRetentionPolicy
            action: aws:executeAwsApi
            inputs:
              Service: cloudwatch
              Api: PutRetentionPolicy
              logGroupName: "/aws/vpc/{{ ResourceId }}"
              retentionInDays: 60
          - name: CreateFlowLogs
            action: aws:executeAwsApi
            inputs:
              Service: ec2
              Api: CreateFlowLogs
              DeliverLogsPermissionArn: "{{ DeliverLogsPermissionArn }}"
              LogDestinationType: cloud-watch-logs
              LogGroupName: "/aws/vpc/{{ ResourceId }}"
              ResourceId.N: "{{ ResourceId }}"
              ResourceType: VPC
              TrafficType: ALL
        parameters:
          AutomationAssumeRole:
            type: String
            description: Automation Assume Role Arn
          DeliverLogsPermissionArn:
            type: String
            description: Deliver Logs Permission Arn
          ResourceId:
            type: String
            description: Resource ID
      DocumentType: Automation
      Tags:
        - Key: !Ref TagKey
          Value: !Ref TagValue

4. AWS Config と SSM Automation の紐付け

Systems Manager Automation ドキュメントは、上述の通り EC2CreateFlowLogs などを実行する必要があるため、このAWS API アクションを Systems Manager Automation から呼び出すことを可能とする IAM Role を作成する。

また、VPCからCloudWatch Logsにフローログを書き込むことのできる権限を持つIAM Roleも別途作成しておく。

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 '${PrefixOfLogicalName}-AWSSystemManagerIAMRole-${AWS::Region}'
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:PutRetentionPolicy'
                  - 'ec2:CreateFlowLogs'
                Resource:
                  - '*'
      RoleName: !Sub '${AWS::StackName}-SSM-${AWS::Region}'
  IAMRoleForVPCFlowLog:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: vpc-flow-logs.amazonaws.com
            Action: 'sts:AssumeRole'
      Description: A role required for VPC flow logs to access CloudWatch Logs.
      Policies:
        - PolicyName: !Sub '${AWS::StackName}-AWSVPCFlowLogCloudWatchLogsPolicy-${AWS::Region}'
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                  - 'logs:DescribeLogGroups'
                  - 'logs:DescribeLogStreams'
                Resource: '*'
      RoleName: !Sub '${AWS::StackName}-AWSVPCFlowLogRole-${AWS::Region}'

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

Resources:
  ConfigVpcFlowLogsEnabledRemediationConfiguration:
    Condition: CreateRemediationResources
    Type: 'AWS::Config::RemediationConfiguration'
    Properties:
      Automatic: true
      ConfigRuleName: !Ref ConfigVpcFlowLogsEnabled
      MaximumAutomaticAttempts: 1
      Parameters:
        AutomationAssumeRole:
          StaticValue:
            Values:
              - !GetAtt IAMRoleForSSM.Arn
        DeliverLogsPermissionArn:
          StaticValue:
            Values:
              - !GetAtt IAMRoleForVPCFlowLog.Arn
        ResourceId:
          ResourceValue:
            Value: RESOURCE_ID
      RetryAttemptSeconds: 30
      TargetId: !Ref SSMAutomationCreateFlowLogs
      TargetType: SSM_DOCUMENT

以上で、CIS AWS Foundations Benchmark に準拠していないVPCに対して、VPCフローログを自動生成することができた。

AWS Config(3)アクセスキーの管理と自動削除

アクセスキーの適切な管理

CIS AWS Foundations Benchmark というセキュリティガイドラインが公開されており、このガイドラインは、AWSアカウントをセキュアに保つために必要なAWSのセキュリティ設定を集めたベストプラクティス集として活用できる。

この CIS AWS Foundations Benchmarkでは、アクセスキーの取り扱いについて以下のように定めている。

  • 1.3 90 日間以上使用されていない認証情報は無効にします
  • 1.4 アクセスキーは 90 日ごとに更新します

この CIS AWS Foundations Benchmark準拠していないアクセスキーCloudWatch EventsLambda を用いて 自動削除 するために以下の設定を行う。

  1. 上記のポリシーに準拠しているか AWS Config を用いて定期的にチェックを行う
  2. 非準拠であった場合には、CloudWatch EventsLambda自動起動する
  3. Lambda非準拠のアクセスキーを削除する

1. AWS Configの有効化

AWS Configを有効化する手順については、こちら

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

アクセスキーのチェックには、あらかじめAWS Configに用意されている access-keys-rotated マネージドルールを使用する。CIS AWS Foundations Benchmark で奨励されているアクセスキーの有効期限は、マネージドルール内の InputParameters で設定する。アクセスキーがこの条件を満たしていない場合、このリソースはルールに 非準拠(NON_COMPLIANT) であると判定される。

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

Resources:
  ConfigIamAccessKeysRotated:
    DependsOn:
      - ConfigConfigurationRecorder
    Type: 'AWS::Config::ConfigRule'
    Properties:
      ConfigRuleName: access-keys-rotated
      Description: アクティブなアクセスキーが、maxAccessKeyAge で指定された日数内にローテーションされるかどうかを確認します。
      InputParameters:
        maxAccessKeyAge: 90
      Source:
        Owner: AWS
        SourceIdentifier: ACCESS_KEYS_ROTATED

3. CloudWatch Events を用いた Lambda の自動実行

Configルールに 非準拠(NON_COMPLIANT)となった場合に、これを修復するLambdaを発火させるためのトリガとして、CloudWatch Events を設定する。

Resources:
  CloudWatchEventsForConfigIamAccessKeysRotated:
    Type: 'AWS::Events::Rule'
    Properties: 
      Description: CloudWatch Events about Config IAM Access Keys Rotated.
      EventPattern:
        source:
          - aws.config
        detail-type: 
          - Config Rules Compliance Change
        detail:
          messageType:
            - ComplianceChangeNotification
          newEvaluationResult:
            complianceType:
              - NON_COMPLIANT
      Name: AWS_Config
      State: ENABLED
      Targets:
        - Arn: !GetAtt LambdaDeleteExpiredAccessKeys.Arn
          Id: lambda

4. Lambda を用いた アクセスキー の削除

Lambdaが受け取るConfigから通知されたメッセージには、期限切れのアクセスキーを持つIAMユーザの情報が含まれる。そこでLambdaは、このユーザが持つアクセスキーのうち、有効期限を超過したアクセスキーのIDを探し当てDeleteAccessKey API を用いてこれを削除する。

また、AWS::Lambda::Permission リソースタイプを用いて、前述のCloudWatch Eventsが、このLambdaを実行可能とする権限を設定する。

Resources:
  LambdaDeleteExpiredAccessKeys:
    Type: 'AWS::Lambda::Function'
    Properties:
      Code:
        ZipFile: |
          import boto3
          import datetime
          import time
          import logging

          logger = logging.getLogger()
          logger.setLevel(logging.INFO)

          def lambda_handler(event, context):
              logger.info(str(event))
            
              if 'detail' in event:
                  detail = event['detail']
                  if 'configRuleName' in detail:
                      # access-keys-rotated
                      if detail['configRuleName'] == 'access-keys-rotated':
                          iam = boto3.client('iam')
                          users = iam.list_users()
                          for user in users['Users']:
                              if detail['resourceId'] == user['UserId']:
                                  access_keys = iam.list_access_keys(
                                      UserName=user['UserName']
                                      )
                                  for access_key in access_keys['AccessKeyMetadata']:
                                      create_date = access_key['CreateDate'].timestamp()
                                      now = time.time()
                                      if now - create_date > 60*60*24*90:
                                          response = iam.delete_access_key(
                                              UserName=user['UserName'],
                                              AccessKeyId=access_key['AccessKeyId']
                                          )
      Description: 有効期限が過ぎたアクセスキーを削除します
      FunctionName: deleteExpiredAccessKeys
      Handler: index.lambda_handler
      MemorySize: 128
      Role: !GetAtt IAMRoleForLambda.Arn
      Runtime: python3.7
      Tags:
        - Key: !Ref TagKey
          Value: !Ref TagValue
      Timeout: 3
      TracingConfig:
        Mode: Active
  LambdaDeleteExpiredAccessKeysPermission:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref LambdaDeleteExpiredAccessKeys
      Principal: events.amazonaws.com
      # DO NOT write 'SourceAccount' option.
      SourceArn: !GetAtt CloudWatchEventsForConfigIamAccessKeysRotated.Arn

以上で、CIS AWS Foundations Benchmark に非準拠のアクセスキーを削除することができた。

AWS Config(2)パスワードポリシーの自動修復

IAMパスワードポリシーの自動修復

CIS AWS Foundations Benchmark というセキュリティガイドラインが公開されており、このガイドラインは、AWSアカウントをセキュアに保つために必要なAWSのセキュリティ設定を集めたベストプラクティス集として活用できる。

この CIS AWS Foundations Benchmarkでは、IAMユーザ用のパスワードポリシーについて、以下の設定とすることが奨励されている。

  • 1.5 IAM パスワードポリシーには少なくとも 1 つの大文字が必要です
  • 1.6 IAM パスワードポリシーには少なくとも 1 つの小文字が必要です
  • 1.7 IAM パスワードポリシーには少なくとも 1 つの記号が必要です
  • 1.8 IAM パスワードポリシーには少なくとも 1 つの数字が必要です
  • 1.9 IAM パスワードポリシーは 14 文字以上の長さが必要です
  • 1.10 IAM パスワードポリシーはパスワードの再使用を禁止しています

この CIS AWS Foundations Benchmark準拠していないIAMパスワードポリシーSSM Automation を用いて 自動修復 するために以下の設定を行う。

  1. 上記のポリシーに準拠しているか AWS Config を用いて定期的にチェックを行う
  2. 非準拠であった場合には、AWS ConfigSSM Automation自動起動する
  3. SSM Automation正しいIAMパスワードポリシーとなるように設定を自動修復する

1. AWS Configの有効化

AWS Configを有効化する手順については、こちら

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

IAM パスワードポリシー設定のチェックには、あらかじめAWS Configに用意されている iam-password-policy マネージドルールを使用する。CIS AWS Foundations Benchmark で奨励されているパスワードポリシーの値は、マネージドルール内の InputParameters で設定する。IAM パスワードポリシーがこの条件を満たしていなかった場合、このリソースはルールに 非準拠(NON_COMPLIANT) であると判定される。

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

Resources:
  ConfigIamPasswordPolicy:
    DependsOn:
      - ConfigConfigurationRecorder
    Type: AWS::Config::ConfigRule
    Properties:
      ConfigRuleName: iam-password-policy
      Description: IAM ユーザーのアカウントパスワードポリシーが、指定した要件を満たしているかどうかを確認します。
      InputParameters:
        RequireUppercaseCharacters: true
        RequireLowercaseCharacters: true
        RequireSymbols: true
        RequireNumbers: true
        MinimumPasswordLength: 14
        PasswordReusePrevention: 24
      Source:
        Owner: AWS
        SourceIdentifier: IAM_PASSWORD_POLICY

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

Systems Manager Automation は、AWS Config直接指定できる、現時点で唯一の自動修復手段 となっている。そこで、IAM パスワードポリシー を修復する Systems Manager Automation ドキュメント を作成し、AWS Config との紐付けを行う。

下のSystems Manager Automation ドキュメントは、IAMUpdateAccountPasswordPolicy を実行して、IAM パスワードポリシーの設定を自動修復する。

Resources:
  SSMAutomationUpdateAccountPasswordPolicy:
    Type: AWS::SSM::Document
    Properties: 
      Content:
        schemaVersion: "0.3"
        assumeRole: "{{ AutomationAssumeRole }}"
        description: Update account password policy.
        mainSteps:
          - name: UpdateAccountPasswordPolicy
            action: aws:executeAwsApi
            inputs:
              Service: iam
              Api: UpdateAccountPasswordPolicy
              AllowUsersToChangePassword: true
              HardExpiry: false
              MinimumPasswordLength: 14
              PasswordReusePrevention: 24
              RequireLowercaseCharacters: true
              RequireNumbers: true
              RequireSymbols: true
              RequireUppercaseCharacters: true
        parameters:
          AutomationAssumeRole:
            type: String
            description: Automation Assume Role Arn
      DocumentType: Automation

4. AWS Config と SSM Automation の紐付け

Systems Manager Automation ドキュメントは、上述の通り IAMUpdateAccountPasswordPolicy を実行する必要があるため、このAWS API アクションを Systems Manager Automation から呼び出すことを可能とする IAM Role を作成する。

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:
                  - 'iam:UpdateAccountPasswordPolicy'
                Resource:
                  - '*'
      RoleName: !Sub 'DefaultSecuritySettings-SSM-${AWS::Region}'

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

Resources:
  ConfigIamPasswordPolicyRemediationConfiguration:
    Type: AWS::Config::RemediationConfiguration
    Properties:
      Automatic: true
      ConfigRuleName: !Ref ConfigIamPasswordPolicy
      MaximumAutomaticAttempts: 1
      Parameters:
        AutomationAssumeRole:
          StaticValue:
            Values:
              - !GetAtt IAMRoleForSSM.Arn
      RetryAttemptSeconds: 60
      TargetId: !Ref SSMAutomationUpdateAccountPasswordPolicy
      TargetType: SSM_DOCUMENT

以上で、CIS AWS Foundations Benchmark に準拠したIAM パスワードポリシーへと、自動で修復することができた。

Amazon GuardDuty(1)GuardDutyの概要

GuardDutyとは

Amazon GuardDuty は、VPC フローログAWS CloudTrail イベントログDNS ログ を分析して、悪意のある操作や不正な動作を継続的にモニタリングする脅威検出サービス。AWS 環境内の予期しない潜在的に未許可なアクティビティや悪意のあるアクティビティを識別して、AWS アカウントとワークロードを保護を行う。

検出結果

潜在的に悪意のある予期しないアクティビティを検出すると、GuardDuty によって結果が生成される。またこれらの結果は、GuardDuty のマネージメントコンソールから閲覧できるだけでなく、 CloudWatch Events を利用して表示することもできる。

検出した脅威は以下のタイプに分類される。

タイプ 重要度 内容
Backdoor:EC2/Spambot EC2 インスタンスがポート 25 でリモートホストと通信して通常と異なる動作を示す。
Backdoor:EC2/C&CActivity.B!DNS EC2 インスタンスは、既知のコマンドアンドコントロールサーバーに関連付けられるドメイン名をクエリしている。
Backdoor:EC2/DenialOfService.Tcp EC2 インスタンスが、TCP プロトコルを使用したサービス拒否 (DoS) 攻撃の実行に利用されている可能性がある。
Backdoor:EC2/DenialOfService.Udp EC2 インスタンスが、UDP プロトコルを使用したサービス拒否 (DoS) 攻撃の実行に利用されている可能性がある。
Backdoor:EC2/DenialOfService.Dns EC2 インスタンスが、DNS プロトコルを使用したサービス拒否 (DoS) 攻撃の実行に利用されている可能性がある。
Backdoor:EC2/DenialOfService.UdpOnTcpPorts EC2 インスタンスが、TCP ポートで UDP プロトコルを使用したサービス拒否 (DoS) 攻撃の実行に利用されている可能性がある。
Backdoor:EC2/DenialOfService.UnusualProtocol EC2 インスタンスが、異常なプロトコルを使用したサービス拒否 (DoS) 攻撃の実行に利用されている可能性がある。
Behavior:EC2/NetworkPortUnusual EC2 インスタンスが通常と異なるポートでリモートホストと通信している。
Behavior:EC2/TrafficVolumeUnusual EC2 インスタンスがリモートホストに対して通常と異なる大量のネットワークトラフィックを生成している。
CryptoCurrency:EC2/BitcoinTool.B!DNS EC2 インスタンスは、暗号通貨関連のアクティビティに関連付けられているドメイン名をクエリしている。
CryptoCurrency:EC2/BitcoinTool.B EC2 インスタンスは、暗号通貨関連のアクティビティに関連付けられている IP アドレスをクエリしている。
PenTest:IAMUser/KaliLinux API が Kali Linux EC2 インスタンスから呼び出されました。
PenTest:IAMUser/ParrotLinux API が Parrot Security Linux EC2 インスタンスから呼び出されました。
PenTest:IAMUser/PentooLinux API が Pentoo Linux EC2 インスタンスから呼び出されました。
Persistence:IAMUser/NetworkPermissions プリンシパルが、通常 AWS アカウントのセキュリティグループ、ルート、ACL のネットワークアクセス許可を変更するために使用される API を呼び出した。
Persistence:IAMUser/ResourcePermissions プリンシパルが、通常 AWS アカウントのさまざまなリソースのセキュリティアクセスポリシーを変更するために使用される API を呼び出した。
Persistence:IAMUser/UserPermissions プリンシパルが、通常 AWS アカウントの IAM ユーザー、グループ、ポリシーを追加、変更、削除するために使用される API を呼び出した。
Policy:IAMUser/S3BlockPublicAccessDisabled バケットの Amazon S3 ブロックパブリックアクセスが無効になった。
Policy:IAMUser/RootCredentialUsage API がルート認証情報を使用して呼び出された。
PrivilegeEscalation:IAMUser/AdministrativePermissions プリンシパルが許容度の高いポリシーを割り当てようとしている。
Recon:EC2/PortProbeUnprotectedPort EC2 インスタンスの保護されていないポートを既知の悪意のあるホストが探している。
Recon:EC2/PortProbeEMRUnprotectedPort EMR クラスタの保護されていないポートを既知の悪意のあるホストが探している。
Recon:IAMUser/TorIPCaller API が Tor 出口ノードの IP アドレスから呼び出された。
Recon:IAMUser/MaliciousIPCaller.Custom API がカスタム脅威リストにある IP アドレスから呼び出された。
Recon:IAMUser/MaliciousIPCaller API が既知の悪意のある IP アドレスから呼び出された。
Recon:EC2/Portscan EC2 インスタンスがリモートホストにアウトバウンドポートスキャンを実行している。
Recon:IAMUser/NetworkPermissions プリンシパルが、通常 AWS アカウントの既存のセキュリティグループ、ACL、ルートのネットワークアクセス許可を検出するために使用される API を呼び出した。
Recon:IAMUser/ResourcePermissions プリンシパルが、通常 AWS アカウントのさまざまなリソースに関連付けられたアクセス権限を検出するために使用される API を呼び出した。
ResourceConsumption:IAMUser/ComputeResources プリンシパルが、通常 EC2 インスタンスなどのコンピューティングリソースを起動するために使用される API を呼び出した。
Stealth:IAMUser/S3ServerAccessLoggingDisabled バケットの Amazon S3 サーバーアクセスログ記録が無効になった.
Stealth:IAMUser/PasswordPolicyChange アカウントのパスワードポリシーが弱化された.
Stealth:IAMUser/CloudTrailLoggingDisabled AWS CloudTrail の証跡が無効化されている。
Stealth:IAMUser/LoggingConfigurationModified プリンシパルが、通常 AWS アカウントの CloudTrail ログ記録の停止、既存ログの削除、その他アクティビティの痕跡を消去するために使用される API を呼び出した。
Trojan:EC2/BlackholeTraffic EC2 インスタンスは、ブラックホールと呼ばれるリモートホストの IP アドレスに通信しようとしている。
Trojan:EC2/DropPoint EC2 インスタンスは、マルウェアによって収集された認証情報やその他の盗難されたデータによって認識されているリモートホストの IP アドレスに通信しようとしている。
Trojan:EC2/BlackholeTraffic!DNS EC2 インスタンスは、ブラックホール IP アドレスにリダイレクトされるドメイン名へのクエリを実行している。
Trojan:EC2/DriveBySourceTraffic!DNS EC2 インスタンスは、Drive By Download 攻撃の既知のソースであるリモートホストのドメイン名をクエリしている。
Trojan:EC2/DropPoint!DNS EC2 インスタンスは、マルウェアによって収集された認証情報やその他の盗難されたデータによって認識されているリモートホストのドメイン名をクエリしている。
Trojan:EC2/DGADomainRequest.B EC2 インスタンスで、アルゴリズムを使用して生成されたドメインがクエリされている。
Trojan:EC2/DGADomainRequest.C!DNS EC2 インスタンスで、アルゴリズムを使用して生成されたドメインがクエリされています。このようなドメインは、一般的にマルウェアによって悪用されることが多く、EC2 インスタンスが侵害されている場合がある。
Trojan:EC2/DNSDataExfiltration EC2 インスタンスが DNS クエリを通じてデータを密かに抽出しようとしている。
Trojan:EC2/PhishingDomainRequest!DNS EC2 インスタンスはフィッシング攻撃に関与するクエリ実行のドメインである。
UnauthorizedAccess:EC2/MetadataDNSRebind Amazon EC2 インスタンスが、インスタンスメタデータサービスに解決される DNS ルックアップを実行している。
UnauthorizedAccess:IAMUser/TorIPCaller API が Tor 出口ノードの IP アドレスから呼び出された。
UnauthorizedAccess:IAMUser/MaliciousIPCaller.Custom API がカスタム脅威リストにある IP アドレスから呼び出された。
UnauthorizedAccess:IAMUser/ConsoleLoginSuccess.B 世界中でコンソールに対する複数の正常なログインが確認された。
UnauthorizedAccess:IAMUser/MaliciousIPCaller API が既知の悪意のある IP アドレスから呼び出された。
UnauthorizedAccess:EC2/TorIPCaller EC2 インスタンスが Tor 出口ノードからのインバウンド接続を受信している。
UnauthorizedAccess:EC2/MaliciousIPCaller.Custom EC2 インスタンスがカスタム脅威リスト内の IP アドレスとアウトバウンド通信している。
UnauthorizedAccess:EC2/SSHBruteForce EC2 インスタンスが SSH ブルートフォース攻撃に関与している。
UnauthorizedAccess:EC2/RDPBruteForce EC2 インスタンスが RDP ブルートフォース攻撃に関与している。
UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration インスタンス起動ロールを通じて EC2 インスタンス専用に作成された認証情報が外部 IP アドレスから使用されている。
UnauthorizedAccess:IAMUser/ConsoleLogin AWS アカウントのプリンシパルによる通常とは違うコンソールへのログインが確認された。
UnauthorizedAccess:EC2/TorClient EC2 インスタンスは Tor Guard または Authority ノードに接続している。
UnauthorizedAccess:EC2/TorRelay EC2 インスタンスは、Tor リレーとして Tor ネットワークに接続中である。

Amazon GuardDuty のセットアップ

Amazon GuardDutyはCloudFormationに対応しているため、CloudFormation経由でGuardDutyをセットアップすることができる。

サービスロールの有効化

以下のサービスロールを有効化することで、EC2リストの読み込み権限GuardDuty に付与する。これは、悪意のあるアクティビティに関係する AWS 環境の EC2 インスタンスのメタデータを取得するためである。

Resources:
  ServiceLinkedRoleForGuardDuty:
    Type: AWS::IAM::ServiceLinkedRole
    DeletionPolicy: Retain
    Properties: 
      AWSServiceName: guardduty.amazonaws.com
      Description: A service-linked role required for Amazon GuardDuty to access your resources.

GuardDutyの有効化

GuardDuty を有効化する。有効化すると直ちにデータの取得と分析を開始する。 これらの処理は、通常のAWS CloudTrail、VPC フローログ、および DNS ログの保存とは独立している。

Resources:
  GuardDutyDetector:
    DependsOn:
      - ServiceLinkedRoleForGuardDuty
    Type: AWS::GuardDuty::Detector
    Properties:
      Enable: true

CloudFormation Launch Stack URL

以下のボタンから上のCloudFormationテンプレートを実行することが可能である。ソースコードは、aws-cloudformation-templates/security – GitHub にて公開。

作成されるAWSサービス CloudFormationテンプレート
セキュリティサービス全般 cloudformation-launch-stack
GuardDutyのみ cloudformation-launch-stack

AWS Config(1)Configの概要

AWS Configとは

AWS Configは、リソースごとの設定項目を生成し、履歴としてこれを保持するため、全ての変更を追跡することが可能で、AWSリソース間の関係と設定の履歴などを確認することができる。

  • リソースの設定が最適であるか
  • 現在のスナップショットの取得
  • リソース設定の取得
  • 設定履歴の取得
  • リソース間の関係の表示
  • 通知

これらの機能を用いて、リソースの管理監査とコンプライアンス設定変更の確認とトラブルシューティングセキュリティ分析などを行うことができる。

設定項目は、S3バケットに蓄積することが可能で、データはJSON形式で、S3に6時間ごとに送信される。また、リソースが変更されたタイミング等で、Amazon SNSを用いてEメール等で通知することも可能である。

AWS Configは、マルチアカウントマルチリージョンの データ集約 に対応しており、複数のアカウントやリージョンの設定、コンプライアンスデータを1つのアカウントに集約することができる。

AWS Configの概念

設定履歴と設定項目、スナップショット、レコーダ

設定履歴は、特定期間の特定リソースに関する設定項目のコレクションである。また、設定項目は、アカウント内のサポートされているAWSリソースの属性(メタデータ、関係、設定、関連イベントなど)を記録したものである。設定スナップショット は、設定項目のコレクションで、記録対象のリソースの全体像を示す。スナップショットは、S3 Bucketに配信が可能。

設定レコーダは、(標準設定では)Configがサポートしている全てのリソースの設定項目の評価と保存を行う。設定レコーダをオフにすると設定変更トリガによる評価は実行されない。一方で、定期実行トリガは引き続き指定した間隔で実行される

設定ストリーム

設定ストリームは、設定項目の自動更新リストで、リソースの作成や変更、削除が行われる度に、Amazon SNSを使用して通知を行うことができる。

ルール

AWS Configでは、望ましい設定をルールとして定めることができ、これに違反しているリソースに対しては、非準拠 のフラグを立てる。ルールは、事前に用意されたマネージドルールのほかに、ユーザが自ら作成したカスタムルールを適用することもできる。これらのルールは、リソースの設定変更時に評価されるのか、それとも定期的に評価されるのかを定義することができる。

AWS Configの仕組み

AWS Configは、サポートされているAWSリソースを検出し、リソースごとに設定項目を生成し、その記録を履歴として保持する。Configはリソースごとに、DescribeもしくはListのAPIコールによって、リソースの全ての変更を追跡する。Configルールを利用することで、定期的にこのルールに照らして、リソースの設定の評価を行うことができる。

また、この設定項目は、S3バケット もしくは Amazon SNS に配信することができる。SNSへ配信時のメッセージタイプは以下の通り。

メッセージタイプ 内容
ComplianceChangeNotification コンプライアンスタイプの変更時
ConfigRulesEvaluationStarted リソースの評価開始時
ConfigurationSnapshotDeliveryStarted スナップショット配信開始時
ConfigurationSnapshotDeliveryCompleted スナップショット配信完了時
ConfigurationSnapshotDeliveryFailed スナップショット配信失敗時
ConfigurationHistoryDeliveryCompleted 設定履歴配信完了時
ConfigurationItemChangeNotification リソース変更時
OversizedConfigurationItemChangeNotification SNSの最大サイズ超過時

AWS Configのセットアップ

AWS ConfigはCloudFormationに対応しているため、CloudFormation経由でConfigをセットアップすることができる。

サービスロールの有効化

以下のサービスロールを有効化することで、AWSリソースの読み込み権限 および S3への書き込み権限Config に、IAMとSystemManagerへの書き込み権限Config Remediation にそれぞれ付与する。

Resources:
  ServiceLinkedRoleForConfig:
    Type: AWS::IAM::ServiceLinkedRole
    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
    DeletionPolicy: Retain
    Properties: 
      AWSServiceName: remediation.config.amazonaws.com 
      Description: A service-linked role required for AWS Config Remediation to access your resources.

Configの有効化

DeliveryChannelConfigurationRecorder を作成する。

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

すでにAWS Configをセットアップ済みの状態で上記テンプレートを実行すると、 the maximum number of delivery channels エラーが発生する。その場合は既存の DeliveryChannel を削除した上で、上記テンプレートを再度実行する。

aws configservice delete-delivery-channel --delivery-channel-name default
aws configservice delete-configuration-recorder --configuration-recorder-name default

S3バケットの作成

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

Resources:
  S3ForConfig:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      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

CloudFormation Launch Stack URL

以下のボタンから上のCloudFormationテンプレートを実行することが可能である。ソースコードは、aws-cloudformation-templates/security – GitHub にて公開。

作成されるAWSサービス CloudFormationテンプレート
セキュリティサービス全般 cloudformation-launch-stack
Configのみ cloudformation-launch-stack

モニタリング

他のAWSサービスを利用して、AWS Configのリソースをモニタリングすることができる。例えば、Amazon SQSAmazon CloudWatch Eventsを利用することで、AWSリソースが作成、変更、削除された際に通知を受け取ることが可能となる。

AWS Security Hub(1)Security Hubの概要

Security Hubとは

Security Hubは、Amazon GuardDutyAmazon InspectorAmazon Macie などのAWSが提供するセキュリティ関連サービスや、AWSパートナーが提供するセキュリティ製品からの セキュリティ検出結果等を統合的に閲覧可能なサービス で、本サービスを利用することで、情報の収集や優先度の決定などのコストを低減できる。発見事項は、Security Hub内に90日保管 される。Security Hubは、リージョンサービスであり、使用するリージョン毎にサービスを有効化する必要 がある。一方で、 複数アカウントをサポート しており、全てのアカウントを統合して発見事項を表示することもできる。

また、Center for Internet Security (CIS) AWS Foundations Benchmark のスコア表示にも対応しており、業界標準のベストプラクティスをどの程度満たしているかについても確認することが可能となっている。なお、この機能を正常に実行するためには、AWS Configを有効化することが必要。ベストプラクティスを満たしていない場合は、Security Hubから修復方法を確認することができる。

Amazon CloudWatch Eventsとの統合がサポートされているため、検出結果を受信した際に実行するカスタムアクションを規定することもできる。

また、インサイトと呼ばれるグループ化された検出結果のコレクションが存在し、コレクションを用いることで、修復が必要な問題の特定ができる。カスタムインサイトを作成することも可能。

AWS Security Hub のセットアップ

一部機能のみではあるがCloudFormationに対応しているため、CloudFormation経由でSecurity Hubをセットアップすることができる。

サービスロールの有効化

以下のサービスロールを有効化することで、AWS CloudTrail, AWS Config, Amazon CloudWatch Logs および Amazon SNS から 情報を取得する権限 を Security Hub 付与する。また、AWS Config に対して 新たなConfigルールを設定する権限 も付与される。このルールは、CIS AWS Foundationsコンプライアンスチェックに使用される。これらを正常に動作させるためには、 AWS Configを有効化 しておく必要がある。

Resources:
  ServiceLinkedRoleForSecurityHub:
    Type: AWS::IAM::ServiceLinkedRole
    DeletionPolicy: Retain
    Properties: 
      AWSServiceName: securityhub.amazonaws.com
      Description: A service-linked role required for AWS Security Hub to access your resources.

Security Hubの有効化

Security Hubを有効化することで、CIS AWS Foundationsコンプライアンスチェックが自動で有効化される。

Resources:
  SecurityHub:
    DependsOn:
      - ServiceLinkedRoleForSecurityHub
    Type: AWS::SecurityHub::Hub

AWS Security Hubのセットアップテンプレート

AWS Security Hubを含むAWSのセキュリティサービスをまとめて有効化できるCloudFormationテンプレートを公開している。

作成されるAWSサービス CloudFormationテンプレート
セキュリティサービス全般 cloudformation-launch-stack
Security Hub のみ cloudformation-launch-stack

CIS AWS Foundationsコンプライアンスチェック

Security Hubは、AWS Configに新たなConfigルールを自動的に作成した上で、Center for Internet Security (CIS) AWS Foundations Benchmarkに適合しているかのチェックを行う。Security Hubは、AWS Security Finding と呼ばれるテンプレートに沿って検出結果を表示するために、結果毎にデータ変換等を行う必要がない。AWS Security Finding の構成については、下記を参照のこと。

なお、CIS AWS Foundationsは、同一リージョン内のリソースに対しての結果のみ有効であり、他のリージョンのリソースに対しての結果は FAILED が返却される。したがって、例えば複数のリージョンでCloudTrailが有効化されており、各リージョンで証跡用およびアクセスログ用のバケットが作成されている場合は、チェック 2.3 および 2.6は非準拠として表示される

チェックは、前回から12時間以内に再度実行 される。また、変更によってトリガーされるチェックに関しては、リソースに変更が変更された際に実行される。

AWSサービスとの統合

Security Hubは、Amazon GuardDutyAmazon InspectorAmazon Macie など、AWSが提供するセキュリティ関連サービスで生成されたセキュリティ検索結果を統合することができる。統合を行うためには、各AWSサービスを有効化する必要がある。

CloudWatchイベントによる自動化

CloudWatchイベントを使用して、Security Hubで検知した問題やリソースの変更に自動的に対応することが可能である。以下の通知を行うことが可能である。

  1. 全ての結果を自動的にCloudWatchイベントに送信
  2. カスタムアクションに関連づけられた結果をCloudWatchイベントに送信
  3. カスタムアクションを使用してインサイトの結果をCloudWatchイベントに送信

1.の場合は、CIS AWS Foundationsコンプライアンスチェックに準拠している状態でも非準拠の場合でも、全ての結果が CloudWatch Events に送信されてしまうので、そのうち 準拠から非準拠となった状態のイベントのみを受信して、Amazon SNS に送信する場合は、以下のような Amazon CloudWatch Events を作成する。

  CloudWatchEventsForSecurityHub:
    Type: AWS::Events::Rule
    Properties: 
      Description: CloudWatch Events about SecurityHub.
      EventPattern:
        source:
          - aws.securityhub
        detail-type: 
          - Security Hub Findings - Imported
        # Events fired when status has been changed from PASSED to ARCHIVED.
        detail:
          findings:
            Compliance:
              Status:
                - PASSED
            RecordState:
              - ARCHIVED
      Name: AWS_Security_Hub
      State: ENABLED
      Targets:
        - Arn: !Ref SnsTopicARN
          Id: CloudWatchEventsForSecurityHub

これは、結果のステータスが PASSED から FAILED に変化した場合、

  1. 既存の結果のステータスを PASSED から ARCHIVED に設定
  2. 結果のステータスが FAILE である新たな結果を生成

という挙動となるため、1.の挙動のみを検知することで実現している。

CloudFormation Launch Stack URL

以下のボタンから上のCloudFormationテンプレートを実行することが可能である。ソースコードは、aws-cloudformation-templates/security – GitHub にて公開。

作成されるAWSサービス CloudFormationテンプレート
セキュリティサービス全般 cloudformation-launch-stack
Security Hub のみ cloudformation-launch-stack