Service Screener v2 を使って AWS 環境の設定チェックを行う

# はじめに
Service Screener v2 というものを見つけたので試してみました。

https://github.com/aws-samples/service-screener-v2

# どんなツール？
以下、GitHub の README に記載の Overview になります。
>Service Screener is a tool that runs automated checks on AWS environments and provides recommendations based on AWS and community best practices.
>
>AWS customers can use this tool on their own environments and use the recommendations to improve the Security, Reliability, Operational Excellence, Performance Efficiency and Cost Optimisation at the service level.
>
>This tool aims to complement the AWS Well Architected Tool.

AWS 環境の設定を自動でチェックして、セキュリティやコスト最適化などの観点から改善点を提案してくれるツールで、AWSのベストプラクティスや Well-Architected Framework に基づいて診断してくれるそうです。
つまり、**「AWSの設定チェックを自動化してくれる、軽くて便利な診断ツール」** ということのようです。

# インストール
ツールの README を参考にインストールを行います。CloudShell を利用して実行しているので今回も同じ環境で実施しようと思います。

まずは作業ディレクトリとして `/tmp` へ移動します。
```bash:ディレクトリ移動
[cloudshell-user@ip-10-134-12-27 ~]$ cd /tmp
```

現在のディレクトリに Python 仮想環境を作成します。
```bash:仮想環境作成
[cloudshell-user@ip-10-134-12-27 tmp]$ python3 -m venv .
```

仮想環境を有効化します。
```bash:仮想環境の有効化
[cloudshell-user@ip-10-134-12-27 tmp]$ source bin/activate
```

pip（Pythonパッケージ管理ツール）を最新バージョンにアップグレードします。
```bash:pip の最新化
(tmp) [cloudshell-user@ip-10-134-12-27 tmp]$ python3 -m pip install --upgrade pip
Requirement already satisfied: pip in ./lib/python3.9/site-packages (21.3.1)
Collecting pip
  Using cached pip-25.0.1-py3-none-any.whl (1.8 MB)
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 21.3.1
    Uninstalling pip-21.3.1:
      Successfully uninstalled pip-21.3.1
Successfully installed pip-25.0.1
```

既存の service-screener-v2 ディレクトリを削除（存在する場合）します。
```bash:service-screener-v2 ディレクトリ削除
(tmp) [cloudshell-user@ip-10-134-12-27 tmp]$ rm -rf service-screener-v2
```

GitHub から Service Screener のコードをクローンします。
```bash:コードのクローン
(tmp) [cloudshell-user@ip-10-134-12-27 tmp]$ git clone https://github.com/aws-samples/service-screener-v2.git
Cloning into 'service-screener-v2'...
remote: Enumerating objects: 4355, done.
remote: Counting objects: 100% (889/889), done.
remote: Compressing objects: 100% (149/149), done.
remote: Total 4355 (delta 779), reused 761 (delta 735), pack-reused 3466 (from 4)
Receiving objects: 100% (4355/4355), 3.94 MiB | 24.73 MiB/s, done.
Resolving deltas: 100% (2408/2408), done.
```

クローンしたディレクトリに移動します。
```bash:ディレクトリの移動
(tmp) [cloudshell-user@ip-10-134-12-27 tmp]$ cd service-screener-v2
```

