ブログ

AWS Security Hub 修復プランで「どこから直すか」を決めてみた

エンジニアの坂下です。

以前のブログで、AWS 環境のセキュリティの司令塔として AWS Security Hub をご紹介しました。検出結果を 1 か所に集約できる利点がある反面、実際に有効化すると「何百件もの検出結果から、どれから直せばいいのか分からない」「同じリソースの指摘を何度も見ている」というお悩みをよく耳にします。

そんな「どこから直すか」問題に効きそうなのが、2026 年 10 月 1 日に発表された Security Hub の新機能「修復プラン(Remediation plans)」です。根本原因が同じリスクをまとめ、「この設定を直せば、どれだけのリスクが解消するか」を提示してくれます。

本ブログでは、わざと設定不備を仕込んだ EC2(Amazon Elastic Compute Cloud)インスタンスを用意し、修復プランの確認から修正・解消までの実体験をレポートします。

※ 本ブログの情報は 2026/10/16 時点の情報です。

AWS Security Hub 修復プラン|修復プランとは

修復プランの話に入る前に、その材料になる「露出検出(exposure findings)」を簡単におさらいします。

材料になる露出検出

露出検出は、複数のサービスから届くセキュリティ上の信号を突き合わせて、「このリソースは、こういう組み合わせで危ない状態にある」とリソース単位でまとめた検出結果です [*4]。信号の出どころは、設定チェックを担う Security Hub CSPM(Cloud Security Posture Management: クラウドセキュリティポスチャ管理)、脆弱性を調べる Amazon Inspector、脅威を検知する Amazon GuardDuty、機密データを見つける Amazon Macie などです。

ポイントは、1 つ 1 つは小さな設定ミスでも、組み合わさると危険度が上がるという考え方です。たとえば「SSH のポートが開いている」ことと「インスタンスのメタデータに認証なしでアクセスできる」ことが重なると、侵入されたときに認証情報まで盗まれるおそれが出てきます。露出検出の重大度は、悪用されやすさ(Likelihood)と、悪用されたときの影響(Impact)の組み合わせで決まります。重大度が Informational(情報)まで下がったものは公開されず、そもそも一覧に出てきません [*10]。

どのリソースが対象になるかは、露出の要因(トレイト)の種類ごとに決まっています。たとえば、ネットワークの到達可能性(Reachability)は EC2 インスタンス、EKS クラスター、Lambda 関数、S3 バケットが対象です [*11]。

修復プランは「直す場所」でまとめたもの

露出検出が「どのリソースが、どう危ないか」の単位でまとまっているのに対して、修復プランは「どこを直せば、どれだけ片付くか」の単位でまとまっています [*3]。

関連する露出は、同じ設定ミスや、権限を広く与えすぎた 1 つのリソースから生まれていることがよくあります。修復プランはそうした露出を原因ごとにまとめ、1 つのプランで 1 つのリソースを直す形にしてくれます。Security Hub は、直す対象のリソースと露出の要因(トレイト)の組み合わせごとにプランを作り、リスクを多く減らせるものから順に並べます。

1 つのプランには、主に次の情報が載っています [*3]。

項目内容
Priority(優先度)Critical / High / Medium / Low の 4 段階
Status(状態)New / Updated / Resolved。利用者は直接変更できない
Impact(影響)完全に解消できる露出、重大度が下がる露出、重大度は変わらないが対処される露出の、それぞれの件数
Rollout(反映)すぐ反映される(Immediate)か、デプロイが必要(Requires deployment)か
Action / Trait推奨される変更と、そのプランが対処する露出の要因
Target resource直す対象のリソースとその種類、アカウント、リージョン

さらに、プランごとに直し方のガイダンスが付きます。手順は Prerequisite(前提)、Snapshot(変更前の控え)、Fix(修正)、Verify(確認)、Done(完了)のような段階に分かれていて、手順によっては元に戻す方法(ロールバック)も書かれています。コマンド例は AWS CLI、Terraform、CDK、CloudFormation、Python などの形式で用意されます。どの段階と形式が出るかは、対象リソースによって変わります [*3]。

