fix(credentials): require host identity for role_arn accounts without an ARN - #494
Merged
Merged
Conversation
… an ARN An AWS account with aws_auth_mode=role_arn and an empty aws_role_arn is treated as the CUDly host account and served with the host's own ambient credentials. Nothing checked that the account really was the host, so an operator who picked role_arn on a tenant account and left the ARN out got collection (and purchase execution) against the host account's resources, filed under the tenant account's UUID. Add credentials.VerifyHostAccount, which compares the account's external_id with the host's sts:GetCallerIdentity account and returns the typed ErrNotHostAccount on a mismatch, an STS failure, a missing STS client or an empty identity. The scheduler's ambient branch and resolveRoleARNProvider (used by purchase execution and the commitment-options probe) call it before handing out ambient credentials. Refs #402
The setup-admin and password-reset-confirm handlers base64-decode the password like login does, but the OpenAPI schemas did not say so. Add the same "Base64-encoded" description login carries, plus a spec test that checks every such field. Refs #402
Contributor
|
Warning Review limit reached
This review includes 11 billable files and costs up to $2.75.
Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing. Or wait 49 minutes for your next included review. View limit detailsLimit details: You’ve used the included review currently available. Your 60 included PR review attempts over the past 7 days set your current allowance at 1 review per hour. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (11)
Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Items 3 and 4 of #402. Items 1 and 2 (API-key revocation) landed in #492, so this PR closes #402.
Item 3: role_arn with no ARN on a non-host account. An AWS account with
aws_auth_mode=role_arnand an emptyaws_role_arnis the "self account" shape: CUDly serves it with the host's own ambient credentials. Nothing checked that the account was the host. A tenant account configured as role_arn with the ARN left out got:scheduler.collectAWSForAccountambient branch), andcredentials.resolveRoleARNProvider).The fix adds
credentials.VerifyHostAccount. It compares the account'sexternal_idwith the host'ssts:GetCallerIdentityaccount and returns the typedcredentials.ErrNotHostAccounton a mismatch, an STS error, a missing STS client, or an empty identity. Both ambient paths call it before they hand out ambient credentials. Callers wireAmbientSTS(the STS client already built from the sameawsCfgas the ambient provider) inpurchase/execution.goandserver/app.go. The scheduler reuses its existingstsClient. The per-account error goes through the existing fan-out failure reporting.Item 4.
SetupAdminRequest.passwordnow says "Base64-encoded password", asLoginRequest.passwordalready did.PasswordResetConfirm.new_passwordhad the same gap (its handler also callsdecodeBase64Password), so it gets the same note. No generated client or frontend contract mirrors these schemas.Not in this PR
validateAWSAuthMode) still accepts role_arn with no ARN for any external_id. The runtime check is the guard that fails closed, because existing rows skip validation. A create-time rejection is a possible follow-up.POST /api/accounts/:id/test(awsAmbientCredResult) still reports "ambient credentials (CUDly host account)" for this shape without probing. It is a status message and no credentials are used, but it is misleading for a non-host account.How verified
Toolchain:
GOTOOLCHAIN=go1.26.6 GOWORK=off GOFLAGS='-p=2 -count=1' AWS_EC2_METADATA_DISABLED=truego build ./...,go vet ./...,go vet -tags integration ./...: cleango test ./internal/credentials/ ./internal/scheduler/ ./internal/purchase/ ./internal/server/ ./internal/api/: 3484 passedgo test -tags integration ./internal/scheduler/ -run Completeness(Postgres testcontainer): 25 passedgolangci-lint runon the touched packages: no issuesRegression tests (all fixture/mock-based):
TestScheduler_CollectAWSForAccount_RoleARNWithoutARNOnNonHostFailsClosed: a tenant account (external_id 222222222222) with the host on 999999999999, an STS error, or no STS client must returnErrNotHostAccountand never callCreateAndValidateProvider(ctx, "aws", nil).TestResolveAWSCredentialProvider_SelfAccount_NonHostFailsClosed: covers mismatch, empty external_id, empty host identity (so"" == ""cannot pass), STS error, and a nil client.TestResolveAWSProvider_RoleARNWithoutARNOnNonHostFailsClosed: covers the purchase path, for both the non-host case (rejected) and the host case (ambient credentials returned).TestOpenAPIPasswordFieldsDocumentBase64: covers the spec.Failing before the fix: with only the two
VerifyHostAccountcall sites disabled (scheduler.go, resolver.go):With the openapi.yaml change stashed:
Mutation check: changing the external_id comparison in
VerifyHostAccounttoif false && ...fails the credentials and scheduler regression tests. Reverted.Not verified against a real AWS account. The STS identity comparison is exercised only through fakes.