특정 IP 주소에만 액세스를 허용하도록 HTTP API를 구성하려면 어떻게 해야 합니까?

4분 분량
0

AWS Lambda 함수와 HTTP API를 통합하여 특정 IP 주소만 권한을 부여하고 허용하고 싶습니다.

간략한 설명


사전 정의된 특정 IP 주소에 대한 HTTP API 액세스를 제한하려면 권한 부여자로 Lambda 함수를 배포하십시오. Lambda 함수는 들어오는 요청이 승인된 소스에서 시작되었는지 확인하기 위해 IP 주소 검증을 수행합니다. 그런 다음 권한 부여자는 IP 주소를 기반으로 HTTP API에 대한 액세스를 허용하거나 거부합니다.

해결 방법

Lambda 함수 생성

먼저 권한 부여자로 사용할 Lambda 함수를 생성합니다. Lambda 함수를 구성하여 허용 목록에 환경 변수를 사용할 수 있습니다.

Key: IP_RANGE, Value: ['0.0.0.0','XX.XX.XX.XX']

은 허용하려는 특정 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 공식
AWS 공식업데이트됨 일 년 전