Skip to content
Quest 05Intermediate15 min

Grant, Don't Hand-Write

A new function can't do anything: its role starts empty. The quick fix, a policy that allows dynamodb:* on *, works and is a security finding waiting to happen. CDK has a better way: grants.

What you'll learn

  • Every Lambda function gets its own IAM role, with no permissions beyond writing its logs.
  • Grant methods such as table.grantReadData(fn) add a narrow policy for exactly one resource and the actions the method name promises.
  • Prefer the narrowest grant: grantRead, grantPut or grantReadData over grantReadWrite, and never wildcards.

Section 01

The wildcard trap

Hand-written policy statements are easy to get wrong in the generous direction. A function that only reads cards ends up able to delete the table, and a bug or a compromised dependency inherits all of it. Least privilege means giving each function exactly the actions it needs on exactly the resources it touches.

What to replace
// Too broad: any DynamoDB or S3 action on anything
lookup.addToRolePolicy(new iam.PolicyStatement({
  actions: ["dynamodb:*", "s3:*"],
  resources: ["*"],
}));

Section 02

Grants

Most L2 constructs that own data have grant methods. You pass the principal, which can be a function, a role or a user; CDK adds a statement to that principal's policy with the right actions and the resource's ARN. If the table has indexes, the grant also covers them.

MethodLets the functionUse for
grantReadDataRead items from the tableLookups
grantWriteDataWrite and delete itemsImporters
grantReadGet and list objectsServing cards
grantPutPut objects onlyUploaders
grantReadWriteBoth directionsOnly when it truly does both
Narrow grants
table.grantReadData(lookupFn);   // GetItem, Query, Scan, BatchGetItem, …
bucket.grantRead(lookupFn);      // s3:GetObject*, s3:GetBucket*, s3:List*
bucket.grantPut(uploadFn);       // s3:PutObject, s3:PutObjectLegalHold, … (no read)

Section 03

Read the policy it wrote

Open the exercise output and find the AWS::IAM::Policy resources. The Resource lists are references to the table and bucket, not *. One detail looks odd the first time: a DynamoDB grant ends with Ref: AWS::NoValue in its resource list. CDK adds the table's indexes there when it has any; with no index the slot is empty, and CloudFormation drops it.

Practice

Your turn

Both functions were given every permission on every resource. Delete the wildcard policies and use grants instead: LookupFn reads the table and the card bucket (grantReadData and grantRead; no write access); UploadFn may only put objects (grantPut) into the bucket and must not read them or touch the table.

Remove addToRolePolicy; use table.grantReadData, bucket.grantRead for the lookup and bucket.grantPut for the upload.
Tab inserts two spaces. Press Escape, then Tab, to leave the editor. Control or Command plus Enter runs the code.
Simulated — no AWS calls

The simulator runs the constructs this course teaches, plus simple loops and helper methods. Other CDK code may not be recognised.

Check

Check your understanding

Quick Quiz · one question, as many tries as you need.

UploadFn only has to store card images in the bucket. Which grant fits?

Choose one answer.