import { Construct } from "constructs"; import { App, TerraformStack, TerraformOutput } from "cdktf"; import { HelmProvider } from "./.gen/providers/helm/provider"; import { Release } from "./.gen/providers/helm/release"; import { KubernetesProvider } from "./.gen/providers/kubernetes/provider"; import { NullProvider } from "./.gen/providers/null/provider"; import { Resource } from "./.gen/providers/null/resource"; export class ClusterComponentsStack extends TerraformStack { constructor(scope: Construct, id: string) { super(scope, id); // Configure providers new HelmProvider(this, "helm", { kubernetes: { configPath: "~/.kube/config", configContext: "kind-kind", }, }); new KubernetesProvider(this, "kubernetes", { configPath: "~/.kube/config", configContext: "kind-kind", }); new NullProvider(this, "null", {}); // 1. Install cert-manager for TLS certificate management const certManager = new Release(this, "cert-manager", { name: "cert-manager", repository: "oci://quay.io/jetstack/charts", chart: "cert-manager", version: "v1.18.2", namespace: "cert-manager", createNamespace: true, wait: true, set: [ { name: "crds.enabled", value: "true", }, ], }); // 2. Install Traefik ingress controller const traefik = new Release(this, "traefik", { name: "traefik", repository: "https://traefik.github.io/charts", chart: "traefik", version: "36.3.0", namespace: "ingress", createNamespace: true, wait: true, values: [ `logs: general: level: DEBUG additionalArguments: - "--serverstransport.insecureskipverify=true" service: type: NodePort ports: web: nodePort: 30080 redirections: entryPoint: to: websecure scheme: https permanent: true websecure: nodePort: 30443 ingressClass: enabled: true isDefaultClass: true`, ], dependsOn: [certManager], }); // 3. Install PostgreSQL database const postgresql = new Release(this, "postgresql", { name: "db", repository: "https://charts.bitnami.com/bitnami", chart: "postgresql", version: "12.10.0", namespace: "default", wait: true, values: [ `primary: pgHbaConfiguration: | host all all all trust`, ], dependsOn: [traefik], }); // 4. Install Zitadel const zitadel = new Release(this, "zitadel", { name: "my-zitadel", repository: "https://charts.zitadel.com", chart: "zitadel", namespace: "default", wait: true, values: [ `zitadel: masterkey: x123456789012345678901234567891y configmapConfig: Log: Level: debug ExternalDomain: machine.127.0.0.1.sslip.io ExternalPort: 443 TLS: Enabled: false FirstInstance: Org: Machine: Machine: Username: zitadel-admin-sa Name: Admin MachineKey: ExpirationDate: "2026-01-01T00:00:00Z" Type: 1 # PAT: # ExpirationDate: "2026-01-01T00:00:00Z" Database: Postgres: Host: db-postgresql Port: 5432 Database: zitadel MaxOpenConns: 20 MaxIdleConns: 10 MaxConnLifetime: 30m MaxConnIdleTime: 5m User: Username: postgres SSL: Mode: disable Admin: Username: postgres SSL: Mode: disable ingress: enabled: true login: ingress: enabled: true`, ], dependsOn: [postgresql], }); // 5. Wait for cert-manager CRDs to be available const waitForCertManagerCRDs = new Resource(this, "wait-for-cert-manager-crds", { triggers: { cert_manager_dependency: certManager.id, }, provisioners: [ { type: "local-exec", command: "kubectl wait --for=condition=established --timeout=120s crd/clusterissuers.cert-manager.io || kubectl get crd clusterissuers.cert-manager.io", when: "create", }, ], dependsOn: [certManager], }); // 6. Create self-signed certificate issuer and certificate using kubectl apply const createTLSResources = new Resource(this, "create-tls-resources", { triggers: { crd_dependency: waitForCertManagerCRDs.id, zitadel_dependency: zitadel.id, }, provisioners: [ { type: "local-exec", command: `cat < ./certs/zitadel-cert.crt || true `, when: "create", }, ], dependsOn: [patchIngresses], }); // 10. Wait for Zitadel service account secret and extract credentials const extractCredentials = new Resource(this, "extract-credentials", { triggers: { ssl_dependency: configureSSL.id, }, provisioners: [ { type: "local-exec", command: `echo 'Credential extraction would run during apply'`, when: "create", }, ], dependsOn: [configureSSL], }); // 11. Verify Zitadel accessibility const verifyZitadel = new Resource(this, "verify-zitadel", { triggers: { credentials_dependency: extractCredentials.id, }, provisioners: [ { type: "local-exec", command: `echo 'Zitadel verification would run during apply'`, when: "create", }, ], dependsOn: [extractCredentials], }); // 12. Output success message new Resource(this, "completion-message", { triggers: { verification_dependency: verifyZitadel.id, }, provisioners: [ { type: "local-exec", command: `echo 'Installation completed successfully!'`, when: "create", }, ], dependsOn: [verifyZitadel], }); // Output important information new TerraformOutput(this, "zitadel_url", { value: "https://machine.127.0.0.1.sslip.io/ui/console?login_hint=zitadel-admin@zitadel.machine.127.0.0.1.sslip.io", description: "Zitadel Console URL", }); new TerraformOutput(this, "admin_credentials", { value: "zitadel-admin@zitadel.machine.127.0.0.1.sslip.io / Password1!", description: "Default admin credentials", }); } } const app = new App(); new ClusterComponentsStack(app, "cluster-components"); app.synth();