GitHub Actions で Secretlint の Docker コンテナを実行する方法(誤検知対策としてのルールの追加も)

1.この記事を書こうと思った背景 昨今のニュースを眺めていると、クレデンシャル情報(シークレット情報/機密情報)漏洩対策の一環として、ガードレール的なツールを使いたい、またそういったツールを継続的に利用したいというお気持ちが一層強くなる。 そういうわけで Secretlint をはじめとするガードレール的なツールを使おうと思うのだが、SecretlintをCIパイプラインでお手軽に使う方法をひらめいたのでここに書き残しておく。なお、今回の導入対象のCIパイプラインは、GitHub Actionsとしている。というのも https://github.com/secretlint にSecretlintをNode.jsのライブラリとしてGitHub Actions上で扱うサンプルコードが公開されていることから検証のハードルが低いと感じたためである。 secretlint/secretlint-github-actions-example さて、この記事では、SecretlintをCIパイプラインでお手軽に使う方法の他に、誤検知対策としてカンタンにルールを追加する方法についても触れたい。この手のツールは誤検知が大量に作動してしまえば、そのツールはオオカミ少年と認識されてしまいかねない。それだけにSecretlintでは簡易的とはいえ誤検知対策ができるという点は、かゆいところに手が届いているといえるのではないだろうか。 2.解決したい課題とその解決策 まず、具体的な方法論について話す前に前提となる解決したい課題と、ここで提案する解決策について述べておきたい。 2-1.解決したい課題 SecretlintをGitHub Actionsのワークフローでお手軽に使いたい Secretlintを使うためにはDockerかNode.jsが必要である戦う つまり、GitHub ActionsのワークフローのなかでDockerかNode.jsのいずれかを使えるようにセットアップするJobが必要 Node.jsでSecretlintを使う場合、Secretlintのインストールが必要とやや手間 $ npm install secretlint @secretlint/secretlint-rule-preset-recommend --save-dev ルールの追加もお手軽にしたい Secretlintではビルトインのルールが提供されていないが、専用の設定ファイルの .secretlintrc.{yml,yaml,js} (以下、.secretlintrc.json) でルールを利用者側で導入する必要がある Dockerコンテナイメージの場合、推奨ルールセットである、@secretlint/-rule-preset-recommend が同梱されており、イメージをbuildするだけでok https://github.com/secretlint/secretlint#using-docker @secretlint/-rule-preset-recommend Node.jsの場合、上述した @secretlint/-rule-preset-recommend などを.secretlintrc.json で指定し、secretlintコマンドを実行するディレクトリに配置しておかなければならない https://github.com/secretlint/secretlint#using-nodejs # Dockerコンテナイメージを使う場合、Secretlintのインストールは不要 # `.secretlintrc.json もイメージに同梱されている # ルールを追加したい場合、自分で用意する必要があり、その方法は後述 $ docker run -v `pwd`:`pwd` -w `pwd` --rm -it secretlint/secretlint secretlint "**/*" # Node.jsの場合、以下のコマンドで .secretlintrc.json を生成する必要がある $ npx secretlint --init # .secretlintrc.json はsecretlintコマンドを実行するディレクトリに配置する必要がある $ cat <<EOF > .secretlintrc.json { "rules": [ { "id": "@secretlint/secretlint-rule-preset-recommend" } ] } EOF ところで、SecretlintをGitHub Actionsのワークフローで使うメリットはなんだろうか? メリットのひとつは、Secretlintの開発者であるazuさんの、 SecretlintでAPIトークンや秘密鍵などのコミットを防止する | Web Scratch で記載されている、一度きりのチェックだと継続的なセキュリティは担保できない という点であろう 一度きりのチェックだと継続的なセキュリティは担保できないので、CIやGitコミットフックなどでプロジェクトに導入する方法を紹介しています。 また、個人環境のグローバルなGitコミットフックに常にSecretlintのチェックを入れることもできます。 SecretlintをCIパイプラインで使う副次的効果として、Secretlintを通過したという証跡を残すことも期待できる 検証している当初は、Secretlintをローカルで使えなくてもCIパイプラインで組み込むことで代用できると思っていた。しかし、いくらリポジトリをプライベート運用していたところでActions上で動かす以上、CIパイプラインでツールを使うことで安心してはいけないなと考え直した。CIパイプラインで使うツールの立ち位置はあくまでもガードレール的な扱いとし、ローカルでもなにかしらの対策を導入しておいたほうがいいだろう。 ...

March 24, 2022 · 4 min · gkzz

