Skip to main content

Hardening STS AssumeRole for AWS Services

·3 mins

No Entry (You too, AWS Services.) #

Test

Often I see examples where an AWS service needs to assume an IAM role, but provide no verification the service is being called by an account that is trusted.

For instance, here’s a snippet from an AWS blog post, Simplifying Cross Account Access with Amazon EventBridge Resource Policies:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
CentralEventBusToInvoiceProcessingEventBusRole:
  Type: 'AWS::IAM::Role'
  Properties:
    AssumeRolePolicyDocument:
      Version: 2012-10-17
      Statement:
        - Effect: Allow
          Principal:
            Service:
            - events.amazonaws.com
          Action:
            - 'sts:AssumeRole'
    Path: /
    Policies:
      - PolicyName: PutEventsOnInvoiceProcessingEventBus
        PolicyDocument:
          Version: 2012-10-17
          Statement:
            - Effect: Allow
              Action: 'events:PutEvents'
              Resource: !GetAtt InvoiceProcessingEventBus.Arn

In the above example, events.amazonaws.com is allowed to assume the IAM role to perform an action; however, no verification is done to ensure events.amazonaws.com is doing those actions on behalf of an account you trust. What if a malicious actor knew this IAM role ARN, had intimate knowledge of the account’s event rules, and fashioned their own EventBridge infrastructure to assume the role and place an event?

Notice: Some AWS services may protect against this type of abuse, but it isn’t clearly defined in the documentation that I could find. If you have anything clearly explaining this please forward it my way on LinkedIn.

Either way, I prefer to explicitly protect against this.

The above example is for events.amazonaws.com, but there are many other AWS services that assume IAM roles in this way.

Adding a Layer of Protection #

After talking to the IAM team at AWS Support about my concerns, they helpfully pointed me to the aws:SourceAccount global condition key. This key is described as follows:

Use this key to compare the account ID of the resource making a service-to-service request with the account ID that you specify in the policy.

After testing, I confirmed that this condition can be applied within the AssumeRolePolicyDocument to restrict the IAM role assumption unless the service is doing work on behalf of an account we trust. Our original snippet now becomes the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
CentralEventBusToInvoiceProcessingEventBusRole:
  Type: 'AWS::IAM::Role'
  Properties:
    AssumeRolePolicyDocument:
      Version: 2012-10-17
      Statement:
        - Effect: Allow
          Principal:
            Service:
            - events.amazonaws.com
          Action:
            - 'sts:AssumeRole'
          Condition:
            StringEquals:
              "aws:SourceAccount": !Ref AnAccountIdThatWeTrust
    Path: /
    Policies:
      - PolicyName: PutEventsOnInvoiceProcessingEventBus
        PolicyDocument:
          Version: 2012-10-17
          Statement:
            - Effect: Allow
              Action: 'events:PutEvents'
              Resource: !GetAtt InvoiceProcessingEventBus.Arn

Now we can rest easy knowing this role will only get used by events.amazonaws.com when it’s doing work for an account we trust.

Closing Thoughts #

The big takeaway I hope that you get from this post is that AWS services can be used by bad actors. AWS may provide some protections against this at their level, but you shouldn’t depend on that when you can explicitly define that protection yourself.

Also, aws:SourceAccount isn’t the only condition key you can use to secure this. For instance, you may want to try aws:PrincipalOrgPaths instead if you have a role that needs to be assumed by several accounts within an AWS Organization. In my experience availability of these keys seems to vary service to service, so you may have to try it out on your own or discuss it with AWS Support if you have a special use case. See the Global Condition Keys for more ideas on how you can secure this.