Use the Conformity Knowledge Base AI to help improve your Cloud Posture

Limit REST API Access by IP Address

Trend Cloud One™ – Conformity is a continuous assurance tool that provides peace of mind for your cloud infrastructure, delivering over 1000 automated best practice checks.

Risk Level: Medium (should be achieved)

Ensure that Amazon API Gateway API access is limited only to specific (trusted) IP addresses or range of IP addresses in order to protect your REST APIs against unapproved access.

Security

Allowing untrustworthy access to your Amazon API Gateway APIs can lead to unauthorized API invocation. To prevent API exposure, you can use the API resource policies to allow your REST APIs to be securely invoked by trusted IP addresses and/or IP address ranges.


Audit

To determine if the access to your Amazon API Gateway REST APIs is restricted to specific IP addresses/ranges, perform the following operations:

Using AWS Console

01 Sign in to the AWS Management Console.

02 Navigate to Amazon API Gateway console at https://console.aws.amazon.com/apigateway/.

03 In the left navigation panel, select APIs to access the Amazon API Gateway APIs listing page.

04 Click on the name of the REST API that you want to examine to access the API configuration. To identify a REST API check the value available in the Protocol column for each listed API.

05 In the navigation panel, within the API submenu, choose Resource Policy to access the resource policy attached to the selected API. An API resource policy is a JSON policy document that you can attach to your API in order to control whether a specified AWS principal (typically an IAM user or role) can invoke your API.

06 Inside the Resource Policy document box, search for the "Condition" policy element that contains the "aws:SourceIp" condition key, e.g. "Condition" : { "IpAddress": { "aws:SourceIp": [ "192.0.2.0/32" ] } }, where "192.0.2.0/32" is the trusted IP address that can access your REST API. The "Condition" element lets you specify conditions for when an access policy is in effect. Within the "Condition" element block you build expressions in which you use operators to match the condition in the policy against the values in the request. The "Condition" values can include the IP address of the requester, date, time, the ARN of the request source, the user name, the user ID or the user agent of the requester. For this conformity rule, the "Condition" element values must include one or more IP addresses in combination with the "Effect" element set to "Allow", which allows access based on trusted IP addresses only. If the "Condition" element does not include "aws:SourceIp" key or the "Condition" element block is not defined within the policy document, the access to the selected Amazon API Gateway REST API is not limited to trusted IP addresses/ranges only.

07 Repeat steps no. 4 – 6 for each REST API available within the current AWS cloud region.

08 Change the AWS region from the navigation bar and repeat the audit process for other regions.

Using AWS CLI

01 Run get-rest-apis command (OSX/Linux/UNIX) with custom query filters to list the IDs of the REST APIs created in the selected AWS cloud region:

aws apigateway get-rest-apis
  --region us-east-1
  --output table
  --query 'items[*].id'

02 The command output should return a table with the requested API identifiers (IDs):

----------------
|  GetRestApis |
+--------------+
|  aaabbbbccc  |
|  aabbccddee  |
|  abcdabcdab  |
+--------------+ 

03 Run get-rest-api command (OSX/Linux/UNIX) using the ID of the REST API that you want to examine as the identifier parameter and custom query filters to describe the resource policy attached to the selected API:

aws apigateway get-rest-api
  --region us-east-1
  --rest-api-id aaabbbbccc
  --query 'policy'

04 The command output should return the attached resource policy in JSON format:

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Deny",
			"Principal": "*",
			"Action": "execute-api:Invoke",
			"Resource": "arn:aws:execute-api:us-east-1:123456789012:aaabbbbccc///",
			"Condition": {
				"StringNotEquals": {
					"aws:sourceVpc": "vpc-abcdabcd"
				}
			}
		},
		{
			"Effect": "Allow",
			"Principal": "*",
			"Action": "execute-api:Invoke",
			"Resource": "arn:aws:execute-api:us-east-1:123456789012:aaabbbbccc///"
		}
	]
}

Search the policy document returned by the get-rest-api command output for the "Condition" element that contains the "aws:SourceIp" condition key, e.g. "Condition" : { "IpAddress": { "aws:SourceIp": [ "192.0.5.0/32" ] } }, where "192.0.5.0/32" is the trusted IP address that can access your REST API. For compliance, the "Condition" element values must include one or more IP addresses in combination with the "Effect" element set to "Allow", which allows access based on trusted IP addresses only. If the "Condition" element does not include "aws:SourceIp" key or the "Condition" element block is not defined within the policy document, the access to the selected Amazon API Gateway REST API is not limited to trusted IP addresses/ranges only.

05 Repeat steps no. 3 and 4 for each REST API available in the selected AWS cloud region.

