Cloud Buildのステップ内でDockerを使うならcloudbuildネットワークを覚えておく

## 概要
Cloud Buildで

- ステップ内でDockerを使い
- DockerからApplication Default Credentialも使いたい

なら `--network=cloudbuild` を渡そうという話です。

## 前提
例には[berglas](https://github.com/GoogleCloudPlatform/berglas)利用します。
berglasは環境変数に特定フォーマットで秘密情報への参照を入れておくと、その値をとってきてくれます。
例えば `FOO=sm://$PROJECT_ID/$SECRET_NAME berglas exec -- bar` を実行すると、Secret Managerから取ってきた値が環境変数 `FOO` に入って `bar` が実行されます。

## 準備
まずSecret Managerで `TEST` というシークレットに値を入れておきます。

```console
$  echo -n "supersecret" | gcloud beta secrets create TEST --replication-policy automatic --data-file=-
```

またCloud Buildの実行サービスアカウントに、Secret Accesorロールをつけておきます。

```console
$ gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member "serviceAccount:$(gcloud projects describe $PROJECT_ID --format 'value(projectNumber)')@cloudbuild.gserviceaccount.com" \
  --role roles/secretmanager.secretAccessor
```

## 実験

実験を単純にする為に `env` で環境変数を出力していますが、ログに残るので本当に秘密の情報を扱うならそのまま使わないように気をつけてください。
### ステップ内部でDockerを使わないのでうまくいく例
まずberglasのイメージを直接使ってみます。 

```yaml:cloudbuild.yaml
steps:
  - name: 'asia-docker.pkg.dev/berglas/berglas/berglas:latest'
    args:
      - 'exec'
      - '--'
      - 'env'
    env:
      - 'TEST=sm://$PROJECT_ID/TEST'
```

これで実行してみます。

```console
$ gcloud builds submit --config cloudbuild.yaml --no-source
...
TEST=supersecret
...
```

復元されたTESTをみることができました。

### ダメな例
次にビルドステップ内で`docker run`経由でberglasを使ってみます。

```yaml:cloudbuild.yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'run'
      - '-e'
      - 'TEST=sm://$PROJECT_ID/TEST'
      - 'asia-docker.pkg.dev/berglas/berglas/berglas:latest'
      - 'exec'
      - '--'
      - 'env'
```

すると…

```console
$ gcloud builds submit --config cloudbuild.yaml --no-source
...
failed to access secret sm://$PROJECT_ID/TEST: failed to access secret: rpc error: code = Unauthenticated desc = transport: Get "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform": dial tcp 169.254.169.254:80: i/o timeout
...
```

エラーが起きてしまいます。DockerコンテナからApplication Default Credential取得リクエストができないようですね。

どんなネットワークがあるのか試しに見てみます。

```yaml:cloudbuild.yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'network'
      - 'ls'
```


```console
$ gcloud builds submit --config cloudbuild.yaml --no-source
...
NETWORK ID          NAME                DRIVER              SCOPE
ed09d11c5bd1        bridge              bridge              local
a01cfc17c577        cloudbuild          bridge              local
f3426b77657b        host                host                local
9b756bf55527        none                null                local
...
```

Application Default Credentialを使いたい場合には、このうち `cloudbuild` ネットワークを渡す必要があります。（ `host` ではだめです。）
これは[ドキュメントにも書いてあります](https://cloud.google.com/cloud-build/docs/build-config?hl=ja#network)。

### うまくいく例

```yaml:cloudbuild.yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'run'
      - '--network=cloudbuild' # 追加
      - '-e'
      - 'TEST=sm://$PROJECT_ID/TEST'
      - 'asia-docker.pkg.dev/berglas/berglas/berglas:latest'
      - 'exec'
      - '--'
      - 'env'
```

```console
$ gcloud builds submit --config cloudbuild.yaml --no-source
...
TEST=supersecret
...
```

無事見ることができました。

## 結論
Cloud Buildのステップ内部でDockerコンテナを使い、コンテナからApplication Default Credentialも使いたいなら `--network=cloudbuild` を渡しましょう。

## 参考
- [ビルド構成の概要  |  Cloud Build のドキュメント  |  Google Cloud](https://cloud.google.com/cloud-build/docs/build-config?hl=ja#network)