Skip to content

Feat/rds auth#386

Draft
pquadri wants to merge 4 commits intoduckdb:mainfrom
pquadri:feat/rds-auth
Draft

Feat/rds auth#386
pquadri wants to merge 4 commits intoduckdb:mainfrom
pquadri:feat/rds-auth

Conversation

@pquadri
Copy link
Copy Markdown

@pquadri pquadri commented Nov 21, 2025

Fixes #360.

Quite dirty, but it seemed the least intrusive solution, let me know what you think about this.
It can potentially be just an experimental addition then be changed to use the AWS SDK? (i didn't want to add that as a dependency, having a soft requirement of "you need aws-cli if you want to use this" seemed better)

I'm working on having an RDS with IAM to test this properly.

pquadri added 2 commits April 20, 2026 19:28
Implements RDS IAM-based authentication using the AWS CLI to generate
temporary auth tokens instead of static passwords. Tokens are cached
for 13 minutes (expiry is 15 min) to avoid spawning a new process for
every pool connection.

Usage:
  CREATE SECRET rds_secret (
      TYPE POSTGRES,
      HOST 'my-db.xxxxxx.us-east-1.rds.amazonaws.com',
      PORT '5432',
      USER 'my_iam_user',
      DATABASE 'mydb',
      USE_RDS_IAM_AUTH true,
      AWS_REGION 'us-east-1'  -- optional, uses AWS CLI default if omitted
  );
  ATTACH '' AS rds_db (TYPE POSTGRES, SECRET rds_secret);

Implementation notes:
- Token generation via `aws rds generate-db-auth-token` (inherits env for
  AWS_PROFILE, instance roles, web-identity, etc.)
- Token cache keyed on (hostname, port, username, region) with a 13-min TTL
- RDS params are extracted from the secret at ATTACH time so
  CreateNewConnection() can regenerate tokens without a ClientContext
- stderr from the aws command propagates to the process stderr so users
  see credential errors directly
- Debug logging (pg_debug_print_queries) prints only the token prefix+length
Switch from popen/shell-out to a direct fork+exec (POSIX) /
CreateProcess (Windows) subprocess helper so RDS IAM auth token
generation works on Windows and closes several safety issues
flagged in code review.

Changes:
- Add src/process_exec.{hpp,cpp}: RunProcess(argv) — no shell, no
  escaping, separate stdout/stderr pipes, 30s timeout, clear
  "aws not found on PATH" error on ENOENT/ERROR_FILE_NOT_FOUND.
  POSIX uses fork/execvp/poll + close-on-exec error pipe to detect
  exec failure without waitpid races. Windows uses CreateProcessA
  with two std::thread drain workers to avoid two-pipe deadlock.
- src/storage/postgres_catalog.cpp: replace escape_shell_arg lambda
  + popen block with RunProcess call; stderr now surfaces in the
  exception message on failure instead of potentially corrupting
  the token.
- src/storage/postgres_connection_pool.cpp: fix two "str" + int
  pointer-arithmetic bugs in exception messages (were compile
  warnings, would produce garbage strings at runtime).
- CMakeLists.txt: add ${PostgreSQL_INCLUDE_DIRS} to include path
  (was missing, broke builds without vcpkg).
- test/stub/aws + test/stub/aws.cmd: fake aws binary for manual
  smoke-testing; prints a known token, logs invocation to
  $AWS_STUB_LOG.
pquadri added 2 commits April 21, 2026 12:02
- Replace hand-rolled clock_gettime/timespec arithmetic with
  steady_clock (chrono.hpp was already a transitive dep)
- Unify the 30s subprocess timeout into a single PROCESS_TIMEOUT_MS
  constant shared by both POSIX and Windows paths
- Fix double-space in GetFreshConnectionString: rds_base_connection_string
  already ends with a space from AddConnectionOption, so the leading
  " password=" was producing "host='x' port='5432'  password=..."
- Document the intentional cache TOCTOU: two concurrent misses produce
  two valid tokens; second write wins, both tokens are valid for 15 min
- Remove child-block comment that described what the code does
- postgres_extension.cpp: store use_rds_iam_auth Value directly instead
  of .ToString() to preserve BOOLEAN type; BooleanValue::Get() asserts
  type==BOOL and would crash on a VARCHAR "true"
- process_exec.cpp (Windows): split CreatePipe calls so stdout handles
  are closed if the stderr pipe creation fails
- process_exec.cpp (POSIX): split pipe() calls with proper fd cleanup on
  partial failure to prevent fd leaks
- postgres_catalog.cpp: strip \\r before \\n from aws CLI token output
  to handle Windows CRLF line endings
- postgres_catalog.cpp: store rds_base_connection_string without
  attach_path; append attach_path after the password in
  GetFreshConnectionString() so the connection string is well-formed
  when attach_path is non-empty
@staticlibs
Copy link
Copy Markdown
Collaborator

Hi, thanks for the PR!

It can potentially be just an experimental addition then be changed to use the AWS SDK?

M, I cannot answer this off the top of my head, there are obviously good and bad parts of bringing in AWS SDK.

Meanwhile, to pass the CI format check

  1. install black==25.1.0, clang_format==11.0.1 and cmake-format==0.6.13 from Python pip
  2. run make format-fix

Or, alternatively, just apply the diff from the CI job output.

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.

Feature Request: Automatically get password for AWS RDS IAM based authentication

2 participants