06 Change the AWS region by updating the --region command parameter value and repeat steps no. 1 – 5 to perform the audit process for other regions.

Remediation / Resolution

To enforce access to Amazon API Gateway REST APIs from specific (trusted) IP addresses/ranges only using API resource policies, perform the following operations:

Using AWS CloudFormation

01 CloudFormation template (JSON):

{
	"AWSTemplateFormatVersion": "2010-09-09",
	"Description": "Allows Access from Specific IP Addresses",
	"Resources": {
		"RestAPI": {
			"Type": "AWS::ApiGateway::RestApi",
			"Properties": {
				"Name": "WebServiceRestAPI",
				"Description": "A simple API Gateway REST API",
				"Policy": {
					"Version": "2012-10-17",
					"Statement": [
						{
							"Effect": "Allow",
							"Principal": "*",
							"Action": "execute-api:Invoke",
							"Resource": "arn:aws:execute-api:us-east-1:123456789012:aaabbbbccc/Production/*",
							"Condition": {
								"IpAddress": {
									"aws:SourceIp": [
										"192.0.5.0/32",
										"198.40.100.0/32"
									]
								}
							}
						}
					]
				}
			}
		},
		"StageDeployment": {
			"Type": "AWS::ApiGateway::Deployment",
			"Properties": {
				"RestApiId": {
					"Ref": "RestAPI"
				}
			}
		},
		"APIStage": {
			"Type": "AWS::ApiGateway::Stage",
			"Properties": {
				"DeploymentId": {
					"Ref": "StageDeployment"
				},
				"RestApiId": {
					"Ref": "RestAPI"
				},
				"StageName": "Production"
			}
		}
	}
}

02 CloudFormation template (YAML):

