09 / Learn — Hands-on Labs

Hands-on Labs

ここに掲載する8つのラボは、すべてサンドボックスのAWS/Azure/GCPアカウントやKubernetesクラスタを対象に、実際によくあるミスコンフィグレーションを自分の手で再現し、検知し、是正する演習です。それぞれのラボは Scenario → Architecture → CLI Commands → Misconfiguration → Detection → Remediation → Verification という同じ流れで構成されており、概念の説明だけでなく、実際に動くコマンドと確認手順まで一貫して扱います。

Public S3 Bucket Critical AWS

サンドボックスのAWSアカウントに作成したS3バケットに、誰でも読み取り・一覧取得できるバケットポリシーが付与されてしまうシナリオです。原因の特定から、Block Public Accessによる恒久的な是正までを一通り体験します。

1. Scenario

サンドボックスのAWSアカウントで、静的ファイル配信用にS3バケットを新規作成したという想定です。開発中に「とりあえず外部からアクセスできるようにする」ためバケットポリシーを緩めたまま、Block Public Accessの設定を見直さずに放置してしまいました。この状態のバケットを自分で作り、パブリック公開状態を検知して是正します。

2. Architecture

3. CLI Commands

lab環境で以下を再現する。バケットを作成し、意図的に公開範囲を広げるバケットポリシーをアタッチする。

bash
# lab用バケットを作成
$ aws s3api create-bucket --bucket cs-lab-public-demo-2026 --region ap-northeast-1 \
    --create-bucket-configuration LocationConstraint=ap-northeast-1

# サンプルオブジェクトを配置
$ aws s3 cp ./sample.html s3://cs-lab-public-demo-2026/sample.html

# 誰でも読み取り・一覧取得できるバケットポリシーを付与(意図的な誤設定)
$ aws s3api put-bucket-policy --bucket cs-lab-public-demo-2026 --policy file://public-read-policy.json

4. Misconfiguration

Principal"*" にしたまま s3:GetObjects3:ListBucket を許可しているため、認証なしの匿名ユーザーがバケット内の全オブジェクトを閲覧・一覧取得できる状態です。

public-read-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetAndList",
      "Effect": "Allow",
      "Principal": "*",
      "Action": ["s3:GetObject", "s3:ListBucket"],
      "Resource": [
        "arn:aws:s3:::cs-lab-public-demo-2026",
        "arn:aws:s3:::cs-lab-public-demo-2026/*"
      ]
    }
  ]
}

5. Detection

バケットポリシーの公開状態とBlock Public Accessの設定状況を確認する。

bash
# S3自身の判定機能でポリシーが公開状態かを確認
$ aws s3api get-bucket-policy-status --bucket cs-lab-public-demo-2026
#  "PolicyStatus": { "IsPublic": true }

# Block Public Accessの設定を確認(全項目falseが問題)
$ aws s3api get-public-access-block --bucket cs-lab-public-demo-2026

6. Remediation

Block Public Accessの4項目をすべて有効化し、問題のあるバケットポリシーを削除する。

bash
# Block Public Accessを全項目有効化
$ aws s3api put-public-access-block --bucket cs-lab-public-demo-2026 \
    --public-access-block-configuration \
    BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

# 公開バケットポリシーを削除
$ aws s3api delete-bucket-policy --bucket cs-lab-public-demo-2026

7. Verification

公開判定が解消されたことを再確認する。

bash
$ aws s3api get-bucket-policy-status --bucket cs-lab-public-demo-2026
#  ポリシーが存在しないため NoSuchBucketPolicy エラーとなり、公開ポリシーは解消済み

$ aws s3api get-public-access-block --bucket cs-lab-public-demo-2026
#  "PublicAccessBlockConfiguration": {
#    "BlockPublicAcls": true, "IgnorePublicAcls": true,
#    "BlockPublicPolicy": true, "RestrictPublicBuckets": true
#  }

Overly Permissive IAM High AWS

検証用に作成した「とりあえず動かすため」のIAMポリシーが、Action: *Resource: * を許可したまま本番相当の環境に残ってしまうシナリオです。Access Analyzerとポリシーシミュレーションで問題を特定し、最小権限に縮小します。

1. Scenario

サンドボックスのAWSアカウントで、CI用のIAMロールを急いで動かすために「一旦全部許可」のポリシーをアタッチしたという想定です。デプロイは通ったものの、そのポリシーがそのまま残り続けています。このロールを自分で作成し、過剰権限を検出して段階的に縮小します。

2. Architecture

