인증
엑세스 토큰과 비밀 키
API 서버에 요청하려면, 클라이언트에서는 API 엑세스 키와 비밀 키가 쌍으로 필요합니다. 클라우드 서비스 나 Backend.AI 클러스터의 관리자에서 해당 키를 확인할 수 있습니다.
서버는 각 클라이언트를 식별하기 위해 API 키를 사용하며, 클라이언트를 인증하고 API 요청의 무결성을 검증하기 위해 비밀 키를 사용합니다.
경고
API 액세스 키와 비밀 키가 외부로 유출되는 것을 막기 위한 보안 조치로, Backend.AI 를 활용해 공개된 프론트엔드 서비스를 설계할 때는 가급적 API 서비스를 위한 서버사이드 프록시를 사용하는 것을 권장합니다.
로컬 배포의 경우, 환경 설정에 마스터 더미 데이터(dummy data) 쌍을 만들 수 있습니다. (TODO)
API 요청의 공통 구조
HTTP 헤더 |
값 |
---|---|
메서드 |
|
쿼리스트링 |
If your access key has the administrator privilege, your client may
optionally specify other user’s access key as the Added in version v4.20190315. |
|
항상 ``application/json``이어야 합니다 |
|
Signature information generated as the section Signing API Requests describes. |
|
요청의 날짜, 시간은 RFC 8022나 ISO 8601의 형식입니다. 만약 특별한 시간대가 명시되지 않았다면, UTC로 가정합니다. 서버의 시간과 요청의 시간의 차이는 15분 이내여야 합니다. |
|
|
|
|
|
선택 사항: 반복된 요청을 서버가 구별할 수 있게 하는 클라이언트 생성 랜덤 문자열입니다.때때로 나타나는 장애에 대해 여러 번 재시도하여 멱등성을 유지하는 것이 중요합니다. (구현 중)*멱등성 : 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질 |
Body |
JSON 인코딩 요청 매개 변수 |
API 응답들의 공통 구조
HTTP 헤더 |
값 |
---|---|
상태 코드 |
API에 대한 HTTP 표준 상태 코드입니다. 모든 API에서 일반적으로 사용되는 응답에는 200, 201, 204, 400, 401, 403, 404, 429, 그리고 500이 포함되지만 이에 국한되지 않습니다. |
|
|
|
Web link headers specified as in RFC 5988. Only optionally used when returning a collection of objects. |
|
The rate-limiting information (see Rate Limiting). |
Body |
JSON 인코딩 결과 |
API 요청 서명
각각의 API 요청은 서명과 함께 등록되어야 합니다. 먼저, 클라이언트는 API 비밀 키에서 파생된 서명 키와 HTTP 요청을 정규화하여 얻을 수 있는 서명할 문자열을 생성해야 합니다.
서명 키 생성하기
다음은 비밀 키로부터 파생된 서명 키를 생성하는 Python 코드 입니다. 키는 현재 날짜 (시간 제외) 및 API 엔드포인트 주소에 대해 중첩되어 생성됩니다.
import hashlib, hmac
from datetime import datetime
SECRET_KEY = b'abc...'
def sign(key, msg):
return hmac.new(key, msg, hashlib.sha256).digest()
def get_sign_key():
t = datetime.utcnow()
k1 = sign(SECRET_KEY, t.strftime('%Y%m%d').encode('utf8'))
k2 = sign(k1, b'your.sorna.api.endpoint')
return k2
서명할 문자열 생성하기
서명할 문자열은 다음과 같은 요청 정보 값에 의해 생성됩니다.
HTTP 메서드 (대문자)
쿼리스트링을 포함하는 URI
UTC 시간대를 활용하고 ISO 8601 형식으로 구성된 (
YYYYmmddTHHMMSSZ
)Date
의 값 (단, 요청에서Date
가 주어지지 않았다면,X-BackendAI-Date
를 사용함.)정규화 된
Host
의 헤더/값 쌍정규화 된
Content-Type
의 헤더/값 쌍정규화 된
X-BackendAI-Version
의 헤더/값 쌍body 전체를 hex로 인코딩한 hash 값. 사용한 hash 함수는 반드시
Authorization
헤더에 명시된 함수와 동일해야 합니다. (e.g., SHA256).
서명할 문자열을 생성하기 위해, 클라이언트는 위의 값들을 newline 문자열 ("\n"
, ASCII 10) 을 활용하여 합쳐야 합니다. 모든 non-ASCII 문자열은 반드시 UTF-8 형식으로 인코딩 되어야 합니다. HTTP 헤더/값 쌍을 정규화 하기 위해선, 먼저 맨 앞이나 맨 뒤에 붙어있는 공백 문자열 ("\n"
, "\r"
, " "
, "\t"
; 또는 ASCII 10, 13, 32, 9) 을 제거해야 하며, 소문자로 변경된 헤더의 이름과 값을 콜론 (":"
, ASCII 58) 문자열을 통해 연결해야 합니다.
요청과 응답 예시 에 적힌 예시는 다음과 같은 방식으로 서명할 문자열을 생성 하였습니다.
GET
/v2
20160930T01:23:45Z
host:your.sorna.api.endpoint
content-type:application/json
x-sorna-version:v2.20170215
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
이 예시에서, 해시 값 ``e3b0c4…``는 GET 요청에 대한 본문이 없으므로 SHA256 해시 함수를사용하여 빈 문자열에서 생성됩니다.
그리고, 클라이언트는 서명 키와 hash 함수로 부터 생성된 문자열을 활용해 다음과 같이 서명해야 합니다.
import hashlib, hmac
str_to_sign = 'GET\n/v2...'
sign_key = get_sign_key() # see "Generating a signing key"
m = hmac.new(sign_key, str_to_sign.encode('utf8'), hashlib.sha256)
signature = m.hexdigest()
서명 작성
마지막으로, 클라이언트는 이제 Authorization
HTTP 헤더를 구성해야 합니다.
Authorization: BackendAI signMethod=HMAC-SHA256, credential=<access-key>:<signature>
요청과 응답 예시
이 예시에서, 우리는 다음과 같은 더미 엑세스 키와 비밀 키를 사용할 것입니다.
엑세스 키 예시:
AKIAIOSFODNN7EXAMPLE
비밀 키 예시:
wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
최신 API 버전을 확인하는 예시
GET /v2 HTTP/1.1
Host: your.sorna.api.endpoint
Date: 20160930T01:23:45Z
Authorization: BackendAI signMethod=HMAC-SHA256, credential=AKIAIOSFODNN7EXAMPLE:022ae894b4ecce097bea6eca9a97c41cd17e8aff545800cd696112cc387059cf
Content-Type: application/json
X-BackendAI-Version: v2.20170215
HTTP/1.1 200 OK
Content-Type: application/json
Content-Language: en
Content-Length: 31
X-RateLimit-Limit: 2000
X-RateLimit-Remaining: 1999
X-RateLimit-Reset: 897065
{
"version": "v2.20170215"
}