🏛️

AWS BLEAの詳細を構成図ベースで解説してみる

に公開

概要

AWS BLEAのStandAlone版で作成されるリソース間の関係を構成図を用いて解説していきます。
AWS BLEAってなに?という方は公式の記事をご確認いただければと思います。

https://aws.amazon.com/jp/blogs/news/announcing-baseline-environment-on-aws/

全体構成図

BLEAでは以下の構成図に示されたセキュリティサービスにより、監視・通知・ログ保管がなされます。(IAM、KMSは構成図から省略しています)

詳細を解説するにあたって、説明の都合上、以下のような二つのパートに分けます。
青枠の領域が各パートでの該当範囲となります。

  1. CloudTrail, CloudWatch編

  2. Config, Security Hub, GuardDuty, Health Dashboard編

CloudTrail, CloudWatch編

AWS APIコールを監視する部分にフォーカスして詳細を確認していきます。
CloudTrailで管理しているAPIコールログを監視する方法として主に以下の二つがあります。

  • CloudTrail→EventBridge→SNS
  • CloudTrail→CloudWatch Logs→CloudWatch Alarm→SNS

後者を使用するとCloudWatch Logsを経由する分の余計な費用や遅延が発生してしまうため、BLEAでは基本的には前者を使用しています。しかし、IAMイベントはus-east-1で発生するため、BLEAをデプロイしたリージョンのEventBridgeではIAMイベントを拾ってくることができません。(us-east-1にBLEAをデプロイするのであれば問題はないですが...)
そこで、IAMイベントを監視するために、APIコールログをCloudWatch Logsに配信するという後者の設計も同時に採用されています。

https://dev.classmethod.jp/articles/check-iam-operation-by-aws-cloudtrail/

構成図

CloudTrail

CloudTrail証跡が作成され、CloudWatch Logsへの配信も有効化されています。また、ログファイルのKMS暗号化も有効となっており、カスタマー管理CMKに適用するキーポリシーも定義されています。

lib/construct/logging.ts
new trail.Trail(this, 'CloudTrail', {
  bucket: cloudTrailBucket,
  enableFileValidation: true,
  includeGlobalServiceEvents: true,
  cloudWatchLogGroup: cloudTrailLogGroup,
  encryptionKey: cloudTrailKey,
  sendToCloudWatchLogs: true,
});

S3

APIコール監視の文脈では以下に示す二つのS3バケットが作成されます。また、これらのS3バケットに適用するバケットポリシーも定義されます。

CloudTrailLogBucket
証跡ログを格納する用のS3バケットです。

lib/construct/logging.ts
const cloudTrailBucket = new s3.Bucket(this, 'CloudTrailBucket', {
  accessControl: s3.BucketAccessControl.PRIVATE,
  blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
  versioned: true,
  serverAccessLogsBucket: cloudTrailAccessLogBucket,
  serverAccessLogsPrefix: 'cloudtraillogs',
  removalPolicy: cdk.RemovalPolicy.RETAIN,
  enforceSSL: true,
});

CloudTrailAccessLogBucket
CloudTrailLogBucketのアクセスログ取得用のS3バケットです。オブジェクトを90日後にS3 Glacier Flexible Retrievalに移行させ、2555日後に削除するライフサイクルルールが適用されています。

lib/construct/logging.ts
const cloudTrailAccessLogBucket = new s3.Bucket(this, 'CloudTrailAccessLogBucket', {
  blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
  versioned: true,
  encryption: s3.BucketEncryption.S3_MANAGED,
  removalPolicy: cdk.RemovalPolicy.RETAIN,
  enforceSSL: true,
  lifecycleRules: [
    {
      enabled: true,
      expiration: cdk.Duration.days(2555),
      transitions: [
        {
          transitionAfter: cdk.Duration.days(90),
          storageClass: s3.StorageClass.GLACIER,
        },
      ],
    },
  ],
});

EventBridge

前述の通り、BLEAではIAMイベント以外はEventBridgeを用いて監視する設計となっています。そのために、以下に示す三つのEventBridgeルールが作成されます。全てのルールで同一のSNSトピックをターゲットとして指定し、メール通知・Slack通知を実現しています。