3. CLI Commands

lab環境で以下を再現する。ワイルドカードのカスタムポリシーを作成し、lab用ロールにアタッチする。

bash
# ワイルドカードポリシーを作成(意図的な誤設定)
$ aws iam create-policy --policy-name cs-lab-ci-wildcard \
    --policy-document file://wildcard-policy.json

# lab用CIロールにアタッチ
$ aws iam attach-role-policy --role-name cs-lab-ci-deploy-role \
    --policy-arn arn:aws:iam::123456789012:policy/cs-lab-ci-wildcard

4. Misconfiguration

"Action": "*""Resource": "*" の組み合わせにより、このロールはIAMユーザーの作成やポリシーのアタッチを含む、アカウント内のあらゆる操作を実行できます。

wildcard-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowEverything",
      "Effect": "Allow",
      "Action": "*",
      "Resource": "*"
    }
  ]
}

5. Detection

Access Analyzerのファインディングと、ポリシーシミュレーションで実際に許可されるアクションを確認する。

bash
# IAM Access Analyzerのファインディングを確認
$ aws accessanalyzer list-findings --analyzer-arn <analyzer-arn> \
    --filter '{"resource":{"contains":["cs-lab-ci-deploy-role"]}}'

# 実際に危険なアクションが許可されているかシミュレーション
$ aws iam simulate-principal-policy \
    --policy-source-arn arn:aws:iam::123456789012:role/cs-lab-ci-deploy-role \
    --action-names iam:CreateUser iam:AttachUserPolicy ec2:TerminateInstances

6. Remediation

デプロイに必要な最小限のアクションだけを許可する新しいポリシーバージョンを作成し、デフォルトに切り替える。

bash
# 最小権限に絞った新しいポリシーバージョンを作成
$ aws iam create-policy-version \
    --policy-arn arn:aws:iam::123456789012:policy/cs-lab-ci-wildcard \
    --policy-document file://scoped-deploy-policy.json \
    --set-as-default

# scoped-deploy-policy.json の例(S3デプロイ先バケットのみ許可)
# {
#   "Effect": "Allow",
#   "Action": ["s3:PutObject", "s3:ListBucket"],
#   "Resource": [
#     "arn:aws:s3:::cs-lab-site-bucket",
#     "arn:aws:s3:::cs-lab-site-bucket/*"
#   ]
# }

# 古いワイルドカードバージョンを削除
$ aws iam delete-policy-version \
    --policy-arn arn:aws:iam::123456789012:policy/cs-lab-ci-wildcard --version-id v1

7. Verification

危険なアクションが拒否されるようになったことをシミュレーションで確認する。

bash
$ aws iam simulate-principal-policy \
    --policy-source-arn arn:aws:iam::123456789012:role/cs-lab-ci-deploy-role \
    --action-names iam:CreateUser ec2:TerminateInstances s3:PutObject
#  iam:CreateUser        -> implicitDeny
#  ec2:TerminateInstances -> implicitDeny
#  s3:PutObject            -> allowed

Exposed Storage Critical Azure

Azure Storage Accountとコンテナで匿名の公開アクセスが有効化され、ストレージアカウント全体が意図せずインターネットに公開されてしまうシナリオです。アカウントレベルとコンテナレベルの両方の設定を確認し、是正します。

1. Scenario

サンドボックスのAzureサブスクリプションで、フロントエンドから直接画像を配信するためにBlobコンテナを作成したという想定です。動作確認のため --public-access blob を指定したまま、ストレージアカウント側の匿名アクセス許可も見直さずに放置してしまいました。この構成を自分で再現し、検知・是正します。

2. Architecture

3. CLI Commands

lab環境で以下を再現する。ストレージアカウントとコンテナを、匿名Blobアクセスを許可した状態で作成する。

bash
# lab用ストレージアカウントを作成
$ az storage account create --name cslabstorage2026 \
    --resource-group cs-lab-rg --location japaneast --sku Standard_LRS

# コンテナを匿名read(blob)アクセス許可付きで作成(意図的な誤設定)
$ az storage container create --account-name cslabstorage2026 \
    --name public-assets --public-access blob

4. Misconfiguration

ストレージアカウントの allowBlobPublicAccesstrue のまま、コンテナに --public-access blob を指定しているため、コンテナ内のすべてのBlobが認証なしで読み取り可能になります。

storage account properties (excerpt)
{
  "name": "cslabstorage2026",
  "allowBlobPublicAccess": true,
  "networkRuleSet": { "defaultAction": "Allow" }
}