AWSTemplateFormatVersion: '2010-09-09'
	Description: Allows Access from Specific IP Addresses
	Resources:
	RestAPI:
		Type: AWS::ApiGateway::RestApi
		Properties:
		Name: WebServiceRestAPI
		Description: A simple API Gateway REST API
		Policy:
			Version: '2012-10-17'
			Statement:
			- Effect: Allow
				Principal: '*'
				Action: execute-api:Invoke
				Resource: arn:aws:execute-api:us-east-1:123456789012:aaabbbbccc/Production/*
				Condition:
				IpAddress:
					aws:SourceIp:
					- 192.0.5.0/32
					- 198.40.100.0/32
	StageDeployment:
		Type: AWS::ApiGateway::Deployment
		Properties:
		RestApiId: !Ref 'RestAPI'
	APIStage:
		Type: AWS::ApiGateway::Stage
		Properties:
		DeploymentId: !Ref 'StageDeployment'
		RestApiId: !Ref 'RestAPI'
		StageName: Production

Using Terraform (AWS Provider)

01 Terraform configuration file (.tf):

terraform {
	required_providers {
		aws = {
			source  = "hashicorp/aws"
			version = "~> 4.0"
		}
	}

	required_version = ">= 0.14.9"
}

provider "aws" {
	profile = "default"
	region  = "us-east-1"
}

resource "aws_api_gateway_rest_api" "rest-api" {
	name        = "web-service-rest-api"
	description = "A simple API Gateway REST API"
}

# Allows Access from Specific IP Addresses
data "aws_iam_policy_document" "iam-policy-document" {
	statement {
		effect = "Allow"

		principals {
			type        = "AWS"
			identifiers = ["*"]
		}

		actions   = ["execute-api:Invoke"]
		resources = [aws_api_gateway_rest_api.rest-api.execution_arn]

		condition {
			test     = "IpAddress"
			variable = "aws:SourceIp"
			values   = ["192.0.5.0/32","198.40.100.0/32"]
		}
	}
}

resource "aws_api_gateway_rest_api_policy" "rest-api-policy" {
	rest_api_id = aws_api_gateway_rest_api.rest-api.id
	policy      = data.aws_iam_policy_document.iam-policy-document.json
}

resource "aws_api_gateway_deployment" "rest-api-deployment" {
	rest_api_id = aws_api_gateway_rest_api.rest-api.id
}

resource "aws_api_gateway_stage" "api-stage" {
	deployment_id = aws_api_gateway_deployment.rest-api-deployment.id
	rest_api_id   = aws_api_gateway_rest_api.rest-api.id
	stage_name    = "Production"
}

Using AWS Console

01 Sign in to the AWS Management Console.

02 Navigate to Amazon API Gateway console at https://console.aws.amazon.com/apigateway/.

03 In the left navigation panel, select APIs to access the Amazon API Gateway APIs listing page.

04 Click on the name of the REST API that you want to reconfigure (see Audit section part I to identify the right API) to access the API configuration.

05 In the navigation panel, within the API submenu, choose Resource Policy to access the resource policy attached to the selected API.

06 Within the Resource Policy editor box, find the policy statement with the "Effect" set to "Allow" and the "Action" set to "execute-api:Invoke", and append the following "Condition" element: "Condition" : { "IpAddress": { "aws:SourceIp": ["192.0.5.0/32", "198.40.100.0/32" ] }, where 192.0.5.0 and 198.40.100.0 are examples of trusted IP addresses that can invoke the selected Amazon API Gateway API (replace the described IP(s) with your own trusted IP(s)). Choose Save to apply the changes. Once the API policy has been successfully updated, only requests that originate from the IP addresses specified in the "Condition" element value can reach the selected API.

07 Repeat steps no. 4 – 6 to reconfigure other Amazon API Gateway APIs available within the current AWS region.

08 Change the AWS cloud region from the navigation bar and repeat the remediation process for other regions.

Using AWS CLI

01 Modify the existing resource policy attached to the Amazon API Gateway API that you want to reconfigure (see Audit section part II to identify the attached resource policy), to append the following "Condition" element: "Condition" : { "IpAddress": { "aws:SourceIp": ["192.0.5.0/32", "198.40.100.0/32" ] }, where 192.0.5.0 and 198.40.100.0 are examples of trusted IP addresses that can invoke the selected API (replace the described IP(s) with your own trusted IP(s)). Make sure that the "Effect" is set to "Allow" and the "Action" is set to "execute-api:Invoke", e.g.:

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Effect": "Deny",
			"Principal": "*",
			"Action": "execute-api:Invoke",
			"Resource": "arn:aws:execute-api:us-east-1:123456789012:aaabbbbccc///",
			"Condition": {
				"StringNotEquals": {
					"aws:sourceVpc": "vpc-abcdabcd"
				}
			}
		},
		{
			"Effect": "Allow",
			"Principal": "*",
			"Action": "execute-api:Invoke",
			"Resource": "arn:aws:execute-api:us-east-1:123456789012:aaabbbbccc///",
			"Condition" : {
				"IpAddress": {
					"aws:SourceIp": ["192.0.5.0/32", "198.40.100.0/32" ]
				}
			}
		}
	]
}

02 Run update-rest-api command (OSX/Linux/UNIX) using the ID of the REST API that you want to reconfigure as the identifier parameter, to replace the existing resource policy attached to the selected API with the one modified at the previous step. Replace jsonEscapedPolicyDocument placeholder with your properly-escaped JSON policy document:

aws apigateway update-rest-api
  --region us-east-1
  --rest-api-id aaabbbbccc
  --patch-operations op=replace,path=/policy,value='{\"jsonEscapedPolicyDocument\"}'

03 The command output should return the metadata available for the reconfigured API:

{
	"id": "aaabbbbccc",
	"name": "cc-project5-api",
	"description": "Project5 Web API",
	"createdDate": "2021-02-04T10:00:00+00:00",
	"apiKeySource": "HEADER",
	"endpointConfiguration": {
		"types": [
			"REGIONAL"
		]
	},
	"policy": "{\\\"Version\\\":\\\"2012-10-17\\\",\\\"Statement\\\":[{\\\"Effect\\\":\\\"Deny\\\",\\\"Principal\\\":\\\"*\\\",\\\"Action\\\":\\\"execute-api:Invoke\\\",\\\"Resource\\\":\\\"arn:aws:execute-api:us-east-1:123456789012:aaabbbbccc\\/\\/\\/\\\",\\\"Condition\\\":{\\\"StringNotEquals\\\":{\\\"aws:sourceVpc\\\":\\\"vpc-abcdabcd\\\"}}},{\\\"Effect\\\":\\\"Allow\\\",\\\"Principal\\\":\\\"*\\\",\\\"Action\\\":\\\"execute-api:Invoke\\\",\\\"Resource\\\":\\\"arn:aws:execute-api:us-east-1:123456789012:aaabbbbccc\\/\\/\\/\\\",\\\"Condition\\\":{\\\"IpAddress\\\":{\\\"aws:SourceIp\\\":[\\\"192.0.5.0\\/32\\\",\\\"198.40.100.0\\/32\\\"]}}}]}",
	"tags": {},
	"disableExecuteApiEndpoint": false
}

04 Repeat steps no. 1 – 3 to reconfigure other Amazon API Gateway APIs available in the selected AWS region.

05 Change the AWS cloud region by updating the --region command parameter value and repeat the remediation process for other regions.

References

Publication date Feb 6, 2021