From 07c2dc3ecb97f82cb54ffd5e5232a34357200210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Rodrigues?= Date: Sat, 20 Jun 2026 15:43:10 +0100 Subject: [PATCH] feat(infra): auto-generate Gitea admin password and runner token MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace var.gitea_admin_password with random_password (like Grafana) - Replace var.gitea_runner_token with terraform_data bootstrapper that calls the Gitea admin API after first deploy and patches the secret - Empty variables.tf — no manual secrets needed on terraform apply Co-Authored-By: Claude Sonnet 4.6 --- infrastructure/terraform/act-runner.tf | 14 ------ infrastructure/terraform/gitea.tf | 63 ++++++++++++++++++++++++-- infrastructure/terraform/variables.tf | 16 ++----- 3 files changed, 63 insertions(+), 30 deletions(-) diff --git a/infrastructure/terraform/act-runner.tf b/infrastructure/terraform/act-runner.tf index 55f91e5..a5f0b20 100644 --- a/infrastructure/terraform/act-runner.tf +++ b/infrastructure/terraform/act-runner.tf @@ -44,20 +44,6 @@ resource "kubernetes_cluster_role_binding" "act_runner" { } } -# Populated after initial Gitea deploy: -# 1. Open http://git.homelab.local → Admin Area → Runners → Create Runner -# 2. Copy the token -# 3. terraform apply -var gitea_runner_token= -resource "kubernetes_secret" "gitea_runner_token" { - metadata { - name = "gitea-runner-token" - namespace = kubernetes_namespace.domains["gitea"].metadata[0].name - } - data = { - token = var.gitea_runner_token - } -} - # ConfigMap for act runner config (host executor mode — steps run directly in runner container) resource "kubernetes_config_map" "act_runner" { metadata { diff --git a/infrastructure/terraform/gitea.tf b/infrastructure/terraform/gitea.tf index d08e661..a4d8bff 100644 --- a/infrastructure/terraform/gitea.tf +++ b/infrastructure/terraform/gitea.tf @@ -1,3 +1,8 @@ +resource "random_password" "gitea_admin" { + length = 24 + special = false +} + resource "kubernetes_secret" "gitea_admin" { metadata { name = "gitea-admin" @@ -5,7 +10,7 @@ resource "kubernetes_secret" "gitea_admin" { } data = { username = "admin" - password = var.gitea_admin_password + password = random_password.gitea_admin.result email = "admin@homelab.local" } } @@ -42,7 +47,7 @@ resource "helm_release" "gitea" { } } - "postgresql-ha" = { enabled = false } + "postgresql-ha" = { enabled = false } "valkey-cluster" = { enabled = false } ingress = { @@ -81,6 +86,58 @@ resource "helm_release" "gitea" { })] } +# Placeholder secret created by Terraform; data is populated by the +# terraform_data bootstrapper below after Gitea is reachable. +resource "kubernetes_secret" "gitea_runner_token" { + metadata { + name = "gitea-runner-token" + namespace = kubernetes_namespace.domains["gitea"].metadata[0].name + } + data = { token = "" } + + lifecycle { + # After the bootstrapper writes the real token we must not overwrite it + # with the empty placeholder on subsequent applies. + ignore_changes = [data] + } +} + +# On first apply: poll until Gitea is up, call the admin API to obtain a +# runner registration token, and patch the secret in place. +# On subsequent applies this resource is a no-op (terraform_data only +# re-runs its provisioner when triggers_replace changes). +resource "terraform_data" "gitea_runner_registration" { + depends_on = [helm_release.gitea, kubernetes_secret.gitea_runner_token] + + # Re-bootstrap only if the admin password rotates. + triggers_replace = [random_password.gitea_admin.id] + + provisioner "local-exec" { + interpreter = ["/bin/sh", "-c"] + command = <<-EOT + set -e + + echo "Waiting for Gitea to be ready..." + until curl -sf "http://git.homelab.local/api/v1/version" > /dev/null 2>&1; do + sleep 5 + done + + PASSWORD=$(kubectl get secret gitea-admin -n gitea \ + -o jsonpath='{.data.password}' | base64 -d) + + TOKEN=$(curl -sf -X POST \ + -u "admin:$PASSWORD" \ + "http://git.homelab.local/api/v1/admin/runners/registration-token" \ + | grep -o '"token":"[^"]*"' | cut -d'"' -f4) + + kubectl patch secret gitea-runner-token -n gitea \ + -p "{\"data\":{\"token\":\"$(printf '%s' "$TOKEN" | base64)\"}}" + + echo "Runner registration token written to gitea-runner-token secret." + EOT + } +} + # imagePullSecret for finance namespace — allows k8s to pull images from Gitea registry. # Containerd mirrors "git.homelab.local" to localhost:30002 (see k3d/config.yaml) and # forwards these credentials to authenticate against the Gitea NodePort. @@ -94,7 +151,7 @@ resource "kubernetes_secret" "gitea_registry_finance" { ".dockerconfigjson" = jsonencode({ auths = { "git.homelab.local" = { - auth = base64encode("admin:${var.gitea_admin_password}") + auth = base64encode("admin:${random_password.gitea_admin.result}") } } }) diff --git a/infrastructure/terraform/variables.tf b/infrastructure/terraform/variables.tf index 328596c..66bae69 100644 --- a/infrastructure/terraform/variables.tf +++ b/infrastructure/terraform/variables.tf @@ -1,13 +1,3 @@ -variable "gitea_admin_password" { - description = "Gitea admin password — set TF_VAR_gitea_admin_password or override in terraform.tfvars" - type = string - default = "gitea-dev-changeme" - sensitive = true -} - -variable "gitea_runner_token" { - description = "Gitea runner registration token — obtain from Gitea UI: Admin Area → Runners → Create Runner, then set TF_VAR_gitea_runner_token" - type = string - default = "" - sensitive = true -} +# No manual secrets required — passwords are generated by random_password resources +# and stored in Terraform state. Runner token is fetched from the Gitea API +# automatically after the first deploy.