コンテンツにスキップ

Redshift.15

検証日: 2026-05-10 / リージョン: ap-northeast-1

概要

Redshift.15 Redshift security groups should allow ingress on the cluster port only from restricted origins は、Amazon Redshift クラスターに関連付けられたセキュリティグループ(SG)の ingress ルールが、インターネット(0.0.0.0/0 または ::/0)からクラスターポートへのアクセスを許可していないかを検証する CSPM コントロール。

判定対象はクラスター自体の設定ではなく、クラスターに関連付けられた SG の ingress ルールである。SG ingress に 0.0.0.0/0 または ::/0 からクラスターポートへの許可ルールがあると FAILED となる。Config ルール redshift-unrestricted-port-access は Periodic 型で、パラメータは持たない。

Redshift.1 との関係(直交する 2 つの評価軸)

Amazon Redshift の公開状態を評価する CSPM コントロールは本 Redshift.15 と Redshift.1(クラスターのパブリックアクセスを禁止) の 2 つがあり、それぞれ異なる観点を評価する。

コントロール評価対象FAILED 条件
Redshift.1クラスターの PubliclyAccessible フラグPubliclyAccessible=true
Redshift.15クラスターに関連付けられた SG の ingress ルール0.0.0.0/0 または ::/0 からクラスターポートへの許可

2 軸は独立しており、以下の 4 通りの組み合わせが論理的にあり得る:

PubliclyAccessibleSG ingress実効的な公開度Redshift.1Redshift.15
false制限あり完全プライベートPASSEDPASSED
false0.0.0.0/0パブリック IP なし、SG は緩いPASSEDFAILED
true制限ありパブリック IP あり、SG は制限FAILEDPASSED
true0.0.0.0/0完全公開(最も危険)FAILEDFAILED

本検証はデフォルト設定(--publicly-accessible--no-publicly-accessible も指定しない、--vpc-security-group-ids 未指定)でクラスターを作成し、SG ingress を変えて Redshift.15 の判定挙動を実測する。後述のとおり、本検証で create-cluster のデフォルトは PubliclyAccessible=false(セキュアバイデフォルト)であることが実測された。よって本検証では上記表の上 2 行(PubliclyAccessible=false)を順にたどる形となり、Redshift.1 は終始 PASSED のまま推移する。

IPv6 について

公式ドキュメントには「ingress が 0.0.0.0/0 または ::/0 の場合に NON_COMPLIANT になる」と記載されている。本検証では IPv4(0.0.0.0/0)のみを対象とし、IPv6(::/0)は実測対象外とする。

本記事で確認すること

本検証では 単一の Redshift クラスター(デフォルト設定で作成)を使って以下を段階的に確認する:

#SG ingressRedshift.15 期待目的
1default SG(ingress は同一 SG 内通信のみ)PASSEDデフォルト状態の確認
2検証用 SG に 0.0.0.0/0 → port 5439 を authorizeFAILED典型的な誤設定の検出
3検証用 SG で 0.0.0.0/0 を revoke、<MY_IP>/32 → port 5439 を authorizePASSED送信元制限による修復

結果

Redshift.15 は、Redshift クラスターに関連付けられた SG の ingress ルールが 0.0.0.0/0 から クラスターポート への許可を含む場合に FAILED となる。送信元を /32 などの特定 IP に制限すれば PASSED に復帰する。判定は SG の ingress ルールのみに依存し、PubliclyAccessible の値や実効的なネットワーク到達性とは独立している。

#SG ingressPubliclyAccessibleRedshift.15
1default SG(同一 SG 内通信のみ)false(デフォルト)PASSED
2検証用 SG に 0.0.0.0/0:5439falseFAILED
3検証用 SG に <検証者のグローバル IP>/32:5439falsePASSED

本検証はすべて PubliclyAccessible=false のまま SG ingress だけ変化させたため、Redshift.1 は終始 PASSED のまま推移した。本検証で 2×2 マトリックスの「PubliclyAccessible=false」の 2 行が実測で埋まった。残る 2 行(PubliclyAccessible=true)は Redshift.1 検証記事 で実測済み。