必要な Python パッケージをインストール
```bash:パッケージインストール
(tmp) [cloudshell-user@ip-10-134-12-27 service-screener-v2]$ pip install -r requirements.txt
Obtaining file:///tmp/service-screener-v2 (from -r requirements.txt (line 9))
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
  Getting requirements to build editable ... done
  Preparing editable metadata (pyproject.toml) ... done
Collecting boto3>=1.35 (from -r requirements.txt (line 1))
  Downloading boto3-1.37.18-py3-none-any.whl.metadata (6.7 kB)
Collecting packaging>=23.1 (from -r requirements.txt (line 2))
  Using cached packaging-24.2-py3-none-any.whl.metadata (3.2 kB)
Collecting XlsxWriter>=3.1.0 (from -r requirements.txt (line 3))
  Using cached XlsxWriter-3.2.2-py3-none-any.whl.metadata (2.8 kB)
Collecting netaddr>=0.9.0 (from -r requirements.txt (line 4))
  Using cached netaddr-1.3.0-py3-none-any.whl.metadata (5.0 kB)
Collecting requests>=2.31.0 (from -r requirements.txt (line 5))
  Using cached requests-2.32.3-py3-none-any.whl.metadata (4.6 kB)
Collecting openpyxl>=3.1.2 (from -r requirements.txt (line 6))
  Using cached openpyxl-3.1.5-py2.py3-none-any.whl.metadata (2.5 kB)
Collecting multiprocess>=0.70 (from -r requirements.txt (line 7))
  Using cached multiprocess-0.70.17-py39-none-any.whl.metadata (7.2 kB)
Collecting simple-term-menu>=1.6.4 (from -r requirements.txt (line 8))
  Using cached simple_term_menu-1.6.6-py3-none-any.whl.metadata (29 kB)
Collecting botocore<1.38.0,>=1.37.18 (from boto3>=1.35->-r requirements.txt (line 1))
  Downloading botocore-1.37.18-py3-none-any.whl.metadata (5.7 kB)
Collecting jmespath<2.0.0,>=0.7.1 (from boto3>=1.35->-r requirements.txt (line 1))
  Using cached jmespath-1.0.1-py3-none-any.whl.metadata (7.6 kB)
Collecting s3transfer<0.12.0,>=0.11.0 (from boto3>=1.35->-r requirements.txt (line 1))
  Using cached s3transfer-0.11.4-py3-none-any.whl.metadata (1.7 kB)
Collecting charset-normalizer<4,>=2 (from requests>=2.31.0->-r requirements.txt (line 5))
  Using cached charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (35 kB)
Collecting idna<4,>=2.5 (from requests>=2.31.0->-r requirements.txt (line 5))
  Using cached idna-3.10-py3-none-any.whl.metadata (10 kB)
Collecting urllib3<3,>=1.21.1 (from requests>=2.31.0->-r requirements.txt (line 5))
  Using cached urllib3-2.3.0-py3-none-any.whl.metadata (6.5 kB)
Collecting certifi>=2017.4.17 (from requests>=2.31.0->-r requirements.txt (line 5))
  Using cached certifi-2025.1.31-py3-none-any.whl.metadata (2.5 kB)
Collecting et-xmlfile (from openpyxl>=3.1.2->-r requirements.txt (line 6))
  Using cached et_xmlfile-2.0.0-py3-none-any.whl.metadata (2.7 kB)
Collecting dill>=0.3.9 (from multiprocess>=0.70->-r requirements.txt (line 7))
  Using cached dill-0.3.9-py3-none-any.whl.metadata (10 kB)
Collecting python-dateutil<3.0.0,>=2.1 (from botocore<1.38.0,>=1.37.18->boto3>=1.35->-r requirements.txt (line 1))
  Using cached python_dateutil-2.9.0.post0-py2.py3-none-any.whl.metadata (8.4 kB)
Collecting urllib3<3,>=1.21.1 (from requests>=2.31.0->-r requirements.txt (line 5))
  Using cached urllib3-1.26.20-py2.py3-none-any.whl.metadata (50 kB)
Collecting six>=1.5 (from python-dateutil<3.0.0,>=2.1->botocore<1.38.0,>=1.37.18->boto3>=1.35->-r requirements.txt (line 1))
  Using cached six-1.17.0-py2.py3-none-any.whl.metadata (1.7 kB)
Downloading boto3-1.37.18-py3-none-any.whl (139 kB)
Using cached packaging-24.2-py3-none-any.whl (65 kB)
Using cached XlsxWriter-3.2.2-py3-none-any.whl (165 kB)
Using cached netaddr-1.3.0-py3-none-any.whl (2.3 MB)
Using cached requests-2.32.3-py3-none-any.whl (64 kB)
Using cached openpyxl-3.1.5-py2.py3-none-any.whl (250 kB)
Using cached multiprocess-0.70.17-py39-none-any.whl (133 kB)
Using cached simple_term_menu-1.6.6-py3-none-any.whl (27 kB)
Downloading botocore-1.37.18-py3-none-any.whl (13.4 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 13.4/13.4 MB 35.7 MB/s eta 0:00:00
Using cached certifi-2025.1.31-py3-none-any.whl (166 kB)
Using cached charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (146 kB)
Using cached dill-0.3.9-py3-none-any.whl (119 kB)
Using cached idna-3.10-py3-none-any.whl (70 kB)
Using cached jmespath-1.0.1-py3-none-any.whl (20 kB)
Using cached s3transfer-0.11.4-py3-none-any.whl (84 kB)
Using cached urllib3-1.26.20-py2.py3-none-any.whl (144 kB)
Using cached et_xmlfile-2.0.0-py3-none-any.whl (18 kB)
Using cached python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
Using cached six-1.17.0-py2.py3-none-any.whl (11 kB)
Building wheels for collected packages: ServiceScreenerV2
  Building editable for ServiceScreenerV2 (pyproject.toml) ... done
  Created wheel for ServiceScreenerV2: filename=servicescreenerv2-2.0-0.editable-py3-none-any.whl size=7849 sha256=15df5c44e2ae5745fb296c10f71bac84111b3cd50748e5b48c57684698a1ca38
  Stored in directory: /tmp/pip-ephem-wheel-cache-gbip6pnl/wheels/48/b9/16/c34a56b58d7bc2beab3cdb804fa9bf2bc6b66b6796c3db032d
Successfully built ServiceScreenerV2
Installing collected packages: ServiceScreenerV2, XlsxWriter, urllib3, six, simple-term-menu, packaging, netaddr, jmespath, idna, et-xmlfile, dill, charset-normalizer, certifi, requests, python-dateutil, openpyxl, multiprocess, botocore, s3transfer, boto3
Successfully installed ServiceScreenerV2-2.0 XlsxWriter-3.2.2 boto3-1.37.18 botocore-1.37.18 certifi-2025.1.31 charset-normalizer-3.4.1 dill-0.3.9 et-xmlfile-2.0.0 idna-3.10 jmespath-1.0.1 multiprocess-0.70.17 netaddr-1.3.0 openpyxl-3.1.5 packaging-24.2 python-dateutil-2.9.0.post0 requests-2.32.3 s3transfer-0.11.4 simple-term-menu-1.6.6 six-1.17.0 urllib3-1.26.20
```

