DEV Community

Cover image for Grant limited IAM permissions with AWS CDK - but fast!
Ramon for AWS Switzerland

Posted on

Grant limited IAM permissions with AWS CDK - but fast!

I love writing CDK apps but there is something I really loathe: Writing IAM policies and assigning them to resources like Lambdas. It feels like a step back because I don't have the same type-safety and syntax highlighting that I'm used to from native CDK constructs.

When I start writing an app, I want to make fast progress, so I fall back to using AWS Managed IAM policies, which are usually too broad and open. Then I add TODO's and promise myself to take care of it later...

Like in this example where the Lambda should only be able to read from a single bucket, but is granted with full S3 permissions:

const bucket = new s3.Bucket(...)

const executionRole = new iam.Role(this, "execution-role", {
  assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
  managedPolicies: [
    iam.ManagedPolicy.fromAwsManagedPolicyName(
      "service-role/AWSLambdaBasicExecutionRole"
    ),
    iam.ManagedPolicy.fromAwsManagedPolicyName(
      "service-role/AWSLambdaVPCAccessExecutionRole"
    ),
    //TODO lock down permissions!
  iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonS3FullAccess"),
  ],
})

const fn = new lambda.Function(this, "MyLambda", {
  runtime: lambda.Runtime.PYTHON_3_8,
  code: ...,
  handler: ...,
  timeout: ...,
  role: executionRole
})

Enter fullscreen mode Exit fullscreen mode

Wouldn't it be nice if there was an idiomatic way of granting permissions in CDK? Turns out, there is!

Many CDK constructs representing resources that can be accessed (like S3, DynamoDB, SQS, SNS...) provide various .grant...() methods (see CDK Grants). With this method you don't have to memorize or look up the names of any of the AWS Managed IAM policies and it's incredibly succinct:

const bucket = new s3.Bucket(...)

const fn = new lambda.Function(this, "MyLambda", {
  runtime: lambda.Runtime.PYTHON_3_8,
  code: ...,
  handler: ...,
  timeout: ...
})

bucket.grantRead(fn)
Enter fullscreen mode Exit fullscreen mode

Note how I was able to remove the executionRole completely because CDK will chose a sensible default Execution Role that will include permissions to invoke the Lambda.
In the last line I just use the bucket object and call grantRead to give the Lambda permissions to read from this bucket only.

Not only is this easier and faster to write, it also makes our infrastructure more secure! Besides, you can always fall back to explicitly using IAM Roles and Policies if you encounter CDK constructs where grant isn't available.

Learn more

Other CDK modules follow similar mechanisms, for example @aws-cdk/aws-ec2 when it comes to allowing connections. No more manual writing of Security Group rules!

CDK is evolving fast and getting better by the day. If you want to dive deeper, check out the CDK Workshop for some hands-on learning and the CDK Construct Catalog to find hundreds of reusable CDK constructs from AWS and other developers.

Have fun building!
-Ramon

Top comments (0)