判明したこと(AWS 公式ドキュメントには明示されていない仕様):

  • PubliclyAccessible のデフォルトは false(セキュアバイデフォルト): create-cluster--publicly-accessible--no-publicly-accessible も指定しない場合、PubliclyAccessible=false でクラスターが作成される。Redshift.1 検証では --publicly-accessible を明示指定していたため、このデフォルト挙動は実測されていなかった。
  • Configuration Item 更新ラグは発生しなかった: MSK.4 検証で発見した「リソース変更が Config CI に自動キャプチャされず、タグ変更で誘発が必要」という事象は、Redshift.15(Periodic 型 + SG の ingress 変更)では発生しなかった。Config 手動トリガー後、7 秒で評価が反映され、約 20 秒で Security Hub に伝播した。

検証環境

検証環境の構成図

フローチャート

    flowchart LR
    s1[1. 前提確認] --> s2[2. 検証用 SG 作成]
    s2 --> s3[3. クラスター作成<br/>デフォルト設定]
    s3 --> s4[4. available 待ち]
    s4 --> s5[5. デフォルト状態で評価<br/>パターン 1]
    s5 --> s6[6. SG 差し替え<br/>default → 検証用]
    s6 --> s7[7. 0.0.0.0/0:5439 追加<br/>パターン 2]
    s7 --> s8[8. /32 に差し替え<br/>パターン 3]
    s8 --> s9[9. クラスター削除]
    s9 --> s10[10. 検証用 SG 削除]
    s10 --> s11[11. 削除確認]
  

実測所要時間