Lambdaの依存パッケージを解凍して準備（高速化のため）します。
```bash:依存パッケージの解凍
(tmp) [cloudshell-user@ip-10-134-12-27 service-screener-v2]$ python3 unzip_botocore_lambda_runtime.py
```

`screener` というショートカットコマンドを定義（main.pyを簡単に実行するため）します。
```bash:ショートカットコマンドの定義
(tmp) [cloudshell-user@ip-10-134-12-27 service-screener-v2]$ alias screener='python3 $(pwd)/main.py'
```

以上で実行する準備が整いました。


# 実行
先ほど定義したショートカットコマンドを使って実行します。

```bash:実行
(tmp) [cloudshell-user@ip-10-134-12-27 service-screener-v2]$ screener --regions ap-southeast-1
 -- Acquiring identify info...

=================================================
Processing the following account id: 555555555555
=================================================

[info] Empty CF stacked created successfully, name:ssv2-eb69532e4e06
PREPARING -- LAMBDA::ap-southeast-1
PREPARING -- CLOUDFRONT::us-east-1
PREPARING -- IAM::us-east-1
PREPARING -- EC2::ap-southeast-1
COMPLETED -- LAMBDA::ap-southeast-1 (0.413s)
PREPARING -- GUARDDUTY::ap-southeast-1
COMPLETED -- GUARDDUTY::ap-southeast-1 (0.276s)
PREPARING -- ELASTICACHE::ap-southeast-1
... (CloudFront::Distribution) - E1L5PTZURK3LBI
Generating IAM Credential Report...
COMPLETED -- CLOUDFRONT::us-east-1 (1.033s)
PREPARING -- CLOUDTRAIL::ap-southeast-1
... (Cloudtrail) - CloudTrail
... (Compute Optimizer Recommendations) 
... (CloudTrail:Common) 
COMPLETED -- CLOUDTRAIL::ap-southeast-1 (0.723s)
PREPARING -- DYNAMODB::ap-southeast-1
... (Cost Explorer Recommendations) 
... (Dynamodb::Generic) 
COMPLETED -- ELASTICACHE::ap-southeast-1 (1.723s)
PREPARING -- EKS::ap-southeast-1
COMPLETED -- EKS::ap-southeast-1 (0.326s)
PREPARING -- KMS::ap-southeast-1
COMPLETED -- KMS::ap-southeast-1 (0.241s)
PREPARING -- CLOUDWATCH::ap-southeast-1
COMPLETED -- DYNAMODB::ap-southeast-1 (1.339s)
PREPARING -- OPENSEARCH::ap-southeast-1
... (EBS::Snapshots) 
COMPLETED -- OPENSEARCH::ap-southeast-1 (0.325s)
PREPARING -- REDSHIFT::ap-southeast-1
... (Cloudwatch Logs) - /aws/cloudfront/LambdaEdge/EJVEFL8O5MBA3
... (Cloudwatch Logs) - /aws/lambda/us-east-1.basic
... (Cloudwatch Logs) - /aws/lambda/us-east-1.prod-psmatching-re
COMPLETED -- CLOUDWATCH::ap-southeast-1 (0.683s)
PREPARING -- S3::ap-southeast-1
... (S3Account) 
Public access configuration not set
COMPLETED -- REDSHIFT::ap-southeast-1 (1.021s)
PREPARING -- APIGATEWAY::ap-southeast-1
... (EC2::Security Group) - sg-04a67036975087815
COMPLETED -- APIGATEWAY::ap-southeast-1 (0.594s)
... (S3Macie) 
... (VPC::Virtual Private Cloud) - vpc-0c3b113f54830ec4a
COMPLETED -- S3::ap-southeast-1 (1.716s)
... (NACL::Network ACL) - acl-0560a9b473777a0fd
COMPLETED -- EC2::ap-southeast-1 (5.623s)
PREPARING -- EFS::ap-southeast-1
COMPLETED -- EFS::ap-southeast-1 (0.277s)
... (IAM::User) - <root_account>
... (IAM::User) - kohei
... (IAM::Role) - ecsEventsRole
... (IAM::Role) - ecsTaskExecutionRole
... (IAM::Role) - EKSClusterRole
... (IAM::Role) - EKSNodeGroupRole
... (IAM::Role) - test
... (IAM::Group) - Admin
... (IAM::Group) - AdministratorAccess
... (IAM:Account) 
NoSuchEntity
COMPLETED -- IAM::us-east-1 (24.266s)
PREPARING -- RDS::ap-southeast-1
COMPLETED -- RDS::ap-southeast-1 (3.151s)
[info] Empty CF stacked deleted successfully, name:ssv2-eb69532e4e06
Total Resources scanned: 30.00 | No. Rules executed: 97.00
Time consumed (seconds): 28.254
DynamodbpageBuilder class not found, using default pageBuilder
LambdapageBuilder class not found, using default pageBuilder
IampageBuilder class not found, using default pageBuilder
ElasticachepageBuilder class not found, using default pageBuilder
Ec2pageBuilder class not found, using default pageBuilder
CloudfrontpageBuilder class not found, using default pageBuilder
RedshiftpageBuilder class not found, using default pageBuilder
ApigatewaypageBuilder class not found, using default pageBuilder
EkspageBuilder class not found, using default pageBuilder
OpensearchpageBuilder class not found, using default pageBuilder
RdspageBuilder class not found, using default pageBuilder
KmspageBuilder class not found, using default pageBuilder
EfspageBuilder class not found, using default pageBuilder
S3pageBuilder class not found, using default pageBuilder
CloudwatchpageBuilder class not found, using default pageBuilder
CloudtrailpageBuilder class not found, using default pageBuilder
... Running CP - TA, it can takes up to 60 seconds
Error: TA unable to generate. Access denied due to support level
Pages generated, download output.zip to view
CloudShell user, you may use this path:  =====>  /tmp/service-screener-v2/output.zip  <===== 
@ Thank you for using Service Screener, script spent 30.448s to complete @
```

