コンテンツにスキップ

RDS.46

検証日: 2026-04-30 / リージョン: ap-northeast-1

コントロールの説明

RDS DB インスタンスがパブリックサブネット(IGW へのルートがあるサブネット)にデプロイされていないかをチェックする。サブネットのルートテーブルに 0.0.0.0/0 または ::/0 宛の IGW ルートが存在する場合に FAILED となる。

RDS.2(PubliclyAccessible フラグ)とは異なり、本コントロールはサブネットのルートテーブルを評価する。実際にインターネットから RDS インスタンスにアクセスできるのは、パブリックサブネット配置(RDS.46 FAILED)かつ PubliclyAccessible=true(RDS.2 FAILED)の両方が揃った場合である。片方だけ FAILED の場合、インターネットからの到達は防がれている。

状態RDS.2(PubliclyAccessible)RDS.46(サブネット)インターネットからのアクセス
両方 FAILEDtrueパブリックサブネット可能
RDS.2 のみ PASSEDfalseパブリックサブネット不可
RDS.46 のみ PASSEDtrueプライベートサブネット不可
両方 PASSEDfalseプライベートサブネット不可

対応する Config ルール: RDS_INSTANCE_SUBNET_IGW_CHECK(評価頻度: Periodic)

検証環境

検証環境の構成図

--profile 指定がない場合は Workload アカウントで実行する。export AWS_PROFILE=Workload でデフォルトを設定しておくと便利。

結果

  • RDS DB インスタンスが存在しない場合は PASSED
  • パブリックサブネット(IGW へのルートがあるサブネット)に配置すると FAILED。PubliclyAccessible=false でも FAILED になる(サブネットのルートテーブルのみを評価するため)
  • インスタンスを削除すると PASSED に復帰
  • デフォルトではパブリックサブネットへの配置は保護されていない(デフォルト VPC の DB サブネットグループはパブリックサブネットのみで構成される)

検証の流れ

    flowchart LR
    A[1. デフォルト状態の確認<br>PASSED] --> B[2. パブリックサブネットに<br>RDS インスタンス起動]
    B --> C[3. FAILED 確認]
    C --> D[4. インスタンス削除]
    D --> E[5. PASSED 復帰確認]
  

1. デフォルト状態の確認

デフォルト VPC のルートテーブル確認

デフォルト VPC のルートテーブルに IGW へのルートがあることを確認する。

aws ec2 describe-route-tables \
  --filters Name=vpc-id,Values=<デフォルト VPC ID> \
  --query 'RouteTables[].{RouteTableId:RouteTableId,Routes:Routes[?DestinationCidrBlock==`0.0.0.0/0`].{Dest:DestinationCidrBlock,GatewayId:GatewayId}}' \
  --region ap-northeast-1
[
    {
        "RouteTableId": "<ルートテーブル ID>",
        "Routes": [
            {
                "Dest": "0.0.0.0/0",
                "GatewayId": "<IGW ID>"
            }
        ]
    }
]

DB サブネットグループの確認

RDS インスタンスは個別のサブネットではなく、DB サブネットグループを指定して起動する。DB サブネットグループは 2 つ以上の AZ のサブネットを含むグループで、RDS はこの中からサブネットを選んで配置する。デフォルト VPC には default という DB サブネットグループが自動作成されており、VPC 内の全サブネットが含まれる。

aws rds describe-db-subnet-groups \
  --db-subnet-group-name default \
  --query 'DBSubnetGroups[].{Name:DBSubnetGroupName,VpcId:VpcId,Subnets:Subnets[].SubnetIdentifier}' \
  --region ap-northeast-1
[
    {
        "Name": "default",
        "VpcId": "<デフォルト VPC ID>",
        "Subnets": [
            "<サブネット ID 1>",
            "<サブネット ID 2>",
            "<サブネット ID 3>"
        ]
    }
]

すべてのサブネットが、先ほど確認した IGW へのルートを持つルートテーブルに関連付けられている。RDS.46 はサブネットのルートテーブルに IGW ルートがあるかをチェックするため、どのサブネットに配置されても FAILED になる。

Security Hub finding の確認

aws securityhub get-findings \
  --filters '{
    "ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "RDS.46"}],
    "AwsAccountId": [{"Comparison": "EQUALS", "Value": "<アカウント ID>"}],
    "WorkflowStatus": [{"Comparison": "NOT_EQUALS", "Value": "SUPPRESSED"}],
    "RecordState": [{"Comparison": "EQUALS", "Value": "ACTIVE"}]
  }' \
  --query 'Findings[].{Status:Compliance.Status,ResourceId:Resources[0].Id}' \
  --region ap-northeast-1
[
    {
        "Status": "PASSED",
        "ResourceId": "AWS::::Account:<アカウント ID>"
    },
    {
        "Status": "PASSED",
        "ResourceId": "AWS::::Account:<アカウント ID>"
    }
]

RDS DB インスタンスが存在しないため PASSED。2 件返るのは、東京リージョンの Security Hub finding と、集約リージョン(ap-southeast-1)から転送された finding がそれぞれ存在するためである。

2. パブリックサブネットに RDS インスタンス起動

デフォルト VPC の DB サブネットグループ(default)を使用する。全サブネットが IGW へのルートを持つパブリックサブネットである。

