Local Storage auto-open default-off hardening¶
Motivation¶
During post-deployment validation, the live Azure Storage account was observed in publicNetworkAccess=Enabled and defaultAction=Allow. Azure Activity Log and local API logs correlated the write with a local /api/blast/databases request: local-run.sh had silently defaulted LOCAL_DEBUG_AUTO_OPEN_STORAGE to true even though the service gate and operator documentation described it as default-OFF.
The account was immediately restored to publicNetworkAccess=Disabled and defaultAction=Deny; all three private endpoints remained approved and /api/health/ready continued to report Storage healthy.
User-facing change¶
Ordinary scripts/dev/local-run.sh start|api and VS Code API debug launches no longer opt into Storage auto-open. Developers must explicitly set LOCAL_DEBUG_AUTO_OPEN_STORAGE=true or use the existing storage-on / auth-on workflows. Every explicit open is restricted to one detected caller IPv4 with defaultAction=Deny and bypass=None; caller-IP discovery failure leaves the account closed. Local authentication behavior, Azure RBAC, browser streaming, and the deployed CONTAINER_APP_NAME refusal guard are unchanged.
API and infrastructure diff¶
- Changed the local launcher fallback for
LOCAL_DEBUG_AUTO_OPEN_STORAGEfromtruetofalse. - Removed the VS Code launch profile's hard-coded
true, allowing the service's default-OFF contract or an explicit debug environment override to apply. - Replaced the stale
defaultAction=Allow/bypass=AzureServicesworkaround in both local-debug helpers with one caller IPv4 rule underdefaultAction=Deny/bypass=None. - Ordered the shell transition as close-first, rule replacement, then enable-last; its close path disables access before removing rules and verifies the final production posture.
- Added a fail-closed same-region Azure topology check. Azure Storage IP rules do not apply to same-region Azure clients, so the API, shell helper, and Storage card now direct those developers to the deployed private-endpoint path without performing an ARM write.
- Added a source-contract regression test for both local launch entry points.
- No API schema, Service Bus wire contract, Azure role assignment, Bicep resource, or deployed Container App setting changed.
Validation¶
uv run pytest -q api/tests/test_storage_public_access.pybash -n scripts/dev/storage-public-access.sh scripts/dev/local-run.shuv run pytest -q api/tests/test_persona_matrix.pyuv run ruff check api/tests/test_storage_public_access.py- Live ARM state:
publicNetworkAccess=Disabled,defaultAction=Deny, zero IP rules, three approved private endpoints. - Live readiness:
/api/health/readyreturned HTTP 200 withazure_storage.status=okafter closure. - Live topology probe: the developer host and Storage account were both in Korea Central; a selected-network request returned the documented 403, and cleanup restored
Disabled/Deny/Nonewith zero IP rules.