ここで一つ注意点があります。Security Hub は手順を示すだけで、リソースを自動では直しません [*3]。直すのはあくまで利用者側です。

料金と提供リージョン

修復プランは、Security Hub の Essentials プランの範囲で追加料金なしで使えます [*2]。露出検出も Essentials プランのリソース単位の料金に含まれています。Security Hub には Essentials プランの機能を対象にした 30 日間の無料トライアルがあるので、今回の検証はその範囲で行いました [*7]。リソースあたりの単価は、料金ページ [*7] をご確認ください。

提供リージョンは、Security Hub が使えるすべてのリージョンです [*2]。本ブログでは東京リージョンで試しています。

AWS Security Hub 修復プラン|試す準備

ここからは手を動かしていきます。検証の流れは次のとおりです。

  1. 検証用アカウントで Security Hub を有効化する
  2. わざと設定不備のある EC2 インスタンスを CloudFormation で作る
  3. 露出検出と修復プランが出てくるのを待つ

1. Security Hub を有効化する

マネジメントコンソールで Security Hub を開き、オンボードの画面から有効化します [*6]。

Security Hub のオンボード画面。「セキュリティ機能」で「必須を有効にする」を選んだ状態

「セキュリティ機能」では、次の 3 つから選べます。

  • 必須を有効にする(基本料金の対象となる機能だけを有効にする)
  • すべて有効にする(必須機能に加えて、すべての追加機能を有効にする)
  • 特定を有効にする(有効にする機能を個別に選ぶ)

今回は、既定で選ばれている「必須を有効にする」のまま進めました。画面の「必要不可欠な機能」にあるとおり、露出検出(画面では「露出相関」)や Amazon Inspector の EC2 スキャン、Security Hub CSPM のチェックは必須機能に含まれているので、修復プランを試すにはこれで足ります。必須機能には、新しく「ネットワーク到達可能性スキャン」も入っていました。後半の検証で出てくる「22 番ポートがインターネットから到達可能」という検出結果は、このスキャンによるものです。GuardDuty による脅威分析などのアドオン機能は別料金で、30 日間の無料トライアルの対象外なのでご注意ください [*7]。

リージョンは東京だけを選んで有効化しました。

ちなみに、有効化するとサービスにリンクされたロール(AWSServiceRoleForSecurityHubV2)、AWS Config のサービスリンクレコーダー、IAM Access Analyzer のサービスリンクアナライザーがアカウントに作られます [*6]。

2. わざと設定不備のある EC2 インスタンスを作る

露出検出を出すために、次の 3 つの不備をわざと仕込んだ EC2 インスタンスを作ります。EC2 インスタンスの露出の要因としてユーザーガイドに挙がっているもの [*5] から選びました。

  • パブリック IP アドレスを持ち、インターネットから到達できる
  • セキュリティグループで SSH(TCP 22 番)を 0.0.0.0/0 に開けている
  • インスタンスメタデータサービスのバージョン 1(IMDSv1)を許可している

インスタンスにはキーペアを付けないので、SSH のポートが開いていてもログインはできません。とはいえ、本番アカウントでは絶対に真似しないでください。検証が終わったらすぐに削除します。

下記のコードブロックの内容を、お好みのファイル名.yaml で保存してください(本ブログでは remediation-plan-demo.yaml としています)。

AWSTemplateFormatVersion: "2010-09-09"
Description: >-
  Security Hub remediation plans hands-on.
  Deliberately misconfigured EC2 instance (public IP, SSH open to the internet, IMDSv1 allowed).
  Delete this stack right after the verification.

Parameters:
  SshCidr:
    Type: String
    Default: 0.0.0.0/0
    Description: Source CIDR allowed to reach TCP 22 (0.0.0.0/0 is the deliberate misconfiguration)
  HttpTokens:
    Type: String
    Default: optional
    AllowedValues: [ optional, required ]
    Description: optional = IMDSv1 allowed (misconfiguration), required = IMDSv2 only
  LatestAmiId:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64

Resources:
  Vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.99.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - { Key: Name, Value: shrp-demo-vpc }

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - { Key: Name, Value: shrp-demo-igw }

  VpcGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref Vpc
      InternetGatewayId: !Ref InternetGateway

  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref Vpc
      CidrBlock: 10.99.1.0/24
      AvailabilityZone: !Select [0, !GetAZs ""]
      MapPublicIpOnLaunch: true
      Tags:
        - { Key: Name, Value: shrp-demo-public }

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref Vpc
      Tags:
        - { Key: Name, Value: shrp-demo-public-rt }

  DefaultRoute:
    Type: AWS::EC2::Route
    DependsOn: VpcGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable

  SshSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Deliberately open SSH for the Security Hub hands-on
      VpcId: !Ref Vpc
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref SshCidr
      Tags:
        - { Key: Name, Value: shrp-demo-sg }

  DemoInstance:
    Type: AWS::EC2::Instance
    DependsOn: DefaultRoute
    Properties:
      ImageId: !Ref LatestAmiId
      InstanceType: t3.micro
      SubnetId: !Ref PublicSubnet
      SecurityGroupIds:
        - !Ref SshSecurityGroup
      MetadataOptions:
        HttpEndpoint: enabled
        HttpTokens: !Ref HttpTokens
      Tags:
        - { Key: Name, Value: shrp-demo-ec2 }

Outputs:
  InstanceId:
    Value: !Ref DemoInstance
  SecurityGroupId:
    Value: !Ref SshSecurityGroup
  PublicIp:
    Value: !GetAtt DemoInstance.PublicIp

SSH の許可元(SshCidr)と IMDS の設定(HttpTokens)をパラメータにしてあるのは、あとで修復プランに沿って直すときに、テンプレートの更新として直せるようにするためです。

まずは、どんなリソースが作られるのかを変更セットで確かめます。–no-execute-changeset を付けているので、この時点ではまだリソースは作られません。

$ aws cloudformation deploy --template-file remediation-plan-demo.yaml --stack-name shrp-demo --no-execute-changeset --region ap-northeast-1

Waiting for changeset to be created..
Changeset created successfully. Run the following command to review changes:
aws cloudformation describe-change-set --change-set-name arn:aws:cloudformation:ap-northeast-1:123456789012:changeSet/awscli-cloudformation-package-deploy-1791625430/adc8f357-2e4f-4f5e-b029-28e79e9b940d

表示されたコマンドで中身を確認すると、9 件すべてが Add(新規作成)で、既存のリソースへの変更や削除は含まれていませんでした。問題がなければ、–no-execute-changeset を外して作成します。

$ aws cloudformation deploy --template-file remediation-plan-demo.yaml --stack-name shrp-demo --region ap-northeast-1

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - shrp-demo

無事に作成できました! 私の環境では、スタックの作成開始から完了まで 1 分ほどでした。

3. 露出検出が出てくるのを待つ

ユーザーガイドにも「新しい露出を検出しても、そのプランがすぐに表示されないことがある」とあるとおり [*3]、露出検出と修復プランは作ってすぐには出てきません。

私の環境では、スタックの作成完了からおよそ 3 分後に、今回の EC2 インスタンスの露出検出が作られていました。AWS CLI で確認すると、次のとおりです。

$ aws securityhub get-findings-v2 --region ap-northeast-1 --query 'Findings[?metadata.product.name==`Security Hub Exposure Detection` && resources[0].type==`AWS::EC2::Instance`].{title:finding_info.title,severity:severity,created:finding_info.created_time_dt}'
[
    {
        "title": "Potential Credential Stealing: EC2 instance has open remote access ports and uses IMDSv1 for metadata access",
        "severity": "Low",
        "created": "2026-10-10T09:48:07.926Z"
    }
]