// public-assets container
{
  "publicAccess": "blob"
}

5. Detection

アカウントレベルの匿名アクセス許可設定と、コンテナレベルの公開設定の両方を確認する。

bash
# アカウントレベルで匿名Blobアクセスが許可されているか確認
$ az storage account show --name cslabstorage2026 \
    --resource-group cs-lab-rg --query allowBlobPublicAccess
#  true

# コンテナの公開アクセスレベルを確認
$ az storage container show-permission --account-name cslabstorage2026 \
    --name public-assets
#  "publicAccess": "blob"

6. Remediation

アカウントレベルの匿名アクセスを無効化し、コンテナの公開設定もoffに戻す。

bash
# アカウントレベルで匿名Blobアクセスを禁止
$ az storage account update --name cslabstorage2026 \
    --resource-group cs-lab-rg --allow-blob-public-access false

# コンテナの公開アクセスレベルをoffに変更
$ az storage container set-permission --account-name cslabstorage2026 \
    --name public-assets --public-access off

7. Verification

両方の設定がfalse/offになっていることを再確認する。

bash
$ az storage account show --name cslabstorage2026 \
    --resource-group cs-lab-rg --query allowBlobPublicAccess
#  false

$ az storage container show-permission --account-name cslabstorage2026 \
    --name public-assets
#  "publicAccess": "off"

Open Security Group High AWS

EC2インスタンスのセキュリティグループに、SSH(22番ポート)を 0.0.0.0/0 に開放するインバウンドルールが残ってしまうシナリオです。踏み台運用の見直しも含めて是正します。

1. Scenario

サンドボックスのVPCで、緊急のトラブルシューティングのため一時的にSSHを全世界に開放し、その後もとに戻すのを忘れたという想定です。このセキュリティグループを自分で作成し、スキャンで検出、アクセス元を制限、あるいはSSMへの切り替えまでを体験します。

2. Architecture

3. CLI Commands

lab環境で以下を再現する。セキュリティグループを作成し、SSHを全世界に開放するルールを追加する。

bash
# lab用セキュリティグループを作成
$ aws ec2 create-security-group --group-name cs-lab-open-ssh-sg \
    --description "Lab: intentionally open SSH" --vpc-id vpc-0abc123456789

# 0.0.0.0/0からの22番ポートを許可(意図的な誤設定)
$ aws ec2 authorize-security-group-ingress --group-id sg-0abcdef1234567890 \
    --protocol tcp --port 22 --cidr 0.0.0.0/0

4. Misconfiguration

インバウンドルールの CidrIp0.0.0.0/0 になっているため、インターネット上の任意のホストからSSHの接続試行が可能です。ブルートフォースや既知の脆弱な認証情報を狙った攻撃の対象になります。

security group rule (JSON)
{
  "IpPermissions": [
    {
      "IpProtocol": "tcp",
      "FromPort": 22,
      "ToPort": 22,
      "IpRanges": [
        { "CidrIp": "0.0.0.0/0", "Description": "temporary troubleshooting" }
      ]
    }
  ]
}

5. Detection

0.0.0.0/0 を含むインバウンドルールを持つセキュリティグループをフィルタで検索する。

bash
$ aws ec2 describe-security-groups \
    --filters Name=ip-permission.cidr,Values=0.0.0.0/0 \
    --query 'SecurityGroups[].{GroupId:GroupId,Name:GroupName}'

6. Remediation

0.0.0.0/0のルールを削除し、必要であれば特定の踏み台/オフィスCIDRに絞り込む。恒久対応としてはSSMセッションマネージャーへの切り替えを推奨する。

bash
# 0.0.0.0/0からの22番ポート許可を削除
$ aws ec2 revoke-security-group-ingress --group-id sg-0abcdef1234567890 \
    --protocol tcp --port 22 --cidr 0.0.0.0/0

# 必要な場合のみ、特定のオフィス/踏み台CIDRに限定して再許可
$ aws ec2 authorize-security-group-ingress --group-id sg-0abcdef1234567890 \
    --protocol tcp --port 22 --cidr 203.0.113.0/24

# 恒久対応: SSHポートを開けず、SSM Session Managerで接続する運用に切り替える
$ aws ssm start-session --target i-0123456789abcdef0

7. Verification

0.0.0.0/0のルールがもう存在しないことを確認する。

bash
$ aws ec2 describe-security-groups \
    --filters Name=ip-permission.cidr,Values=0.0.0.0/0 \
    --query 'SecurityGroups[].GroupId'
