Javaアプリケーション向けにGitHub ActionsでセキュアなCI/CDパイプラインを構築する
2022年6月27日
0 分で読めますGitHub Actionsにより、GitHubプロジェクト向けのセキュアな継続的インテグレーション/継続的デリバリー(CI/CD)パイプラインを、これまで以上に簡単に構築できるようになりました。CI/CDパイプラインとGitHubリポジトリを統合することで、GitHub Actionsを使ってビルド、テスト、デプロイのパイプラインを自動化できます。リポジトリへのプルリクエストごとにビルドとテストを実行するワークフローや、マージ済みのプルリクエストを本番環境にデプロイするワークフローを作成できます。さらに、SnykをGitHub CI/CDに統合すれば、本番環境にリリースする前のビルド工程でセキュリティスキャンを自動化できます。
Java向けGitHub Actions CIパイプラインを設定する
GitHub Actionsのワークフローは、.github/workflowsフォルダに保存されるYAMLファイルです。ワークフローがまだない場合や、新しく追加する場合は、Actions、New workflowの順に選択します。

このJava Spring Bootプロジェクトでは、次のようにMavenを使ってCIパイプラインを作成しました。
このアクションは、masterブランチへのプッシュまたはプルリクエストのたびに実行されます。Ubuntuをベースにリポジトリをチェックアウトし、Java 17とMavenを使用するGitHub Actionのsetup-javaで、Javaのjarファイルをビルドします。構文に慣れていれば、このワークフローは比較的シンプルです。さまざまな活用方法について詳しくは、GitHub Actionsのドキュメントをご覧ください。
GitHub CI/CDにSnykを統合する
Snykを使うと、新しいJavaプロジェクトにセキュリティテストを統合できます。主な方法は2つありますが、まずは次の2点を準備しましょう。Snykアカウントにログインします。まだアカウントをお持ちでない場合は、無料で作成してください。次に、APIキーをGitHubリポジトリのシークレットSNYK_TOKENとして設定します。
方法1:GitHub ActionのビルドステップにSnyk CLIを統合する
Snyk CLIを使うと、現在のビルド内でセキュリティスキャンを自動実行できます。以下の手順に従い、Build with Mavenの後にいくつかのステップを追加して、設定を始めましょう。
NodeJSバージョン14をセットアップし、npmでSnyk CLIをダウンロードします。次に、Snyk Open Sourceで依存関係を分析し、Snyk Codeで独自のコードに脆弱性がないかスキャンします。
次に、APIキーを含む環境変数としてSNYK_TOKENを宣言します。先ほど設定したシークレットSNYK_TOKENを参照するか、GitHub Actionのコード例をそのまま再利用できます。
この方法の利点は、アプリケーションのコンパイルとビルドが一度で済むことです。大規模なアプリケーションをビルドする際に、多くの時間を節約できます。一方、各ステップは順番に実行されるため、後半のステップで失敗すると効率が悪くなる場合があります。
方法2:Snykの定義済みGitHub Actionsを使ってCI/CDパイプラインを作成する
Snykは、プロジェクトの脆弱性をチェックするGitHub Actionsを一式提供しています。必要なアクションは、プログラミング言語やビルドツールによって異なります。ここでは、Javaプロジェクト向けに、以下のMavenベースのGitHub Actionを使います。
定義済みのアクションを使えば、アプリケーションのビルドに必要な前提条件が整い、コードのスキャンには最新のCLIバージョンが使われます。アプリケーションを何度か再ビルドすることになるものの、各アクションを個別に並行実行できる点は、この方法の大きなメリットです。
まず、依存関係をスキャンしましょう。Snykアカウントはすでに作成済みで、APIキーはSNYK_TOKENという名前のシークレットとして保存されています。そこで、ビルドジョブにステップを追加する代わりに、opensource-securityという新しいジョブを作成します。
ドキュメントによると、デフォルトのコマンドはtestです。追加の設定をしなくても、依存関係に既知の脆弱性がないかアプリケーションをスキャンします。ネストされたプロジェクトに対応するために--all-projectsのような特定のCLI引数を設定する場合は、withキーワードを使い、プロパティにargsを指定します。

Snykで依存関係をスキャンしている間に、GitHub ActionでJavaコードの脆弱性もチェックしましょう。前の手順を繰り返して、そのための3つ目のジョブを設定し、commandプロパティにcode testを指定します。
3つのジョブはすべて並行して実行されます。多くの場合、こちらのほうが効率的です。
GitHub CI/CDにセキュアな継続的デリバリーを追加する
次に、GitHub CI/CDのデプロイ、つまりデリバリーの部分を見ていきましょう。ビルドとテストが完了したら、パッケージをGitHubに公開します。ここでは、JavaプロジェクトでMaven Release Pluginを使います。
ビルドジョブと2つのセキュリティジョブがすべて正常に完了した場合にのみパッケージをリリースしたいため、リリースに必要なジョブの一覧をneedsプロパティに追加します。これにより、パッケージが完全にビルドされ、安全性が確認される前にデプロイされることを防げます。
Mavenのコマンドrelease:prepareとrelease:performは、リリースのバージョン番号が正しいことを確認し、実際にGitHubリポジトリへ公開します。Mavenで処理するため、pom.xmlファイルを次のように設定します。
リリースしたばかりのアプリケーションに脆弱性がなくても、その状態がずっと続くとは限りません。さまざまな場所で新たな脆弱性が見つかる可能性があるため、アプリケーションのデプロイ後もコードと依存関係を継続的に監視することが重要です。
開発中のスキャンに加えて、Snykを使ってデプロイ後も依存関係を監視できます。リリースが完了したら、Snykの定義済みアクションを再び使い、今度はcommandプロパティにmonitorを指定します。
これにより、リリース後は変化しない依存関係ツリーがSnykに送信され、監視されます。SnykのUIでプロジェクトを確認できるようになり、使用中の依存関係に新たな脆弱性が見つかった場合は自動通知を受け取れます。公開したJavaプロジェクトに脆弱性がない状態を維持できます。

GitHub Actionsにセキュリティを統合する
GitHub Actionsを使えば、GitHubプロジェクトのCI/CDパイプラインを簡単に作成できます。さらにSnykのアクションを使うことで、あらゆるアプリケーションに複数のレベルでセキュリティスキャンを簡単に統合できます。
本日作成したパイプラインを、GitHubでは次の図のように可視化できます。ジョブによっては並行して実行され、ほかのジョブの正常完了を待つものもあります。プロジェクト全体の例は、こちらのGitHubリポジトリでご確認ください。

今回はSnyk CodeとSnyk Open Sourceを使って、Javaのソースコードとパイプラインの依存関係をスキャンしました。さらに、Snyk ContainerでDockerファイルを、Snyk IaCでKubernetesファイルをスキャンすることもできます。
Snyk GitHub Actionsを使えば、GitHub Actionsのワークフローにスキャンを自動的に追加できます。プロジェクトに最適なアクションを組み合わせて、コードを今も将来も安全に保ちましょう。
キャプチャー・ザ・フラッグを始めよう
オンデマンドのバーチャル入門ワークショップを視聴して、キャプチャー・ザ・フラッグの課題の解き方を学びましょう。