Skip to content

[BREAKING] FEAT: Add fixed egress deployment for CoPyRIT - #2438

Merged
Bashir Partovi (bashirpartovi) merged 20 commits into
microsoft:mainfrom
bashirpartovi:feature/aca-internal-nat-baseline
Aug 28, 2026
Merged

[BREAKING] FEAT: Add fixed egress deployment for CoPyRIT#2438
Bashir Partovi (bashirpartovi) merged 20 commits into
microsoft:mainfrom
bashirpartovi:feature/aca-internal-nat-baseline

Conversation

@bashirpartovi

@bashirpartovi Bashir Partovi (bashirpartovi) commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Description

This PR replaces the former Azure Container Apps environment Private Endpoint and private DNS path with a supported workload-profiles ACA topology on a dedicated delegated subnet. A Standard NAT Gateway and static public IP provide fixed outbound egress independently of the inbound routing mode.

The Bicep template supports these inbound modes:

  • Community default: direct ACA-managed HTTPS ingress, with an optional source CIDR restriction.
  • Optional Azure Front Door Premium with the public ACA hostname as its HTTPS origin.
  • Optional Azure Front Door Premium with an AFD-managed Private Link origin. When ACA public access is also disabled, Front Door becomes the only public application path.

The Front Door and Private Link controls are opt-in and default to disabled for community deployments. Bicep rejects ACA public-access shutdown unless both Front Door and its Private Link origin are enabled. Front Door changes inbound routing only; ACA-originated outbound traffic continues to use the NAT Gateway's static public IP.

The Azure DevOps deployment workflow now:

  • builds and propagates an immutable image digest;
  • validates existing application and network resources before deployment;
  • runs a fail-closed ARM what-if validator that rejects malformed results, deletes, cross-resource-group writes, protected-topology changes, and unexpected core-resource creation;
  • preserves resource and policy-managed public-IP tags;
  • optionally applies a CanNotDelete lock to the static egress public IP and verifies its resource ID and address after deployment;
  • deploys the team-managed environments with Front Door Private Link and ACA public access disabled;
  • configures the Front Door origin response timeout to 240 seconds, matching the ACA HTTP ingress limit for long-running model responses;
  • discovers and approves only the expected ACA-side private connection through a dedicated Bicep module;
  • allows up to 30 minutes for Front Door propagation, then validates ACA-side approval, Front Door health, revision health, direct-origin shutdown, and unchanged fixed egress;
  • restores the public Front Door origin on cutover failure or cancellation, re-enables ACA public access only after private-connection deletion is confirmed, and otherwise fails closed for manual recovery;
  • keeps production opt-in, test-first, and independently approved.

The isolated-instance lifecycle scripts now validate Azure CLI JSON boundaries, restrict Azure SQL to the static egress IP, keep the private Storage container network-reachable for managed-identity and signed-browser media access, use ownership tags, and require explicit acknowledgement before teardown releases an allow-listed IP.

Breaking change: the existing enablePrivateEndpoint parameter and its ACA environment Private Endpoint and private DNS resources are removed, along with the previous Private Endpoint subnet parameters. ACA environment network type is creation-time configuration, so deployments using that path must migrate to a parallel VNet-integrated workload-profiles environment. Pipeline callers must adopt the deployment parameters documented in infra/README.md.

Tests and Documentation

  • python -m pytest tests/unit/infra -q - 27 tests and 7 subtests pass.
  • Compiled infra/main.bicep, infra/modules/aca_nat_network.bicep, infra/modules/aca_front_door.bicep, and infra/modules/aca_private_endpoint_approval.bicep with Azure CLI/Bicep.
  • Ran py_compile for both lifecycle scripts and the what-if validator.
  • Ran bash -n for the container startup and deployment scripts.
  • Validated both parameter JSON files, README Mermaid rendering, documented Bash fences, no-wrap Markdown formatting, and git diff --check.
  • Pylance/editor diagnostics are clean for the changed lifecycle, pipeline, test, and documentation files.
  • Updated infra/README.md and infra/DEPLOY_NEW_INSTANCE.md with the supported topology, ingress and egress behavior, migration boundary, pipeline contract, lifecycle safeguards, and teardown requirements.
  • JupyText was not run because this change does not modify notebooks.

Bashir Partovi added 3 commits August 19, 2026 23:46
Deploy the GUI on a VNet-integrated public Container Apps environment with static NAT egress and optional Azure Front Door.

Harden the Azure DevOps workflow around immutable image digests, fail-closed what-if validation, and preservation of the reserved public IP. Update isolated-instance lifecycle guidance and add focused infrastructure tests.
Apply the repository-pinned Ruff formatter, resolve typing-only imports and long fixture lines, and normalize file endings for the new infrastructure Python files.
Add the trailing newlines required by the cross-platform end-of-file pre-commit hook.
Comment thread docker/start.sh
Comment thread gui-deploy.yml
Comment thread tests/unit/infra/__init__.py
Comment thread infra/DEPLOY_NEW_INSTANCE.md
Comment thread infra/deploy_instance.py Outdated

@behnam-o Behnam (behnam-o) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

Generally, I would suggest not mixing "refactors" (cosmetic changes with little consequence e.g. updated comments, using effective*** instead of ***.properties.X, introducing env vars in inline scripts, changing reference ADO var groups, etc.) with the "actual feature" (which, here is, adding a AFD and wiring it up to the ACA) ... but I won't block on it :D

Bashir Partovi added 4 commits August 20, 2026 17:10
Add opt-in AFD Premium Private Link for ACA, disable direct ACA public access in the team deployment path, and automate connection approval, validation, and ordered rollback.

Preserve community defaults, protect the managed environment in what-if validation, and document the cutover lifecycle.
Approve ACA private endpoint connections through ARM instead of MSYS-sensitive resource-ID CLI calls, and use REST cleanup during rollback.

Allow the full observed Front Door propagation window, set explicit deployment-job timeouts, and cover the approval contract in tests.

@varunj-msft varunj-msft left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went through the changes and it looks really good!

Left a couple of notes on the rollback path, both look small.

Few minor things, none blocking: the FD health loop worst case looks closer to an hour than the 30 min in the README; az afd is warning it's moving to the cdn extension so might be worth pinning; and I couldn't spot $(prodApprovers) in the copyrit-gui-prod group yet, though the README does call it out.

Really nice work on this 😊

Comment thread infra/pipelines/deploy_public_nat.sh
Comment thread infra/pipelines/deploy_public_nat.sh
Comment thread tests/unit/infra/test_bicep_topology.py Outdated
Comment thread infra/deploy_instance.py Outdated
Comment thread infra/pipelines/deploy_public_nat.sh Outdated
Comment thread tests/unit/infra/test_bicep_topology.py Outdated

@hannahwestra25 hannahwestra25 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good! small nits

Comment thread .github/workflows/build_and_test.yml Outdated
Merged via the queue into microsoft:main with commit a7e2f61 Aug 28, 2026
48 checks passed
@bashirpartovi
Bashir Partovi (bashirpartovi) deleted the feature/aca-internal-nat-baseline branch August 28, 2026 18:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants