Skip to content

feat(aws-infra): Authentik as external IdP for org IAM Identity Center (SAML + SCIM) - #41

Open
coolguy1771 wants to merge 21 commits into
mainfrom
feature/authentik-identity-center
Open

feat(aws-infra): Authentik as external IdP for org IAM Identity Center (SAML + SCIM)#41
coolguy1771 wants to merge 21 commits into
mainfrom
feature/authentik-identity-center

Conversation

@coolguy1771

Copy link
Copy Markdown
Contributor

Authentik as external IdP for the org IAM Identity Center (SAML + SCIM)

Manages, in the existing infra/aws / prod Pulumi stack:

  • Authentik groups aws-admins / aws-viewers, a SAML provider + application (aws-iam-identity-center), and a SCIM provider scoped (via groupFilters + excludeUsersServiceAccount) to just those two groups.
  • IC permission sets aws-adminsAdministratorAccess and aws-viewersReadOnlyAccess.
  • Account assignments for both groups in both org accounts (icAssignmentAccountIds), gated behind icAssignmentsEnabled for the two-phase rollout.
  • A dual-provider setup: the default AWS provider (workload account, existing Route53 / OIDC) plus an assumed-role ic-management provider into arn:aws:iam::977656673179:role/keeper-ic-pulumi for the SSO Admin / Identity Store APIs.
  • CI: .github/workflows/aws-infra.yml fetches AUTHENTIK_TOKEN / AUTHENTIK_SCIM_TOKEN from OpenBao (secret/data/pulumi/authentik) via a new github-actions-aws-infra JWT role, gated on repo var AUTHENTIK_IC_ENABLED.

This is already applied to prod. The org identity source was cut over to Authentik during implementation; pulumi preview on this branch is clean (23 unchanged). This PR is bringing the reviewed code + docs onto main to match the running state, not proposing an un-applied change.

Not in code (one-time console / manual)

Changing the IC identity source and enabling SCIM have no API — see the rewritten Identity Center bootstrap checklist in README.md. Also manual: the SAML provider's default_name_id_policy must be emailAddress (AWS 400s on unspecified; the goauthentik terraform provider 1.2.1 can't express it), and infra/aws/keeper-ic-pulumi.policy.json must be attached to the management role out-of-band.

Gotchas captured in the runbook

  • AWS ACS only accepts the HTTP-POST SAML binding (spBinding: "post"); a redirect-binding response is silently dropped with no CloudTrail Federate event.
  • SCIM must be group-scoped or the outpost service account syncs an empty userName (AWS 400); pre-cutover Identity Store users whose email collides with an aws-* member must be deleted first (AWS 409).
  • Hand-made AccountAssignments need pulumi import — the AWS provider errors already exists rather than adopting.

Follow-ups (tracked, not blocking)

  • Rotate the Authentik API + SCIM tokens; load them into OpenBao and set AUTHENTIK_IC_ENABLED=true.
  • Point teammates' ~/.aws/config at sso_role_name = aws-admins.
  • Retire the orphaned legacy Admins group + permission set (or keep as break-glass alongside management root).

Test

cd infra/aws && npm test && npx tsc --noEmit — green. pulumi preview -s prod — no drift.


https://claude.ai/code/session_01EZ2pLGAZfBApkjFhAvjthW

Wire an authentik.Application (SAML SSO + backchannel SCIM provisioning) to AWS IAM Identity Center, plus aws-admins/aws-viewers permission sets. Account assignments stay gated behind an explicit assignmentsEnabled flag so preview/apply don't fail before the SCIM sync creates matching groups.
Drop the unused resolveAssignmentsPending import, mark the SCIM token secret even if the caller forgot, and guard the SAML/SCIM provider id -> number conversions so a malformed id fails loudly instead of sending NaN to the Authentik API.
Align with bao-sync JWT auth and fail fast instead of exporting null tokens.
- identityCenterAuthentik: SCIM provider is only attached when icScimUrl is
  set, so the first (SAML-only) apply can run before automatic provisioning
  is enabled in the IC console. Adds icScimAttached stack output.
- index.ts: IC gate no longer requires icScimUrl; the SCIM token is only
  resolved when icScimUrl is present.
