Closed8

AWS Security Hub と AWS Config を Terraform で管理する

ueshouesho

AWS Security HubでベストプラクティスのチェックやCIS Benchmarksのチェックを行いたい。
しかし、Security Hubの有効化だけでは以下のエラーが発生してしまう。AWS Configの設定が必要。

The security score cannot be calculated until AWS Config is enabled and resource recording is configured.

ueshouesho

自分はConfigを現状SecurityHub以外の用途で使う予定がないので、以下の記事を元に必要なものだけ適用させたい。

Optimizing AWS Config for Security Hub
Recording global resources as well as current and future resources in AWS Config is more than what is necessary to enable Security Hub controls. If you’re using the configuration recorder only for Security Hub controls, and you want to cost optimize your use of AWS Config or reduce the amount of data produced, stored, and analyzed by AWS Config, you only need to record the configurations of approximately 60 resource types, as described in AWS Config resources required to generate control findings.

日本語訳:
AWS ConfigをSecurity Hubに最適化する
AWS Configにグローバルリソースだけでなく、現在および将来のリソースを記録することは、Security Hubの制御を有効にするために必要な以上のことです。構成レコーダーをSecurity Hubコントロールのためだけに使用し、AWS Configの使用をコスト的に最適化したり、AWS Configによって生成、保存、分析されるデータ量を減らしたい場合は、コントロールの調査結果を生成するために必要なAWS Configリソースで説明されているように、約60種類のリソースの構成を記録するだけでよい。

https://aws.amazon.com/blogs/security/optimize-aws-config-for-aws-security-hub-to-effectively-manage-your-cloud-security-posture/

ueshouesho

まずAWS Configについて整理する。
https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/WhatIsConfig.html

Rules

AWS Config マネージドルール とカスタムルールがある。
今回はマネージドルールだけ構築していく。

Resources (Configuration recorder)

リソース設定の変更を検出し、これらの変更を設定項目としてキャプチャできる。
https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/stop-start-recorder.html

コントロールの調査結果を生成するために必要なAWS Configリソースで説明されているように、約60種類のリソースの構成を記録するだけでよい。

SecurityHubに必要なリソースだけを記録するようにconfiguration recorderを作るのが良さそう。

Conformance Packs (適合パック)

Cofigルールと修復アクションがパックで管理されているもの。
とても便利そう。しかし、私たちはTerraformで管理しているので修復パックで直すと管理できなくなるので適合パックは使わないでいく。

Aggregators

マルチアカウント、マルチリージョンのデータ集約で使用する。
今回は単一アカウント、リージョンなので使用しないで良さそう。

ueshouesho

AWS::Config::ResourceComplianceこのリストに入っていないので、関係なさそう。

コストに関する考慮事項
リソースの記録に関連するコストの詳細については、「AWS Security Hub の料金」と「AWS Config の料金」を参照してください。

Security Hub は、 AWS Config 設定項目を更新することで、AWS::Config::ResourceCompliance設定レコーダーのコストに影響を与える可能性があります。更新は、 AWS Config ルールに関連付けられた Security Hub コントロールがコンプライアンス状態を変更するか、有効または無効になるか、パラメータを更新するたびに発生する可能性があります。 AWS Config 設定レコーダーを Security Hub にのみ使用し、この設定項目を他の目的で使用しないときは、 AWS Config コンソールまたは で記録をオフにすることをお勧めします AWS CLI。これにより、 AWS Config コストを削減できます。Security Hub でセキュリティチェックを行うために AWS::Config::ResourceCompliance を記録する必要はありません。

https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-setup-prereqs.html

ueshouesho

最終的に以下のようになった。

# Security Hub
resource "aws_securityhub_account" "securityhub" {}

# Config
resource "aws_iam_role" "config_recorder_role" {
  name = "ConfigRecorderRole"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Service = "config.amazonaws.com"
        }
        Action = "sts:AssumeRole"
      },
    ]
  })

  managed_policy_arns = [
    "arn:aws:iam::aws:policy/service-role/AWS_ConfigRole"
  ]
}

