Skip to content

Harden the AWS client configuration#42

Merged
GrahamCampbell merged 1 commit into
mainfrom
fix/aws-shim-hardening
Jun 11, 2026
Merged

Harden the AWS client configuration#42
GrahamCampbell merged 1 commit into
mainfrom
fix/aws-shim-hardening

Conversation

@GrahamCampbell

Copy link
Copy Markdown
Contributor

The AWS client configuration utilities in this repository are copies of the files that were recently hardened in osls, and they carried the same defects. Since compose polls CloudFormation while creating the remote state stack and reads and writes state in S3, these affected every command that touches remote state.

The documented AWS_CLIENT_TIMEOUT environment variable was mapped to requestTimeout, which @smithy/node-http-handler treats as warn-only since 4.4.0 across our entire declared range, so it never aborted anything. Worse, when no proxy, certificate, or timeout environment variables were set, no request handler was attached at all, leaving clients with no timeout whatsoever — a hung connection during state stack polling would hang compose forever. The variable now maps to socketTimeout with inactivity semantics, the default is 120 seconds, and a handler is always constructed. The proxy agent is applied to both the https and plain-http schemes, and the keepAlive agent option that was lost when the file was copied from osls is restored.

Credential resolution had its own transport gap. The fromIni and fromNodeProviderChain providers were constructed without a clientConfig, so the inner SSO and OIDC clients they spin up made direct connections that ignored the proxy, custom certificate authorities, and timeouts. A single shared NodeHttpHandler is now passed through clientConfig.requestHandler on every construction path, with the region deliberately left out because it would override the profile's sso_region. The MFA prompt now rejects with MFA_CODE_UNAVAILABLE when stdin reaches end of file instead of hanging forever in CI, and an AWS_DEFAULT_PROFILE that names a profile absent from both shared files now logs a warning and falls back to the SDK default provider chain instead of failing hard; this deliberately reverses semantics that a previous test had pinned and matches the behavior osls ships. A one-time warning is also logged when a profile's static keys in the credentials file are shadowed by a role_arn in the config file, since commands then run under the assumed role identity.

Credential resolution results are now memoized process-wide in get-credential-provider.js, keyed by every input the resolution chain reads so environment changes still produce a fresh provider. Previously nothing cached at all: every client construction re-ran the full resolution, and monitorStackCreation constructed a new CloudFormation client on every two-second poll, which for a profile with mfa_serial or credential_process meant a prompt or process spawn per poll. The provider is wrapped once with memoizeIdentityProvider from @smithy/core and marked with the memoized flag so clients skip their own per-client wrapping; this was verified against the aggregated client classes this repository uses, where one shared provider now resolves exactly once across multiple clients. The polling loop also reuses one client for the whole stack creation instead of constructing one per poll.

The S3StateStorage constructor previously fell back to a raw { region, credentials } config when no client config was given, bypassing all proxy, certificate, timeout, and retry configuration; the fallback now routes through buildClientConfig while preserving the credential semantics. @aws-sdk/credential-providers is raised to ^3.1034.0 to match the two client packages, and @smithy/core is added as a direct dependency at ^3.23.16, the exact range the SDK floor itself declares.

The new tests include a real-socket timeout test against a listener that never responds, end-of-file and answered MFA prompt cases, request handler inheritance assertions on every credential construction path, a process-wide memoization suite covering cache hits, per-profile separation, environment-change misses, and expiring-credential refresh, and a stack creation poll test asserting a single client construction.

@GrahamCampbell GrahamCampbell merged commit 9ecba9b into main Jun 11, 2026
4 checks passed
@GrahamCampbell GrahamCampbell deleted the fix/aws-shim-hardening branch June 11, 2026 21:17
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