Amazon CodeGuru Securityを使ってみた

この記事は、2024.3Insurtechラボアドベントカレンダーの3日目の記事です。

書いたソースコードにセキュリティ脆弱性がないかどうかをどのように確認していますか?

ペアプロで有識者にソースコードレビューをお願いしたり、「セキュリティチェックリスト」のようなノウハウ集を元に確認するかもしれません。ただ、人力でチェックするのは大変です。とにかくコストが掛かります。

そこで機械的にチェックするライブラリやツールを使おうとなります。今回「Amazon CodeGuru Security」を使う機会があったので、使ってみた感想を書きます。

Amazon CodeGuru Securityとは?

まず最初にこれを。

この記事を書いている2023/3/4現在、CodeGuru Securityはプレビューリリース中です。
明日には機能が激変しているかもしれませんので、ご了承ください。

CodeGuru Securityは何ができるの?

まずは公式の情報から。

Amazon CodeGuru Security is a static application security tool that uses machine learning to detect security policy violations and vulnerabilities. It provides suggestions for addressing security risks and generates metrics so you can track the security posture of your applications. CodeGuru Security’s policies, which are informed by years of Amazon.com and AWS security best practices, help you to create and deploy secure, high-quality applications.

CodeGuru Security is currently supported in several AWS Regions.

(日本語訳)

Amazon CodeGuru Securityは、機械学習を使用してセキュリティポリシー違反や脆弱性を検出する静的アプリケーションセキュリティツールです。セキュリティリスクに対処するための提案を提供し、アプリケーションのセキュリティ姿勢を追跡できるようにメトリクスを生成します。CodeGuru Securityのポリシーは、長年にわたるAmazon.comとAWSのセキュリティ・ベスト・プラクティスに基づいたもので、安全で高品質なアプリケーションの作成とデプロイを支援します。

CodeGuru Securityは現在、いくつかのAWSリージョンでサポートされています。

https://docs.aws.amazon.com/ja_jp/codeguru/latest/security-ug/what-is-codeguru-security.html

SASTツールの一種ということですね。FAQには機械学習とプログラム解析ベースのコードスキャンツールと記載されています。

どんな「セキュリティポリシー違反や脆弱性」を検知してくれるかですが、例として以下のように記載されています。

Examples of security vulnerabilities it detects include resource leaks, hardcoded credentials, and cross-site scripting. CodeGuru Security can also identify code quality issues with some integrations.CodeGuru Security can also identify code quality issues with some integrations. For more information on the types of analysis performed in code scans, see Types of code scans.

(日本語訳)

検出されるセキュリティ脆弱性の例としては、リソースリークハードコードされた認証情報クロスサイトスクリプティングなどがあります。また、CodeGuru Securityは、いくつかの統合のコード品質の問題を特定することができます。コードスキャンで実行される分析の種類の詳細については、コードスキャンの種類を参照してください。

https://docs.aws.amazon.com/ja_jp/codeguru/latest/security-ug/what-is-codeguru-security.html#suggestions

実際のセキュリティスキャンは「Amazon CodeGuru detectors」によって提供されているようです。検知できるものは下記のリンク先に記載があります。

https://docs.aws.amazon.com/codeguru/detector-library/

対応言語

対応しているプログラミング言語に制限があります。

  • Java(Java17以前)
  • JavaScript(ECMAScript 2021 以前)
  • Python(3系の3.11以前)
  • TypeScript
  • Ruby(2.7、3.2)
  • Go(1.18)
  • IaC(AWS CloudFormation 2010-09-09、Terraform(1.6.2以前)、AWS CDK(TypeScript、Python))

個人的には、JavaScriptやTypeScriptで書かれたReactのjsxやtsxは未サポートなのが残念でした。これらのファイルを指定してスキャンするとサポートされていないよエラーが出てきます。下記は、VSCodeにプラグインでCodeGuru Securityを組み込んでスキャンしたときに表示された警告です。

jsxやtsxにこそ、脆弱性を埋めがちなので、今後のサポート拡充に期待です。

利用料金

現時点(2024/3/4)では「無料です。

CodeGuru Reviewer、CodeGuru Profilerは有償ですので、将来的にはCodeGuru Securityも有償になるでしょう。いまのうちに使うしかありませんね!

https://aws.amazon.com/jp/codeguru/pricing/

Amazon CodeGuru Reviewerとの違いは?

公式ドキュメントでは、違いについて以下のように記載されています。