露出検出の発行元(metadata.product.name)は Security Hub Exposure Detection になるので、ここで絞り込んでいます。さらに、主なリソースが EC2 インスタンスのものだけに絞りました。時刻は UTC で、日本時間では 18 時 48 分です。

一方、修復プランのほうは少し時間がかかりました。露出検出が出てから 16 分後にはまだ一覧が空で、47 分後に見に行ったときには出ていました。試すときは、スタックを作ってから 1 時間ほど見ておくと安心かと思います。

AWS Security Hub 修復プラン|画面の見方

まずは、修復プランの材料になった露出検出から見ていきます。今回の EC2 インスタンスには、次の露出検出が 1 件出ていました。

項目内容
タイトルPotential Credential Stealing: EC2 instance has open remote access ports and uses IMDSv1 for metadata access
種類Exposure/Potential Credential Access/Unsecured Credentials
重大度Low
関連リソースEC2 インスタンス、セキュリティグループ、サブネット

タイトルを訳すと「認証情報窃取のおそれ:リモートアクセス用のポートが開いていて、メタデータへのアクセスに IMDSv1 を使っている」です。SSH の開放と IMDSv1 の 2 つが組み合わさって、1 件の露出になっていることが分かります。検出結果の説明には、IMDS の設定、リモートアクセスの許可の順に直すよう書かれていました。

ここで、予想と違った点が 2 つありました。1 つ目は、わざと仕込んだ 3 つの不備のうち、インターネットからの到達性がタイトルにも説明にも入っていなかったことです。2 つ目は、重大度が Low にとどまったことです。ドキュメントによると、影響はリソースに関連付いた IAM プリンシパルの実効権限から評価され、影響が判断できない場合は悪用されやすさだけで重大度が決まります [*10]。今回のインスタンスには IAM ロールを付けていないので、このあたりが効いたのかもしれません。ただし、1 つ目も含めて、今回の結果になった理由まではドキュメントから確かめられていません。

同じ EC2 インスタンスとセキュリティグループには、その時点で Security Hub CSPM の検出結果も 8 件出ていました。「EC2 instances should not have a public IPv4 address」(High)や「Security groups should not allow unrestricted access to ports with high risk」(Critical)などです。1 件ずつ見ていくと、同じリソースの話が何度も出てくる状態ですね。

続いて、修復プランの一覧を開きます。英語版のユーザーガイドでは Response の下の Remediations と書かれているメニューは [*3]、日本語のコンソールでは「応答」の下の「是正」です。開いた画面の見出しは「改善計画」となっていて、日本語の表記がまだ揃っていないようです。本ブログでは、英語名の Remediation plans に合わせて「修復プラン」と呼んでいます。

修復プランの一覧を、今回の EC2 インスタンスのターゲットリソース ID で絞り込んだ画面

一覧には「是正」「優先」「ターゲットリソース」「リージョン」「アカウント」「インパクト」「ステータス」「ロールアウト」の列が並びます。検証用アカウントには既存のリソースに対するプランも並んでいたので、上の画面はターゲットリソース ID で今回のインスタンスに絞り込んでいます。既存のプランの中には、1 つのプランで複数の露出が解決したり、重大度が下がったりするものもありました。1 か所直せば複数片付く、というのはこういうことですね。

今回の EC2 インスタンスまわりで出ていたプランは、次の 2 件です。

是正優先ターゲットリソースインパクトステータスロールアウト
Configure IMDSv2.LowEC2 インスタンス1露出が解決されましたNew即時
Restrict remote access.Lowセキュリティグループ1露出は変わりませんNew即時

どちらも同じ 1 件の露出検出から作られたプランですが、インパクトがはっきり分かれました。IMDSv2 を必須にすれば露出が解消する一方で、SSH の許可元を絞っても露出の重大度は変わらない、という判定です。

