mirror of
https://github.com/azaion/missions.git
synced 2026-06-21 20:21:09 +00:00
refactor: enhance JWT authentication and CORS configuration
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.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# 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}-arm` and the container name is typically `flights`. 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:
|
||||
|
||||
1. `IConfiguration` (defaults: appsettings.json + ASPNETCORE_-prefixed env vars)
|
||||
2. `Environment.GetEnvironmentVariable(...)` (legacy fallback for unprefixed env)
|
||||
3. **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:
|
||||
|
||||
```yaml
|
||||
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 `.env` file (created at provisioning) OR a local secrets manager (per-customer choice — the suite supports both patterns). The `JWT_SECRET` is suite-wide (one value across all backend services on the device).
|
||||
- **Rotation**: changing `JWT_SECRET` invalidates 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:8080` per 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-stopped` in 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.
|
||||
- `missions` itself 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_dump` against `postgres-local`.
|
||||
Reference in New Issue
Block a user