Registry 인증

Registry 인증

이 문서는 registry 인증 방식을 설명해요. 레지스트리에서 push/pull 작업을 시작하면, 인증이 필요할 때 401 Unauthorized 응답과 함께 인증 방법을 알려 주고, 클라이언트는 인증 서비스에서 Bearer 토큰을 받아 다시 요청하는 흐름이에요.

출처: 문서

본문

이 문서는 registry 인증 방식을 설명해요.

레지스트리와 함께 push/pull 작업을 시작하려 시도해요.

  • 레지스트리가 권한 부여를 요구하면 인증 방법에 대한 정보와 함께 401 Unauthorized HTTP 응답을 반환해요.
  • registry 클라이언트는 Bearer 토큰을 위해 인증 서비스에 요청을 보내요.
  • 인증 서비스는 클라이언트의 권한 있는 접근을 나타내는 불투명한 Bearer 토큰을 반환해요.
  • 클라이언트는 요청의 Authorization 헤더에 Bearer 토큰을 넣어 원래 요청을 다시 시도해요.
  • Registry는 Bearer 토큰과 그 안에 포함된 claim 세트를 검증해 클라이언트를 권한 부여하고, 평소처럼 push/pull 세션을 시작해요.

요구 사항 (Requirements)

  • 리소스 서버가 반환하는 토큰 인증 챌린지를 이해하고 응답할 수 있는 registry 클라이언트.
  • 주어진 서비스(예: Docker Registry의 저장소)가 호스팅하는 리소스에 대한 접근 제어를 관리할 수 있는 인증 서버.
  • 클라이언트가 권한 부여에 사용할 수 있는 토큰에 서명하도록 인증 서버를 신뢰할 수 있고, 이러한 토큰을 단일 사용 또는 충분히 짧은 기간 사용으로 검증할 수 있는 Docker Registry.

인증 서버 엔드포인트 설명

설명된 서버는 별도의 접근 제어 관리자를 사용해 인증하고 권한 부여를 관리하려는 다른 서비스가 호스팅하는 리소스를 위한 독립형 접근 제어 관리자 역할을 하도록 설계됐어요.

이런 서비스는 공식 Docker Registry가 클라이언트를 인증하고 Docker 이미지 저장소에 대한 권한 부여를 확인하는 데 사용해요.

Docker 1.6부터 Docker Engine 내의 registry 클라이언트는 이러한 권한 부여 워크플로를 처리하도록 업데이트됐어요.

인증 방법 (How to authenticate)

Registry V1 클라이언트는 push나 pull을 시작하기 위해 먼저 인덱스에 접촉해요. Registry V2 워크플로에서는 클라이언트가 먼저 레지스트리에 접촉해야 해요. 레지스트리 서버가 인증을 요구하면 이 레지스트리에 인증하는 방법을 상세히 설명하는 WWW-Authenticate 헤더와 함께 401 Unauthorized 응답을 반환해요.

예를 들어 나(사용자 이름 jlhawn)가 samalba/my-app 저장소에 이미지를 푸시하려 한다고 해 봐요. 레지스트리가 이 작업을 승인하려면 samalba/my-app 저장소에 대한 push 접근이 필요해요. 레지스트리는 먼저 이 응답을 반환해요.

HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8
Docker-Distribution-Api-Version: registry/2.0
Www-Authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull,push"
Date: Thu, 10 Sep 2015 19:32:31 GMT
Content-Length: 235
Strict-Transport-Security: max-age=31536000

{"errors":[{"code":"UNAUTHORIZED","message":"access to the requested resource is not authorized","detail":[{"Type":"repository","Name":"samalba/my-app","Action":"pull"},{"Type":"repository","Name":"samalba/my-app","Action":"push"}]}]}

인증 챌린지를 나타내는 HTTP 응답 헤더를 주목하세요.

Www-Authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull,push"

이 형식은 RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage의 섹션 3에 문서화되어 있어요.

이 챌린지는 레지스트리가 지정된 토큰 서버가 발급한 토큰을 요구하며, 클라이언트가 시도하는 요청은 claim 세트에 충분한 접근 항목을 포함해야 한다는 것을 나타내요. 이 챌린지에 응답하기 위해 클라이언트는 WWW-Authenticate 헤더의 servicescope 값을 사용해 URL https://auth.docker.io/tokenGET 요청을 해야 해요.

토큰 요청 (Requesting a token)

토큰 엔드포인트를 사용해 bearer 및 refresh 토큰을 얻는 것을 정의해요.

쿼리 파라미터

service

리소스를 호스팅하는 서비스의 이름이에요.

offline_token

bearer 토큰과 함께 refresh 토큰을 반환할지 여부예요. refresh 토큰은 같은 주체에 대해 다른 스코프로 추가 bearer 토큰을 얻을 수 있어요. refresh 토큰은 만료가 없으며 클라이언트에게 완전히 불투명한 것으로 간주해야 해요.

client_id

클라이언트를 식별하는 문자열이에요. 이 client_id는 인증 서버에 등록할 필요는 없지만, 등록되지 않은 클라이언트가 만든 키를 감사할 수 있도록 의미 있는 값으로 설정해야 해요. 허용되는 문법은 RFC6749 부록 A.1에 정의되어 있어요.

scope

앞서 보여드린 WWW-Authenticate 헤더의 scope 파라미터에서 공백으로 구분된 항목 중 하나로 형식화된 해당 리소스예요. WWW-Authenticate 헤더에 scope 항목이 둘 이상 있으면 이 쿼리 파라미터를 여러 번 지정해야 해요. 앞선 예시는 scope=repository:samalba/my-app:push로 지정돼요. scope 필드는 반환된 bearer 토큰에 리소스 권한을 부여하지 않고 refresh 토큰을 요청하기 위해 비워 둘 수 있어요.

토큰 응답 필드

token

클라이언트가 이후 요청의 Authorization 헤더에 제공해야 하는 불투명한 Bearer 토큰이에요.

access_token

OAuth 2.0과의 호환성을 위해 access_token이라는 이름의 token도 허용돼요. 이 필드 중 하나 이상을 지정해야 하지만, 둘 다 나타날 수도 있어요(이전 클라이언트와의 호환성용). 둘 다 지정되면 동등해야 해요. 다르면 클라이언트의 선택은 정의되지 않아요.

expires_in

(선택) 토큰이 발급된 시점부터 유효한 지속 시간(초)이에요. 생략하면 기본값 60초예요. 이전 클라이언트와의 호환성을 위해 토큰은 유효 수명 60초 미만으로 반환되어서는 안 돼요.

issued_at

(선택) 주어진 토큰이 발급된 시점의 RFC3339로 직렬화된 UTC 표준 시간이에요. issued_at을 생략하면 만료는 토큰 교환이 완료된 시점부터예요.

refresh_token

(선택) 같은 주체에 대해 다른 스코프로 추가 액세스 토큰을 얻는 데 사용할 수 있는 토큰이에요. 이 토큰은 클라이언트가 안전하게 보관해야 하며 bearer 토큰을 발급하는 인증 서버에만 보내야 해요. 이 필드는 요청에 offline_token=true가 제공된 경우에만 설정돼요.

예제

이 예시에서 클라이언트는 다음 URL에 HTTP GET 요청을 해요.

https://auth.docker.io/token?service=registry.docker.io&scope=repository:samalba/my-app:pull,push

토큰 서버는 먼저 요청과 함께 제공된 인증 자격 증명을 사용해 클라이언트를 인증하려 시도해야 해요. Docker 1.11부터 Docker Engine은 토큰을 얻기 위해 Basic 인증과 OAuth2를 모두 지원해요. Docker 1.10 이하에서는 Docker Engine의 registry 클라이언트가 Basic 인증만 지원해요. 토큰 서버에 대한 인증 시도가 실패하면, 토큰 서버는 제공된 자격 증명이 유효하지 않음을 나타내는 401 Unauthorized 응답을 반환해야 해요.

토큰 서버가 인증을 요구하는지는 그 접근 제어 제공자의 정책에 달려 있어요. 어떤 요청은 접근을 결정하기 위해 인증이 필요할 수 있고(비공개 저장소 push/pull처럼), 어떤 요청은 필요하지 않을 수 있어요(공개 저장소 풀처럼).

클라이언트를 인증한 후(인증을 시도하지 않았다면 단순히 익명 클라이언트일 수 있음) 토큰 서버는 접근 제어 목록을 쿼리해 클라이언트가 요청된 스코프를 가졌는지 결정해야 해요. 이 예시 요청에서 사용자 jlhawn으로 인증했다면, 토큰 서버는 registry.docker.io 엔티티가 호스팅하는 samalba/my-app 저장소에 대한 나의 접근 권한을 결정할 거예요.

토큰 서버가 클라이언트가 scope 파라미터에 요청한 리소스에 대한 접근을 결정하면, 각 리소스에 대한 요청된 작업 집합과 실제로 부여된 작업 집합의 교집합을 취해요. 클라이언트가 요청된 접근의 일부만 가진다면 이를 오류로 간주해서는 안 돼요. 이 워크플로의 일부로 인증 오류를 나타내는 것은 토큰 서버의 책임이 아니기 때문이에요.

예시 요청을 계속해 보면, 토큰 서버는 클라이언트의 저장소에 대한 부여된 접근 집합이 [pull, push]임을 발견하고, 요청된 접근 [pull, push]와 교집합하면 동일한 집합이 돼요. 부여된 접근 집합이 [pull]뿐이라면 교집합 집합도 [pull]뿐이 돼요. 클라이언트가 저장소에 대한 접근이 없으면 교집합 집합은 빈 []가 돼요.

반환된 토큰에 들어가는 것이 바로 이 교집합된 접근 집합이에요.

그런 다음 서버는 이 교집합된 접근 집합으로 구현별 토큰을 구성하고, Docker 클라이언트가 (표시된 시간 창 내에서) 대상 서비스에 인증하는 데 사용하도록 반환해요.

HTTP/1.1 200 OK
Content-Type: application/json

{"token": "eyJ0eX...9t3w", "expires_in": 3600,"issued_at": "2009-11-10T23:00:00Z"}

Bearer 토큰 사용 (Using the Bearer token)

클라이언트가 토큰을 얻으면 HTTP Authorization 헤더에 토큰을 넣어 레지스트리 요청을 다시 시도해요.

Authorization: Bearer eyJ0eX...gkbw

이것은 RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage의 섹션 2.1에도 설명되어 있어요.

더 알아보기 (Learn more)