OWASP ZAPとSnykを利用したDevSecOps CI/CD パイプラインを構築してみましょう
はじめに
皆様、初めまして!10月1日入社のアーノルドと申します。ポーランド出身で、専門領域はAWS上のインフラ構築、IaC、DevSecOpsです。
さて早速ですが、このブログ記事では、SCA, SAST, DASTのセキュリティツールを統合した、サンプルのDevSecOps CI/CDパイプラインをご紹介します。SCAとSASTにはSnykを、DASTにはOWASP ZAPを採用します。
※このソリューションは、AWSの以下の記事に基づいています:
https://aws.amazon.com/blogs/publicsector/create-a-secure-and-fast-devsecops-pipeline-with-circleci/
SCA, SAST, DASTとは何?
SCA とは、「Software Composition Analysis」の省略で、ソフトウェア構成分析を意味します。SCAツールは、アプリケーション内で使用されているライブラリやフレームワークなどのサードパーティのコンポーネントを分析し、それらのコンポーネントの脆弱性やライセンスのコンプライアンスを検証します。さらに、コンテナ環境のような現代的なアーキテクチャに適用することができ、非公開コンテナおよびDocker Hubなどの公共レジストリから利用できるコンテナ内の公開された脆弱性を自動的に検出することができます。
よく使われるSCAツール:
・Snyk
・Clair
・Black Duck
・Veracode SCA
など。
SASTとは、「Static Application Security Testing」の省略で、静的アプリケーション・セキュリティ・テストを意味します。SASTのソリューションは、アプリケーションのソースコード、バイトコード、またはバイナリ内の脆弱性を行単位で自動的にチェックし、OWASP Top10などのWebアプリケーションセキュリティリスクランキングに掲載されているようなセキュリティ脆弱性を、開発プロセスの早い段階で検出することを可能にします。これにより、開発者はコードが本番環境にデプロイされる前に欠陥やリスクを特定し、脆弱性を修正することができます。このアプローチは、「シフトレフトアプローチ」と呼ばれます。
SASTの利点は、コードのセキュリティチェックを行うために実行中のアプリサーバーを必要とせず、手動のコードレビューや侵入テストのように速度を落とすことがない点です。
よく使われるSASTツール:
・Snyk
・Sonarqube
・Veracode SAST
など。
DASTとは、「Dynamic Application Security Testing」の省略で、動的アプリケーション・セキュリティ・テストを意味します。DASTのソリューションは、実行中のアプリケーションと対話し、そのアプリケーションの脆弱性を検出することを目的としています。
SASTとの主な違いは、DASTツールを使って脆弱性を検出するためには、Webサーバー、仮想マシン、コンテナなどにアプリケーションをインストールし、解析の際に実行中の状態にする必要がある点です。
DASTツールはウェブアプリケーションの通信をプロキシし、ブラウザ(フロントエンド)とサーバー(バックエンド)の間に位置づけられます。ソースコードを見ることなく、動的解析は侵入テストのような攻撃をシミュレートし、ハッカーの視点から悪用可能な脆弱性とビジネスロジックの問題を発見し、信頼性の高い結果を出します。
よく使われるDASTツール:
・OWASP ZAP
・StackHawk
・Burp Suite
・Arachni
などです。
では、SCA、SAST、DASTのツールを統合したサンプルソリューションを見てみましょう。
検証環境とアーキテクチャ
今回は、以下のようなアーキテクチャのCI/CDパイプラインをデプロイします。SnykとZAPの他に、CI/CDプラットフォームとしてCircleCIを、コンテナイメージの保存先としてAmazon ECRを利用します。
このチュートリアルを進めるには、以下のアカウントが必要になりますね。アカウントの作成は簡単な作業なので、ここでは詳細を省きます。
・GitHub
・CircleCI
・AWS
・Snyk
ちなみに、上記サービスは無料版も提供しています。
① 事前準備
GitHub
このリポジトリをフォークします。検証用の脆弱なアプリと、CircleCI上でCI/CDパイプラインを実行するために必要な設定を含んでいます。
CircleCI
上記ステップでフォークしたリポジトリをCircleCI に連携させ、新規プロジェクトを作成します。
AWS
-
Amazon Elastic Container Registry(ECR)のプライベートリポジトリを作成し、「zap-snyk-circleci」という名前をつけます(名前が異なっていても構いません)。ECRのURLをメモしておきます。
参照資料:https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/repository-create.html -
ECRへの読取り/書込み権限のあるIAMユーザーを作成します(Programmatic accessで良いです)。
※AWSが推奨する最小権限アクセス原則に従って、前のステップで作成したリポジトリへのアクセスのみを許可することが推奨されます。そのユーザーのAWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYを保存しておきます。
Snyk
Snykのアカウントを登録またはログインし、APIトークンを発行します
https://app.snyk.io/login
トークン発行手順:
Account Settings → General → Auth Token
② CircleCIの設定
CircleCIのProject Settings画面で、以下の環境変数を設定します:
- AWS_ACCESS_KEY_ID: 先ほど作成したIAMユーザーのアクセスキーIDを入力します。
- AWS_SECRET_ACCESS_KEY: 同IAMユーザーのシークレットアクセスキーを入力します。
- AWS_REGION: 使用するリージョンを入力します。
- AWS_ECR_ACCOUNT_URL: ECRのURLのホスト名を入力します(.com までのところ、例:dkr.ecr.us-east-1.amazonaws.com)
- AWS_ECR_REPO: ECRリポ作成時に設定した名前を入力します
- SNYK_TOKEN: Snyk APIトークンを入力します。
- CIRCLE_PROJECT_USERNAME: GitHubのユーザーネームを入力します。
- CIRCLE_PROJECT_REPONAME: GitHubのリポジトリ名を入力します。
以上で設定が完了です。
上記①②の手順に沿って正しく設定を行い、GitHubのリポジトリにコードをプッシュするとCI/CDが自動的に動き出します!しかし、最後のステージでビルドが失敗してしまいますね、、、。
なぜこのようなことが起こるのか、次のセクションでご説明します。
パイプラインの構成
ここで、パイプラインのコンフィギュレーションYAMLファイルを参照しながらパイプラインの構成を解説します。
.circleci/config.ymlを見ながらお読みください。
- jobs: run_tests(7行目)
・このステップでは、サンプルnode.jsのアプリをビルドし、単体テストを実行します - jobs: sca_scan(24行目)
・ここでソースコードに対してSnykでSCAのスキャンを実行します -
jobs: sast_dast_scan_docker_image(35行目)
↪︎aws-ecr/build-and-push-image(41行目)
・ここでDockerのイメージをビルドし、ECRにプッシュします↪︎snyk/scan(48行目)
・ECRのイメージに対して、SnykでSASTスキャンを実行します
・スキャンの結果はCircleCIまたはSnykのUIで確認できます※ 今回は50行目の関数fail-on-issuesをfalseに設定していますね。そうすることによって、脆弱性が発見されてもCI/CDパイプラインの実行が継続されます。
このような動作は、今回の検証環境では問題ありませんが、本番のワークロードにおいては脆弱性を放置することは危険ですので、fail-on-issuesをtrueに設定することを推奨します。 -
run:
↪︎name: Run docker container(56行目)
・DASTのスキャンを実行するためにアプリコンテナを起動します↪︎name: ZAP baseline test of application(60行目)
・ZAPのDockerイメージをダウンロードします
・スキャン対象のアプリコンテナに対してZAPでベースラインのDASTスキャン※を実行します
※ベースラインスキャンとは何か、最後のセクションでご説明します!
・スキャン結果レポートをHTMLとJSON形式で保存します(他にwikiとXMLの形式が出力可能)
・スキャンの終了コードを保存しておきます
→ 終了コード 1 は,少なくとも 1 つの FAIL が検出されたことを示します。
→ 終了コード 2と3はWARNなどを示し、パイプラインを切断しません。 -
store_artifacts
・ZAPスキャン結果のレポートをCircleCIアーティファクトとしてエクスポートします -
run: Check result of ZAP scan and fail pipeline if exit code was 1
・ZAPスキャンの終了コードを確認し、1の場合(=コンテナには脆弱性が検出された)パイプラインを失敗させます。↑これがまさにサンプルパイプラインで起こったことで、最後のステージが失敗した理由ですね!
ちなみに、リポジトリのルートディレクトリにある zap-baseline.conf ファイルをいじれば、どのスキャンルールでパイプラインを失敗させるかをカスタマイズすることができます。
おまけ:OWASP ZAPの基礎
ZAPの概要
OWASP ZAPは、OWASP団体の最重要なプロジェクトの一つです。Webアプリケーションの脆弱性を発見するためのオープンソース、クロスプラットフォームのDASTツールです。
スキャンの種類
ZAPでは、3種類のスキャンを実行可能です。
- ベースラインスキャン - 高速で、パッシブのみのスキャン。デフォルトで実行時間は1分。アクティブなスキャンや攻撃は一切行いません。特徴:
- XSSやSQLインジェクションなどの問題は検出できない
- セキュリティヘッダーの欠落やクロスサイトリクエストフォージェリトークンの欠落などの問題は検出できる。
- フルスキャン - パッシブなスキャンとアクティブなスキャン(攻撃)の両方を実行します。スパイダーはデフォルトで時間制限はないので、スキャン対象ウェブアプリによっては数十時間かかる場合があります。
要注意:アプリケーションの所有者の許可なく、このスキャンを実行することは違法行為と見なされる。 - APIスキャン - APIを対象とするスキャン。サポートされているAPIはOpenAPI、SOAP、GraphQL。ローカルファイルとURLの両方をスキャンできます。
ZAPのスキャンを実行するには
ZAPをCI/CDプロセスに組み込むための一番簡単な方法は、Dockerイメージを使用することです。
ZAPのDockerコンテナは、以下4種類が利用可能です。
- 安定版:
docker pull owasp/zap2docker-stable
- ウィークリーリリース(週1回の頻度でリリースされます):
docker pull owasp/zap2docker-weekly
- ライブリリース (GitHub上のZAPプロジェクトのソースコードが変更されるたびにビルドされます):
docker pull owasp/zap2docker-live
- ベアリリース(非常に小さなDockerイメージで、ZAPを実行するために必要な依存関係のみを含みます):
docker pull owasp/zap2docker-bare
以下は、Dockerを利用した場合の基本的なコマンドです:
docker run -t owasp/zap2docker-weekly zap-baseline.py -t [URL]
上記のコマンドをよく見ると、ZAPのウィークリーリリース(owasp/zap2docker-weekly
)を使用してベースラインスキャン(zap-baseline.py
)を実行していることがわかります!
フルスキャンを実行したい場合、zap-baseline.py
をzap-full-scan.py
に置き換えるだけです。
APIスキャンを実行するには、zap-baseline.py
をzap-api-scan.py
に置き換ます。
※APIスキャンの場合、もう少し複雑で、フォーマットの指定も必要になります。ドキュメントを参照にしてみてください。
最後に[URL]
の部分は、対象URLまたはサーバーIPに書き換える必要がありますね。例:https://www.example.com
、http://172.17.0.2:5000/
レポートを出力したいが、どうすれば良いの?
スキャン結果のレポートをファイルに出力することは可能です!
利用可能なフォーマットと、必要なコマンドフラグは以下の通りになります。
-r report.html
:HTML レポートの出力。
-w report.md
:Wiki レポートの出力。
-x report.xml
:XML レポートの出力。
-J report.json
:JSON レポートの出力。
HTMLとJSONのレポート出力を含めたコマンド例:
docker run -v /tmp:/zap/wrk/:rw -t owasp/zap2docker-weekly zap-baseline.py -t http://172.17.0.2:8080 -r report.html -J report.json
※レポート出力の際にはコンテナディレクトリ/zap/wrk
をマウントする必要があります。上記コマンドを実行すると、レポートファイルが/tmpに保存されます。
まとめ
この記事では、DevSecOpsのサンプルソリューションについて紹介しました。
まず、SCA、SAST、DASTといったセキュリティツールの異なるカテゴリーについて説明しました。
次に、DevSecOpsのCI/CDパイプラインのサンプルアーキテクチャを提示し、そのセットアップに必要なステップを説明しました。
その後、バックグラウンドで何が起きているかをより深く理解するために、CircleCIの設定ファイルのコンポーネントについて解説しました。
最後に、OWASP ZAPの使用に関する基本的な知識を共有しました。
皆様のプロジェクトにおいてDevSecOpsのオートメーションを導入する際の参考となれば幸いです!