ステップ操作所要時間
3-4Redshift クラスター作成 → available約 9 分(実測上限。検証中に他の作業を挟んだため厳密値は未測定)
5Config 評価反映約 6 秒(Config トリガーから ResultRecordedTime 更新まで)
5Security Hub 反映約 22 秒(Config トリガーから UpdatedAt 更新まで)
6SG 差し替え(modify-clusteractive27 秒以内(初回ポーリングで active
7パターン 2 評価反映(Config)約 7 秒
7パターン 2 反映(Security Hub)約 14 秒
8パターン 3 評価反映(Config)約 7 秒
8パターン 3 反映(Security Hub)約 20 秒
9クラスター削除(delete-clusterdeleted約 3 分 10 秒
合計検証全体(API 操作と待機時間の累積)約 25 分(クラスター作成・削除待機で大半を占める)

Redshift.15 は Periodic 型の Config ルールで、SG ingress の変更は Config で即座に再評価される。MSK.4 で発生した Configuration Item 更新ラグ(ユーザー操作が CI に自動キャプチャされず、タグ変更での誘発が必要)は本検証では発生しなかった。

1. 前提確認

AWS_PROFILE=Workload をエクスポートしてから以下を実行する。

デフォルト VPC の取得

VPC_ID=$(aws ec2 describe-vpcs \
  --filters "Name=is-default,Values=true" \
  --query 'Vpcs[0].VpcId' --output text \
  --region ap-northeast-1)
echo "VPC_ID=$VPC_ID"
VPC_ID=<デフォルト VPC ID>

デフォルト SG の ingress 確認

クラスター作成時(ステップ 3)は --vpc-security-group-ids 未指定のためデフォルト SG が自動的に関連付けられる。ステップ 5 ではこのデフォルト SG の状態で Redshift.15 を評価する(パターン 1)が、そのときに PASSED になるかどうかはデフォルト SG の ingress 内容で決まる。ここで先に確認しておく。

ステップ 2 で作成する検証用 SG は、ステップ 6 でクラスターの関連付け SG をデフォルト SG から切り替えるときに使う。ステップ 7 以降では、この検証用 SG の ingress ルールを追加・変更して、Redshift.15 の判定結果がどう変わるかを確認する。

DEFAULT_SG=$(aws ec2 describe-security-groups \
  --filters "Name=vpc-id,Values=$VPC_ID" "Name=group-name,Values=default" \
  --query 'SecurityGroups[0].GroupId' --output text \
  --region ap-northeast-1)
echo "DEFAULT_SG=$DEFAULT_SG"
DEFAULT_SG=<デフォルト SG ID>
aws ec2 describe-security-groups \
  --group-ids $DEFAULT_SG \
  --query 'SecurityGroups[0].IpPermissions' \
  --region ap-northeast-1
[
    {
        "IpProtocol": "-1",
        "UserIdGroupPairs": [
            {
                "UserId": "<アカウント ID>",
                "GroupId": "<デフォルト SG ID>"
            }
        ],
        "IpRanges": [],
        "Ipv6Ranges": [],
        "PrefixListIds": []
    }
]

IpRanges / Ipv6Ranges が空で、同一 SG 内通信(UserIdGroupPairs)のみであることを確認する。

サブネット取得

Redshift クラスター作成には最低 1 サブネット(Subnet Group 経由)が必要。デフォルト VPC の 3 AZ 分のサブネットを取得する。

aws ec2 describe-subnets \
  --filters "Name=vpc-id,Values=$VPC_ID" \
  --query 'Subnets[].{SubnetId:SubnetId,AZ:AvailabilityZone,Cidr:CidrBlock}' \
  --region ap-northeast-1
[
    {"SubnetId": "<サブネット 1a ID>", "AZ": "ap-northeast-1a", "Cidr": "172.31.32.0/20"},
    {"SubnetId": "<サブネット 1d ID>", "AZ": "ap-northeast-1d", "Cidr": "172.31.16.0/20"},
    {"SubnetId": "<サブネット 1c ID>", "AZ": "ap-northeast-1c", "Cidr": "172.31.0.0/20"}
]

Config ルール名の取得

RULE_NAME=$(aws configservice describe-config-rules \
  --query "ConfigRules[?Source.SourceIdentifier=='REDSHIFT_UNRESTRICTED_PORT_ACCESS'].ConfigRuleName" \
  --output text --region ap-northeast-1)
echo "RULE_NAME=$RULE_NAME"
RULE_NAME=securityhub-redshift-unrestricted-port-access-<ハッシュ>

既存リソースの確認(冪等性確保)

ステップ 2 で作成する検証用 SG、ステップ 3 で作成する Redshift クラスターが既に存在すると後続が失敗するため、事前に確認する。

aws redshift describe-clusters \
  --cluster-identifier redshift-15-test --region ap-northeast-1 2>&1 | head -3
An error occurred (ClusterNotFound) when calling the DescribeClusters operation: Cluster redshift-15-test not found.
aws ec2 describe-security-groups \
  --filters "Name=group-name,Values=redshift-15-test-sg" \
  --query 'SecurityGroups[].GroupId' \
  --region ap-northeast-1
[]

どちらもリソースが存在しない状態であれば、前回検証のクリーンアップが完了しており問題なし。

2. 検証用 SG 作成

パターン 2 以降で ingress ルールを操作する検証用 SG を作成する。ingress は空のまま作成し、ステップ 6 でクラスターに差し替える。

SG_ID=$(aws ec2 create-security-group \
  --group-name redshift-15-test-sg \
  --description "Security group for Redshift.15 verification" \
  --vpc-id $VPC_ID \
  --query 'GroupId' --output text \
  --region ap-northeast-1)
echo "SG_ID=$SG_ID"
SG_ID=<検証用 SG ID>
aws ec2 describe-security-groups \
  --group-ids $SG_ID \
  --query 'SecurityGroups[0].{Id:GroupId,Ingress:IpPermissions}' \
  --region ap-northeast-1
{
    "Id": "<検証用 SG ID>",
    "Ingress": []
}

ingress が空であることを確認する。

3. Redshift クラスター作成(デフォルト設定)

--publicly-accessible--no-publicly-accessible も指定せず、--vpc-security-group-ids 未指定でクラスターを作成する。本検証では実測で PubliclyAccessible=false(セキュアバイデフォルト)、VpcSGs=[default SG]Port=5439 になることを確認する。

なお、--cluster-subnet-group-name も指定しないため、Redshift のデフォルトサブネットグループ(default)が自動的に使用される。これは Redshift.1 検証 と同じ前提。

aws redshift create-cluster \
  --cluster-identifier redshift-15-test \
  --node-type ra3.large \
  --cluster-type single-node \
  --master-username redshiftadmin \
  --master-user-password '<パスワード>' \
  --region ap-northeast-1 \
  --query 'Cluster.{Id:ClusterIdentifier,Status:ClusterStatus,Public:PubliclyAccessible,NodeType:NodeType,VpcSGs:VpcSecurityGroups[].VpcSecurityGroupId,SubnetGroup:ClusterSubnetGroupName}'

<パスワード> は 8 文字以上で英大文字・小文字・数字を含む文字列を指定する(Redshift のパスワードポリシー)。Git 等で管理するスクリプトには書かず、環境変数や対話的入力(read -s -p "Password: " PASSWORD)を推奨。

{
    "Id": "redshift-15-test",
    "Status": "creating",
    "Public": false,
    "NodeType": "ra3.large",
    "VpcSGs": ["<デフォルト SG ID>"],
    "SubnetGroup": "default"
}

PubliclyAccessible: falseVpcSecurityGroups にデフォルト SG(sg-xxx)、ClusterSubnetGroupName: "default" となり、デフォルトサブネットグループとデフォルト SG が自動的に関連付けされていることを確認できる。

PubliclyAccessible のデフォルト値(本検証で実測判明)

Redshift の create-cluster--publicly-accessible--no-publicly-accessible も指定しない場合、PubliclyAccessible はデフォルトで false になる(セキュアバイデフォルト)。AWS 公式ドキュメントには明示されていない挙動だが、本検証で実測された。関連する Redshift.1 検証記事 では --publicly-accessible を明示指定して FAILED 状態を作成していたため、このデフォルト挙動は実測されていなかった。

4. available 待ち

aws redshift wait cluster-available \
  --cluster-identifier redshift-15-test \
  --region ap-northeast-1

aws redshift describe-clusters \
  --cluster-identifier redshift-15-test \
  --query 'Clusters[0].{Status:ClusterStatus,Public:PubliclyAccessible,Port:Endpoint.Port,Endpoint:Endpoint.Address,VpcSGs:VpcSecurityGroups[].VpcSecurityGroupId,SubnetGroup:ClusterSubnetGroupName}' \
  --region ap-northeast-1
{
    "Status": "available",
    "Public": false,
    "Port": 5439,
    "Endpoint": "<クラスター名>.<識別子>.ap-northeast-1.redshift.amazonaws.com",
    "VpcSGs": ["<デフォルト SG ID>"],
    "SubnetGroup": "default"
}

Status: availablePublic: falsePort: 5439(Redshift のデフォルトポート)、VpcSGs: [<デフォルト SG ID>] を確認する。

クラスター ARN の取得

ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
CLUSTER_ARN="arn:aws:redshift:ap-northeast-1:${ACCOUNT_ID}:cluster:redshift-15-test"
echo "CLUSTER_ARN=$CLUSTER_ARN"
CLUSTER_ARN=arn:aws:redshift:ap-northeast-1:<アカウント ID>:cluster:redshift-15-test

Redshift は describe-clusters から直接 ARN を取得できないため、ARN 形式で構築する。以降のステップで Configuration Item 再キャプチャの誘発(必要時)に使用する。

5. デフォルト状態で評価 - パターン 1

デフォルト状態(PubliclyAccessible=false + デフォルト SG)で Redshift.15 が PASSED になることを確認する。

aws configservice start-config-rules-evaluation \
  --config-rule-names $RULE_NAME \
  --region ap-northeast-1
(出力なし)
sleep 90
aws configservice get-compliance-details-by-config-rule \
  --config-rule-name $RULE_NAME \
  --query 'EvaluationResults[].{ResourceId:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType:ComplianceType,ResultRecordedTime:ResultRecordedTime}' \
  --region ap-northeast-1
[
    {
        "ResourceId": "redshift-15-test",
        "ComplianceType": "COMPLIANT",
        "ResultRecordedTime": "<日時>"
    }
]

ComplianceType: COMPLIANT で PASSED 相当の評価であることを確認できる。ResourceId はクラスター識別子(AWS::Redshift::Cluster リソースタイプ)。

Security Hub finding も確認する。ComplianceSecurityControlId=Redshift.15 フィルタを指定して Redshift.15 のみを取得する(Redshift.1 の finding が混在するため)。

sleep 120
aws securityhub get-findings \
  --filters '{
    "ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "Redshift.15"}],
    "AwsAccountId": [{"Comparison": "EQUALS", "Value": "<アカウント ID>"}],
    "RecordState": [{"Comparison": "EQUALS", "Value": "ACTIVE"}]
  }' \
  --query 'Findings[].{Status:Compliance.Status,ResourceId:Resources[0].Id,UpdatedAt:UpdatedAt}' \
  --region ap-northeast-1
[
    {
        "Status": "PASSED",
        "ResourceId": "arn:aws:redshift:ap-northeast-1:<アカウント ID>:cluster:redshift-15-test",
        "UpdatedAt": "<日時>"
    },
    {
        "Status": "PASSED",
        "ResourceId": "AWS::::Account:<アカウント ID>",
        "UpdatedAt": "<日時>"
    }
]

クラスターの finding(arn:aws:redshift:...:cluster:redshift-15-test)が PASSED であることを確認できる。もう 1 件の AWS::::Account:<アカウント ID> はアカウントレベルのレコードで本検証の対象外。

併せて Redshift.1 の Config 評価結果と Security Hub finding も確認しておく(PubliclyAccessible=false のデフォルト挙動の実測確認)。Redshift.1 の Config ルールは Configuration changes 型のため、クラスター作成時の CI 生成で自動評価されており手動トリガーは不要。

REDSHIFT1_RULE=$(aws configservice describe-config-rules \
  --query "ConfigRules[?Source.SourceIdentifier=='REDSHIFT_CLUSTER_PUBLIC_ACCESS_CHECK'].ConfigRuleName" \
  --output text --region ap-northeast-1)
echo "REDSHIFT1_RULE=$REDSHIFT1_RULE"
REDSHIFT1_RULE=securityhub-redshift-cluster-public-access-check-<ハッシュ>
aws configservice get-compliance-details-by-config-rule \
  --config-rule-name $REDSHIFT1_RULE \
  --query 'EvaluationResults[].{ResourceId:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType:ComplianceType,ResultRecordedTime:ResultRecordedTime}' \
  --region ap-northeast-1
[
    {
        "ResourceId": "redshift-15-test",
        "ComplianceType": "COMPLIANT",
        "ResultRecordedTime": "<日時>"
    }
]
aws securityhub get-findings \
  --filters '{
    "ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "Redshift.1"}],
    "AwsAccountId": [{"Comparison": "EQUALS", "Value": "<アカウント ID>"}],
    "RecordState": [{"Comparison": "EQUALS", "Value": "ACTIVE"}]
  }' \
  --query 'Findings[].{Status:Compliance.Status,ResourceId:Resources[0].Id,UpdatedAt:UpdatedAt}' \
  --region ap-northeast-1
[
    {
        "Status": "PASSED",
        "ResourceId": "arn:aws:redshift:ap-northeast-1:<アカウント ID>:cluster:redshift-15-test",
        "UpdatedAt": "<日時>"
    },
    {
        "Status": "PASSED",
        "ResourceId": "AWS::::Account:<アカウント ID>",
        "UpdatedAt": "<日時>"
    }
]

Redshift.1 も Config・Security Hub の両方で COMPLIANT / PASSED となっており、PubliclyAccessible=false(デフォルト)のセキュアな状態が実測で確認できる。これで 2×2 マトリックスの左上セル(false + 制限 SG)は Redshift.1 / Redshift.15 ともに PASSED が実測された。

本検証の Pattern 2 / 3 では PubliclyAccessible=false のまま SG ingress だけ変化させるため、Redshift.1 の評価は終始 PASSED のまま推移する。

6. SG 差し替え(default SG → 検証用 SG)

クラスターに関連付けられた SG をデフォルト SG から検証用 SG に差し替える。

aws redshift modify-cluster \
  --cluster-identifier redshift-15-test \
  --vpc-security-group-ids $SG_ID \
  --region ap-northeast-1 \
  --query 'Cluster.{Status:ClusterStatus,VpcSGs:VpcSecurityGroups[].{Id:VpcSecurityGroupId,Status:Status}}'
{
    "Status": "available",
    "VpcSGs": [
        {"Id": "<デフォルト SG ID>", "Status": "removing"},
        {"Id": "<検証用 SG ID>", "Status": "adding"}
    ]
}

modify-cluster の即時レスポンスでは、デフォルト SG が removing、検証用 SG が adding の過渡的状態。クラスター自体は available を保ったまま非同期で SG 差し替えが進む。

差し替え反映まで少し時間がかかる場合があるため、VpcSecurityGroups[].Statusactive になるまで待つ。

while true; do
  SG_STATUS=$(aws redshift describe-clusters \
    --cluster-identifier redshift-15-test \
    --query "Clusters[0].VpcSecurityGroups[?VpcSecurityGroupId=='$SG_ID'].Status | [0]" \
    --output text \
    --region ap-northeast-1)
  echo "$(date '+%H:%M:%S') SG status: $SG_STATUS"
  case "$SG_STATUS" in
    active) break ;;
    *) sleep 15 ;;
  esac
done
<HH:MM:SS> SG status: active

active になれば差し替え完了。環境によっては adding が観測される場合もある。

7. パターン 2: 0.0.0.0/0 → port 5439 を authorize

検証用 SG に 0.0.0.0/0 からクラスターポート(5439)への ingress を追加する。

aws ec2 authorize-security-group-ingress \
  --group-id $SG_ID \
  --ip-permissions '[{
    "IpProtocol": "tcp",
    "FromPort": 5439,
    "ToPort": 5439,
    "IpRanges": [{"CidrIp": "0.0.0.0/0"}]
  }]' \
  --region ap-northeast-1
{
    "Return": true,
    "SecurityGroupRules": [
        {
            "SecurityGroupRuleId": "<SG ルール ID>",
            "GroupId": "<検証用 SG ID>",
            "GroupOwnerId": "<アカウント ID>",
            "IsEgress": false,
            "IpProtocol": "tcp",
            "FromPort": 5439,
            "ToPort": 5439,
            "CidrIpv4": "0.0.0.0/0",
            "SecurityGroupRuleArn": "arn:aws:ec2:ap-northeast-1:<アカウント ID>:security-group-rule/<SG ルール ID>"
        }
    ]
}
aws ec2 describe-security-groups \
  --group-ids $SG_ID \
  --query 'SecurityGroups[0].IpPermissions' \
  --region ap-northeast-1
