Grafana와 ArgoCD를 배포해서 사용 중인데 개별로 사용자 관리를 하는 것이 불필요하다고 생각이 들었습니다.
점점 회사에 사람들이 많아지는 중이고, 그럴 때마다 각각 관리를 하는 건 매우 비효율적이라고 판단했습니다.
마침 KeyCloak으로 kube-apiserver에 대한 접근 제어를 사용하고 있었는데,
비슷한 방식으로 애드온에 대한 계정 관리도 가능하지 않을까 싶었습니다.
마침 구글링을 해보니 몇 가지 사례들이 있었고, 제가 운영하는 리소스에도 적용하면서 그 과정을 정리해보려고 합니다.
먼저 ArgoCD 구성을 변경하기에 앞서서 KeyCloak 재설치를 먼저 진행했습니다.
ArgoCD OIDC 설정 중에 logoutURL이라는 속성을 추가할 수 있는데, ArgoCD에서 로그아웃 하면 KeyCloak에서도 세션이 끊어지게 되도록 설정할 수 있습니다.
KeyCloak에서 로그아웃 동작을 수행할 수 있는 REST API 명세에 맞게 logoutURL을 작성해야 하는데, 기존에 사용 중이었던 KeyCloak의 버전은 17.0.1-legacy이라 버전이 너무 낮아 적절한 REST API 값을 맞춰 넣는 것이 힘들었습니다.
~ helm search repo keycloak
NAME CHART VERSION APP VERSION DESCRIPTION
bitnami/keycloak 21.4.4 24.0.5 Keycloak is a high performance Java-based ident...
codecentric/keycloak 18.4.4 17.0.1-legacy Open Source Identity and Access Management For ...
codecentric/keycloakx 2.3.0 22.0.4 Keycloak.X - Open Source Identity and Access Ma...
codecentric에서 제공하는 keycloak 헬름 차트를 쓰고 있었는데, 이번에 bitnami keycloak 차트를 사용해서 24.0.5 버전으로 재설치하게 되었습니다.
공식 문서를 참고하면 대부분의 설정을 하실 수 있는데, 저는 ArgoCD를 Helm Chart로 배포했기 때문에 Configuring ArgoCD OIDC 부분에서 사용한 것과 같이 직접 Configmap과 Secret을 수정하는 방식이 아닌, values.yaml에 속성을 수정해서 재배포 했습니다.
...
...
configs:
cm:
url: https://argocd.example.com
oidc.config: |
name: Keycloak
issuer: https://keycloak.exmaple.com/realms/exmaple
clientID: example
clientSecret: $oidc.keycloak.clientSecret
requestedScopes: ["openid", "profile", "email", "groups"]
logoutURL: https://keycloak.example.com/realms/example/protocol/openid-connect/logout?id_token_hint={{token}}&post_logout_redirect_uri=https://argocd.example.com
...
...
secret:
extra:
oidc.keycloak.clientSecret: ********************************
...
...
rbac:
policy.csv: |
g, argocd-admin, role:admin
g, argocd-member, role:readonly
...
...
********************************
대신 KeyCloak 콘솔 내부에서 Client의 Credentials 탭에서 client secret을 생성하고 대입하면 됩니다.Grafana Labs 공식 문서에 가이드가 잘 나와있어서 참고를 했고 내용에 따라 진행하면 대부분의 설정은 진행할 수 있지만 몇 가지 특이점이 있어서 내용을 작성했습니다.
가이드를 참고해서 values.yaml을 수정하고 배포했더니 오류가 발생했습니다.
Sensitive key 'auth.generic_oauth.client_secret' should not be defined explicitly in values. Use variable expansion instead. You can disable this client-side validation by changing the value of assertNoLeakedSecrets.
grafana 차트의 helper를 사펴보니 아래와 같은 코멘트를 볼 수 있었습니다.
values.yaml에 평문으로 데이터를 넣지 못하게 막혀 있었습니다.
...
...
{{/*
Checks whether the user is attempting to store secrets in plaintext
in the grafana.ini configmap
*/}}
{{/* grafana.assertNoLeakedSecrets checks for sensitive keys in values */}}
...
...
구글링을 해보니 환경 변수로 처리가 가능해서 values.yaml을 수정해서 배포했습니다.
# kube-prometheus-stack/values.yaml
...
...
# 오류 발생
grafana:
grafana.ini:
auth.generic_oauth:
enabled: true
name: Keycloak
allow_sign_up: true
client_id: grafana-client
client_secret: ********************************
scopes: openid email profile offline_access roles
email_attribute_path: email
login_attribute_path: username
name_attribute_path: full_name
auth_url: https://keycloak.example.com/realms/example/protocol/openid-connect/auth
token_url: https://keycloak.exmaple.com/realms/example/protocol/openid-connect/token
api_url: https://keycloak.example.com/realms/example/protocol/openid-connect/userinfo
role_attribute_path: contains(roles[*], 'admin') && 'Admin' || contains(roles[*], 'editor') && 'Editor' || 'Viewer'
signout_redirect_url: https://keycloak.example.com/realms/example/protocol/openid-connect/logout?post_logout_redirect_uri=https%3A%2F%2Fhttps://grafana.example.com%2Flogin
...
...
# 개선
...
...
grafana:
env:
GF_SERVER_DOMAIN: "https://grafana.example.com"
GF_SERVER_ROOT_URL: "https://grafana.example.com"
GF_AUTH_GENERIC_OAUTH_ENABLED: "true"
GF_AUTH_GENERIC_OAUTH_NAME: "Keycloak"
GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP: "true"
GF_AUTH_GENERIC_OAUTH_CLIENT_ID: "grafana-client"
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: "********************************"
GF_AUTH_GENERIC_OAUTH_SCOPES: "openid email profile offline_access roles"
GF_AUTH_GENERIC_OAUTH_AUTH_URL: "https://keycloak.example.com/realms/example/protocol/openid-connect/auth"
GF_AUTH_GENERIC_OAUTH_TOKEN_URL: "https://keycloak.example.com/realms/example/protocol/openid-connect/token"
GF_AUTH_GENERIC_OAUTH_API_URL: "https://keycloak.example.com/realms/example/protocol/openid-connect/userinfo"
GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH: "contains(roles[*], 'admin') && 'Admin' || contains(roles[*], 'editor') && 'Editor' || 'Viewer'"
GF_AUTH_SIGNOUT_REDIRECT_URL: 'https://keycloak.example.com/realms/example/protocol/openid-connect/logout?post_logout_redirect_uri=https://grafana.example.com/login&client_id=grafana-client'
...
...
ArgoCD와 마찬가지로 로그아웃을 하면 KeyCloak의 세션도 끊어지도록 설정하고 싶었습니다.
Grafana 변수에도 GF_AUTH_SIGNOUT_REDIRECT_URL에 대해 적용을 했는데 KeyCloak 세션이 끊어지지 않는 문제가 있었는데요.
Grafana에 대한 Client 설정을 할 때, Valid post logout redirect URIs를 적용해주었더니 해결되었습니다.
공식 문서만 참고해서 연동하게 되면 모든 사용자에게 Viewer 권한이 할당되는 것을 볼 수 있었습니다.
여러 가지 방법을 시도해 보면서 제가 해결한 방법은 Dedicated scopes에 'roles'라는 객체를 새로 추가하고, 모든 옵션을 활성화시켜주었더니 사용자에게 적절한 권한이 할당되었습니다.
https://honglab.tistory.com/265#fromHistory
https://kmaster.tistory.com/77
https://ksr930.tistory.com/277
https://enginnersnack.tistory.com/16
안녕하세요. 글 잘 읽었습니다.
혹시 argoCD에서 로그아웃해도 grafana에서 로그아웃 잘 이루어지시나요?