🔧

Terraform のプライベートレジストリーを構築するツール

に公開

作ったツール

https://github.com/ikedam/terraform-registry-builder

概要

  • Terraform プロバイダーを配布する自前のプライベートレジストリーの構築 で、 Terraform プロバイダーを公開するプライベートレジストリーを静的な Web サイトで構築する方法についてまとめました。
  • その内容を発展させ、プロバイダーのバイナリーと、GPG プライベートキーを用意すれば静的な Web サイト用のファイル一式を生成するツールを作りました。
  • 本記事では、使い方と、GitHub Pages を使った公開方法の例を紹介します。
    • 実際のところ GitHub Pages で公開するのであれば公式の Terraform Registry を使ったほうが利便性が高く、単なるツールのデモとしての位置づけです。
    • 実際の利用用途としては隔離されたネットワークや、アクセス制限をかけている Web サーバーへの設置などが想定されます。

使い方

使い方のアウトライン

  1. GPG キーを用意する
  2. プロバイダーのバイナリーをビルドする
  3. terraform-registry-builder を実行する

使い方: 1. GPG キーを用意する

Terraform のレジストリーの仕様上、署名用の GPG キーが必要になります。
GPG キーを用意してプライベートキーをファイルにエクスポートします。

詳細は GPG のドキュメントなどを参照していただくのが簡単ですが、ざっくりとは以下の手順になります:

  1. GPG キーを作成 (対話形式)

    gpg --full-generate-key
    
  2. GPG キーの ID を取得

    gpg --list-secret-keys --keyid-format LONG
    
    • この出力が信じられないくらい分かりづらい。
  3. 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

使い方: 3. terraform-registry-builder を実行する

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 を使うものに変更したバージョンを用意しました:

https://github.com/ikedam/terraform-private-registry-demo/tree/use_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

動作させるまでの手順は以下のようになります:

  1. GitHub Pages を有効化する

  2. gh-pages ブランチに必要なスケルトンを配置しておく。

  3. GPG の秘密鍵を生成しておき、Secrets として TFREGBUILDER_GPG_KEY を登録しておく。

  4. GitHub Actions Workflow を作成する: https://github.com/ikedam/terraform-private-registry-demo/blob/main/.github/workflows/release.yaml

  5. リリースを作成する: https://github.com/ikedam/terraform-private-registry-demo/releases/tag/v1.0.0

  6. 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 initterraform 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