Skip to content

Build1 publisher2 min readPublished

A 15-minute IAM token replaces the password Lambda keeps in its environment variables

Taking the password out of a Lambda's environment variables costs five console steps and one inline rds-db:connect policy, and buys a database credential that expires fifteen minutes after boto3 mints it.

The Engineer · Build desk

Illustration accompanying A 15-minute IAM token replaces the password Lambda keeps in its environment variables

What happened

  • A dev.to walkthrough has Lambda generate a temporary IAM token with boto3 and present it as the database password, valid for 15 minutes, in place of a static username and password.
  • The Lambda execution role needs the rds-db:connect permission, which is what lets the function generate that auth token at all.
  • The MySQL user is created with AWSAuthenticationPlugin and holds no password, so authentication for it is delegated entirely to AWS IAM.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint Required is a property of the proxy, not of each client, so any other service still logging in to that proxy with a password stops connecting the moment the setting is saved.
  • decision Shops running functions outside a VPC have to move them into the proxy's VPC, subnets and security group first, and that migration is larger than writing the policy.
  • exposure A leaked execution role buys token generation for one database user that can read, insert and update in one schema, and cannot delete rows or change tables.
  • capability Rotation leaves the deployment pipeline. The credential turns over on its own 15-minute clock, and no build step has to ship a new value.

Validation happens once, at connect. The proxy checks the token against IAM, authorizes the connection and passes through to RDS MySQL [2]. The fifteen-minute life of the token bounds when a connection can be opened [1]. A container that keeps one connection open across invocations generates a token rarely; one that reconnects on every invocation generates one every time [1].

Step 1 leaves the database itself accepting both. Under Database authentication the walkthrough selects "Password and IAM database authentication" on the RDS instance and applies it immediately [7]. Required is set one layer up, on the proxy, and there any connection without a valid IAM token is rejected [6]. Traffic that reaches the instance without going through the proxy still authenticates with a password [7].

The dev.to post says AWS gives you a way to "eliminate database passwords entirely from your Lambda code" [11]. The last four words are the precise ones. The proxy needs credentials of its own to reach the database, and the prerequisite list has AWS Secrets Manager already storing them [10]. What goes away is the pair in the function's environment, the pattern the post marks as a security risk: `pymysql.connect` with `password=os.environ['DB_PASSWORD']` [13].

The reach of a stolen role is written into two config lines. The inline policy allows `rds-db:connect` on a single resource ARN ending in `/lambda_user` [8]. That user is created with `AWSAuthenticationPlugin` and holds no password of its own [4], and its grant covers SELECT, INSERT and UPDATE on `mydb.*` [5], so it cannot delete a row or alter a table [15]. The caller also has to be inside the VPC, subnets and security group the proxy sits in [9].

Two conditions decide whether the number of steps in the walkthrough is the real cost [16]. The engine is MySQL: the user creation depends on a MySQL plugin name in a `CREATE USER` statement [4]. And the walkthrough starts from an RDS MySQL instance in a VPC, an RDS Proxy already pointing at it, and a Lambda function already in the same VPC [14].

What to watch

  • Whether the corrected connection code regenerates the token on every invocation or caches it in the warm container.
  • If the RDS instance setting is tightened from both modes to IAM only, anything connecting directly with a password stops working.
  • Documentation of the same path for a non-MySQL engine, since the user creation here depends on a MySQL plugin name.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories