はじめに
最近よく目にするようになったSnyk。なんて読むかご存知ですか?「すにぃく」や「すにっく」と読み、鍵を閉める際の音を表し、セキュリティ強化するという意味合いがあるようです。なお、 ‘So Now You Know’ (日本語だと「これでお分かりでしょう」のような意味)の頭文字をとったものらしいです(参考)。開発者向けのセキュリティツールで、GitHub Actionsなどのソースコード管理システム(SCM)との連携などを行い、開発プロセス中にセキュリティチェックをしてくれる、注目度が高まるツールです。ちなみにSnyk社のロゴの犬はドーベルマンで、Patch(パッチ)という名前のようです(参考)。
今回は、SnykとGitHub Actionsと組み合わせた活用例をご紹介します。開発者からのプルリクエストをトリガーで起動し、自動でSnyk Open Sourceによる脆弱性チェックとSnyk Codeによるコード分析を実施します。
SnykのFreeプランでも利用できるので気になった方は是非試してみてください。
事前に用意するもの
- GitHub
- リポジトリを作成し、Repository SecretにSNYK_TOKENを登録
- Snyk
- Account SettingsからSNYK_TOKENの取得
- Settings > Snyk CodeからEnable Snyk Codeにチェック
コード作成
まずはactionから作成していきます。
TC3ではCIの中で差分をチェックし、差分のあるアプリケーションに対してのみSnykを実行するようにしていますが、今回はファイルを直接指定するようにしています。
action.yml
name: snyk
run-name: snyk ${{ github.head_ref }}
on:
pull_request:
branches:
- main
types: [opened, synchronize]
permissions:
contents: read
id-token: write
jobs:
snyk:
needs: check-targets
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
dir: [web/app1,web/app2,web/app3]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Snyk setup
id: snyk
uses: snyk/actions/setup@master
with:
snyk-version: v1.1196.0
- name: Snyk version
run: snyk --version
- name: Check package.json is exists
id: check-package
continue-on-error: true
run: ls -al ${{ matrix.dir }}/package.json
- uses: actions/setup-node@v3
if: steps.check-package.outcome == 'success'
id: cache
with:
node-version: 14
cache: npm
cache-dependency-path: ${{ matrix.dir }}
- name: npm install
if: steps.cache.outputs.cache-hit != 'true' && steps.check-package.outcome == 'success'
run: npm install
working-directory: ${{ matrix.dir }}
- name: Snyk Test
id: snyk-test
continue-on-error: true
run: snyk test ${APP_PATH} ${ARGS}
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
ARGS: '--all-projects --severity-threshold=high'
APP_PATH: ${{ matrix.dir }}
- name: Snyk code test
id: snyk-code
continue-on-error: true
run: snyk code test ${APP_PATH} ${ARGS}
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
ARGS: --severity-threshold=high
APP_PATH: ${{ matrix.dir }}
- name: Error Handler
if: ${{ steps.snyk-test.outcome == 'failure' || steps.snyk-code.outcome == 'failure' }}
run: |
echo "Snyk test or Snyk code test failed."
exit 1
次にSnykでチェックしたいファイルを用意します。今回はpom.xmlとpackage.jsonに対して
脆弱性をチェックしてみます。
まずは比較的新しいバージョンを指定したもの
web/app1/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
</dependencies>
<!-- Additional lines to be added here... -->
</project>
次に古いバージョンを指定したもの
web/app2/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.0</version>
</dependency>
</dependencies>
<!-- Additional lines to be added here... -->
</project>
最後はreact-create-appで生成したpackage.json
web/app3/package.json
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.0.0",
"@types/jest": "^29.0.0",
"@types/node": "^18.0.0",
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "4.9.5",
"web-vitals": "^3.0.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
作成したファイルは以下のディレクトリ構成で配置してください。
.github/workflows/action.yml
web/app1
web/app2
web/app3
実行
それでは作成したコードをGitHubにプッシュしましょう。
暫くするとGitHub Actionsが動作し、以下のような結果が表示されます。
比較的新しいバージョンを指定したapp1には脆弱性が検知されませんでした。
一方で、古いバージョンを指定したapp2では脆弱性が検知されています。
app3ではpackage.jsonを設置しましたが、こちらは脆弱性が検知されているようです。
GitHub Actions内ではSnyk OSS, Snyk Codeのどちらも実行するようになっていますが、今回はソースコードを書いていないのでSnyk Codeでは何も検知されませんでした。
脆弱性が検知された場合
Snykでは、どのライブラリに問題があるかどうかだけではなく、どのバージョンに上げると良いというところまで案内してくれるので指示に従うと良いでしょう。
ただし、場合によってはバージョンアップが原因で動作しなくなることや、コードの修正に多くの工数がかかることもあるため、仮に脆弱性が検知された場合でもプロジェクトの状況やSnykが提示する深刻度(Critical, Highなど)を考慮した対策を考えることが大事です。
GitHub連携との違いについて
今回ご紹介したGitHub Actionsと組み合わせた利用とは別に、SnykにはGitHub連携機能も用意されており、これを利用すると定期的にリポジトリを検査し、依存ライブラリの更新の為のプルリクエストを自動で生成してくれます。
また、今回紹介したPRの検査機能も併せ持っており、Github Actions内で前処理、後処理をしない場合などはこちらでも問題なく運用できそうです。
こちらについてはまた機会があればご紹介いたします。
TC3でのSnykの活用について
今回ご紹介したGitHub Actionsの一部は実際の開発でも活用されており、Gig Workerとの開発がよりスピーディかつセキュアになりました。
従来のソフトウェア開発のように開発フェーズの最後にまとめて脆弱性チェックをかけるのではなく、早い段階からチェックをかけることで、脆弱性の早期検知や手戻りコストの削減などの様々な恩恵があります。まだSnykを試していない方はこれを機会に挑戦し、DevSecOpsの文化を広めていきましょう。
また、Snykを活用したDevSecOps基盤を導入した開発のご支援も可能ですので、ご興味のある方はお気軽にお問い合わせください!
おわりに
TC3では『デジタル顧客接点トータルサービス』として、Oktaの導入からアプリケーション開発までをトータルでご支援しております。IDaaS基盤を中核としたウェブアプリケーション開発支援をさせていただいております。開発基盤として今回ご紹介したようなGitHub Actions + Snykを活用し開発を進めることが可能です。ご興味ありましたら、お気軽にお問い合わせください。
●資料ダウンロード●
デジタル顧客接点トータルサービスに関する詳細のご紹介資料は以下からダウンロードいただけます!
TC3は「Gig Innovated.」のスローガンを掲げ、ギグ・エコノミーとの共創を通してソフトウェア開発やAI開発を支援する会社です。ギグ・エコノミーとの共創による開発には、ツール、プロセスなどの観点で様々な課題も存在しています。このような世界を一緒に作っていく仲間をTC3では募集していますので、カジュアル面談などお気軽にお問い合わせください!(参考:リクルートサイト)