「AWS無料相談会」をオンラインで開催中

CodeGuruがPython対応したようなので試してみた

CodeGuruがPython対応したようなので試してみた

Amazon CodeGuru Reviewer の Python サポートの一般提供を開始

機械学習などにより開発コードのレビューを自動的に行ってくれるツール、"Amazon CodeGuru Reviewer"の対応言語にPythonが追加されたことが発表されました。
https://aws.amazon.com/jp/about-aws/whats-new/2021/04/python-support-amazon-codeguru-reviewer-now-generally-available/

AWSでの設定自動化などをPythonで書いたAWS Lambdaの関数で実装することが多かったので、PythonでもCodeGuruによってAWSのベストプラクティスに準じた改善点の指摘を受けられるようになるのであれば嬉しい限りです。

実際にどのような指摘事項が出てくるのか確認するべく、試してみました。

CodeCommitとCodeGuru設定

自動レビュー対象のコード内容

まず、分析対象となるコード群をコード管理サービスのリポジトリに格納します。
GitHubなどの外部サービスでも対応していればCodeGuruは利用可能なのですが、今回はAWSアカウント内で設定を完結させてしまいたかったので、AWS CodeCommitにコードを置くことにしました。


Serverless Framework用のファイルなども含まれていますが、Pythonで書かれた handler.py の内容が診断されることを期待します。

handler.py の内容は以下の通りです。

import json
import os
import boto3

def deactivate_access_key(access_key):
    response = access_key.deactivate()
    print(response)
    HTTPStatusCode = response['ResponseMetadata']['HTTPStatusCode']
    print("HTTPStatusCode:")
    print(HTTPStatusCode)
    accessKeyId = access_key.access_key_id
    print(accessKeyId + " is deactivated.")
    return

def main(event, context):
    # 環境変数から取得
    targetAccessKeyUserName = os.environ['TARGET_ACCESS_KEY_USER_NAME']
    # IAMのclientとresource作成
    iamClient = boto3.client('iam')
    iamResource = boto3.resource('iam')
    # IAMユーザーのアクセスキーを取得し無効化
    keys=iamClient.list_access_keys(UserName=targetAccessKeyUserName)
    for key in keys['AccessKeyMetadata']:
        access_key = iamResource.AccessKey(targetAccessKeyUserName, key['AccessKeyId'])
        # アクセスキーの無効化
        deactivate_access_key(access_key)
    return

これは以前、

AWSアクセスキーを自動的に無効化する方法

https://blog.mmmcorp.co.jp/blog/2020/12/09/deactivate-aws-access-key/

にて実装していた内容で、

  • 任意の(環境変数で指定された)IAMユーザーのアクセスキーを取得する
  • 取得されたアクセスキーを無効化する

というような内容です。

CodeGuruと連携

以上の内容のコードが置かれたCodeCommitとCodeGuruを連携します。


CodeCommitの画面上から連携を行いたいリポジトリを選択


そして「リポジトリ」の「設定」を開き、"Amazon CodeGuru Reviewer"のタブから関連付け設定を行う。
(画像は関連付け済みの状況)

以上の設定でこのCodeCommitリポジトリを対象にCodeGuruのサービスを使うことができます。

CodeGuruのリポジトリ全体のレビューを実行

関連付け設定を終えたら、まずはリポジトリ全体のコードレビューを実行してみます。

「レビュー担当者」の「コードレビュー」を開き、「リポジトリの分析」のタブを開くと出てくる、「リポジトリ分析を作成」を開きます。


そして次のような必要事項を入力します。

  • 「コードの推奨事項」を選択
  • 分析対象にしたいリポジトリを選択
  • 分析対象にしたいブランチ名を記入

そして「リポジトリの分析 を作成」を押して分析が完了するのを待ちます。
(今回、コード量が比較的少ないと思うのですが、それでも数分はかかりました。)

レビュー結果

「保留中」だったのが「完了」になったらレビュー結果を見てみましょう。

今回は推奨事項は1件検出されたようです。
指摘内容は以下の通り

The API method list_access_keys returns paginated results instead of all results. Consider using the pagination API or checking one of the following keys in the response to verify that all results were returned: IsTruncated, Marker, NextToken.