実行が完了すると `output.zip` というファイルが出力されます。

```bash:出力確認
(tmp) [cloudshell-user@ip-10-134-12-27 service-screener-v2]$ ls
adminlte            CONTRIBUTING.md            DEVELOPER.md        __fork      LICENSE       NOTICE                       __pycache__  reporter.md       Screener.py  ServiceScreenerV2.egg-info  unzip_botocore_lambda_runtime.py
CODE_OF_CONDUCT.md  CreateService.py           DISCLAIMER.md       frameworks  licenses.txt  organizationAccountsInit.py  README.md    requirements.txt  scripts      setup.py                    usecases
constants.py        crossAccounts.sample.json  DocLinkValidity.py  info.json   main.py       output.zip                   readme.txt   RuleCount.py      services     templates                   utils
```

# 実行内容の確認
出力されたファイルをダウンロードします。
CloudShell の **`[アクション > ファイルのダウンロード]`** をクリックします。
![servicescreener01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/1f1dcc94-91b3-4296-8f6d-31951ae04b7f.png)

出力先のパスを入力し **`[ダウンロード]`** をクリックします。
(同じように進めていた場合は `/tmp/service-screener-v2/output.zip` になります。)
![servicescreener02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/e7db57f1-c734-4bc6-9e69-377c4b362b33.png)

`oupt.zip` を解凍し、`index.html` をクリックします。
![servicescreener03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/534e97e0-46af-4e14-9484-3253e4cb7009.png)

するとブラウザが起動しチェック結果について確認ができます。
![servicescreener04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82090/8dadd1ae-1921-486f-b840-f28e514b9efe.png)


# サンプル
以下、ツールが用意しているサンプルページなので、実践する前にどんな感じかは以下で確認してみてください。

https://dev.d11el1twchxpia.amplifyapp.com/769655955296/index.html


# おわりに
たまたま試してみましたツールですが導入も簡単で見易いなと感じたので今後もっと詳しくみていきたいと思います。