resource "aws_config_configuration_recorder" "config_recorder" {
  name     = "ConfigRecorderForSecurityHub"
  role_arn = aws_iam_role.config_recorder_role.arn

  recording_group {
    all_supported = false
    resource_types = [
      "AWS::ACM::Certificate",
      "AWS::ApiGateway::Stage",
      "AWS::ApiGatewayV2::Stage",
      "AWS::AppSync::GraphQLApi",
      "AWS::AutoScaling::AutoScalingGroup",
      "AWS::AutoScaling::LaunchConfiguration",
      "AWS::CloudFormation::Stack",
      "AWS::CloudFront::Distribution",
      "AWS::CloudWatch::Alarm",
      "AWS::CodeBuild::Project",
      "AWS::DynamoDB::Table",
      "AWS::EC2::EIP",
      "AWS::EC2::Instance",
      "AWS::EC2::LaunchTemplate",
      "AWS::EC2::NetworkAcl",
      "AWS::EC2::NetworkInterface",
      "AWS::EC2::SecurityGroup",
      "AWS::EC2::Subnet",
      "AWS::EC2::TransitGateway",
      "AWS::EC2::VPNConnection",
      "AWS::EC2::Volume",
      "AWS::ECR::Repository",
      "AWS::ECS::Cluster",
      "AWS::ECS::Service",
      "AWS::ECS::TaskDefinition",
      "AWS::EFS::AccessPoint",
      "AWS::EKS::Cluster",
      "AWS::ElasticBeanstalk::Environment",
      "AWS::ElasticLoadBalancing::LoadBalancer",
      "AWS::ElasticLoadBalancingV2::LoadBalancer",
      "AWS::Elasticsearch::Domain",
      "AWS::IAM::Group",
      "AWS::IAM::Policy",
      "AWS::IAM::Role",
      "AWS::IAM::User",
      "AWS::KMS::Key",
      "AWS::Kinesis::Stream",
      "AWS::Lambda::Function",
      "AWS::NetworkFirewall::FirewallPolicy",
      "AWS::NetworkFirewall::RuleGroup",
      "AWS::OpenSearch::Domain",
      "AWS::RDS::DBCluster",
      "AWS::RDS::DBClusterSnapshot",
      "AWS::RDS::DBInstance",
      "AWS::RDS::DBSnapshot",
      "AWS::RDS::EventSubscription",
      "AWS::Redshift::Cluster",
      "AWS::S3::Bucket",
      "AWS::SNS::Topic",
      "AWS::SQS::Queue",
      "AWS::SSM::AssociationCompliance",
      "AWS::SSM::PatchCompliance",
      "AWS::SageMaker::NotebookInstance",
      "AWS::SecretsManager::Secret",
      "AWS::StepFunctions::StateMachine",
      "AWS::WAF::Rule",
      "AWS::WAF::RuleGroup",
      "AWS::WAF::WebACL",
      "AWS::WAFRegional::Rule",
      "AWS::WAFRegional::RuleGroup",
      "AWS::WAFRegional::WebACL",
      "AWS::WAFv2::WebACL",
    ]
  }
}

resource "aws_config_delivery_channel" "config_delivery_channel" {
  name           = "config-delivery-channel"
  s3_bucket_name = aws_s3_bucket.config_bucket.id
  depends_on     = [aws_config_configuration_recorder.config_recorder]
}

resource "aws_config_configuration_recorder_status" "config_recorder_status" {
  name       = aws_config_configuration_recorder.config_recorder.name
  is_enabled = true
  depends_on = [aws_config_configuration_recorder.config_recorder]
}

# S3
resource "aws_s3_bucket" "config_bucket" {
  bucket = var.config_s3_bucket_name
}

resource "aws_s3_bucket_server_side_encryption_configuration" "example" {
  bucket = aws_s3_bucket.config_bucket.bucket

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}


resource "aws_s3_bucket_policy" "config_bucket_policy" {
  bucket = aws_s3_bucket.config_bucket.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "AWSConfigBucketPermissionsCheck"
        Effect = "Allow"
        Principal = {
          Service = "config.amazonaws.com"
        }
        Action   = "s3:GetBucketAcl"
        Resource = aws_s3_bucket.config_bucket.arn
      },
      {
        Sid    = "AWSConfigBucketDelivery"
        Effect = "Allow"
        Principal = {
          Service = "config.amazonaws.com"
        }
        Action   = "s3:PutObject"
        Resource = "${aws_s3_bucket.config_bucket.arn}/AWSLogs/*"
      },
      {
        Sid       = "AWSConfigBucketSecureTransport"
        Effect    = "Deny"
        Principal = "*"
        Action    = "s3:*"
        Resource = [
          aws_s3_bucket.config_bucket.arn,
          "${aws_s3_bucket.config_bucket.arn}/*",
        ]
        Condition = {
          Bool = {
            "aws:SecureTransport" = "false"
          }
        }
      },
    ]
  })
}
このスクラップは2024/03/19にクローズされました