プランの行を選ぶと、画面の右側に詳細パネルが開きます。「影響を受ける暴露」タブを見ると、2 件の違いがさらに分かりやすくなります [*3]。

Configure IMDSv2. のプランの詳細パネル。影響を受ける暴露タブで、重大度が Low から Informational に変わると表示されている

プランインパクト重要度の変更
Configure IMDSv2.解決するLow → Informational
Restrict remote access.変更なしLow のまま

先ほどお話ししたとおり、重大度が Informational まで下がった露出は一覧に出なくなります。プランの判定どおりなら、IMDSv2 を必須にすればこの露出は片付き、セキュリティグループを絞るだけでは片付かない、ということになります。「どこから直すか」の答えは、セキュリティグループではなく IMDS の設定でした。

概要タブとガイダンス

「概要」タブには、ターゲットリソース、トレイト、アクション、ロールアウト、インパクトのほかに、リスクレベル、可逆性、オートメーション、ヒューマンレビューの要否が並びます。Configure IMDSv2. のプランでは、リスクレベルが Medium、可逆性が Fully reversible、オートメーションが full、ヒューマンレビューは「必要ありません」でした。その下に、問題、リスク、影響を受ける範囲の説明が英語で続きます。

ガイダンスは、今回の 2 件とも次の 5 段階に分かれていました。

  1. 前提条件
  2. スナップショット(変更前の設定を控える)
  3. 修正(ロールバックと、修正直後の確認を含む)
  4. 検証
  5. 完了(直したあとのあるべき状態)

Configure IMDSv2. の前提条件には、「IMDSv2 を必須にする前に、CloudWatch の MetadataNoToken メトリクスで IMDSv1 が使われていないか確かめる」「インスタンス上のアプリケーションや SDK、エージェントがすべて IMDSv2 に対応していること」といった注意が書かれていました。実行に必要な権限が ec2:DescribeInstances と ec2:ModifyInstanceMetadataOptions であることも明記されています。修正の段階では、HttpTokens だけを required に変え、ほかのメタデータの設定には触らないこと、再起動は不要なことが説明されていました。ロールバックは HttpTokens を optional に戻す手順で、「セキュリティ上は後退になるので、アプリケーションが壊れたときに限って一時的に使うこと」という但し書き付きです。

本番環境でいきなり IMDSv2 を必須にすると、古い SDK を使うアプリケーションがメタデータを読めなくなるおそれがあります。前提条件の確認は飛ばさないようにしましょう。

ガイダンスの下には、コード例も用意されています。形式は AWS CLI、Python、Terraform、CDK、CloudFormation の 5 種類から選べました。ちなみに、日本語のコンソールでは Terraform や CloudFormation がカタカナで表示され、AWS CLI の CLI は「クリップ」と訳されていました。翻訳の都合かと思います。

ガイダンスの完了の段階と、コード例の形式の切り替え。AWS CLI のコード例を表示している

一覧の絞り込みは、Filter remediation plans(日本語のコンソールでは「改善計画をフィルタリングする」)のバーで、優先度、状態、リソースの種類、クラウドプロバイダー、対象リソースの ID、アカウントを条件にできます。ただし、条件は完全一致だけで、同時に使えるのは 2 つまで(AND 条件)です。値は大文字と小文字を区別するので、リソースの種類は AWS::EC2::Instance のように正確に入力する必要があります。列での並び替えもできません [*3]。少しクセがあるので、最初は戸惑うかと思います。

AWS Security Hub 修復プラン|プランに沿って直してみる

それでは、インパクトの大きい Configure IMDSv2. のプランから直していきます。

ガイダンスの AWS CLI の例では、aws ec2 modify-instance-metadata-options で HttpTokens を直接 required に変える手順が示されていました。ただ、今回の EC2 インスタンスは CloudFormation で作っているので、CLI で直接変えるとテンプレートと実際の設定がずれてしまいます。そこで、コード例の形式を CloudFormation に切り替えてみると、MetadataOptions の HttpTokens に required を指定する例が載っていました。今回のテンプレートでは HttpTokens をパラメータにしてあるので、パラメータの値を変えてスタックを更新します。