Amazon CodeGuru Reviewer scans your code repositories for code defects related to quality, maintainability, and security and provides recommendations for how to address them. CodeGuru Security is a rearchitected and redesigned version of CodeGuru Reviewer. CodeGuru Security uses hundreds of new security detectors to scan your code, in addition to the detectors that were developed for CodeGuru Reviewer.

(日本語訳)

Amazon CodeGuru Reviewerは、あなたのコードリポジトリをスキャンして、品質、保守性、セキュリティに関連するコードの不具合を探し、その不具合に対処する方法を提案します。CodeGuru Securityは、CodeGuru Reviewerの再アーキテクトされ、再設計されたバージョンです。CodeGuru Securityは、CodeGuru Reviewerのために開発されたディテクターに加え、何百もの新しいセキュリティ・ディテクターを使用してコードをスキャンします。

https://docs.aws.amazon.com/ja_jp/codeguru/latest/security-ug/security-vs-other-services.html

非常によく似ています。あちこちで情報収集したところ、下記のような差があるようです。

  • CodeGuru Reviewerはリポジトリを指定してスキャンする、CodeGuru SecurityはAPIベースでスキャンする。つまり、CI/CDと組み合わせ易いし、IDEなどに組み込み易い
  • CodeGuru SecurityはCodeGuru Reviewerよりも新しいsecurity detectorを使用している
    • 何が違うのか記載したドキュメントは見つかりませんでした・・・
  • CodeGuru Securityにはバグ追跡機構がついている

APIベースであること、バグ追跡機構がついていることはCodeGuru Securityの売りポイントのようなので、公式の「メリット」にも記載されています。

https://aws.amazon.com/jp/codeguru/

セキュリティスキャンを実行する

CodeGuru Securityは統合を売りにしているだけあって、色々なものと組み合わせできます。

IDEに組み込んで実行

CodeGuru SecurityはVSCodeのプラグインとして統合することができます。単独のプラグインではなく、AWS Toolkitの一部になります。

セットアップ手順は、マネコンの「統合」にある「IDEプラグイン」ボタンを押下して確認できます。別ドキュメント見なくてもいいのは楽ですね。

今回はAWS Builder IDを新規登録して利用しました。CodeWhispererの下に「Run Security Scan」として現れてきます。これをクリックするとセキュリティスキャンを実行します。

なお、スキャン時にフォーカスが当たっているソースファイルがサポート対象外の場合、スキャンは停止します。サポート対象ファイルを選んでいれば、同じプロジェクト内にあるサポートされている全ファイルが対象になります。若干わかりにくいですね。

サポート対象ファイルであれば、単体テスト用のファイルも対象になります。テストのためにクレデンシャル情報を埋め込んでいた?いいえ見逃しませんよ、という訳です。

AWS CLI経由で実行

AWS CLI経由でも実行可能です。実行の仕方は、マネコンの「統合」にある「AWS CLIと統合」ボタンを押下して確認できます。

開くと、下記のような手順が出てきます。手順に従って、AWS CLIコマンドを導入し、run_codeguru_security.shをダウンロードしておきます。

run_codeguru_security.shの意味は以下の通りです。

引数の順番引数の意味値の例
1スキャン名。
スキャン結果はCodeGuru Securityの「スキャン」から見えるようになりますが、このとき各スキャン結果を識別する名称がこれになります。同じ名称にするとスキャン結果が混じるため、同じソースツリーに対してバグ自動追跡をしたければ、必ず同じスキャン名を設定します。
scanname-xxx
2スキャンするソースツリーのトップディレクトリパス、または、Zipファイル名のフルパス。

ディレクトリパスを指定した場合、そのディレクトリを丸ごとZip圧縮してからスキャンします(S3にzipファイルをアップロードしているようです)Zipファイルパスを指定した場合、そのZipをスキャンします。
ディレクトリパスで指定すると、node_modulesや.gitのようなディレクトリも対象となります。Zipファイルは自前で作った方が良いでしょう
$HOME/myproduct_top_dir
3リージョン名ap-northeast-1

このシェルスクリプトは、「aws codeguru-security」を最終的に実行しますが、プロファイルを指定することができません。そのため、デフォルト以外のプロファイルを使いたい場合には、環境変数「AWS_PROFILE」を使って設定します。

プロファイルに指定するユーザには「AmazonCodeGuruSecurityFullAccess」をアタッチしておく必要があります。

これが終われば実行です。

# シェル(zsh)に実行権限をつける
$ chmod a+x run_codeguru_security.sh

# 環境変数をexportする(デフォルトプロファイルでよければ不要)
$ export AWS_PROFILE=(プロファイル名)

# スキャン実行
$ ./run_codeguru_security.sh codeguru-knockun-scan-1 ./myproduct_top_dir ap-northeast-1
・・・(省略)・・・
# しばらく待っていると、結果が(スキャン名).jsonファイルに保存され、それがコンソール上に表示されます
{
    "findings": [
        {
            "createdAt": "2024-03-05T19:44:37+09:00",
            "description": "Making sure the parameters defined are used.",
            "detectorId": "cloudformation/cfn-parameters-used@v1.0",
            "detectorName": "parameters used",
            "detectorTags": [
                "parameters",
                "cloudformation"
            ],
            "generatorId": "AmazonCodeGuruSecurity",
・・・(省略)・・・
$

「(スキャン名).json」ファイルの形式はGetFindingsを参照。実行結果はマネージメントコンソールからも確認できます。

マネコン経由で実行

マネージメントコンソールからもスキャン実行可能です。AWS CLIと同じ使い勝手です。GUI化されているだけですね。

CodeGuruのサービスを開き、ナビケーションメニューから「スキャン」を選択。
表示された画面上の「新しいスキャンを作成」ボタンを押下。なお、このメニューを開くには、操作ユーザに「AmazonCodeGuruSecurityFullAccess」が必要です。

スキャン対象のソースを含むZipファイルをアップロードし、スキャン名の入力、必要に応じてタグの設定を行います。スキャン名の役割は、AWS CLIの時と同じです。

「スキャンを作成」で新しいスキャン作成され、スキャンが実行されます。

CodePipeline経由で実行

マネコン上からCodeGuruをサービスとして開き、ナビゲーションメニューの「統合」から下記の「AWS CodePipelineを統合」ボタンを押下します。

表示された画面の説明に従って、CodeBuildプロジェクトとCodePipelineの作成を行います。初回のみCodeBuildプロジェクトの作成が必要です。CodeBuildプロジェクトの作成には、CloudFormationスタックの実行が必要なため、適切な権限を持ったユーザで実行します。

さて、デフォルトで用意されたCloudFormationのテンプレートでは、CodeGuru Securityがセキュリティ脆弱性を検知しても、CodePipelineは正常終了します。セキュリティ脆弱性を検知した時に後続を止めて通知したいという用途に利用するのであれば、異常終了して欲しいところです。

しかし、うまいやり方が思い浮かばなかったので、CloudFormationテンプレートをローカルにダウンロードし、以下の部分を書き換えて、脆弱性が1個でも検出していたら異常終了するように書き換えました。

<書き換え前>

          BuildSpec: !Sub |
              version: 0.2
              phases:
                build:
                  commands:
                    - SCAN_NAME=$(echo $CODEBUILD_INITIATOR | sed 's/\//-/g')
                    - python /usr/app/codeguru/command.py --source_path . --aws_region ${AWS::Region} --output_file_prefix codeguru-security-results --scan_name $SCAN_NAME
                    - cat codeguru-security-results.sarif.json

スキャン名はパイプライン名を元に命名していることがわかります。脆弱性のスキャンには「/usr/app/codeguru/command.py」というpythonファイルが使われているようです。AWS CLIだと思っていました・・・

<書き換え後>

今回は、脆弱性が1つでもあったら落とす(exit 1する)ようにしています。先頭のcurlはjqコマンドをインストールするために実行しています。

          BuildSpec: !Sub |
              version: 0.2
              phases:
                build:
                  commands:
                    - curl -o ./jq -L https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64 && chmod a+x ./jq
                    - SCAN_NAME=$(echo $CODEBUILD_INITIATOR | sed 's/\//-/g')
                    - python /usr/app/codeguru/command.py --source_path . --aws_region ${AWS::Region} --output_file_prefix codeguru-security-results --scan_name $SCAN_NAME
                    - if [ "$(cat codeguru-security-results.sarif.json | ./jq '.runs[].results | length')" -gt 0 ];then cat codeguru-security-results.sarif.json;exit 1;else echo "Success";fi
                    - cat codeguru-security-results.sarif.json

あとは、CodePipelineかCodeBuild側でこのアクションが失敗(exit 1)した時に通知するように設定すればOKです。

ちなみに、/usr/app/codeguru/command.pyは、以下のような形式のjsonを出力します。run_codeguru_security.shでコンソール出力された結果とは異なります。

{
  "version": "2.1.0",
  "$schema": "https://json.schemastore.org/sarif-2.1.0-rtm.4",
  "runs": [
    {
      "tool": {
・・・(省略)・・・
      },
      "results": [
        {
          "ruleId": "typescript/hardcoded-credentials@v1.0",
          "level": "error",
・・・(省略)・・・
        },
        {
          "ruleId": "typescript/insecure-connection@v1.0",
          "level": "warning",
・・・(省略)・・・
        },
・・・(省略)・・・
      }
     ]
    }
   ]
}

runs/resultsにセキュリティ脆弱性の検知結果を吐き出しているように見えたので、この中の要素をカウントして脆弱性の結果があるかどうか判定しています。どこかにドキュメントとして書いてあった訳ではないので、間違っていたら、ごめんなさい。。

スキャン結果の確認

スキャン結果は、実行方法により様々な形式で出力されます。

IDEの場合

スキャンすると、VSCodeの「問題」タブに結果を表示します。

「Detected by CodeWhisperer」が目印です。CodeGuruじゃないんですね。

問題のあったソースの該当箇所にフォーカスを当てると、NG理由が見えます。

「View Details」リンクを押下すると、CWEの内容が表示されます。

さらに、CWE-502のリンクを押下すると下記のようにCWEの詳細を確認できます。

あちこち探しに行かなくてよく、ここだけで完結するので楽ですね。

AWS CLI場合

run_codeguru_security.shを実行したディレクトリ上に「(スキャン名).json」というファイルが出力されますので、ここで確認できます。

ただ、概要確認であればよいのですが、次の「マネコンの場合」にあるようにGUI上で確認した方がよいでしょう。

マネコンの場合

CodeGuruのナビゲーションメニュー「スキャン」からスキャン名ごとに結果を確認できます。

スキャン名のリンク押下でメトリクスを確認できます。

検出結果タブでは、このスキャンで検出された脆弱性の一覧を表示します。

各リンクを開くと、どのようなCWEが出ていて、どのように修正すれば良いのか示してくれます。

上記のコードはパスワード文字列を直接持たせているように見えるから環境変数から取りなさい、というアドバイスですね。ただ、このコードはユーザが画面入力したパスワードを受け取る部分に使うので、環境変数からは取得できません。コードの文脈までは流石に確認できないようですね。

パスワードだけでなく、アクセスキーのような文字列が埋まっていても教えてくれます。ここは公式に記載されていた通りの動きです。

さて、ではバグを解決した場合にはどのように見えるでしょうか?これがCodeGuru Securityの売りの一つであるバグ追跡機構です。下記は2件の脆弱性を解消し、再度スキャンした結果です。

「解決済ステータス」が2件見えます。リンク先で詳細を確認できます。ダッシュボード上では統計情報として確認できます。

ちなみに、スキャン名を変更してスキャンを実行すると、別々の検出件数として加算されてしまうので要注意です。上記は15件→30件になっているので、どこかで2重加算してしまったのかも・・・

CodePipelineの場合

(パイプライン名)」というスキャン名でCodeGuru上に作成されます。見えるものは上と同じです。

まとめ

以上、Amazon CodeGuru Securityを使ってみた、でした。

良かった点

  • バグの自動追跡が使い易い
    • 脆弱性修正の痕跡が統計情報と共に見えるので、解消具合が確認できる
    • これがないと、別途どこかに記録することになって煩雑
  • 脆弱性検知の結果からCWEの詳細をすぐに確認できる
    • IDE、マネコンからその場で確認できるのが便利
  • 実行速度は思ったよりも速い
    • もちろん、ソースコード量に応じて変わると思います
  • IDE、CodePipelineとの統合手順がマネコンから簡単にアクセスできる
    • 他のドキュメントを見なくても良いので楽
  • 機能がシンプル
    • IDEやAPIでスキャンして、結果を確認できて、修正の状況を追跡する、これだけです

気になった点、もう少しと思った点

  • Reactをサポートして欲しかった
    • ロジックがjsxやtsxに書いてしまっているので、、サポートして欲しいな
  • CodeCommitとのリポジトリ統合が欲しかった
    • これが欲しければCodeGuru Reviewer使えよ、というのはもちろん理解しています。ただ、GitHubとかこっちにあるし、できればCodeGuru Security側で見たかったな
  • セキュリティの脆弱性を検知したときに動作するスキャンコマンド(/usr/app/codeguru/command.py)が吐き出すjsonをパースして無理矢理落とす対応を入れて通知させたが、もっとスマートな方法はないのだろうか。そもそも、このコマンドの仕様が見つからない。

ここまで読んでいただき、ありがとうございました。