
Service Screener v2をスケジュール実行してみた
こんにちは。たかやまです。
弊社いわさの記事でService Screener v2というツールが紹介されていました。
Service Screener v2はAWSのサービス設定をベストプラクティスに基づいて評価し、改善に活用できるレポートを作成するオープンソースツールです。
レポートの詳細については以下の記事をご覧ください。
記事の中では、Service Screener v2をCloudShellから手動で実行する方法を紹介しています。
私もこちらの内容をみてService Screener v2を使っていこうかと思いましたが、こういった環境チェック系のツールは定期的に実行して結果を取得したいものです。
Service Screener v2では定期実行するためのScreener Schedulerも提供しているので、今回はそのスケジューラーを使ってService Screener v2をスケジュールで自動実行する方法を紹介します。
Screener Schedulerの概要
Screener Schedulerは、Service Screener v2を定期的に自動実行するための環境をCDKで構築するテンプレートです。
全体的な構成は以下のようになります。
執筆時点でデプロイされるリソースは以下の通りです。
- DynamoDB: 各セキュリティスクリーニングの実行スケジュールと設定を管理
- Lambda(設定更新): 設定変更を検知し、スケジュールと通知先を自動更新
- EventBridge Scheduler: 定期的にAWS Batchを実行
- AWS Batch: ECS FargateでService Screenerを実行するためのジョブ。最初にスポットインスタンスが使用され、利用できない場合は、オンデマンドインスタンスが使用される
- ECS Fargate: コンテナ環境上でService Screenerを実行
- S3: Service Screenerの実行結果を保存
- EventBridge + Lambda: 新しいレポートを検知して自動処理
- Lambda(結果処理): 前回との差分を分析し、新規・解決済みの内容をまとめる
- SNS: 分析結果をメールで関係者に通知
忙しい方向けのコマンドまとめ
CloudShell上で以下のコマンドを実行することで、Service Screener v2のスケジューラーをデプロイすることができます。
# 環境準備
cd /tmp
python3 -m venv .
source bin/activate
python3 -m pip install --upgrade pip
rm -rf service-screener-v2
git clone https://github.com/aws-samples/service-screener-v2.git
cd service-screener-v2
pip install -r requirements.txt
# 環境変数設定(適宜変更)
export NAME="scheduler-sample" # スケジューラーの名前
export EMAIL_LIST="scheduler@example.com" # 結果通知先メールアドレス
export SERVICES="" # チェック対象サービス(空欄は全サービス)
export REGIONS="ALL" # チェック対象リージョン(ALLは全リージョン)
export FREQUENCY="cron(0 12 * * ? *)" # 実行スケジュール(cron(UTC)形式)
export CROSSACCOUNTS='' # クロスアカウント設定(空欄は無効)
export BUCKET_NAME="your-bucket" # 結果保存用S3バケット名
export AWS_DEFAULT_REGION=ap-northeast-1 # リソースデプロイ先のデフォルトリージョン
# インフラ準備
cd usecases/scheduler/src/infra
pip install -r requirements.txt
cd ../lambda/ssv2_resultProcesser
pip install -r requirements.txt -t .
cd ../../infra
cdk synth
# CDKデプロイ
cdk bootstrap
cdk deploy
# 初期設定
chmod +x ./deploy.sh
./deploy.sh
クロスアカウントでのスケジュール実行が必要な方は、プラスして(オプション)クロスアカウント実行
の内容を実行してください。
やってみた
事前準備
デプロイには以下が必要です。
- Python3.12 & pip3
- awscli & awscdk
- Docker
CloudShellはこれらがプリインストールされているのでCloudShell上で実行するのがオススメです。
以下の手順でPython仮想環境を作成し、リポジトリをクローンします。
# 作業ディレクトリに移動
cd /tmp
# Python 仮想環境の作成とアクティベート
python3 -m venv .
source bin/activate
# pip のアップグレード
python3 -m pip install --upgrade pip
# リポジトリのクローン
rm -rf service-screener-v2
git clone https://github.com/aws-samples/service-screener-v2.git
cd service-screener-v2
# 依存関係のインストール
pip install -r requirements.txt
環境変数の設定
次に、スケジューラ機能の設定に必要な環境変数を設定します。
こちらはみなさんの環境に合わせて適宜変更してください。
チェック対象サービスはこちらで確認できます。
export NAME="scheduler-sample" # スケジューラーの名前
export EMAIL_LIST="scheduler@example.com" # 結果通知先メールアドレス
export SERVICES="" # チェック対象サービス(空欄は全サービス)
export REGIONS="ALL" # チェック対象リージョン(ALLは全リージョン)
export FREQUENCY="cron(0 12 * * ? *)" # 実行スケジュール(cron(UTC)形式)
export CROSSACCOUNTS='' # クロスアカウント設定(空欄は無効)
export BUCKET_NAME="your-bucket" # 結果保存用S3バケット名
export AWS_DEFAULT_REGION=ap-northeast-1 # リソースデプロイ先のデフォルトリージョン
インフラストラクチャの準備
次に、CDKを使ってインフラを準備します。
cdk synth
コマンドは、CloudFormationテンプレートを生成します。これにより、実際にデプロイする前に生成されるリソースを確認することができます。
# インフラストラクチャの依存関係をインストール
cd usecases/scheduler/src/infra
pip install -r requirements.txt
# Lambda 関数の依存関係をインストール
cd ../lambda/ssv2_resultProcesser
pip install -r requirements.txt -t .
# CDK の合成
cd ../../infra
cdk synth
執筆時点でデプロイされるリソースは以下の通りです。
- DynamoDB: 各セキュリティスクリーニングの実行スケジュールと設定を管理
- Lambda(設定更新): 設定変更を検知し、スケジュールと通知先を自動更新
- EventBridge Scheduler: 定期的にAWS Batchを実行
- AWS Batch: ECS FargateでService Screenerを実行するためのジョブ。最初にスポットインスタンスが使用され、利用できない場合は、オンデマンドインスタンスが使用される
- ECS Fargate: コンテナ環境上でService Screenerを実行
- S3: Service Screenerの実行結果を保存
- EventBridge + Lambda: 新しいレポートを検知して自動処理
- Lambda(結果処理): 前回との差分を分析し、新規・解決済みの内容をまとめる
- SNS: 分析結果をメールで関係者に通知
インフラストラクチャのデプロイ
CDKの実行準備ができたら、実際にインフラをデプロイします。
# CDK のブートストラップ
cdk bootstrap
# CDK のデプロイ
cdk deploy
これでさきほどのリソースがデプロイされます。
メール送信についてはSNSトピックのSubscribeが必要なので忘れずにしましょう。
初回設定の挿入
最後に、環境変数で設定した内容をDynamoDBに挿入します。
# デプロイスクリプトの実行権限を付与
chmod +x ./deploy.sh
# 初回設定を DynamoDB に挿入
./deploy.sh
出力結果は Initial item inserted successfully
が出ればOKです。
出力結果例
(tmp) infra $ ./deploy.sh
No services specified. Proceeding with empty service list.
All regions selected.
Cron expressiom is valid
DynamoDB table name: ServiceScreenerAutomationStack-screenerscheduler1291276B-80XJCXOFZAF5
Inserting initial item into DynamoDB...
Initial item inserted successfully
動作確認
処理が正常実行されると、指定したメールアドレスに結果が通知されます。
メール結果では調査対象リソースで重要度が 「HIGH」 の件数がサマリーとして表示されています。
また、前回の内容と比較して差分で 「New Finding」 と 「Resolved」 として新たな検知件数と解決済み件数も表示されるようですね。
レポート内容については、指定したS3バケットに日付.output.zip
で保存されているので、そちらから確認できます。
(バケット名 : servicescreenerautomations-<環境変数で指定したバケット名><乱数>
)
レポートの見方については最初にご紹介したService Screener v2の紹介ブログを参考にしてください。
また、アカウントIDのフォルダには、 workItem.xlsx
というExcelファイルが保存されています。
こちらは、Service Screener v2の実行結果をExcelファイルとして保存したもので、リソースを一覧で確認する場合にはこちらを参照すると便利そうですね。
(スケジュール実行ではない単発実行の場合には作成されるoutput.zipの中にも同じファイルが存在します。)
(オプション) クロスアカウント実行
Service Screener v2は複数アカウントにまたがって実行することも可能です。
こちらはOrganizations環境やマルチアカウント環境で利用できるオプションです。
非Organizations環境でのクロスアカウント実行
まず、以下のCFnテンプレート(crossAccountRoleCF.yml)をダウンロードします。
こちらのCFnテンプレートを対象の各アカウントで実行することで、Service Screenerが引き受けるロールを作成します。
つぎ、クロスアカウント対象の各アカウント上で先ほどダウンロードしたCFnテンプレートを実行します。
- ExecAccountNo: Service Screenerを実行するアカウントの12桁のAWSアカウント番号
- ExternalID: サードパーティがアカウントにアクセスするために使用する一意の識別子
- RoleName: CloudFormationテンプレートで作成されるロールの名前(デフォルト: ServiceScreenerAssumeRole)
Service Screener v2を実行しているアカウントに戻り、CloudShell上で以下のコマンドを実行しCROSSACCOUNTS環境変数を設定します。
export CROSSACCOUNTS=$(cat << 'EOF' | tr -d '\n' | sed 's/ //g'
{
"general":{
"IncludeThisAccount": true,
"ExternalId":"<対象の各アカウントのExternalID>",
"RoleName":"ServiceScreenerAssumeRole"
},
"accountLists":{
"<対象の各アカウントのAWSアカウント番号>":{
"ExternalId":"<対象の各アカウントのExternalID>"
}
}
}
EOF
)
各パラメータの指定方法は以下の通りです。
{
"general":{
"IncludeThisAccount": true, // 現在のアカウントもスキャンに含めるかどうか(true/false)
"ExternalId":"abc123", // デフォルトのExternalId(セキュリティ強化のため)
"RoleName":"ServiceScreenerAssumeRole" // デフォルトのロール名
},
"accountLists":{
"123456":{
"ExternalId":"zzz" // このアカウント固有のExternalId("abc123"より優先される)
},
"234567":{
"RoleName":"MyReadOnlyRole" // このアカウント固有のロール名
},
"345678":{
"ExternalId": "" // 空の値を設定すると、ExternalIdなしでロール引き受けが試行される
},
"456789":{
// パラメータを省略すると、generalセクションの値がデフォルトとして使用される
// このアカウントでは、ExternalId:"abc123"とRoleName:"ServiceScreenerAssumeRole"が使用される
}
}
}
参考 : crossAccounts.sample.json
環境変数を設定したら、初期設定した環境設定を更新するためにdeploy.shを実行します。
※他の環境変数が未設定の場合、スクリプトの変数チェックでエラーが発生するため、必要に応じて設定してください。
cd /tmp/service-screener-v2/usecases/scheduler/src/infra
./deploy.sh
スクリプト実行後、DynamoDBテーブルの crossAccounts
の設定が更新されていればokです。
スケジュール実行が正常に終了すると、以下のようにアカウントごとにサマリ結果がメール通知されます。
レポート結果についても、指定したS3バケットに日付.output.zip
に2アカウント分保存されています。
zipファイルを展開してindex.html確認すると以下のように右上タブで複数アカウントを切り替えて確認できます。
Organizations環境でのクロスアカウント実行
ちなみにOrganizations環境であれば、クロスアカウント設定が多少楽になるようにスクリプトが用意されています。
まず初めに、非Organizations環境でのクロスアカウント実行と同じようにCFnテンプレートを実行します。
先ほどと同じようにCFnテンプレート(crossAccountRoleCF.yml)をダウンロードしておきます。
次にCloudFormationコンソールを開き、CFn StackSetsでのデプロイを行います。
- ExecAccountNo: Service Screenerを実行するアカウントの12桁のAWSアカウント番号
- ExternalID: サードパーティがアカウントにアクセスするために使用する一意の識別子
- RoleName: 後続のスクリプトでデフォルトRole名の「OrganizationAccountAccessRole」を使用することをオススメ(デフォルト: ServiceScreenerAssumeRole)
あとは適切なオプションを選択していただければですが、「リージョンの指定」は適切なリージョンを一つだけ選択してください。
複数リージョンを選択するとグローバルリソースのRole作成が重複してエラーになる注意してください。ここではus-east-1を選択しています。
ロールのデプロイが完了したら、AWS Organizationsのアカウント情報を自動取得するpython3 organizationsAccountsInit.py
を実行します。
cd /tmp
python3 -m venv .
source bin/activate
python3 -m pip install --upgrade pip
rm -rf service-screener-v2
git clone https://github.com/aws-samples/service-screener-v2.git
cd service-screener-v2
pip install -r requirements.txt
python3 organizationAccountsInit.py
実行すると以下のようなインタラクティブなコマンドが表示されます。
クロスアカウントチェックをするアカウントをスペースキーで選択してEnterキーを押すと[x]が表示されます。
問題なければEnterキーを押します。
(tmp) service-screener-v2 $ python3 organizationAccountsInit.py
Welcome to Service-Screener-v2 helper: OrganizationAccountsJson Generator
You are currently in this account: xxxxxxxxxxxx, which will be automatically included in the scan
Select the accounts to be included into the list
=================================================
> [x] xxxxxxxxxxxx::Account01
[ ] xxxxxxxxxxxx::Account02
[ ] xxxxxxxxxxxx::Account03
[ ] xxxxxxxxxxxx::Account04
Press <space>, <tab> for multi-selection and <enter> to select and accept
次に、クロスアカウントチェックをするアカウントのRole名を指定します。
ここではRole名のデフォルトは「OrganizationAccountAccessRole」になります。さきほど作成したCFnテンプレートで作成したロール名を指定してください。
externalIdも、さきほど作成したCFnテンプレートで作成したロールのExternalIdを指定してください。
問題なければ y を入力してEnterキーを押します。
Enter organization cross accounts role (Leave it blank to use the default role: [OrganizationAccountAccessRole]):
Enter your external id (leave it blank if NONE):
===================Summary=======================
(4) Accounts selected, they are: ('xxxxxxxxxxxx::Account01', 'xxxxxxxxxxxx::Account02', 'xxxxxxxxxxxx::Account03', 'xxxxxxxxxxxx::Account04')
OrganizationAccessRole: OrganizationAccountAccessRole
ExternalId:
=================================================
Confirm to proceed JSON output creation? (y/n)
organizationAccountsInit.py の実行が完了すると、カレントディレクトリに crossAccounts.json
が作成されます。
このファイルにはさきほどインタラクティブモードで入力した情報が保存されています。
{
"general": {
"IncludeThisAccount": true,
"RoleName": "OrganizationAccountAccessRole",
"ExternalId": "your-external-id"
},
"accountLists": {
"Account01": {},
"Account02": {},
"Account03": {},
"Account04": {}
}
}
こちらの内容を以下のコマンドを実行してCROSSACCOUNTS
環境変数に登録します。
export CROSSACCOUNTS=$(cat crossAccounts.json | tr -d '\n' | sed 's/ //g')
あとは非Organizations環境でのクロスアカウント実行と同じように環境設定の更新を行うことで、クロスアカウント実行が可能になります。
cd /tmp/service-screener-v2/usecases/scheduler/src/infra
./deploy.sh
ちなみに、スケジュール実行ではなくCloudShellから単発でクロスアカウント実行したい場合には、crossAccounts.json
ファイルが保存されているディレクトリで以下のコマンドを実行してください。
screener --regions ALL --crossAccounts 1
料金
実際にかかるコストは、実行頻度、設定数、リソース量、スキャン対象アカウント数によって異なりますが、GitHubのドキュメントには以下のようなシナリオが記載されています。
- 設定アカウント数 5: スケジュール週次 , 月額0.42ドル または 年間5ドル
- 設定アカウント数 1: スケジュール週次 , 月額0.1ドル または 年間1.2ドル
- 設定アカウント数 1: スケジュール月次 , 月額0.025ドル または 年間0.3ドル
参考 : https://github.com/aws-samples/service-screener-v2/blob/main/usecases/scheduler/README.md#costs
個人的に気になった点について
Q. Service Screener v2が更新された時にCDKの再デプロイが必要か
A. 必要ない。AWS Batchトリガ時に最新コンテナイメージを取得するようになっている。
Q. Output.zipに格納されているhtmlファイルを直接S3バケットに静的ホスティングするオプションはあるか
A. オプションなし。README.mdに以下の記載があるように、生成されたレポートはローカルでの利用を推奨されている。静的Webホスティングする場合は自己責任での実装が必要。
Important note: The generated report has to be hosted locally and MUST NOT be internet accessible
最後に
Service Screener v2のスケジューラ機能を使うことで、AWS環境の設定状態を継続的に確認することができます。
個人的にはoutput.zipは展開された状態ですぐに見れる状況のほうが使い勝手よさそうなきがするので、構築したスケジューラ機能をカスタマイズしてみたいなと思いました。
この記事が誰かのお役に立てれば幸いです。
以上、たかやま(@nyan_kotaroo)でした。