Github Actions の schedule で日時と曜日を指定することができなかったけどなんとかした

1.この記事を書こうと思った背景 Github Actionsでは、schedule ( schedule イベントやスケジュール実行ともいうがここでは、 schedule とする。)というイベントが用意されている https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows#schedule 他のイベントとしては、push や workflow_dispatch などがある scheduleは、POSIX 規格の crontab の構文 で表記するのだが、日時の条件指定と曜日の指定はAND判定されるかと思いきや、OR判定されるようだと分かり、Github feedback や Support などで問い合わせた 問い合わせた結果、丁寧に教えていただいたので共有したい [bug] Schedule event’s multiple conditions are judged by OR conditions, not AND conditions #12804 日時の条件指定と曜日の指定のAND判定というのは、たとえば、第1月曜日の午前2:00に schedule を実行したい場合、下記のような書き方を指している(ただし、この書き方ではAND判定とならないので要注意!) on: schedule: - cron: '0 17 1-7 * 1' 2.長いので結論を書く Github Actions の cron で採用されている POSIX 規格の crontab の構文 では日時と曜日が指定されている場合、日時と曜日のOR判定となることが正しい if either the month or day of month is specified as an element or list, and the day of week is also specified as an element or list, then any day matching either the month and day of month, or the day of week, shall be matched. (Google翻訳) 月または日のいずれかが要素またはリストとして指定され、曜日も要素またはリストとして指定されている場合、月と日、または曜日のいずれかに一致する任意の日、一致するものとします。 出所:POSIX 規格の crontab の構文 つまり、冒頭で一例として書いた cron の場合、以下のいずれかの条件に合致する場合、Schedule event は実行されることとなる 毎月1日〜7日の17:00(UTC) 毎週月曜日の17:00(UTC) ...

March 11, 2022 · 3 min · gkzz

[GitHub Actions]repository_dispatchとworkflow_dispatchの使い分けや書き方の違いをまとめてみた

1.この記事で達成したいこと repository_dispatchとworkflow_dispatch の使い分けや書き方の違い、共通点や相違点を整理したい 結局どっちを使うのがいいのか?判断基準を見つけたい そもそもrepository_dispatchとworkflow_dispatchはどういうときに使うのか? アプリケーションリポジトリでイメージをレジストリにpushした後、マニフェストリポジトリでそのイメージタグをマニフェストに反映させたい 使いまわしているWorkflowを呼びたい このようなときに使えるのがGitHub Actionsでは2つ提供されている。それが冒頭に書いた、repository_dispatchとworkflow_dispatchである。 この記事の結論 長くなってしまったので、冒頭で結論を書く。 repository_dispatchとworkflow_dispatchの使い分けの判断基準の一つは、実行時に参照するWorkflowのブランチをデフォルトブランチ以外としたいケースがあるかどうか? デフォルトブランチ以外のWorkflowのファイルを参照してWorkflowを実行したい場合は、workflow_dispatchを選ぶしかない 2.サンプルコードで使っているリポジトリ https://github.com/gkzz/actions-playground 起点となるWorkflow(実行トリガーはpush)のリポジトリ https://github.com/gkzz/actions-dispatch-playground 起点となるWorkflowからkickされるWorkflow(実行トリガーはrepository_dispatch)のリポジトリ 3.環境情報 ローカル始めバージョンを書いておく必要があるものはない 使うActionのバージョンについては後述するWorkflowを参照してほしい 4.repository_dispatchとworkflow_dispatchの共通点や相違点 共通点 どちらも以下の権限を有する Personal Access Token が必要 repo:write 相違点 workflow_dispatchのみ、GUIから実行できる 実行場所はGithubの実行先のリポジトリのActionタブ pushしたWorkflowからdispatchする際のパラメーターの渡し方が違う(詳細は4-1参照) パラメーターの受け取り方が違う(詳細は5-1及び5-2参照) repository_dispatchのみ、event-typeを使ってWorkflowを実行するか制御できる repository_dispatchはevent-typeに応じて実行するかどうか決めることができる workflow_dispatchの場合、Workflowをkickされたら実行されてしまうのでkickしたWorkflowから渡されるパラメータの値によってjobを実行するように制御することはできる repository_dispatchのみ、Workflowはデフォルトブランチを参照して実行する 4-1.pushしたWorkflowからdispatchする際のパラメーターの渡し方 ここでは、curlコマンドでrepository_dispatchとworkflow_dispatchのWorkflowを実行しながらパラメータの渡し方の違いを確認しよう。 とりわけ、POSTする接続先URLと -d (--data)オプションで渡しているPOSTする値の書式はおさえておきたい。 repository_dispatch 接続先URLは https://api.github.com/repos/<REPOSITORY_OWNER>//dispatches $ curl -X POST \ -H "Accespt: application/vnd.github.v3+json" \ -H "Authorization: token <PAT_REPOSITORY_DISPATCH>" \ https://api.github.com/repos/gkzz/actions-dispatch-playground/dispatches \ -d '{"event_type": "sample-event", "client_payload": {"hoge": "hogevalue"}}' https://docs.github.com/en/rest/reference/repos#create-a-repository-dispatch-event ...