#  []  (空配列 = 該当なし。0.0.0.0/0のインバウンドルールは解消済み)

Kubernetes Privileged Container Critical Kubernetes

デバッグ用に privileged: true で起動したPodがそのままクラスタに残ってしまうシナリオです。特権コンテナはホストのカーネル機能に直接アクセスできるため、コンテナエスケープの起点になります。

1. Scenario

サンドボックスのKubernetesクラスタ(kindやminikubeなどのローカルクラスタを想定)で、ホストデバイスにアクセスする必要があるデバッグ作業のために特権コンテナをデプロイし、そのまま削除せずに残してしまったという想定です。このPodを自分でデプロイし、Pod Security基準で検出・是正します。

2. Architecture

3. CLI Commands

lab環境で以下を再現する。特権コンテナのマニフェストを適用する。

bash
# lab用namespaceを作成
$ kubectl create namespace cs-lab-debug

# 特権Podを適用(意図的な誤設定)
$ kubectl apply -n cs-lab-debug -f privileged-pod.yaml

4. Misconfiguration

securityContext.privileged: true により、コンテナはホストとほぼ同等の権限(全capability、デバイスへの直接アクセス)を持ちます。コンテナブレイクアウトが成立すれば、ノード全体、ひいてはクラスタ全体の侵害につながります。

privileged-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: debug-tool
  namespace: cs-lab-debug
spec:
  containers:
    - name: debug-tool
      image: busybox
      command: ["sleep", "infinity"]
      securityContext:
        privileged: true
        allowPrivilegeEscalation: true
        runAsUser: 0

5. Detection

全namespaceを対象に、privileged: true のコンテナを持つPodを検索する。

bash
# jqでprivileged: trueのPodを抽出
$ kubectl get pods -A -o json | \
    jq -r '.items[] | select(.spec.containers[].securityContext.privileged==true) | "\(.metadata.namespace)/\(.metadata.name)"'

# Kyvernoを導入している場合はPolicyReportからも確認できる
$ kubectl get policyreport -A -o json | \
    jq -r '.items[].results[] | select(.policy=="disallow-privileged-containers")'

6. Remediation

特権を外した修正版マニフェストを適用し、namespace全体にPod Security基準のrestrictedプロファイルを強制する。

bash
# securityContextを修正したマニフェストを適用
# securityContext:
#   privileged: false
#   allowPrivilegeEscalation: false
#   runAsNonRoot: true
#   capabilities:
#     drop: ["ALL"]
$ kubectl apply -n cs-lab-debug -f privileged-pod-fixed.yaml

# namespace全体にrestrictedプロファイルを強制し、再発を防止
$ kubectl label namespace cs-lab-debug \
    pod-security.kubernetes.io/enforce=restricted --overwrite

7. Verification

特権Podが存在しないこと、そしてPod Security Admissionが機能していることを確認する。

bash
$ kubectl get pods -A -o json | \
    jq -r '.items[] | select(.spec.containers[].securityContext.privileged==true) | .metadata.name'
#  (出力なし = 特権Podは存在しない)

# restrictedプロファイル適用後に特権Podを再度デプロイしようとすると拒否される
$ kubectl apply -n cs-lab-debug -f privileged-pod.yaml
#  Error from server (Forbidden): pods "debug-tool" is forbidden:
#  violates PodSecurity "restricted:latest": privileged (container "debug-tool" must not set securityContext.privileged=true)

Public Container Registry High GCP

GCP Artifact Registryのリポジトリに allUsers への読み取り権限が付与され、社内向けのコンテナイメージが誰でも取得できる状態になってしまうシナリオです。イメージに含まれるシークレットや内部実装がそのまま漏洩するリスクがあります。

1. Scenario

サンドボックスのGCPプロジェクトで、外部パートナーにイメージを1つだけ共有する目的で allUsers にreader権限を付与し、共有が終わった後もそのバインディングを削除し忘れたという想定です。このリポジトリを自分で作成し、公開バインディングを検出・是正します。

2. Architecture

3. CLI Commands

lab環境で以下を再現する。リポジトリを作成し、allUsersにreader権限を付与する。

bash
# lab用Artifact Registryリポジトリを作成
$ gcloud artifacts repositories create cs-lab-images \
    --repository-format=docker --location=asia-northeast1 \
    --project=cs-lab-sandbox

