aws / aws/serverless-application-model

Feature Request: Create "Encrypted" Variants of Some Policy Templates

Open
#1,959 0 comments 0 reactions 0 assignees View on GitHub
area/policy-templates maintainer/need-response type/feature
Dominant language
Python
Stars
9.6k
Forks
2.5k
Avg merge
1d 11h
Merged PRs (30d)
7

Description

### Describe your idea/feature/enhancement

When using KMS with various AWS resources, it can be undesirable to give a Function (or a State Machine – anything which can take a SAM Policy Template, I guess) blanket `kms:Decrypt` for a particular key in order to augment, say, `AWSSecretsManagerGetSecretValuePolicy`, `DynamoDBCrudPolicy` or the like. Through KMS, IAM has `Condition`s which can read the encryption context of a particular request, narrowing the scope of the permissions. As an example:

```yaml
- AWSSecretsManagerGetSecretValuePolicy:
SecretArn: !Ref MySecret
```

…transforms into (effectively):

```json
{
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": { "Ref": "MySecret" }
}
]
}
```

…with the user of the Policy Template also having to add `KMSDecryptPolicy` to the same resource when the Secret is encrypted with a CMK. These could be combined into one while narrowing the scope of the KMS permissions like this:

```yaml
- Encrypted-AWSSecretsManagerGetSecretValuePolicy: # This name is very much not a recommendation.
SecretArn: !Ref MySecret
KeyId: !Ref MyKey
```

…transforming into (effectively):

```json
{
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": { "Ref": "MySecret" }
},
{
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": {
"Fn::Sub": [
"arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:key/${keyId}",
{
"keyId": { "Ref": "KeyId" }
}
]
},
"Condition": {
"StringEquals": {
"kms:ViaService": { "Fn::Sub": "secretsmanager.${AWS::Region}.${AWS::URLSuffix}" }
},
"ForAnyValue:ArnEquals": {
"kms:EncryptionContext:SecretARN": { "Ref": "MySecret" }
}
}
}
]
}
```

Knowing the context in which the key will be used allows the permissions to be narrowed greatly.

This would also provide ergonomics where it would be silly to provide every possible IAM permission as a separate SAM Policy Template. For example, to publish to an encrypted SNS topic, a Function requires:

- `kms:Encrypt`
- `kms:GenerateDataKey`
- `sns:Publish`

…for only two of which does a SAM Policy Template exist. A template for `kms:GenerateDataKey` has been requested, but matching the template to the use case would obviate such requests:

```yaml
- Encrypted-SNSPublishMessagePolicy:
TopicName: !GetAtt MyTopic.TopicName
KeyId: !Ref MyKey
```

…the transformation of which, I hope, is straightforward. (I'm getting tired of doing it by hand. 😝)

### Proposal

When I am able, I can go through the existing SAM Policy Templates to audit which would benefit from an "Encrypted" variant. I can then list which `kms:` permissions such a variant would use, then really dig into the documentation and list the encryption contexts each of those operations accepts. From that point, it's only a matter of plugging them into the document which defines the policy templates.

Oh, and naming. We'd have to decide on naming. Possibly the hardest part.

Things to consider:
[x] The [SAM documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification.html) will need to be updated

### Additional Details

I wonder if some kind of smart use of `Fn::If` or its like would allow `KeyId` to become an optional parameter to the existing templates. Where leaving it out would have the template transform exactly as it does today.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.