Updated JWT authentication to use configuration values instead of hardcoded secrets, improving security and flexibility. Enhanced CORS policy to conditionally allow origins based on configuration settings, with logging for permissive defaults. Updated README to reflect project renaming and clarify service context.
6.6 KiB
Environment Strategy
NOTE (forward-looking): image tag, container name, and namespace reflect the post-rename state. Today's edge compose still references
azaion/flights:${BRANCH}-armand the container name is typicallyflights. Rename tracked under B10 (suite compose update).
Environments
| Environment | Where it runs | Audience | Image tag (post-B10) |
|---|---|---|---|
| Development | Local workstation (dotnet run from the repo root, or docker run against a local PG) |
Engineers | none — built ad-hoc |
| Edge production | Each customer-owned edge device (Jetson Orin / OrangePI / operator-PC), one container per device | Operators, autopilot, UI | azaion/missions:dev-arm / stage-arm / main-arm per device tier |
There is no centralized staging environment in the suite. Each edge device is its own deployment; the stage image tag is for pre-prod customer demo devices, not for a separate cloud staging cluster.
Configuration sources (precedence)
Program.cs resolves each setting in this order:
IConfiguration(defaults: appsettings.json + ASPNETCORE_-prefixed env vars)Environment.GetEnvironmentVariable(...)(legacy fallback for unprefixed env)- Hardcoded dev fallback (last resort)
DATABASE_URL
| Environment | Value source | Resolved value |
|---|---|---|
| Development (no env set) | hardcoded fallback | Host=localhost;Database=azaion;Username=postgres;Password=changeme |
| Development (env set) | env var | Whatever the engineer sets (URL form OR raw Npgsql key=value form both work) |
| Edge production | env var passed via docker compose | postgresql://postgres:${PG_LOCAL_PASSWORD}@postgres-local/azaion (per ../../../suite/_docs/00_top_level_architecture.md) |
ConvertPostgresUrl helper parses the URL form into Npgsql key=value form. Does NOT URL-decode user/password — credentials with @, :, /, % will be mis-parsed. 07_host Caveats #4 calls this out. Mitigation: avoid those characters in the local PG password (the standard suite provisioning does), or pass a raw Npgsql key=value string instead of a URL.
JWT_SECRET
| Environment | Value source | Resolved value |
|---|---|---|
| Development (no env set) | hardcoded fallback | development-secret-key-min-32-chars!! (well-known; never use in production) |
| Development (env set) | env var | Whatever the engineer sets |
| Edge production | env var (compose env_file or per-device-provisioned secret) |
The shared HMAC secret used by admin + every backend service on the device. Rotation is suite-coordinated — see architecture.md § Security |
Critical foot-gun (ADR-005 carry-forward): there is no runtime gate that blocks startup with the dev fallback in production. A misconfigured production deploy will silently boot with the well-known dev secret. The CMMC L2 scorecard tracks the broader fix at suite level (AZ-487 / AZ-494).
Other configuration
These settings are NOT environment-overridable today (carry-forward improvements):
| Setting | Current behavior | Should it differ between dev and prod? |
|---|---|---|
| Swagger UI mount | Always on | Yes — production should gate on IsDevelopment() (ADR-005) |
| CORS policy | AllowAnyOrigin/Method/Header always |
Yes — production should restrict to the suite's reverse-proxy origin |
| HTTPS redirection | None — assumes upstream TLS termination | No — the suite's reverse proxy handles TLS; this is correct |
| Logging verbosity | ASP.NET Core defaults (Information+) | Probably not at this scale; LogLevel:Default = Warning could be useful in prod |
Migrator DROP TABLE IF EXISTS (B9 one-shot) |
Runs every startup; idempotent on already-cleaned devices | No — the idempotent design means this is safe everywhere |
Edge compose excerpt (suite-wide pattern, post-B10)
Per ../../../suite/_docs/00_top_level_architecture.md § Edge compose:
services:
missions: # was: flights (pre-B10)
image: ${REGISTRY_HOST}/azaion/missions:${BRANCH:-main}-arm
container_name: missions
restart: unless-stopped
depends_on:
postgres-local:
condition: service_healthy
environment:
DATABASE_URL: postgresql://postgres:${PG_LOCAL_PASSWORD}@postgres-local/azaion
JWT_SECRET: ${JWT_SECRET}
ports:
- "5002:8080"
networks:
- azaion-edge
The actual file lives in the suite repo (../../../suite/_infra/_compose/) — the snippet here is illustrative.
Secrets management
- Local dev: hardcoded fallbacks in
Program.cs(the dev-secret values listed above). - Edge production: env vars sourced from a per-device
.envfile (created at provisioning) OR a local secrets manager (per-customer choice — the suite supports both patterns). TheJWT_SECRETis suite-wide (one value across all backend services on the device). - Rotation: changing
JWT_SECRETinvalidates every issued token until new ones are minted. Coordinated procedure across the device's backend services + UI re-login. There is no online rotation — every backend must be restarted with the new secret simultaneously.
Network / port layout
- Container
EXPOSE 8080; bound HTTP only (no TLS in this service). - Edge compose maps
5002:8080per the suite convention. - Reverse proxy (Caddy fronting the suite per
../../../suite/_docs/00_top_level_architecture.md) terminates TLS upstream. - No outbound network calls except to
postgres-local(DB).
Restart / lifecycle
- Container restart policy:
unless-stoppedin production compose (manually-stopped containers stay stopped; crash → auto-restart). - Watchtower polls the registry and triggers re-create on new image digest.
flight-gate(suite component) gates container restart so it does not happen mid-mission. Once the active mission completes, Watchtower's queued restart goes through.missionsitself does not implement graceful shutdown beyond ASP.NET Core's defaults — in-flight HTTP requests are allowed to complete; idle connections are closed.
Backup / disaster recovery
- Out of scope for this service. PostgreSQL backup is a per-device, suite-level concern (not per-service). Each edge device runs
postgres-local; backup cadence and offsite replication are decided at provisioning time and documented at suite level (currently informally). - No application-level export — the only way to read mission / waypoint data out of the device is through the API or
pg_dumpagainstpostgres-local.