++ contour: gitea workflow (runner contract via CI vars INFRA_ENV/RUNNER_LABEL/RUNNER_IMAGE) + load_admin_creds.sh (infra admin creds from Vault) + run_all_stacks.sh

This commit is contained in:
Kochetkov S 2026-07-16 17:10:06 +03:00
parent b8b77536c3
commit 83291cee1e
3 changed files with 217 additions and 0 deletions

View File

@ -0,0 +1,132 @@
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
# secrets: TF_STATE_S3_ENDPOINT, TF_STATE_S3_BUCKET, S3_ACCESS_KEY, S3_SECRET_KEY,
# VAULT_ADDR, VAULT_TOKEN, SOPS_AGE_KEY, 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:
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 }}
jobs:
validate:
runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-latest' }}
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 }}
SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
KUBE_CONTEXT: ${{ secrets.KUBE_CONTEXT }}
KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }}
KUBECONFIG: /workspace/.kube/config
GIT_AUTH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v4
- 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: Run validate for all stacks
run: |
. ./scripts/load_admin_creds.sh
./scripts/run_all_stacks.sh validate
plan:
needs: [validate]
runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-latest' }}
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 }}
SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
KUBE_CONTEXT: ${{ secrets.KUBE_CONTEXT }}
KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }}
KUBECONFIG: /workspace/.kube/config
GIT_AUTH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v4
- 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: Run plan for all stacks
run: |
. ./scripts/load_admin_creds.sh
./scripts/run_all_stacks.sh plan
apply:
needs: [plan]
if: github.event_name == 'push'
runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-latest' }}
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 }}
SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
KUBE_CONTEXT: ${{ secrets.KUBE_CONTEXT }}
KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }}
KUBECONFIG: /workspace/.kube/config
GIT_AUTH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v4
- 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: Run apply for all stacks
run: |
. ./scripts/load_admin_creds.sh
./scripts/run_all_stacks.sh apply

40
scripts/load_admin_creds.sh Executable file
View File

@ -0,0 +1,40 @@
#!/usr/bin/env sh
# Read in-cluster infra-service ADMIN creds from the contour Vault and export them
# for the providers generated in live/terragrunt.hcl. Sourced (not executed) by the
# CI run steps so the exported vars live in the same shell as terragrunt.
#
# Paths are the platform bootstrap layout (same as the bootstrap cronjobs read):
# secrets/postgresql/admin postgres-password
# secrets/kafka/bootstrap interBrokerPassword
# secrets/minio/admin rootUser / rootPassword
# secrets/rabbitmq/auth username / password
set -eu
: "${VAULT_ADDR:?VAULT_ADDR is required}"
: "${VAULT_TOKEN:?VAULT_TOKEN is required}"
_kv() {
curl -sf -H "X-Vault-Token: ${VAULT_TOKEN}" "${VAULT_ADDR}/v1/secrets/data/$1" \
| jq -r --arg k "$2" '.data.data[$k] // ""'
}
# Service endpoints default to the in-cluster svc DNS (consistent across contours);
# override via CI vars if a contour differs.
export PG_ADMIN_HOST="${PG_ADMIN_HOST:-postgresql.postgresql.svc.cluster.local}"
export PG_ADMIN_PORT="${PG_ADMIN_PORT:-5432}"
export PG_ADMIN_USER="${PG_ADMIN_USER:-postgres}"
export PG_ADMIN_PASSWORD="$(_kv postgresql/admin postgres-password)"
export KAFKA_BOOTSTRAP="${KAFKA_BOOTSTRAP:-kafka-kafka-contour.kafka.svc.cluster.local:9092}"
export KAFKA_ADMIN_USER="${KAFKA_ADMIN_USER:-inter_broker_user}"
export KAFKA_ADMIN_PASSWORD="$(_kv kafka/bootstrap interBrokerPassword)"
export KAFKA_SASL_MECHANISM="${KAFKA_SASL_MECHANISM:-plain}"
export MINIO_ENDPOINT="${MINIO_ENDPOINT:-minio.minio.svc.cluster.local:9000}"
export MINIO_ADMIN_USER="$(_kv minio/admin rootUser)"
export MINIO_ADMIN_PASSWORD="$(_kv minio/admin rootPassword)"
export RABBITMQ_ENDPOINT="${RABBITMQ_ENDPOINT:-http://rabbitmq.rabbitmq.svc.cluster.local:15672}"
export RABBITMQ_ADMIN_USER="$(_kv rabbitmq/auth username)"
export RABBITMQ_ADMIN_PASSWORD="$(_kv rabbitmq/auth password)"
echo "infra admin creds loaded from Vault (${VAULT_ADDR})"

45
scripts/run_all_stacks.sh Executable file
View File

@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
ACTION="${1:-}"
if [[ -z "$ACTION" ]]; then
echo "Usage: $0 <validate|plan|apply>"
exit 1
fi
STACK_FILES=()
while IFS= read -r tg; do
STACK_FILES+=("$tg")
done < <(find live -name 'terragrunt.hcl' -not -path '*/.terragrunt-cache/*' | sort)
if [[ ${#STACK_FILES[@]} -eq 0 ]]; then
echo "No terragrunt stacks found under live/"
exit 0
fi
for tg in "${STACK_FILES[@]}"; do
stack_dir="$(dirname "$tg")"
# Skip only root-level Terragrunt configuration file (live/terragrunt.hcl).
# Execute concrete stacks like live/<component> and live/<group>/<component>.
if [[ "$stack_dir" == "live" ]]; then
continue
fi
echo "=== STACK: ${stack_dir} ==="
(
cd "$stack_dir"
terragrunt init -reconfigure
if [[ "$ACTION" == "validate" ]]; then
terragrunt validate
elif [[ "$ACTION" == "plan" ]]; then
terragrunt plan -out=tfplan
elif [[ "$ACTION" == "apply" ]]; then
terragrunt apply -auto-approve
else
echo "Unknown action: $ACTION"
exit 1
fi
)
done