# allUsersにreader権限を付与(意図的な誤設定)
$ gcloud artifacts repositories add-iam-policy-binding cs-lab-images \
    --location=asia-northeast1 --project=cs-lab-sandbox \
    --member=allUsers --role=roles/artifactregistry.reader

4. Misconfiguration

IAMポリシーバインディングの memberallUsers になっているため、Google Cloudの認証情報を持たない匿名ユーザーでもリポジトリ内の全イメージをpullできます。

IAM policy binding (excerpt)
{
  "bindings": [
    {
      "role": "roles/artifactregistry.reader",
      "members": [
        "allUsers"
      ]
    }
  ]
}

5. Detection

リポジトリのIAMポリシーを取得し、allUsers バインディングの有無を確認する。

bash
$ gcloud artifacts repositories get-iam-policy cs-lab-images \
    --location=asia-northeast1 --project=cs-lab-sandbox \
    --format=json | grep -A2 allUsers

6. Remediation

allUsers のバインディングを削除し、必要なアクセスは特定のサービスアカウント単位で許可し直す。

bash
# allUsersのバインディングを削除
$ gcloud artifacts repositories remove-iam-policy-binding cs-lab-images \
    --location=asia-northeast1 --project=cs-lab-sandbox \
    --member=allUsers --role=roles/artifactregistry.reader

# 必要なパートナー用サービスアカウントにのみ限定して付与し直す
$ gcloud artifacts repositories add-iam-policy-binding cs-lab-images \
    --location=asia-northeast1 --project=cs-lab-sandbox \
    --member=serviceAccount:partner-pull@cs-lab-sandbox.iam.gserviceaccount.com \
    --role=roles/artifactregistry.reader

7. Verification

IAMポリシーを再取得し、allUsers がもう含まれていないことを確認する。

bash
$ gcloud artifacts repositories get-iam-policy cs-lab-images \
    --location=asia-northeast1 --project=cs-lab-sandbox \
    --format=json | grep allUsers
#  (出力なし = allUsersバインディングは解消済み)

Cloud Logging Investigation Medium Multi-Cloud

このラボはミスコンフィグレーションの是正ではなく、監査ログを読み解くインシデント調査演習です。GuardDutyの異常検知アラートを起点に、CloudTrailのイベント履歴を掘り下げて何が起きたのかを再構築します。

1. Scenario

サンドボックスのAWSアカウントで、GuardDutyが特定のIAMユーザー(svc-reporting)に関して「普段利用しないリージョンからのAPIコール」の異常検知アラートを発報したという想定です。このアラートを起点に、CloudTrailのイベント履歴を辿ってセッションの全体像を調査します。ログの再現には、あらかじめlabアカウント上で該当イベントに相当するCloudTrailログを用意しておきます。

2. Architecture

3. CLI Commands

lab環境で以下を再現する。アラート対象のプリンシパルに関するCloudTrailイベント履歴を取得する。

bash
# 対象プリンシパルの直近24時間のイベント履歴を取得
$ aws cloudtrail lookup-events \
    --lookup-attributes AttributeKey=Username,AttributeValue=svc-reporting \
    --start-time "$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ)" \
    --max-results 50

4. Indicators Found

イベント履歴を時系列に並べると、以下の不審なパターンが確認できます。まず普段利用しないASNから ConsoleLogin の失敗が複数回連続し、その直後に同じIPから成功しています。さらに成功の数分後、同一セッションから CreateAccessKey が呼び出されており、資格情報の窃取後に永続化が試みられたことを示唆しています。

observed event timeline (excerpt)
03:12:01  ConsoleLogin  FAILURE  sourceIP=198.51.100.20 (unfamiliar ASN)
03:12:07  ConsoleLogin  FAILURE  sourceIP=198.51.100.20
03:12:14  ConsoleLogin  FAILURE  sourceIP=198.51.100.20
03:12:41  ConsoleLogin  SUCCESS  sourceIP=198.51.100.20
03:15:02  CreateAccessKey  userName=svc-reporting  sourceIP=198.51.100.20

5. Detection

同じパターン(失敗連続 → 成功 → CreateAccessKey)を検知するためのクエリ・フィルタ例。

CloudTrail Lake query (example)
SELECT eventTime, userIdentity.userName, eventName, sourceIPAddress, errorMessage
FROM cloudtrail_lake
WHERE userIdentity.userName = 'svc-reporting'
  AND eventName IN ('ConsoleLogin', 'CreateAccessKey', 'CreateUser', 'AttachUserPolicy')
  AND eventTime > date_sub(now(), 24h)
ORDER BY eventTime ASC;

6. Remediation

