Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
fed0be0
Add POC: Security and OAuth 2.0 Configuration
MarvelintheCloud May 21, 2026
cb42737
Fix Mermaid syntax in OAuth POC full-flow diagram, added jwt validati…
MarvelintheCloud May 21, 2026
bd708e8
Add APIM policy test steps for OAuth configuration POC
MarvelintheCloud May 21, 2026
d3a380a
Added instructions for creating app registrations
MarvelintheCloud May 21, 2026
4c1b2b1
Split security OAuth POC into ACA and APIM focused docs
MarvelintheCloud May 22, 2026
b65e82e
Expand APIM security POC with MI setup, issuer guidance, and operatio…
MarvelintheCloud May 22, 2026
f6aac7b
Merge pull request #164 from microsoft/docs/poc-security-oauth
nagendramishr May 22, 2026
8ef52e2
merge in olivias changes, reduce cognitive load
nagendramishr May 22, 2026
a91e1e5
merge the verification steps
nagendramishr May 22, 2026
caad793
docs: update secure proxy EasyAuth and token flow
MarvelintheCloud May 23, 2026
2cb7842
docs: harden secure proxy auth guidance
MarvelintheCloud May 24, 2026
f7a1a34
docs: improve APIM JWT test guidance
MarvelintheCloud May 25, 2026
d018b7d
Merge pull request #167 from MarvelintheCloud/docs/poc-secure-proxy-r…
nagendramishr May 26, 2026
e847c81
cleanup docs
nagendramishr May 26, 2026
7023101
simplify with a script
nagendramishr May 27, 2026
017fa09
update docs for the new validation scenarios
nagendramishr May 27, 2026
eca5c14
update for new key based validation mode
nagendramishr May 27, 2026
a4355be
update docs, update version
nagendramishr May 27, 2026
824d3c2
Merge pull request #168 from microsoft/feature/async
nagendramishr May 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,71 @@ If the file doesn't exist, create it and document any important lessons learned
- When a change requires modifications outside the immediate scope of what was requested, ask first.
- When the user says "undo", revert ALL changes from the last action, not just some.


## definition of a gold standard document:
- A POC doc is complete when: A new user can run it in <5 minutes , Behavior is visible and verifiable, No section requires rereading to understand
- The reader can explain:what happened, why it happened, how to reproduce it

## when writing POCs'
POC docs must prioritize runnable usability over completeness; use direct engineer-to-engineer tone; no marketing language; always include TLDR with <5 min steps and expected outcome; include “what you will observe” as pure behavior bullets; separate sections strictly into setup (minimal prereqs), run (exact commands), verify (checklist mapping signals→meaning), deep dive (step-by-step execution flow), optional variants, and troubleshooting; prefer bullets over prose; avoid repetition and narrative phrasing; every config section must start with “what matters” and highlight only critical knobs (timeout, retry, backend behavior); always define observable signals (headers/logs/state changes) and map them explicitly; include execution cycles (cycle 1 fail, cycle 2 retry, final result); include mental model as simple state machine (select→fail→throttle→retry→recover); include minimal flow diagram (client→proxy→backend A fail→backend B success); verification must be checklist not table; troubleshooting must map symptom→cause→check; all claims must be reproducible and observable; avoid vague phrasing; front-load value in first 30%; reader must be able to run, see, and explain behavior without reading entire document

## When generating a Reference Document, enforce the following rules:
1. Purpose:
- Produce the authoritative, canonical, single source of truth for the topic.
- Output must be complete, deterministic, and audit‑ready.
2. Language Rules:
- Use mandatory language: MUST, REQUIRED, MANDATORY, SHALL.
- Avoid ambiguity: do not use should, could, might, typically, generally.
- Use exact values, configurations, constraints, and specifications.
- No conversational tone. No filler. No speculation.
3. Required Document Structure (always in this order):
A. Document Metadata (Title, Version, Last Updated, Owner, Review Cycle, Compliance Tags)
B. Summary (what this defines, why it exists, who must follow it)
C. Scope & Applicability (in-scope, out-of-scope, dependencies)
D. Authoritative Specification (architecture, configurations, patterns, constraints, SLAs/SLOs, security requirements)
E. Reference Implementation (canonical diagrams, workflows, configuration blocks, API contracts)
F. Validation & Compliance (required tests, checks, evidence, audit artifacts)
G. Version History (changes, rationale, approvers)
4. Behavioral Rules:
- Never invent facts. Request missing parameters before finalizing.
- Ensure internal consistency across all sections.
- All examples must be canonical, valid, and copy‑paste‑ready.
- All diagrams, tables, and configs must be deterministic and aligned with the specification.
- No placeholders unless explicitly allowed by the user.
- No contradictions across sections.
5. Output Requirements:
- Produce a fully structured, complete document.
- Enforce strict formatting and section order.
- Ensure the document is suitable for governance, compliance, and long‑term reference.

## When generating an Overview Document, enforce the following rules:
1. Purpose:
- Provide a high‑clarity, high‑signal summary of a system, solution, or domain.
- Communicate essential concepts, architecture, flows, and rationale without deep implementation detail.
- Serve as the onboarding and orientation artifact for new readers.
2. Language Rules:
- Use concise, precise, high‑signal language.
- Avoid ambiguity, filler, marketing language, or conversational tone.
- Use factual, neutral, technically accurate statements.
- Avoid mandatory language unless describing non‑negotiable constraints.
3. Required Document Structure (always in this order):
A. Document Metadata (Title, Version, Last Updated, Owner)
B. Overview Summary (what the system is, what problem it solves, why it exists)
C. Key Objectives (primary goals, outcomes, and value)
D. High‑Level Architecture (major components, interactions, boundaries)
E. Core Concepts (definitions, domain terms, key abstractions)
F. High‑Level Workflows (end‑to‑end flows, sequence summaries)
G. Key Constraints & Assumptions (technical, operational, business)
H. Integration Points (external systems, APIs, dependencies)
I. Non‑Goals (what is intentionally excluded)
J. Future Considerations (roadmap‑level items only)
4. Behavioral Rules:
- Never invent facts. Request missing parameters before finalizing.
- Ensure internal consistency across all sections.
- Keep all diagrams and workflows high‑level; no implementation detail.
- Do not include configuration, SLAs, or compliance details unless explicitly requested.
- No placeholders unless explicitly allowed by the user.
5. Output Requirements:
- Produce a complete, structured overview document.
- Maintain strict section order and formatting.
- Ensure the document is suitable for onboarding, orientation, and executive‑level understanding.
2 changes: 2 additions & 0 deletions ReleaseNotes/version2.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

Proxy:
* Add status checker
* Add ability to validate requests via api-key
* Add ability to call backend via api-key

RequestAPI:
* Add status checker
Expand Down
194 changes: 194 additions & 0 deletions deployment/POC/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
### Step 1 — Set Variables

Set `APP_NAME`, `CONTAINER_APP_NAME`, `RG` to match your environment.

```bash
export ENTRA_APP_NAME="aca-proxy" # Display name for the Entra app registration
export CONTAINER_APP_NAME="<your-app-name>" # Container App name
export RG="<your-resource-group>" # Container App resource group
```

> [!NOTE]
> In Windows/WSL environments, sanitize `-o tsv` outputs with `tr -d '\r\n'` before reusing values in later CLI calls.

### Step 2 — Create the Entra App Registration and enable EasyAuth

Save the generated `APP_ID` and `CLIENT_SECRET` variables for troubleshooting.

```bash

# Lookup tenant and app fqdn
export TENANT_ID="$(az account show --query tenantId -o tsv | tr -d '\r\n')"
export APP_FQDN="https://$(az containerapp show --name "$CONTAINER_APP_NAME" --resource-group "$RG" --query properties.configuration.ingress.fqdn -o tsv | tr -d '\r\n')"
export HEALTH_URL="$APP_FQDN/health"

export APP_ID=$(az ad app create \
--display-name "$ENTRA_APP_NAME" \
--sign-in-audience AzureADMyOrg \
--query appId -o tsv | tr -d '\r\n')
echo "APP_ID=$APP_ID"

# Required so az token requests to api://$APP_ID can resolve the resource principal.
az ad app update --id "$APP_ID" --identifier-uris "api://$APP_ID"

# Create service principal
az ad sp create --id "$APP_ID" 1>/dev/null

# Create delegated scope
if [ -z "$APP_ID" ]; then
echo "APP_ID is empty. Re-run Step 2 app creation or app lookup first."
exit 1
fi

SCOPE_ID="$(uuidgen | tr '[:upper:]' '[:lower:]')"
API_OBJ="$(az ad app show --id "$APP_ID" --query api -o json)"
UPDATED_API_OBJ="$(echo "$API_OBJ" | jq --arg id "$SCOPE_ID" '.oauth2PermissionScopes = [{
adminConsentDescription: "Access the API",
adminConsentDisplayName: "Admin Access",
id: $id,
isEnabled: true,
type: "Admin",
userConsentDescription: "Access the API",
userConsentDisplayName: "User Access",
value: "api.access"
}]')"
az ad app update --id "$APP_ID" --set api="$UPDATED_API_OBJ"

# Enable ID token issuance
az ad app update --id "$APP_ID" --enable-id-token-issuance true

# Create client secret
export CLIENT_SECRET=$(az ad app credential reset \
--id "$APP_ID" \
--display-name "proxy-auth-secret" \
--end-date "$(date -d '+30 days' '+%Y-%m-%d')" \
--query password -o tsv | tr -d '\r\n')

# Do not print or commit secret values. Keep them in memory only.


# Enable EazyAuth
az containerapp auth microsoft update \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RG" \
--client-id "$APP_ID" \
--client-secret "$CLIENT_SECRET" \
--tenant-id "$TENANT_ID" \
--yes

# Verify identifier URI is set correctly.
az ad app show --id "$APP_ID" --query "{appId:appId,identifierUris:identifierUris,scopes:api.oauth2PermissionScopes[].value}" -o table

# Optional hygiene: clear secret from shell after auth configuration is complete.
# unset CLIENT_SECRET
```