- Pulumi.prod.yaml: real values for org o-2j4dlyoocl -- management account
  977656673179, workload 417568418531, instance ssoins-722325f246f3860b,
  authentikUrl. ACS / audience / SCIM URL still come from the console bootstrap.

Claude-Session: https://claude.ai/code/session_01EZ2pLGAZfBApkjFhAvjthW
Rewrite the README Identity Center bootstrap checklist for org o-2j4dlyoocl
with real account ids, the SAML-first apply order (SCIM is now optional), and
an explicit warning that accepting the external IdP wipes the Identity Center
directory and all assignments until SCIM re-provisions.

Claude-Session: https://claude.ai/code/session_01EZ2pLGAZfBApkjFhAvjthW
From the us-east-1 IAM Identity Center SP metadata for identity store
d-9067963c52. SCIM URL still pending the console "enable automatic
provisioning" step.

Claude-Session: https://claude.ai/code/session_01EZ2pLGAZfBApkjFhAvjthW
The first SCIM sync tried to push every Authentik user: service accounts
(ak-outpost-*) have no email so userName came out empty (AWS 400), and
unrelated users collided with pre-existing Identity Store entries (AWS 409).

Set groupFilters to the aws-admins / aws-viewers group ids and
excludeUsersServiceAccount so only those two groups and their members sync.

Claude-Session: https://claude.ai/code/session_01EZ2pLGAZfBApkjFhAvjthW
Replace the single workloadAccountId assignment target with
assignmentAccountIds (config key icAssignmentAccountIds). prod assigns
aws-admins / aws-viewers in both the workload (417568418531) and management
(977656673179) accounts, matching the pre-cutover Admins group reach, and
enables assignments (icAssignmentsEnabled) now that SCIM has synced the
groups into the Identity Store.

Claude-Session: https://claude.ai/code/session_01EZ2pLGAZfBApkjFhAvjthW
AWS IAM Identity Center's ACS only advertises the HTTP-POST binding.
Authentik's ProviderSaml defaults spBinding to redirect, so the signed
response was deflated into a GET query string that AWS silently dropped
(no Federate event, generic "we couldn't complete your request" page).
Pin spBinding to post.

Claude-Session: https://claude.ai/code/session_01EZ2pLGAZfBApkjFhAvjthW
Captures what the first live cutover of org o-2j4dlyoocl needed beyond the
original plan:
- keeper-ic-pulumi also needs SAML-provider + aws-reserved/sso role IAM
  actions for first-time permission-set provisioning; full policy checked in
  as infra/aws/keeper-ic-pulumi.policy.json.
- SAML provider default_name_id_policy must be emailAddress (AWS 400s on
  unspecified); not expressible in the terraform provider yet -> manual step.
- SCIM must be scoped (groupFilters + excludeUsersServiceAccount) and
  colliding pre-cutover Identity Store users deleted first.
- Hand-made AccountAssignments need `pulumi import`, not create.
- CLI profiles move to sso_role_name = aws-admins.

Claude-Session: https://claude.ai/code/session_01EZ2pLGAZfBApkjFhAvjthW
No behaviour change (pulumi preview: 23 unchanged, all resource names kept).

- Drop the unused `authentikUrl` module arg (provider auth is env-only).
- Fold `icScimUrl` + `scimToken` into one optional `scim: {url, token}`; validate
  once in index.ts instead of a redundant check in createScimProvider.
- Resolve the group names once and thread concrete strings, instead of
  `?? "aws-admins"` in four places.
- Rename createAccountAssignment -> createAccountAssignments (it loops accounts);
  drive both groups from one array in the caller.
- Guard: assignmentsEnabled with an empty account list now throws.
- Remove the dead resolveAssignmentsPending helper + its test.
- Update the Pulumi.yaml project description.

Claude-Session: https://claude.ai/code/session_01EZ2pLGAZfBApkjFhAvjthW
@greptile-apps

greptile-apps Bot commented Aug 30, 2026

Copy link
Copy Markdown

Too many files changed for review (149 files, 100 file limit).

Bypass the limit by tagging @greptile-apps to review.

Match the repo rename swept in chore/rename-cloud-security-cluster.

Claude-Session: https://claude.ai/code/session_01EZ2pLGAZfBApkjFhAvjthW
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.

1 participant