SgChangeEventRule
SGに対するインバウンドルールの追加・削除、アウトバウンドルールの追加・削除が発生した際に通知するルールです。

lib/construct/detection.ts
new cwe.Rule(this, 'SgChangedEventRule', {
  description: 'Notify to create, update or delete a Security Group.',
  enabled: true,
  eventPattern: {
    source: ['aws.ec2'],
    detailType: ['AWS API Call via CloudTrail'],
    detail: {
      eventSource: ['ec2.amazonaws.com'],
      eventName: [
        'AuthorizeSecurityGroupIngress',
        'AuthorizeSecurityGroupEgress',
        'RevokeSecurityGroupIngress',
        'RevokeSecurityGroupEgress',
      ],
    },
  },
  targets: [new cwet.SnsTopic(topic)],
});

NetworkAclChangeEventRule
NACLの作成・削除、NACLエントリの追加・削除・置換、NACLを関連付けるサブネットの変更が発生した際に通知するルールです。

lib/construct/detection.ts
new cwe.Rule(this, 'NetworkAclChangeEventRule', {
  description: 'Notify to create, update or delete a Network ACL.',
  enabled: true,
  eventPattern: {
    source: ['aws.ec2'],
    detailType: ['AWS API Call via CloudTrail'],
    detail: {
      eventSource: ['ec2.amazonaws.com'],
      eventName: [
        'CreateNetworkAcl',
        'CreateNetworkAclEntry',
        'DeleteNetworkAcl',
        'DeleteNetworkAclEntry',
        'ReplaceNetworkAclEntry',
        'ReplaceNetworkAclAssociation',
      ],
    },
  },
  targets: [new cwet.SnsTopic(topic)],
});

CloudTrailChangeEventRule
ログ記録の停止、CloudTrailの設定変更、証跡の削除が発生した際に通知するルールです。

lib/construct/detection.ts
new cwe.Rule(this, 'CloudTrailChangeEventRule', {
  description: 'Notify to change on CloudTrail log configuration',
  enabled: true,
  eventPattern: {
    detailType: ['AWS API Call via CloudTrail'],
    detail: {
      eventSource: ['cloudtrail.amazonaws.com'],
      eventName: ['StopLogging', 'DeleteTrail', 'UpdateTrail'],
    },
  },
  targets: [new cwet.SnsTopic(topic)],
});

CloudWatch Logs (Metrics Filter)

APIコールログをCloudWatch Logsロググループに配信し、メトリクスフィルタの適用・CloudWatch Alarmの設定を実施することでIAMイベントを監視します。具体的には、以下に示すような四つのメトリクスフィルタに合致するイベントを検出した場合に通知をおこないます。(CloudWatch Alarmは基本的に一回でもメトリクスフィルタに合致するイベントが発生した時点でアラーム発報するというシンプルな設定のため、詳細は割愛します)

IAMPolicyChangeFilter
インラインポリシの追加・削除、IAMポリシの作成・削除、IAMポリシのアタッチ・デタッチ、IAMポリシの新しいバージョンの作成・削除が発生した際に、メトリクスを発行するメトリクスフィルタです。

lib/construct/detection.ts
const mfIAMPolicyChange = new cwl.MetricFilter(this, 'IAMPolicyChangeFilter', {
  logGroup: cloudTrailLogGroup,
  filterPattern: {
    logPatternString:
      '{($.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)}',
  },
  metricNamespace: 'CloudTrailMetrics',
  metricName: 'IAMPolicyEventCount',
  metricValue: '1',
});

UnauthorizedAttemptsFilter
AWS環境でのアクセス拒否エラーが発生した際に、メトリクスを発行するメトリクスフィルタです。

lib/construct/detection.ts
const unauthorizedAttemptsFilter = new cwl.MetricFilter(this, 'UnauthorizedAttemptsFilter', {
  logGroup: cloudTrailLogGroup,
  filterPattern: {
    // Exclude calls “Decrypt" event by config.amazonaws.com to ignore innocuous errors caused by AWS Config.
    // That error occurs if you have KMS (CMK) encrypted environment variables in Lambda function.
    logPatternString:
      '{($.errorCode = "*UnauthorizedOperation" || $.errorCode = "AccessDenied*") && ($.eventName != "Decrypt" || $.userIdentity.invokedBy != "config.amazonaws.com" )}',
  },
  metricNamespace: 'CloudTrailMetrics',
  metricName: 'UnauthorizedAttemptsEventCount',
  metricValue: '1',
});

