CodebuildでSnyk CLIを使用し、OSSの脆弱性をスキャンする

CodebuildでSnyk CLIを使用し、OSSの脆弱性をスキャンする

はじめに

本記事では、AWSのCodeBuildを使って、プルリクエストが作成された際にSnykを利用してOSSの脆弱性をスキャンする方法をご紹介します。 Snykは、開発者がソフトウェアのセキュリティ問題を特定し、修正するためのツールです。今回はAWS CDKを用いてCodeBuildを作成し、その中でSnyk CLIを利用します。

CodeBuildを作成する

まずはAWS CDKを用いてCodeBuildのプロジェクトを作成します。ここではTypeScriptを使用します。

  • CodeBuildの設定: GitHubのリポジトリと連携し、PRの作成をトリガーにCodeBuildが動作するように設定しています。

  • Snykの設定: buildSpecにて、Snykのインストールから認証、スキャンまでの処理を定義しています。Snykの組織IDと認証トークンは、前述のSSM Parameter Storeから取得します。

  • IAMの設定: Snykの設定情報をSSM Parameter Storeから取得するため、CodeBuildのロールに対してssm:GetParametersの権限を付与しています。

import { StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as codeBuild from 'aws-cdk-lib/aws-codebuild';
import * as iam from 'aws-cdk-lib/aws-iam';
import { ScopedAws } from 'aws-cdk-lib';

export interface CiProps extends StackProps {
 repositoryName: string;
 githubOwnerName: string;
}

export class Ci extends Construct {
 constructor(
 scope: Construct,
 id: string,
 props: CiProps
 ) {
 super(scope, id);

 const {
 repositoryName,
 githubOwnerName,
 } = props;
 const { accountId, region } = new ScopedAws(this);

 // codeBuild
 const gitHubSource = codeBuild.Source.gitHub({
 owner: githubOwnerName,
 repo: repositoryName,
 webhook: true,
 webhookFilters: [
 codeBuild.FilterGroup
 .inEventOf(codeBuild.EventAction.PULL_REQUEST_CREATED, codeBuild.EventAction.PULL_REQUEST_REOPENED)
 ],
 });

 let snyk_build_project = new codeBuild.Project(this, 'snykBuild', {
 source: gitHubSource,
 buildSpec: codeBuild.BuildSpec.fromObject({
 "version": "0.2",
 "env": {
 "parameter-store": {
 "SNYK_ORG": "snyk-org-id",
 "SNYK_TOKEN": "snyk-auth-code",
 }
 },
 "phases": {
 "install": {
 "commands": [
 "echo 'installing Snyk'",
 "npm install -g snyk"
 ]
 },
 "pre_build": {
 "commands": [
 "echo 'authorizing Snyk'",
 "snyk config set api=$SNYK_TOKEN"
 ]
 },
 "build": {
 "commands": [
 "echo 'starting scan'",
 "pip install -r ./cdk/scraping-lambda/lambda/requirements.txt",
 "snyk config set org=$SNYK_ORG",
 `snyk test --file=./cdk/scraping-lambda/lambda/requirements.txt --project-name=${repositoryName} --package-manager=pip`
 ]
 },
 "post_build": {
 "commands": [
 "echo ***build complete****"
 ]
 }
 }
 }),
 environment: {
 buildImage: codeBuild.LinuxBuildImage.STANDARD_5_0,
 computeType: codeBuild.ComputeType.SMALL
 }
 });

 snyk_build_project.addToRolePolicy(new iam.PolicyStatement({
 actions: ['ssm:GetParameters'],
 effect: iam.Effect.ALLOW,
 resources: [
 `arn:aws:ssm:${region}:${accountId}:parameter/snyk-org-id`,
 `arn:aws:ssm:${region}:${accountId}:parameter/snyk-auth-code`
 ]
 }));
 }
}

CodeBuildのbuildspec.yml

CodeBuildの実行内容を定義したbuildspec.ymlについて説明します。 ここでは、Snykをインストールし、認証情報を設定した後、特定のパスにあるrequirements.txtを対象にSnykのスキャンを実行します。 コマンドのオプションについては、Test - Snyk User Docsを参照ください。 スキャンが完了したら、ビルドが終了したことを示すメッセージを表示します。

{
 "version": "0.2",
 "env": {
 "parameter-store": {
 "SNYK_ORG": "snyk-org-id",
 "SNYK_TOKEN": "snyk-auth-code"
 }
 },
 "phases": {
 "install": {
 "commands": [
 "echo 'installing Snyk'",
 "npm install -g snyk"
 ]
 },
 "pre_build": {
 "commands": [
 "echo 'authorizing Snyk'",
 "snyk config set api=$SNYK_TOKEN"
 ]
 },
 "build": {
 "commands": [
 "echo 'starting scan'",
 "pip install -r ./cdk/scraping-lambda/lambda/requirements.txt",
 "snyk config set org=$SNYK_ORG",
 "snyk test --file=./cdk/scraping-lambda/lambda/requirements.txt --project-name=jumble --package-manager=pip"
 ]
 },
 "post_build": {
 "commands": [
 "echo ***build complete****"
 ]
 }
 }
}

動作確認

設定が完了したら、実際にCodeBuildが動作することを確認します。 プルリクエストを作成すると、CodeBuildが起動しSnykによるスキャンが開始されます。下記は実際にSnykが脆弱性を検出し、その結果がCodeBuildのログに表示されている例です。

(省略)

[Container] 2023/07/28 04:35:47 Running command snyk test --file=./cdk/scraping-lambda/lambda/requirements.txt --project-name=jumble --package-manager=pip

Testing /codebuild/output/src1714918155/src/github.com/masawai/jumble...

Tested 13 dependencies for known issues, found 1 issue, 1 vulnerable path.

Issues to fix by upgrading dependencies:

 Pin certifi@2023.5.7 to certifi@2023.7.22 to fix
 ✗ Improper Following of a Certificate's Chain of Trust (new) [Low Severity][https://security.snyk.io/vuln/SNYK-PYTHON-CERTIFI-5805047] in certifi@2023.5.7
 introduced by selenium@4.10.0 > certifi@2023.5.7

Organization: masawai
Package manager: pip
Target file: ./cdk/scraping-lambda/lambda/requirements.txt
Project name: jumble
Open source: no
Project path: /codebuild/output/src1714918155/src/github.com/masawai/jumble
Licenses: enabled

Tip: Try `snyk fix` to address these issues.`snyk fix` is a new CLI command in that aims to automatically apply the recommended updates for supported ecosystems.
See documentation on how to enable this beta feature: https://docs.snyk.io/snyk-cli/fix-vulnerabilities-from-the-cli/automatic-remediation-with-snyk-fix#enabling-snyk-fix

Tip: Detected multiple supported manifests (7), use --all-projects to scan all of them at once.

[Container] 2023/07/28 04:35:53 Command did not exit successfully snyk test --file=./cdk/scraping-lambda/lambda/requirements.txt --project-name=jumble --package-manager=pip exit status 1
[Container] 2023/07/28 04:35:53 Phase complete: BUILD State: FAILED
[Container] 2023/07/28 04:35:53 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: snyk test --file=./cdk/scraping-lambda/lambda/requirements.txt --project-name=jumble --package-manager=pip. Reason: exit status 1

終わりに

本記事では、Snyk CLIとCodeBuildを用いてOSSの脆弱性スキャンを実行する方法を解説しました。これにより開発のスピードを落とすことなくセキュリティを確保することができます。 この記事がどなたかの参考になれば幸いです。

参考