From b6d240ce31e77d8fc4cb1946d4c4ce90898b67f4 Mon Sep 17 00:00:00 2001 From: Gabriel Radureau Date: Fri, 7 Nov 2025 13:54:52 +0100 Subject: [PATCH] configure ovh client and allow cms project to access zoho client --- .gitea/workflows/iac.yaml | 1 + iac/{cloudflare_ovh_cms.tf => cloudflare.tf} | 21 ++++++++ iac/modules/cloudflare_token/main.tf | 10 ++-- iac/ovh.tf | 57 ++++++++++++++++++++ iac/providers.tf | 19 +++++-- 5 files changed, 99 insertions(+), 9 deletions(-) rename iac/{cloudflare_ovh_cms.tf => cloudflare.tf} (78%) create mode 100644 iac/ovh.tf diff --git a/.gitea/workflows/iac.yaml b/.gitea/workflows/iac.yaml index 3b449eb..9f8f068 100644 --- a/.gitea/workflows/iac.yaml +++ b/.gitea/workflows/iac.yaml @@ -31,6 +31,7 @@ concurrency: kvv1/google/credentials credentials | GOOGLE_CREDENTIALS ; kvv1/admin/gitea token | GITEA_TOKEN ; kvv1/admin/cloudflare iam_token | CLOUDFLARE_API_TOKEN ; + kvv1/admin/ovh/app * | OVH_ ; jobs: gitea_vault_auth: name: Auth with gitea for vault diff --git a/iac/cloudflare_ovh_cms.tf b/iac/cloudflare.tf similarity index 78% rename from iac/cloudflare_ovh_cms.tf rename to iac/cloudflare.tf index 943e4b0..aeb8df4 100644 --- a/iac/cloudflare_ovh_cms.tf +++ b/iac/cloudflare.tf @@ -24,6 +24,9 @@ module "cf_r2_arcodange_tf_token" { "account:Workers R2 Storage Read", "bucket:Workers R2 Storage Bucket Item Write", ] + account = [ + "account:Account Settings Read", + ] } } resource "vault_kv_secret" "cf_r2_arcodange_tf" { @@ -40,6 +43,10 @@ data "vault_policy_document" "cf_r2_arcodange_tf" { path = "kvv1/cloudflare/r2/arcodange-tf" capabilities = ["read"] } + rule { + path = "kvv1/zoho/self_client" # zoho mail client is created manually + capabilities = ["read"] + } } resource "vault_policy" "cf_r2_arcodange_tf" { name = "factory__cf_r2_arcodange_tf" @@ -59,6 +66,9 @@ module "cf_arcodange_cms_token" { account = [ "account:Pages Write", "account:Account DNS Settings Write", + "account:Account Settings Read", + "zone:Zone Write", + "zone:DNS Write", ] } } @@ -68,6 +78,17 @@ resource "gitea_repository_actions_secret" "cf_arcodange_cms_token" { secret_name = "CLOUDFLARE_API_TOKEN" secret_value = module.cf_arcodange_cms_token.token } +resource "gitea_repository_actions_secret" "cf_account_id_cms" { + repository = data.gitea_repo.cms.name + repository_owner = data.gitea_repo.cms.username + secret_name = "CLOUDFLARE_ACCOUNT_ID" + secret_value = local.cloudflare_account_id +} + +output "token" { + value = module.cf_arcodange_cms_token.token + sensitive = true +} resource "vault_kv_secret" "cf_arcodange_cms_token" { path = "kvv1/cloudflare/cms/cf_arcodange_cms_token" diff --git a/iac/modules/cloudflare_token/main.tf b/iac/modules/cloudflare_token/main.tf index 3fb695c..ff7c655 100644 --- a/iac/modules/cloudflare_token/main.tf +++ b/iac/modules/cloudflare_token/main.tf @@ -10,6 +10,7 @@ locals { 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 } + permission_map_from_id = zipmap(values(local.permission_map), keys(local.permission_map)) # Résout les permissions (si présentes) pour chaque catégorie selected_account_permissions = var.permissions.account != null ? compact([ @@ -63,8 +64,8 @@ resource "cloudflare_account_token" "token" { expires_on = null lifecycle { - ignore_changes = [expires_on] - replace_triggered_by = [null_resource.cloudflare_account_token_replace] + ignore_changes = [expires_on, policies] # ignore permission id change as unstable + replace_triggered_by = [null_resource.cloudflare_account_token_replace] # replace permission name change d precondition { condition = length(local.missing_permissions) == 0 error_message = local.error_message @@ -72,8 +73,9 @@ resource "cloudflare_account_token" "token" { } } -resource "null_resource" "cloudflare_account_token_replace" { +resource "null_resource" "cloudflare_account_token_replace" { # replace token when permission names change triggers = { - "policies" = sha256(join("", local.selected_account_permissions, local.selected_bucket_permissions)) + "account_permissions" = sha256(join("",sort([for p_id in local.selected_account_permissions: lookup(local.permission_map_from_id, p_id)]))) + "bucket_permissions" = sha256(join("",sort([for p_id in local.selected_bucket_permissions: lookup(local.permission_map_from_id, p_id)]))) } } diff --git a/iac/ovh.tf b/iac/ovh.tf new file mode 100644 index 0000000..52256d3 --- /dev/null +++ b/iac/ovh.tf @@ -0,0 +1,57 @@ +data "ovh_me" "account" {} +data "ovh_iam_reference_actions" "domain" { + type = "domain" +} +locals { + domain_read_permissions = [ for a in data.ovh_iam_reference_actions.domain.actions: a if contains(a.categories, "READ") ] +} + +resource "ovh_me_api_oauth2_client" "cms" { + name = "cms repo" + description = "arcodange.fr management" + flow = "CLIENT_CREDENTIALS" +} +resource "ovh_iam_policy" "cms" { + name = "cms_manager" + description = "Permissions related to www.arcodange.fr domain" + identities = [ovh_me_api_oauth2_client.cms.identity] + resources = [ + data.ovh_me.account.urn, + # ovh_me_api_oauth2_client.cms.identity, + "urn:v1:eu:resource:domain:arcodange.fr", + ] + # these are all the actions + allow = concat([ + "account:apiovh:me/get", + "account:apiovh:me/supportLevel/get", + "account:apiovh:me/certificates/get", + "account:apiovh:me/tag/get", + "account:apiovh:services/get", + ], + local.domain_read_permissions[*].action, + [ + "domain:apiovh:nameServer/edit", + ]) +} + +resource "gitea_repository_actions_secret" "ovh_cms_client_id" { + repository = data.gitea_repo.cms.name + repository_owner = data.gitea_repo.cms.username + secret_name = "OVH_CLIENT_ID" + secret_value = ovh_me_api_oauth2_client.cms.client_id +} +resource "gitea_repository_actions_secret" "ovh_cms_client_secret" { + repository = data.gitea_repo.cms.name + repository_owner = data.gitea_repo.cms.username + secret_name = "OVH_CLIENT_SECRET" + secret_value = ovh_me_api_oauth2_client.cms.client_secret +} + +resource "vault_kv_secret" "ovh_cms_token" { + path = "kvv1/ovh/cms/app" + data_json = jsonencode({ + client_id = ovh_me_api_oauth2_client.cms.client_id + client_secret = ovh_me_api_oauth2_client.cms.client_secret + urn = ovh_me_api_oauth2_client.cms.identity + }) +} \ No newline at end of file diff --git a/iac/providers.tf b/iac/providers.tf index e5c811d..2d3ebe7 100644 --- a/iac/providers.tf +++ b/iac/providers.tf @@ -16,6 +16,10 @@ terraform { source = "cloudflare/cloudflare" version = "~> 5" } + ovh = { + source = "ovh/ovh" + version = "2.8.0" + } } } @@ -26,10 +30,11 @@ provider "gitea" { # https://registry.terraform.io/providers/go-gitea/gitea/late provider "vault" { address = "https://vault.arcodange.duckdns.org" - auth_login_jwt { # TERRAFORM_VAULT_AUTH_JWT environment variable - mount = "gitea_jwt" - role = "gitea_cicd" - } + token = "hvs.CAESIH6uB0AKBdNoX5HdY4FQ8NlF1Dvrxoxo6fbMEnkhQ2zJGh4KHGh2cy40cFU1UHAzejl0bXB4VElJWGpobTNaQ3U" + # auth_login_jwt { # TERRAFORM_VAULT_AUTH_JWT environment variable + # mount = "gitea_jwt" + # role = "gitea_cicd" + # } } provider "google" { @@ -37,4 +42,8 @@ provider "google" { region = "US-EAST1" } -provider "cloudflare" {} # CLOUDFLARE_API_TOKEN environment variable required \ No newline at end of file +provider "cloudflare" {} # CLOUDFLARE_API_TOKEN environment variable required + +provider "ovh" { # OVH_APPLICATION_KEY OVH_APPLICATION_SECRET OVH_CONSUMER_KEY + endpoint = "ovh-eu" +} \ No newline at end of file