[
    {
        "IpProtocol": "tcp",
        "FromPort": 5439,
        "ToPort": 5439,
        "UserIdGroupPairs": [],
        "IpRanges": [{"CidrIp": "0.0.0.0/0"}],
        "Ipv6Ranges": [],
        "PrefixListIds": []
    }
]

0.0.0.0/0 から port 5439 への TCP ingress が追加されたことを確認できる。

Config ルールを手動トリガーして FAILED を確認する。

aws configservice start-config-rules-evaluation \
  --config-rule-names $RULE_NAME \
  --region ap-northeast-1
(出力なし)
sleep 90
aws configservice get-compliance-details-by-config-rule \
  --config-rule-name $RULE_NAME \
  --query 'EvaluationResults[].{ResourceId:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType:ComplianceType,ResultRecordedTime:ResultRecordedTime}' \
  --region ap-northeast-1
[
    {
        "ResourceId": "redshift-15-test",
        "ComplianceType": "NON_COMPLIANT",
        "ResultRecordedTime": "<日時>"
    }
]

ComplianceType: NON_COMPLIANT で FAILED 相当の評価に切り替わったことを確認できる。

評価結果が古い状態のまま返る場合の対処(MSK.4 検証時に同様の事象を発見)

Config の Configuration Item が SG 変更を自動キャプチャしない場合、評価が古い状態に基づいた結果を返すことがある。その場合はタグを変更して Configuration Item の再キャプチャを誘発する。