NewAccessKeyCreatedFilter
IAMユーザのアクセスキーが作成された際に、メトリクスを発行するメトリクスフィルタです。

lib/construct/detection.ts
const newAccessKeyCreatedFilter = new cwl.MetricFilter(this, 'NewAccessKeyCreatedFilter', {
  logGroup: cloudTrailLogGroup,
  filterPattern: {
    logPatternString: '{($.eventName=CreateAccessKey)}',
  },
  metricNamespace: 'CloudTrailMetrics',
  metricName: 'NewAccessKeyCreatedEventCount',
  metricValue: '1',
});

RootUserActivityFilter
Rootユーザによる操作が行われた際に、メトリクスを発行するメトリクスフィルタです。

lib/construct/detection.ts
const rootUserActivityFilter = new cwl.MetricFilter(this, 'RootUserActivityFilter', {
  logGroup: cloudTrailLogGroup,
  filterPattern: {
    logPatternString:
      '{$.userIdentity.type="Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType !="AwsServiceEvent"}',
  },
  metricNamespace: 'CloudTrailMetrics',
  metricName: 'RootUserPolicyEventCount',
  metricValue: '1',
});

Config, Security Hub, GuardDuty, Health Dashboard編

Config、Securityhub、GuardDuty、Health Dashboardによる評価をもとに、AWS環境を監視する部分の詳細を確認していきます。

構成図

Config

設定レコーダ(ConfigRecorder)とConfigに適用するIAMロールを定義することで、AWSリソースの設定を継続的に記録・評価します。Configにより管理されるリソース追跡ログはConfigBucketに配信されます。

ConfigRecorder
このリージョンで現在および将来サポートされるすべてのリソースタイプに加えて、IAMなどのAWSグローバルサービスも対象としています。

lib/construct/logging.ts
new config.CfnConfigurationRecorder(this, 'ConfigRecorder', {
  roleArn: configRole.roleArn,
  recordingGroup: {
    allSupported: true,
    includeGlobalResourceTypes: true,
  },
});

ConfigBucket

lib/construct/logging.ts
const configBucket = new s3.Bucket(this, 'ConfigBucket', {
  accessControl: s3.BucketAccessControl.PRIVATE,
  blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
  versioned: true,
  removalPolicy: cdk.RemovalPolicy.RETAIN,
  encryption: s3.BucketEncryption.S3_MANAGED,
  enforceSSL: true,
});

Configルールとして、デフォルトSGに一つ以上のインバウンドルール・アウトバウンドルールが存在する場合に非準拠となるDefaultSgClosedRuleが作成されます。

DefaultSgClosedRule
vpc-default-security-group-closedというAWS マネージド型のConfigルールが選択されています。

lib/construct/detection.ts
const defaultSgClosedRule = new config.ManagedRule(this, 'DefaultSgClosedRule', {
  identifier: config.ManagedRuleIdentifiers.VPC_DEFAULT_SECURITY_GROUP_CLOSED,
  ruleScope: config.RuleScope.fromResources([config.ResourceType.EC2_SECURITY_GROUP]),
  configRuleName: 'bb-default-security-group-closed',
  description:
    'Checks that the default security group of any VPC does not allow inbound or outbound traffic. The rule is non-compliant if the default security group has one or more inbound or outbound traffic.',
});

上記Configルールが非準拠になると、以下に示すDefaultSgClosedEventRuleというEventBridgeルールにより通知します。

DefaultSgClosedEventRule

lib/construct/detection.ts
new cwe.Rule(this, 'DefaultSgClosedEventRule', {
  description: 'CloudWatch Event Rule to send notification on Config Rule compliance changes.',
  enabled: true,
  eventPattern: {
    source: ['aws.config'],
    detailType: ['Config Rules Compliance Change'],
    detail: {
      configRuleName: ['bb-default-security-group-closed'],
      newEvaluationResult: {
        complianceType: ['NON_COMPLIANT'],
      },
    },
  },
  targets: [new cwet.SnsTopic(topic)],
});