侵害された可能性のあるアクセスキーを無効化し、MFAをリセットしてから再登録を求める。

bash
# 03:15に作成された不審なアクセスキーを無効化
$ aws iam update-access-key --user-name svc-reporting \
    --access-key-id AKIAEXAMPLE12345678 --status Inactive

# MFAデバイスを無効化し、再登録を要求する
$ aws iam deactivate-mfa-device --user-name svc-reporting \
    --serial-number arn:aws:iam::123456789012:mfa/svc-reporting

7. Verification

該当キーが無効化されていること、その後の追跡クエリで同様の異常イベントが発生していないことを確認する。

bash
$ aws iam list-access-keys --user-name svc-reporting
#  AKIAEXAMPLE12345678  Status: Inactive

# 無効化後の期間で同一パターンの異常イベントが再発していないか再確認
$ aws cloudtrail lookup-events \
    --lookup-attributes AttributeKey=Username,AttributeValue=svc-reporting \
    --start-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
#  新たなConsoleLogin失敗やCreateAccessKeyイベントは検出されない

CSPM Misconfiguration Medium Multi-Cloud

オープンソースのCSPMスキャナー(Prowlerなど)がサンドボックスのAWSアカウントに対して複数のファインディングを検出したという想定です。数あるファインディングの中からリスクの高いものを優先順位付けし、公開状態かつ未暗号化のEBSスナップショットを是正します。

1. Scenario

サンドボックスのAWSアカウントで定期的にProwlerを実行しているという想定です。今回のスキャンでは数十件のファインディングが検出されましたが、その中に「暗号化されておらず、かつ全アカウントに公開されているEBSスナップショット」という重大度の高いものが含まれていました。データ流出に直結するため、他のファインディングより優先して対応します。

2. Architecture

3. CLI Commands

lab環境で以下を再現する。Prowlerでスキャンし、対象のチェックに絞り込んで実行する(実行イメージ)。

bash
# EBSスナップショットの暗号化・公開設定に関するチェックのみ実行(実行イメージ)
$ prowler aws --check ec2_ebs_snapshot_encrypted ec2_ebs_public_snapshot \
    --profile cs-lab-sandbox

# 素のAWS CLIでも同等の一覧化が可能
$ aws ec2 describe-snapshots --owner-ids self \
    --filters Name=encrypted,Values=false \
    --query 'Snapshots[].{ID:SnapshotId,Encrypted:Encrypted,VolumeSize:VolumeSize}'

4. Misconfiguration

該当のスナップショットは暗号化されていないうえ、createVolumePermission が全アカウント(group: all)に公開されています。暗号化されていないボリュームの中身がそのまま第三者にコピー・復元されうる状態です。

Prowler finding (excerpt)
{
  "check_id": "ec2_ebs_public_snapshot",
  "status": "FAIL",
  "severity": "critical",
  "resource_id": "snap-0abcdef1234567890",
  "region": "ap-northeast-1",
  "extra": {
    "encrypted": false,
    "public": true,
    "createVolumePermission": [{ "group": "all" }]
  }
}

5. Detection

該当スナップショットの公開権限設定を直接確認する。

bash
$ aws ec2 describe-snapshot-attribute \
    --snapshot-id snap-0abcdef1234567890 --attribute createVolumePermission
#  "CreateVolumePermissions": [{ "Group": "all" }]

6. Remediation

公開権限を削除し、暗号化された複製を新規作成したうえで、以降はそちらを正としてリソースを切り替える。

bash
# 公開権限(group: all)を削除
$ aws ec2 modify-snapshot-attribute --snapshot-id snap-0abcdef1234567890 \
    --attribute createVolumePermission \
    --group-names all --operation-type remove

# 暗号化された複製スナップショットを作成
$ aws ec2 copy-snapshot --source-snapshot-id snap-0abcdef1234567890 \
    --source-region ap-northeast-1 --region ap-northeast-1 --encrypted \
    --kms-key-id arn:aws:kms:ap-northeast-1:123456789012:key/cs-lab-key

7. Verification

元のスナップショットが非公開に戻ったこと、新しい複製が暗号化済みであることを確認する。

bash
$ aws ec2 describe-snapshot-attribute \
    --snapshot-id snap-0abcdef1234567890 --attribute createVolumePermission
#  "CreateVolumePermissions": []  (公開権限は解消済み)

$ aws ec2 describe-snapshots --snapshot-ids snap-0newcopy1234567890 \
    --query 'Snapshots[0].Encrypted'
#  true