aws redshift create-tags \
  --resource-name $CLUSTER_ARN \
  --tags Key=VerificationTrigger,Value=Redshift15-Step7 \
  --region ap-northeast-1
(出力なし)
sleep 180
aws configservice start-config-rules-evaluation \
  --config-rule-names $RULE_NAME \
  --region ap-northeast-1
(出力なし)
sleep 90
aws configservice get-compliance-details-by-config-rule \
  --config-rule-name $RULE_NAME \
  --query 'EvaluationResults[].{ResourceId:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType:ComplianceType,ResultRecordedTime:ResultRecordedTime}' \
  --region ap-northeast-1

本検証ではこの対処は不要だった(最初の start-config-rules-evaluation で NON_COMPLIANT の評価結果が返ったため)。

Security Hub finding も確認する。

sleep 120
aws securityhub get-findings \
  --filters '{
    "ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "Redshift.15"}],
    "AwsAccountId": [{"Comparison": "EQUALS", "Value": "<アカウント ID>"}],
    "RecordState": [{"Comparison": "EQUALS", "Value": "ACTIVE"}]
  }' \
  --query 'Findings[].{Status:Compliance.Status,ResourceId:Resources[0].Id,UpdatedAt:UpdatedAt}' \
  --region ap-northeast-1
[
    {
        "Status": "FAILED",
        "ResourceId": "arn:aws:redshift:ap-northeast-1:<アカウント ID>:cluster:redshift-15-test",
        "UpdatedAt": "<日時>"
    },
    {
        "Status": "PASSED",
        "ResourceId": "AWS::::Account:<アカウント ID>",
        "UpdatedAt": "<日時>"
    }
]

