Skip to content

feat: Add AWS Session Token (STS) and default credential chain support for all S3 storage providers #2769

Description

@markli-zd

Component(s)

router, controlplane, cdn-server

Is your feature request related to a problem? Please describe.

When deploying Cosmo in Kubernetes environments that use temporary AWS credentials (STS AssumeRole, IRSA, or credential injection sidecars like Zendesk's temp-auth), S3 storage providers cannot authenticate because:

  1. There is no way to pass a session token alongside access key / secret key.
  2. The Node.js components (controlplane + CDN server) throw an error when credentials are empty, preventing fallback to the @aws-sdk default credential provider chain.

This blocks self-hosted Cosmo deployments in any Kubernetes environment where temporary/rotated credentials are standard.

Affected code paths (verified against 0b0d42d6e):

Router (Go / minio-go): The StaticIAM credential chain does not set SessionToken on the Static provider.

  • router/pkg/routerconfig/s3/client.gocredentials.Static (lines 47–52)
  • router/internal/persistedoperation/operationstorage/s3/client.gocredentials.Static (lines 57–62)
  • router/pkg/config/config.goS3StorageProvider struct has AccessKey/SecretKey but no SessionToken

Controlplane (Node.js / @aws-sdk): createS3ClientConfig() only passes accessKeyId and secretAccessKey, and throws an error when either is empty.

  • controlplane/src/core/util.tscreateS3ClientConfig() (lines 395–421)

CDN Server (Node.js / @aws-sdk): Identical createS3ClientConfig() with the same limitations.

  • cdn-server/src/utils.tscreateS3ClientConfig() (lines 18–44)

Related: #2159 (covers CDN server IRSA only — this issue expands to all components + adds sessionToken passthrough)

Describe the solution you'd like

Two complementary fixes:

Fix 1: Add sessionToken passthrough

Router (Go): Add SessionToken field to S3StorageProvider config and both ClientOptions structs, pass through to credentials.Static:

&credentials.Static{
    Value: credentials.Value{
        AccessKeyID:     options.AccessKeyID,
        SecretAccessKey: options.SecretAccessKey,
        SessionToken:    options.SessionToken,  // new
        SignerType:      credentials.SignatureV4,
    },
}

Controlplane & CDN Server (Node.js): Add S3_SESSION_TOKEN env var and sessionToken to S3StorageOptions:

return {
    region,
    endpoint,
    credentials: {
        accessKeyId,
        secretAccessKey,
        ...(sessionToken && { sessionToken }),
    },
    forcePathStyle,
};

Fix 2: Support default credential provider chain when keys are empty

When accessKeyId and secretAccessKey are both empty, omit the credentials field instead of throwing. The @aws-sdk SDK will use its default credential provider chain (env vars with AWS_SESSION_TOKEN, IRSA, EC2 instance metadata, shared credentials file).

const config: S3ClientConfig = { region, endpoint, forcePathStyle };

if (accessKeyId && secretAccessKey) {
    config.credentials = {
        accessKeyId,
        secretAccessKey,
        ...(sessionToken && { sessionToken }),
    };
}
// When credentials are omitted, @aws-sdk uses default provider chain

return config;

The Go router already partially supports this — when Static credentials are empty, credentials.NewChainCredentials falls through to the IAM provider.

Files to modify (complete list)

Router (Go):

  • router/pkg/config/config.go — add SessionToken to S3StorageProvider
  • router/pkg/config/config.schema.json — add session_token property
  • router/pkg/routerconfig/s3/client.go — add SessionToken to ClientOptions, pass to Static
  • router/internal/persistedoperation/operationstorage/s3/client.go — same
  • router/core/init_config_poller.go — map provider.SessionToken
  • router/core/router.go — map provider.SessionToken

Controlplane (Node.js):

  • controlplane/src/core/env.schema.ts — add S3_SESSION_TOKEN
  • controlplane/src/core/util.ts — update createS3ClientConfig() + S3StorageOptions
  • controlplane/src/index.ts — map env var

CDN Server (Node.js):

  • cdn-server/src/utils.ts — update createS3ClientConfig() + S3StorageOptions
  • cdn-server/src/s3.ts — read S3_SESSION_TOKEN from env

Describe alternatives you've considered

  1. File-based workaround (Router only): Use AWS CLI in an init container + sidecar to download execution config to a local file, then configure the router with execution_config.file.path. This bypasses Cosmo's S3 client but doesn't help Controlplane or CDN Server and adds operational complexity.

  2. Internal MinIO: Run MinIO with static credentials as an internal S3-compatible store. Zero Cosmo changes but adds another service to operate.

Additional context

All changes are purely additive — new fields are optional, existing configurations work without modification. Fix 2 is especially valuable because it enables IRSA and other IAM-based auth that requires zero explicit credential configuration.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions