F-Secure Radar API を CodePipeline に組み込んで脆弱性診断を自動実行してみた
エフセキュア 様が提供している脆弱性管理ツール、F-Secure Radar をご存知でしょうか?
管理画面上で脆弱性診断の実行・管理等を実施できるツールなのですが、実は豊富な API が用意されています。
そこで、本エントリでは F-Secure Radar API を CI/CD パイプラインから呼び出す事で、自動で脆弱性診断を実施する仕組み作りを試してみます。
目次
- F-Secure Radar API を見てみる
- 構成
- やってみた
- 1. 基本的な CI/CD パイプラインの構築
- 2. スキャンの設定
- 3. APIキー と スキャンID を取得
- APIキーの取得
- スキャンID の取得
- 4. Lambda の作成
- 5. CodePipeline の編集
- Lambda 呼び出しアクションの追加
- 手動承認のアクションを作成
- 6. 動かしてみる
- 終わりに
F-Secure Radar API を見てみる
まずはどんな API が提供されているのか見てみましょう。
F-SECURE RADAR API の下部に API documentation があります。
「Assets monitoring」「Vulnerability scans」の様に API がカテゴリ分けされています。
カテゴリをクリックすると、API 一覧が表示されますが、Swagger が埋め込まれていて非常に見やすいです。
ざっと見ただけでも数百の API が提供されている様ですので、やりたい事に合わせて柔軟に API を選定し利用することが出来そうです!
構成
今回の構成は以下になります。
- ユーザーはソースを変更し CodeCommit に Push
- CodeCommit への Push をトリガーに CodePipeline が作動
- CodePipeline から Lambda を呼び出す
- Lambda からシステムスキャンを開始する F-secure Radar API を呼び出す
- F-Secure Radar でシステムスキャンが実施される
- システムスキャンが終了したら、F-Secure Radar からユーザーに通知が送られる
- ユーザーはスキャン結果を確認し、問題なければ CodePipeline 上で "承認" を行う
- 承認されると、CodePipeline は CodeDeploy を作動させる
- CodeDeploy によってソースの変更が反映される
やってみた
以下の流れで進めてみます。
- 基本的な CI/CD パイプラインの構築
- スキャンの設定
- APIキー と スキャンID を取得
- Lambda の作成
- CodePipeline の編集
- テスト
1. 基本的な CI/CD パイプラインの構築
今回は AWS の公式チュートリアルに沿って基本的な CI/CD パイプラインを構築しました。
チュートリアル: シンプルなパイプラインを作成する (CodeCommit リポジトリの場合)
上記チュートリアルに沿って作業を実施すると、下記図の様なリソースが作成された状態になります。
2. スキャンの設定
F-Secure Radar 上で Vulnerability scans を作成します。詳細な手順は以下ブログを参照ください。
今回は 「MyCodePipelineDemo」という名前のシステムスキャンを作成しました。
また、スキャン開始/終了時にメール通知が来るように設定もしておきます。
3. APIキー と スキャンID を取得
APIキーの取得
F-Secure Radar API を実行するために必要な APIキー を取得します。
管理画面右上の 「Accout」より「My profile」に移動
My profile 画面の下部に「Add API key」というボタンがあるので、ここから APIキー を作成します。
作成後に表示されるアクセスキーとシークレットキーの値を API 呼び出し時に使用するため、メモしておきます。
スキャンID の取得
今回使用する API は以下になりますが、開始するスキャンを指定するために scanId が必要です。
この ID も API で取得していきます。
まずは、作成したスキャングループの ID を取得します。
curl -X GET https://api.radar.f-secure.com/api/latest/scangroups/simple -H 'Content-Type: application/json' -H 'ApiAccessKey: {取得したアクセスキー}' -H 'ApiSecretKey: {取得したシークレットキー}' | jq .
作成したグループ名と一緒に ID が表示されるので、これをメモします。
次に、以下コマンドで取得したスキャングループからシステムスキャン情報を取得します
curl -X GET https://api.radar.f-secure.com/api/latest/scangroups/{取得したスキャングループID}/systemscans -H 'Content-Type: application/json' -H 'ApiAccessKey:{取得したアクセスキー}' -H 'ApiSecretKey:{取得したシークレットキー}'
作成したシステムスキャン名と一緒に ID が表示されます。これがスキャン開始 API を実行するために必要な scanId になります。
4. Lambda の作成
F-Secure Radar API を呼び出す、以下の Lambda 関数を作成しました。
import os import urllib.request import boto3 code_pipeline = boto3.client('codepipeline') APIACCESSKEY = os.environ['ApiAccessKey'] APISECRETKEY = os.environ['ApiSecretKey'] SYSTEMSCANID = os.environ['SystemScanId'] def lambda_handler(event, context): print('Start Invoke API') try: jobId = event['CodePipeline.job']['id'] # API呼び出し url = "https://api.radar.f-secure.com/api/latest/vulnerabilityscans/" + SYSTEMSCANID + "/start" headers = { "Content-Type": "application/json", "ApiAccessKey": APIACCESSKEY, "ApiSecretKey": APISECRETKEY } req = urllib.request.Request( url, method="PUT", headers=headers ) urllib.request.urlopen(req) code_pipeline.put_job_success_result(jobId=jobId) except Exception as e: # 予期せぬエラー print(e) code_pipeline.put_job_failure_result(jobId=jobId, failureDetails={'message': 'Function failed due to exception.', 'type': 'JobFailed'}) print('Finish Invoke API') return
ApiAccessKey、ApiSecretKey、SystemScanId はそれぞれ今までの手順で取得した値で、環境変数にセットして読み込んでいます。
ソースコードについての細かい説明は省きますが、以下の処理をしています。
- スキャン開始API("https://api.radar.f-secure.com/api/latest/vulnerabilityscans/" + SYSTEMSCANID + "/start")の呼び出し
- 成功したら code_pipeline.put_job_success_result() で CodePipeline に成功したことを伝える
- 何かしらのエラーが発生した場合には code_pipeline.put_job_failure_result() で失敗したことを伝える
また、この関数を実行するロールには以下のポリシーをアタッチしておく必要があります。
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:*" ], "Effect": "Allow", "Resource": "arn:aws:logs:*:*:*" }, { "Action": [ "codepipeline:PutJobSuccessResult", "codepipeline:PutJobFailureResult" ], "Effect": "Allow", "Resource": "*" } ] }
5. CodePipeline の編集
Lambda を作成したので、CodePipeline を編集します。
ステージが 「Source」 と 「Deploy」 の2つ存在しているはずですので、「+ステージを追加する」を押下します。
ステージ名は「SystemScan」にします。
追加したら、「+アクショングループを追加する」を押下します。
Lambda 呼び出しアクションの追加
以下の様な、 Lambda 関数を呼び出すアクショングループを作成します。
- アクション名 : InvokeSystemScan
- アクションプロバイダー : AWS Lambda
- 関数名 : 作成した Lambda 関数
手動承認のアクションを作成
アクションを作成する前に、SNS のトピックが必要なため事前に作成しておきます。
作成したトピックには自身のメールアドレスをサブスクライブしておきます。
CodePipeline に戻り、作成したアクショングループの後ろに手動承認を行うためのアクショングループを作成します。
レビュー用 URL とコメントはメール本文に記載されますので、スキャン結果の確認 URL など入力してあげると親切かもしれません。
- アクション名 : ConfirmScanResult
- アクションプロバイダー : Manual approval
- SNS トピックの ARN : 事前に作成した SNS トピックのARN
最終的なパイプラインはこの様になりました。
InvokeSystemScan で F-Secure Radar API(Lambda)を呼び出した後は、ConfirmScanResult にて手動で承認が行われるまでは Deploy されなくなります。
スキャンの結果によって承認or否認 を行い、後続の処理(デプロイ)を実行するか否かを決めます。
6. 動かしてみる
一通りリソースの作成が完了したので、動かしてみます。
ソースを変更し、ローカルPC から CodeCommit リポジトリに対して Push を行ってみます。
少し待つと、Lambda を呼び出すアクションが完了した様です。
ConfirmScanResult にて「承認を待機中」と表示されている通り、手動で承認を行うまで Pipeline の処理は進みません。
F-Secure Radar の管理画面を見てみます。
ステータスが「Initialized」となっており、システムスキャンが開始されているのが確認できます。
スキャンが完了するまでしばらく待ちます。
(〜スキャン完了待機中〜)
スキャンが完了すると、F-Secure Radar の管理画面にて設定した通知設定にしたがってメールが来ます。
メール本文に検出された脆弱性の個数とタイプが記載されているので、脆弱性が増えた/減ったレベルであれば管理画面を見に行かなくても判断できそうです。
今回はスキャン結果を問題ないとして、"承認" します。
CodePipeline から、SNS トピックにサブスクライブしたアドレス宛にメールが来ているので、メール下部の「Approve or reject」を押下して承認画面に飛ぶことができます。勿論コンソール画面から直接画面遷移しても問題ありません。
ConfirmScanResult の Review ボタンを押下します。
コメントを入力し、「承認します」を押下します。否認する際には「却下します」を押下する事になります。
承認すると、ここで初めて後続の Deploy が動き始めます。
こうして、今回想定した構成を実現することが出来ました!
終わりに
F-Secure Radar API を使用することで、CI/CD パイプラインに脆弱性診断を組み込むことが出来ました!
また、F-Secure Radar API の数も非常に豊富なため、やりたい事に合わせて細かく作り込む事も出来そうです。
今回は手動承認を挟む形にしましたが、手動操作なしで脆弱性診断の実行と結果判定を行える様なパイプライン構築も検討してみたいと思います。
本記事がどなたかのお役にたてば幸いです。
以上、AWS事業本部の大前でした!