이번에 다룰 주제는 AWS API Gateway를 사용하여 REST API를 생성하고 Lambda에 연결하는 과정을 적어보도록 하겠다.
위 사진에서 보듯이 api 엔드포인트 유형이 세가지로 나뉜다.
📍리전 API : 현재 AWS 리전에 배포되어 있는 것 -> 리전간의 데이터 전송 지연 최소화
📍엣지 최적화 API : 요청을 가장 가까운 CloudFront 접속 지점으로 라우팅함 -> 전세계 요청 최적화
📍프라이빗 API : VPC에서만 액세스할 수 있음 -> vpc를 통한 연결
여기서 우리 프로젝트는 사용자의 로그인 기능과 사용자가 아직 많지 않기에 vpc 설정은 하지 않고 리전 유형을 결정하기로 했다. 하지만 나의 탐구욕은 vpc가 뭔지 너무나 궁금한 것이야. 그래서 간단히 작성해보았다. (나만 궁금한가요?)
내가 생각했을 때 간단히 정리하자면 vpc는 "나만 아는 지름길" 인 것 같다.
AWS VPC 엔드포인트는 VPC 내부 리소스가 AWS 서비스와 프라이빗하게 통신할 수 있도록 하는 네트워크 연결 메커니즘이다. 세 가지 주요 유형의 VPC 엔드포인트가 있으며, 각각의 특성과 사용 방법이 다르다.
요약하자면, 인터페이스 엔드포인트와 게이트웨이 로드 밸런서 엔드포인트는 AWS PrivateLink를 기반으로 하며, 주로 보안이 중요하고 프라이빗한 연결이 필요한 경우에 사용된다. 이들은 ENI를 통해 트래픽을 관리한다. 반면, 게이트웨이 엔드포인트는 VPC 라우팅 테이블을 이용하여 특정 AWS 서비스로의 직접적인 프라이빗 액세스를 제공한다.
즉, API Gateway에 연결하기 위해서는 Interface 엔드포인트를 선택해야한다.
근데 나만 궁금한 것인가? 1,2 번의 기술과 3번의 기술이 다르다!!
🧐 AWS PrivateLink와 VPC 라우팅 테이블을 사용해 구현되는 것의 차이가 뭘까?
AWS PrivateLink와 VPC 라우팅 테이블을 사용한 구현은 둘 다 AWS 리소스 간의 프라이빗 네트워킹 솔루션을 제공하지만, 구현 방식과 사용 사례에서 차이가 있다. 각각의 특징과 차이점을 알아보겠다.
AWS PrivateLink는 AWS 서비스, 사용자 정의 서비스, 그리고 VPC 엔드포인트 서비스 간의 안전하고 프라이빗한 연결을 가능하게 하는 서비스이다. PrivateLink를 통해 생성된 연결은 AWS 네트워크 내부에서만 발생하며, 인터넷을 경유하지 않는다.
특징:
사용 사례:
AWS 서비스와 애플리케이션을 인터넷 없이 프라이빗하게 연결하는 안전한 다리라고 할 수 있다.
VPC 라우팅 테이블은 VPC 내에서 네트워크 트래픽을 특정 대상으로 라우팅하기 위해 사용되는 규칙 또는 경로의 집합이다. VPC 내의 각 서브넷은 하나의 라우팅 테이블에 연결되며, 이를 통해 인바운드 및 아웃바운드 트래픽의 흐름을 제어한다.
특징:
사용 사례:
VPC 내에서 트래픽을 어디로 보낼지 결정하는 지도라고 생각하면 될 듯 하다.
구현 방식: AWS PrivateLink는 서비스 간의 프라이빗 연결을 위해 특별히 설계된 반면, VPC 라우팅 테이블은 VPC 내의 트래픽 흐름과 라우팅을 제어하는 데 사용된다.
보안과 프라이버시: PrivateLink는 데이터 전송 시 인터넷을 사용하지 않으므로, 더 높은 수준의 보안과 프라이버시를 제공한다. VPC 라우팅 테이블은 네트워크 트래픽의 경로를 정의하지만, PrivateLink처럼 엔드포인트 간의 직접적인 프라이빗 연결을 생성하지는 않는다.
사용 사례: PrivateLink는 특정 AWS 서비스나 사용자 정의 서비스를 다른 VPC 리소스와 안전하게 연결하는 데 적합하며, VPC 라우팅 테이블은 VPC 내부 또는 외부로의 트래픽 라우팅을 관리하는 데 사용된다.
실제 프로젝트에 적용할 때에는 비용을 적절히 따져가면서 구현하면 될 듯하다. PL은 프라이빗하게 접근이 가능한 대신, 추가비용이 발생할 수 있고 설정이 더 복잡하다고 한다.
프라이빗 API와 VPC에 대해서 더욱 자세히 알고 싶다면? 역시 공식문서 를 참고하길 바란다.
맨처음에 첨부된 사진을 통해 생성했다면 다음과 같은 그림이 나온다.
여기서 리소스 생성을 눌러보자
그럼 위와 같은 그림이 나오는데 여기서 CORS를 설정할 지 말지 궁금하지 않는가? 나는 궁금하다. ㅋㅋ
브라우저가 웹페이지가 로드된 출처와 다른 출처로부터 리소스를 요청할 때, CORS 정책을 적용하여 요청을 제한한다. 아래 두가지 이유로 설정을 취해야 한다고 한다.
- 다른 출처에서의 API 접근 허용 (웹 페이지와 API가 다른 도메인에 호스팅되는 경우)
- 안전한 웹 애플리케이션 구성 (악의적인 접근 방지)
나는 S3에 호스팅된 프론트엔드 애플리케이션이 AWS API Gateway를 통해 Lambda 함수를 호출하는 구조라서, CORS(Cross-Origin Resource Sharing) 설정이 필요하다. 그니까 체크 꾸욱 ✓
메서드 생성을 누르면 위와 같은 화면이 나온다.
여기서 메서드 유형은 get, post 등 원하는 것을 선택하고 Lambda 함수 부분에 ARN을 Lambda 서비스에 가서 그 주소를 복붙해서 가져온다음 생성하자.
아그리고 프록시 통합! 체크해주자. 왜냐면 안하면...
프록시 통합이 비활성화되면, 요청 및 응답 데이터를 Lambda 함수와 API Gateway 간에 전달하기 위해 매핑 템플릿을 직접 구성해야 합니다. 이는 요청을 Lambda 함수가 처리할 수 있는 형식으로 변환하고, Lambda 함수의 반환 값을 API Gateway가 클라이언트에 전달할 HTTP 응답으로 매핑하는 과정을 포함합니다.
라고 한다.. 그래서 나는 프록시 통합 무시하고 테스트할 때 키에러가 발생했었다. (참 aws를 잘 하려면 사소한 옵션도 놓칠 수 없다...)
그래서 테스트 쿼리를 날렸는데 200으로 떠서 잘 나왔지만 인코딩 에러가 발생한 모습을 확인할 수 있었다. 하지만 이것은 신경쓸 필요 없다.
응답값에서 보이는 이상한 인코딩 문제는 한국어 문자열이 유니코드로 인코딩되어 반환되었기 때문. 이는 서버(여기서는 AWS Lambda 함수)가 응답 본문을 JSON 문자열로 인코딩할 때 기본적으로 발생할 수 있는 현상이다. 클라이언트 측에서 이 데이터를 정상적으로 해석하고 표시하려면, 응답을 받은 후 적절히 디코딩 처리해야 한다.
그래서 프론트상에서 아래처럼 디코딩하면 된다.
const response = '{"message": "\\ucc45\\uc744 ...}'
const decodedResponse = JSON.parse(response);
console.log(decodedResponse.message);
이제 배포하기를 눌러보자. 그러면 스테이지 이름을 생성할 수 있는데 알파벳 대소문자(a-zA-Z), 숫자(0-9), 그리고 밑줄(_)만 사용할 수 있다. 지키지 않으면 Stage name only allows a-zA-Z0-9\_
이런 에러를 만나게 된다.
확인했을 때 잘 구성되어 있는 것을 확인할 수 있다. 그러면 저기 엔드포인트로 요청을 해보자!
포스트맨에서 요청하니 결과가 잘 나왔다!
(사실 send 보냈을 때 조마조마 했던 것은 안비밀)
보안관련해서 구체적인 설정을 하지 않아서 그냥 이렇게 간단히 끝냈지만 아마 프론트에서 연결하면... CORS 설정 이런것 때문에 뭔가뭔가 엄청난 일들이 벌어질 것 같지만 그것은 그때 이슈 터지면 글을 작성해보도록 하겠다.