[テンプレート公開]GitHub ActionsでECRのイメージスキャンでCI/CDするワークフローを組んでみた

2019.12.13

夜にエナドリをキメるとめちゃめちゃ作業が捗ることに気がついてしまった、もこ@札幌オフィスです。

つい先月、ECRでイメージスキャン機能が提供されました!

【超待望アップデート】ECRに対する脆弱性スキャン機能が提供されました

これにより、ECR単体で「デプロイ前にコンテナイメージに脆弱性がないかをスキャン」することや、「CloudWatch Events / Lambdaと連携して実行中のイメージに新たな脆弱性がないかを定期的にスキャン」することができます。

今回は、GitHub Actionsを使ってコンテナをECSにデプロイする前にスキャンしてクリティカルな脆弱性があったらワークフローを停止するようなものを作っていきます。

テンプレート

裏側ではNode.js + AWS SDKを利用して、イメージのスキャンを開始、スキャン結果を取得、パイプラインを進めるか否かの判定をするようにしています。

GitHub Actionsのテンプレートは公開していますので、ymlから数行追加するだけでワークフローにコンテナスキャンを埋め込めるようにしました。

https://github.com/mokocm/ecr-imagescan-action

使い方

ワークフローでイメージをスキャンしたい任意のタイミングでこのようにmokocm/ecr-imagescan-action@v3 を利用する形で追記してあげればOKです。

- name: Image Scan
      id: image-scan
      uses: mokocm/ecr-imagescan-action@v3
      with:
        image-digest: "スキャンするイメージのダイジェスト(SHA256)"
        image-tag: "スキャンするイメージのTag"
        repository-name: "ECRのリポジトリ"
        trigger-severity: "INFORMATIONAL | LOW | MEDIUM | HIGH | CRITICALの中からトリガーするレベルを指定"

イメージのdigestが必要なため、少し工夫する必要があります。

やってみる

実際にやっていきましょう。

3分クッキング感で申し訳ないですが、デプロイするコンテナ、デプロイ先のECS、デプロイまで出来るGitHub Actionsワークフローを用意します。

今回は下記記事にて構築したGitHub Actionsをベースに組み込んでいます。

GitHub ActionsからサクッとFargateにデプロイしてみた

.github/workflows/aws.yml

- name: Login to Amazon ECR
jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v1

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-1

    - name: Login to Amazon ECR
      id: login-ecr
      uses: aws-actions/amazon-ecr-login@v1

    - name: Build, tag, and push image to Amazon ECR
      id: build-image
      env:
        ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        ECR_REPOSITORY: githubactions-nginx
        IMAGE_TAG: ${{ github.sha }}
      run: |
        # Build a docker container and
        # push it to ECR so that it can
        # be deployed to ECS.
        docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
        docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

        echo ::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
        echo ::set-output name=digest::$(docker images --digests | grep $ECR_REGISTRY/$ECR_REPOSITORY | grep $IMAGE_TAG | awk '{print $3}')
        echo ::set-output name=repository-name::$ECR_REPOSITORY
    - name: Image Scan
      id: image-scan
      uses: mokocm/ecr-imagescan-action@v3
      with:
        image-digest: ${{ steps.build-image.outputs.digest }}
        image-tag: ${{ github.sha }}
        repository-name: ${{ steps.build-image.outputs.repository-name }}
        trigger-severity: "CRITICAL"
    - name: Fill in the new image ID in the Amazon ECS task definition
      id: task-def
      uses: aws-actions/amazon-ecs-render-task-definition@v1
      with:
        task-definition: task-definition.json
        container-name: nginx
        image: ${{ steps.build-image.outputs.image }}

    - name: Deploy Amazon ECS task definition
      uses: aws-actions/amazon-ecs-deploy-task-definition@v1
      with:
        task-definition: ${{ steps.task-def.outputs.task-definition }}
        service: spot-ecs
        cluster: spot-ecs
        wait-for-service-stability: true

追記した部分はハイライトした部分のみとなっています。

usesで mokocm/ecr-imagescan-action@v3 を利用するようにし、image-digest, image-tag, repository-name, trigger-severity を代入します。

GitHub Actionsでは echo ::set-output name={変数名}::{outputしたいデータ} のように指定することで、

次のステップで {{ steps.{StepId}.outputs.{変数名} }}のように変数の橋渡しができます!

動作確認

脆弱性があるコンテナを流す

DockerHubで公開されているNginxイメージの中で一番古く、4年前が最終更新のnginx:1.9.9のイメージで試してみます。

masterブランチにPushすると、正常にイメージスキャンを開始し、ワークフローが停止しました!

脆弱性がないコンテナを流す

続いて脆弱性のないコンテナを流してみましょう。 今回は検証でnginx:mainline-alpineのイメージを使っています。

コンテナスキャン結果のステータスがCOMPLATE、 findingSeverityCountstrigger-severity で指定したタイプの脆弱性がなければ正常に完了します。

全体のワークフローが流れるとこんな感じになります。

今回GitHub Actionsを利用したリポジトリはこちらに上がっていますので、ご確認ください!

https://github.com/mokocm/ecr-imagescan-cicd

まとめ

GitHub Actionsを利用することで簡単にCI/CDを組み込みつつ、(スキャンした時点で)安全なイメージをデプロイするようなワークフローを簡単に作ることができました。

リリース頻度の高いサービスなどでもユニットテストと同じノリでデプロイ前にコンテナの脆弱性スキャンを出来るようなワークフローを組んで行けると、よりセキュアにコンテナ環境の運用が出来ると思います!

また、ECRのイメージスキャン機能は無料で使えるので、「とりあえずコンテナセキュリティに入門したい」ニーズも捉えられていると思います。

パイプラインに埋め込まないまでも、脆弱性があったらSNSで通知するくらいの機能なら15~30分程度で構築することができますので、是非お試しください!

以上、もこでした。