
데이터를 지키는 첫걸음, 스테이트풀셋 보안의 중요성
데이터베이스나 메시지 큐처럼 상태를 유지해야 하는 애플리케이션을 운영하다 보면 예상치 못한 보안 사고의 위협을 직접 체감하게 돼요. 단순한 웹 서버라면 파드가 재시작될 때 데이터가 사라져도 큰 타격이 없지만, 스테이트풀셋(StatefulSet)으로 관리되는 데이터 저장소는 이야기가 전혀 달라요. 만약 공격자가 스테이트풀셋으로 실행 중인 컨테이너의 권한을 탈취한다면, 그 결과는 단순한 서비스 중단을 넘어 소중한 고객 데이터의 유출이나 영구적인 데이터 파괴로 이어질 수 있어요.
실제로 많은 주니어 개발자분들이 디플로이먼트(Deployment)와 스테이트풀셋의 차이에만 집중하느라, 이들이 가진 데이터 지속성이라는 강력한 특성이 보안 측면에서는 얼마나 큰 공격 지점이 될 수 있는지 놓치곤 해요. 권한 설정 하나를 소홀히 하여 컨테이너가 루트(root) 권한으로 실행되게 두거나, 볼륨 권한을 너무 느슨하게 열어두는 실수는 클러스터 전체의 보안을 무너뜨리는 도미노의 첫 번째 조각이 될 수 있어요.
지금 이 글을 읽고 계신 분들은 단순히 기능을 구현하는 단계를 넘어, 실제 운영 환경에서도 신뢰할 수 있는 인프라를 구축하고 싶어 하는 분들이라고 생각해요. 스테이트풀셋은 일반적인 무상태(Stateless) 애플리케이션보다 훨씬 까다로운 보안 요구사항을 요구해요. 데이터가 담긴 볼륨, 고유한 네트워크 식별자, 그리고 정해진 순서대로 생성되고 삭제되는 특성 모두가 보안 설계의 핵심 요소이기 때문이에요.
이 가이드를 끝까지 따라오신다면, 막연하게 느껴졌던 쿠버네티스 보안 강화를 위해 무엇부터 시작해야 할지 명확하게 알 수 있어요. 이론적인 나열이 아니라, 실무에서 바로 적용할 수 있는 구체적인 설정 방법과 주의사항을 중심으로 이야기를 풀어갈게요.
- 스테이트풀셋이 가진 주요 보안 위협 지점 파악
- 권한 최소화 원칙을 적용한 보안 컨텍스트 설정법
- 데이터 볼륨과 네트워크를 보호하는 실전 설정 예제
- 보안 정책을 자동화하고 위반 사례를 점검하는 방법
보안 설정을 위한 사전 준비와 판단 기준
본격적인 설정을 시작하기 전에, 우리가 어떤 도구와 개념을 가지고 싸워야 하는지 먼저 이해해야 해요. 보안은 단순히 ‘막는 것’이 아니라, 정상적인 서비스 운영에 필요한 최소한의 통로만 열어두는 과정이에요. 스테이트풀셋의 보안 수준을 결정할 때는 현재 운영 중인 서비스의 성격과 데이터의 민감도를 먼저 고려해야 해요.
가장 먼저 확인해야 할 것은 클러스터의 Pod Security Admission (PSA) 정책이에요. 쿠버네티스는 파드가 가질 수 있는 권한을 세 가지 수준(Privileged, Baseline, Restricted)으로 나누어 관리할 수 있게 도와줘요. 스테이트풀셋은 데이터를 다루기 때문에 때때로 높은 권한이 필요할 것 같다는 착각에 빠지기 쉽지만, 가능한 한 가장 엄격한 수준을 지향하는 것이 원칙이에요.
또한, 스테이트풀셋이 사용하는 ServiceAccount와 RBAC(Role-Based Access Control)에 대한 이해도 필수적이에요. 파드가 클러스터의 API와 통신해야 한다면, 어떤 권한을 부여할지 미리 결정해야 해요. 무심코 ‘cluster-admin’ 권한을 주는 것은 집 현관문 열쇠를 도둑에게 맡기는 것과 다를 바 없어요.
보안 수준별 권한 비교
애플리케이션의 특성에 따라 어떤 보안 수준을 목표로 해야 할지 아래 표를 통해 비교해 보세요. 대부분의 현대적인 데이터베이스 애플리케이션은 Restricted 수준을 목표로 설계하는 것이 가장 바람직해요.
| 보안 수준 | 주요 특징 | 스테이트풀셋 적용 시 고려사항 |
|---|---|---|
| Privileged (특권) | 거의 모든 커널 기능 접근 가능 | 매우 위험함. 시스템 수준의 공격에 노출됨 |
| Baseline (기본) | 일반적인 운영에 필요한 수준 | 데이터베이스 운영 시 일부 제약이 생길 수 있음 |
| Restricted (제한) | 가장 엄격한 보안 정책 적용 | 비루트 사용자 실행 및 권한 상승 차단 필수 |
보안 수준을 높이면 데이터베이스가 설치 과정에서 특정 디렉토리에 권한을 쓰지 못해 실행에 실패할 수 있어요. 설정을 변경하기 전에 반드시 스테이징 환경에서 권한 문제를 먼저 검증해야 해요.
준비가 끝났다면, 이제 실제 스테이트풀셋 리소스에 어떻게 보안 설정을 녹여낼지 단계별로 실행해 볼 차례예요. 단순히 설정을 넣는 것이 아니라, 왜 이 설정이 필요한지 그 원리를 파악하며 진행하는 것이 중요해요.
스테이트풀셋 보안 강화를 위한 4단계 실행 가이드
이제 실전이에요. 스테이트풀셋의 보안은 크게 컨테이너 자체의 권한, 데이터가 담기는 볼륨, 파드 간의 통신, 그리고 클러스터 리소스 접근 권한이라는 네 가지 축으로 이루어져요. 이 축들을 하나씩 단단하게 조여 나가면 아주 견고한 보안 체계를 만들 수 있어요.
STEP 1. 보안 컨텍스트(Security Context)를 통한 권한 최소화
가장 기본적이면서도 강력한 방법은 컨테이너가 실행될 때 가지는 권한을 물리적으로 제한하는 거예요. 많은 기본 컨테이너 이미지가 루트 사용자로 설정되어 있는데, 이를 비루트(Non-root) 사용자로 변경하는 것만으로도 컨테이너 탈출(Container Escape) 공격의 위험을 획기적으로 줄일 수 있어요.
스테이트풀셋의 `spec.template.spec.securityContext`와 `spec.template.spec.containers[].securityContext`를 적절히 혼합해서 사용해야 해요. 특히 `runAsNonRoot: true` 설정은 컨테이너가 루트로 실행되려고 할 때 즉시 차단하는 안전장치 역할을 해요. 또한, `allowPrivilegeEscalation: false`를 설정하면 프로세스가 자식 프로세스로 넘어갈 때 권한을 높이는 행위를 원천 봉쇄할 수 있어요.
여기서 한 가지 팁을 드리자면, readOnlyRootFilesystem: true 설정을 고려해 보세요. 컨테이너 내부의 루트 파일시스템을 읽기 전용으로 만들면, 공격자가 침입하더라도 악성 스크립트를 설치하거나 시스템 파일을 수정하는 것이 불가능해져요. 데이터는 오직 마운트된 볼륨에만 써야 한다는 원칙을 강제하는 것이죠.
STEP 2. 데이터 볼륨 및 파일시스템 권한 관리
스테이트풀셋의 핵심은 데이터예요. 하지만 데이터가 저장되는 Persistent Volume(PV)의 권한 설정이 잘못되면, 보안 컨텍스트를 아무리 잘 설정해도 무용지물이 돼요. 예를 들어, 컨테이너를 비루트 사용자로 실행하도록 설정했는데, 마운트된 볼륨의 소유권이 루트에게 있다면 데이터베이스는 파일 쓰기 오류를 내며 죽어버릴 거예요.
이 문제를 해결하기 위해 쿠버네티스가 제공하는 fsGroup 설정을 적극적으로 활용해야 해요. `securityContext.fsGroup`에 특정 그룹 ID를 지정하면, 쿠버네티스가 볼륨을 마운트할 때 해당 그룹이 파일에 접근할 수 있도록 권한을 자동으로 조정해 줘요. 이를 통해 비루트 사용자로 실행되는 애플리케이션이 데이터 볼륨에 안전하고 원활하게 접근할 수 있는 환경을 만들 수 있어요.
또한, 볼륨 자체의 암호화도 잊지 말아야 해요. 클라우드 환경을 사용 중이라면 스토리지 클래스(StorageClass) 레벨에서 암호화(Encryption at rest)가 활성화되어 있는지 반드시 확인하세요. 물리적인 디스크 탈취 상황에서도 데이터를 보호할 수 있는 최후의 보루이기 때문이에요.
STEP 3. 네트워크 정책(Network Policy)을 통한 격리
스테이트풀셋으로 운영되는 데이터베이스는 클러스터 내부의 모든 파드로부터 접근을 허용해서는 안 돼요. 제로 트러스트(Zero Trust) 원칙에 따라, 해당 데이터베이스를 사용하는 특정 애플리케이션 파드만 접근할 수 있도록 네트워크 통로를 좁혀야 해요.
쿠버네티스의 NetworkPolicy 리소스를 사용하면 파드 단위의 방화벽을 구축할 수 있어요. 예를 들어, ‘order-service’라는 파드만 ‘mysql-statefulset’의 3306 포트에 접근할 수 있도록 허용하고, 그 외의 모든 트래픽은 기본적으로 차단(Default Deny)하는 정책을 세워야 해요. 이렇게 하면 설령 다른 웹 서버 파드가 해킹당하더라도, 공격자가 네트워크를 타고 데이터베이스까지 도달하는 것을 막을 수 있어요.
특히 스테이트풀셋 내의 노드 간 통신(Peer-to-peer)이 필요한 경우(예: MongoDB Replica Set, Cassandra Cluster)에는 노드끼리의 통신은 허용하되, 외부나 다른 서비스에서의 접근은 엄격히 제한하는 정교한 규칙 설계가 필요해요.
STEP 4. RBAC를 이용한 API 접근 권한 제어
마지막으로, 스테이트풀셋의 파드가 쿠버네티스 API 서버와 통신해야 하는 상황을 점검해야 해요. 간혹 상태를 모니터링하거나 설정을 변경하기 위해 파드에 권한을 부여하는데, 이때 ServiceAccount에 너무 넓은 범위의 권한을 주는 실수를 많이 해요.
반드시 필요한 권한만 정의된 Role을 생성하고, 이를 스테이트풀셋의 파드와 연결하는 RoleBinding을 구성하세요. 만약 파드가 클러스터 전체의 정보를 읽어야 한다면 ClusterRole을 써야 하겠지만, 특정 네임스페이스 내의 리소스만 관리한다면 반드시 Role을 사용해 범위를 제한해야 해요. ‘get’, ‘list’, ‘watch’ 같은 조회 권한조차도 꼭 필요한 리소스에 대해서만 선별적으로 부여하는 습관을 들여야 해요.
1. 상황: 비루트 사용자로 실행되는 Redis 스테이트풀셋 구축
2. 설정: `runAsUser: 1000`, `fsGroup: 2000` 적용
3. 결과: 컨테이너는 루트 권한 없이 실행되며, `fsGroup` 덕분에 `/data` 볼륨에 데이터를 안정적으로 기록함
자주 하는 실수와 해결법 및 FAQ
보안 설정을 적용하다 보면 예상치 못한 오류 때문에 당황하는 경우가 많아요. 그중에서도 가장 흔하게 발생하는 패턴들을 정리했으니, 비슷한 상황을 겪고 있다면 참고해 보세요.
자주 하는 실수와 해결법
❌ 실수: 컨테이너를 비루트 사용자로 변경했더니 DB가 실행되지 않아요.
이유: 데이터가 저장되는 볼륨의 소유권이 여전히 루트(root) 사용자에게 있기 때문이에요.
✅ 해결법: `securityContext`에 `fsGroup`을 설정하여 볼륨의 그룹 권한을 조정하거나, 데이터 디렉토리의 권한을 미리 맞춰두어야 해요.
❌ 실수: NetworkPolicy를 적용했더니 파드 간 통신이 끊겼어요.
이유: 기본적으로 NetworkPolicy를 설정하면 ‘Default Deny’가 작동하여 모든 트래픽이 차단되기 때문이에요.
✅ 해결법: 애플리케이션이 필요로 하는 필수 포트와 소스(Source) IP/Pod 범위를 화이트리스트 방식으로 먼저 정의한 뒤 정책을 적용하세요.
❌ 실수: ServiceAccount에 Role을 부여했는데 권한 오류가 발생해요.
이유: Role은 특정 네임스페이스 내에서만 유효한데, 다른 네임스페이스의 리소스를 요청하고 있기 때문이에요.
✅ 해결법: 요청하는 리소스의 범위에 따라 Role 대신 ClusterRole을 사용하거나, 요청 범위를 해당 네임스페이스로 한정하세요.
❌ 실수: readOnlyRootFilesystem을 켰더니 컨테이너가 계속 크래시(Crash)나요.
이유: 애플리케이션이 임시 파일(`/tmp` 등)을 루트 파일시스템에 쓰려고 시도하기 때문이에요.
✅ 해결법: `emptyDir` 볼륨을 `/tmp` 경로에 마운트하여 쓰기 가능한 임시 공간을 제공해 주세요.
❌ 실수: 보안 설정을 다 했는데도 취약점 스캐닝 도구에서 경고가 떠요.
이유: 컨테이너 이미지 자체에 보안 패치가 안 된 오래된 패키지가 포함되어 있을 수 있어요.
✅ 해결법: 보안 설정뿐만 아니라 주기적인 이미지 빌드와 취약점 스캔(Image Scanning)을 병행해야 해요.
자주 묻는 질문
Q. 스테이트풀셋 보안 설정을 자동화할 수 있는 방법이 있을까요?
네, 가능해요. Kyverno나 OPA(Open Policy Agent) 같은 정책 엔진을 사용하면, 보안 기준에 맞지 않는 스테이트풀셋이 배포되는 것을 클러스터 수준에서 자동으로 차단할 수 있어요. 이는 사람이 일일이 검수하는 수고를 줄여주는 아주 효과적인 방법이에요.
Q. 보안을 강화하면 성능이 떨어지지는 않나요?
대체로 보안 설정 자체가 CPU나 메모리 사용량을 크게 늘리지는 않아요. 다만, 네트워크 정책에 의해 트래픽 경로가 복잡해지거나 암호화 과정이 추가된다면 미세한 오버헤드가 발생할 수 있지만, 보안으로 얻는 이득에 비하면 매우 작은 수준이에요.
Q. 권한을 너무 최소화해서 서비스가 안 되면 어떻게 하죠?
그래서 단계적 적용이 중요해요. 처음부터 모든 정책을 강하게 걸기보다는, 모니터링을 통해 애플리케이션의 실제 동작 패턴을 파악한 뒤 조금씩 권한을 좁혀가는 방식을 추천해요.
Q. 클라우드 관리형 쿠버네티스(EKS, GKE 등)에서도 이 규칙이 똑같이 적용되나요?
네, 쿠버네티스 표준 API를 사용하는 설정은 모두 동일하게 적용돼요. 다만, 클라우드 제공업체의 스토리지 클래스나 네트워크 설정 방식에 따라 세부적인 구현법은 조금 다를 수 있어요.
안전한 데이터 운영을 위한 마무리
스테이트풀셋 보안은 한 번의 설정으로 끝나는 작업이 아니라, 서비스의 성장과 함께 계속해서 다듬어 나가야 하는 과정이에요. 기술이 발전하고 새로운 공격 기법이 등장할수록 우리의 방어선도 함께 견고해져야 하니까요. 오늘 배운 내용들을 바탕으로 여러분의 클러스터를 다시 한번 점검해 보시기 바라요.
- 비루트(Non-root) 사용자로 컨테이너 실행을 강제하세요.
- fsGroup을 사용하여 데이터 볼륨의 권한 문제를 해결하세요.
- NetworkPolicy로 데이터베이스 접근 경로를 엄격히 격리하세요.
- 최소 권한 원칙에 따라 전용 ServiceAccount와 Role을 사용하세요.
- 읽기 전용 파일시스템 설정을 통해 공격자의 침투 범위를 제한하세요.
지금 바로 실무에 적용해 보실 준비가 되셨나요? 처음에는 설정 하나 때문에 파드가 실행되지 않아 막막할 수도 있지만, 그 과정을 하나씩 해결해 나가는 것이 진짜 실력을 쌓는 길이에요. 만약 설정을 적용하다가 도저히 해결되지 않는 문제가 있다면, 주저하지 말고 아래 댓글로 질문을 남겨 주세요. 함께 고민해 드릴게요.
🚀 이번 주 실행 과제
- 현재 운영 중인 스테이트풀셋의 `securityContext` 설정 확인하기
- 애플리케이션이 실제로 사용하는 포트 외에 열려 있는 네트워크 경로 차단하기
- 사용하지 않는 권한이 부여된 ServiceAccount 삭제하기
다음 단계로 나아가고 싶다면, 쿠버네티스 스테이트풀셋 기본 개념 글이나 클러스터 구축 및 보안 입문 글을 함께 읽어 보시는 것을 추천해요. 인프라의 기초부터 보안까지 탄탄하게 쌓아 올려 보세요.