Keyless Auth Hardening
The blocked security-hardening wave: disable storage shared-key access, blob public access, and Search/Event Grid local auth, and set storage network default-deny. Every switch is held open by an app code path using key-based auth — this proposal is the app-side migration that unblocks them.
Scope
Today: Azure Functions already use DefaultAzureCredential with least-privilege roles; the Railway-hosted app authenticates to Storage/Search/Event Grid/Service Bus with keys and connection strings (apps/infra/docs/azure/security-constraints.md maps each blocker).
This adds, per service, in order:
- Inventory — enumerate every key-based client construction in
apps/web/server+packages/dbagainst the constraints doc. - Credential path — Railway has no Azure managed identity, so the app uses a service principal (client id/secret via env) with the same least-privilege role assignments pattern already proven for Functions; SAS issuance moves to user-delegation SAS where storage keys are disabled.
- Flip the switches in Pulumi one service at a time (Search local auth → Event Grid local auth → storage shared-key → blob public access → network default-deny), smoke-testing the affected feature between each.
Key files
| File | Change |
|---|---|
packages/db/src/ + apps/web/server/composables/azure/ | credential-based client construction |
apps/infra/src/azure/ | role assignments + auth switches |
apps/infra/docs/azure/security-constraints.md | tick off each unblocked constraint |
Notes
User-delegation SAS is the hard part — message-attachment and survey uploads depend on SAS (file uploads); verify expiry limits (user-delegation keys cap at 7 days) fit the upload flow before flipping shared-key off. Every SAS now fits: resource asset reads sign a minutes-scale SAS per request through /api/resource-assets, message-attachment reads default to a day, and upload SAS urls are hour-scale — nothing signs past the 7-day cap.
Sources
- Azure Storage — prevent authorization with Shared Key —
allowSharedKeyAccess, and a user delegation SAS as the one SAS still permitted once it is false. - Azure Storage — create a user delegation SAS — the SAS the upload and read urls move to.
- Azure AI Search — enable role-based access control —
disableLocalAuthand the data-plane roles that replace the admin key. - Event Grid — authenticate publishing clients with Microsoft Entra ID — a service principal through
DefaultAzureCredential's environment variables, the EventGrid Data Sender role, anddisableLocalAuth.