コンテンツにスキップ

EC2.9

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

--profile 指定がない場合は Workload アカウントで実行する。export AWS_PROFILE=Workload でデフォルトを設定しておくと便利。Control Tower の有効化・無効化操作(ステップ 6・8)は --profile Master(Organizations 管理アカウント)で実行する。

コントロールの説明

EC2 インスタンスにパブリック IPv4 アドレスが割り当てられていないかをチェックする。インスタンスの設定に publicIp フィールドが存在する場合に FAILED となる。IPv4 のみが対象(IPv6 アドレスのみを持つインスタンスは本コントロールの対象外)。

対応する Config ルール: EC2_INSTANCE_NO_PUBLIC_IP(評価頻度: 変更トリガー)

結果

  • パブリック IP を持つ EC2 インスタンスが存在しない場合は PASSED。ResourceId は AWS::::Account(評価対象リソースなし)
  • パブリック IP 付きインスタンスを起動すると FAILED。ResourceId はインスタンス ARN
  • インスタンスを終了すると PASSED に復帰。ResourceId は再び AWS::::Account に戻る
  • CT.EC2.PV.8(VPC BPA、Declarative Policy 型)を有効化しても finding は FAILED のまま変化しない。VPC BPA はインターネットアクセスをブロックするが、パブリック IP の付与自体は止めないため

検証の流れ

    flowchart LR
    A[1. デフォルト状態の確認<br>PASSED] --> B[2. パブリック IP 付き<br>インスタンス起動]
    B --> C[3. FAILED 確認]
    C --> D[4. インスタンス終了]
    D --> E[5. PASSED 復帰確認]
    E --> F[6. CT.EC2.PV.8 有効化]
    F --> G[7. FAILED のまま変化しないことを確認]
    G --> H[8. クリーンアップ]
  

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

aws securityhub get-findings \
  --filters '{
    "ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "EC2.9"}],
    "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>"
    }
]

パブリック IP を持つインスタンスが存在しないため PASSED。評価対象リソース(インスタンス)が存在しない場合、Config の評価結果は空となり、Security Hub はアカウントレベルの PASSED(AWS::::Account)を返す。インスタンスを起動すると、インスタンス単位の finding が生成される。

2. パブリック IP 付きインスタンス起動

デフォルト VPC のサブネットはパブリック IP の自動割り当てが有効なため、デフォルト VPC で起動する。

デフォルト VPC の確認

aws ec2 describe-vpcs \
  --filters Name=isDefault,Values=true \
  --query 'Vpcs[].{VpcId:VpcId,CidrBlock:CidrBlock}' \
  --region ap-northeast-1
[
    {
        "VpcId": "<デフォルト VPC ID>",
        "CidrBlock": "172.31.0.0/16"
    }
]

デフォルト VPC のサブネット確認

aws ec2 describe-subnets \
  --filters Name=vpc-id,Values=<デフォルト VPC ID> Name=availabilityZone,Values=ap-northeast-1a \
  --query 'Subnets[].{SubnetId:SubnetId,MapPublicIpOnLaunch:MapPublicIpOnLaunch}' \
  --region ap-northeast-1
[
    {
        "SubnetId": "<デフォルトサブネット ID 1>",
        "MapPublicIpOnLaunch": false
    },
    {
        "SubnetId": "<デフォルトサブネット ID 2>",
        "MapPublicIpOnLaunch": true
    }
]

MapPublicIpOnLaunch: true のサブネット(<デフォルトサブネット ID 2>)を使用する。

最新の Amazon Linux 2023 AMI を取得

aws ec2 describe-images \
  --owners amazon \
  --filters Name=name,Values=al2023-ami-2023*-x86_64 Name=state,Values=available \
  --query 'sort_by(Images,&CreationDate)[-1].ImageId' \
  --region ap-northeast-1
"<AMI ID>"

インスタンス起動

aws ec2 run-instances \
  --image-id <AMI ID> \
  --instance-type t3.micro \
  --subnet-id <デフォルトサブネット ID 2> \
  --associate-public-ip-address \
  --query 'Instances[].{InstanceId:InstanceId,State:State.Name,PublicIpAddress:PublicIpAddress}' \
  --region ap-northeast-1
[
    {
        "InstanceId": "<インスタンス ID>",
        "State": "pending",
        "PublicIpAddress": null
    }
]

インスタンスの running 確認

aws ec2 describe-instances \
  --instance-ids <インスタンス ID> \
  --query 'Reservations[].Instances[].{InstanceId:InstanceId,State:State.Name,PublicIpAddress:PublicIpAddress}' \
  --region ap-northeast-1
