카테고리 없음

쿠버네티스 접근제어 개발 회고

134130 2024. 5. 17. 19:07

QueryPie 라는 접근제어 플랫폼에 쿠버네티스 접근제어(Kubernetes Access Control; KAC) 제품을 약 5개월이 안되는 시간동안 만들었고, 이제 릴리즈를 앞두고 있다. 뻔한 boilerplate 멘트는 없이 타임라인을 짚으며 시작해보고자 한다.

1월

1월에는 요구사항 분석과 설계를 했다.

 

 

KAC 프로젝트는 사내에서 최초로 DDD로 진행한 프로젝트다.

Domain Driven Development가 아닌 Developer Driven Development다. 😂


기획이 먼저 기획서를 제공하고 개발자들이 개발을 하는 플로우와 다르게, 나를 포함한 개발자 3명이서 요구사항 분석부터 기획 그리고 개발까지 모두 시행했다. 그 흐름속에서 Role context, PaC(Policy as Code)를 포함한 기존에 존재하지 않았던 다양한 아이디어들이 나왔고, 동시에 PoC까지 할 수 있었다.



사용자들이 왜 KAC를 필요로 할지 분석한 내용을 적자면...

 

1.  다양한 클러스터들을 중앙관리 하고싶어 한다.

쿠버네티스 API 서버에는 이미 RBAC 시스템이 있다. 하지만 이러한 RBAC 시스템은 기본적으로 Cluster 단위로 동작하며, 많은 회사들이 하나의 클러스터만 운용하지 않는다.


또, 매 클러스터마다 사내에서 사용중인 IdP를 연동시켜주는 과정은 생각보다 귀찮고 관리되기 어렵다.

 

2. 기본적으로 제공되는 Kubernetes 내장 RBAC 시스템은 생각보다 Graceful 하지 못하다.

첫번째로, 사용자 A에게 namespace/ns1namespace/ns2 하위의 리소스들에만 접근할 수 있도록 정책을 정의한다고 가정했을 때, 사용자는 kubectl get pods --all-namespaces 명령어를 실행하면 403 응답을 받게 된다.

쿼리파이는 우아하게 namespace/ns1namespace/ns2 하위의 리소스들만 필터링하여 제공할 수 있도록 개발했다.


