name: Terraform Terragrunt (contour) # One workflow for ALL closed contours. Per-contour differentiation is done via # repository variables/secrets in each contour's Gitea — this is the downstream # runner contract: # vars: INFRA_ENV, RUNNER_LABEL, RUNNER_IMAGE, RABBITMQ_ENDPOINT, PG_ADMIN_HOST, # KAFKA_BOOTSTRAP, SKIP_POSTGRES_ADMIN, SKIP_KAFKA_ADMIN, SKIP_MINIO_ADMIN # secrets: TF_STATE_S3_ENDPOINT, TF_STATE_S3_BUCKET, S3_ACCESS_KEY, S3_SECRET_KEY, # VAULT_ADDR, VAULT_TOKEN, SOPS_AGE_KEY_CONTOUR, KUBECONFIG_B64 (external # runner only), KUBE_CONTEXT (external runner only) # Infra-service admin creds are NOT passed as secrets — they are read from Vault # at run time (see the "Run ... stacks" step) so the single source of truth stays # in the contour Vault. on: workflow_dispatch: pull_request: branches: [contour] paths: - "live/**" - "modules/**" - "infrastructure.yaml" - "infrastructure-secrets.yaml" - "scripts/**" - ".gitea/workflows/**" push: branches: [contour] paths: - "live/**" - "modules/**" - "infrastructure.yaml" - "infrastructure-secrets.yaml" - "scripts/**" - ".gitea/workflows/**" env: TF_STATE_S3_REGION: ru-central1 INFRA_ENV: ${{ vars.INFRA_ENV }} SKIP_POSTGRES_ADMIN: ${{ vars.SKIP_POSTGRES_ADMIN }} SKIP_KAFKA_ADMIN: ${{ vars.SKIP_KAFKA_ADMIN }} SKIP_MINIO_ADMIN: ${{ vars.SKIP_MINIO_ADMIN }} PG_ADMIN_HOST: ${{ vars.PG_ADMIN_HOST }} KAFKA_BOOTSTRAP: ${{ vars.KAFKA_BOOTSTRAP }} RABBITMQ_ENDPOINT: ${{ vars.RABBITMQ_ENDPOINT }} jobs: validate: runs-on: ${{ vars.RUNNER_LABEL || 'incluster' }} container: image: ${{ vars.RUNNER_IMAGE || 'cr.yandex/crp3ccidau046kdj8g9q/terraform/terragrunt:v9.11' }} env: TF_STATE_S3_ENDPOINT: ${{ secrets.TF_STATE_S3_ENDPOINT }} TF_STATE_S3_BUCKET: ${{ secrets.TF_STATE_S3_BUCKET }} S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }} S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }} VAULT_ADDR: ${{ secrets.VAULT_ADDR }} VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }} KUBE_CONTEXT: ${{ secrets.KUBE_CONTEXT }} KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }} KUBECONFIG: /workspace/.kube/config GIT_AUTH_TOKEN: ${{ github.token }} steps: - name: Checkout (without Node.js action) run: | if [ -f infrastructure.yaml ] && [ -d live ]; then echo "Workspace already contains repository files, skip checkout." exit 0 fi TOKEN="${GIT_AUTH_TOKEN:-${GITHUB_TOKEN:-${GITEA_TOKEN:-}}}" if [ -z "$TOKEN" ]; then echo "No token found for git checkout (github.token/GITHUB_TOKEN/GITEA_TOKEN)." exit 1 fi REPO_URL="${GITHUB_SERVER_URL%/}/${GITHUB_REPOSITORY}.git" git init . git remote add origin "$REPO_URL" 2>/dev/null || git remote set-url origin "$REPO_URL" git -c http.extraHeader="Authorization: token ${TOKEN}" fetch --depth=1 origin "${GITHUB_SHA}" git checkout -f FETCH_HEAD - name: Prepare kubeconfig run: | if [ -n "${KUBECONFIG_B64:-}" ]; then mkdir -p /workspace/.kube echo "$KUBECONFIG_B64" | base64 -d > /workspace/.kube/config chmod 600 /workspace/.kube/config else echo "No KUBECONFIG_B64 — in-cluster runner: kubernetes/vault providers use the pod ServiceAccount kubeconfig or in-cluster config." fi - name: Decrypt secret values # SOPS_AGE_KEY only reaches this step, not the whole job - the rest # (checkout, kubeconfig, terragrunt run) never sees it. env: SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY_CONTOUR }} run: | if ! command -v sops >/dev/null 2>&1; then apk add --no-cache sops || (apk add --no-cache curl && curl -fsSL https://github.com/getsops/sops/releases/download/v3.9.0/sops-v3.9.0.linux.amd64 -o /usr/local/bin/sops && chmod +x /usr/local/bin/sops); fi sops --decrypt infrastructure-secrets.yaml > /tmp/infra-secret-values.yaml echo "INFRA_SECRET_VALUES_FILE=/tmp/infra-secret-values.yaml" >> "$GITHUB_ENV" - name: Run validate for all stacks run: | . ./scripts/load_admin_creds.sh ./scripts/run_all_stacks.sh validate rm -f /tmp/infra-secret-values.yaml plan: needs: [validate] runs-on: ${{ vars.RUNNER_LABEL || 'incluster' }} container: image: ${{ vars.RUNNER_IMAGE || 'cr.yandex/crp3ccidau046kdj8g9q/terraform/terragrunt:v9.11' }} env: TF_STATE_S3_ENDPOINT: ${{ secrets.TF_STATE_S3_ENDPOINT }} TF_STATE_S3_BUCKET: ${{ secrets.TF_STATE_S3_BUCKET }} S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }} S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }} VAULT_ADDR: ${{ secrets.VAULT_ADDR }} VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }} KUBE_CONTEXT: ${{ secrets.KUBE_CONTEXT }} KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }} KUBECONFIG: /workspace/.kube/config GIT_AUTH_TOKEN: ${{ github.token }} steps: - name: Checkout (without Node.js action) run: | if [ -f infrastructure.yaml ] && [ -d live ]; then echo "Workspace already contains repository files, skip checkout." exit 0 fi TOKEN="${GIT_AUTH_TOKEN:-${GITHUB_TOKEN:-${GITEA_TOKEN:-}}}" if [ -z "$TOKEN" ]; then echo "No token found for git checkout (github.token/GITHUB_TOKEN/GITEA_TOKEN)." exit 1 fi REPO_URL="${GITHUB_SERVER_URL%/}/${GITHUB_REPOSITORY}.git" git init . git remote add origin "$REPO_URL" 2>/dev/null || git remote set-url origin "$REPO_URL" git -c http.extraHeader="Authorization: token ${TOKEN}" fetch --depth=1 origin "${GITHUB_SHA}" git checkout -f FETCH_HEAD - name: Prepare kubeconfig run: | if [ -n "${KUBECONFIG_B64:-}" ]; then mkdir -p /workspace/.kube echo "$KUBECONFIG_B64" | base64 -d > /workspace/.kube/config chmod 600 /workspace/.kube/config fi - name: Decrypt secret values # SOPS_AGE_KEY only reaches this step, not the whole job - the rest # (checkout, kubeconfig, terragrunt run) never sees it. env: SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY_CONTOUR }} run: | if ! command -v sops >/dev/null 2>&1; then apk add --no-cache sops || (apk add --no-cache curl && curl -fsSL https://github.com/getsops/sops/releases/download/v3.9.0/sops-v3.9.0.linux.amd64 -o /usr/local/bin/sops && chmod +x /usr/local/bin/sops); fi sops --decrypt infrastructure-secrets.yaml > /tmp/infra-secret-values.yaml echo "INFRA_SECRET_VALUES_FILE=/tmp/infra-secret-values.yaml" >> "$GITHUB_ENV" - name: Run plan for all stacks run: | . ./scripts/load_admin_creds.sh ./scripts/run_all_stacks.sh plan rm -f /tmp/infra-secret-values.yaml apply: needs: [plan] if: github.event_name == 'push' runs-on: ${{ vars.RUNNER_LABEL || 'incluster' }} container: image: ${{ vars.RUNNER_IMAGE || 'cr.yandex/crp3ccidau046kdj8g9q/terraform/terragrunt:v9.11' }} env: TF_STATE_S3_ENDPOINT: ${{ secrets.TF_STATE_S3_ENDPOINT }} TF_STATE_S3_BUCKET: ${{ secrets.TF_STATE_S3_BUCKET }} S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }} S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }} VAULT_ADDR: ${{ secrets.VAULT_ADDR }} VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }} KUBE_CONTEXT: ${{ secrets.KUBE_CONTEXT }} KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }} KUBECONFIG: /workspace/.kube/config GIT_AUTH_TOKEN: ${{ github.token }} steps: - name: Checkout (without Node.js action) run: | if [ -f infrastructure.yaml ] && [ -d live ]; then echo "Workspace already contains repository files, skip checkout." exit 0 fi TOKEN="${GIT_AUTH_TOKEN:-${GITHUB_TOKEN:-${GITEA_TOKEN:-}}}" if [ -z "$TOKEN" ]; then echo "No token found for git checkout (github.token/GITHUB_TOKEN/GITEA_TOKEN)." exit 1 fi REPO_URL="${GITHUB_SERVER_URL%/}/${GITHUB_REPOSITORY}.git" git init . git remote add origin "$REPO_URL" 2>/dev/null || git remote set-url origin "$REPO_URL" git -c http.extraHeader="Authorization: token ${TOKEN}" fetch --depth=1 origin "${GITHUB_SHA}" git checkout -f FETCH_HEAD - name: Prepare kubeconfig run: | if [ -n "${KUBECONFIG_B64:-}" ]; then mkdir -p /workspace/.kube echo "$KUBECONFIG_B64" | base64 -d > /workspace/.kube/config chmod 600 /workspace/.kube/config fi - name: Decrypt secret values # SOPS_AGE_KEY only reaches this step, not the whole job - the rest # (checkout, kubeconfig, terragrunt run) never sees it. env: SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY_CONTOUR }} run: | if ! command -v sops >/dev/null 2>&1; then apk add --no-cache sops || (apk add --no-cache curl && curl -fsSL https://github.com/getsops/sops/releases/download/v3.9.0/sops-v3.9.0.linux.amd64 -o /usr/local/bin/sops && chmod +x /usr/local/bin/sops); fi sops --decrypt infrastructure-secrets.yaml > /tmp/infra-secret-values.yaml echo "INFRA_SECRET_VALUES_FILE=/tmp/infra-secret-values.yaml" >> "$GITHUB_ENV" - name: Run apply for all stacks run: | . ./scripts/load_admin_creds.sh ./scripts/run_all_stacks.sh apply rm -f /tmp/infra-secret-values.yaml