| ← Back to Table of Contents | ← Back to Deployment |
8.1 Environment Setup and Variables
This page documents the environment contract for the current application. The managed Azure deployment is authoritative for production; local development and historical single-database containers use smaller profiles.
Do not copy a production environment from an old MySQL example or from the
retired installer. For Azure, use deploy/azure/main.bicep and its parameter
files so web and job roles receive the same database, secret, storage, mail, and
telemetry settings.
Configuration profiles
| Profile | Database | Tenancy | Cache/session | Secrets | Storage |
|---|---|---|---|---|---|
| Managed Azure production | PostgreSQL default + platform + tenant databases | Enabled | Redis + cache-backed sessions | Encrypted platform database, master key supplied by Key Vault | Azure Blob through managed identity |
| Managed Azure POC/staging | PostgreSQL default + platform + tenant databases | Enabled | Redis when provisioned; local fallback is not production-safe | Same database driver after bootstrap/import | Azure Blob through managed identity |
| Local development/test | MySQL or PostgreSQL | Optional | APCu/file/PHP, or local Redis | chain (environment then local file) |
Local by default |
| Historical self-hosted | MariaDB/MySQL or BYO | Single database | Local, optional Redis | Legacy environment/file | Local or legacy cloud credentials |
The historical profile is unsupported for new managed deployments.
Loading and precedence
Production should inject process environment variables and should not ship
app/config/.env. KMP loads a local dotenv file only when that file exists and
one of these conditions is true:
APP_NAMEis missing;KMP_ENV=local; orKMP_LOAD_DOTENV=true.
When loaded, the dotenv loader is configured to overwrite existing values.
Consequently, an unexpected app/config/.env can override process settings.
Keep it out of managed images and deployments.
CakePHP then loads app/config/app.php and optional
app/config/app_local.php overrides. The production image generates
app_local.php from the runtime environment.
Never commit environment files, connection URLs, SMTP passwords, storage keys, database passwords, recovery keys, or KEKs.
Managed application and role variables
| Variable | Purpose | Managed value/notes |
|---|---|---|
KMP_ENV |
Runtime environment label | production in production |
DEBUG |
CakePHP debug output | false |
APP_NAME |
Deployment/application label | Set by Bicep |
RELEASE_CHANNEL / IMAGE_TAG |
Health and telemetry release identity | Bicep sets the channel; the image normally supplies config/version.txt, and IMAGE_TAG is an optional override |
REQUIRE_HTTPS |
Secure-cookie and HTTPS behavior | true |
TRUST_PROXY |
Honor approved proxy headers | true behind Container Apps |
TRUSTED_PROXY_IPS |
Optional explicit proxy allowlist | Prefer an explicit list where the platform provides stable ranges |
KMP_TENANCY_ENABLED |
Enable host-based tenant resolution | true in managed environments |
KMP_SKIP_MIGRATIONS |
Suppress production-image startup migrations | true on web and worker jobs; the migration job runs the command chain explicitly |
KMP_SKIP_CRON |
Suppress in-container cron | true on every managed web/job role |
Do not use the web process as a scheduler or migration authority.
Database and tenancy
| Variable | Purpose | Notes |
|---|---|---|
KMP_DB_DRIVER |
Database family | postgres for managed Azure |
DATABASE_URL |
Default application datasource | Secret URL for the default/rehearsal database |
PLATFORM_DATABASE_URL |
Platform metadata datasource | Required for managed tenancy |
DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD, DB_DATABASE |
Split default datasource settings | Useful locally when no URL is supplied |
PLATFORM_DB_HOST, PLATFORM_DB_PORT, PLATFORM_DB_USERNAME, PLATFORM_DB_PASSWORD, PLATFORM_DB_DATABASE |
Split platform datasource settings | Useful for local POC/rehearsal |
DATABASE_TEST_URL / PLATFORM_DATABASE_TEST_URL |
Test datasources | Never point tests at production |
The platform database stores the tenant registry, host mappings, platform users, encrypted secret rows, job/schedule state, backup metadata, and audit events. It must not be used for tenant application records. Each managed tenant registry row selects its own PostgreSQL database and secret references.
The Azure migration job owns the required order documented in Deployment. Do not run migrations from multiple web replicas.
Cache and sessions
| Variable | Purpose | Managed value/notes |
|---|---|---|
CACHE_ENGINE |
Application cache backend | redis in production |
REDIS_URL |
Redis endpoint including TLS/password when required | Key Vault-backed Container Apps secret |
REDIS_PERSISTENT |
Reuse PHP worker Redis connections | Enabled by the current production profile |
KMP_SESSION_DEFAULTS |
CakePHP session backend | cache with Redis |
KMP_SESSION_CACHE_CONFIG |
Cache config used for sessions | default |
KMP_SESSION_COOKIE_SECURE |
Require secure session cookies | true outside local HTTP development |
If Redis is requested but unavailable, KMP logs a warning and falls back to a
local cache. /health treats that fallback as degraded when shared Redis/cache
sessions were requested. Do not serve multi-replica production traffic with
per-process APCu/file caches or PHP file sessions.
Database-backed secrets
| Variable | Purpose | Managed value/notes |
|---|---|---|
KMP_SECRETS_DRIVER |
Secret-store driver | database |
KMP_SECRETS_DB_CONNECTION |
Datasource containing encrypted secret rows | platform |
KMP_SECRETS_DB_NAMESPACE |
Secret row namespace | platform |
KMP_SECRETS_DB_MASTER_DRIVER |
Source of the database store’s master key | env |
KMP_SECRETS_DB_MASTER_KEY_NAME |
Portable master-key name | platform.master_kek |
KMP_SECRET_PLATFORM_MASTER_KEK |
Master wrapping key resolved by the env driver | Key Vault-backed; never stored in the platform DB |
KMP_SECRETS_DB_KEY_NAME / KMP_SECRETS_DB_KEY_VERSION |
Metadata for encrypted rows | Defaults platform-secrets / v1 |
KMP_SECRETS_FILE |
Local writable file store | Local/dev only |
KMP_SECRETS_ENV_PREFIX |
Legacy env secret prefix | Defaults KMP_SECRET_ |
The migration job runs:
bin/cake platform secrets import-env
bin/cake platform backup-keys ensure --allow-read-only
import-env is a transition step. It imports only missing legacy values after
platform migrations; database values and tombstones win. Remove legacy
KMP_SECRET_* values only after a successful import deployment. A missing
database master key is a hard failure once the database driver is active.
BACKUP_ENCRYPTION_KEY is the passphrase for the bundled destructive POC seed
archive. It is not the KEK used by new managed tenant or platform backups.
Platform Admin
Platform Admin runs in the same web application on reserved hosts. It is not a separate Container App and does not trust an upstream identity header.
| Variable | Purpose | Safe production value |
|---|---|---|
KMP_PLATFORM_ADMIN_PORTAL_ENABLED |
Enable Platform Admin routes | true only on an environment with an approved reserved host |
KMP_PLATFORM_ADMIN_HOSTS |
Comma-separated reserved admin hosts | Explicit host(s), or the Container App default host when intentionally used |
KMP_PLATFORM_ADMIN_ALLOWED_STATUSES |
Permitted platform_users.status values |
active |
KMP_PLATFORM_ADMIN_DETAILED_LOGIN_ERRORS |
Distinguish password/MFA errors | false |
KMP_PLATFORM_DATA_CONSOLE_ENABLED |
Enable privileged data-console routes | false unless separately reviewed |
PLATFORM_ADMIN_TOTP_WINDOW, PLATFORM_ADMIN_TOTP_PERIOD, PLATFORM_ADMIN_TOTP_DIGITS, PLATFORM_ADMIN_TOTP_ALGORITHM |
TOTP validation parameters | Keep defaults unless an approved migration changes them |
Authentication uses platform-user email/password plus TOTP, lockout, allowed status, and a host-bound session. Bootstrap a local operator only after platform migrations:
bin/cake platform admin bootstrap --email admin@example.org
The command emits one-time credentials and recovery material. Capture them in an approved password manager, never in a ticket or screenshot.
The production image supports SMTP and API transports. The managed template uses SMTP:
| Variable | Purpose |
|---|---|
EMAIL_DRIVER |
smtp, azure, sendgrid, or resend |
EMAIL_SMTP_HOST / EMAIL_SMTP_PORT |
SMTP endpoint |
EMAIL_SMTP_USERNAME / EMAIL_SMTP_PASSWORD |
SMTP credentials |
EMAIL_SMTP_TLS |
Enable SMTP TLS |
EMAIL_FROM |
Sender address |
EMAIL_TRANSPORT_DEFAULT_URL |
Optional complete CakePHP transport URL |
Do not use the stale SMTP_* or EMAIL_FROM_ADDRESS names from historical
examples unless an application-specific override explicitly reads them.
Documents and managed backup objects
| Variable | Purpose | Managed value/notes |
|---|---|---|
DOCUMENT_STORAGE_ADAPTER |
local, azure, or s3 |
azure |
AZURE_STORAGE_AUTH_MODE |
Azure authentication method | managedIdentity |
AZURE_STORAGE_ACCOUNT_NAME |
Storage account | Non-secret |
AZURE_CLIENT_ID |
User-assigned managed identity client ID | Non-secret |
AZURE_STORAGE_CONTAINER_PREFIX |
Prefix for derived tenant document containers | documents by default |
AZURE_STORAGE_CONNECTION_STRING |
Legacy/dev shared-key authentication | Do not use in managed Azure |
AWS_S3_BUCKET / AWS_DEFAULT_REGION |
Canonical S3 bucket/region | Historical or alternate deployment |
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN |
S3 credentials | Prefer workload identity/IAM roles |
AWS_S3_PREFIX / AWS_S3_ENDPOINT / AWS_S3_USE_PATH_STYLE_ENDPOINT |
S3-compatible tuning | Optional |
The managed Azure identity currently has Blob Data Contributor at the storage
account scope. Tenant-specific container names and object prefixes are logical
application isolation, not separate per-tenant Azure identities or RBAC grants.
The same configured Flysystem backend stores encrypted managed backup objects
under scoped tenants/<slug>/ and platform/ keys.
Local managed-backup adapters are disabled by default. The
KMP_LOCAL_BACKUPS_ENABLED, KMP_LOCAL_BACKUPS_PATH,
KMP_PLATFORM_LOCAL_BACKUPS_ENABLED, and
KMP_PLATFORM_LOCAL_BACKUPS_PATH overrides exist for local/historical recovery,
not ephemeral production replicas.
Telemetry and health
The production Bicep profile enables Application Insights and managed OTLP transport. Important controls include:
| Variable | Purpose |
|---|---|
APPINSIGHTS_TRANSPORT |
otlp for the managed agent or direct as a rollback path |
APPINSIGHTS_CONNECTION_STRING |
Required only for direct application export |
OTEL_EXPORTER_OTLP_ENDPOINT |
OTLP endpoint when supplied to the app runtime |
APPINSIGHTS_LOG_ENABLED / APPINSIGHTS_ERROR_LOG_ENABLED |
Trace/error export |
APPINSIGHTS_QUERY_LOG_ENABLED / APPINSIGHTS_QUERY_SAMPLE_RATE |
Sanitized sampled query telemetry |
APPINSIGHTS_CLOUD_ROLE |
Deployment role label |
PERF_REQUEST_LOG_ENABLED / PERF_LOG_ALL_REQUESTS |
Request timing |
PERF_DB_QUERY_LOG_ENABLED |
Database query timing |
PLATFORM_TENANT_TELEMETRY_ENABLED / PLATFORM_TENANT_SLOW_REQUEST_MS |
Per-tenant fleet health inputs |
Validate effective non-secret settings and writable paths:
cd app
bin/cake telemetry_check
bin/cake telemetry_check --send
Use /livez for liveness, /health for default DB plus cache readiness, and
bin/cake platform_health --json for the platform datasource.
Platform audit WORM mirror
| Variable | Purpose | Current status |
|---|---|---|
PLATFORM_AUDIT_WORM_SINK |
disabled or file |
Defaults to disabled |
PLATFORM_AUDIT_WORM_FILE_PATH |
Local append-only JSONL path | Local/dev only |
PLATFORM_AUDIT_WORM_FAIL_CLOSED |
Propagate mirror failure | Defaults to false |
The azure_blob sink throws a not-implemented error. The Azure template does not
provision an immutable audit container or set PLATFORM_AUDIT_WORM_*. The file
sink adds redaction, digests, and a mirror hash chain, but filesystem append is
not storage-enforced WORM. Production immutability, retention/legal hold,
monitoring, and continuity evidence are external prerequisites until the cloud
sink is implemented.
Minimal non-secret managed profile
Secure values below are supplied through Key Vault references, not a committed file:
KMP_ENV=production
KMP_DB_DRIVER=postgres
KMP_TENANCY_ENABLED=true
KMP_SECRETS_DRIVER=database
KMP_SECRETS_DB_MASTER_DRIVER=env
KMP_SECRETS_DB_MASTER_KEY_NAME=platform.master_kek
CACHE_ENGINE=redis
KMP_SESSION_DEFAULTS=cache
KMP_SESSION_CACHE_CONFIG=default
DOCUMENT_STORAGE_ADAPTER=azure
AZURE_STORAGE_AUTH_MODE=managedIdentity
REQUIRE_HTTPS=true
TRUST_PROXY=true
KMP_SKIP_MIGRATIONS=true
KMP_SKIP_CRON=true
DEBUG=false
Required secret references include DATABASE_URL, PLATFORM_DATABASE_URL,
SECURITY_SALT, KMP_SECRET_PLATFORM_MASTER_KEK, REDIS_URL, SMTP
credentials, and the POC seed BACKUP_ENCRYPTION_KEY where that destructive job
is enabled.
Rotation and verification
A Key Vault value change is not automatically a complete application rotation. Container Apps secret references, web revisions, and every affected job must resolve the new version. Database-stored tenant passwords and KEKs have their own audited rotation paths; changing a similarly named Key Vault value does not rotate those rows.
After configuration changes, verify the affected role rather than restarting only web:
bin/cake platform_health --json
bin/cake platform backup-keys ensure --allow-read-only
bin/cake telemetry_check
curl -fsS https://<approved-host>/livez
curl -fsS https://<approved-host>/health
For the complete production values and resource wiring, read
deploy/azure/main.bicep and the Azure runbook.
For local defaults, read app/config/.env.example, app/config/app.php, and
app/config/secrets.php.