Authorization tokens
출처: 문서
본문
인증 토큰
Security 플러그인에서는 두 가지 유형의 인증 토큰을 설정할 수 있어요: On-Behalf-Of(OBO) 토큰과 Service Account 토큰이에요.
On-Behalf-Of 인증
다음 섹션에서는 OBO 토큰의 사용 방법, 설정, 구조, 엔드포인트를 설명해요.
사용 방법
On-Behalf-Of 토큰은 사용자의 클라이언트와 확장 프로그램(extension) 사이의 인증 요청을 관리하는 데 사용되는 특수한 형태의 JSON Web Token(JWT)이에요. 이 토큰은 "just-in-time" 방식으로 동작하는데, 즉 인증에 필요해지는 순간 바로 직전에 토큰이 발급된다는 뜻이에요. 토큰에는 설정 가능한 유효 기간(최대 5분)이 부여되고, 그 이후에는 만료되어 사용할 수 없어요.
확장 프로그램은 OBO 토큰을 사용해서 해당 토큰이 대표하는 사용자와 동일한 권한으로 OpenSearch 클러스터와 상호 작용할 수 있어요. 이 때문에 이 토큰을 "on-behalf-of"(대리)라고 부르는 거예요. 이 토큰은 제한이 없기 때문에, 토큰이 만료될 때까지 서비스가 마치 원래 사용자인 것처럼 동작할 수 있어요. 즉, 이 기능의 적용 범위가 확장 프로그램 관련 사용 사례에만 국한되지 않고 더 넓은 범위의 용도로 활용될 수 있다는 뜻이에요.
설정
config/opensearch-security/config.yml 파일에서 OBO 설정은 config.dynamic 섹션에 위치해요. 이 섹션에는 토큰 서명을 위한 signing_key와, 토큰 페이로드의 roles 클레임을 암호화하기 위한 선택적인 encryption_key가 들어 있어요:
config:
dynamic:
on_behalf_of:
enabled: #'true'/non-specified will be consider as 'enabled'
signing_key: #encoded signing key here
encryption_key: #(optional) encoded encryption key here
...
JWT 서명에 사용되는 기본 인코딩 알고리즘은 HMAC SHA512예요. 키는 config/opensearch-security/config.yml 파일에 Base64로 인코딩된 문자열이에요. securityadmin.sh -cd <configuration directory> 명령으로 설정을 적용하면, 그 값들은 보안 시스템 인덱스에 저장되고 클러스터 전체에서 사용돼요.
encryption_key를 생략하면 역할(roles)과 백엔드 역할(backend roles)이 토큰 클레임에 일반 텍스트로 저장돼요. encryption_key를 제공하면 roles 클레임이 암호화돼요. 클러스터 관리자는 보안 요구 사항에 따라 역할 정보를 암호화할지 여부를 선택할 수 있어요.
토큰 구조
OBO 토큰의 페이로드에는 역할 클레임과 함께 JWT의 모든 표준 구성이 포함되어야 해요. 이 클레임 중 하나라도 빠지면 토큰이 잘못된 형태가 되어 인증에 필요한 표준을 충족하지 못해요.
OBO 토큰에는 다음과 같은 클레임이 들어 있어요:
- Issuer(
iss): OpenSearch 클러스터 식별자- 보안 통제 조치의 일부로 issuer를 검증하는 것이 필수적이에요. 이 전략은 특히 OpenSearch Serverless처럼 issuer마다 서로 다른 암호화 키가 연결될 수 있는 잠재적인 멀티 테넌트 시나리오를 고려할 때 선제적인 접근 방식이에요. issuer 값을 확인함으로써 각 OBO 토큰은 해당 issuer에만 묶이게 돼요.
- Issue-at(
iat): 이 토큰이 발급되는 현재 시각- 만료 시점의 기준으로 사용돼요.
- Not-before(
nbf): 토큰을 사용할 수 있는 가장 이른 시점- OBO 토큰은 just-in-time 사용을 위해 설계되었기 때문에,
nbf는 토큰이 생성된 시점을 나타내는 발급 시각(iat)과 일치해야 해요.
- OBO 토큰은 just-in-time 사용을 위해 설계되었기 때문에,
- Expiry(
exp): 만료 시각- 각 OBO 토큰에는 만료 메커니즘이 포함되어 있고, 토큰을 받는 시점에 이를 검증해요. 토큰이 한 번 발급되면 철회(revoke)할 수 없어요. 대신 토큰은 만료될 때만 무효화돼요. 또한 확장 프로그램이 OBO 토큰을 생성하는 것은 동적 설정의 영향을 받아요. 이 기능은 특정 조건에서 미래 토큰의 발급을 막음으로써 시스템을 보호해요.
- 기본 설정에서는 OBO 토큰의 만료 시간이 300초로 정해져 있어요. 서로 다른 시나리오에서 서로 다른 토큰 유효 기간이 필요할 수 있다는 점을 고려해, OpenSearch는 사용자가 이 만료 시간을 직접 조정할 수 있는 기능을 제공해요. 토큰에 지정할 수 있는 최대 유효 기간은 600초예요.
- OBO 토큰의 현재 설계를 보면, just-in-time 사용과 짧은 수명이 의도되어 있기 때문에 토큰 철회는 현재로서는 큰 문제가 아니에요. 하지만 향후 조정으로 이 토큰의 수명을 연장해야 할 필요가 생기면 토큰 철회 기능이 추가될 거예요. 이 전략은 OBO 토큰 사용과 관련된 보안 조치를 개선하고 강화하기 위해 채택될 거예요.
- Subject(
sub): 사용자 식별자- 이 OBO 토큰이 연결된 사용자의 이름이에요.
- Audience(
aud): 확장 프로그램의 고유 식별자- 확장 프로그램 사용 사례에서는
aud필드가 대상 서비스를 나타내는 특정 확장 프로그램을 가리켜요. - REST API 사용 사례에서는 API 파라미터인 service를 사용해 이 토큰으로 접근할 대상 서비스를 지정할 수 있어요. 기본값은
self-issued로 설정되어 있어요.
- 확장 프로그램 사용 사례에서는
- Roles: 보안 권한 평가
encryption_key가 설정되면 매핑된 역할이 토큰 페이로드에서 암호화돼요:- 암호화된 매핑 역할(
encrypted_roles)
- 암호화된 매핑 역할(
encryption_key가 설정되지 않으면 역할이 일반 텍스트로 저장돼요:- 매핑 역할(
roles) - 백엔드 역할(
backend_roles)
- 매핑 역할(
암호화와 복호화 과정은 OpenSearch Security 플러그인이 처리해요. 이 방식 덕분에 OpenSearch와 서드파티 서비스 사이의 신뢰 경계(trust boundary)를 넘을 때에도 사용자 정보가 보호돼요.
API 엔드포인트
Security 플러그인의 POST /_plugins/_security/api/generateonbehalfoftoken API 엔드포인트에 접근하면, 사용자를 대신해 특정 작업을 수행하기 위한 수명이 짧은 self-issued OBO 토큰을 생성할 수 있어요.
이 API 엔드포인트에 접근하려면 요청 본문에 세 가지 API 파라미터가 포함되어야 해요:
description: 이 파라미터를 사용하면 사용자가 이 토큰을 요청하는 목적을 명확하게 표현할 수 있어서 투명성이 높아져요.service(선택 사항): 이 파라미터는 OBO 토큰의 audience 클레임으로 전달돼요. 사용자가 토큰을 사용하려는 대상 서비스를 지정할 수 있게 해줘요. 선택 사항이긴 하지만, 지정하지 않으면 기본값이self-issued로 설정돼요.durationSeconds(선택 사항): 이 파라미터를 사용하면 예상 용도에 맞게 토큰의 만료 시간을 조정할 수 있어요. 보안을 유지하기 위해 최대 유효 기간은 600초로 제한돼요. 지정하지 않으면 기본 유효 기간은 300초로 설정돼요. 다음은 테스트 목적으로 사용자 “admin”에게 수명이 3분인 OBO 토큰을 요청하는 예제예요:
POST /_plugins/_security/api/generateonbehalfoftoken
{
"description":"Testing",
"service":"Testing Service",
"durationSeconds":"180"
}
{% include copy-curl.html security=true %}
추가 인가 제한
OBO 토큰 사용에 대한 논의가 계속되는 가운데, 몇 가지 엣지 케이스를 관리하는 것이 중요해요. OBO 토큰이 모든 API 접근에 유효한 Bearer 인증 헤더로 동작할 수 있긴 하지만, 특정 제한이 필요해요. 예를 들어, OBO 토큰을 사용해 다른 OBO 토큰을 발급하는 API 엔드포인트에 접근하는 것은 금지되어야 해요. 마찬가지로 OBO 토큰을 사용해 reset password API에 접근해 사용자의 인증 정보를 수정하는 것도 허용되지 않아야 해요. 시스템의 무결성과 보안을 지키기 위해서는 이런 예방 조치가 필요해요.
자세한 내용은 관련 논의를 참고하세요.
권한
OBO 토큰을 생성하려면 security:obo/create 권한이 있어야 해요.
Service Account
Service Account 토큰은 Security 플러그인이 지원하는 두 번째 인증 토큰 형태예요.
소개
Service Account는 활성 사용자의 역할을 대행하지 않고도 확장 프로그램이 요청을 실행할 수 있는 새로운 authC/authZ 경로예요. Service Account는 각 확장 프로그램에 연결되는 특수한 유형의 principal(주체)이며, 일련의 권한을 가지고 있어요. Service Account에 할당된 권한은 활성 사용자의 역할을 대행하거나 사용자의 역할을 임시 사용자 컨텍스트에 저장(stash)할 필요 없이, 매핑된 작업을 실행할 수 있는 인가를 해당 확장 프로그램에 부여해요.
Service Account는 매핑된 확장 프로그램과 연결된 시스템 인덱스에 대한 작업만 허용해요. {: .important}
배경
Service Account가 도입되기 전에는 확장 프로그램이 활성 사용자의 역할을 대행하지 않고 요청을 처리할 수 없었어요. 대신 요청이 처리될 때 임시 "Plugin User"가 생성되었어요. 그러면 Plugin User는 현재 인증된 운영자(사람 사용자)의 모든 권한을 대행했어요. 그 결과 확장 프로그램을 대신해 동작하지만 운영자의 모든 권한을 가진 Plugin User가 만들어졌죠. 이런 의미에서 이전 모델은 확장 프로그램이 운영자를 "가장(impersonate)"했다고 할 수 있어요. 이 가장(impersonation) 방식은 두 가지 주요 문제를 낳았어요:
- 가장(impersonation)은 참조 무결성을 훼손해요. 즉, 감사자가 어떤 요청이 확장 프로그램에 의해 실행되었는지 운영자에 의해 실행되었는지 파악하기 어려워져요. 참조 무결성을 갖춘 시스템은 감사 로그에 트랜잭션 기록을 유지해요. 이 기록은 다양한 주체가 특정 시점에 수행한 동작의 명확한 이력을 제공해요. 확장 프로그램이 운영자를 대신해 보내는 요청과 자체적으로 보내는 요청 모두에서 사용자를 가장하면, 감사 로그는 참조 무결성을 잃게 돼요.
- 또한 가장(impersonation) 방식에서는 확장 프로그램이 가장하는 사용자의 권한 이상으로 권한을 제한할 수 없어요. 확장 프로그램이 활성 주체의 역할을 대행하면 모든 역할을 복사해요. 여기에는 의도한 작업을 완료하는 데 불필요한 권한까지 포함돼요. 이런 관행은 최소 권한 원칙에서 벗어날 뿐만 아니라 위협 표면(threat surface)도 넓혀요. Plugin User에 권한이 하나 추가될 때마다, 잘못 설정되었거나 악의적인 확장 프로그램이 미칠 잠재적 영향이 커져요.
이점
Service Account는 자율적으로 동작하는 확장 프로그램이 실행되는 별도의 상태를 정의함으로써 배경 섹션에서 설명한 문제를 해결해요. Service Account는 확장 프로그램이 자신을 위해 요청을 보낼 때 실행되는 별개의 상태를 도입함으로써 참조 무결성을 유지해요. 그러면 감사 로깅은 확장 프로그램이 자체적으로 실행되는 시점—즉 Service Account에 대해 authC/authZ 호출을 하는 경우—와, 운영자를 대신해 작업을 실행하므로 OBO 토큰을 활용하는 경우를 구분해서 기록할 수 있어요.
마찬가지로 Service Account는 확장 프로그램이 대행하는 역할을 운영자나 일반적인 하드코딩된 사용자(예: internal_users.yml 파일에 있는 사용자)의 역할과 분리함으로써 위협 노출 문제를 해결해요.
Service Account는 운영자의 역할을 대행하지 않고, 대신 Service Account에 나열된 자체 권한을 가져요. 따라서 Service Account와 연결된 역할은 최소 권한 원칙에 맞게 최대한 제한적으로 설정할 수 있어요. 확장 프로그램에 지나치게 관대한 Service Account를 제공하지 않으려면, 확장 프로그램 작성자는 자신의 확장 프로그램이 실행하려는 작업 유형을 잘 이해하고 있어야 해요.
API 엔드포인트
이름이 암시하듯, Boolean 플래그인 service는 해당 내부 사용자 계정이 Service Account인지 여부를 나타내요. 계정이 Service Account가 아니라면, 해당 계정에 연결된 인가 토큰을 생성하려는 시도는 모두 실패해요. 마찬가지로 enabled 필드는 확장 프로그램이 Service Account를 사용해 작업을 수행할 수 있는 시점을 결정해요. Service Account가 enabled 상태가 아니면 인가 토큰을 가져오려는 시도는 차단되고, Service Account는 이전에 발급된 인가 토큰을 사용해 자신을 위해 요청을 실행할 수 없어요.
다음은 여러분의 서비스나 확장 프로그램을 위해 ALL PERMISSIONS를 가진 Service Account를 생성하는 예제예요.
PUT /_plugins/_security/api/internalusers/admin_service
{
"opendistro_security_roles": ["all_access"],
"backend_roles": [],
"attributes": {
"enabled": "true",
"service": "true"
}
}
{% include copy-curl.html security=true %}
OBO 및 서비스 계정 요청 처리하기
OBO 토큰 처리와 서비스 계정(Service Accounts)은 각각 독립적인 기능으로 볼 수 있지만, 두 기능을 결합했을 때 가장 큰 이점을 얻을 수 있어요. 구체적으로, OpenSearch는 OpenSearch 클러스터에 연결하는 데 사용되는 클라이언트를 노출하며, 플러그인이 요청을 실행할 수 있는 기능을 제공해요.
OBO 토큰과 서비스 계정을 사용하면 이제 클라이언트로 이 두 기능을 모두 활용하는 요청을 처리할 수 있어요. 클라이언트가 확장(extensions)에서 OBO 토큰을 사용해야 하는 요청을 보내면, 요청 처리의 첫 단계는 해당 요청을 Security 플러그인으로 전달하는 거예요. Security 플러그인에서는 활성 사용자(active user)를 기준으로 요청을 인증하고 권한을 부여해요. 활성 사용자가 허용되면 요청은 OpenSearch의 핵심 코드 베이스로 돌아가고, 여기서 활성 사용자의 신원을 사용해 대상 확장을 위한 OBO 토큰을 생성하는 요청이 만들어져요. 이 OBO 토큰 생성 요청은 이후 IdentityPlugin 구현에서 처리돼요. 표준 시나리오에서는 Security 플러그인이 그 역할을 하므로, 요청은 Security 플러그인의 TokenManager 인터페이스 구현으로 반환되고, 이 구현이 요청에 대한 새로운 OBO 토큰을 생성해요.
토큰이 생성되고 나면 Security 플러그인은 OBO 토큰이 담긴 요청을 확장으로 전달해요. 이 시점부터 확장은 토큰으로 OpenSearch의 REST 메서드를 호출할 수 있어요. 그런 다음 토큰에 연관된 권한이 요청 승인을 위해 평가돼요. 토큰이 해당 작업에 필요한 권한을 담고 있다면 작업이 수행되고, 응답이 확장으로 다시 전송돼요. 확장은 OpenSearch의 응답을 처리한 뒤, 자체적인 응답 처리 결과를 클라이언트로 전달해요. 반면 OBO 토큰이 대상 작업을 시작하는 데 필요한 권한을 담고 있지 않으면 확장으로 forbidden 응답이 반환돼요.
자기 자신을 대신해 동작하는 확장 역시 OpenSearch가 노출하는 클라이언트를 사용해요. 확장이 OpenSearch에서 처음 초기화될 때 IdentityPlugin이 트리거되어 해당 확장을 위한 새로운 서비스 계정을 생성하고, 관련된 서비스 계정 토큰을 제공해요. 기본 설정에서는 Security 플러그인이 IdentityPlugin 역할을 하며 이 과정들을 처리해요.
OpenSearch가 서비스 계정 토큰을 받으면 해당 토큰을 연관된 확장으로 전달해요. 확장이 자신의 토큰을 받고 나면, 클라이언트가 해당 확장에 연관된 서비스 계정을 활용하는 요청을 수행할 수 있게 돼요. 이런 시나리오에서는 확장이 클라이언트로부터 요청을 받은 다음, 요청과 함께 서비스 계정 토큰을 OpenSearch로 전달해요. OpenSearch는 이어서 패키지를 Security 플러그인으로 넘기고, 여기서 토큰이 파싱되며 요청은 InternalAuthenticationBackend에서 "Basic Authentication"을 사용하는 전통적인 방식의 요청으로 취급돼요.
OBO 및 서비스 계정 토큰 요청 흐름 모두에서, IdentityPlugin은 IdentityPlugin을 위한 TokenManager 인터페이스를 사용해 토큰의 배포와 처리를 담당해요. 이 인터페이스는 Security 플러그인이 IdentityPlugin으로서 구현하며, OBO 토큰 또는 서비스 계정 토큰을 발급하는 로직을 담고 있어요.