

https://{rest-api-id}-{vpce-id}.execute-api.{region}.amazonaws.com/{stage}와 같은 형태의 URL을 사용해야만 해서 어떤 API인지 직관적으로 파악하기 어려웠습니다.
하지만 24년 11월 AWS API Gateway가 Private REST API의 사용자 지정 도메인을 공식 지원하면서, 이제 우리만의 도메인으로 내부 API를 깔끔하게 관리할 수 있게 되었습니다.
AWS Lambda 함수를 VPC 내부에 배포하고, 이를 API Gateway의 Private REST API와 연동한 뒤, Route 53 Private Hosted Zone을 통해 private.mydomain.com과 같은 사용자 지정 도메인을 연결하는 전체 과정을 단계별로 상세히 알아보겠습니다.

VPC 내부의 리소스가 Route 53 Private Hosted Zone을 통해 private.bamtoly.com을 질의하면, VPC Endpoint를 통해 API Gateway로 라우팅되고, 최종적으로 VPC 내의 Lambda 함수를 호출하여 응답을 받습니다.
먼저, API Gateway에 Rest API로 연결할 Lambda 함수를 만들겠습니다.
API Gateway는 람다 뿐만 아니라, 다른 AWS 서비스 와 연동할 수 있으나 실습을 위해 람다를 연결 하는 방법으로 실습 하도록 하겠습니다.



Deploy 버튼을 눌러서 배포 해줍시다.
200 성공이 뜨는 것을 볼 수 있습니다.아래는 작성 코드 입니다.
/**
 * Lambda handler for API Gateway (Proxy Integration)
 * Expects event.body to be a JSON string:
 *   { type: "stringify" | "parse", data: any }
 */
export const handler = async (event) => {
  try {
    // 1) body 파싱
    const body = typeof event.body === 'string'
      ? JSON.parse(event.body)
      : event.body;
    const { type, data } = body ?? {};
    // 2) type에 따라 처리
    let result;
    if (type === 'stringify') {
      // data를 JSON 문자열로 변환
      result = JSON.stringify(data);
    }
    else if (type === 'parse') {
      // data가 문자열인지 검증
      if (typeof data !== 'string') {
        return {
          statusCode: 400,
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            error: '`data` must be a string when type is "parse"'
          }),
        };
      }
      // 문자열을 객체로 파싱
      result = JSON.parse(data);
    }
    else {
      // 허용되지 않은 type
      return {
        statusCode: 400,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          error: 'Invalid `type` field: must be "stringify" or "parse".'
        }),
      };
    }
    // 3) 성공 응답
    return {
      statusCode: 200,
      headers: { 'Content-Type': 'application/json' },
      body: result,
    };
  }
  catch (err) {
    // 파싱 에러나 그 외 예외 처리
    return {
      statusCode: 500,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        error: err.message ?? 'Internal Server Error'
      }),
    };
  }
};
/* 테스트 데이터
{
  "body": { "type": "stringify", "data":{"foo":123,"bar":"baz"}}
}
*/
API Gateway의 Private REST API 를 사용하기 위해서는 VPC Endpoint 를 통해서 사용 해야 합니다.

엔드포인트 탭 > 엔드포인트 생성 을 클릭 합니다

AWS 서비스 클릭 → 서비스 이름이 = com.amazonaws-ap-northeast-2-excute-api 인 서비스 선택

Private 서브넷을 서브넷으로 선택하여 네트워크 설정을 합니다.

이렇게 하면 VPC 엔드포인트가 생성 된 것을 확인 할 수 있습니다. 그리고 VPC Endpoint ID를 이제 사용 하러 가봅시다

API Gateway 에 들어가 API 생성 버튼을 클릭합니다.

그러면 위와 같은 이미지가 나오는데, REST API 프라이빗 을 구축 하도록 합니다.

화면에서 엔드포인트 유형 > 프라이빗 > VPC 엔드포인트 ID 에 방금 생성 하였던 VPC 엔드포인트 ID 를 작성 해줍시다.