aws rds create-db-instance \
  --db-instance-identifier rds46-test \
  --db-instance-class db.t3.micro \
  --engine mysql \
  --master-username admin \
  --master-user-password '<パスワード>' \
  --allocated-storage 20 \
  --no-publicly-accessible \
  --db-subnet-group-name default \
  --no-multi-az \
  --query 'DBInstance.{DBInstanceIdentifier:DBInstanceIdentifier,DBInstanceStatus:DBInstanceStatus,PubliclyAccessible:PubliclyAccessible}' \
  --region ap-northeast-1
{
    "DBInstanceIdentifier": "rds46-test",
    "DBInstanceStatus": "creating",
    "PubliclyAccessible": false
}
--no-publicly-accessible を指定している。RDS.46 はサブネットのルートテーブルを評価するため、PubliclyAccessible の値に関係なく FAILED になるはずである。

available 確認

RDS インスタンスの起動には数分かかる。

aws rds describe-db-instances \
  --db-instance-identifier rds46-test \
  --query 'DBInstances[].{DBInstanceIdentifier:DBInstanceIdentifier,DBInstanceStatus:DBInstanceStatus,AvailabilityZone:AvailabilityZone}' \
  --region ap-northeast-1
[
    {
        "DBInstanceIdentifier": "rds46-test",
        "DBInstanceStatus": "available",
        "AvailabilityZone": "<AZ>"
    }
]

3. FAILED 確認

Config ルールの手動トリガー

aws configservice start-config-rules-evaluation \
  --config-rule-names securityhub-rds-instance-subnet-igw-check-<サフィックス> \
  --region ap-northeast-1
(出力なし)

Config 評価結果の確認

Config の RDS リソース ID は DB インスタンス識別子ではなく内部 ID(DbiResourceId)が使われる。list-discovered-resources で確認できる。

aws configservice list-discovered-resources \
  --resource-type AWS::RDS::DBInstance \
  --region ap-northeast-1
{
    "resourceIdentifiers": [
        {
            "resourceType": "AWS::RDS::DBInstance",
            "resourceId": "<Config リソース ID>",
            "resourceName": "rds46-test"
        }
    ]
}
aws configservice get-compliance-details-by-config-rule \
  --config-rule-name securityhub-rds-instance-subnet-igw-check-<サフィックス> \
  --query 'EvaluationResults[?EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId==`<Config リソース ID>`].{ResourceId:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType:ComplianceType}' \
  --region ap-northeast-1
[
    {
        "ResourceId": "<Config リソース ID>",
        "ComplianceType": "NON_COMPLIANT"
    }
]

Security Hub finding の FAILED 確認

aws securityhub get-findings \
  --filters '{
    "ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "RDS.46"}],
    "AwsAccountId": [{"Comparison": "EQUALS", "Value": "<アカウント ID>"}],
    "WorkflowStatus": [{"Comparison": "NOT_EQUALS", "Value": "SUPPRESSED"}],
    "RecordState": [{"Comparison": "EQUALS", "Value": "ACTIVE"}]
  }' \
  --query 'Findings[].{Status:Compliance.Status,ResourceId:Resources[0].Id}' \
  --region ap-northeast-1
[
    {
        "Status": "FAILED",
        "ResourceId": "arn:aws:rds:ap-northeast-1:<アカウント ID>:dbinstance/<Config リソース ID>"
    },
    {
        "Status": "PASSED",
        "ResourceId": "AWS::::Account:<アカウント ID>"
    }
]

4. インスタンス削除

aws rds delete-db-instance \
  --db-instance-identifier rds46-test \
  --skip-final-snapshot \
  --query 'DBInstance.{DBInstanceIdentifier:DBInstanceIdentifier,DBInstanceStatus:DBInstanceStatus}' \
  --region ap-northeast-1
{
    "DBInstanceIdentifier": "rds46-test",
    "DBInstanceStatus": "deleting"
}

削除完了確認

aws rds describe-db-instances \
  --db-instance-identifier rds46-test \
  --query 'DBInstances[].{DBInstanceStatus:DBInstanceStatus}' \
  --region ap-northeast-1
An error occurred (DBInstanceNotFound) when calling the DescribeDBInstances operation: DBInstance rds46-test not found.

5. PASSED 復帰確認

Config ルールの手動トリガー

aws configservice start-config-rules-evaluation \
  --config-rule-names securityhub-rds-instance-subnet-igw-check-<サフィックス> \
  --region ap-northeast-1
(出力なし)

Security Hub finding の PASSED 確認

aws securityhub get-findings \
  --filters '{
    "ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "RDS.46"}],
    "AwsAccountId": [{"Comparison": "EQUALS", "Value": "<アカウント ID>"}],
    "WorkflowStatus": [{"Comparison": "NOT_EQUALS", "Value": "SUPPRESSED"}],
    "RecordState": [{"Comparison": "EQUALS", "Value": "ACTIVE"}]
  }' \
  --query 'Findings[].{Status:Compliance.Status,ResourceId:Resources[0].Id}' \
  --region ap-northeast-1
[
    {
        "Status": "PASSED",
        "ResourceId": "AWS::::Account:<アカウント ID>"
    }
]

補足:Config ルール名の確認方法

aws configservice describe-config-rules \
  --query 'ConfigRules[?contains(Source.SourceIdentifier,`RDS_INSTANCE_SUBNET_IGW_CHECK`)].ConfigRuleName' \
  --region ap-northeast-1

Amazonアソシエイトリンク