인증

엑세스 토큰과 비밀 키

API 서버에 요청하려면, 클라이언트에서는 API 엑세스 키와 비밀 키가 쌍으로 필요합니다. 클라우드 서비스 나 Backend.AI 클러스터의 관리자에서 해당 키를 확인할 수 있습니다.

서버는 각 클라이언트를 식별하기 위해 API 키를 사용하며, 클라이언트를 인증하고 API 요청의 무결성을 검증하기 위해 비밀 키를 사용합니다.

경고

API 액세스 키와 비밀 키가 외부로 유출되는 것을 막기 위한 보안 조치로, Backend.AI 를 활용해 공개된 프론트엔드 서비스를 설계할 때는 가급적 API 서비스를 위한 서버사이드 프록시를 사용하는 것을 권장합니다.

로컬 배포의 경우, 환경 설정에 마스터 더미 데이터(dummy data) 쌍을 만들 수 있습니다. (TODO)

API 요청의 공통 구조

HTTP 헤더

메서드

GET / REPORT / POST / PUT / PATCH / DELETE

쿼리스트링

If your access key has the administrator privilege, your client may optionally specify other user’s access key as the owner_access_key parameter of the URL query string (in addition to other API-specific ones if any) to change the scope of access key applied to access and manipulation of keypair-specific resources such as kernels and vfolders.

Added in version v4.20190315.

Content-Type

항상 ``application/json``이어야 합니다

Authorization

Signature information generated as the section Signing API Requests describes.

Date

요청의 날짜, 시간은 RFC 8022나 ISO 8601의 형식입니다. 만약 특별한 시간대가 명시되지 않았다면, UTC로 가정합니다. 서버의 시간과 요청의 시간의 차이는 15분 이내여야 합니다.

X-BackendAI-Date

Date``와 동일합니다. 만약 ``Date 항목이 있다면 생략됩니다.

X-BackendAI-Version

vX.yyymmdd 에서 ``X``는 주 버전이고 ``yyyymmdd``는 특정 API 버전의 마이너 릴리스 날짜입니다. (예: 20160914)

X-BackendAI-Client-Token

선택 사항: 반복된 요청을 서버가 구별할 수 있게 하는 클라이언트 생성 랜덤 문자열입니다.때때로 나타나는 장애에 대해 여러 번 재시도하여 멱등성을 유지하는 것이 중요합니다. (구현 중)*멱등성 : 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질

Body

JSON 인코딩 요청 매개 변수

API 응답들의 공통 구조

HTTP 헤더

상태 코드

API에 대한 HTTP 표준 상태 코드입니다. 모든 API에서 일반적으로 사용되는 응답에는 200, 201, 204, 400, 401, 403, 404, 429, 그리고 500이 포함되지만 이에 국한되지 않습니다.

Content-Type

application/json 및 변형 (예: application/problem+json - 오류)

Link

Web link headers specified as in RFC 5988. Only optionally used when returning a collection of objects.

X-RateLimit-*

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"
}

authorization 헤더를 포함하지 않아 발생하는 실패 예시

GET /v2/kernel/create HTTP/1.1
Host: your.sorna.api.endpoint
Content-Type: application/json
X-BackendAI-Date: 20160930T01:23:45Z
X-BackendAI-Version: v2.20170215
HTTP/1.1 401 Unauthorized
Content-Type: application/problem+json
Content-Language: en
Content-Length: 139
X-RateLimit-Limit: 2000
X-RateLimit-Remaining: 1998
X-RateLimit-Reset: 834821

{
   "type": "https://sorna.io/problems/unauthorized",
   "title": "Unauthorized access",
   "detail": "Authorization header is missing."
}