How can I use IAM roles to restrict API calls from specific IP addresses to the AWS Management Console?

Last updated: 2020-11-25

I want to restrict access to AWS API calls to specific IP addresses. How can I use AWS Identity and Access Management (IAM) roles to limit access from API calls to the AWS Management Console?

Short description

You can use the aws:SourceIp global condition key in the condition element of an IAM policy to restrict API calls from specific IP addresses. However, this denies access to AWS services, such as AWS CloudFormation, that make calls on your behalf.

For example, assume that you have an AWS service role that allows AWS CloudFormation to call Amazon Elastic Compute Cloud (Amazon EC2) to stop an instance. The request is denied, because the target service (Amazon EC2) sees the IP address of the calling service (AWS CloudFormation) instead of the IP address of the originating user. You can't pass the originating IP address through a calling service to the target service for evaluation in an IAM policy.

Resolution

Create an IAM role that has the same set of permissions attached to it as the IAM policy that's attached to the IAM user. The IAM user will have permissions only to assume the role sts:AssumeRole API if the request is coming from the specified IP address. This is because of the aws:SourceIp restriction check that's performed when the user tries to assume the role. When the user assumes the IAM role, they acquire the permissions of the IAM policy that's attached to it. Because the IAM policy attached to the role doesn't use the aws:SourceIp condition key, access to AWS services are allowed.

Create the following IAM policy, and then attach this policy to an IAM user who has programmatic access. This IAM policy allows the IAM user to AssumeRole with the role name Bob. Bob doesn't need additional permissions. All other necessary permissions are acquired when the IAM user successfully assumes the role Bob.

Note:

Example IAM user policy

This example policy has permissions to perform API calls on the resources in the account.

{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::EXAMPLEIAMACCOUNTID:role/Bob"
}
}

Create the IAM role Bob to delegate permissions to the IAM user. Follow the instructions for Creating an IAM Role (Console). You can also use the AWS CLI or API.

Note:

  • When using the console to create the role, modify the role's trust policy similar to this example for the Bob trust policy. By using the AWS CLI create-role or API CreateRole, you can pass the trust relationship policy document as a value in the update-assume-role-policy document parameter.
  • The request must come from the specified IP address range 103.15.250.0/24 or 12.148.72.0/23, or the IAM user won't be able to assume the role and make API calls.

Example IAM role trust policy

This example trust policy allows the user to assume the role if the request is coming from the IP address range 103.15.250.0/24 or 12.148.72.0/23.

Note: Replace YOURIAMUSERNAME with your IAM user name.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::account-id:user/YOURIAMUSERNAME"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Effect": "Deny",
      "Principal": {
        "AWS": "arn:aws:iam::account-id:user/YOURIAMUSERNAME"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": [
            "103.15.250.0/24",
            "12.148.72.0/23"
          ]
        }
      }
    }
  ]
}

Note: This workaround disrupts the CloudTrail logs because actions are performed by the IAM role that the user assumed, not the IAM user. The assumeRole API call performed by the IAM user are logged in CloudTrail logs under the IAM user. Any additional API calls performed by the IAM role are logged in CloudTrail logs under the role name.

You can also use an IAM policy that denies access to all AWS actions in the account when the request comes from principals outside the specified IP range. For more information, see AWS: Deny access to AWS based on the source IP.


Did this article help?


Do you need billing or technical support?