Redshift.15
概要
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 通りの組み合わせが論理的にあり得る:
PubliclyAccessible | SG ingress | 実効的な公開度 | Redshift.1 | Redshift.15 |
|---|---|---|---|---|
false | 制限あり | 完全プライベート | PASSED | PASSED |
false | 0.0.0.0/0 | パブリック IP なし、SG は緩い | PASSED | FAILED |
true | 制限あり | パブリック IP あり、SG は制限 | FAILED | PASSED |
true | 0.0.0.0/0 | 完全公開(最も危険) | FAILED | FAILED |
本検証はデフォルト設定(--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 ingress | Redshift.15 期待 | 目的 |
|---|---|---|---|
| 1 | default SG(ingress は同一 SG 内通信のみ) | PASSED | デフォルト状態の確認 |
| 2 | 検証用 SG に 0.0.0.0/0 → port 5439 を authorize | FAILED | 典型的な誤設定の検出 |
| 3 | 検証用 SG で 0.0.0.0/0 を revoke、<MY_IP>/32 → port 5439 を authorize | PASSED | 送信元制限による修復 |
結果
Redshift.15 は、Redshift クラスターに関連付けられた SG の ingress ルールが 0.0.0.0/0 から クラスターポート への許可を含む場合に FAILED となる。送信元を /32 などの特定 IP に制限すれば PASSED に復帰する。判定は SG の ingress ルールのみに依存し、PubliclyAccessible の値や実効的なネットワーク到達性とは独立している。
| # | SG ingress | PubliclyAccessible | Redshift.15 |
|---|---|---|---|
| 1 | default SG(同一 SG 内通信のみ) | false(デフォルト) | PASSED |
| 2 | 検証用 SG に 0.0.0.0/0:5439 | false | FAILED |
| 3 | 検証用 SG に <検証者のグローバル IP>/32:5439 | false | PASSED |
本検証はすべて 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-4 | Redshift クラスター作成 → available | 約 9 分(実測上限。検証中に他の作業を挟んだため厳密値は未測定) |
| 5 | Config 評価反映 | 約 6 秒(Config トリガーから ResultRecordedTime 更新まで) |
| 5 | Security Hub 反映 | 約 22 秒(Config トリガーから UpdatedAt 更新まで) |
| 6 | SG 差し替え(modify-cluster → active) | 27 秒以内(初回ポーリングで active) |
| 7 | パターン 2 評価反映(Config) | 約 7 秒 |
| 7 | パターン 2 反映(Security Hub) | 約 14 秒 |
| 8 | パターン 3 評価反映(Config) | 約 7 秒 |
| 8 | パターン 3 反映(Security Hub) | 約 20 秒 |
| 9 | クラスター削除(delete-cluster → deleted) | 約 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 -3An 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: false、VpcSecurityGroups にデフォルト 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: available、Public: false、Port: 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-testRedshift は 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[].Status が active になるまで待つ。
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: activeactive になれば差し替え完了。環境によっては 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 が PASSED → FAILED に遷移した。もう 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 が FAILED → PASSED に復帰した。
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 -3An 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 -3An error occurred (InvalidGroup.NotFound) when calling the DescribeSecurityGroups operation: The security group '<検証用 SG ID>' does not exist