とのこと。
冒頭に載せたコードから抜粋すると

(略)

def main(event, context):
    # 環境変数から取得
    targetAccessKeyUserName = os.environ['TARGET_ACCESS_KEY_USER_NAME']
    # IAMのclientとresource作成
    iamClient = boto3.client('iam')
    iamResource = boto3.resource('iam')
    # IAMユーザーのアクセスキーを取得し無効化
    keys=iamClient.list_access_keys(UserName=targetAccessKeyUserName)
    for key in keys['AccessKeyMetadata']:
        access_key = iamResource.AccessKey(targetAccessKeyUserName, key['AccessKeyId'])
        # アクセスキーの無効化
        deactivate_access_key(access_key)
    return

とあるうちの

    keys=iamClient.list_access_keys(UserName=targetAccessKeyUserName)

の部分から指摘されているようです。
boto3の”iam”のClientの list_access_keys のメソッドを使って

  • 該当するIAMユーザーのアクセスキーを取得する

という処理をしているですが、その状況に対して

  • 「この場合は、paginateされたレスポンスが返ってくるので、条件にマッチした内容が1発で全件返って取得できているかが担保されないよ。」
  • 「ちゃんと全件取得できているように担保したいなら paginationをAPI使うか、レスポンス中にIsTruncated, Marker, NextTokenなどのキーが含まれているのでそれをみてチェックするようにしてね」

という具合でしょうか。

・・・なるほど勉強になります。 learn more で公式ドキュメントに飛べるのも嬉しいですね。

言語を問わずAWS SDKにて list_ 系のAPIを使うとき、一度に取得できる情報の件数の制約に引っかかる場合があります。(一度に〜〜件分の情報しか取得されない。など)
今回は「IAMユーザーに紐づくアクセスキー」の情報取得なので、最大でも2件しか存在し得ないため件数制約は気にする必要はないと思いますが、CodeGuruの動作検証としてレビューに従って改修してみます。

改訂版とレビュー結果

改訂版の内容が以下の通り

(略)

def main(event, context):
    # 環境変数から取得
    targetAccessKeyUserName = os.environ['TARGET_ACCESS_KEY_USER_NAME']
    # IAMのclientとresource作成
    iamClient = boto3.client('iam')
    iamResource = boto3.resource('iam')
    # IAMユーザーのアクセスキーを取得し無効化
    paginator = iamClient.get_paginator('list_access_keys')
    page_iterator = paginator.paginate(UserName=targetAccessKeyUserName)
    for page in page_iterator:
        for key in page['AccessKeyMetadata']:
            access_key = iamResource.AccessKey(targetAccessKeyUserName, key['AccessKeyId'])
            # アクセスキーの無効化
            deactivate_access_key(access_key)
    return
  • boto3のiamのClientで list_access_keys 用のpaginatorを作成
  • paginatorを使って該当するIAMユーザーの情報取得用のpage_iteratorを作成
  • page_iteratorをループ処理して、アクセスキーを取得する

というような実装に書き換えました。そしてそのあとは従来通りアクセスキーを無効化して行っています。

そして、その状態で分析を再度実行して結果を見てみると

現時点ではコードの推奨事項はありません。

無事、指摘事項が解消されたようです!

まとめ

今回は list_ 系のAPIの指摘で、かつ気にしなくても影響はないような場面(IAMユーザーのアクセスキーの取得)でしたが、 list_ 系のAPIを使う場面次第では「問題なさそう」ということで人力のレビューは通過しつつも、いざ稼働すると

  • 期待した通りにならなかった(実は情報取得の上限制約のせいで部分的にしか処理されなかった)

などということが考えられます(例えば、「S3バケット内のオブジェクト情報取得して、それに基づいて削除する」・・・など?)

今回のようにCodeGuruはAWS SDKの「仕様」の観点などから自動的なレビューをしてくれるので、そういった状況を未然に予防でき、Pythonで書かれたコードの安全性を高めるのに役立てられそうです。

例えば、AWS Lambdaを使った自動化においてPythonが使用される場面は比較的多いかと思います。
一度既存のLambda関数の実装がAWSのベストプラクティスに準じているかの見直しをするためCodeGuruの分析にかけてみるのはいかがでしょうか?