Skip to content

Production deploy prereqs

This runbook lists the prerequisites an Operator must satisfy before running finnest deploy --environment=prod against an AWS or Azure cluster. Each prereq is also surfaced by finnest doctor --environment=prod as a discrete envelope; failures fail the deploy closed.

Checklist

1. DNS records

Power Admin, Keycloak, and Kong expose Gateway-API routes for these hostnames (defaults from infra/helm/finnest-power/values.yaml):

  • admin.<customer-domain> — Power Admin web UI.
  • auth.<customer-domain> — Keycloak.
  • api.<customer-domain> — Kong API gateway.

Create A or AAAA records for each pointing at the cluster load balancer.

  • AWS: NLB hostname from kubectl -n finnest-power get svc finnest-kong-gateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'.
  • Azure: ILB or AGIC IP from kubectl -n finnest-power get svc finnest-kong-gateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}'.

Optional automation: install external-dns chart and grant it write access to the customer's DNS zone.

Doctor envelope: DEPLOY_DNS_RECORDS_MISSING.

2. TLS certificates

The Helm chart defaults tls.enabled: true. Without certs, ingress TLS handshake fails.

Option A (recommended): Install cert-manager with an ACME issuer (Let's Encrypt):

bash
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager --create-namespace \
  --version v1.16.0 \
  --set installCRDs=true

kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    email: admin@<customer-domain>
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
      - http01:
          ingress:
            class: cilium
EOF

cert-manager auto-issues certs for the hostnames above.

Option B: BYO wildcard cert in Kubernetes secrets finnest-keycloak-tls and finnest-kong-tls:

bash
kubectl -n finnest-power create secret tls finnest-keycloak-tls \
  --cert=/path/to/cert.pem --key=/path/to/key.pem
kubectl -n finnest-power create secret tls finnest-kong-tls \
  --cert=/path/to/cert.pem --key=/path/to/key.pem

Doctor envelope: DEPLOY_TLS_CERT_MISSING.

3. External secrets provider

Production runtime secrets (DB password, JWT keys, FAPI signing keys) cannot be plain Kubernetes secrets in a regulated environment.

AWS: Pre-create the secret in AWS Secrets Manager with the required keys (see Helm chart secret schema). Grant the cluster's IRSA role read access.

Azure: Pre-create the secret in Azure Key Vault. Grant the cluster's Workload Identity read access.

Optional: install external-secrets-operator chart for automatic Kubernetes Secret reflection.

Doctor envelope: DEPLOY_EXTERNAL_SECRETS_UNREACHABLE.

4. Workload identity federation

Static cloud credentials in the cluster are a procurement audit flag.

AWS (EKS + IRSA):

bash
eksctl create iamserviceaccount \
  --cluster=<cluster-name> \
  --namespace=finnest-power \
  --name=finnest-power-runtime \
  --role-name=FinnestPowerRuntimeRole \
  --attach-policy-arn=<your-policy-arn> \
  --approve

Azure (AKS + Workload Identity):

bash
az aks update --resource-group=<rg> --name=<cluster> \
  --enable-oidc-issuer --enable-workload-identity

az identity federated-credential create \
  --name finnest-power-runtime \
  --identity-name finnest-power-runtime \
  --resource-group <rg> \
  --issuer "$(az aks show -g <rg> -n <cluster> --query oidcIssuerProfile.issuerUrl -o tsv)" \
  --subject system:serviceaccount:finnest-power:finnest-power-runtime

Doctor envelope: DEPLOY_WORKLOAD_IDENTITY_NOT_CONFIGURED.

5. Pulumi state backend versioning

Production state must survive accidental delete. finnest bootstrap creates the bucket/container but does not enable versioning automatically.

AWS S3:

bash
aws s3api put-bucket-versioning --bucket <state-bucket> \
  --versioning-configuration Status=Enabled
# Optional but recommended: MFA delete
aws s3api put-bucket-versioning --bucket <state-bucket> \
  --versioning-configuration Status=Enabled,MFADelete=Enabled \
  --mfa "<mfa-serial> <mfa-code>"

Azure Blob:

bash
az storage account blob-service-properties update \
  --account-name <storage-account> \
  --enable-versioning true \
  --enable-delete-retention true \
  --delete-retention-days 30

Doctor envelope: DEPLOY_STATE_BACKEND_NOT_VERSIONED (warning, not blocking).

Running the preflight

bash
finnest doctor --cloud=aws --environment=prod --json | jq '.checks[] | select(.ok == false)'

Expected: empty (no failing checks) before finnest deploy --environment=prod.

Optional: CVE freshness check

bash
finnest doctor --check-cves --json | jq '.checks[] | select(.name == "manifest-cve-scan")'

Runs Trivy locally against every digest in your installed CLI's compatibility manifest. Surfaces fresh HIGH/CRITICAL findings as the manifest-cve-scan check; remediate by finnest self-update to a newer CLI that pins newer digests.

The check fails closed: if Trivy is unreachable or the CVE database fetch fails, the check returns a warn with status: 'unknown' rather than falsely reporting "all clear."

Opt-in crash reports

To enable opt-in Sentry crash reports for the CLI itself, edit ~/.finnest/config.toml:

toml
[plane.crashReports]
enabled = true

Then run:

bash
finnest support crash-report-test

The command sends a synthetic event to verify the Sentry DSN baked into your CLI build is reachable. With opt-in off, the command returns skipped and never reaches Sentry. The redaction layer is fail-closed: any event containing high-confidence secrets (Bearer tokens, sk- keys, GitHub PATs) is dropped entirely rather than sent in a "cleaned" form.

SBOM inspection

To inspect the CycloneDX SBOM bundled with your installed CLI binary:

bash
finnest support sbom
finnest support sbom --json | jq '.components | length'

This is offline (reads the embedded SBOM). Dev builds return a typed SBOM_DEV_BUILD error envelope so you cannot mistake a developer build for a signed release.

Finnest Power — Open Finance Brasil + Open Insurance Brasil platform.