LabHub
배우기 러닝패스 코스

GitOps 와 ArgoCD · 누가 무엇을 동기화할 수 있는가 · 이론

Argo CD 의 권한은 클러스터 권한이 아니다

LabHub 에서 이어서 보기

한 줄 요약

Argo CD 안에서 누가 무엇을 할 수 있는지는 쿠버네티스 RBAC 가 아니라 argocd-rbac-cmpolicy.csv 한 장이 정하고,
그 판정은 서버 없이 argocd admin settings rbac 로 지금 자리에서 확인할 수 있다.

왜 이 구분이 필요했나

GitOps 를 켜는 순간 클러스터를 실제로 바꾸는 주체는 사람이 아니라 Argo CD 다. Argo CD 의 컨트롤러는 자기가
관리하는 네임스페이스에 대해 아주 넓은 권한을 들고 있다 — 그래야 매니페스트에 적힌 무엇이든 만들 수 있다.
여기서 함정이 생긴다. 클러스터에서 아무 권한도 없는 사람이 Argo CD 계정만 받으면, 그 사람이 누른 동기화는
Argo CD 의 권한으로 실행된다. 쿠버네티스 RBAC 는 이 사람을 한 번도 보지 않는다.

그래서 Argo CD 는 자기만의 권한 표를 따로 둔다. argocd-rbac-cm ConfigMap 의 policy.csv 키가 그것이고,
형식은 casbin 의 정책 CSV 다. 줄은 두 종류뿐이다.

p, <주체>, <자원>, <동작>, <객체>, allow|denyg, <사용자 또는 그룹>, <역할>

p 는 권한 한 줄, g 는 소속 한 줄이다. 자원은 applications, applicationsets, projects, clusters,
repositories, certificates, gpgkeys, logs 같은 이름이고, 동작은 자원마다 다르다 — 애플리케이션이라면
get, create, update, delete, sync, override, 그리고 리소스 동작을 가리키는
action/<그룹>/<종류>/<이름> 형태까지 받는다. 객체는 애플리케이션의 경우 <프로젝트>/<앱이름> 두 칸이다.
dev/* 는 dev 프로젝트의 모든 앱이고, */* 는 전부다. 여기서 제일 자주 나는 실수가 객체에 앱 이름만
적는 것이다 — web 은 어떤 앱과도 맞지 않는다.

어떻게 동작하나

판정에는 두 가지 성질이 있다. 첫째, deny 는 줄 순서와 상관없이 이긴다. 위에 allow 를 쓰고 아래에
deny 를 써도, 반대로 써도 결과는 같다. 첫 일치 규칙을 쓰는 방화벽 문법과 다르니 그 감각으로 읽으면 틀린다.
둘째, 어느 줄에도 걸리지 않은 요청은 policy.default 가 정한 역할로 다시 판정된다. 여기에
role:readonly 를 적으면 계정만 있는 사람은 읽기만 되고, 빈 값이면 아무것도 안 된다.

전역 정책 말고 프로젝트 안에서만 통하는 역할도 있다. AppProject 의 spec.roles 에 이름과 정책 줄,
그리고 묶을 그룹을 적는다. 주체 이름은 proj:<프로젝트>:<역할> 이고 문법은 전역 정책과 똑같다.
차이는 사는 곳이다 — 전역 정책은 플랫폼 팀이 가진 ConfigMap 이고, 프로젝트 역할은 그 프로젝트를 가진
팀이 자기 매니페스트에서 고칠 수 있다. 팀이 늘어날수록 이 경계가 실제로 일을 줄여 준다.

마지막으로 이 실습을 가능하게 하는 도구다. argocd admin settings rbac validate
argocd admin settings rbac canArgo CD 서버에 접속하지 않는다. --policy-file 로 준 파일만
읽어 판정한다. 그래서 정책을 코드로 다루고, 바꿀 때마다 기대표를 돌리는 회귀 검사가 가능하다.
can 은 기본이 엄격 모드라 존재하지 않는 자원 이름이나 동작 이름을 주면 판정 전에 멈추고 알려 준다 —
오타 난 정책을 배포한 뒤에 "왜 안 되지" 하는 시간을 통째로 없앤다.

현장에서 만나는 모습

사고는 보통 이렇게 온다. 온콜이 밤에 결제 앱을 동기화했고, 그 동기화가 잘못된 커밋을 올렸다. 사후에 보면
정책에는 p, role:oncall, applications, sync, prod/*, allow 한 줄만 있었다. 결제는 다른 팀의 앱인데
prod/* 라는 한 칸이 그것까지 덮고 있었던 것이다. 고치는 방법은 간단하다 — prod/payments 에 대한
deny 한 줄을 더하면 순서와 무관하게 막힌다. 어려운 것은 고친 뒤에 다른 게 안 깨졌는지 아는 일이고,
그건 기대표를 돌려 확인하는 수밖에 없다.

반대 방향의 사고도 흔하다. 권한을 좁혔더니 배포 자동화가 조용히 멈춘다. CI 계정이 쓰던 동작이
sync 가 아니라 action/apps/Deployment/restart 였다거나, 객체 표기를 * 한 칸으로만 적어 두어
*/* 로 고쳐야 했던 식이다. 좁히는 변경일수록 표가 필요하다. 표가 없으면 아무도 좁히지 않고,
권한은 넓어지기만 한다.

이 실습 환경의 한계

실습 파드에는 Argo CD 컨트롤러도 API 서버도 없다. 그래서 "이 사람으로 로그인해서 단추를 눌러 본다" 는
할 수 없다. 대신 정책을 실제로 해석하는 그 코드가 CLI 안에 그대로 들어 있어서, 판정 결과는 서버가 내는 것과
같은 경로로 나온다. 진짜 컨트롤러를 띄워 동기화가 도는 것을 보는 실습은 자격 과정 쪽에 따로 있다.

다음 실습에서 할 것

정책 한 장을 쓰고, 문법을 검사하고, rbac can 으로 여덟 가지를 물어본다. 일부러 칸을 빠뜨려 오류를 보고,
deny 를 위에 써 보고, policy.default 로 낯선 사람에게 줄 몫을 정한다. AppProject 에 프로젝트 역할을
넣어 kwok 클러스터에 올리고, 마지막에는 기대표와 검사 스크립트를 만들어 전부 한 번에 돌린다.