LabHub
배우기 러닝패스 코스

CNPE — クラウドネイティブプラットフォームエンジニア

セルフサービスの囲いは何を塞ぐのか

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

한 줄 요약

스키마는 요청의 내용, RBAC은 주체의 권한, ResourceQuota는 네임스페이스의 상한을 다룹니다. 허용된 요청도 쿼터에서 거절될 수 있고, 조회 실패는 안전한 거절의 증거가 아닙니다.

フロー図: 한 줄 요약・왜 이게 필요했나・어떻게 동작하나・권한 조회와 실제 요청을 구분합니다

왜 이게 필요했나

다음은 연습 상황입니다. blue-dev의 Role에는 AppClaim 읽기와 생성만 있습니다. 그런데 시크릿 읽기가 됩니다. Role 파일이 잘못 적용됐다고 단정하기 전에 같은 주체에 연결된 다른 바인딩을 봐야 합니다. RBAC의 권한은 허용 규칙을 합칩니다. 한 Role에서 동사를 빼는 것은 다른 Role이 준 허용을 취소하는 deny 규칙이 아닙니다.

RoleBinding은 ClusterRole을 참조할 수도 있습니다. 이때 권한은 그 RoleBinding의 네임스페이스 안에 적용됩니다. ClusterRole이라는 이름만 보고 항상 클러스터 전체 권한이라고 결론내리지 마세요. 어떤 바인딩이 어떤 범위로 연결했는지 봐야 합니다. 공식 RBAC 규칙과 바인딩

어떻게 동작하나

권한 조회와 실제 요청을 구분합니다

kubectl auth can-i는 인가 판정을 조회합니다. “create 가능”이라는 답이 입력 스키마나 ResourceQuota까지 통과한다는 뜻은 아닙니다. 최종 동작은 해당 주체의 실제 요청 또는 안전한 서버 dry-run으로 확인합니다. 서버 dry-run은 API의 검증 경로를 거치되 객체를 저장하지 않는 방법이지, 모든 애플리케이션 동작을 실행하는 방법은 아닙니다. 공식 API dry-run

실습 환경의 관리자 문맥에서 다음 조회를 실행할 수 있습니다. 일반 사용자에게 임의 주체의 --as 사용 권한이 자동으로 생기는 것은 아닙니다.

kubectl auth can-i get appclaims.platform.labhub.io \
  -n tenant-blue --as=system:serviceaccount:tenant-blue:blue-dev
kubectl auth can-i patch appclaims.platform.labhub.io \
  --subresource=status -n tenant-blue \
  --as=system:serviceaccount:tenant-blue:blue-dev

뒤 명령의 --subresource=status를 빼면 다른 질문이 됩니다. resource/name 표현의 name 자리에 status를 넣어도 서브리소스 권한을 물은 것이 아닙니다. 공식 can-i 사용법

이번 실습의 검증된 kubectl에서는 명시적 허용이 stdout의 yes와 종료 코드 0, 명시적 거절이 no와 종료 코드 1로 나타납니다. 빈 stdout, 인증 오류, 연결 실패를 “yes가 아니므로 no”로 바꾸지 않습니다. 먼저 정상 get을 대조군으로 확인하고 거절 결과도 정확히 판별합니다. CLI·인가 방식이 달라지면 출력 형식부터 재확인해야 합니다.

API 사용 권한과 정책 관리 권한을 나눕니다

요청 이 실습의 정책 확인 이유
AppClaim get·list·watch·create·update·patch 허용 자기 팀이 신청하고 관찰하고 수정
AppClaim status patch·update 거절 관측 결과를 쓸 주체와 사용자 분리
쿼터 create·patch 거절 사용자가 자신의 상한을 수정하지 않음
Role·RoleBinding create 거절 정책 관리 기능을 셀프서비스 API와 분리
Secrets get, 다른 namespace의 AppClaim list 거절 자격 증명과 테넌트 범위 제한
AppClaim delete 거절 이 실습에서 선택한 운영자 회수 정책