1. 変更セットで差分を確かめる

$ aws cloudformation deploy --template-file remediation-plan-demo.yaml --stack-name shrp-demo --parameter-overrides HttpTokens=required --no-execute-changeset --region ap-northeast-1

Waiting for changeset to be created..
Changeset created successfully. Run the following command to review changes:
aws cloudformation describe-change-set --change-set-name arn:aws:cloudformation:ap-northeast-1:123456789012:changeSet/awscli-cloudformation-package-deploy-1791639560/71048001-f31d-45e7-b477-4212fe07be3a

変更の中身を確認します。

$ aws cloudformation describe-change-set --change-set-name (上で表示された ARN) --region ap-northeast-1 --query 'Changes[].ResourceChange.{Action:Action,Id:LogicalResourceId,Replacement:Replacement,Scope:join(`,`,Scope)}' --output table
---------------------------------------------------------
|                    DescribeChangeSet                  |
+-------+----------------+---------------+--------------+
| Action|       Id       |   Replacement |     Scope    |
+-------+----------------+---------------+--------------+
| Modify|   DemoInstance |   False       |   Properties |
+-------+----------------+---------------+--------------+

変わるのは EC2 インスタンスのプロパティだけで、Replacement が False なので、インスタンスは作り直されません。再起動が要るかどうかは変更セットからは分からないため、ここはガイダンスの「再起動は不要」という説明を頼りにしています。

2. スタックを更新する

$ aws cloudformation deploy --template-file remediation-plan-demo.yaml --stack-name shrp-demo --parameter-overrides HttpTokens=required --region ap-northeast-1

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - shrp-demo

3. ガイダンスの「検証」の手順で確かめる

ガイダンスの AWS CLI の例にある検証用のコマンドで、設定が反映されたかを確かめます。

$ aws ec2 describe-instances --instance-ids i-0123456789abcdef0 --region ap-northeast-1 --query 'Reservations[0].Instances[0].MetadataOptions.{HttpTokens:HttpTokens,State:State,HttpEndpoint:HttpEndpoint,HopLimit:HttpPutResponseHopLimit}'
{
    "HttpTokens": "required",
    "State": "applied",
    "HttpEndpoint": "enabled",
    "HopLimit": 2
}

ガイダンスの検証の段階にある「HttpTokens が required」「State が applied」の 2 点を満たしています。HttpEndpoint も enabled のままで、メタデータサービス自体は止まっていません。

4. 露出検出と修復プランの変化を見る

CSPM の「EC2 instances should use Instance Metadata Service Version 2 (IMDSv2)」のチェックは、スタックの更新完了から 1 分ほどで Fail から Pass に変わりました。こちらは素直です。

修復プランのほうは、2 件とも Resolved になりました。ところが、経過を細かく追ってみると、一筋縄ではいきませんでした。

ここで一つ落とし穴があります。実は、露出検出は IMDSv2 を直すより前に閉じられていたのです。露出検出には、状態(status)とは別に、最後の操作を表す activity_name という項目があります。status が New のままでも、activity_name が Close になっていれば、その露出検出は閉じられていて、コンソールの露出の一覧には表示されません(一覧の既定のフィルターで除外されます)。私は最初、status だけを見ていたので「何時間たっても露出検出が変わらない」と勘違いしていました。

本当に修正と関係があるのかを確かめるため、スタックを作り直して同じ手順をもう一度試しました。2 回の経過は次のとおりです(時刻は日本時間、修復プランはコンソールで見に行った時点の状態です)。

