💭

Cloud Build で Chainguard の ko イメージを使う

に公開

はじめに

Go アプリケーションのコンテナイメージをビルドする際、ko は非常に便利なツールです。

Google Cloud Build で ko を使う場合、Chainguard の ko イメージ を使うと、セキュリティに優れ、ビルドも高速です。

しかし、実際に使ってみると、いくつかの落とし穴がありました。

結論

Chainguard の ko イメージを Cloud Build で使うには、以下の環境変数が必要です。

steps:
  - name: 'cgr.dev/chainguard/ko'
    env:
      - GOCACHE=/tmp/go-cache
      - GOMODCACHE=/tmp/go-mod
      - GIT_CONFIG_COUNT=1
      - GIT_CONFIG_KEY_0=safe.directory
      - GIT_CONFIG_VALUE_0=/workspace
      - KO_DOCKER_REPO=${_REGION}-docker.pkg.dev/$PROJECT_ID/${_REPO_NAME}/web
    args:
      - 'build'
      - '.'
      - '--bare'
      - '-t'
      - '$SHORT_SHA'
環境変数 目的
GOCACHE=/tmp/go-cache Go ビルドキャッシュの権限エラー回避
GOMODCACHE=/tmp/go-mod Go モジュールキャッシュの権限エラー回避
GIT_CONFIG_* Git safe.directory エラー回避

以下、各問題の詳細を説明します。

落とし穴 1: GOCACHE の権限エラー

エラー内容

failed to initialize build cache at /builder/home/.cache/go-build:
mkdir /builder/home/.cache: permission denied

原因

Chainguard の ko イメージは、セキュリティのため nonroot ユーザー (UID 65532) で実行されます。一方、Cloud Build は $HOME として /builder/home を使用しますが、このディレクトリは nonroot ユーザーには書き込みできません。

Go コンパイラはビルドキャッシュを $HOME/.cache/go-build に作成しようとしますが、権限がないため失敗します。

解決策

GOCACHE 環境変数で、書き込み可能な /tmp を指定します。

Cloud Build では各ビルドが新しいコンテナで実行され、ビルド間でキャッシュは共有されません。そのため、キャッシュの場所を /tmp に変更しても実質的なデメリットはありません。

落とし穴 2: GOMODCACHE の権限エラー

エラー内容

go: could not create module cache: mkdir /builder/home/go: permission denied

原因

Go はダウンロードしたモジュールを $HOME/go/pkg/mod に保存します。これも nonroot ユーザーでは書き込みできません。

なお、GOCACHE=off は Go 1.12 以降では使えません(ビルドキャッシュが必須になったため)。GOMODCACHE=off も同様に使えません。モジュールのソースコードは実際にファイルとして保存する必要があるためです。

解決策

GOMODCACHE 環境変数で、書き込み可能な /tmp を指定します。

落とし穴 3: Git の safe.directory エラー

エラー内容

error obtaining VCS status: exit status 128
Use -buildvcs=false to disable VCS stamping.

ログを見ると、以下のメッセージがありました。

current folder is not a git repository. Git info will not be available

原因

Go 1.18 から、ビルド時に VCS(バージョン管理システム)の情報をバイナリに埋め込む機能がデフォルトで有効になっています。この機能は Git リポジトリの情報を取得しようとします。

しかし、Git には CVE-2022-24765 への対策として、リポジトリの所有者とコマンド実行者が異なる場合にアクセスを拒否する セキュリティ機能があります。

Cloud Build では:

  1. ソースファイルは特定のユーザー(おそらく root)が所有
  2. Chainguard ko は nonroot (UID 65532) で実行
  3. Git が「安全でないリポジトリ」としてアクセスを拒否

解決策

Git の設定を環境変数で渡し、/workspace ディレクトリを信頼するよう指定します。

safe.directory=* で全ディレクトリを信頼することもできますが、セキュリティの観点から /workspace(Cloud Build のソースディレクトリ)のみを指定することをお勧めします。

参考リンク

Discussion