두번째로, 사용자 A에게 namespace/* 하위 리소스들에 대한 접근을 허용하지만 namespace/ns1 하위 리소스들은 접근을 막고 싶다면 어떻게 해야할까?

An RBAC Role or ClusterRole contains rules that represent a set of permissions. Permissions are purely additive (there are no "deny" rules).

안타깝게도 쿠버네티스에는 deny rule을 제공하지 않기 때문에, 존재하는 namespace들을 모두 일일히 등록해줘야만한다. 이는 namespace등의 리소스를 추가할 때 마다 정책을 수정해야줘야만 하는 불편함을 낳는다. 변경이 잦은 클라우드상의 리소스들을 정책을 연계하여 지속적으로 관리해줘야한다는 것은 사실상 이루어지기 불가능한 영역이다.

KAC는 allow와 deny를 모두 제공하며, 리소스 이름에 대한 wildcard 뿐만 아니라 정규식 형태의 필터링 또한 제공한다.

또한 IdP로 부터 제공받은 User Attribute들을 정책에 활용하려면 Admission WebHook등을 사용해야만 했지만, 단일의 PaC에서 한꺼번에 관리가 가능하다. (K8s 1.30 부터 CEL for Admission Control이 등장하긴 했다)

 

3. 감사(Auditing)을 지원한다.

데이터베이스 접근제어와 서버 접근제어가 필요하고 사용되는 이유와 같다.
데이터베이스의 스키마 또는 서버내의 자산이나 구성정보들이 어떻게 변경되었는지 히스토리 또는 해당 작업을 담당자를 찾을 수 없는 경우들을 보완해준다. 또한 이는 법률적으로 관리되어야한다고 명시되는 부분이다. 쿠버네티스상에 있는 무형의 자산들 또한 관리되어야하는 영역이다.

Deployment의 replicaSet이 1로 변경되어있는데, 누가 변경했는지 추적이 불가능하다면 정말 골치아플 것이다.



기존의 DAC, SAC 요구사항과 크게 다르지는 않았기에 설계 자체는 크게 어렵지 않았다. 쿼리파이 제품의 핵심인 사용자가 가장 편하게 사용할 수 있는 형태를 중심으로 기능들을 구성했다.

쿼리파이에서 사용자라고 하면 두 분류로 나뉜다. 정책을 구성하는 보안관리자정책을 적용받는 일반사용자.


프로젝트 언어로는 Go를 채택했다.

현재 사내에서 백엔드로 사용하던 언어는 Java/Kotlin과 C# 그리고 일부 TypeScript가 있었다. C#은 여러가지 이유로 인해 앞으로 사내에서 제거해나가고자 하는 언어였기에, Kotlin 기반으로 개발하고자 연구를 시작했다. 짧은 리서치 기간이었지만 JVM 생태계에서 HTTP Proxy를 만들기 어렵다고 판단했고, Kubernetes 관련 모델 및 로직들을 모두 손수 만들어야하는 부담감이 있었다. 또한, K8s에서 사용되는 SPDY라는 비공식 프로토콜이 큰 발목을 잡았다.

보통 프로토콜들은 잘 테스팅된 구현체를 사용하는게 안정적이기에 손수 작성하고 싶지 않았으며, 프레임워크에 따라 저수준의 프로토콜을 지원하기 까다로운 경우도 있다.



Go언어를 사용하는 것은, 유지보수해야하는 언어의 종류가 많아 C#을 걷어내고자하는 사내의 정책과 반대되는 방향이었다. 하지만 Kubernetes 라이선스가 Apache 2.0 이기에 많은 로직들을 재사용할 수 있다는 점은, 안정적이고 빠른 속도로 제품을 만들어 낼 수 있다는 장점이 있었다. 또한 Cloud Platform 이라고하는 DevOps 팀에서 사용하는 언어이기 때문에 새로운 언어를 사내에 추가하는 부담감을 조금은 덜 수 있었다.


요구사항 분석과 기획을 하면서, 처음 접하는 GoLang과 많이 사용해보지 않은 쿠버네티스를 공부하는 걸 병렬로 진행했다. 거의 일주일 동안은 쿠버네티스 공식 홈페이지에 있는 문서들을 읽고 정리하는데에만 시간을 쏟았다. 문서만 읽다보니 눈이 빠질 것 같은 경험을 했고, 한 달이 넘는 시간동안 기획과 공부 그리고 회의만 하다보니 코드가 얼른 짜고 싶었다.. 🫠

 

2월~3월 중순

본격적으로 코드를 작성하기 시작했다.

2월 1일은 main 코드를 작성하는 PR이 머지된 날이다.

 

복잡한 Proxy 코드를 먼저 작성했기 때문에 (정책을 서빙하는 API서버와 Front-end 코드는 4월부터 작성하기 시작) Proxy 서버 혼자서도 독립적으로 동작 및 테스트할 수 있도록 했으며, Proxy에 대한 기본적인 기능들이 완성된 3월 말에는 타운홀에서 데모 시연을 진행했다.

 

KAC라는 기존에 없던, 그리고 생소한 제품을 기획, 영업 그리고 마케팅 부서 등등에게 설명할 수 있었던 시간이었다.

 

타운홀 데모를 하기 전까지는 내가 요즘 뭘 개발하고 있는지 다른 팀원분들이 많이 물어보셨다. 개발자 3명을 중심으로만 개발했었기 때문에 특히나 더더욱 베일에 싸여있었다.

 

3월 중순~4월 중순

기획자와 API, Front-end 개발자가 합류하여 디자인이나 유저 시나리오 기반의 기획서를 본격적으로 뽑아내기 시작했다. 기존에 리서치한 내용들을 공유하고, 조금 더 나은 제품을 만들기 위해 시간을 쏟았다. 코드적으로는 MVP에서 MSP로 넘어갈 수 있도록 내부적으로 부족한 구현들을 챙겨나가는 시간이었다.

 

4월 중순~5월 중순

3rd Party tool을 통한 테스팅, 부하 및 에이징 테스팅 그리고 유닛 테스트 코드와 E2E 테스트 코드들 작성을 통해 기존에 발견하지 못했던 문제점들을 찾고 고쳐나가는 시간을 가졌다. 또한 본격적으로 각 컴포넌트들(Proxy <-> API <-> Front)간의 연동이 이루어지는 기간이었다.

 

현재

그리고 지금은 또 다른 새로운 제품 출시를 위해 KAC 제품을 위해 준비했던 이터레이션의 첫 번쨰 과정으로 돌아온 상태이다. 회고의 목적에 맞게 기존 이터레이션에서 얻은 KPT(Keep, Problem, Try)를 도출해보면..

 

Keep

  • 기획을 개발자 주도로 시작하기
    • B2B 제품이자, 개발자가 사용하는 제품이며, 기술이 중심이 우리회사의 제품은 기획자가 커버하기 어려운 부분들이 많다. 좋은 아이디어들을 개발자 중심에서 먼저 제안하고 리뷰했기에, 기존의 기획에서 먼저 리뷰되어 전달되는 형태보다 더욱 빠르게 제품을 만들어 나갈 수 있었다.
  • 개발 이후(도중이 아닌) 테스팅할 수 있는 시간을 충분히 갖기
    • 왜 제품을 개발하는 중에 테스트코드를 작성하지 않고 이후에 작성하냐 라고 생각할 수 있지만, 스타트업은 빠르게 제품을 개발 및 검증 해나가야하고, 테스트 코드는 발목을 잡는다.
    • 새로 0부터 만들어 나가는 코드는 특히나 많은 코드들이 개발 과정중에 사라지고 새로 생긴다. 또한 기획이 완벽하게 나오고 시작되지 않기 때문에 그 변화는 더더욱 크다.
    • (만약 기존의 제품을 유지보수하는 경우에는 이야기가 조금 다르다.)
    • 제품을 완전히 개발한 이후 실제 사용자 시나리오 바탕으로 다양한 테스트 코드들을 작성했고, 충분한 시간에 걸쳐 테스트 했으며, 많은 로직상의 결함들을 발견할 수 있었다. (물론 자동화 또한 완료했다)
  • 로그를 코드 짜는 시점부터 잘 신경쓰기
    • 이전에 다른 컴포넌트들을 유지보수할 때 항상 아쉬웠던 부분이다. 장애가 보고되었을 때 우리가 알 수 있는 정보는 로그에서 옴에도 불구하고, 잘 작성되고 있지 않았기 때문이다.
    • 로그는 처음부터 잘 작성하지 않는다면, 이후에는 잘 챙겨지기 어려운 부분이다.
    • 그동안 겪었던 상황들과 우리 제품의 특성을 바탕으로 동료 개발자분들께 로그를 잘 남기자고 설득했고, 프로젝트 시작부터 잘 챙겨나가고자 신경썼다.
  • 다른 팀을 최대한 돕기
    • 약속한 릴리즈 일정이 있었기에 제품 개발일정이 촉박했다. Proxy 개발은 문제 없었지만, 뒤늦게 합류한 API와 Front-end는 많이 힘들었다.
    • 나의 컴포넌트가 완성되었다고 조금 여유를 가지고 쉬거나, 다른 팀을 불난듯 불구경해야하는 것은 절대 있어서는 안되는 부분이다. 우리는 하나의 제품을 만들고 있고 서로에게 신세지는 사람들이다.
    • 재택근무가 가능함에도 불구하고 매일 사무실 출근을 하며 오프라인 소통을 하고자했고, 내가 Kotlin/Spring을 조금은 할 수 있었기 때문에 팀과 컴포넌트를 넘어 일부 로직을 같이 작성하기도 했다.

Problem

  • 완벽한 코드를 짜려했던 점
    • 새로운 컴포넌트는 완벽하게 짜고자하는 욕심이 있었다. 내가 생각하기에 더 나은 구조나 로직을 추구하고자 동료개발자와 언성을 높이는 경우도 있었다.
    • 어디까지나 내가 생각하기에 더 나은 구조나 로직일 수 있으며, 비즈니스 요구사항에 따라 이후에 충분히 바뀔수도 있는 부분이다.
    • 동료와 나의 사기를 저하시키는 행동이었다고 생각하며, 그다지 중요하지 않은 부분들에 있어서 논쟁하며 쓸모없는 시간들을 낭비했던 것 같다.
    • 해당 구조나 로직에 대해서 빠르게 구현해보고 검증해보면 된다.
    • 언제까지나 회사의 코드를 작성하는 것이지 나의 코드를 작성하려하면 안된다. 코드에 대한 과한 애정은 오히려 좋지 않다.
  • 회의가 길어지는 점
    • 3월 부터 시작한 KAC 제품회의는 위클리 형식으로 진행했으며, 기획, 각 컴포넌트 개발자들 그리고 QA 담당자가 모두 모여 진행했다.
    • 회의 시간을 한 시간으로 잡았지만, 두 시간 가까이 진행된적이 많았다. 회의는 항상 짧고 간결하게 해야한다. 나에게 한 시간은 짧을 수 있지만, 열 명이 모인 회의는 회사의 10시간을 빼앗는 것이다.
    • 회의 도중에 어떤 구현이나 기능에 대해서 토론이 시작되는 경우들이 회의가 길어지는 원인이었다. (프로젝트 후기에 조금 완화되긴 했지만)
    • 회의에서는 큰 틀만 리뷰하며 맥락들을 공유하고, 세부 구현들은 각 컴포넌트 담당자들만 따로 모여 회의를 진행하는게 낫다.
    • 모두와는 관련없는 구체적인 리뷰가 길어지는건 다른 사람들의 시간을 뺴았고, 전반적인 회의의 품질을 떨어트리게된다.
  • 음.. 기만할 수 있지만.. 그 외의 문제점들은 잘 떠오르지 않는다.

Try

  • 🤔

마치며

음.. 생각해보면 적지 못한 좋았던 부분들만 계속해서 생각나고, 문제라던가 시도해야할 점들이 딱히 떠오르지 않는다. (시도해야할 점이 생각나지 않는건 조금 아쉽다)

정식적인 릴리즈를 마치고 CS를 받고난 이후에 프로젝트의 성공과 실패 여부를 판가름 할 수 있겠지만.. KEP를 작성하는걸 포함하여 회고를 했을 때 좋은 점들이 훨씬 많이 생각나는걸 보면 잘 진행했던 프로젝트였다고 정의해도 괜찮지 않을까?