TM Taeyang Moon
Demo · Architecture write-up

Governance-immune storage — Private Endpoint

Keep automation jobs alive even when governance locks public storage access

Private EndpointVNet-injected Container AppsPrivate DNSVNet PeeringManaged Identity (keyless)Coexist with governance
🔗
Live sitemoontaeyang.com
Open site →

This document treats "how to keep an automation job running even when a cloud governance policy auto-locks your storage" as a single Azure architecture case study, explaining which services were combined and why, from the perspective of an engineer who wants to rebuild it. (As of 2026-06-16 · Region: East US 2 · Target: the two digest agents behind moontaeyang.com)

🎯 What this demo shows: Many enterprise/regulated environments run a central governance automation that periodically enforces security baselines like "block public storage access (publicNetworkAccess=Disabled)" silently. Even if you turn it back on, it flips off again within minutes to a day. In such an environment, an automation job that relied on public access suddenly breaks one day. The fix is not to fight it but to route around it via a private path (Private Endpoint) — a design that coexists with the policy while keeping the job unbroken.


At a glance

Keywords: Private Endpoint · VNet-injected Container Apps · Private DNS · VNet Peering · Managed Identity (keyless) · coexisting with policy


Business view — why it matters


Architecture

  [Public users]                        ※ Unaffected even when storage public access (pna) is off
      │ HTTPS
      ▼
  Azure Static Web Apps  ──  moontaeyang.com  (engit-daily · azure-daily sections)
      ▲                                   SWA owns public serving
      │ swa deploy (outbound)
      │
  ┌─────────────────────────── rg-english-daily ───────────────────────────┐
  │  VNet 10.60.0.0/16                                                       │
  │   ├ snet-aca /23 (delegation: Microsoft.App/environments)                │
  │   │    └ Container Apps Env (VNet-injected, workload profile)            │
  │   │         └ engitdaily-job ── UAMI (keyless) ─┐                         │
  │   └ snet-pe /24                                  │ blob R/W               │
  │        └ Private Endpoint(blob) 10.60.2.4 ◀──────┘                        │
  │             │ private path                                               │
  │             ▼                                                            │
  │        Storage engitdailyst…  (PE passes even when pna=Disabled)         │
  │   Private DNS: privatelink.blob.core.windows.net                        │
  │        engitdailyst… → 10.60.2.4   (+ azwhatsnewst… → 10.61.2.4 x-reg)   │
  └──────────────────────────────┬──────────────────────────────────────────┘
                                  │  VNet Peering (bidirectional, Connected)
  ┌──────────────────────────────┴──── rg-azwhatsnew ───────────────────────┐
  │  VNet 10.61.0.0/16  (snet-aca /23, snet-pe /24)                          │
  │    Container Apps Env (VNet-injected) └ azwhatsnew-job ─ UAMI ─ PE 10.61.2.4 │
  │    Storage azwhatsnewst…   ·   Private DNS (same, engit record x-registered) │
  └─────────────────────────────────────────────────────────────────────────┘

  Governance (MCAPSGov-AutomationApp): periodically forces both storages' pna to Disabled → jobs still work via PE

Components and design decisions

1) Make the Container Apps env "VNet-injected" — why recreation is unavoidable

2) Storage Private Endpoint (blob) + Private DNS

3) Cross-dependency — the most important lesson of this demo

4) SWA decouples public serving — lock the warehouse, visitors unaffected


Verification (actually locked it and ran)

With both storages locked (publicNetworkAccess=Disabled + defaultAction=Deny), both jobs ran:

Check Result
engit job / azwn job both Succeeded
own blob write Blob upload complete …
cross-mirror (read peer warehouse) mirrored engit-daily:4 / azure-daily:8 ✅ (via PE)
auth errors 0
live sites moontaeyang.com /·/engit-daily/·/azure-daily/ all 200
notification Telegram 200

→ Empirically confirmed: automation keeps running even in the steady-state where the policy has locked public access.


Cost / trade-offs

Item Value
Private Endpoint 2 ≈ $15/mo + small data processing
Private DNS / VNet / Peering effectively free (same-region peering, tiny queries)
Env recreation one-time effort (downtime is short, between cron runs)

Build-it-yourself checklist

  1. Separate storage used for the data plane (job R/W) vs public serving (serve via SWA/CDN).
  2. Put the job in a VNet-injected Container Apps env (existing env needs recreation; job environmentId is immutable).
  3. Reuse a UAMI for keyless + minimal role re-granting.
  4. Add a PE (blob) + privatelink.blob.core.windows.net Private DNS to the storage.
  5. If multiple jobs read each other's storageVNet Peering + cross-register every storage's A record into each zone.
  6. Make the deploy script's data-plane calls (--static-website, etc.) tolerant of pna=Disabled.
  7. Actually lock it (--public-network-access Disabled) and run the job to verify the steady-state.

Reference code / locations

← All demosPortal home