화면에 Role 선택 상자가 하나 있다.

Viewer를 골랐다.

이제 Viewer 권한만 적용될 것 같다. 이름이 Role 선택이니까. 너무 자연스러운 예상이다.

그런데 Kubernetes 명령을 실행했더니, 선택하지 않은 다른 Role의 권한도 적용됐다.

“이거 버그 아닌가?”

처음 보면 그렇게 생각하기 쉽다. 나도 같은 지점에서 멈췄다.

하지만 코드를 따라가 보니 반전이 있었다.

같은 Role 선택 UI라도 제품마다 의미가 달랐다.

KAC에서 Role 선택은 지도 앱의 검색 필터에 가까웠다. 반면 SAC에서 Role 선택은 자동차의 기어 레버에 가까웠다.

겉모습은 같은 드롭다운인데, 하나는 “무엇을 보여줄까?”를 바꾸고 다른 하나는 “어떤 권한으로 움직일까?”를 바꾼다.

오늘은 이 미묘하지만 중요한 차이를 쉽게 풀어보려 한다.

먼저 KAC와 SAC가 뭘까?

둘 다 접근 제어다. 다만 지키는 대상이 다르다.

  • KAC, Kubernetes Access Control: Kubernetes Cluster와 API Resource 접근을 통제한다.
  • SAC, Server Access Control: Linux·Windows Server와 계정, SSH·RDP 같은 접속을 통제한다.

예를 들어 KAC에서는 이런 요청을 다룬다.

kubectl get pods -n dev
kubectl patch deployment demo -n dev --type merge -p '<patch>'

SAC에서는 이런 접속을 다룬다.

개발 서버에 SSH로 접속
운영 서버에 RDP로 접속
특정 서버 계정으로 SFTP 사용

둘 다 사용자에게 Role을 부여한다. 둘 다 Agent에서 Role을 선택할 수 있다.

바로 여기서 오해가 시작된다.

KAC Role 선택은 ‘지도 필터’다

지도 앱에서 카페를 선택했다고 해보자.

지도에는 카페만 보인다. 그렇다고 내 운전면허에서 식당과 병원 방문 권한이 사라지는 건 아니다.

KAC의 Role 선택도 비슷하다.

KAC Role A 선택
  -> Role A로 접근 가능한 Cluster만 표시
  -> Cluster 선택
  -> kubectl 요청 실행

선택한 KAC Role은 Cluster를 찾기 쉽게 목록을 좁힌다.

하지만 실제 kubectl 요청을 평가할 때는 사용자가 가진 유효한 KAC Role 전체를 본다.

사용자가 가진 Role
  - Viewer
  - Operator
  - 그룹을 통해 받은 Security Role

실제 Kubernetes 요청
  -> 세 Role의 Policy를 모두 평가

핵심은 이것이다.

KAC에서 Role을 선택하는 것은 다른 Role을 끄는 일이 아니다.

화면에서는 Viewer를 선택했어도, 사용자가 Operator 권한을 가지고 있다면 Operator Policy도 실제 요청 평가에 참여한다.

“Viewer를 골랐는데 수정이 되네요?”

조금 더 구체적인 예를 보자.

사용자에게 두 개의 KAC Role이 있다.

KAC Role Policy
Viewer Pod 조회 허용
Operator Deployment 수정 허용

Multi-Agent에서 Viewer를 선택한 뒤 다음 명령을 실행한다.

kubectl patch deployment demo -n dev --type merge -p '<patch>'

Viewer Policy에는 Deployment 수정 규칙이 없다.

하지만 Operator Policy에는 수정 허용 규칙이 있다.

그래서 전체 평가 결과는 Allow가 될 수 있다.

Viewer: 매칭 규칙 없음
Operator: Allow
최종 결과: Allow

여기서 아주 중요한 구분이 하나 있다.

‘규칙이 없음’과 ‘명시적으로 Deny’는 다르다.

다른 Role에 Deny가 있다면 결과가 달라질 수 있다.

