일반적으로 인가 시스템의 승인 여부는 다음과 같은 질문을 고려해야 한다.
1. 사용자는 누구인가?
2. 사용자와 관련된 데이터는 무엇인가?
3. 리소스에 접근하기 위한 조건은 무엇인가?
위 질문들에 대한 답변을 확인한 다음, 접근 권한을 부여할지 결정해야 한다.
일반적으로 ID 공급자(Keycloak 등)으로부터 발급받은 토큰에 포함된 인가 데이터를 토대로 어플리케이션 내부에서 접근제어를 수행하는 방법이 있다. 다른 방법으로는 Keycloak 에 인가 위임하여 Keycloak 을 통합 인증서버로 활용하는 방법도 있다. 두 가지 방법을 각각 사용할 수도 있고 같이 사용할 수도 있다.
이제 Keycloak을 사용해 어플리케이션에서 다양한 인증 전략을 활성화하는 방법을 살펴보자.
RBAC 은 사용자에게 부여된 역할을 토대로 접근 제어를 하는 방법이다.
역할은 사용자 개인 또는 조직 등 레벨에 따라 부여할 수 있다. 예를 들어 Keycloak 에는 realm 과 client 에서 설정할 수 있는 역할이 각각 하나씩, 총 두 종류의 역할을 갖고 있다.
realm 레벨에서 정의된 역할을 realm roles 라고 하며 일반적으로 realm 에 존재하는 다양한 클라이언트에 관계없이 조직 내 사용자의 역할을 나타낸다.
반면 client roles 는 클라이언트에 따라 다르며 역할의 의미는 클라이언트가 사용하는 시멘틱에 따라서 달라진다.
만약 역할이 갖고있는 범위가 동일한 의미를 가지며 여러 클라이언트에 포함될 경우 realm role 로 정의할 수 있다. 반대로 특정 클라이언트만 역할을 수행할 경우 client role 을 사용하는 것이 적절하다.
역할을 사용하는 경우 무분별한 역할 사용을 피해야한다. 과도하게 많을 경우 관리하기 어렵게 될 수 있다. 이를 방지하기 위해 한가지 방법으로는 역할이 관련된 범위와 어플리케이션에서 역할과 관련된 권한의 세분성을 고려해 매우 신중하게 역할을 생성하는 것이다. 역할의 범위가 세분화될수록 시스템에는 더 많은 역할이 존재한다. 또한 인가를 위해 역할 사용을 자제해야한다.
또 하나 역할을 부여할 때 그룹 단위로 역할을 부여한다면 역할 관리 이슈를 해결할 수 있다. Keycloak 에서는 그룹 단위로 역할 부여 기능을 제공할 뿐만 아니라 체인 기능까지 더해져 특정 역할을 다른 역할에 체이닝할 수도 있다. 해당 역할을 부여받은 사용자는 체이닝된 역할들도 사용할 수 있다. (그러나 무분별한 체이닝은 역할 관리 이슈로 이어질 수 있다)
시스템 역할을 모델링하는 방법은 Keycloak 에서 발행하는 토큰의 크기에도 영향을 미친다. 따라서 토큰에는 클라이언트가 로컬에서 또는 해당 토큰을 사용하는 다른 서비스에 접근할 때 필요한 최소한의 역할 집합이 포함되도록 모델링해야한다.
Keycloak 에서는 realm 그룹을 관리할 수 있으며 사용자는 특정 그룹 내 포함시킬 수 있다. 그리고 역할을 그룹에 할당하여 관리를 할 수 있기 때문에 사용자마다 관리할 필요가 없다. Keycloak 의 그룹은 계층 구조이며, 토큰이 발행되면 그룹의 경로를 보고 계층 구조를 순회한다. 예를 들어, 인사 팀 그룹(human_resource)이 있고 하위 그룹에 매니저(manager) 그룹이 있다 가정하자. Keycloak 이 그룹에 대한 정보를 토큰에 포함할 경우 해당 정보는 /human_resource/manager 형식으로 저장된다. 해당 정보는 객체가 그룹의 멤버인 서버에서 발급된 모든 토큰에게 적용된다.
그러나 역할과 달리 그룹 정보는 토큰에 자동으로 포함되지 않는다. 이런 경우 특정 프로토콜 매퍼를 클라이언트에 연결해야 한다. 다음 실습을 통해 자세히 알아보자.
myclient
로 지었다.(이미지 생략)myclient
로 지었기 때문에 scope 이름도 myclient-dedicated
로 만들어져 있다.group membership
으로 설정하였다.OAuth2 범위를 사용한 권한 부여는 전적으로 사용자 동의를 기반으로 한다. 리소스 서버는 액세스 토큰을 활용해 사용자가 부여한 범위에 따라 클라이언트가 리소스 서버의 보호된 리소스에 접근한다. 이는 앞서 살펴본 전략과 근본적인 차이가 있다. 예를 들어 RBAC 은 사용자로부터 시스템을 보호하는 반면, OAuth2 는 클라이언트로부터 시스템을 보호할 수 있다.
RBAC:
1. 사용자는 역할(role)에 할당됨
2. 역할에는 특정 리소스에 대한 권한(permission)이 정의됨
3. 권한이 부여된 역할을 가진 사용자는 리소스에 접근 가능
=> 사용자가 해당 서비스에 대한 접근이 가능한가?
OAuth2:
1. 접근 범위(scope)가 토큰에 포함되어 특정 리소스에 대한 접근을 제어
2. 클라이언트는 access token을 사용하여 보호된 리소스에 접근
=> 특정 어플리케이션이 리소스 서버에서 특정 사용자 데이터에 대한 접근이 가능한가?
토큰에는 인증된 사용자 및 토큰이 발급된 클라이언트에 대한 정보, 그리고 인증 프로세스 수행 중 수집한 정보 등이 담겨있다. ABAC 은 토큰에 담겨있는 정보들을(클레임) 토대로 접근 권한을 제어하는 전략이다. RBAC 과 달리 유연하게 접근을 제어할 수 있다. 예를 들어, RBAC 은 사용자가 가진 역할에 범위를 토대로 제어를 하지만, ABAC 은 사용자가 발급받은 토큰의 발행시간, 위치 등 다양한 속성을 토대로 제어할 수 있다.
다음과 같은 의사코드(pseudo-code)가 있다 가정하자.
if (User.hasRole("manager") {
// can access the protected resource
}
위 코드는 유저가 manager
라는 역할을 가졌는지 확인하고 보호된 리소스에 접근할 수 있는 코드이다(RBAC). 만약 요구 사항이 변경되어 동일한 리소스에 대한 접근 권한을 특정 사용자에게도 부여해야 하면 어떻게 될까? 또는 다른 역할이 부여된 사용자에게 해당 리소스에 대한 접근 권한을 부여하려면 어떻게 해야할까? 요구사항이 변경될 때마다 코드 변경하고 어플리케이션을 다시 배포해야 할 것이다.
이번에는 다른 코드를 살펴보자
if (User.canAccess("Manager Resource") { // 외부 인가 서비스에서 부여한 권한
// can access the protected resource
}
유저가 Manager Resource
에 접근가능한지 확인하고 보호된 리소스에 접근할 수 있는 코드이다. 즉, 어플리케이션에서 직접 접근 제어하는 것이 아닌 Keycloak 등에서 부여한 권한만 고려하여 보호된 리소스를 접근할 수 있다. Keycloak 의 Authorization Services 기능을 통해 통합 인가 서비스를 사용하면 어플리케이션 내 코드 수정 및 재배포를 안하고도 바로 수정할 수 있다. Keycloak 의 인가 서비스 기능은 세분화된 인가를 수행하기 위해 ABAC 을 활용한다.
통합 인가 서버의 일반적인 이슈는 접근 결정을 수행하기 위해 추가적인 통신이 필요하다는 점이다. 이는 토큰 기반 인가를 사용하면 Keycloak 인가 서비스 기능은 서버에서 부여한 모든 권한을 가진 토큰을 발급하고, 어플리케이션은 내부적으로 검증하는 것 이외에 추가적인 네트워크 요청이 필요없기 때문에 해결할 수 있다.