Skip to content

fix(infra): route /login/* through CloudFront to the ALB for Entra login#351

Merged
danielbowne merged 1 commit into
mainfrom
fix/cloudfront-login-entra-routing
Jun 18, 2026
Merged

fix(infra): route /login/* through CloudFront to the ALB for Entra login#351
danielbowne merged 1 commit into
mainfrom
fix/cloudfront-login-entra-routing

Conversation

@danielbowne

Copy link
Copy Markdown
Collaborator

Fixes the Entra login path being unreachable from the public CloudFront URL.

Problem

CloudFront routes only the exact path /login to the ALB origin (cloudfront.tf); there is no /login/* behavior. So /login/entra does not match, falls through to the S3 default origin, and S3 returns an AccessDenied XML page. Entra login is unreachable for everyone, not specific to any user or email. Okta is unaffected because it lives at exactly /login.

The dual-IdP work added the /login/entra* rule on the ALB but never added the matching CloudFront behavior. The two layers are owned separately (the CloudFront login behavior was set up under #166 as an exact match), and the end-to-end "user lands at /login/entra" check was deferred to runtime, so the gap only surfaced once dev was flipped to entra_enabled = true and Entra login was first exercised.

Fix

Add a /login/* ordered cache behavior pointing at the ztmf_api (ALB) origin, mirroring the existing /login behavior (same forwarding, no caching). It is gated with dynamic ... for_each = var.entra_enabled ? [1] : [] so it exists only when Entra is enabled, matching the per-IdP ALB listener rules that are created under the same flag. The exact /login behavior is left untouched, so Okta keeps working exactly as before.

On dev (entra_enabled = true) this creates the behavior and /login/entra reaches the ALB. On prod (entra_enabled = false) nothing changes.

Validation

  • terraform fmt clean, terraform validate passes, tflint clean.
  • After this applies to dev: /login/entra routes to the ALB (Entra OIDC) instead of returning S3 AccessDenied; /login (Okta) unchanged.

Refs #264

The Entra login path /login/entra is unreachable from the public CloudFront
URL: the only login behavior is an exact /login, so /login/entra falls through
to the S3 default origin and returns an S3 AccessDenied. The /login/entra* ALB
rule from the dual-IdP work was added without the matching CloudFront behavior.

Add a /login/* ordered_cache_behavior to the ztmf_api (ALB) origin, gated on
entra_enabled to mirror the per-IdP ALB rules. Okta keeps using the exact
/login behavior, unaffected.

Refs #264
@danielbowne danielbowne added area/infra Terraform, AWS resources, networking, IAM hhs For HHS ZT work labels Jun 17, 2026
@danielbowne danielbowne self-assigned this Jun 17, 2026
@a-dipietro a-dipietro self-requested a review June 18, 2026 14:47

@a-dipietro a-dipietro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verify listener rules are UTD, otherwise g2g!

@danielbowne danielbowne merged commit 39e9353 into main Jun 18, 2026
8 checks passed
@danielbowne danielbowne deleted the fix/cloudfront-login-entra-routing branch June 18, 2026 14:54
danielbowne added a commit that referenced this pull request Jun 23, 2026
#351) (#361)

## Summary

Routine refresh of the `impl` branch from `main` so the experimental
environment does not drift from production code. Merge (not rebase), per
the impl-sync policy, because `impl` is a shared, deployed branch.

## What main brought in

The bulk of main's recent history (OpDiv-scoped RBAC, dual-IdP
scaffolding, pgxpool, OpenAPI autogeneration, the N+1 users-list fix)
was already present on impl from the previous sync, so the net new
content here is small:

- Scores diff endpoint to compare two data calls (#356)
- Okta JWT `kid` validation and hardened key-fetch client (#354)
- Route `/login/*` through CloudFront to the ALB for Entra login (#351)
- The enrichment OpDiv gate as it landed on main (#359), reconciled with
impl's own copy (#358)

## Conflict resolution

- **Makefile** - kept impl's per-environment port scaffolding
(`ZTMF_ENV` detection, parametrized `TEST_DB_PORT`). Reverting to main's
hardcoded ports would break side-by-side worktree runs.
- **fismasystems.go / scores.go / openapi.yaml** - took main's canonical
versions (main's `FindFismaSystemByUUID` adds an explicit `LIMIT 1`;
scores-diff is additive). OpenAPI regenerated from annotations
afterward, no drift.

## Environment safety

- Entra remains dormant on impl: there is no impl tfvars override, so
`entra_enabled` stays at its default of false. Main's #350 only enabled
it in dev.
- No new migrations introduced by this sync beyond what is already
merged on main.

## Testing

Full local suite on the impl port set (unit, integration,
E2E/Emberfall).

---------

Co-authored-by: cameron testerman <11036339+voidspooks@users.noreply.github.com>
Co-authored-by: MackOverflow <114018913+MackOverflow@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/infra Terraform, AWS resources, networking, IAM hhs For HHS ZT work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants