Summary
TYPE rds secrets cannot authenticate from ECS/Fargate tasks: no CHAIN value resolves ECS container credentials (AWS_CONTAINER_CREDENTIALS_RELATIVE_URI / AWS_CONTAINER_CREDENTIALS_FULL_URI), and rds secrets require CHAIN, which makes the SDK default chain — the only place the container provider lives — unreachable. Every DuckLake/postgres RDS-IAM attach from a Fargate task therefore fails with:
Unable to generate RDS IAM token for secret with name: "<secret>"
(the presigned token comes back unsigned — no credentials resolved — so the X-Amz-Algorithm check in duckdb-postgres src/postgres_aws.cpp throws).
Why
In src/aws_secret.cpp:
DuckDBCustomAWSCredentialsProviderChain maps each chain name to exactly one SDK provider: env → EnvironmentAWSCredentialsProvider, config → ProfileConfigFileAWSCredentialsProvider, instance → InstanceProfileCredentialsProvider (EC2 IMDS — Fargate does not serve it), plus sts/sso/process/web_identity. Aws::Auth::TaskRoleCredentialsProvider (ECS container credentials) appears nowhere in the vocabulary, and unknown names throw.
- For
input.type == "rds", an empty chain throws "Invalid RDS secret parameters, 'CHAIN' option must be specified" — so unlike s3 secrets, rds secrets can never fall back to DefaultAWSCredentialsProviderChain, which does include the container provider.
So the standard ECS/Fargate credential mechanism — task-role credentials via the container endpoint, the default for any containerized AWS workload — has no supported path.
Reproduction
Probed against @duckdb/node-api 1.5.4-r.1 (latest published) with a local mock of the container-credentials endpoint (AWS_CONTAINER_CREDENTIALS_FULL_URI=http://127.0.0.1:8899/creds serving valid-shape JSON creds; HOME isolated; no env keys):
| CHAIN |
endpoint hits |
outcome |
config, env, instance, process, sso, web_identity, config;env;instance |
0 |
Unable to generate RDS IAM token |
omitted / '' |
— |
rejected: 'CHAIN' option must be specified |
sts + ASSUME_ROLE_ARN |
2 |
credentials resolved (inner STSClient in AddSTSProvider is built without an explicit provider, so it uses the SDK default chain — the one code path that reaches container credentials) |
INSTALL postgres; LOAD postgres; INSTALL aws; LOAD aws;
CREATE SECRET t (TYPE rds, PROVIDER credential_chain, CHAIN 'config',
RDS_USER 'u', RDS_HOST 'h', RDS_PORT 5432, REGION 'us-east-1');
CREATE SECRET tp (TYPE postgres, HOST 'h', PORT '5432', USER 'u',
DATABASE 'd', SSLMODE require, AWS_RDS_SECRET t);
ATTACH 'ducklake:postgres:' AS m (META_SECRET 'tp');
-- in any ECS/Fargate task: Unable to generate RDS IAM token for secret with name: "t"
Workaround
CHAIN 'sts' + ASSUME_ROLE_ARN pointing at the task role itself (requires adding a self-assume trust statement + an identity-policy sts:AssumeRole on the role). This works because the STS provider's inner client resolves the container credentials via the default chain — but a self-assuming IAM role is an odd requirement for what should be ambient credentials.
Suggested fixes (either resolves it)
- Allow
CHAIN to be omitted (or empty) for rds secrets and fall back to Aws::Auth::DefaultAWSCredentialsProviderChain, matching the s3 secret behavior.
- Add a chain entry for container credentials (e.g.
container → Aws::Auth::TaskRoleCredentialsProvider, or the newer GeneralHTTPCredentialsProvider).
Summary
TYPE rdssecrets cannot authenticate from ECS/Fargate tasks: noCHAINvalue resolves ECS container credentials (AWS_CONTAINER_CREDENTIALS_RELATIVE_URI/AWS_CONTAINER_CREDENTIALS_FULL_URI), and rds secrets requireCHAIN, which makes the SDK default chain — the only place the container provider lives — unreachable. Every DuckLake/postgres RDS-IAM attach from a Fargate task therefore fails with:(the presigned token comes back unsigned — no credentials resolved — so the
X-Amz-Algorithmcheck in duckdb-postgressrc/postgres_aws.cppthrows).Why
In
src/aws_secret.cpp:DuckDBCustomAWSCredentialsProviderChainmaps each chain name to exactly one SDK provider:env→EnvironmentAWSCredentialsProvider,config→ProfileConfigFileAWSCredentialsProvider,instance→InstanceProfileCredentialsProvider(EC2 IMDS — Fargate does not serve it), plussts/sso/process/web_identity.Aws::Auth::TaskRoleCredentialsProvider(ECS container credentials) appears nowhere in the vocabulary, and unknown names throw.input.type == "rds", an empty chain throws"Invalid RDS secret parameters, 'CHAIN' option must be specified"— so unlikes3secrets, rds secrets can never fall back toDefaultAWSCredentialsProviderChain, which does include the container provider.So the standard ECS/Fargate credential mechanism — task-role credentials via the container endpoint, the default for any containerized AWS workload — has no supported path.
Reproduction
Probed against
@duckdb/node-api1.5.4-r.1 (latest published) with a local mock of the container-credentials endpoint (AWS_CONTAINER_CREDENTIALS_FULL_URI=http://127.0.0.1:8899/credsserving valid-shape JSON creds;HOMEisolated; no env keys):config,env,instance,process,sso,web_identity,config;env;instanceUnable to generate RDS IAM token'''CHAIN' option must be specifiedsts+ASSUME_ROLE_ARNSTSClientinAddSTSProvideris built without an explicit provider, so it uses the SDK default chain — the one code path that reaches container credentials)Workaround
CHAIN 'sts'+ASSUME_ROLE_ARNpointing at the task role itself (requires adding a self-assume trust statement + an identity-policysts:AssumeRoleon the role). This works because the STS provider's inner client resolves the container credentials via the default chain — but a self-assuming IAM role is an odd requirement for what should be ambient credentials.Suggested fixes (either resolves it)
CHAINto be omitted (or empty) forrdssecrets and fall back toAws::Auth::DefaultAWSCredentialsProviderChain, matching thes3secret behavior.container→Aws::Auth::TaskRoleCredentialsProvider, or the newerGeneralHTTPCredentialsProvider).