> [!WARNING]
> You may need to grant admin consent in the Azure portal before token acquisition works.
> If `az account get-access-token --resource "api://$APP_ID"` returns `AADSTS65001` (`consent_required`), ask a tenant admin to grant consent for your client app/API scope in Entra ID:
> **App registrations** -> your client app -> **API permissions** -> **Grant admin consent**.
>
> For better secret hygiene, avoid sharing terminal output that includes auth commands and never paste secret values into tickets, PR comments, or chat logs.

### Step 3 — Verify Container App

Run these checks to ensure auth is enabled and the Microsoft identity provider is registered.

```bash
ENABLED="$(az containerapp auth show \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RG" \
--query "platform.enabled" -o tsv | tr -d '\r\n')"

AAD_CLIENT_ID="$(az containerapp auth show \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RG" \
--query "identityProviders.azureActiveDirectory.registration.clientId" -o tsv | tr -d '\r\n')"

AUDIENCE="$(az containerapp auth show \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RG" \
--query "identityProviders.azureActiveDirectory.validation.allowedAudiences[0]" -o tsv | tr -d '\r\n')"

echo "enabled=$ENABLED"
echo "aad_client_id=$AAD_CLIENT_ID"
echo "allowed_audience=$AUDIENCE"
```

Expected:

- enabled=true
- aad_client_id=<guid>
- allowed_audience=api://<same-guid-or-intended-api-uri>

If `aad_client_id` or `allowed_audience` is empty, or `enabled` is not `true`, re-run the auth microsoft update command above and do not continue to Step 4.

### Step 4 — Set the Unauthenticated Action

Rejects unauthenticated requests outright — callers get a `401` with no redirect.

```bash
az containerapp auth update \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RG" \
--enabled true \
--unauthenticated-client-action Return401
```

### Step 5 — Align Allowed Audiences with v2.0 Tokens

The default Microsoft provider configuration registers `api://<APP_ID>` as the allowed audience. Entra v2.0 access tokens (issued by `https://login.microsoftonline.com/<tenant>/v2.0`) carry the **bare GUID** in their `aud` claim — not the `api://` form. Without this step, valid tokens are rejected with `403`.

Replace the allowed audience with the bare GUID:

```bash
az containerapp auth microsoft update \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RG" \
--allowed-audiences "$APP_ID"
```

Verify:

```bash
az containerapp auth show \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RG" \
--query "identityProviders.azureActiveDirectory.validation.allowedAudiences"
```

Expected output:

```json
[
"<APP_ID>"
]
```

> [!NOTE]
> `--allowed-audiences` **replaces** the existing list and only accepts one value per invocation. If you also need to accept v1-style `api://<APP_ID>` audiences (for legacy callers), patch the list directly via `az containerapp auth update --set identityProviders.azureActiveDirectory.validation.allowedAudiences=...` with a JSON array, taking care with shell quoting.

### Step 6 — Restrict to Trusted Client Applications

Even with a valid token, EasyAuth's `defaultAuthorizationPolicy.allowedApplications` decides which client apps may call the proxy. An empty list combined with EasyAuth's MISE evaluation results in `403` with `"this principal does not match any of the allowed applications"`.

For this POC we explicitly trust the Microsoft Azure CLI client (`04b07795-8ddb-461a-bbee-02f9e1bf7b46`) so you can verify with `az account get-access-token`. In production, replace this with the client app IDs of the real callers (your console SP, APIM, another service, etc.).

```bash
az containerapp auth update \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RG" \
--set identityProviders.azureActiveDirectory.validation.defaultAuthorizationPolicy.allowedApplications='["04b07795-8ddb-461a-bbee-02f9e1bf7b46"]'
```

Verify:

```bash
az containerapp auth show \
--name "$CONTAINER_APP_NAME" \
--resource-group "$RG" \
--query "identityProviders.azureActiveDirectory.validation.defaultAuthorizationPolicy.allowedApplications"
```

> [!NOTE]
> EasyAuth caches authorization decisions per principal for roughly 60 seconds. After changing `allowedApplications` or `allowedAudiences`, wait a minute (or acquire a fresh token) before re-testing — otherwise you'll see a cached deny.
Loading