diff --git a/k8s/argocd/apps/phase4-terraform-0.yaml b/k8s/argocd/apps/phase4-terraform-0.yaml new file mode 100644 index 0000000..efa9643 --- /dev/null +++ b/k8s/argocd/apps/phase4-terraform-0.yaml @@ -0,0 +1,26 @@ +# Phase 4 — IaC (Terraform) — infrastructure-as-code via Hook Job +# ArgoCD-driven terraform apply. All changes via git push. + +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: terraform-apply + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "4" +spec: + project: homelab + sources: + - repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git + targetRevision: main + path: k8s/hooks/phase4 + destination: + server: https://kubernetes.default.svc + namespace: argocd + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/k8s/hooks/phase4/terraform-apply-hook.yaml b/k8s/hooks/phase4/terraform-apply-hook.yaml new file mode 100644 index 0000000..17e1e87 --- /dev/null +++ b/k8s/hooks/phase4/terraform-apply-hook.yaml @@ -0,0 +1,68 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: terraform-apply + namespace: argocd + annotations: + argocd.argoproj.io/hook: PostSync + argocd.argoproj.io/hook-delete-policy: HookSucceeded +spec: + backoffLimit: 3 + template: + spec: + serviceAccountName: terraform-apply + containers: + - name: terraform + image: hashicorp/terraform:latest + command: ["/bin/sh", "-c"] + args: + - | + set -e + + echo "=== Terraform Apply Hook (ArgoCD PostSync) ===" + + # Clone repo + git clone --depth 1 https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git /repo + cd /repo/terraform + + # Set S3 credentials + export AWS_ACCESS_KEY_ID=$(cat /run/secrets/s3/AWS_ACCESS_KEY_ID) + export AWS_SECRET_ACCESS_KEY=$(cat /run/secrets/s3/AWS_SECRET_ACCESS_KEY) + export AWS_ENDPOINT_URL=$(cat /run/secrets/s3/AWS_ENDPOINT_URL) + + # Initialize and apply + echo "Initializing Terraform..." + terraform init + + echo "Planning Terraform changes..." + terraform plan -out=tfplan + + echo "Applying Terraform..." + terraform apply -auto-approve tfplan + + echo "✓ Terraform apply complete" + volumeMounts: + - name: s3-creds + mountPath: /run/secrets/s3 + readOnly: true + resources: + requests: + memory: "256Mi" + cpu: "250m" + limits: + memory: "1Gi" + cpu: "1" + volumes: + - name: s3-creds + projected: + sources: + - secret: + name: terraform-s3-creds + items: + - key: AWS_ACCESS_KEY_ID + path: AWS_ACCESS_KEY_ID + - key: AWS_SECRET_ACCESS_KEY + path: AWS_SECRET_ACCESS_KEY + - key: AWS_ENDPOINT_URL + path: AWS_ENDPOINT_URL + restartPolicy: Never diff --git a/k8s/hooks/phase4/terraform-rbac.yaml b/k8s/hooks/phase4/terraform-rbac.yaml new file mode 100644 index 0000000..cba71a8 --- /dev/null +++ b/k8s/hooks/phase4/terraform-rbac.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: terraform-apply + namespace: argocd + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: terraform-apply +rules: +- apiGroups: ["*"] + resources: ["*"] + verbs: ["*"] + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: terraform-apply +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: terraform-apply +subjects: +- kind: ServiceAccount + name: terraform-apply + namespace: argocd diff --git a/k8s/hooks/phase4/terraform-s3-secrets.enc.yaml b/k8s/hooks/phase4/terraform-s3-secrets.enc.yaml new file mode 100644 index 0000000..d82f7da --- /dev/null +++ b/k8s/hooks/phase4/terraform-s3-secrets.enc.yaml @@ -0,0 +1,25 @@ +apiVersion: ENC[AES256_GCM,data:kiY=,iv:wvX0y4RDJQbk7fGdXWbSQr60WfM3M5rvc7SCPb1q25g=,tag:C71TErBwHF5FKHzeLXaMzA==,type:str] +kind: ENC[AES256_GCM,data:WILs0jRC,iv:vkkqDYv45946c21yEWBZf0USa0b3IZuhQAXhdSjDKvU=,tag:Sn6ViACi321IUkd8YHfpsQ==,type:str] +metadata: + name: ENC[AES256_GCM,data:WQw0C3Y0MhkHyhJyY7oD9Ib9,iv:+OaUam5cBOwL8eXuxi5clYvV8HvjQgJ7N7mcjmIcpOg=,tag:II2lOgY0edI+bvd3fSreiQ==,type:str] + namespace: ENC[AES256_GCM,data:hSaYZZ+E,iv:BpL3rZSdoM1zvsXNZWISUQBEm6Blv7REGeeVQnHBDP4=,tag:tlmhyRvE3coSFehyKFTsGw==,type:str] +type: ENC[AES256_GCM,data:FQ2B9iNr,iv:aZ4Ah0TzsMciw0NiMBc3vPsMHAczwzeTuhTos+GjuCg=,tag:7V3t9VkcHlhHK9+4Oo6i2A==,type:str] +stringData: + AWS_ACCESS_KEY_ID: ENC[AES256_GCM,data:i4b932+5rglSbg==,iv:6z2HLtTYXUfwkuPzzNZakJ+8UYkpHNs1otrz/lScuLM=,tag:4FxelmrF5p+EF79hGB+ejQ==,type:str] + AWS_SECRET_ACCESS_KEY: ENC[AES256_GCM,data:ATzJ0GwtWVgMc+pnLxoW0zLB37h94HxSoUTsad9Efpe9z0zh3HBdquCr4ek=,iv:dPxiRhnxqEEbtZZW4aSRnByv1rQCcbc0R/ot9bCBiHg=,tag:IpXFDVjc6kJKP7NqDXpAAQ==,type:str] + AWS_ENDPOINT_URL: ENC[AES256_GCM,data:9V0dljvWeFiG4bWAoUs0LSkztGgDIjaSyEaO+C0A4Cb1G1jj+xY=,iv:lnUyU+Vz4kD/VdhA7aKXXGXLcmnXuxkYJa/HT7jICEk=,tag:oafx5JSV20OHdFq5PaJVhQ==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMaFNEREVhZmFJNkVxMDdz + S2hBSG9EQ2grVU1NNHNFcDRDN1ljUldodzA0CkhLOE5YSGNqWVRNbDNNR25yclho + bHJ3c0J0WVVSRHAycWFzSGt2Y2EyS2cKLS0tIFloSkF2YnRUZ25VRDF5NnFlR1Uz + eDFvS2d5S2lQNkJQZDhGY0YvU3FTTVEK0DhLUMtCwsz0hH5WCp1xTZ6sm06hL0cw + KVTiIt/vX6jbWTW3tr6hXdRkZkyXxfHqcY04pWKYIZG82l3DyTipuQ== + -----END AGE ENCRYPTED FILE----- + recipient: age1smu533f803gmd0jq60s2zaj9zlznajy0ca6rtewd4r37mr2hs3uqsrldfh + lastmodified: "2026-07-15T23:39:08Z" + mac: ENC[AES256_GCM,data:DMasKoeAWIR4OHE2cHuYBVZgiEesh1NFraT9D1oqqWnnTyrLaBXSlC0f++g9fMjqba5+50mfgMvK5uimAcHhMVQQadhNrOYY821WcHbaRTPVJty12Ho/ahIaZVzxviQPeeWwh0biXIZdicYYY+jBnh/yXRlPgh0kv4BnuBIq39Y=,iv:/PjQPhfr29B9+rJxjYJfbItKjsmI++lIDVcWnwUTJtg=,tag:olnTGWGQaAE3IJNEy2zUrw==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.2 diff --git a/terraform/argocd-bootstrap.tf b/terraform/argocd-bootstrap.tf index eb619f6..89c3073 100644 --- a/terraform/argocd-bootstrap.tf +++ b/terraform/argocd-bootstrap.tf @@ -96,7 +96,7 @@ resource "helm_release" "argocd" { { name = "GIT_SSL_CAINFO" value = "/etc/ssl/certs/homelab-ca.crt" - } + }, { name = "SOPS_AGE_KEY_FILE" value = "/home/argocd/.sops/keys.txt" @@ -108,7 +108,7 @@ resource "helm_release" "argocd" { secret = { secretName = "homelab-ca-secret" } - } + }, { name = "sops-age" secret = { @@ -122,7 +122,7 @@ resource "helm_release" "argocd" { name = "homelab-ca" mountPath = "/etc/ssl/certs/homelab-ca.crt" subPath = "tls.crt" - } + }, { name = "sops-age" mountPath = "/home/argocd/.sops"