Closed8
Terraform で Provider がない Bunny CDN を設定する
問題
Cloudflare R2 にあるリソースを Bunny CDN で配信したい。
Bunny CDN には API が存在するが、Terraform Provider はメンテナンスされているものがない。
(bunny.net の API のページは充実しててめっちゃいいな...)
方針
今回使いたいのは Pull Zone というリソースのみ。
Custom Provider を作るのはコストに見合わないと思ったので、terraform_data
リソースの provisioner
で API を叩いて設定していく。
必要なこと
デフォルトでどこまで設定されるかわからないが、必要なもの。
- Pull Zone の作成
- Origin の設定
- Origin URL
- Verify Origin SSL Certificate -> on
- Follow Redirects -> on
- Forward Host Header -> off
- Pricing
- Choose Tier -> Standard Tier
- Pricing Zones -> Asia & Oceania
- Security
- Block Root Path Access -> on
- Block POST Requests -> on
- Allowed Referrers
- Block Direct Url File Access
- S3 Authentication
- Enable AWS S3 Authentication
- AWS Key
- AWS Secret
- AWS Region Name
Cloudflare R2 のバケットは作成済みで、カスタムドメインを設定してある。Terraform で R2 にカスタムドメインを設定するのにはかなり苦労したので下記にぶら下げておく。
スパイクとして、手動で Bunny CDN と R2 の接続がうまくいくことは検証済みなので、新しいプロジェクトで Terraform で設定を再現していく。
各種 API を叩くために API Key を取得する必要がある。
Add Pull Zone の API を叩くだけで完了しそう。
しかし、設定項目が膨大にある。
module の構成。
.
├── main.tf
├── outputs.tf
├── requests
│ └── add_pull_zone.json.tftpl
├── state
│ └── pull_zone.json
└── variables.tf
provisioner
の削除時に Pull Zone の ID が必要なので、state/pull_zone.json に保存して受け渡しています。ただし、初回の実行時には pull_zone.json が存在しないので、ダミーファイルを作る必要があります。
main.tf
locals {
request_body = templatefile("${path.module}/requests/add_pull_zone.json.tftpl", {
name = var.pull_zone_name
origin_url = var.origin_url
aws_key = var.aws_key
aws_secret = var.aws_secret
aws_region = var.aws_region
allowed_referrers = var.allowed_referrers
})
}
data "local_file" "pull_zone" {
filename = "${path.module}/state/pull_zone.json"
}
// API reference: https://docs.bunny.net/reference/pullzonepublic_add
resource "terraform_data" "pull_zone" {
triggers_replace = [
md5(local.request_body),
]
input = {
api_key = var.api_key
pull_zone_file_path = data.local_file.pull_zone.filename
}
provisioner "local-exec" {
on_failure = fail
when = create
command = <<-EOT
curl -f -X POST \
--url https://api.bunny.net/pullzone \
-H 'AccessKey: ${var.api_key}' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
-d '${local.request_body}' | jq '{id: (.Id | tostring), cdnFqdn: .Hostnames[0].Value}' > ${data.local_file.pull_zone.filename}
EOT
}
provisioner "local-exec" {
when = destroy
on_failure = fail
command = <<-EOT
curl -f -X DELETE \
--url "https://api.bunny.net/pullzone/${jsondecode(file(self.input.pull_zone_file_path)).id}" \
-H 'AccessKey: ${self.input.api_key}'
EOT
}
}
data "external" "pull_zone" {
program = ["cat", data.local_file.pull_zone.filename]
depends_on = [terraform_data.pull_zone]
}
resource "terraform_data" "pull_zone_ssl" {
triggers_replace = [
data.external.pull_zone.result.id,
data.external.pull_zone.result.cdnFqdn
]
provisioner "local-exec" {
on_failure = fail
when = create
command = <<-EOT
curl -f -X POST \
--url https://api.bunny.net/pullzone/${data.external.pull_zone.result.id}/setForceSSL \
-H 'AccessKey: ${var.api_key}' \
-H 'accept: application/json' \
-H 'content-type: application/json' \
-d '{"ForceSSL": true, "Hostname": "${data.external.pull_zone.result.cdnFqdn}"}'
EOT
}
}
state/pull_zone.json
{
"id": "1234567",
"cdnFqdn": "dummy-test.b-cdn.net"
}
variables.tf
variable "pull_zone_name" {
description = "The name and hostname of your Pull Zone where your files will be accessible"
type = string
}
variable "api_key" {
description = "Bunny.net API Key"
type = string
sensitive = true
}
variable "origin_url" {
description = "The origin URL of the object storage bucket"
type = string
}
variable "aws_key" {
description = "The AWS access key used to authenticate the requests"
type = string
sensitive = true
}
variable "aws_secret" {
description = "The AWS secret key used to authenticate the requests"
type = string
sensitive = true
}
variable "aws_region" {
description = "The region name of your AWS S3 bucket used to authenticate the requests"
type = string
}
variable "allowed_referrers" {
description = "The set of allowed referrers fqdn"
type = set(string)
}
outputs.tf
output "cdn_url" {
description = "The Bunny CDN URL"
value = "https://${data.external.pull_zone.result.cdnFqdn}"
}
output "pull_zone_id" {
description = "The Bunny CDN pull zone ID"
value = data.external.pull_zone.result.id
}
requests/add_pull_zone.json.tftpl
{
"OriginUrl": "${origin_url}",
"Name": "${name}",
"FollowRedirects": true,
"BlockRootPathAccess": true,
"BlockPostRequests": true,
"BlockNoneReferrer": true,
"DisableCookies": true,
"AllowedReferrers": ${jsonencode(allowed_referrers)},
"AccessControlOriginHeaderExtensions": [
"eot",
"ttf",
"woff",
"woff2",
"css"
],
"AWSSigningEnabled": true,
"AWSSigningRegionName": "${aws_region}",
"AWSSigningKey": "${aws_key}",
"AWSSigningSecret": "${aws_secret}",
"EnableTLS1": true,
"EnableTLS1_1": true,
"VerifyOriginSSL": true,
"EnableLogging": true,
"EnableGeoZoneUS": false,
"EnableGeoZoneEU": false,
"EnableGeoZoneASIA": true,
"EnableGeoZoneSA": false,
"EnableGeoZoneAF": false
}
このスクラップは5ヶ月前にクローズされました