クラスターの finding が PASSEDFAILED に遷移した。もう 1 件の AWS::::Account:<アカウント ID> はアカウントレベルのレコードで本検証の対象外。

8. パターン 3: <MY_IP>/32 → port 5439 への差し替え

0.0.0.0/0 のルールを revoke し、特定 IP(/32)からの ingress に差し替える。先に authorize してから revoke する順で、SG が一時的に無防備になる瞬間を避ける。

MY_IP=$(curl -s https://checkip.amazonaws.com | tr -d '[:space:]')
if [[ ! "$MY_IP" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
  echo "MY_IP 取得失敗または形式不正: '$MY_IP'"; exit 1
fi
echo "MY_IP=$MY_IP"
MY_IP=<検証者のグローバル IP>

先に /32 のルールを追加する。

aws ec2 authorize-security-group-ingress \
  --group-id $SG_ID \
  --ip-permissions "[{
    \"IpProtocol\": \"tcp\",
    \"FromPort\": 5439,
    \"ToPort\": 5439,
    \"IpRanges\": [{\"CidrIp\": \"${MY_IP}/32\"}]
  }]" \
  --region ap-northeast-1
{
    "Return": true,
    "SecurityGroupRules": [
        {
            "SecurityGroupRuleId": "<SG ルール ID>",
            "GroupId": "<検証用 SG ID>",
            "GroupOwnerId": "<アカウント ID>",
            "IsEgress": false,
            "IpProtocol": "tcp",
            "FromPort": 5439,
            "ToPort": 5439,
            "CidrIpv4": "<検証者のグローバル IP>/32",
            "SecurityGroupRuleArn": "arn:aws:ec2:ap-northeast-1:<アカウント ID>:security-group-rule/<SG ルール ID>"
        }
    ]
}

その後、0.0.0.0/0 のルールを削除する。

aws ec2 revoke-security-group-ingress \
  --group-id $SG_ID \
  --ip-permissions '[{
    "IpProtocol": "tcp",
    "FromPort": 5439,
    "ToPort": 5439,
    "IpRanges": [{"CidrIp": "0.0.0.0/0"}]
  }]' \
  --region ap-northeast-1
{
    "Return": true,
    "RevokedSecurityGroupRules": [
        {
            "SecurityGroupRuleId": "<ステップ 7 で作成した SG ルール ID>",
            "GroupId": "<検証用 SG ID>",
            "IsEgress": false,
            "IpProtocol": "tcp",
            "FromPort": 5439,
            "ToPort": 5439,
            "CidrIpv4": "0.0.0.0/0"
        }
    ]
}

SG の ingress が期待通りになっているか確認する。

