Closed9
Terraform で Cloudflare R2 の Token, Access Key ID, Secret Access Key を管理する
(未来からのまとめ)
- Terraform で Cloudflare の Token, Access Key ID, Secret Access Key は作れる
- 公式ドキュメントには書いていないが、トークンのスコープも絞れる
やりたいこと
Cloudflare R2 のバケットに CORS 設定をしたい場合、Cloudflare Provider では実現できず、AWS Provider を使う必要があります。
AWS Provider を使って Cloudflare R2 を管理する場合、Access Key ID, Secret Access Key を発行して以下のように provider に渡す必要があります。
これらトークンも Terraform で発行することができます(後述)。
公式ドキュメントの例の抜粋:
modules/r2/main.tf
provider "aws" {
region = "us-east-1"
access_key = <R2 Access Key>
secret_key = <R2 Secret Key>
skip_credentials_validation = true
skip_region_validation = true
skip_requesting_account_id = true
endpoints {
s3 = "https://<account id>.r2.cloudflarestorage.com"
}
}
例:
module/cloudflare_account_token/outputs.tf
output "token" {
value = cloudflare_api_token.default.value
sensitive = true
description = "Token value"
}
output "access_key_id" {
value = cloudflare_api_token.default.id
description = "Access Key ID"
}
output "secret_access_key" {
value = sha256(cloudflare_api_token.default.value)
sensitive = true
description = "Secret Access Key"
}
output "name" {
value = cloudflare_api_token.default.name
description = "Name of the API Token"
}
module/cloudflare_account_token/main.tf
terraform {
required_version = "~> 1.8.0"
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.36"
}
}
}
resource "cloudflare_api_token" "default" {
name = var.token_name
policy {
permission_groups = var.permission_groups
resources = {
"com.cloudflare.api.account.${var.cloudflare_account_id}" = "*"
}
}
}
module/cloudflare_account_token/variables.tf
variable "cloudflare_account_id" {
description = "The Cloudflare account ID"
type = string
sensitive = true
}
variable "token_name" {
description = "The name of the token"
type = string
}
variable "permission_groups" {
description = "The permission groups for the token. https://developers.cloudflare.com/fundamentals/api/reference/permissions/"
type = set(string)
}
WIP
発行したトークンをどうやって provider
に渡すかですが、私は R2 用 module と Token 用 module をそれぞれ用意して、R2 用 module の中に provider "aws"
を書いています。
main.tf
// e.g.:
data "cloudflare_api_token_permission_groups" "all" {}
module "cloudflare_r2_token" {
source = "../../../modules/cloudflare_account_token"
token_name = "terraform-app-r2-management"
permission_groups = [
data.cloudflare_api_token_permission_groups.all.account["Workers R2 Storage Write"],
data.cloudflare_api_token_permission_groups.all.account["Workers R2 Storage Read"],
]
cloudflare_account_id = data.sops_file.secrets.data["cloudflare.account_id"]
}
module "object_storage" {
source = "../../../modules/cloudflare_r2"
cloudflare_r2_token = module.cloudflare_r2_token.token
cloudflare_r2_access_key_id = module.cloudflare_r2_token.access_key_id
cloudflare_r2_secret_access_key = module.cloudflare_r2_token.secret_access_key
}
modules/cloudflare_r2/main.tf
// e.g.:
provider "aws" {
region = "APAC"
access_key = var.cloudflare_r2_access_key_id
secret_key = var.cloudflare_r2_secret_access_key
skip_requesting_account_id = true
skip_credentials_validation = true
skip_region_validation = true
endpoints {
s3 = "https://${var.cloudflare_account_id}.r2.cloudflarestorage.com"
}
}
元々、tfstate 等 Terraform 必要な情報を管理するためにアプリケーション用とは別のルートモジュール management
をもっていた。
その management
であらかじめ Cloud Secret Manager に各種 R2 トークンを入れておく。
data "cloudflare_api_token_permission_groups" "all" {}
resource "cloudflare_api_token" "r2_write" {
name = "terraform-demo-r2"
policy {
permission_groups = [
data.cloudflare_api_token_permission_groups.all.account["Workers R2 Storage Write"],
data.cloudflare_api_token_permission_groups.all.account["Workers R2 Storage Read"],
]
resources = {
"com.cloudflare.api.account.${var.cloudflare_account_id}" = "*"
}
}
}
resource "google_project_service" "secret_manager" {
service = "secretmanager.googleapis.com"
}
resource "google_secret_manager_secret" "cloudflare_r2_access_key_id" {
secret_id = "cloudflare_r2_access_key_id"
replication {
auto {}
}
}
resource "google_secret_manager_secret_version" "cloudflare_r2_access_key_id" {
secret = google_secret_manager_secret.cloudflare_r2_access_key_id.id
secret_data = cloudflare_api_token.r2_write.id
}
resource "google_secret_manager_secret" "cloudflare_r2_secret_access_key" {
secret_id = "cloudflare_r2_secret_access_key"
replication {
auto {}
}
}
resource "google_secret_manager_secret_version" "cloudflare_r2_secret_access_key" {
secret = google_secret_manager_secret.cloudflare_r2_secret_access_key.id
secret_data = sha256(cloudflare_api_token.r2_write.value)
}
resource "google_secret_manager_secret" "cloudflare_r2_token" {
secret_id = "cloudflare_r2_token"
replication {
auto {}
}
}
resource "google_secret_manager_secret_version" "cloudflare_r2_token" {
secret = google_secret_manager_secret.cloudflare_r2_token.id
secret_data = cloudflare_api_token.r2_write.value
}
ルートモジュール側から Secret Manager の値で Provider を定義して、無事に module から Provider 定義を消すことができた。
maiin.tf
data "google_secret_manager_secret_version" "cloudflare_r2_access_key_id" {
version = "latest"
secret = "cloudflare_r2_access_key_id"
}
data "google_secret_manager_secret_version" "cloudflare_r2_secret_access_key" {
version = "latest"
secret = "cloudflare_r2_secret_access_key"
}
provider "aws" {
region = "APAC" # Asia-Pacific
access_key = data.google_secret_manager_secret_version.cloudflare_r2_access_key_id.secret_data
secret_key = data.google_secret_manager_secret_version.cloudflare_r2_secret_access_key.secret_data
skip_requesting_account_id = true
skip_credentials_validation = true
skip_region_validation = true
endpoints {
s3 = "https://${data.sops_file.secrets.data["cloudflare.account_id"]}.r2.cloudflarestorage.com"
}
}
R2 トークンのスコープを絞る方法
data "cloudflare_api_token_permission_groups" "all" {}
resource "cloudflare_api_token" "demo" {
name = var.token_name
policy {
permission_groups = [
data.cloudflare_api_token_permission_groups.all.account["Workers R2 Storage Write"],
data.cloudflare_api_token_permission_groups.all.account["Workers R2 Storage Read"],
]
resources = {
"com.cloudflare.api.account.${var.cloudflare_account_id}" = "*"
}
}
}
上記の方法でトークンを作成すると、All buckets
, Admin Read & Write
の権限をもつトークンが生成されます。
例えば、特定のバケットに対して、Object Read only
のトークンを作るには以下のようにします。
data "cloudflare_api_token_permission_groups" "all" {}
resource "cloudflare_api_token" "demo" {
name = var.token_name
policy {
permission_groups = [
data.cloudflare_api_token_permission_groups.all.r2["Workers R2 Storage Bucket Item Read"],
]
resources = {
"com.cloudflare.edge.r2.bucket.${var.cloudflare_account_id}_default_${var.bucket_name}" = "*"
}
}
}
参考
このスクラップは6ヶ月前にクローズされました