cloudflare management for cms

This commit is contained in:
2025-10-30 10:17:14 +01:00
parent 9b09e6bd86
commit 140dab4f1d
7 changed files with 239 additions and 6 deletions

View File

@@ -0,0 +1,79 @@
# Récupère toutes les permissions Cloudflare disponibles
data "cloudflare_account_api_token_permission_groups_list" "all" {
account_id = var.account_id
}
# Sélectionne uniquement les permissions demandées
locals {
# Simplifie le scope Cloudflare (ex: "account" depuis "com.cloudflare.api.account")
permission_map = {
for p in data.cloudflare_account_api_token_permission_groups_list.all.result :
"${split(".", p.scopes[0])[length(split(".", p.scopes[0])) - 1]}:${p.name}" => p.id
}
# Résout les permissions (si présentes) pour chaque catégorie
selected_account_permissions = var.permissions.account != null ? compact([
for name in var.permissions.account : lookup(local.permission_map, name, null)
]) : []
selected_bucket_permissions = var.bucket != null && try(var.permissions.bucket, null) != null ? compact([
for name in var.permissions.bucket : lookup(local.permission_map, name, null)
]) : []
# Validation des permissions introuvables
missing_permissions = concat(
[for name in coalesce(var.permissions.account, []) : name if lookup(local.permission_map, name, null) == null],
[for name in coalesce(var.permissions.bucket, []) : name if lookup(local.permission_map, name, null) == null]
)
# Ressources cibles
account_resource = {
"com.cloudflare.api.account.${var.account_id}" = "*"
}
bucket_resource = var.bucket != null ? {
"com.cloudflare.edge.r2.bucket.${var.account_id}_${var.bucket.jurisdiction}_${var.bucket.name}" = "*"
} : {}
# Policies construites dynamiquement
policies = [for policy in [
length(local.selected_account_permissions) > 0 ? {
effect = "allow"
permission_groups = [for id in local.selected_account_permissions : { id = id }]
resources = local.account_resource
} : null,
length(local.selected_bucket_permissions) > 0 ? {
effect = "allow"
permission_groups = [for id in local.selected_bucket_permissions : { id = id }]
resources = local.bucket_resource
} : null
] : policy if policy != null]
error_message = length(local.missing_permissions) > 0 ? format("Permissions introuvables : %s", join(", ", local.missing_permissions)) : ""
}
# Création du token
resource "cloudflare_account_token" "token" {
account_id = var.account_id
name = var.token_name
policies = local.policies
expires_on = null
lifecycle {
ignore_changes = [expires_on]
replace_triggered_by = [null_resource.cloudflare_account_token_replace]
precondition {
condition = length(local.missing_permissions) == 0
error_message = local.error_message
}
}
}
resource "null_resource" "cloudflare_account_token_replace" {
triggers = {
"policies" = sha256(join("", local.selected_account_permissions, local.selected_bucket_permissions))
}
}

View File

@@ -0,0 +1,35 @@
output "token" {
description = "Valeur du token Cloudflare"
value = cloudflare_account_token.token.value
sensitive = true
}
output "token_id" {
description = "ID du token Cloudflare (sert de Access Key ID pour R2 si bucket défini)"
value = cloudflare_account_token.token.id
}
output "token_sha256" {
description = "SHA-256 du token Cloudflare (sert de Secret Access Key pour R2 si bucket défini)"
value = sha256(cloudflare_account_token.token.value)
sensitive = true
}
output "r2_credentials" {
description = "Credentials R2 si bucket configuré (AccessKeyId, SecretAccessKey)"
value = var.bucket != null ? {
access_key_id = cloudflare_account_token.token.id
secret_access_key = sha256(cloudflare_account_token.token.value)
} : null
sensitive = true
}
output "permissions" {
description = "Liste des permissions introuvables (si existantes)"
value = compact(concat(local.selected_account_permissions, local.selected_bucket_permissions))
}
output "resources" {
description = "Map des resources assignées au token"
value = keys(merge(local.account_resource, local.bucket_resource))
}

View File

@@ -0,0 +1,37 @@
variable "account_id" {
description = "Cloudflare account ID"
type = string
}
variable "token_name" {
description = "Nom du token Cloudflare à créer"
type = string
}
variable "permissions" {
description = <<-EOT
Liste des permissions Cloudflare (ex: [\"Pages Deploy\", \"Zone DNS Edit\"])
you can check required permissions per service
https://developers.cloudflare.com/api/node/
EOT
type = object({
account = optional(list(string))
bucket = optional(list(string))
})
}
variable "bucket" {
description = <<-EOT
Objet optionnel représentant un bucket R2.
Exemple :
{
name = "mon-bucket"
jurisdiction = "eu"
}
EOT
type = object({
name = string
jurisdiction = string
})
default = null
}