如何配置 HTTP API 以仅允许访问特定 IP 地址?
我想将 HTTP API 与 AWS Lambda 函数集成,以便仅授权和允许特定 IP 地址。
简短描述
要限制 HTTP API 访问特定、预定义的 IP 地址,请以授权方身份部署 Lambda 函数。Lambda 函数执行 IP 地址验证,以确定传入的请求是否来自经批准的来源。然后,授权方根据 IP 地址授予或拒绝对 HTTP API 的访问权限。
解决方法
创建 Lambda 函数
首先,创建 Lambda 函数以用作授权方。您可以将 Lambda 函数配置为使用环境变量作为允许列表:
Key: IP_RANGE, Value: ['0.0.0.0','XX.XX.XX.XX']
Value(值)可以是您想要允许的特定 IP 地址,也可以是完整的 CIDR 范围。
部署代码后,为 Lambda 函数配置环境变量以将特定变量定义为 IP_RANGE。
出于安全考虑,最佳做法是使用 AWS Key Management Service (AWS KMS) 加密环境变量。
创建 HTTP API
创建 HTTP API 以用作传入请求的入口点。由于 HTTP API 在默认情况下是公共的,因此使用授权方 Lambda 函数来控制访问权限。
连接 Lambda 授权方
将 Lambda 函数作为授权方关联到 API。当请求到达 API 时,授权方会根据允许列表评估源 IP 地址。如果授权方允许 IP 地址,则会授予对 HTTP API 端点的访问权限。否则,它会拒绝该请求。
要根据列入允许列表的环境变量评估 IP 地址,请使用以下 Lambda 函数示例:
**注意:**此示例传递了一个值为 secretcode 的 authorizationtoken。但是,您可以将这些参数配置为使用其他值。
# -*- coding: utf-8 -*- # ======================== # AWS Lambda Python Runtime # ======================== # Import necessary modules import os from ipaddress import ip_network, ip_address import uuid import ast # Function to check if an IP address is within the specified IP range def check_ip(IP_ADDRESS, IP_RANGE): VALID_IP = False # Check if any of the elements in IP_RANGE contain a CIDR notation (e.g., "192.168.0.0/24") cidr_blocks = list(filter(lambda element: "/" in element, IP_RANGE)) if cidr_blocks: for cidr in cidr_blocks: # Create an IP network from the CIDR notation net = ip_network(cidr) # Check if the IP_ADDRESS is within the network VALID_IP = ip_address(IP_ADDRESS) in net if VALID_IP: break # If the IP_ADDRESS is not within any CIDR block, check if it matches an exact IP in IP_RANGE if not VALID_IP and IP_ADDRESS in IP_RANGE: VALID_IP = True return VALID_IP # Lambda function handler def lambda_handler(event, context): # Extract the source IP address from the request's RequestContext IP_ADDRESS = event["requestContext"]["http"]["sourceIp"] # Parse the IP_RANGE environment variable, which is a list of allowed IP addresses or CIDR blocks IP_RANGE = ast.literal_eval(os.environ.get("IP_RANGE", "[]")) # Check if the source IP is within the allowed IP range VALID_IP = check_ip(IP_ADDRESS, IP_RANGE) # Extract relevant information from the request event # Extract the AWS API Gateway's API ID from the event API_ID = event["requestContext"]["apiId"] # Extract the AWS account ID from the event ACC_ID = event["requestContext"]["accountId"] # Extract the AWS API Gateway's Details Method, Stage and Route from the event METHOD = event["requestContext"]["http"]["method"] STAGE = event["requestContext"]["stage"] ROUTE = event["requestContext"]["http"]["path"] # Check if the request includes a valid authorization token and the source IP is allowed # Use the {region} based on the region of the API Gateway's configuration. if event["headers"]["authorizationtoken"] == "secretcode" and VALID_IP: # If authorized, allow the execution of the API response = { "principalId": f"{uuid.uuid4().hex}", "policyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Allow", "Resource": f"arn:aws:execute-api:{region}:{ACC_ID}:{API_ID}/{STAGE}/{METHOD}{ROUTE}", } ], }, "context": {"exampleKey": "exampleValue"}, } return response # If the request is not authorized or the IP is not allowed, deny execution # Use the Acc_ID, region & API_ID as per the HTTP API ID Details response = { "principalId": f"{uuid.uuid4().hex}", "policyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Deny", "Resource": f"arn:aws:execute-api:{region}:{ACC_ID}:{API_ID}/*/*/*", } ], }, "context": {"exampleKey": "exampleValue"}, } return response
**注意:**如果您需要其他 Python 模块,则使用 pip 将模块安装到 Lambda 函数的环境中。使用所需的依赖项打包 Lambda 函数。
测试您的授权方
在将函数部署到生产环境之前,请务必在测试环境中测试该函数。要检查要访问 HTTP API 端点的 IP 地址,请使用访问日志记录。使用上下文变量识别 IP 地址,并通过 IP_RANGE 环境变量将该地址纳入您的允许列表。以下示例包含用于在 HTTP API 中记录访问权限的上下文变量:
{"ownerAccountId":"$context.accountId","apiId":"$context.apiId","requestId":"$context.requestId", / "ip":"$context.identity.sourceIp","requestTime":"$context.requestTime","httpMethod":"$context.httpMethod", / "routeKey":"$context.routeKey","status":"$context.status","protocol":"$context.protocol", / "responseLength":"$context.responseLength","errorMessage":"$context.error.message", / "errorMessageString":"$context.error.messageString","extendedRequestId":"$context.extendedRequestId", / "responseLatency":"$context.responseLatency","stage":"$context.stage","path":"$context.path", / "requestTimeEpoch":"$context.requestTimeEpoch","protocol":"$context.protocol","userAgent":"$context.identity.userAgent", / "errorResponseType":"$context.error.responseType","integrationStatus":"$context.integration.status", / "integrationErrorMessage":"$context.integrationErrorMessage","integrationRequestId":"$context.integration.requestId", / "integrationLatency":"$context.integration.latency","integrationStatusfromIntegration":"$context.integration.integrationStatus", / "integrationError":"$context.integration.error","awsEndpointRequestId":"$context.awsEndpointRequestId", / "customAuthorizerUser":"$context.identity.user","authorizerProperty":"$context.authorizer.property", / "customAuthorizerprincipalId":"$context.authorizer.principalId","authorizerError":"$context.authorizer.error"}
变量 ip":"$context.identity.sourceIp 提供请求 API 端点的 IP 地址。这使您可以识别 IP 地址并将其添加到您的允许列表中。
相关内容
- AWS 官方已更新 2 年前
- AWS 官方已更新 2 年前
- AWS 官方已更新 3 个月前
- AWS 官方已更新 2 年前