fix(amplify-category-auth): clean up OIDC provider on auth stack teardown#14952
fix(amplify-category-auth): clean up OIDC provider on auth stack teardown#14952ahmedhamouda78 wants to merge 4 commits into
Conversation
…down The OpenId custom resource Lambda only handled Create/Update requests, so on stack deletion the account-global IAM OIDC provider (accounts.google.com) was never removed. Orphaned providers accumulate in the account on every teardown. Add a Delete handler that removes the client IDs this resource registered and deletes the provider only once no client IDs remain, so providers shared by other Amplify apps in the same account are preserved. All IAM calls tolerate an already-removed provider/client ID, keeping the handler idempotent. Grant the OpenId Lambda role iam:RemoveClientIDFromOpenIDConnectProvider and iam:DeleteOpenIDConnectProvider (scoped to the accounts.google.com provider). Adds unit tests covering create, sole-owner delete, shared-provider delete, and idempotent delete.
…a deps cfn-response and @aws-sdk/client-iam are provided by the Lambda runtime and are not installed in the package, so jest.mock could not resolve them and the suite failed to run in CI. Mark both mocks as virtual.
- Re-read the provider after removing our client IDs and delete it if a concurrently-deleting stack emptied it, closing a race that could leave a provider with zero client IDs orphaned in the account. - Harden provider lookup to match on the URL host / :oidc-provider/<host> ARN suffix instead of brittle string splitting. - Clarify in the stack builder that account-level iam:ListOpenIDConnectProviders is granted in the adjacent statement (required by the lookup). - Tests: guard invoke() when response.send is never called, rename the URL constant to avoid shadowing the global, and add Update-appends and concurrent-deletion-race cases.
|
Thanks for the thorough review @soberm — all six points addressed in b16780b:
All six unit tests pass locally under CI-like conditions (runtime-only deps mocked virtually). |
sarayev
left a comment
There was a problem hiding this comment.
Review — Approve with comments ✅
Solid fix for a real latent leak: the OpenId custom-resource Lambda never handled Delete, so the accounts.google.com OIDC provider (+ IAM resources) leaked on stack teardown. The Delete handler (removes only this stack's client IDs, deletes the provider only when empty), scoped IAM perms, idempotency (NoSuchEntityException tolerance), shared-provider safety, and the new URL(url).host refactor are all good. 6-scenario test file is a nice addition.
Should-fix (cheap, none break the happy path)
- Inaccurate comment —
auth-cognito-stack-builder.ts:~1073. SaysListOpenIDConnectProvidersmust useResource '*', but the code scopes toarn:aws:iam::<acct>:oidc-provider/*(viaselector: '*'). Misleading — reword to describe the wildcard provider ARN. - Asymmetric race —
openIdLambda.js:~93(sole-owner branch). Shared-provider branch re-reads before deleting; sole-owner deletes from the stale initial read. A concurrentCreatecould be destroyed. Mirror the re-read (Get → confirm empty → delete). - Missing
urlnull-guard.clientIdListgot a guard this PR;urldidn't →new URL(undefined)throwsTypeError. Addevent.ResourceProperties.url ?? ''(or validate early).
Nits
- PR body says 4 tests; file has 6 — update the count.
openIdLambda.test.js:5mutates module-levelmockState(guideline: reset aletinbeforeEach).- Shared-provider test injects state directly; prefer a 2nd
Createto set up shared state (also exercises add-client-ID path). - Pre-existing gap (not this PR): no snapshot coverage of the OpenId IAM policy.
Please run the full split e2e + all PR checks and get them green before merge.
- Mirror the pre-delete re-read in the sole-owner branch so a provider that a concurrent stack added client IDs to (or re-created) is not destroyed; only our client IDs are dropped in that case. - Guard findProviderArn against a missing url (no more new URL(undefined) throw). - Reword the stack-builder IAM comment: ListOpenIDConnectProviders is scoped to the wildcard provider ARN (oidc-provider/*), not Resource '*'. - Tests: reset mockState via reassignment in beforeEach, and set up the shared-provider case with a real second Create (exercises add-client-ID). - Apply prettier formatting (fixes the lint/prettier-check CI failure).
|
Thanks @sarayev — addressed in d153b19: Should-fix
Nits All 6 unit tests pass, and prettier/lint is now clean (the earlier |
Description of changes
The auth category's
OpenIdcustom resource Lambda (openIdLambda.js) only handledCreate/Updateevents. On stack deletion CloudFormation sends aDeleteevent, which fell through to a no-op — so the account-global IAM OIDC provider (accounts.google.com) was never removed. Orphaned providers accumulate in the account on every teardown of an auth resource configured with Google/OpenID federation.This PR:
Deletehandler toopenIdLambda.js. Because the provider is account-global and keyed by URL (the create path reuses it and appends client IDs), the handler removes only the client IDs this resource registered and deletes the provider only once no client IDs remain — preserving providers shared by other Amplify apps in the same account. All IAM calls tolerate an already-removed provider/client ID, so the handler is idempotent.iam:RemoveClientIDFromOpenIDConnectProviderandiam:DeleteOpenIDConnectProvider(scoped to theaccounts.google.comprovider ARN) inauth-cognito-stack-builder.ts.Issue #, if available
N/A
Description of how you validated changes
openIdLambda.test.jspasses (6/6), driving the real handler through: create, update-appends, sole-owner delete, shared-provider delete, concurrent-deletion race, and idempotent delete.Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.