여기서 Role 생성 권한만 얻으면 곧바로 관리자 권한을 만들 수 있다고 이해하면 안 됩니다. Kubernetes에는 자신이 갖지 않은 권한을 Role에 담거나 바인딩하는 행위를 제한하는 API 검사가 있습니다. escalatebind는 각각 관련 검사를 넘을 수 있는 특별한 권한이므로 더욱 신중히 다룹니다. 이 실습은 그 방어를 끄지 않고 Role 관리 자체도 테넌트의 업무에서 제외합니다. 공식 권한 상승 방지

와일드카드는 현재 필요한 리소스뿐 아니라 나중에 추가되는 권한 범위까지 넓힐 수 있습니다. 기본 edit 역할은 이름만으로 안전성을 판단할 수 없으며 시크릿 접근 등의 영향이 있습니다. 사용자의 일을 구체적인 API 그룹·리소스·동사로 적고 실제 바인딩까지 검토합니다. 공식 RBAC 모범 사례

개수 쿼터는 CPU 사용량이나 외부 비용을 재지 않습니다

count/appclaims.platform.labhub.io: "2"는 이 종류의 객체 개수를 제한합니다. 청구 하나가 외부 데이터베이스 10개를 만들더라도 그 비용을 자동으로 세지 않습니다. 개수 제한은 제어 평면 객체가 무제한 늘어나는 것을 막는 도구이며, 작업량·비용·만료 정책은 별도로 설계해야 합니다. 또한 CRD 기반이 아닌 aggregation API의 쿼터는 확장 API 서버 쪽 책임을 확인해야 합니다. 공식 객체 개수 쿼터

쿼터를 진단할 때 세 값을 나눠 읽습니다. spec.hard는 원하는 상한, status.hard는 적용된 상한, status.used는 관측된 사용량입니다. 사용량이 없다는 것은 0이라는 뜻이 아닙니다. 공식 ResourceQuota 필드

실습에서 used가 비었다면 먼저 CRD Established, API discovery, 실제 AppClaim 목록, 쿼터 status를 확인합니다. 반영 시간을 두고 다시 읽으며, 지속되면 관리자가 컨트롤러 상태를 조사합니다. exceeded quotastatus unknown, Forbidden, 연결 오류는 같은 실패가 아닙니다. 이름이 같은 오류처럼 보여도 출력의 원인을 구분해야 합니다. 상한을 늘리거나 쿼터를 삭제하는 것은 진단을 대신하지 못합니다.

삭제 금지는 Kubernetes의 필수 규칙이 아닙니다

이 실습은 테넌트 delete를 막고 운영자가 회수하도록 정했습니다. 실제 플랫폼에서는 사용자 삭제를 허용하고 컨트롤러가 finalizer로 외부 자원을 정리하는 설계도 가능합니다. finalizer는 실행 코드가 아니라 정리 책임을 나타내는 키입니다. 삭제 요청 후 deletionTimestamp가 생기고, 컨트롤러가 정리를 끝내 finalizer를 제거해야 객체 삭제가 마무리됩니다. 담당 컨트롤러가 없다면 키만 추가해도 정리가 실행되는 것은 아닙니다. 공식 finalizer 동작

현장에서 만나는 모습

LabHub의 기존 채점기에 권한 조회 오류를 주입하자 빈 응답도 “거절 확인”으로 통과했습니다. 수정 후에는 정상 get과 명시적 no를 함께 요구합니다. 쿼터 역시 실제 개수 2, 상한 2, 사용량 2를 대조하고 세 번째 요청의 실패가 쿼터 때문인지 확인합니다. 거절됐다는 결과만 기록하면 인증 장애와 올바른 정책을 구별할 수 없습니다.

다음 실습에서 할 것

blue-dev의 허용·거절 목록을 채우고 status와 다른 네임스페이스를 따로 확인하세요. 쿼터가 차면 두 served 버전으로 세 번째 청구를 보내 봅니다. 마지막 보고서에는 실제 조회한 값을 기록하되, 읽지 못한 값을 추측해서 채우지 마세요.