Entra ID Federation — SAML/SCIM Seam (L1)
Scope: TI-2e — L1 federation only (Entra ID ↔ IAM Identity Center). Keycloak (L2) is a separate federation layer documented elsewhere. Pre-requisite: complete
identity-center-enablement.mdx(TI-2a) first. ADR-020 rationale for L1/L2 non-conflation is cross-referenced below.
Section 1 — Understand the Entra Seam in modules/sso
As the HITL operator, I want to understand how modules/sso v1.3.0 exposes the Entra
federation seam so that I know exactly which Terraform variables to set when wiring SCIM-
provisioned users and groups from Entra ID.
The two seam variables
modules/sso exposes two variables specifically for external IdP scenarios:
existing_sso_users (variables.tf lines 71–78):
variable "existing_sso_users" {
description = "Names of the existing users that you wish to reference from IAM Identity Center."
type = map(object({
user_name = string
group_membership = optional(list(string), null)
# group_membership: only used if your IdP syncs users only (not groups);
# set this to add SCIM-provisioned users to Terraform-managed groups.
}))
default = {}
}
Use this variable to reference Entra-provisioned users in account assignments without managing their lifecycle inside Terraform. Entra SCIM creates and updates the users; Terraform assigns them to groups and permission sets.
principal_idp in account_assignments (variables.tf line 117):
variable "account_assignments" {
type = map(object({
principal_idp = string # "INTERNAL" or "EXTERNAL"
...
}))
}
Set principal_idp = "EXTERNAL" for any assignment whose principal (user or group) originates
from Entra ID (or any external IdP). Set principal_idp = "INTERNAL" for principals managed
natively inside Identity Center.
Step 1.1 — READONLY verify: confirm the seam exists in the live module
# READONLY verify
grep -n 'existing_sso_users\|principal_idp' \
terraform-aws/modules/sso/variables.tf
# Expected output includes:
# 71: variable "existing_sso_users" {
# 117: principal_idp = string # "INTERNAL" or "EXTERNAL"
Branch on result:
- If both lines are found → seam is live in the working tree; continue to Section 2.
- If either line is missing → check
modules/ssoversion; the seam was introduced in v1.2.0 and is present in v1.3.0 (current).
5W1H — Entra Seam in modules/sso
| Question | Answer |
|---|---|
| Why | Entra SCIM creates users and groups in Identity Center's identity store; Terraform must reference those objects without owning their lifecycle — existing_sso_users is the pointer, not the creator. |
| What if missing | Terraform attempts to manage user lifecycle and conflicts with SCIM provisioning; the result is a state-drift loop where Terraform destroys SCIM-created users on every apply. |
| Business value | Entra-managed users get automatic provisioning and deprovisioning; offboarding removes access across all AWS accounts in seconds without Terraform changes. |
| Purpose | Separates the two concerns: Entra owns identity lifecycle (create/update/delete); Terraform owns access policy (which groups get which permission sets on which accounts). |
| Critical thinking | ADR-020 mandates L1/L2 non-conflation: Entra federation (L1) and Keycloak federation (L2) must not share the same Identity Center identity source. If both are needed, L1 (Entra) is the direct IdP to Identity Center; Keycloak sits behind a separate boundary. Do not configure Keycloak as the Identity Center IdP when Entra is the org-wide SSO provider. |
Section 2 — Configure SAML in Entra and Identity Center
As the HITL operator, I want to set up the SAML trust between Entra ID and IAM Identity Center so that OceanSoft engineers can authenticate to AWS using their Entra credentials.
Step 2.1 — READONLY verify: no existing external IdP is configured
# READONLY verify
aws sso-admin describe-managed-policy-in-permission-set \
--instance-arn arn:aws:sso:::instance/<YOUR_INSTANCE_ID> \
--permission-set-arn <ANY_PERMISSION_SET_ARN> \
--managed-policy-arn arn:aws:iam::aws:policy/AdministratorAccess \
--region <HOME_REGION> \
--profile sso 2>&1 | head -5
# This is a connectivity check only — not the IdP query.
# Navigate to Identity Center console → Settings → Identity source to confirm source type.
Branch on result:
- If Identity source shows Identity Center directory → no IdP configured; continue.
- If Identity source shows External identity provider and it is already Entra → verify the SAML metadata is current; skip to Step 2.4.
- If Identity source shows Active Directory → a different federation path is in use; consult your AD team before changing the source.
Step 2.2 — Create the Entra Enterprise Application [HITL]
- Sign in to the Microsoft Entra admin centre as a Global Administrator or Cloud Application Administrator.
- Navigate to Enterprise applications → New application.
- Search for
AWS IAM Identity Centerand select the gallery app. - Click Create.
- In the app overview, go to Single sign-on → SAML.
- In the SAML Signing Certificates section, download Federation Metadata XML
and save as
entra-metadata.xmllocally.
Step 2.3 — Change the Identity Center identity source [HITL]
- In IAM Identity Center console → Settings → Identity source tab.
- Click Actions → Change identity source.
- Select External identity provider.
- In Service provider metadata, copy:
- IAM Identity Center Assertion Consumer Service (ACS) URL
- IAM Identity Center issuer URL
- In Identity provider metadata, upload
entra-metadata.xmlfrom Step 2.2. - Type
ACCEPTto confirm the change and click Change identity source.
Changing from Identity Center directory to an external IdP deprovisions all local users immediately. Ensure the Entra SCIM provisioning is configured (Section 3) before this step, or you will lose access to the console. Always have a break-glass IAM user in the management account as a fallback.
Step 2.4 — Complete the Entra SAML configuration [HITL]
- Return to the Entra Enterprise application → Single sign-on → SAML.
- In Basic SAML Configuration:
- Identifier (Entity ID): paste the IAM Identity Center issuer URL from Step 2.3.
- Reply URL (ACS URL): paste the ACS URL from Step 2.3.
- Leave Sign on URL and Relay State empty.
- Click Save.
Post-config verify:
- In Entra, assign a test user to the Enterprise application (Entra admin portal → Users and groups → Add user/group).
- Open the AWS access portal URL (
https://d-<YOUR_OWN_ID>.awsapps.com/start) in an incognito window. - You should be redirected to the Entra login page. After login, the AWS accounts portal should load.
5W1H — SAML Configuration
| Question | Answer |
|---|---|
| Why | SAML is the authentication layer; it proves the user's identity to Identity Center using a signed assertion from Entra; without it every sign-in attempt redirects to an error page. |
| What if missing | Engineers cannot authenticate via Entra; the AWS access portal shows an authentication error; SCIM provisioning works but nobody can log in. |
| Business value | Single sign-on across Office 365 and AWS: engineers use one password and one MFA token for both; onboarding/offboarding is a single Entra action with immediate AWS effect. |
| Purpose | Establishes the cryptographic trust between Entra (the IdP) and Identity Center (the service provider) so that signed SAML assertions are accepted. |
| Critical thinking | The ACS URL and issuer URL are unique per Identity Center instance; if you re-enable Identity Center or change regions, they change and the Entra application must be updated. Always re-download service provider metadata after any Identity Center instance recreation. |
Section 3 — Configure SCIM Provisioning
As the HITL operator, I want to enable SCIM so that Entra automatically provisions and
deprovisions users and groups in Identity Center — enabling the existing_sso_users seam in
Terraform to reference Entra-managed users without managing their lifecycle.
Step 3.1 — Enable automatic provisioning in Identity Center [HITL]
- In IAM Identity Center console → Settings → Provisioning tab.
- Click Enable in the Inbound automatic provisioning section.
- Copy:
- SCIM endpoint (form:
https://scim.<HOME_REGION>.amazonaws.com/<INSTANCE_ID>/scim/v2) - Access token (shown once; save it securely)
- SCIM endpoint (form:
Step 3.2 — Configure provisioning in the Entra app [HITL]
- In the Entra Enterprise application → Provisioning → Get started.
- Set Provisioning Mode to Automatic.
- In Admin Credentials:
- Tenant URL: paste the SCIM endpoint from Step 3.1.
- Secret Token: paste the Access token from Step 3.1.
- Click Test Connection. Expect: "The supplied credentials are authorized to enable provisioning."
- Click Save.
- Under Provisioning → Mappings → Provision Entra ID Groups → confirm Enabled.
- Under Mappings → Provision Entra ID Users → confirm Enabled.
- Under Settings, set Provisioning Status to On.
- Click Save.
Step 3.3 — Verify SCIM is delivering users to Identity Center
# READONLY verify — check that at least one SCIM-provisioned user exists
aws identitystore list-users \
--identity-store-id <YOUR_IDENTITY_STORE_ID> \
--region <HOME_REGION> \
--profile sso \
--query 'Users[*].{UserName:UserName,UserId:UserId}'
# Expected: one or more users provisioned by Entra (after first sync completes ~5-10 min)
Branch on result:
- If users appear → SCIM is working; continue to Section 4.
- If no users after 10 minutes → check Entra provisioning logs (Entra admin → Provisioning logs) for errors; common causes: group assignment missing in Entra, attribute mapping mismatch, access token expired.
5W1H — SCIM Provisioning
| Question | Answer |
|---|---|
| Why | SAML handles authentication (login) but not provisioning (creating accounts); without SCIM, every new engineer must be manually added to Identity Center before they can log in — that is the manual-provisioning anti-pattern that Entra solves. |
| What if missing | Users authenticate via Entra SAML but Identity Center has no user record for them; the portal shows "user not found"; Terraform existing_sso_users has no targets to reference. |
| Business value | Zero-touch provisioning: a new hire added to the Entra group for PowerUsers gets AWS access within minutes; a leavers' Entra account deactivation cascades to all AWS accounts automatically. |
| Purpose | Creates the live user records in Identity Center's identity store that existing_sso_users in config/account_assignments.yaml will reference for account assignments. |
| Critical thinking | SCIM syncs users and groups but does NOT assign permission sets; that is Terraform's job via account_assignments. The SCIM-created group names in Identity Center must match the principal_name values in config/account_assignments.yaml exactly — case-sensitive. |
Section 4 — Wire Terraform to Reference Entra Users
As the HITL operator, I want to know the exact YAML and Terraform patterns for referencing
Entra-provisioned users in account assignments so that I can extend config/account_assignments.yaml
without managing user lifecycle in Terraform.
Step 4.1 — READONLY verify: list the SCIM-provisioned group names
# READONLY verify — get exact group names as they appear in Identity Center
aws identitystore list-groups \
--identity-store-id <YOUR_IDENTITY_STORE_ID> \
--region <HOME_REGION> \
--profile sso \
--query 'Groups[*].DisplayName'
# Expected: group names provisioned by Entra SCIM
# These names must match principal_name in account_assignments.yaml EXACTLY
Step 4.2 — Extend config/account_assignments.yaml for Entra groups
For SCIM-provisioned groups (the recommended approach — manage group membership in Entra):
# In config/account_assignments.yaml
# Entra-provisioned group assignment — principal_idp: EXTERNAL
EntaDevs_B2B_PowerUser:
principal_name: "Entra-Developers" # exact SCIM group name from Step 4.1
principal_type: GROUP
principal_idp: EXTERNAL # <— this is the key seam variable
permission_sets:
- PowerUserAccess
account_ids:
- oceansoft-b2b # account name resolved via enable_organizations_lookup
For SCIM-provisioned individual users (only when group management is unavailable):
# In infra/terraform/aws/identity/main.tf (or terraform.tfvars) — the pilot consumer root
existing_sso_users = {
"engineer-alice" = {
user_name = "[email protected]" # exact SCIM username
group_membership = ["PlatformTeam"] # optional: add to Terraform-managed group
}
}
Individual user assignments (existing_sso_users) work but do not scale. Entra group → Identity
Center group → permission set → account assignment is the pattern that requires zero Terraform
changes when team composition changes.
5W1H — Terraform Entra Wiring
| Question | Answer |
|---|---|
| Why | The principal_idp = "EXTERNAL" flag tells the modules/sso account assignment resource to look up the principal in the Identity Center identity store (where SCIM put it) rather than in the local Terraform-managed user set; without it the assignment fails with a "principal not found" error. |
| What if missing | Account assignments for Entra-provisioned principals fail at apply time; engineers authenticated via Entra SAML have no permission set and see an empty AWS portal. |
| Business value | Terraform governs access policy (what can be done) while Entra governs identity (who is allowed in); the two responsibilities are separated by the principal_idp flag — this is the principle of least coupling between IdP and cloud access governance. |
| Purpose | Closes the loop: SAML proves identity → SCIM provisions the user record → principal_idp = "EXTERNAL" wires the Terraform assignment to the provisioned record → the engineer sees their assigned accounts in the AWS portal. |
| Critical thinking | SCIM group names and Terraform principal_name values must be identical strings. If Entra SCIM uses AWS-Developers but account_assignments.yaml says Developers, the assignment silently fails. Run the Step 4.1 verify command and copy-paste the exact names rather than typing them. |
References
- Pre-requisite runbook:
identity-center-enablement.mdx(TI-2a) — must complete first - ADR-020 (L1/L2 non-conflation, Entra-not-Keycloak):
docs/content/architecture/adrs/ - ADR-021 (parallel 2-account topology):
docs/content/architecture/adrs/ADR-021-parallel-2-account-topology.md - Module seam:
terraform-aws/modules/sso/variables.tflines 71-78 (existing_sso_users), line 117 (principal_idp) - AWS documentation: Set up SAML with Entra ID