January 31, 2022 · 3 min · gkzz

[addnab/docker-run-action]GitHub Actions で yq のコンテナイメージを使ってマニフェストを更新する

1.この記事で達成したいこと GitHub Actionsでyqのコンテナイメージを使ってマニフェストを更新したい yqはPythonのパッケージマネージャのpipでも扱うことが出来るけどコンテナイメージで扱うほうが都合がよさそうなのでコンテナイメージでがんばりたい コンテナイメージで扱うというのは、docker runコマンドでyqのイメージをスポットで使う感じ yqの使い方についてはjqのyaml版と思って大丈夫。詳細は以前書いた記事を参考にしてほしい。 yqコマンド(jq wrapper for YAML)使い方備忘録 $ docker run --rm -v "$PWD:$PWD" -w="$PWD" \ --entrypoint yq linuxserver/yq \ <yqコマンド> GitHub Actions上でDockerコンテナイメージを扱う方法と注意点 やることは addnab/docker-run-action を使うだけ 基本的な使い方はaddnab/docker-run-actionの上記のリンクにサンプルコードを添えて書かれている しかし、docker runコマンドのときのように同アクションを使おうとすると、ホストとコンテナ間でマニフェストが置かれたディレクトリをマウントするところでつまずいた そこで、この記事では特に同アクションを使う際のホストとコンテナ間でディレクトリをマウント方法する方法について、yqのコンテナイメージを使って解説していきたい 2.前提 addnab/docker-run-actionの検証リポジトリはpublic public/private問わず、同Actionsを使う際の注意点は同じはずだけど念のため書いておく yqは以下のとおり2種類あるが、ここでは https://hub.docker.com/r/linuxserver/yq を扱う ↓この記事で使うyq Github https://github.com/kislyuk/yq https://github.com/mikefarah/yq Docker Image https://hub.docker.com/r/linuxserver/yq https://hub.docker.com/r/mikefarah/yq 3.環境情報 ローカル始めバージョンを書いておく必要があるものはない 使うActionやyqのイメージのバージョンについては後述するWorkflowを参照してほしい 4.この記事で扱うサンプルコード(つまずいたところは解決済) yqのコンテナイメージで更新対象のマニフェスト(manifests/deployment.yml.tmpl) 書き換え箇所はマニフェストのごく一部なので抜粋する --- apiVersion: apps/v1 kind: Deployment metadata: # 略 spec: replicas: 3 selector: matchLabels: app: sampleapp template: metadata: labels: app: sampleapp spec: affinity: # 略 containers: - name: sampleapp image: <REGISTRY>/<CONTAINER_IMAGE>:<IMAGE_TAG> ports: - containerPort: 80 yqのコンテナイメージを使うWorkflow(.github/workflows/mod_manifest.yml) jobs: main: runs-on: 'ubuntu-20.04' env: MANIFEST_PATH: 'manifests' steps: - name: Modify image tag uses: addnab/docker-run-action@v3 with: ## yqのイメージを指定 image: linuxserver/yq:2.13.0 ## docker runコマンドで渡していたオプションを書く ## ">"を使い、適宜改行する ## -vオプションの使い方はやや注意なので後述 options: > --rm -v ${{ github.workspace }}/${{ env.MANIFEST_PATH }}:/opt/${{ env.MANIFEST_PATH }} -w=/opt/${{ env.MANIFEST_PATH }} --entrypoint yq shell: bash run: > yq -ry '.spec.template.spec.containers[0].image |="'${{ secrets.REGISTRY }}'/'${{ secrets.CONTAINER_IMAGE }}':'${{ github.sha }}'"' /opt/${{ env.MANIFEST_PATH }}/deployment.yml.tmpl > /opt/${{ env.MANIFEST_PATH }}/deployment.yml 5.addnab/docker-run-actionでディレクトリをマウントする間違ったやり方 -vオプションで指定するホスト側のパスを「リポジトリのルートディレクトリからマニフェストの 相対パス 」とする - name: Modify image tag uses: addnab/docker-run-action@v3 with: ## yqのイメージを指定 image: linuxserver/yq:2.13.0 ## docker runコマンドで渡していたオプションを書く ## ">"を使い、適宜改行する ## -vオプションで指定するホスト側のパスを「リポジトリのルートディレクトリからマニフェストの相対パス」とする options: > --rm -v ${{ env.MANIFEST_PATH }}:/opt/${{ env.MANIFEST_PATH }} -w=/opt/${{ env.MANIFEST_PATH }} --entrypoint yq shell: bash run: > yq -ry '.spec.template.spec.containers[0].image |="'${{ env.REGISTRY }}'/'${{ env.CONTAINER_IMAGE }}':'${{ github.sha }}'"' /opt/${{ env.MANIFEST_PATH }}/deployment.yml.tmpl > /opt/${{ env.MANIFEST_PATH }}/deployment.yml 実行するとエラーとなってしまう、、 yq: error: argument files: can’t open ‘/opt/manifests/deployment.yml.tmpl’: [Errno 2] No such file or directory: ‘/opt/manifests/deployment.yml.tmpl’ エラーログ抜粋 Run addnab/docker-run-action@v3 with: image: linuxserver/yq:2.13.0 options: --rm -v manifests:/opt/manifests -w=/opt/manifests --entrypoint yq shell: bash run: yq -ry '.spec.template.spec.containers[0].image |="'your_registry'/'your_container_image':'xxxxxxxxxxxxxx'"' /opt/manifests/deployment.yml.tmpl > /opt/manifests/deployment.yml env: MANIFEST_PATH: manifests REGISTRY: your_registry CONTAINER_IMAGE: your_container_image 略 Unable to find image 'linuxserver/yq:2.13.0' locally 2.13.0: Pulling from linuxserver/yq 略 Digets: 略 Status: Downloaded newer image for linuxserver/yq:2.13.0 usage: yq [-h] [--yaml-output] [--yaml-roundtrip] [--width WIDTH] [--indentless-lists] [--in-place] [--version] [jq_filter] [files [files ...]] yq: error: argument files: can't open '/opt/manifests/deployment.yml.tmpl': [Errno 2] No such file or directory: '/opt/manifests/deployment.yml.tmpl' 6.解決策 -vオプションで指定するホスト側のパスを「GitHub Actionsのホスト側の 絶対パス 」とする Runnerのワーキングディレクトリは、GITHUB_WORKSPACE で取得できる! options: > - --rm -v ${{ env.MANIFEST_PATH }}:/opt/${{ env.MANIFEST_PATH }} ##ホストの相対パス:コンテナ側の絶対パス + --rm -v ${{ github.workspace }}/${{ env.MANIFEST_PATH }}:/opt/${{ env.MANIFEST_PATH }} ##ホストの絶対パス:コンテナ側の絶対パス -w=/opt/${{ env.MANIFEST_PATH }} --entrypoint yq 7.[備考]GITHUB_WORKSPACEとは GitHubのドキュメントのGITHUB_WORKSPACEの説明文の頼りにすると、Runnerのデフォルトの作業ディレクトリと書かれている GITHUB_WORKSPACE The default working directory on the runner for steps, and the default location of your repository when using the checkout action. For example, /home/runner/work/my-repo-name/my-repo-name. ...