[
    {
        "InstanceId": "<インスタンス ID>",
        "State": "running",
        "PublicIpAddress": "<パブリック IP アドレス>"
    }
]

3. FAILED 確認

Config ルールの手動トリガー

aws configservice start-config-rules-evaluation \
  --config-rule-names securityhub-ec2-instance-no-public-ip-<サフィックス> \
  --region ap-northeast-1
(出力なし)

Config 評価結果の確認

aws configservice get-compliance-details-by-config-rule \
  --config-rule-name securityhub-ec2-instance-no-public-ip-<サフィックス> \
  --query 'EvaluationResults[?EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId==`<インスタンス ID>`].{ResourceId:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType:ComplianceType}' \
  --region ap-northeast-1
[
    {
        "ResourceId": "<インスタンス ID>",
        "ComplianceType": "NON_COMPLIANT"
    }
]

Security Hub finding の FAILED 確認

aws securityhub get-findings \
  --filters '{
    "ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "EC2.9"}],
    "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:ec2:ap-northeast-1:<アカウント ID>:instance/<インスタンス ID>"
    },
    {
        "Status": "PASSED",
        "ResourceId": "AWS::::Account:<アカウント ID>"
    }
]

インスタンス単位で FAILED が生成される。ResourceId はインスタンス ARN。AWS::::Account の PASSED finding はインスタンスが存在しない状態の finding が別 entity として並存しているもの。

4. インスタンス終了

aws ec2 terminate-instances \
  --instance-ids <インスタンス ID> \
  --query 'TerminatingInstances[].{InstanceId:InstanceId,CurrentState:CurrentState.Name}' \
  --region ap-northeast-1
[
    {
        "InstanceId": "<インスタンス ID>",
        "CurrentState": "shutting-down"
    }
]

terminated 確認

aws ec2 describe-instances \
  --instance-ids <インスタンス ID> \
  --query 'Reservations[].Instances[].{State:State.Name}' \
  --region ap-northeast-1
[
    {
        "State": "terminated"
    }
]

5. PASSED 復帰確認

Config ルールの手動トリガー

aws configservice start-config-rules-evaluation \
  --config-rule-names securityhub-ec2-instance-no-public-ip-<サフィックス> \
  --region ap-northeast-1
(出力なし)

Security Hub finding の PASSED 確認

aws securityhub get-findings \
  --filters '{
    "ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "EC2.9"}],
    "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>"
    }
]

インスタンスを終了すると、インスタンス ARN の FAILED finding は消え、AWS::::Account の PASSED finding のみ残る。これはインスタンスが存在しない状態(評価対象リソースなし)を表すアカウントレベルの finding が別 entity として維持されているものである。

6. CT.EC2.PV.8 有効化

CT.EC2.PV.8 は Declarative Policy 型の予防コントロールであり、VPC BPA を強制する。VPC BPA はインターネットアクセスをブロックするが、パブリック IP の付与自体は止めない。そのため EC2.9 の finding は変化しないはずである。

ステップ 4 でインスタンスを終了して PASSED 復帰を確認した後、改めてインスタンスを起動して FAILED 状態を作成する。「PASSED 復帰確認」と「CT.EC2.PV.8 の影響確認」を独立した検証として切り分けるためである。その後、Security Hub finding が FAILED であることを確認してから CT.EC2.PV.8 を有効化する。

run-instances--security-group-ids を指定しない場合、デフォルト VPC のデフォルトセキュリティグループが使用される。デフォルト SG にはインバウンドルールがないため、パブリック IP が付与されても外部からのアクセスは受けない。

インスタンス起動

aws ec2 run-instances \
  --image-id <AMI ID> \
  --instance-type t3.micro \
  --subnet-id <デフォルトサブネット ID 2> \
  --associate-public-ip-address \
  --query 'Instances[].{InstanceId:InstanceId,State:State.Name,PublicIpAddress:PublicIpAddress}' \
  --region ap-northeast-1
[
    {
        "InstanceId": "<インスタンス ID 2>",
        "State": "pending",
        "PublicIpAddress": null
    }
]

インスタンスの running 確認

aws ec2 describe-instances \
  --instance-ids <インスタンス ID 2> \
  --query 'Reservations[].Instances[].{InstanceId:InstanceId,State:State.Name,PublicIpAddress:PublicIpAddress}' \
  --region ap-northeast-1
[
    {
        "InstanceId": "<インスタンス ID 2>",
        "State": "running",
        "PublicIpAddress": "<パブリック IP アドレス>"
    }
]

Config ルールの手動トリガーと FAILED 確認

aws configservice start-config-rules-evaluation \
  --config-rule-names securityhub-ec2-instance-no-public-ip-<サフィックス> \
  --region ap-northeast-1
