SRE兼スクラムマスターのブログ

チーム開発が好きなエンジニアブログです。検証した技術やチームの取り組みを書いていきます。

Azure Pipelines で セキュリティ診断を自動化する

概要

Azure DevOps の Pipelines を使って、アプリケーションのセキュリティテストを実施する方法を記載します。 なお、今回は OWASP ZAP というオープンソースのツールを利用します。

OWASP ZAP とは

Open Web Application Security Project によって公開されている Zed Attack Proxy という名前のペネトレーションテストツールです。

www.zaproxy.org

OWASP ZAP は、対象の Web アプリケーションに対してリクエストを送信し、返ってきたレスポンスの内容から脆弱性の有無を判定します。

OWASP ZAP で実行できるスキャンには、以下の種類があります。

自動スキャン: 入力されたURLから自動的なクロールを開始し、見つかったページに対して「攻撃(スキャン)」を行う

静的スキャン: ユーザーが(モンキーテストのようにランダムに)操作した際のレスポンスをもとに脆弱性の有無を判定する

動的スキャン: 静的スキャンの際に操作した内容を、自動的にリクエスト内容を変えて再実行する

ZAP Docker

今回は Azure Pipelines で実行したいため、client版ではなく Docker版の ZAP Docker を利用します。

www.zaproxy.org

Image について

安定版:

docker pull owasp/zap2docker-stable

最新のweekly(週次)リリース:

docker pull owasp/zap2docker-weekly

最新のリリース:

docker pull owasp/zap2docker-live

ベアリリース: 非常に小さなDockerイメージ、ZAPの実行に必要な依存関係のみが含まれ、CI環境に最適の Image です。

docker pull owasp/zap2docker-bare

スキャンの種類について

Baseline Scan: ターゲットに対して 静的スキャンを実施します。(デフォルト: 1分間)

Full Scan: ターゲットに対して 静的スキャンを実施します。(デフォルト: 時間無制限)

API Scan: OpenAPI または GraphQL (post 2.9.0) によって定義された API に対して、動的スキャンを実施します。

オプションについて

オプションが多く非常に柔軟に設定ができます。

細かい設定の方法については機会があれば書きますが、今回は割愛します。

$ docker run --rm -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-stable zap-full-scan.py -h
Usage: zap-full-scan.py -t <target> [options]
    -t target         target URL including the protocol, e.g. https://www.example.com
Options:
    -h                print this help message
    -c config_file    config file to use to INFO, IGNORE or FAIL warnings
    -u config_url     URL of config file to use to INFO, IGNORE or FAIL warnings
    -g gen_file       generate default config file(all rules set to WARN)
    -m mins           the number of minutes to spider for (defaults to no limit)
    -r report_html    file to write the full ZAP HTML report
    -w report_md      file to write the full ZAP Wiki(Markdown) report
    -x report_xml     file to write the full ZAP XML report
    -J report_json    file to write the full ZAP JSON document
    -a                include the alpha active and passive scan rules as well
    -d                show debug messages
    -P                specify listen port
    -D                delay in seconds to wait for passive scanning
    -i                default rules not in the config file to INFO
    -I                do not return failure on warning
    -j                use the Ajax spider in addition to the traditional one
    -l level          minimum level to show: PASS, IGNORE, INFO, WARN or FAIL, use with -s to hide example URLs
    -n context_file   context file which will be loaded prior to scanning the target
    -p progress_file  progress file which specifies issues that are being addressed
    -s                short output format - dont show PASSes or example URLs
    -T                max time in minutes to wait for ZAP to start and the passive scan to run
    -U user           username to use for authenticated scans - must be defined in the given context file
    -z zap_options    ZAP command line options e.g. -z "-config aaa=bbb -config ccc=ddd"
    --hook            path to python file that define your custom hooks

Azure Pipelines で実行する

azure-pipelines.yml の書き方を紹介します。

リポジトリの作り方や Azure Pipelines についての説明は割愛します。

1. Docker CLIをインストールする

        - task: DockerInstaller@0
          inputs:
            dockerVersion: '17.09.0-ce'
          displayName: 'Install Docker'

2. サンプルアプリケーションを起動する

自分がテストしたいアプリケーションを起動してください。 すでに起動しているサービスに対してテストする場合は、このタスクは不要です。

        - task: Bash@3
          inputs:
            targetType: 'inline'
            script: |
              docker run --rm -p 80:80 --detach yeasy/simple-web:latest
          displayName: 'Run Sample Application'

3. ZAP Dockerを実行する

ZAP を起動して対象サイトに 攻撃しています。 -t http://$(ip -f inet -o addr show docker0 | awk '{print $4}' | cut -d '/' -f 1)の部分をテストしたいところに変更しましょう。 なお、攻撃権限がないサイトを設定しないでください。 末尾の true は Azure Pipelines の Bashタスクの仕様上 成功ステータスにするため追加しています。

        - task: Bash@3
          inputs:
            targetType: 'inline'
            script: |
              chmod -R 777  ./
              docker run --rm -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-stable zap-full-scan.py -t http://$(ip -f inet -o addr show docker0 | awk '{print $4}' | cut -d '/' -f 1) -r report.html
              true
          displayName: 'Run ZAP Scan'

4. ZAP レポートをpublishする

        - task: PublishPipelineArtifact@1
          inputs:
            targetPath: '$(Build.SourcesDirectory)/report.html'
            publishLocation: 'pipeline'
          displayName: 'Publish Report'

5. azure-pipelines.yml

全体としてはこんな感じです。

trigger: none

stages:
  - stage: Test
    jobs:
      - job: Build
        pool:
          vmImage: 'ubuntu-20.04'
        steps:

        - task: DockerInstaller@0
          inputs:
            dockerVersion: '17.09.0-ce'
          displayName: 'Install Docker'

        - task: Bash@3
          inputs:
            targetType: 'inline'
            script: |
              docker run --rm -p 80:80 --detach yeasy/simple-web:latest
          displayName: 'Run Sample Application'

        - task: Bash@3
          inputs:
            targetType: 'inline'
            script: |
              chmod -R 777  ./
              docker run --rm -v $(pwd):/zap/wrk/:rw -t owasp/zap2docker-stable zap-full-scan.py -t http://$(ip -f inet -o addr show docker0 | awk '{print $4}' | cut -d '/' -f 1) -r report.html
              true
          displayName: 'Run ZAP Scan'

        - task: PublishPipelineArtifact@1
          inputs:
            targetPath: '$(Build.SourcesDirectory)/report.html'
            publishLocation: 'pipeline'
          displayName: 'Publish Report'

6. CIが完了して結果をダウンロードするとZAPのレポートを確認できます。

pipeline artifact

レポートはこんな感じです。

ZAP report

まとめ

ZAP Docker は、導入がシンプルなのでセキュリティ診断してみようくらいのモチベーションのときにおすすめです。 Azure Pipelines では OWASP Zed Attack Proxy Scan というタスクを用いるパターンもありますが オプションで柔軟に設定を変更したい場合は、Dockerがおすすめですし、ローカル環境でも動作を確認しやすいです。 また、API Scanは実行に時間がかかるため CIに不向きだと思いますが Baseline Scan や 時間をチューニングした Full Scan は継続的に実行することで問題を早めに検知できます。 なお、今回の手順ではレポートをダウンロードして確認するパターンにですが、それだと確認するのが大変なため レポートを Azure Pipelines で確認できる形式に変換するのが便利かもしれません。こちらの変換の仕方は 実践したらまた記事にしようと思います。