애플리케이션을 구동하기 위한 환경을 얻기까지 전통적인 데이터센터 환경에서 관리자는 거의 모든 작업을 수동으로 수행합니다. 관리자와 운영자는 서버, 스토리지 및 네트워크와 같은 인프라를 구성하고 운영체제와 필요한 프레임워크를 설치하여 애플리케이션을 구동할 수 있는 환경까지 제공하는데 상당한 시간을 소비합니다.
따라서 그 만큼 비즈니스의 시장 진입 시간은 길어질 수 밖에 없습니다. 하지만 클라우드 환경의 경우에는 네트워크가 가능한 곳이라면 장소나 시간에 구애 받지 않고 언제 어디서나 API 호출을 통해 수분내에 원하는 자원을 쉽게 얻을 수 있습니다.
AWS 클라우드에서 인프라 뿐만 아니라 보안, 데이터베이스, 분석, 배포 및 모니터링 등의 모든 IT 자원은 API 호출을 통해서 이용됩니다. API는 이렇게 모든 IT 자원을 코드로 제어할 수 있도록 만들었습니다. API를 호출한다는 것은 개발자에게는 그리 어렵고 생소한 일은 아니지만, 운영자나 관라자 그리고 일반 사용자 측면에서는 낯선 일입니다.
그래서, AWS는 사용자들의 편의를 위해 직접 API 호출을 하지 않고도 보다 쉽고 편하게 자원을 프로비저닝하거나 변경 및 관리할 수 있는 여러가지 도구들도 개발해서 함께 지원합니다. 서비스마다 잘 설계된 웹 기반의 관리 콘솔이나 명령줄 인터페이스가 대표적인 예이고, 심지어 개발자에게도 다양한 프로그래밍 언어를 위한 SDK까지 제공합니다. 이 모든 것은 내부적으로 기본 원재료에 해당하는 API를 호출하도록 설계되어 있습니다.
이처럼 직관적이고 편리한 많은 도구들이 제공되지만, 경우에 따라 AWS 클라우드에 HTTP/HTTPS 기반의 API호출 요청을 직접 보내야 하는 때도 있습니다. 아래와 같은 경우가 대표적인 예라고 생각됩니다:
- C와 같이 SDK를 제공하지 않는 프로그래밍 언어를 사용해야 하는 경우
- 신규로 제공되는 서비스와 기능들에 대해 SDK 지원이 아직 안 되는 경우
- AWS 자원에 보내진 요청이나 응답에 대해서, 보다 세부적이고 완벽하게 제어하고 싶은 경우
AWS클라우드로 API를 요청할 때, 모든 HTTP/HTTPS 요청은 메시지에 대한 무결성과 인증을 보장해야 합니다. 그래서 미리 서명 처리가 되어야 하고, 이런 서명처리는 아래와 같은 방법을 통해서 요청 메시지의 안정성을 보장합니다:
- 요청자 신원 확인: 요청자는 유효한 ‘액세스 키 ID’와 ‘비밀 액세스 키’를 가지고 있어야 합니다. (또는 AssumeRole이나 GetFederationToken과 같은 STS API 호출을 통해서 얻은 임시 보안 자격을 가지고도 요청할 수 있습니다.)
- 전송 중 데이터 보호: 전송 중 요청이 조작되는 것을 방지하기 위해서, 요청 구성 요소들 중 몇 가지는 요청에 대해 해시를 계산하는데 사용됩니다. 그리고 그 해시값은 요청의 일부로 포함됩니다. AWS가 해당 요청을 수신하면, 동일한 정보에 기초하여 해시를 계산하고 요청에 포함된 해시 값과 일치하는지 비교합니다. 만일 해시값이 일치하지 않으며, AWS는 해당 요청을 거절합니다.
- 잠재적인 재생 공격(replay attack) 방어: 모든 요청은 타임 스탬프를 기준으로 5분간만 유효하다고 인정되며, 그 기간이 지난 요청은 전부 거절됩니다.
이에 대한 전체적인 서명 과정을 요약하자면 아래 그림과 같습니다.
보안을 더 강화하기 위해서 HTTPS를 사용하여 요청을 전송할 수 있습니다. SSL은 암호화 전송을 하기 때문에, 요청과 응답 전송을 암호화해서 추가적으로 더 보호합니다. 하지만 AWS의 서비스들마다 지원하는 프로토콜이 다를 수 있습니다. 어떤 서비스는HTTP 또는 HTTPS만 지원하는 서비스가 있을 수 있고, 또 두 가지 프로토콜 모두를 지원하는 서비스도 있습니다. 지원하는 서비스와 프로토콜에 대한 자세한 사항은 여기를 클릭해보시면 확인 가능합니다.
AWS는 현재 서명 버전 (signature version) 2와 서명 버전 4 두 가지를 지원합니다. 대부분의 서비스는 버전2보다 버전 4를 더 지원합니다. 만일 서비스가 두 가지 서명 버전을 모두 지원한다면, 최신의 버전 4를 사용하는 것을 권장합니다. 서명 버전 2에 대한 사항은 이곳을 참조하시고, 서명 버전4에서 변경된 사항을 확인하시려면 여기를 확인해 보세요. 이 후 설명되는 모든 사항들은 서명 버전 4에 대한 내용입니다.
각 요청에 서명을 추가하는 방법은 아래 두 가지 방법 중 하나를 선택할 수 있습니다:
- HTTP 인증 헤더: HTTP 인증 헤더를 사용하여 서명을 추가합니다.
- 쿼리 문자열 매개변수: 서명을 쿼리 문자열 값으로 추가합니다. 요청 서명이 그 URL의 일부이기 때문에 이런 종류의 URL을 미리 서명된(pre-signed) URL이라고 지칭합니다.
아래는 예는 브라우저에서 서명정보 없이 AWS로 요청을 보낼 경우 어떻게 보이는지 보여주고 있습니다.
GET https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08 HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Host: iam.amazonaws.com
X-Amz-Date: 20150830T123600Z
이러한 요청은 HTTP 인증 헤더로 전송되었을 때와 쿼리 문자열 매개변수로 전송되어졌을 때 아래와 같이 달라질 수 있습니다.
HTTP 인증 헤더
사용자는 Authorization 헤더를 통해서 인증 정보를 추가할 수 있습니다. 비록 헤더 이름이 Authorization로 되어 있지만, 서명 정보를 담고 있는 헤더 값들은 실제로 해당 요청이 누구에서 왔는지 인증을 확립하기 위해서 사용됩니다.
Authorization 헤더는 아래 정보를 포함하고 있습니다:
- 서명하기 위해 사용된 알고리즘 (예: AWS4-HMAC-SHA256)
- 자격 범위 (예: 액세스 키 등)
- 서명 헤더 목록
- 계산된 서명
계산된 서명은 암호화되어 생성된 문자열입니다. 이 서명은 요청 정보에 기반하여 생성되며, AWS 비밀 액세스 키를 사용해서 서명을 생성합니다. 그리고 이 값은 요청을 수신한 AWS에서 사용자 신원을 확인하는데 이용됩니다.
아래 예는 앞에서 보셨던 요청에 서명 정보를 생성하고, 이를 Authorization 헤더에 추가할 경우 보여지는 내용입니다.
GET https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08 HTTP/1.1
Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7
content-type: application/x-www-form-urlencoded; charset=utf-8
host: iam.amazonaws.com
x-amz-date: 20150830T123600Z
쿼리 문자열 매개변수
요청 헤더에 인증정보를 추가하는 대신, 쿼리 문자열을 포함 할 수 있습니다. 쿼리 문자열은 서비스 이름과 액션, 날짜, 그리고 인증 정보를 위한 매개변수들 등 요청의 일부인 모든 것을 포함합니다.
아래 예는 쿼리 문자열에 액션과 인증 정보를 포함시켜서, GET 요청을 어떻게 구성하였는지 보여주고 있습니다
GET https://iam.amazonaws.com?Action=ListUsers&Version=2010-05-08&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fus-east-1%2Fiam%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=60&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=37ac2f4fde00b0ac9bd9eadeb459b1bbee224158d66e7ae5fcadb70b2d181d02 HTTP/1.1
content-type: application/x-www-form-urlencoded; charset=utf-8
host: iam.amazonaws.com
많은 AWS 서비스들이 지원하는 쿼리API는 HTTP GET이나 POST를 사용해서 요청을 만들 수 있도록 해줍니다. GET 요청은 쿼리 문자열을 매개변수로 전달하기 때문에, URL의 최대 길이 제한에 적용될 수 있습니다. 만일 IAM 정책을 업로드하거나 DynamoDB 요청을 위해 JSON 형태의 매개변수를 사용하는 것처럼 요청이 큰 페이로드(Payload)를 포함하고 있다면, 일반적으로 POST 요청을 사용하는 것을 권장합니다.
아래 절차는 HTTP/HTTPS 기반의 서명된 AWS API 요청을 어떻게 만드는지 간략하게 요약한 내용입니다:
- 표준 요청(Canonical Request)형식으로 내용들을 정렬하기 – 호스트, 액션, 헤더 등의 요청 내용을 정렬하여 표준 형식으로 만듭니다. 이 표준 요청은 아래 서명하기 위한 문자열을 만들기 위해 사용됩니다. 구체적은 정보는 이곳에서 확인하실 수 있습니다.
- 서명하기 위한 문자열(StringToSign) 만들기 – 알고리즘, 요청 날짜, 자격 범위 및 앞서 생성한 표준 요청의 해시 정보를 가지고 서명하기 위한 문자열을 만듭니다. 구체적인 내용은 이곳에서 확인하실 수 있습니다.
- AWS 서명 버전 4(Signature) 계산하기 – AWS 비밀 액세스 키뿐만 아니라 요청 날짜, 리전, 그리고 서비스이름을 가지고 연속적인 해시 키잉 동작을 행함으로써 서명 키를 유도합니다. 그리고 이 서명 키와 서명하기 위한 문자열을 이용해서 서명을 만듭니다. 구체적인 정보는 이곳에서 확인하실 수 있습니다.
- 생성한 서명 정보를 HTTP/HTTPS API 요청에 추가하기 – 서명을 계산한 후, 그것을 헤더나 요청 쿼리 문자열에 추가합니다. 구체적인 정보는 이곳에서 확인하실 수 있습니다.
이렇게 생성된 URL을 해당 AWS 서비스의 엔드포인트에 보내는 것이 API 호출입니다. 리전별 각 서비스의 엔드포인트는 이곳에서 확인 가능합니다.
이번 블로그에서는 AWS API 호출 요청에 대한 기본 정보와 어떻게 만드는지 전반적인 골격을 확인하였습니다. 다음 회에서는 이를 바탕으로 실제 HTTP/HTTPS API 호출 요청을 직접 생성해 보겠습니다.
▶ AWS API 호출 하기 (2) – Amazon S3 객체에 대한 미리 선언된(pre-signed) URL 생성하기
본 글은 아마존웹서비스 코리아의 솔루션즈 아키텍트가 국내 고객을 위해 전해 드리는 AWS 활용 기술 팁을 보내드리는 코너로서, 이번 글은 박철수 솔루션즈 아키텍트께서 작성해주셨습니다.
Source: aws-blog-korea
Leave a Reply