(出力なし)
aws configservice get-compliance-details-by-config-rule \
  --config-rule-name securityhub-ec2-instance-no-public-ip-<サフィックス> \
  --query 'EvaluationResults[?EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId==`<インスタンス ID 2>`].{ResourceId:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType:ComplianceType}' \
  --region ap-northeast-1
[
    {
        "ResourceId": "<インスタンス ID 2>",
        "ComplianceType": "NON_COMPLIANT"
    }
]

Security Hub finding の FAILED 確認

aws securityhub get-findings \
  --filters '{
    "ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "EC2.9"}],
    "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:ec2:ap-northeast-1:<アカウント ID>:instance/<インスタンス ID 2>"
    },
    {
        "Status": "PASSED",
        "ResourceId": "AWS::::Account:<アカウント ID>"
    }
]

CT.EC2.PV.8 有効化

aws controltower enable-control \
  --control-identifier arn:aws:controlcatalog:::control/acfp8qjz7eggnursu5pfw7q2w \
  --target-identifier <OU の ARN> \
  --region ap-northeast-1 --profile Master
{
    "arn": "<有効化 ARN>",
    "operationIdentifier": "<オペレーション ID>"
}
aws controltower get-control-operation \
  --operation-identifier <オペレーション ID> \
  --query 'controlOperation.{operationType:operationType,status:status}' \
  --region ap-northeast-1 --profile Master
{
    "operationType": "ENABLE_CONTROL",
    "status": "SUCCEEDED"
}

7. FAILED のまま変化しないことを確認

Config ルールの手動トリガー

aws configservice start-config-rules-evaluation \
  --config-rule-names securityhub-ec2-instance-no-public-ip-<サフィックス> \
  --region ap-northeast-1
(出力なし)

Config 評価結果の確認(NON_COMPLIANT のまま)

aws configservice get-compliance-details-by-config-rule \
  --config-rule-name securityhub-ec2-instance-no-public-ip-<サフィックス> \
  --query 'EvaluationResults[?EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId==`<インスタンス ID 2>`].{ResourceId:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType:ComplianceType}' \
  --region ap-northeast-1
[
    {
        "ResourceId": "<インスタンス ID 2>",
        "ComplianceType": "NON_COMPLIANT"
    }
]

VPC BPA はパブリック IP の付与自体を止めないため、インスタンスにはパブリック IP が割り当てられたままとなり、finding は NON_COMPLIANT のまま変化しない。

Security Hub finding の確認(FAILED のまま)

aws securityhub get-findings \
  --filters '{
    "ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "EC2.9"}],
    "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:ec2:ap-northeast-1:<アカウント ID>:instance/<インスタンス ID 2>"
    },
    {
        "Status": "PASSED",
        "ResourceId": "AWS::::Account:<アカウント ID>"
    }
]

8. クリーンアップ

CT.EC2.PV.8 の無効化

aws controltower disable-control \
  --control-identifier arn:aws:controlcatalog:::control/acfp8qjz7eggnursu5pfw7q2w \
  --target-identifier <OU の ARN> \
  --region ap-northeast-1 --profile Master
{
    "operationIdentifier": "<オペレーション ID>"
}
aws controltower get-control-operation \
  --operation-identifier <オペレーション ID> \
  --query 'controlOperation.{operationType:operationType,status:status}' \
  --region ap-northeast-1 --profile Master
{
    "operationType": "DISABLE_CONTROL",
    "status": "SUCCEEDED"
}

インスタンス終了

aws ec2 terminate-instances \
  --instance-ids <インスタンス ID 2> \
  --query 'TerminatingInstances[].{InstanceId:InstanceId,CurrentState:CurrentState.Name}' \
  --region ap-northeast-1
[
    {
        "InstanceId": "<インスタンス ID 2>",
        "CurrentState": "shutting-down"
    }
]

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

Config ルール名のサフィックスは環境によって異なる。以下のコマンドで確認できる。

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

補足:VPC BPA と EC2.9 の関係

CT.EC2.PV.8(VPC BPA)は IGW 経由のインターネット通信をブロックするが、インスタンスへのパブリック IP の付与自体は止めない。そのため、VPC BPA が有効でもインスタンスの publicIp フィールドは存在し続け、EC2.9 の finding は FAILED のままとなる。

VPC BPA は「通信の遮断」、EC2.9 は「IP アドレスの付与」という異なるレイヤーをチェックしている。パブリック IP を持たないインスタンスを確実に運用するには、VPC BPA に加えてサブネットの MapPublicIpOnLaunch を無効化するか、EC2.25 で起動テンプレートの設定を制御する必要がある。

Amazonアソシエイトリンク