出来事1 回目2 回目
スタックの作成完了18:446:36
露出検出が作られる18:486:39
「22 番ポートがインターネットから到達可能」という検出結果が出る19:197:10
露出検出が閉じられる(activity_name が Close)19:217:12
修復プランを確認19:35 に New7:19 に New
IMDSv2 を必須に変更22:407:28
CSPM の IMDSv2 のチェックが Pass22:417:29
修復プランを確認翌 6:30 に 2 件とも Resolved8:00 に 2 件とも Resolved

2 回とも、設定を何も直していないのに、露出検出は作られてから約 33 分で閉じられていました。しかも 2 回とも、その約 2 分半前に、ネットワーク到達可能性スキャンによる「22 番ポートがインターネットから到達可能」という検出結果が出ています。何らかの関係はありそうですが、露出検出がこのタイミングで閉じられる理由は、ユーザーガイドからは確かめられませんでした。ユーザーガイドには「露出検出はほぼリアルタイムで生成、更新される」とあります [*9]。作られるまでの早さはそのとおりでしたが、閉じられたときに私の環境の設定は何も変わっていませんでした。

もう一つ気になったのは、手を付けていないセキュリティグループの Restrict remote access. のプランまで Resolved になったことです。ユーザーガイドでは、プランが Resolved になるのは、プランが対処する露出が解消、抑制、アーカイブされたときや、重大度が Informational に下がったとき、露出からそのトレイトが無くなったときとされています [*3]。つまり、プランの状態は「そのプランの対象リソースを直したか」ではなく、「元になった露出がどうなったか」で決まります。今回のように露出検出自体が閉じられれば、直していないプランも Resolved になりうる、ということです。

今回の検証で確認できたのはここまでです。露出検出が修正前に閉じられていたので、プランが Resolved になったのが IMDSv2 を直したおかげなのかは、切り分けられていません。

ここから言えるのは、Resolved は「自分の修正が効いた」という合図ではない、ということです。直したかどうかは、ガイダンスの検証の段階にあるコマンドや、CSPM の該当するチェックが Pass になったかで、自分で確かめるのが確実です。実際、今回もセキュリティグループの SSH の全開放は残ったままで、CSPM の「Security groups should not allow ingress from 0.0.0.0/0 or ::/0 to port 22」は Fail(High)のままでした。修復プランの一覧から消えたからといって、問題が無くなったわけではありません。

また、プランが Resolved になっても、露出検出そのものが解消したとは限りません [*3]。先ほどの条件のうち、重大度が Informational に下がった場合は、露出検出は公開されなくなり、露出の一覧や API の結果には出てきません [*10]。それでも、露出そのものは存在し続けています [*3]。

AWS Security Hub 修復プラン|運用に組み込むコツ

最後に、修復プランを日々の運用に組み込むときのコツを 3 つご紹介します。

朝いちはダッシュボードのウィジェットから

Security Hub のサマリーダッシュボードには修復プランのウィジェットがあり、状態が New か Updated のプランを優先度の高い順に最大 5 件表示します [*3]。全件の一覧を開かなくても、その日いちばん急ぐ作業が分かります。

ただし、ウィジェットはプランごとの影響をそのまま表示していて、プランをまたいだ合計はしません。1 つの露出が複数のプランで対処される場合は、それぞれのプランで数えられます。ウィジェットの影響の件数を足し上げて「今日はこれだけ減る」と見積もると、実際より多く見えるのでご注意ください。

対応の記録は別に残す

Resolved になったプランは、約 14 日で一覧から消えます [*3]。「いつ、誰が、どのプランに沿って何を変えたか」を後から追えるように、対応の記録はチケットや作業記録に別で残しておくのがおすすめです。

ガイダンスを手順書の叩き台にする

以前、AWS Organizations の組織ポリシーについてのブログ [*8] で、運用でいちばん大事なのは属人化させないことだとお伝えしました。修復プランも同じで、「詳しい人が直してくれたけど、何をしたのか誰も知らない」状態になると、次に同じ露出が出たときにまた止まってしまいます。

