- Keystone은 OpenStack의 Identity Service로, 인증, 인가, 서비스 검색 기능을 제공하는 중앙 집중식 식별 서비스이다.
- Keystone의 핵심 데이터 모델 및 구성 요소
- User : Openstack API를 호출하는 주체. 사람일 수도 있고, nova, neutron과 같은 서비스 데몬일 수도이 있다.
- Project : 구 버전의
Tenant, 리소스(VM, 네트워크, 볼륨 등)가 격리되는 논리적 컨테이너이자, 과금 및 할당량 관리의 단위.
- Role : 사용자가 프로젝트 내에서 수행할 수 있는 작업의 범위를 정의하는 권한 식별자
- Role 자체는 구체적인 권한을 명시하지 않으며, 단순히 토큰에 포함되는 메타데이터 문자열로 기능한다. 실제 권한 제어는 각 서비스의 정책 파일(Policy.yaml)에서 수행된다.
- Token : 사용자의 신원과 권한 범위가 증명된 디지털 자격 증명
- OpenStack의 API 통신은 Stateless하므로, 로그인 세션 대신 매 API 요청의 HTTP 헤더에 이 토큰을 토함하여 전송한다.
- Endpoint & Service Catalog : OpenStack 내의 모든 서비스의 API URL 목록
- client는 Keystone으로부터 이 카탈로그를 받아, 자신이 요청해야할 서비스의 정확한 URL를 획득한다.
Authentication 및 Authorization의 동작 과정
- Authentication - 토근 발급 요청
- API 요청 (Client -> Keystone)
- Client는 자신의 자격 증명(ID/PW)과 접근하고자 하는 Scope(Project ID)를 포함한 JSON Payload를 구성하여 Keystone API를 호출한다.
- 자격 증명 검증
- Keystone은 백엔드 MariaDB의 user 및 password 테이블을 조회하여 자격 증명을 검증한다.
- 동시에 사용자가 요청한 Project에 접근할 권한이 있는지 확인한다.
- Fernet Token 생성
- 검증이 완료되면 Keystone은 Fernet 방식의 토큰을 생성한다.
- Fernet Token : DB에 저장되지 않는 토큰. 사용자 ID, 프로젝트 ID, 만료 시간, Role 목록 등의 정보를 MessagePack으로 직렬화한 뒤, Keystone 서버에 저장된 대칭키로 암호화하고 서명한 문자열.
- 응답 반환
- Keystone은 생성된 토큰 문자열을 HTTP 응답 헤더에 담고, HTTP Body에는 서비스 카탈로그를 담아 Client에게 반환한다.
- 서비스 요청 및 토큰 검증 (Token Validation)
- API 요청 (Client -> Nova)
- Client는 발급받은 토큰을 HTTP 헤더(X-Auth-Token)에 포함하여 Nova API를 호출한다.
- Keystone Middleware (Nova 내부)
- Nova API 서버 앞단에는 keystonemiddleware가 배치되어 있다.
- 이 미들웨어는 요청을 가로채어 헤더의 토큰을 추출한다.
- 토큰 유효성 검증 (Nova -> Keystone)
- Nova는 추출한 토큰이 유효한지, 만료되지 않았는지 확인하기 위해 Keystone API를 호출한다.
- Keystone은 토큰을 복호화하여 서명을 검증하고, 토큰이 폐기 목록에 없는지 확인한다.
- 메타데이터 반환
- 검증이 성공하면 keystone은 토큰에 포함되어 있던 User ID, Project ID, Roles를 JSON 형태로 Nova에게 반환한다.
- Authorization - 정책 검사
- 컨텍스트 생성 (Nova)
- Nova는 Keystone으로부터 받은 메타데이터를 기반으로 RequestContext 객체를 생성한다. 이 객체에는 이 요청자는 admin 프로젝트의 member 역할을 가지고 있음과 같은 정보가 담긴다.
- 정책 파일 조회 (policy.yaml)
- Nova는 자신의 설정 디렉토리(/etc/nova/policy.yaml)에 정의된 정책 규칙을 로드한다.
- 예를 들어, VM 생성 API(compute:create)에 대한 정책이 "rule:admin_or_owner"로 정의 되어 있다고 가정한다.
- 권한 대조
- Nova의 정책 엔진은 요청자의 Role과 정책 파일의 규칙을 대조한다.
- 요청자가 해당 API를 호출할 권리가 있으면 로직을 수행하고(HTTP 200/202), 권한이 없으면 거부(HTTP 403 Forbidden)한다.
- KeyStone : Token 발급기이자 검증기
- 인증 : ID/PW를 검증하여 Token을 발급하는 과정
- 인가 : 각 서비스가 Token 속의 Role 정보를 확인하고, 자신의 policy.yaml 규칙과 대조하여 실행 여부를 결정하는 과정
- OpenStack 내부의 모든 API 호출은 Token을 매개로 이루어진다.
서비스 간 통신에서 인증 및 인가
- OpenStack은 마이크로서비스 아키텍처이므로, 서비스 간의 통신에서도 인증이 필수적이다.
- Nova가 Glance 이미지를 요청할 때
- 사용자 토큰 전달
- Nova가 사용자의 요청을 처리하는 과정에서 Glance를 호출해야 할 때, Nova는 사용자가 보냈던 User Token을 그대로 Glance API 헤더에 실어 보낸다.
- Glance는 이 토큰을 다시 Keystone을 통해 검증한다.
- 이 방식은 사용자가 해당 이미지에 접근할 권한이 있는지를 Glance가 직접 판단할 수 있게 한다.
Nova가 직접 판단하고 명령을 내리는 것이 아니라, 토큰을 넘겨서 Glance가 직접 검사하는 이유
- [ 데이터 소유권과 보안 원칙 ]
- User A가 Image X를 가지고 VM을 만들려고 할 때
- Nova는 이 이미지가 public인지, private인지, shared 상태인지 모른다.
- 이미지의 속성과 공유 정책은 Glance DB에 있기 때문에 만약 Nova가 권한을 판단하려면, Glance DB를 모두 긁어와 로직을 중복으로 구현해야 한다.
- 이는 MSA 원칙에 위배된다. 따라서 Nova는 판단을 위임하며 토큰을 넘기는 것이다.
- 보안에서는 요청한 주체의 권한만큼만 수행하는 것이 원칙이다.
- 만약 Glance가 Nova의 요청을 무조건 신뢰한다면, 악의적인 사용자가 Nova를 통해 이미지를 얻으려고 할 때 Glance는 의심없이 이미지를 주게된다.
- 하지만 토큰을 넘기면, 토큰 내용에 따라 이미지의 권한과 비교하여 불일치 시 거절할 수 있게 된다.
- 서비스 토큰
- 경우에 따라 Nova가 사용자 권한이 아닌, Nova 서비스 자체의 권한으로 작업을 수행해야 할 때가 있다.
- 이때 Nova는
nova.conf에 설정된 서비스 계정 정보(ID/PW)를 이용해 Keystone으로부터 Service Token을 발급받고, 이를 이용해 다른 서비스를 호출한다.
Nova가 Service Token을 사용하는 경우
- 사용자의 토큰이 만료되었을 때 (대용량 이미지를 사용해서 VM 생성을 요청)
- 생성에 1시간 이상이 걸려 작업을 수행하는 도중에 사용자가 처음에 제출했던 토큰의 유효기간이 끝났지만, Nova는 작업이 끊기지 않도록 만료된 사용자 토큰 대신 Service Token을 사용하여 통신을 이어간다.
- 사용자가 시키지 않을 일을 할 때
- Nova는 주기적으로 모든 컴퓨트 노드의 상태를 확인하여 Placement 서비스에 보고하거나, 좀비 인스턴스를 정리하는 청소 작업을 한다. 이 처럼 시스템 유지를 위해 Nova가 스스로 하는 일에는 사용자 토큰 자체가 존재하지 않기 때문에 Nova 자신의 Service Token을 사용해서 DB에 접근하거나 다른 서비스에 리포트를 보낸다.