KAC Role Policy
Developer Secret 조회 Allow
Security Secret 조회 Deny
kubectl get secret api-key -n dev
Developer Allow
+
Security Deny
=
최종 Deny

즉 “선택하지 않은 Role도 적용된다”는 말은 모든 권한이 무조건 넓어진다는 뜻이 아니다.

다른 Role의 Deny도 함께 따라온다.

권한은 덧셈만 하는 계산기가 아니라, Allow와 Deny를 함께 판정하는 심판에 가깝다.

그렇다면 All Role은 슈퍼 권한일까?

이름만 보면 왠지 강해 보인다.

All Role.

최종 보스가 쓸 것 같은 이름이다.

하지만 KAC의 All Role은 별도의 슈퍼 권한이 아니다. 사용자가 가진 모든 Role의 Cluster를 한 번에 보여주는 특별한 필터에 가깝다.

선택값 화면에 보이는 Cluster 실제 요청 평가
Role A Role A의 Cluster 전체 보유 KAC Role
Role B Role B의 Cluster 전체 보유 KAC Role
All Role 모든 보유 Role의 Cluster 전체 보유 KAC Role

Role A를 선택하든 All Role을 선택하든 실제 Kubernetes 요청의 평가 원칙은 같다.

달라지는 것은 주로 지도에 표시되는 목적지다.

SAC Role 선택은 ‘기어 레버’다

이제 SAC를 보자.

SAC에서 Role 선택은 단순한 서버 목록 필터가 아니다.

현재 어떤 Role로 서버에 접속할지를 정하는 권한 문맥이다.

SAC Role A 선택
  -> Role A로 접근 가능한 Server 조회
  -> Role A로 접근 가능한 Account 조회
  -> Role A의 Policy 확인
  -> SSH/RDP/SFTP 접속 판단

자동차에서 D를 선택하면 전진하고 R을 선택하면 후진한다.

선택한 기어가 계기판 목록만 바꾸는 게 아니라 실제 자동차의 움직임을 바꾼다.

SAC도 비슷하다.

Role A를 선택하면 서버 목록, 계정, Protocol, 시간과 IP 조건, Command Policy를 Role A의 문맥으로 평가한다.

일반적으로 Role B의 Policy를 몰래 끌어와 합산해서 접속을 허용하지 않는다.

그래서 KAC와 SAC를 가장 짧게 비교하면 이렇다.

KAC Role 선택 = 어떤 Cluster를 찾을지 고르는 지도 필터
SAC Role 선택 = 어떤 Role로 서버에 접속할지 정하는 기어 레버

All Role과 Default도 이름만 보고 엮으면 안 된다

KAC에는 All Role이 있고 SAC에는 Default가 있다.

둘 다 특별한 선택값처럼 보여서 비슷하다고 생각하기 쉽다.

하지만 완전히 다른 개념이다.

  • KAC All Role: 내가 가진 Role 전체의 Cluster를 보여주는 필터
  • SAC Default: 일반 Role 대신 Direct Permission이나 Workflow로 받은 권한을 사용하는 문맥

즉 다음 공식은 틀렸다.

KAC All Role = SAC Default

이 둘은 이름도, 목적도, 권한 적용 방식도 다르다.

Audit에 여러 Role이 보이는 이유

KAC Audit Log에 이런 값이 보일 수 있다.

선택한 KAC Role: Viewer
Affected Roles: Viewer, Security

이걸 보고 사용자가 Viewer와 Security를 동시에 선택했다고 해석하면 안 된다.

Affected Roles는 화면에서 선택한 Role 목록이 아니다.

현재 요청의 최종 결과에 영향을 준 Role 목록이다.

  • Viewer의 Allow 규칙이 영향을 줬을 수 있다.
  • Security의 Deny 규칙이 영향을 줬을 수 있다.
  • 직접 부여가 아니라 그룹을 통해 받은 Role이 포함될 수도 있다.

Audit은 “어떤 버튼을 눌렀는가?”보다 “어떤 규칙이 판결에 참여했는가?”를 보여준다.