修復プランのガイダンスは、前提、変更前の控え、修正、確認、ロールバックまでが段階ごとに書かれています。これをそのまま社内の手順書の叩き台にすれば、誰が対応しても同じ流れで直せるようになるかと思います。

ただし、今回試してみて、そのままでは足りない点が 2 つありました。

  1. 1 つ目は、変更の手段です。ガイダンスの AWS CLI の例は、リソースの設定を直接変える手順になっています。CloudFormation や Terraform でリソースを管理している環境でそのまま実行すると、テンプレートと実際の設定がずれてしまいます。IaC で管理しているリソースは、コード例の形式を切り替えて、テンプレート側を直す手順に書き換えておくのがおすすめです。
  2. 2 つ目は、完了の判断です。前の節で見たとおり、プランが Resolved になっても、自分の修正が効いたとは限りません。手順書の最後には、ガイダンスの検証の段階のコマンドで設定を確かめることと、関連する CSPM のチェックが Pass になったことを確かめる項目を入れておくと安心です。

AWS Security Hub 修復プラン(まとめ)

いかがでしたでしょうか?

修復プランは、露出検出を「どこを直せば、どれだけ片付くか」の単位にまとめ直し、優先度と直し方を添えて示してくれる機能です。今回は、わざと設定不備のある EC2 インスタンスを作り、修復プランが出てくるところから、プランに沿って直すところまでを試しました。

同じ露出に対して「IMDSv2 を必須にすれば解消、SSH を絞っても重大度は変わらない」と判定が分かれたのは、まさに「どこから直すか」の答えでした。一方で、プランが Resolved になることと、自分の修正が効いたことは別の話です。直したかどうかは、ガイダンスの検証の手順で自分の目で確かめましょう。

クラウドのセキュリティ対策は、ツールを導入して終わりではなく、「検知されたリスクをいかに安全かつ確実に日々の運用へ落とし込むか」が本質です。「Security Hub を導入したものの運用が追いつかない」「自社環境のリスクにどう優先順位をつけるべきか悩んでいる」という場合は、ぜひターン・アンド・フロンティアにご相談ください。24時間365日の運用監視(cloud link)など、AWS 専任のエンジニアがお客様の運用体制に寄り添った最適なセキュリティ改善を全力で伴走支援いたします。

AWS Security Hub 修復プラン(ご参考)

*1「セキュリティの司令塔 AWS Security Hub を理解しよう!」 https://aws.taf-jp.com/blog/127404

*2「AWS Security Hub introduces remediation plans to prioritize and fix security exposures」 https://aws.amazon.com/about-aws/whats-new/2026/10/aws-security-hub-remediation-plans/

*3「Remediation plans in Security Hub」 https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-v2-remediation-plans.html

*4「Exposure findings in Security Hub」 https://docs.aws.amazon.com/securityhub/latest/userguide/exposure-findings.html

*5「Remediating exposures for EC2 instances」 https://docs.aws.amazon.com/securityhub/latest/userguide/exposure-ec2-instance.html

*6「Enabling Security Hub」 https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-v2-enable.html

*7「AWS Security Hub pricing」 https://aws.amazon.com/security-hub/pricing/

*8「AWS Organizations 組織ポリシーについて理解しよう!」 https://aws.taf-jp.com/blog/132894

*9「Generating exposure findings」 https://docs.aws.amazon.com/securityhub/latest/userguide/exposure-findings-generate.html

*10「Determining the severity level of an exposure finding」 https://docs.aws.amazon.com/securityhub/latest/userguide/exposure-findings-severity.html

*11「Supported trait types in Security Hub」 https://docs.aws.amazon.com/securityhub/latest/userguide/exposure-findings-supported-traits.html

【筆者実行環境】 PC:MacBook Air(モデル ID:Mac16,12) OS:macOS 26.6.2 aws cli:aws-cli/2.35.14 リージョン:アジアパシフィック(東京)

元記事発行日: 2026年11月05日、最終更新日: 2026年10月25日