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