이 차이를 알면 여러 Role이 보이는 것이 이상 현상인지 정상적인 multi-role 평가인지 훨씬 빨리 판단할 수 있다.

같은 UI가 같은 의미를 보장하지 않는다

이번에 가장 흥미로웠던 교훈은 접근 제어 규칙보다 UI 언어였다.

Select Role이라는 문구는 너무 많은 것을 생략한다.

사용자는 이렇게 읽을 수 있다.

이 Role만 활성화한다.

하지만 제품은 이렇게 구현했을 수 있다.

이 Role 기준으로 Resource 목록만 좁힌다.

또 다른 제품에서는 정말 이렇게 동작할 수 있다.

이 Role을 현재 접속 권한 문맥으로 사용한다.

세 문장은 완전히 다르다.

그래서 Role 선택 UI에는 가능하면 역할을 설명하는 짧은 문장이 필요하다.

KAC라면:

선택한 Role로 접근 가능한 Cluster를 표시합니다. 실제 요청에는 보유한 전체 KAC Role Policy가 적용됩니다.

SAC라면:

선택한 Role을 기준으로 접근 가능한 Server와 Account를 표시하고 접속 권한을 평가합니다.

도움말 한 줄이 지원 티켓 여러 개를 줄일 수 있다.

권한 문제를 볼 때 던질 다섯 가지 질문

비슷한 현상을 만났다면 “왜 선택한 Role과 다르지?”에서 멈추지 말고 아래 순서로 보면 좋다.

1. 이 Role 선택은 필터인가, 실제 권한 전환인가?

제품 문서와 요청 흐름을 먼저 확인한다.

2. 사용자가 가진 전체 Role은 무엇인가?

직접 부여뿐 아니라 그룹을 통해 받은 Role도 본다.

3. 매칭 규칙 없음인가, 명시적 Deny인가?

둘은 같은 상태가 아니다.

4. Audit의 Role 필드는 무엇을 의미하는가?

선택 Role인지, 평가 Role인지, 결과에 영향을 준 Role인지 구분한다.

5. 특별 선택값의 의미는 무엇인가?

All, Default, None 같은 이름을 보고 추측하지 말고 실제 계약을 확인한다.

이 다섯 질문만으로도 UI 오해, Policy 문제, 실제 authorization 버그를 상당히 빠르게 나눌 수 있다.

버그를 고치기 전에 계약부터 읽자

선택하지 않은 Role이 적용되는 현상만 보면 가장 쉬운 수정은 이것이다.

선택한 Role 하나만 authorization에 넘긴다.

코드 한두 줄로 끝날 수도 있다.

하지만 그 동작이 의도된 multi-role 정책이라면, 이 수정은 버그 픽스가 아니라 권한 모델을 되돌리는 회귀가 된다.

접근 제어 코드는 특히 그렇다.

눈앞의 증상만 고치면 Allow 범위가 달라지고, Deny 우선순위가 깨지고, Audit 근거가 사라질 수 있다.

그래서 패치 전에 세 가지를 함께 봐야 한다.

  1. UI가 사용자에게 무엇을 약속하는가?
  2. API와 Proxy가 어떤 Role을 실제로 평가하는가?
  3. Audit은 어떤 판단 근거를 남기는가?

세 층이 같은 말을 하고 있어야 한다.

오늘의 결론

같은 Role 드롭다운이라고 같은 기능은 아니다.

KAC에서 Role 선택은 Cluster를 찾는 지도 필터다. 실제 Kubernetes 권한은 사용자가 가진 전체 KAC Role Policy를 평가한다.

SAC에서 Role 선택은 서버 접속의 기어 레버다. 선택한 Role 또는 Default 직접 권한이 실제 접속 문맥이 된다.

그리고 가장 중요한 문장은 이것이다.

권한 문제에서 ‘무엇을 선택했는가’와 ‘무엇을 평가했는가’는 반드시 따로 확인해야 한다.

UI 이름만 보고 authorization 계약을 추측하면 빠르게 결론에 도착할 수는 있다.

문제는 그 결론이 반대 방향일 수도 있다는 것이다.