✂️ API Gateway 리소스 생성 방법은 과감하게 스킵 하도록 하겠습니다.
그리고 리소스 생성 버튼을 클릭해서, POST 메소드 에 람다를 통합 해줍시다.

그리고 API 배포 버튼을 클릭 후 새 스테이지를 만들어서 배포를 시작합니다.

이렇게 배포 할경우 배포 가 실패 할 것입니다 ㅠㅠ

Private REST API dosen't have a resource policy attached to it 에러를 통해서 리소스정책이 부여하면 해결 될 것을 알 수 있습니다.

아래와 같이 리소스 정책을 부여 하고, 다시 배포를 하면 배포가 성공 하게 됩니다.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": [
                "execute-api:/*"
            ]
        },
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": [
                "execute-api:/*"
            ],
            "Condition" : {
                "StringNotEquals": {
                    "aws:SourceVpce": <VPC Endpoint Id>
                }
            }
        }
    ]
}
사용자 지정 도메인 이름 을 생성 하러 가야 합니다.


도메인 이름 생성시, 자신이 가지고 있는 도메인을 이용하여 원하는 도메인 이름을 설정 하고 프라이빗 으로 설정 해줍니다.

프라이빗으로 설정 후 도메인 이름 추가 하면 위와 같이 생성됨을 확인 할 수 있습니다.
새로 생성한 도메인 이름으로 들어가서 아래로 내리면 API 매핑 을 선택 할 수 있는 탭이 나옵니다.
이 탭은 생성 했던 API Gateway 의 REST API와 매핑 할 수 있게 해줍니다.

여기서 끝이 아닙니다.. 리소스 공유 탭 > 도메인 연결 생성 클릭 후, 생성한 사용자 지정 도메인 이름 과 VPC Endpoint ID 와 연결을 해줘야 합니다.


여기서 끝이 아닙니다..(2) 해당 사용자 지정 도메인 이름 에 대한 리소스 정책을 설정 해줘야 합니다. (VPC Endpoint 만 접속 할 수 있도록) 위에서 작성한 정책을 그대로 복사해서 사용 하시면 됩니다.


여기까지 오셨으면 다했습니다. 이제 Route53 에서 해당 도메인에 대한 레코드 정책 을 생성 해주면 끝! 입니다. 
✂️ Route53 호스팅영역 생성 및 레코드에 대한 자세한 설명은 스킵 하도록 하겠습니다.
Route53에 등록한 자신의 호스팅 영역 에 들어가 레코드 생성 을 클릭합시다.
그리고, 이미지에 나와 있는 순서대로 트래픽 라우팅 대상 을 VPC Endpoint 로 가도록 설정 합니다.


저는 단순히, 해당 API Gateway의 엔드포인트를 테스트 하기 위해서 함수를 호출 하는 Lambda 함수를 만들었습니다.
Private Subnet 에 Lambda를 위치시켜 호출 하는경우이 두가지에 대해서 테스트 하도록 하겠습니다.


private.bamtoly.com 을 대상으로 호출 하였으나, 500 에러 가 나왔음을 확인 할 수 있습니다. 외부에서 Private 망에 통신할 수 없기 때문에 정상적으로 실패함을 확인 할 수 있습니다.

API Gateway Private RestAPI 가 속한 VPC 및 Subnet 으로 설정 하였습니다.

Private VPC 내 에서  private.bamtoly.com 으로 API 를 호출 해보니, 정상적으로 호출이 되며 통신이 되는 것을 확인 했습니다.24년 11월에 생긴 사용자 지정 도메인 이름 (Private REST API) 이 없을 때는, VPC Endpoin ID 를 Header에 보내거나 VPC Endpoint 를 통한 Private API 간접 호출을 아래와 같이 진행 하여 어떤 도메인의 API 인지 예측하기 어려웠습니다.
https://{rest-api-id}-{vpce-id}.execute-api.{region}.amazonaws.com/{stage}
사용자 지정 도메인을 통해 내부 Private API 요청을 할 때 내 도메인으로 요청하여 조금더 통일성을 주는 것은 어떨까요 ㅎ