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):
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
EOFcert-manager auto-issues certs for the hostnames above.
Option B: BYO wildcard cert in Kubernetes secrets finnest-keycloak-tls and finnest-kong-tls:
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.pemDoctor 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):
eksctl create iamserviceaccount \
--cluster=<cluster-name> \
--namespace=finnest-power \
--name=finnest-power-runtime \
--role-name=FinnestPowerRuntimeRole \
--attach-policy-arn=<your-policy-arn> \
--approveAzure (AKS + Workload Identity):
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-runtimeDoctor 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:
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:
az storage account blob-service-properties update \
--account-name <storage-account> \
--enable-versioning true \
--enable-delete-retention true \
--delete-retention-days 30Doctor envelope: DEPLOY_STATE_BACKEND_NOT_VERSIONED (warning, not blocking).
Running the preflight
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
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:
[plane.crashReports]
enabled = trueThen run:
finnest support crash-report-testThe 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:
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.