Skip to main content

Codefresh + Snyk = 迅速かつ安全なリリース

著者
Headshot of Antoine Arlaud

Antoine Arlaud

2018年12月11日

0 分で読めます

現代のソフトウェア開発とは、コードを書くことです。ビルドでもリリースでもなく、開発です。コードを書き、マージし、ビルドして、リリースする。その流れの両側、つまりコードと自動化された工程の間にあるリポジトリの境界で、テストすることが重要です。変更をスムーズにパイプラインへ流すため、マージ前にテストすることを目指します。

パイプラインは、開発者が変更を初めてテストするためのものではありません。新しいリリースの出荷基準をコードが満たしていない場合に、それを止めるためのものです。ロケットが発射台にある間に行う最終チェックリストのようなものです。理想を言えば、パイプラインの実行中に修正が必要になるのは、すでに手遅れに近い状態です。開発中やマージ中に修正しておきたいところです。とはいえ、いつも理想どおりとは限りません。一般的な目安として、変更は開発段階で解決するよう努めましょう。

そのためには、できるだけ早い段階で、たとえば自分のマシンやコードリポジトリでテストし、フィードバックを得ましょう。もちろん、必要なテストを組み込んだパイプラインをまず構築する必要があります。そこで役立つのがCodefreshです。コンテナやKubernetesへのデプロイを通じてアプリをリリースするための、自動化されたパイプラインを構築できます。

これらのテストには、セキュリティが必須です。これは絶対に欠かせません。納得できない場合は、この記事を読むのをやめて、セキュリティチームや同僚、仲間、ミートアップの参加者、あるいは私たちに話を聞いてみてください。なぜ重要なのか、それぞれが説明します……ここで登場するのがSnykです。

これから5~10分で、Codefreshを使ってこのパイプラインを構築し、Snykによるセキュリティテストを組み込みます。テストは手短に済ませ、コーディングや機能のリリースに戻りましょう。CodefreshとSnykにはどちらも無料プランがあるため、費用をかけずに一緒に進められます。Codefreshのメンバーとウェビナーも行いました。動画をご覧になりたい方は、こちらからご確認ください。

サンプルのNodeアプリを作成し、DockerコンテナにしてDocker Hubにプッシュします。そこから別のパイプラインが起動し、出力をKubernetesアプリケーションとしてデプロイします。Codefreshはリポジトリにマージされた変更を検知してDockerイメージをビルドし、Snykのテストを実行して、生成された成果物を安全にリリースできるか判断します。

まず、アプリケーションとコンテナについて簡単に確認しましょう。コンテナインフラストラクチャ上で動作する一般的なアプリケーションの構成を、以下に示します。

パイプラインはGitHubリポジトリからアプリケーションのソースコードを取得し、Dockerコンテナにビルドします。Docker Hubにプッシュする前に、アプリケーションの依存関係とOSの依存関係の両方をテストし、セキュリティ上の問題がないか確認します。脆弱性がなければ、処理は問題なく進みます。

コミットからアプリのビルド、依存関係のスキャン、Dockerビルド、イメージのスキャンを経てDocker Hubへのプッシュまで、アプリのパイプラインの各ステージを表示

それでは、このパイプラインを実際に作ってみましょう。

1. CodefreshとSnyk.ioのアカウントを新規作成します。

2. Codefreshにリポジトリを追加します。

[Codefreshのリポジトリダッシュボード。All、Private、Publicのフィルターと「Add New Repository」パネルが表示されている]

このデモでは、https://github.com/snyk-playground/codefresh-pipeline-snyk-app-docker-scanリポジトリを使います。

最初のビルドで、ステップ1/4のリポジトリ選択画面。snyk-playground/codeリポジトリとmasterブランチが選択されています

3. 次に、ビルド方法としてStart from templateを選択します。

Codefreshのセットアップ画面。リポジトリのビルド方法としてCodefresh.yml、Dockerfile、テンプレートの3つの選択肢が表示され、Dockerfileが選択されています。

ここではNodeJSアプリケーションを使います。これを選択して「次へ」をクリックしましょう。

getSubQueryメソッドのデバッガーのスタックトレースとソースコードが表示されたJava IDE。変数の検査パネルが開いています。

今回は標準テンプレートを使います。必要に応じて自由に調整してください。

Node.jsのセットアップ、依存関係のインストール、アプリケーションのコピー、[作成]ボタンを含む、編集可能なDockerfileの設定プレビュー

これで新しいリポジトリが追加されました。次はパイプラインを定義しましょう。

2つのHello.javaファイルを比較するJava開発インターフェース。mainメソッドの差分と、下部にGitの履歴が表示されている

4. Create pipelineをクリックして、リポジトリをビルドします。

まず、必要な環境変数を定義します。シークレットは必ず暗号化しましょう。「SNYK_TOKEN」という新しい変数を追加します。

環境変数PORT=8080と、暗号化されたSNYK_TOKEN変数が表示されたパイプライン設定画面。

値はhttps://app.snyk.io/accountで確認できます。

マスクされたAPIトークン欄と、強調表示された「表示」ボタンがあるアカウント設定ページ

その画面で、SNYK_ORGという変数も追加し、値にはURLの末尾部分を設定します。https://app.snyk.io/org/私の場合は、aarlaud-snyk-demoです。

app.snyk.io/org/aarlaud-snyk-demo/ と表示されたブラウザーのURL

Snykの設定は以上です。

次に、Codefreshレジストリからイメージを取得し、最終イメージをDocker Hubにプッシュするため、いくつか環境変数を追加します。

Codefreshがプライベートイメージレジストリにアクセスできるよう、次の変数を追加します(詳しくはhttps://codefresh.io/docs/docs/docker-registries/codefresh-registry/#generate-cfcr-login-tokenをご覧ください)。

  • CF_USER_NAME - Codefreshのユーザー名(例:私の場合はaarlaud)

  • CFCR_ACCOUNT - 私の場合はユーザー名と同じaarlaud

  • CFCR_LOGIN_TOKEN - https://g.codefresh.io/user/settingsでトークンを生成し、暗号化します。

Docker Hubとの連携では、最終的なDockerイメージのプッシュ先となるイメージ名を、次の変数に保存します。

IMAGE_NAME - 例:私の場合はaarlaudsnyk/trainingapp

変数は次のようになります。

環境変数の設定パネル。設定済みのポート、Snyk、Cloud Foundry、イメージ名の変数が表示され、一部の値は暗号化されています

最後に、Codefreshの「Integrations」セクションでDockerの設定を行います。

Git、Docker Registry、Kubernetesのオプションと「Configure」ボタンが表示されたインテグレーション設定画面。サイドバーでは「インテグレーション」が選択されています。

Docker Hubのアカウント(https://hub.docker.com/)が必要です。まだお持ちでない場合は作成し、Dockerレジストリとのインテグレーションを設定してください。

依存関係の問題、パッケージ、利用可能な修正を表形式で表示する、Snykの脆弱性レポート

準備完了です。トリガーを確認すると、コミットごとにビルドが実行されることがわかります。このパイプラインはmasterブランチを基に作成したため、masterへのコミットだけがビルドをトリガーします。今のところはこれで十分です。ほかのブランチや環境向けに変更または複製するのも簡単です。

snyk-playground/codefresh-pipeline-snyk-app-do...リポジトリのGitトリガーが1つ表示されたトリガーインターフェース

ワークフローを見ると、先ほど確認したDockerテンプレートが使われていることがわかります。いずれは、これをDockerfileに移したほうがよいかもしれません。

Node.jsのCodefreshテンプレートDockerfileに、イメージ名とDockerコマンドが表示されたワークフローのビルドフォーム。

それでは、先に進む前に、期待どおりに動作するかビルドしてみましょう。

codefresh-pipeline-snyk-app-docker-scanのビルド前に、masterブランチとパイプラインを選択するダイアログ。Buildボタンが強調表示されています

ビルドが開始されます。

SnykのCVSSダッシュボード。高リスクを示す8.2のスコアと、NVDおよびRed Hatの脆弱性の詳細を表示。完全性と可用性への影響はいずれも高。

アプリのビルドが完了しました。

選択されたUIImage要素とその配置プロパティを含む、JSONレイアウト設定を表示したコードエディター。

Codefreshはこのイメージを、Codefreshアカウント内のプライベートDockerレジストリに自動的に保存します。「Images」セクションを見ると、ビルドしたばかりのDockerイメージを確認できます。

タグ付きフィルターと、ブランチ、コミット、日付、タグ、SHAの各列が表示されたリポジトリイメージの記録を含むイメージダッシュボード

さらに、このイメージをDocker Hubにプッシュする前に、セキュリティ上の脆弱性がないことを確認したいと思います。

5. パイプラインに戻り、依存関係にセキュリティ上の脆弱性がないかテストするため、snyk testコマンドを追加します。

まずSnykをインストールし、重大度の高い問題があればビルドを失敗させるシンプルなコマンドで実行します。ワークフローを十分に把握するまでは、低または中程度の問題では失敗させないようにします。

> npm install -g snyk
> snyk test --severity-threshold=high
ユニットテストのセクション。Snykをグローバルにインストールするターミナルコマンドと、重大度のしきい値を高く設定してテストを実行するコマンドが表示されています。

保存してから再度ビルドを実行します。パイプラインに「Running Unit Tests」というステップが表示されます。何らかの問題があるため、おそらく失敗するでしょう。修正は後で行います。次に、アプリのOSコンポーネントについて、Dockerイメージ自体をスキャンしましょう。

Codefreshがアプリをビルドすると、イメージはプライベートレジストリにプッシュされます。そのイメージを取得してユニットテストを実行します。同じ手順を繰り返し、Dockerイメージを対象に2つ目のsnyk testを実行します。

そのためにCodefreshのコンポジションを使います。詳細はドキュメントをご覧ください。ここでは機能を増やすため、yamlに切り替えます。

BASICとYAMLのオプションがある切り替えスイッチ。YAMLが選択されています

yamlモードで、「version: ‘1.0’」の直後に次の3行を追加します。

-scan
-promote

この変更は見た目だけのもので、UIにバケットのようなセクションを作成します。既存のRunningUnitTestsセクションを少し変更し、SnykAppScanセクションを使うようにしましょう。タイトルを変更するだけでなく、UI上の適切なバケットに配置するためのstageセクションを追加し、環境変数を直接渡すことで、いくつかの部分を簡潔にしています。

SnykAppScan:
title: Snyk Test Application Dependencies
stage: scan
image: '${{BuildingDockerImage}}'
working_directory: IMAGE_WORK_DIR
environment:
- SNYK_TOKEN=${{SNYK_TOKEN}}
- SNYK_ORG=${{SNYK_ORG}}
commands:
- npm install -g snyk
- snyk test --severity-threshold=high
on_success:
metadata:
set:
- '${{BuildingDockerImage.imageId}}':
- CF_QUALITY: true
on_fail:
metadata:
set:
- '${{BuildingDockerImage.imageId}}':
- CF_QUALITY: false

次に、Dockerイメージのスキャン部分としてSnykScanImageセクションを追加します。ここでもStageはscanで、アプリケーションの依存関係をスキャンするステージと同じバケットに入ります。コンポジションのドキュメントにあるように、複数のサービスを実行してテストできます。

この場合、BuildingDockerImageはビルドステージのイメージ出力です。このイメージを外部からテストしたいので、以前ビルドした別のイメージaarlaudsnyk/snyk-container-scan-dockerを実行するスキャンサービスと組み合わせます。このイメージには、SnykでDockerイメージをテストするために必要な要素がまとめられています。ソースはこちらで確認できます。

SnykScanImage:
title: Snyk Test Docker OS Dependencies
stage: scan
type: composition
composition:
version: '2'
services:
targetimage:
image: ${{BuildingDockerImage}} # Must be the Docker build step name
command: sh -c "exit 0"
labels:
build.image.id: ${{CF_BUILD_ID}} # Provides a lookup for the composition
composition_candidates:
scan_service:
image: aarlaudsnyk/snyk-container-scan-docker
command: python snyk-cli.py "${{IMAGE_NAME}}:${{CF_BRANCH_TAG_NORMALIZED}}"
environment:
- SNYK_TOKEN=${{SNYK_TOKEN}}
- SNYK_ORG=${{SNYK_ORG}}
- CFCR_ACCOUNT=${{CFCR_ACCOUNT}}
- CF_USER_NAME=${{CF_USER_NAME}}
- CFCR_LOGIN_TOKEN=${{CFCR_LOGIN_TOKEN}}
depends_on:
- targetimage
volumes: # Volumes required to run DIND
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker:/var/lib/docker
add_flow_volume_to_composition: true
on_success: # Execute only once the step succeeded
metadata: # Declare the metadata attribute
set: # Specify the set operation
- ${{BuildingDockerImage.imageId}}: # Select any number of target images
- SECURITY_SCAN: true

on_fail: # Execute only once the step failed
metadata: # Declare the metadata attribute
set: # Specify the set operation
- ${{BuildingDockerImage.imageId}}: # Select any number of target images
- SECURITY_SCAN: false

上記のyamlファイルで注目すべきセクションは次のとおりです。

image: aarlaudsnyk/snyk-container-scan-docker
command: python snyk-cli.py "${{IMAGE_NAME}}:${{CF_BRANCH_TAG_NORMALIZED}}"

このイメージを使ってPythonコマンドを実行します。主に次の2つの処理を行います。

  • テスト対象のイメージをローカルに取得する

  • 「snyk test --docker 」を実行する

このイメージは、次の環境変数が定義されている場合にCodefreshのレジストリからイメージを取得するように作られています。

  • CFCR_ACCOUNT

  • CF_USER_NAME

  • CFCR_LOGIN_TOKEN

これにより、ビルド直後のイメージをテストできます。そうでない場合は、代わりにDocker Hubからイメージを取得しようとします。

最後に、テストに合格した場合にこのイメージをプッシュできるよう、末尾にDocker Hubレジストリへのプッシュ処理を追加しましょう。

PushingToDockerRegistry:
title: Pushing to Docker Registry
stage: promote
type: push
candidate: '${{BuildingDockerImage}}'
tag: '${{CF_BRANCH_TAG_NORMALIZED}}'
registry: aarlaudsnyk

特別なことはありません。インテグレーションが設定されていれば、Codefreshを使って簡単にDocker Hubへプッシュできます(少し前に設定しました)。スキャンテストと区別するため、stageが「promote」になっている点に注目してください。

全体をまとめると、次のようになります。

version: '1.0'
stages:
- scan
- promote
steps:
BuildingDockerImage:
title: Building Docker Image
type: build
image_name: ${{IMAGE_NAME}}
working_directory: ./
tag: '${{CF_BRANCH_TAG_NORMALIZED}}'
dockerfile:
content: |-
FROM node:8.0-alpine AS builder
WORKDIR /app
COPY package.json /app
# Creating tar of productions dependencies
RUN npm install --production && cp -rp ./node_modules /tmp/node_modules
# Installing all dependencies
RUN npm install
# Copying application code
COPY . /app
SnykAppScan:
title: Snyk Test Application Dependencies
stage: scan
image: '${{BuildingDockerImage}}'
working_directory: IMAGE_WORK_DIR
environment:
- SNYK_TOKEN=${{SNYK_TOKEN}}
- SNYK_ORG=${{SNYK_ORG}}
commands:
- npm install -g snyk
- snyk test --severity-threshold=high
on_success:
metadata:
set:
- '${{BuildingDockerImage.imageId}}':
- CF_QUALITY: true
on_fail:
metadata:
set:
- '${{BuildingDockerImage.imageId}}':
- CF_QUALITY: false

SnykScanImage:
title: Snyk Test Docker OS Dependencies
stage: scan
type: composition
composition:
version: '2'
services:
targetimage:
image: ${{BuildingDockerImage}} # Must be the Docker build step name
command: sh -c "exit 0"
labels:
build.image.id: ${{CF_BUILD_ID}} # Provides a lookup for the composition
composition_candidates:
scan_service:
image: aarlaudsnyk/snyk-container-scan-docker
command: python snyk-cli.py "${{IMAGE_NAME}}:${{CF_BRANCH_TAG_NORMALIZED}}"
environment:
- SNYK_TOKEN=${{SNYK_TOKEN}}
- SNYK_ORG=${{SNYK_ORG}}
- CFCR_ACCOUNT=${{CFCR_ACCOUNT}}
- CF_USER_NAME=${{CF_USER_NAME}}
- CFCR_LOGIN_TOKEN=${{CFCR_LOGIN_TOKEN}}
depends_on:
- targetimage
volumes: # Volumes required to run DIND
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker:/var/lib/docker
add_flow_volume_to_composition: true
on_success: # Execute only once the step succeeded
metadata: # Declare the metadata attribute
set: # Specify the set operation
- ${{BuildingDockerImage.imageId}}: # Select any number of target images
- SECURITY_SCAN: true

on_fail: # Execute only once the step failed
metadata: # Declare the metadata attribute
set: # Specify the set operation
- ${{BuildingDockerImage.imageId}}: # Select any number of target images
- SECURITY_SCAN: false

PushingToDockerRegistry:
title: Pushing to Docker Registry
stage: promote
type: push
candidate: '${{BuildingDockerImage}}'
tag: '${{CF_BRANCH_TAG_NORMALIZED}}'
registry: aarlaudsnyk

6. まずは基準値を得るため、ビルドしてみましょう。組織の状態はかなり良好です。

Angular IDEで、Angular 2 TypeScriptプロジェクトのapp.component.spec.tsテストファイル、プロジェクトエクスプローラー、Terminal+のウェルカムパネルを表示している画面。

少し待つと、次の結果が表示されます。

Snykのアプリケーション依存関係スキャンが失敗し、脆弱なパスが1つあるとターミナルに表示されたCodefreshのビルドパイプライン。

おっと、アプリに問題があるようです。セキュリティ上の問題があるものをリリースする前に、パイプラインが安全に停止しました。出力に示された修正手順に従って解決しましょう。package.jsonでqsパッケージをバージョン6.0.4に上げれば解決します。

もう一度実行しましょう。

デフォルト、スキャン、プロモートの各ステージが表示されたCIパイプラインのダッシュボード。Snykによる依存関係のテストが完了し、脆弱なパスは見つかりませんでした。

qsの脆弱性は解消しました。やりました!ただし、今度はDockerイメージのOS依存関係に問題があるようです。

請求書の文書を表示するXMLエディター。請求先と配送先の詳細、商品明細、合計金額、コメント、フローティング表示のアウトラインパネルが見える。

修正方法としてイメージのバージョンを上げることが示されています(Dockerセクションのsnyk.io/docsをご確認ください)。それではnode:10-alpineに更新して、もう一度試しましょう。

PlantUMLのソースコードと、生成されたメモリレイアウト図およびユースケース図を並べて表示したスクリーンショット。

保存 → ビルド → ビルド中は腕立て伏せ!

リポジトリのクローン、Dockerイメージのビルド、Snykによる依存関係のスキャン、Dockerレジストリへのプッシュを示す、完了したCodefreshパイプライン

やりました!これで新しいベースラインができ、アプリとコンテナをDocker Hubにリリースする、完全に機能するパイプラインが完成しました。

これでコーディングに戻れます。マージ前にsnyk testを実行し、変更をテストするか、SnykのGitHub PRインテグレーションを使って変更をテストしましょう。あとは変更が自動的にリリースされます。おまけに、最新機能も追加されています!

snyk monitorを使って、依存関係を継続的に監視しましょう。プロジェクトの面倒を見続けたい人はいません。snyk monitorを実行すれば、プロジェクトやDockerイメージの依存関係に新たな脆弱性が公表されたとき、Snykが自動的に通知します。snyk testのセクションの後にsnyk monitorを追加するだけです。

YAML設定エディターに、インラインYAMLの選択状態、「ファイルからインポート」ボタン、およびハイライト表示されたコマンド「snyk monitor」が表示されています。

監視用スナップショットのURLが出力に表示されます。

アプリのモニタリングスナップショットのURLと、新たに公開された依存関係の問題に関する通知を表示するターミナル出力。

snyk testに合格すれば(既知の問題がなければ)、Dockerの処理も自動的に行われます。監視用スナップショットへのリンクも表示されます。

Snykがトレーニングアプリを監視し、新たに公表された依存関係の問題についてユーザーに通知しているターミナル出力

Snyk組織のSnyk UIで、監視対象のプロジェクトを確認することもできます。

脆弱性の件数と「毎日テスト」ドロップダウンを表示した、2つのリポジトリを含むSnyk Projectsダッシュボード

リポジトリのバッジをクリックして、Codefreshのパイプラインをご覧ください(https://github.com/snyk-playground/codefresh-pipeline-snyk-app-docker-scan)。

以上です!安全な開発を!

CTFを始めよう

オンデマンドのバーチャル入門ワークショップで、CTFチャレンジの解き方を学びましょう。

カテゴリー:

続きを読む

blog feature ai lilac
Blog

エージェント型修正で脆弱性バックログをプルリクエストに変える

Evo Remediation Agentがオープンプレビューで利用可能になり、Evo Agentic AppSecに依存関係の自動解決機能が加わりました。AppSecチームは継続的な修正キャンペーンを実施できるようになりました

AI Background min crop
Blog

AIが、あなたが受け入れてきたあらゆるリスクを一気に顕在化させる:AI Security Panel: Unfilteredから得た7つの洞察

AIによって攻撃はより安価かつ高速になり、組織がすでに抱えているリスクが露呈しています。4人のセキュリティリーダーが、機械の速度に対応する防御と迅速な修復が今不可欠である理由を語ります。

blog feature snyk container custom base recommendations
Blog

Evo Agentic AppSecのご紹介:AI開発のスピードに追随するセキュリティ

AIを活用した開発は、従来のセキュリティワークフローを上回るスピードで進んでいます。SnykのAgentic AppSecは、セキュリティエージェントが脆弱性を継続的に検出、修正、検証し、人が基準を定められるようにします。