Igor Zinkovsky
Igor Zinkovsky

Reputation: 81

API Gateway resource policy: specify IAM role as AWS principal

I am trying to setup an API Gateway endpoint with a resource policy, which allows access to a specific IAM role in my account. The IAM role is cross-account, setup with a trust policy which allows AssumeRole to a specific IAM user principal from another account.

In the API Gateway resource policy, when I set AWS principal to the role ARN: arn:aws:iam::********:role/myRole, I get the following 403 error when invoking the API:

User: arn:aws:sts::********:assumed-role/myRole/mySession is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:us-west-2:********:********/test/POST/echo

But, if I change the AWS principal to be the temporary STS user ARN: arn:aws:sts::********:assumed-role/myRole/mySession, then I can invoke the API successfully.

Here's the resource policy that doesn't work:

{
"Version": "2012-10-17",
"Statement": [
    {
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::********:role/myRole"
        },
        "Action": "execute-api:Invoke",
        "Resource": "arn:aws:execute-api:us-west-2:********:********/*"
    }
]

}

Here's the resource policy that works:

{
"Version": "2012-10-17",
"Statement": [
    {
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:sts::********:assumed-role/myRole/mySession"
        },
        "Action": "execute-api:Invoke",
        "Resource": "arn:aws:execute-api:us-west-2:********:********/*"
    }
]

}

Can IAM roles be used as AWS principals for API Gateway resource policy?

Upvotes: 8

Views: 4535

Answers (3)

mxxk
mxxk

Reputation: 10264

Actually, it looks like it is possible to grant access to an IAM role session principal by specifying the underlying role ARN in the Principal element of a REST API resource policy in API Gateway.

Did AWS IAM policy evaluation logic change?

As stated in the original question, this was previously not possible. The same was confirmed in September 2022 in another, very similar question: AWS IAM role principal vs role session principal.

If I had to guess, IAM policy evaluation logic had been changed since then; that would explain the difference in behavior.

Steps to reproduce

  1. Create a role (EmptyRole) which has no permissions (identity-based policies), but has a trust policy which allows it to be assumed.

  2. Create a Rest API in API Gateway.

  3. Set a resource policy on the API which grants access to the EmptyRole role ARN:

    {
        "Version": "2012-10-17",
        "Statement": {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::${ACCOUNT_ID}:role/EmptyRole"
            },
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:us-west-2:${ACCOUNT_ID}:${API_ID}/*"
        }
    }
    
  4. Add a new method under the / resource:

    Method details

    Method request settings

    • Authorization: AWS IAM
  5. Deploy the API to a stage (dev).

  6. Make an AWS4 signed request against the dev stage API Gateway URL. For example:

    import aws4 from "aws4";
    
    const API_ID = "...";
    const STAGE_NAME = "dev";
    
    async function main() {
      const options = aws4.sign({
        headers: {},
        path: `/${STAGE_NAME}`,
        method: "GET",
        host: `${API_ID}.execute-api.${process.env.AWS_REGION}.amazonaws.com`,
        service: "execute-api",
        region: process.env.AWS_REGION,
      });
      const url = new URL(`https://${options.host}`);
      url.pathname = options.path;
      const response = await fetch(url, {
        method: options.method,
        headers: options.headers,
      });
      console.log(`${response.status} ${response.statusText}`);
      console.log(await response.text());
    }
    
    await main();
    

For more information...

See https://stackoverflow.com/a/73696226/1727828. It contains more details around using an IAM role ARN in the Principal element of a resource-based policy, and contains relevant references to AWS documentation.

Upvotes: 1

Ivan Samygin
Ivan Samygin

Reputation: 4581

You can achieve this by specifying the role in the condition element of the policy (see an explanation below):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:us-west-2:********:********/*",
            "Condition": {
                "ArnEquals": {
                    "aws:PrincipalArn": "arn:aws:iam::********:role/myRole"
                }
            }
        }
    ]
}

Here's the fragment of the docs with an explanation (link):

you can specify the role principal as the principal in a resource-based policy or create a broad-permission policy that uses the aws:PrincipalArn condition key. When you use this key, the role session principal is granted the permissions based on the ARN of role that was assumed, and not the ARN of the resulting session. Because AWS does not convert condition key ARNs to IDs, permissions granted to the role ARN persist if you delete the role and then create a new role with the same name. Identity-based policy types, such as permissions boundaries or session policies, do not limit permissions granted using the aws:PrincipalArn condition key with a wildcard(*) in the Principal element, unless the identity-based policies contain an explicit deny.

See also APIGW resource policy condition keys

So there are two consequences that needs to be taken seriously for sensitive solutions (as stated in the doc):

  • If the role is assumed with additional session policies passed (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session), they won't be evaluated;
  • Role replacement attack won't be noticed - if an attacker manages to delete and create a role with the same name (but perhaps different set of permissions), the access will remain. In contrast, when Principal element of the resource policy is used, the policy needs to be updated after role replacement to keep an access.

Upvotes: 1

Vighnesh
Vighnesh

Reputation: 97

Based on the documentation https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-policy-language-overview.html,

Principal – The account or user who is allowed access to the actions and resources in the statement. In a resource policy, the principal is the IAM user or account who is the recipient of this permission.

Looks like roles cannot be added as a principal.

P.S: Spent two days trying to restrict access using roles, but couldn't get it to work.

Upvotes: 1

Related Questions