aws ec2 describe-security-groups \
  --group-ids $SG_ID \
  --query 'SecurityGroups[0].IpPermissions' \
  --region ap-northeast-1
[
    {
        "IpProtocol": "tcp",
        "FromPort": 5439,
        "ToPort": 5439,
        "UserIdGroupPairs": [],
        "IpRanges": [{"CidrIp": "<検証者のグローバル IP>/32"}],
        "Ipv6Ranges": [],
        "PrefixListIds": []
    }
]

0.0.0.0/0 が消え、<検証者のグローバル IP>/32 のみが残ったことを確認できる。

Config ルールを手動トリガーして PASSED に復帰したことを確認する。

aws configservice start-config-rules-evaluation \
  --config-rule-names $RULE_NAME \
  --region ap-northeast-1
(出力なし)
sleep 90
aws configservice get-compliance-details-by-config-rule \
  --config-rule-name $RULE_NAME \
  --query 'EvaluationResults[].{ResourceId:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,ComplianceType:ComplianceType,ResultRecordedTime:ResultRecordedTime}' \
  --region ap-northeast-1
[
    {
        "ResourceId": "redshift-15-test",
        "ComplianceType": "COMPLIANT",
        "ResultRecordedTime": "<日時>"
    }
]

ComplianceType: COMPLIANT で PASSED 相当の評価に復帰したことを確認できる。

NON_COMPLIANT のまま返る場合: ステップ 7 の callout を参照。タグ変更で Configuration Item の再キャプチャを誘発する(タグ値は VerificationTrigger=Redshift15-Step8 のように変えて区別する)。本検証ではこの対処は不要だった(最初の start-config-rules-evaluation で COMPLIANT の評価結果が返ったため)。

Security Hub finding も確認する。

sleep 120
aws securityhub get-findings \
  --filters '{
    "ComplianceSecurityControlId": [{"Comparison": "EQUALS", "Value": "Redshift.15"}],
    "AwsAccountId": [{"Comparison": "EQUALS", "Value": "<アカウント ID>"}],
    "RecordState": [{"Comparison": "EQUALS", "Value": "ACTIVE"}]
  }' \
  --query 'Findings[].{Status:Compliance.Status,ResourceId:Resources[0].Id,UpdatedAt:UpdatedAt}' \
  --region ap-northeast-1
[
    {
        "Status": "PASSED",
        "ResourceId": "arn:aws:redshift:ap-northeast-1:<アカウント ID>:cluster:redshift-15-test",
        "UpdatedAt": "<日時>"
    },
    {
        "Status": "PASSED",
        "ResourceId": "AWS::::Account:<アカウント ID>",
        "UpdatedAt": "<日時>"
    }
]

クラスターの finding が FAILEDPASSED に復帰した。

9. クラスター削除

aws redshift delete-cluster \
  --cluster-identifier redshift-15-test \
  --skip-final-cluster-snapshot \
  --region ap-northeast-1 \
  --query 'Cluster.{Id:ClusterIdentifier,Status:ClusterStatus}'
{
    "Id": "redshift-15-test",
    "Status": "deleting"
}
aws redshift wait cluster-deleted \
  --cluster-identifier redshift-15-test \
  --region ap-northeast-1
(出力なし)

10. 検証用 SG 削除

クラスター削除後、検証用 SG を削除する。SG がクラスターに関連付けられている間は削除できないため、クラスター削除完了後に実行する。

aws ec2 delete-security-group \
  --group-id $SG_ID \
  --region ap-northeast-1
{
    "Return": true,
    "GroupId": "<検証用 SG ID>"
}

11. 削除確認

aws redshift describe-clusters \
  --cluster-identifier redshift-15-test --region ap-northeast-1 2>&1 | head -3
An error occurred (ClusterNotFound) when calling the DescribeClusters operation: Cluster redshift-15-test not found.
aws ec2 describe-security-groups \
  --group-ids $SG_ID --region ap-northeast-1 2>&1 | head -3
An error occurred (InvalidGroup.NotFound) when calling the DescribeSecurityGroups operation: The security group '<検証用 SG ID>' does not exist

Amazonアソシエイトリンク