January 30, 2022 · 3 min · gkzz

Firebase HostingとGithub Actionsで独自ドメインのHugoプロジェクトのブログを自動デプロイする

1.この記事で達成したいこと 独自ドメインのHugoプロジェクトのブログを作ってみたい そのブログがこれ! –> https://gkzz.dev ブログはHugo + Firebase Hostingで構成し、デプロイはGithub Actionsで自動化したい これまでローカルからデプロイという運用対処としていた、、 ※Hugoのインストール手順はこちらに書いてあるのでどうぞ。 最新のHugoをインストールする方法とHugoの設定ファイルをtomlフォーマット以外にする方法 | gkzz.dev 2.前提 HugoのテーマはPaperMod Firebase HostingとGoogle Domainsで購入したカスタムドメインを接続する方法は以下のとおり実施している Firebase HostingとGoogle Domainsで購入したカスタムドメインを接続する | gkzz.dev ドメインはgkzz.devとする 3.環境情報 $ grep Ubuntu /etc/os-release NAME="Ubuntu" PRETTY_NAME="Ubuntu 20.04.2 LTS" $ hugo version hugo v0.87.0-B0C541E4 linux/amd64 BuildDate=2021-08-03T10:57:28Z VendorInfo=gohugoio $ 4.PaperModの導入 以下のPaperModのインストール手順を参考に進める https://github.com/adityatelange/hugo-PaperMod/wiki/Installation#method-2 ※ https://github.com/adityatelange/hugo-PaperMod をサブモジュールとする点がミソ! 「6.GitHub Actionsの設定ファイル(.github/workflows/*.yml)を用意」で活きてくる! $ hugo new site ${BLOG_DIR} -f yml $ cd ${BLOG_DIR} $ git init $ git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod config.ymlのbaseURLにFirebase Hostingでホストしているカスタムドメインを指定 $ vi config.yml # https://github.com/adityatelange/hugo-PaperMod/wiki/Installation baseURL: https://gkzz.dev/ #languageCode: en-us title: gkzz.dev paginate: 5 theme: PaperMod 記事を書いてローカルサーバーにデプロイしてみる http://localhost:1313で接続できる $ hugo new posts/<記事のファイル名>.md $ hugo server -D 5.Firebaseのインストールと初期設定 以下のFirebase CLIのインストール手順を参考に進める Firebase CLI reference $ curl -sL https://firebase.tools | bash $ firebase login 略 Visit this URL on this device to log in: ******** <--- 表示されるURLからログイン認証を終える Waiting for authentication... ✔ Success! Logged in as ******** Firebase CLIからGithubのログイン認証を終え、またfirebaseServiceAccountというサービスアカウントを作成 対話形式で進んでいく firebaseServiceAccountはGithub Actions上でFirebase CLIが使うもの ## 改めて設定し直したい場合 $ firebase init hosting:github $ firebase init hosting $ firebase init hosting You're about to initialize a Firebase project in this directory: /path/to/${BLOG_DIR} === Project Setup First, let's associate this project directory with a Firebase project. You can create multiple project aliases by running firebase use --add, but for now we'll just set up a default project. ? Please select an option: Use an existing project ? Select a default Firebase project for this directory: i Using project ${GCP_PROJECT_ID} === Hosting Setup Your public directory is the folder (relative to your project directory) that will contain Hosting assets to be uploaded with firebase deploy. If you have a build process for your assets, use your build's output directory. ## ${BLOG_DIR}からみた相対パス。PaperModの場合、public ? What do you want to use as your public directory? public ## シングルページではないのでNo ? Configure as a single-page app (rewrite all urls to /index.html)? No ## Yes ? Set up automatic builds and deploys with GitHub? Yes ✔ Wrote public/404.html ✔ Wrote public/index.html i Detected a .git folder at /path/to/${BLOG_DIR} i Authorizing with GitHub to upload your service account to a GitHub repository's secrets store. Visit this URL on this device to log in: ******** <--- 表示されるURLからFirebase CLIからGithubのログイン認証を終える Waiting for authentication... ✔ Success! Logged into GitHub as ${GITHUB_USERNAME} ## ${GITHUB_USERNAME}/${BLOG_DIR} ? For which GitHub repository would you like to set up a GitHub workflow? (format: user/repository) ${GITHUB_USERNAME}/${BLOG_DIR} ✔ Created service account ******** with Firebase Hosting admin permissions. ✔ Uploaded service account JSON to GitHub as secret ******** i You can manage your secrets at https://github.com/${GITHUB_USERNAME}/${BLOG_DIR}/settings/secrets. ## 後ほど自分で書くのでNo ? Set up the workflow to run a build script before every deploy? No ✔ Created workflow file /path/to/${BLOG_DIR}/.github/workflows/firebase-hosting-pull-request.yml ## Yes ? Set up automatic deployment to your site's live channel when a PR is merged? Yes ## main (Firebase Hostingへデプロイするときのブランチ) ? What is the name of the GitHub branch associated with your site's live channel? main ✔ Created workflow file /path/to/${BLOG_DIR}/.github/workflows/firebase-hosting-merge.yml i Action required: Visit this URL to revoke authorization for the Firebase CLI GitHub OAuth App: ******** i Action required: Push any new workflow file(s) to your repo i Writing configuration info to firebase.json... i Writing project information to .firebaserc... ✔ Firebase initialization complete! ここまでくると、Github Actions上でFirebase CLIが使うfirebaseServiceAccountというサービスアカウントがご自身のブログのリポジトリの「settings > secrets」のページから登録されていることが確認できる。 ...

August 20, 2021 · 4 min · gkzz