Terraform のプライベートレジストリーを構築するツール
作ったツール
概要
- Terraform プロバイダーを配布する自前のプライベートレジストリーの構築 で、 Terraform プロバイダーを公開するプライベートレジストリーを静的な Web サイトで構築する方法についてまとめました。
- その内容を発展させ、プロバイダーのバイナリーと、GPG プライベートキーを用意すれば静的な Web サイト用のファイル一式を生成するツールを作りました。
- 本記事では、使い方と、GitHub Pages を使った公開方法の例を紹介します。
- 実際のところ GitHub Pages で公開するのであれば公式の Terraform Registry を使ったほうが利便性が高く、単なるツールのデモとしての位置づけです。
- 実際の利用用途としては隔離されたネットワークや、アクセス制限をかけている Web サーバーへの設置などが想定されます。
使い方
使い方のアウトライン
- GPG キーを用意する
- プロバイダーのバイナリーをビルドする
-
terraform-registry-builder
を実行する
使い方: 1. GPG キーを用意する
Terraform のレジストリーの仕様上、署名用の GPG キーが必要になります。
GPG キーを用意してプライベートキーをファイルにエクスポートします。
詳細は GPG のドキュメントなどを参照していただくのが簡単ですが、ざっくりとは以下の手順になります:
-
GPG キーを作成 (対話形式)
gpg --full-generate-key
-
GPG キーの ID を取得
gpg --list-secret-keys --keyid-format LONG
- この出力が信じられないくらい分かりづらい。
-
ID から秘密鍵をエクスポート
gpg --export-secret-keys --armor (キーの ID) > private_key.asc
この private_key.asc
を署名に使用します。
秘密鍵は漏洩しないよう厳重に管理、実際の運用では CI/CD のシークレット情報などに保存して運用します。
使い方: 2. プロバイダーのバイナリーをビルドする
「レジストリーに配置したいプロバイダーを置くディレクトリー」を作成します。
mkdir build
その後、そのディレクトリー内に
terraform-provider-(TYPE)_v(VERSION)_(OS)_(ARCH)
のフォーマットでバイナリーを作成して置いていきます。
TYPE は、プロバイダーアドレスの「(ドメイン名)/(ネームスペース)/(タイプ)」のタイプの部分を設定します。
例えば hello というプロバイダーのバージョン 1.0.0 を配置するのであれば以下のようになります:
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build \
-o build/terraform-provider-hello_v1.0.0_linux_amd64
ディレクトリー内に以下のようにバイナリーを配置します。
すべてのプラットフォームのバイナリーを置く必要はなく、サポートするつもりのプラットフォームのバイナリーだけで十分です:
$ ls -1 build
terraform-provider-hello_v1.0.0_darwin_amd64
terraform-provider-hello_v1.0.0_darwin_arm64
terraform-provider-hello_v1.0.0_linux_amd64
terraform-provider-hello_v1.0.0_linux_arm64
terraform-provider-hello_v1.0.0_windows_amd64.exe
terraform-registry-builder
を実行する
使い方: 3. terraform-registry-builder を使ってプライベートレジストリーを構築します。
docker の利用がオススメです。
プライベートレジストリーに使用する Web サーバーのドキュメントが html 以下にあり、
今回のネームスペースを example として html/providers/example
以下に構築するものとします。
GPG 鍵のファイルは環境変数 TFREGBUILDER_GPG_KEY_FILE
でパスを指定します。
パスを指定する代わりに、 TFREGBUILDER_GPG_KEY
で鍵データ (鍵ファイルの中身) を直接渡すこともできます。
また、パスフレーズを設定している場合は TFREGBUILDER_GPG_PASSPHRASE
を指定し、鍵が複数含まれる場合は TFREGBUILDER_GPG_ID
を指定して鍵 ID を指定できます。
docker run --rm -v "$(pwd):/workspace" -w /workspace \
-e TFREGBUILDER_GPG_KEY_FILE=private_key.asc
ghcr.io/ikedam/terraform-registry-builder \
build \
html/providers/example
以下のようなログが出て…
Adding hello version 1.0.0 for darwin/amd64 to index
Adding hello version 1.0.0 for darwin/arm64 to index
Adding hello version 1.0.0 for linux/amd64 to index
Adding hello version 1.0.0 for linux/arm64 to index
Adding hello version 1.0.0 for windows/amd64 to index
Build completed successfully.
html/providers/example
以下にこういうディレクトリーが構築されます:
$ tree html/providers/example
html/providers/example
└── hello
├── 1.0.0
│ └── download
│ ├── darwin
│ │ ├── amd64
│ │ │ ├── index.json
│ │ │ ├── terraform-provider-hello_v1.0.0_darwin_amd64.zip
│ │ │ ├── terraform-provider-hello_v1.0.0_darwin_amd64_SHA256SUMS
│ │ │ └── terraform-provider-hello_v1.0.0_darwin_amd64_SHA256SUMS.sig
│ │ └── arm64
│ │ ├── index.json
│ │ ├── terraform-provider-hello_v1.0.0_darwin_arm64.zip
│ │ ├── terraform-provider-hello_v1.0.0_darwin_arm64_SHA256SUMS
│ │ └── terraform-provider-hello_v1.0.0_darwin_arm64_SHA256SUMS.sig
│ ├── linux
│ │ ├── amd64
│ │ │ ├── index.json
│ │ │ ├── terraform-provider-hello_v1.0.0_linux_amd64.zip
│ │ │ ├── terraform-provider-hello_v1.0.0_linux_amd64_SHA256SUMS
│ │ │ └── terraform-provider-hello_v1.0.0_linux_amd64_SHA256SUMS.sig
│ │ └── arm64
│ │ ├── index.json
│ │ ├── terraform-provider-hello_v1.0.0_linux_arm64.zip
│ │ ├── terraform-provider-hello_v1.0.0_linux_arm64_SHA256SUMS
│ │ └── terraform-provider-hello_v1.0.0_linux_arm64_SHA256SUMS.sig
│ └── windows
│ └── amd64
│ ├── index.json
│ ├── terraform-provider-hello_v1.0.0_windows_amd64.zip
│ ├── terraform-provider-hello_v1.0.0_windows_amd64_SHA256SUMS
│ └── terraform-provider-hello_v1.0.0_windows_amd64_SHA256SUMS.sig
└── versions
└── index.json
12 directories, 21 files
レジストリープロバイダーとなる Web サーバーの公開のアウトライン
構築したファイル群をレジストリープロバイダーとして公開する場合は、Web サーバーを以下のように設定します:
- HTTPS をサポートする。
-
/.well-known/terraform.json
に、今回作成したhtml/providers
ディレクトリーを参照する設定ファイルを置く。- ドキュメントルートに自由にファイルを設置できる権限が必要なため、実質、専用のドメインの発行をしてもらえるような Web サービスを利用していることが条件になります。
-
.../versions
で.../versions/index.json
の内容が取得されるようにする。- ディレクトリーにアクセスした場合に / 付きのパスにリダイレクトするように設定します。
- 多くの Web サーバーではデフォルトでこの挙動になっています。
-
index.json
がディレクトリーインデックスとして使用されるようにする。
- ディレクトリーにアクセスした場合に / 付きのパスにリダイレクトするように設定します。
- json ファイルの Content-Type が
application/json
になるようにする。
この Web サーバーの設定要件の詳細は Terraform プロバイダーを配布する自前のプライベートレジストリーの構築 を参照してください。
terraform-registry-builder
を使ったデモ
ローカルでのデモ
Terraform プロバイダーを配布する自前のプライベートレジストリーの構築 のデモに使っていたスクリプトを terraform-registry-builder
を使うものに変更したバージョンを用意しました:
シェルスクリプトで頑張ってやっていた処理がだいぶ簡単に済むようになっています。
GitHub Actions Workflow + GitHub Pages のデモ
GitHub Pages は index.json
をインデックスファイルとして扱ってくれるため、プライベートレジストリーとして利用することができます。
デモとして、 GitHub Actions Workflow を使ったプライベートレジストリー構築を実装しました: https://github.com/ikedam/terraform-private-registry-demo/blob/main/.github/workflows/release.yaml
動作させるまでの手順は以下のようになります:
-
GitHub Pages を有効化する
-
gh-pages
ブランチへのプッシュ時にファイルを公開する設定にしています。 - GitHub Pages で用意されるサイトのパスは
https://<user>.github.io/<repository>/
になり、/.well-known/terraform.json
の設定ができないため、カスタムドメインを設定しています。 - 参考: GitHub Pages サイトの公開元を設定する
- 参考: GitHub Pages サイトを作成する
- 参考: GitHub Pages サイトのカスタムドメインを管理する
-
-
gh-pages ブランチに必要なスケルトンを配置しておく。
- https://github.com/ikedam/terraform-private-registry-demo/commit/47a4e1e80ba5b856eb6abf449cf4d33ddcb51645
- jekyll の機能を無効化するために
.nojekyll
ファイルを設置する。 -
/.well-known/terraform.json
を置いておく。 - (オプション)プロバイダーのネームスペースに対応するディレクトリーを作っておく。今回は
/providers/example
としました。
-
GPG の秘密鍵を生成しておき、Secrets として
TFREGBUILDER_GPG_KEY
を登録しておく。 -
GitHub Actions Workflow を作成する: https://github.com/ikedam/terraform-private-registry-demo/blob/main/.github/workflows/release.yaml
-
リリースを作成する: https://github.com/ikedam/terraform-private-registry-demo/releases/tag/v1.0.0
-
Workflow で gh-pages にプライベートレジストリーに必要なファイルが構築される: https://github.com/ikedam/terraform-private-registry-demo/actions/runs/15487445010
上記で https://tf-demo.ikedam.jp/ にプライベートレジストリーが構築されます。
以下のような Terraform テンプレートを作成し…
# main.tf
terraform {
required_providers {
hello = {
source = "tf-demo.ikedam.jp/example/hello"
version = "~> 1.0.0"
}
}
}
data "hello_world" "message" {
}
output "message" {
value = data.hello_world.message.message
}
terraform init
と terraform plan
を実行すると、以下のように自製のプロバイダーが動作します:
data.hello_world.message: Reading...
data.hello_world.message: Read complete after 0s
Changes to Outputs:
+ message = "Hello, World!"
You can apply this plan to save these new output values to the Terraform state, without changing any
real infrastructure.
────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly
these actions if you run "terraform apply" now.
まとめ・今後の見通し
- Terraform プロバイダーを配布する自前のプライベートレジストリーの構築 で記載したプライベートレジストリーの構築手順を自動化~半自動化するツールを作成しました。
- デモとして GitHub Pages でプライベートレジストリーを構築しました。
- 実際には、今回作ったような一般公開されるレジストリーであれば、プライベートレジストリーを作成するよりも https://registry.terraform.io/ で提供されるサービスを使用したほうがはるかに簡単で便利です。
- 実際にこのツールを使用してプライベートレジストリーが使いたくなる状況としては、以下のような状況を想定しています:
- ローカルネットワーク内からだけアクセスできるサーバーで配布したい場合
- IP アドレス制限でアクセス元を制限した状態で配布したい場合
Discussion