aws-cloudformation / cfn-language-discussion

Language discussions for CloudFormation template language
https://aws.amazon.com/cloudformation/
Apache License 2.0
142 stars 13 forks source link

Intrinsic function for simplified IAM permissions #111

Open jlhood opened 1 year ago

jlhood commented 1 year ago

Community Note

Tell us about your request

Wanted to get community feedback about the potential for adding an intrinsic function to simplify generation of minimal IAM policy permissions.

Tell us about the problem you are trying to solve. What are you trying to do, and why is it hard?

Today when authoring declarative templates, writing minimal IAM permissions is difficult. For example, if I want to add minimal permissions allowing read/write data access to a specific DynamoDB table, I have to lookup the DynamoDB IAM actions and determine which are associated with reading and writing data, add them to a policy document and then determine the right resource ARN to use for the DynamoDB table, either via manually constructing the ARN via Fn::Sub or if the table is defined in the template, using Fn::GetAtt to fetch the ARN.

Are you currently working around this issue?

There are a few workarounds:

  1. Follow the manual process described above, but it's time consuming and error-prone (easy to miss needed actions, e.g., for certain DDB write operations, dynamodb:ConditionCheckItem action is required, but this is an easy one to overlook).
  2. Use a managed policy like AmazonDynamoDBFullAccess. Downside is this doesn't follow minimal permissions best practice (includes more actions than needed, uses Resource: *).
  3. Migrate to CDK as it has a really slick solution for this: grants. Downside is migration to CDK can be costly or blocked on updating internal customer deployment tooling.

What is the expect behavior with this new feature

Wondering about taking inspiration from CDK's grant methods and creating something like Fn::Grant that can be used by declarative template authors to create minimal permission sets for common use cases. Picturing something like this:

Resources:
  Table:
    Type: AWS::DynamoDB::Table
    Properties:
      # ...

  Key:
    Type: AWS::KMS::Key
    Properties:
      # ...

  Role:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Fn::Grant
            - Table
            - ReadWriteData
          - Fn::Grant
            - Key
            - EncryptDecrypt

This would be equivalent to this:

Resources:
  Table:
    Type: AWS::DynamoDB::Table
    Properties:
      # ...

  Key:
    Type: AWS::KMS::Key
    Properties:
      # ...

  Role:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
            - dynamodb:BatchGetItem
            - dynamodb:GetRecords
            - dynamodb:GetShardIterator
            - dynamodb:Query
            - dynamodb:GetItem
            - dynamodb:Scan
            - dynamodb:ConditionCheckItem
            - dynamodb:BatchWriteItem
            - dynamodb:PutItem
            - dynamodb:UpdateItem
            - dynamodb:DeleteItem
            - dynamodb:DescribeTable
            Effect: Allow
            Resource:
            - !GetAtt Table.Arn
            - !Sub ${Table.Arn}/index/*
          - Action:
            - kms:Decrypt
            - kms:Encrypt
            - kms:ReEncrypt*
            - kms:GenerateDataKey*
            Effect: Allow
            Resource: !GetAtt Key.Arn

Note, the above examples take the logical resource of a resource defined in the same template as the first argument, but this could potentially be enhanced to allow you to pass an arbitrary ARN value in as well.

ljacobsson commented 1 year ago

I support simplifying IAM in every way possible.

So far all intrinsic functions are resource agnostic, but this is specific to IAM policies, so it'll be adding a new dimension to intrinsic functions imo, but maybe that's unavoidable.

Instead of specifying

Fn::Grant: 
  - Table
  - ReadWrite

I think it'd be nice to be able to specify a grant per api action. Something like:

Fn::Grant: 
  - Table
  - - Query
    - PutItem

Otherwise it gets difficult for the developer to understand what the ReadWrite includes. Does it allow DeleteItem for example?

jdub commented 1 year ago

This does have some drawbacks.

Grants are yet another thing for users to learn, and for AWS to maintain and document. We already have policies to define collections of permissions. Perhaps they could be improved.

From a security point of view, I'd still need to understand which permissions are part of the grant. Already we see @ljacobsson's question about whether ReadWrite implies DeleteItem. I'd still need to look up the documentation whether I was choosing actions or grants.

I'd hope that individual grants would only apply to a specific resource type (S3 buckets vs. objects, not both), which increases the number of grant definitions and would pull them closer to the complexity of actions.