▶ Keycloak 인가(Authorization)
1. Keycloak 인가 개요
- Keycloak을 인증(Authentication)을 위한 도구로만 사용할 수도 있지만, 자원에 대한 세밀한 접근제어를 원할 때는 인가(Authorization) 기능까지 사용해야 제어를 할 수 있다.
2. Authorization(인가) 활성화
- 인가를 적용하기 위해서 먼저 인가를 적용할 Client를 선택한다.
- Capability config 하위의 Autorization을 ON으로 설정하면 인가 메뉴 활성화 된다.
3. Authorization 용어 정리
- 인가를 적용하기 위하여 아래 4개의 용어에 대한 이해가 필요하다.
[ 용어 정리 ]
1.자원(resource): 사용자가 접근하려는 페이지 또는 URIs
2.범위(scope) : 자원에 대한 동작 (C/R/U/D)
3.정책(policy) : ROLE/GROUP/TIME 별로 다른 정책을 정의
4.권한(permission) : 특정 자원에 어떤 작업을 누구에게 허용 또는 거부 할지에 대한 정의
4. Keycloak의 인가의 제약사항
5. 인가 정책 성능이슈
- 사용자가 매번 요청시마다 Application이 Keycloak의 Authorization Endpoint를 호출하면 Keycloak의 성능 이슈가 발생 할 수 있다.
- 이를 극복하기 위해서 사용자가 로그인을 할 때마다 1회만 Keycloak을 호출하여 사용자 권한에 따른 자원의 인가 목록을 받아오면 된다. 이 인가 목록을 Request Party Token, RPT라고 한다.
- Application은 이 목록을 Caching하여 이후 요청에 대하여는 Cache를 먼저 참조하도록 하면 성능 이슈를 해결 할 수 있다.
6. Keycloak 인가의 활용 전략
- Keycloak의 인가 기능을 기존 Spring Security 처럼 권한(ROLE)만을 통제/제어 할 것인지,
- 자원(resource)의 C/R/U/D 까지 상세히 통제/제어할 것인지에 대한 활용 전략을 결정할 필요가 있다.
6.1 방안(1) - ROLE만 체크하기
- Keycloak 인증 후 Keycloak 에 부여된 사용자의 권한을 Spring Security의 Authority 에 넣어주면 기존 Spring Security 적용했을 때 처럼 동작한다.
- Keycloak 에서는 Role 정책 과 사용자에 대한 Role 맵핑을 실시간으로 해주기만 하면 로그인 시 바로 적용되게 된다.
- Role만 체크하는 또 하나의 방법은 Keycloak > Authorization > Permission에서 Role base permission 으로 자원과 권한만 맵핑해 주면 앞의 Authority 를 통해 제어했던 것과 같이 사용자의 자원에 대한 접근 통제 및 제어를 수행 할 수 있다.
6.2 방안(2) - resource + scope + policy까지 체크하기
- Keycloak에서는 자원에 대한 어떤 행위(동작)까지 세밀하게 제어할 수 있다.
- Keycloak > Authorization > Permission 메뉴에서 Scope base permission 을 선택하고,
- 자원(resource) vs 범위(scope/action) vs 정책(policy/role)을 맵핑해 주면 된다.
- 또는 Application은 RPT(Request Party Token) 토큰을 받아서 권한을 체크하면 상세한 부분까지 접근 통제 및 제어가 가능하다.
7. RPT(Request Party Token)
- RPT는 사용자의 권한에 대해 접근이 허용되는 자원/범위에 대한 목록을 말한다.
- 아래 Endpoint를 통해 요청하면 발급 받을 수 있고 샘플은 아래와 같다.
- Endpoint : /protocol/openid-connect/token
- 자원별로 자원명(rsname), 범위(scope), 자원ID(rsid)이 Object로 리턴된다.
# RPT sample
[
{
"rsid": "6d8166dd-fd3d-4a3f-a67a-417adf73af39",
"rsname": "/admin/*",
"scopes": [
"GET",
"POST",
"PUT",
"DELETE"
]
},
{
"rsid": "88110074-6c39-47e2-b4ff-002172b655d4",
"rsname": "/user/*",
"scopes": [
"GET",
"POST",
"PUT",
"DELETE"
]
}
]
8. Resource 제어시 이슈
- RPT 토큰을 활용하여 자원에 대한 접근을 제어 시 이슈가 있다.
- resource-id vs resource name
- 자원(resource) 등록시 URIs 정보에 자원의 패턴을 등록한다. (예를 들면 /admin/*, /user/* 처럼 패턴으로 등록)
- 그러나 Authorization Endpoint를 통해서 RPT 권한 토큰을 받으면 여기에는 URIs 가 없다. 따라서 사용자가 요청한 URI가 허용되는 자원인지 여부를 판단 할 수 가 없다.
- 해결책 (Work-around)
- 이를 해결하기 위하여 RPT(권한토큰) 발급시 들어있는 resource name을 활용한다. resource name에 URIs 패턴과 같은 값을 넣어 주고 패턴 비교시 자원명(rsname)의 패턴과 사용자가 요청한 URI를 비교한다.
[ 이슈 ]
- RPT 권한토큰에 URIs 패턴 정보가 없음
- rsname을 차선책으로 활용하여 권한 허가/거부 여부를 판단함
9. Decision strategy
- 자원과 범위, 정책을 조합하여 권한(permission)을 등록하면 정책 상호간에 충돌이 발생 할 수 있다.
- 예를 들면, 같은 자원인데 어떤 정책에서는 접근을 허용(Positive/Permit)하고
- 어떤 정책에서는 접근을 불가(Negative/Deny) 시킬 수 있다.
- 이를 해결하기 위하여 Keycloak에서는 아래 3가지 전략을 제시한다.
Affirmative(긍정, 동의)
- 여러 정책 중에 하나라도 허용이면 전체를 <허용>
- 가장 관대한 방식
Unamimouse(만장일치)
- 모든 정책이 허용이어야 함, 하나라도 불가가 있으면 전체가 <불가>
- 가장 엄격한 방식
Consensus(합의)
- 허용의 개수가 불가보다 많으면 <허용>, 불가의 개수가 허용보다 많으면 <불가>
- 균형있는 다수결 방식