また、非準拠となった場合の修復アクションとしてDefaultSgRemediationが作成されています。この修復アクションにより、デフォルトSGに一つ以上のインバウンドルール・アウトバウンドルールが存在する場合に、デフォルトSGの全てのルールが削除されます。

DefaultSgRemediation
AWSConfigRemediation-RemoveVPCDefaultSecurityGroupRulesというSSMドキュメントが選択されており、SSM Automationにより自動的に修復されます。

lib/construct/detection.ts
new config.CfnRemediationConfiguration(this, 'DefaultSgRemediation', {
  configRuleName: defaultSgClosedRule.configRuleName,
  targetType: 'SSM_DOCUMENT',
  targetId: 'AWSConfigRemediation-RemoveVPCDefaultSecurityGroupRules',
  targetVersion: '1',
  parameters: {
    AutomationAssumeRole: {
      StaticValue: {
        Values: [defaultSgRemediationRole.roleArn],
      },
    },
    GroupId: {
      ResourceValue: {
        Value: 'RESOURCE_ID',
      },
    },
  },
  automatic: true,
  maximumAutomaticAttempts: 5,
  retryAttemptSeconds: 60,
});

Security Hub

「AWS基礎セキュリティのベストプラクティス」と「CIS AWS Foundations Benchmark」という二つのセキュリティ基準からの逸脱検知をおこないます。以下のEventBridgeルールが定義されており、逸脱を検知した場合に通知します。

SecurityHubEventRule
「重要度」が 'CRITICAL' か 'HIGH' 、「コンプライアンスのステータス」が 'FAILED' 、「ワークフローのステータス」が 'NEW' か 'NOTIFIED'、「レコードの状態」が 'ACTIVE' の場合に通知します。つまり、基準に非準拠であり、重要度が高いもののうち、レビューが実施されていないものが存在する場合に通知します。

lib/construct/detection.ts
new cwe.Rule(this, 'SecurityHubEventRule', {
  description: 'CloudWatch Event Rule to send notification on SecurityHub all new findings and all updates.',
  enabled: true,
  eventPattern: {
    source: ['aws.securityhub'],
    detailType: ['Security Hub Findings - Imported'],
    detail: {
      findings: {
        Severity: {
          Label: ['CRITICAL', 'HIGH'],
        },
        Compliance: {
          Status: ['FAILED'],
        },
        Workflow: {
          Status: ['NEW', 'NOTIFIED'],
        },
        RecordState: ['ACTIVE'],
      },
    },
  },
  targets: [new cwet.SnsTopic(topic)],
});

GuardDuty

GuardDutyを有効化することで、脅威検出・異常な振る舞い検知をおこないます。
以下のようなEventBridgeルールが定義されており、重要度が「高」「中」(Severity:4.0~8.9)の場合に通知します。

GuardDutyEventRule

lib/construct/detection.ts
new cwe.Rule(this, 'GuardDutyEventRule', {
  description: 'CloudWatch Event Rule to send notification on GuardDuty findings.',
  enabled: true,
  eventPattern: {
    source: ['aws.guardduty'],
    detailType: ['GuardDuty Finding'],
    detail: {
      severity: [
        4, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6,
        6.0, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7, 7.0, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8,
        8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9,
      ],
    },
  },
  targets: [new cwet.SnsTopic(topic)],
});

Health Dashboard

以下に示すEventBridgeルールにより、全てのAWS Healthイベントが通知されます。

AwsHealthEventRule

lib/construct/detection.ts
new cwe.Rule(this, 'AwsHealthEventRule', {
  description: 'Notify AWS Health event',
  enabled: true,
  eventPattern: {
    source: ['aws.health'],
    detailType: ['AWS Health Event'],
  },
  targets: [new cwet.SnsTopic(topic)],
});

最後に

BLEAテンプレートはCDKを使用しないプロジェクトにおいても、AWSにおけるセキュリティの基準として活用できると思います。個人的には「とりあえずBLEAを参考にする」くらいの気持ちでいます。

https://github.com/aws-samples/baseline-environment-on-aws/tree/main/usecases/blea-gov-base-standalone

Discussion