요즘IT
위시켓
최근 검색어
전체 삭제
최근 검색어가 없습니다.

최근 컨테이너 기반 애플리케이션 개발과 운영에 대한 수요가 늘어나고 있습니다. 이에 따라 많은 컨테이너를 쉽게 관리할 수 있는 컨테이너 오케스트레이션 도구가 애플리케이션 개발의 필수 요소가 되었습니다. 가장 많이 사용되는 컨테이너 오케스트레이션 도구는 쿠버네티스입니다. 쿠버네티스는 수많은 컨테이너를 통합적으로 관리하는 기능을 제공하여 컨테이너 서비스 배포, 운영, 관리에 많은 이점을 줍니다.

회원가입을 하면 원하는 문장을
저장할 수 있어요!

다음

회원가입을 하면
성장에 도움이 되는 콘텐츠를
스크랩할 수 있어요!

확인

개발

쿠버네티스 환경의 대표적 보안 기능 3가지

년차,
어떤 스킬
,
어떤 직무
독자들이 봤을까요?
어떤 독자들이 봤는지 궁금하다면?
로그인

 

쿠버네티스 보안 기능 사례
< 출처: pixabay>

 

최근 컨테이너 기반 애플리케이션 개발과 운영에 대한 수요가 늘어나고 있습니다. 이에 따라 많은 컨테이너를 쉽게 관리할 수 있는 컨테이너 오케스트레이션 도구가 애플리케이션 개발의 필수 요소가 되었습니다. 가장 많이 사용되는 컨테이너 오케스트레이션 도구는 쿠버네티스입니다. 쿠버네티스는 수많은 컨테이너를 통합적으로 관리하는 기능을 제공하여 컨테이너 서비스 배포, 운영, 관리에 많은 이점을 줍니다.

 

그런데 이러한 쿠버네티스의 기능이 애플리케이션을 보안 취약점에 노출시킬 수도 있습니다. 실제로 컨테이너에 대한 보안 공격이 증가하고 있으며 그 영향도 점점 심각해지고 있습니다. 그래서 다른 개발/운영 환경에서와 마찬가지로 쿠버네티스 환경에서도 보안은 매우 중요합니다.

 

쿠버네티스 환경에서의 보안이란 쿠버네티스 클러스터의 안정성과 보안성을 유지하는 것을 의미합니다. 쿠버네티스는 클러스터를 보호하기 위한 기본적인 보안 기능을 제공합니다. 많은 기능이 있지만 이 글에서는 가장 대표적인 세 가지 기능을 소개합니다. 쿠버네티스 클러스터에 접속하는 것을 통제할 수 있는 네트워크 정책, 역할 기반 접근 제어(RBAC) 그리고 민감한 정보를 안전하게 저장하기 위한 시크릿(secret), 지금부터 이 세 가지 보안 기능에 관해 알아보겠습니다.

 


네트워크 정책을 사용하여 파드 통신 제어하기

쿠버네티스의 통신 정책은 기본적으로 모든 파드(Pod) 간 통신을 허용합니다. 원활한 통신에 유용한 정책이지만 원치 않는 접속에 파드를 노출시킬 수 있다는 위험도 있습니다. 따라서 무분별한 접속을 막고 파드를 보호하고 싶다면 네트워크 정책(Network Policy)을 사용해야 합니다.



네트워크 정책은 파드 간 통신 또는 다른 네트워크 엔드포인트와 파드 사이의 통신을 제어하는 기능입니다. 네트워크 정책을 사용하면 IP 주소, 포트, 프로토콜 및 레이블(label)과 같은 다양한 기준에 따라 트래픽을 허용하거나 거부하는 규칙을 정의할 수 있습니다. 그뿐만 아니라 특정 네임스페이스로부터 들어오는 트래픽만 허용하는 네트워크 정책을 세울 수도 있습니다.

 

 

네트워크 정책은 쿠버네티스 네트워크 플러그인 아키텍처를 사용하여 구현됩니다. 따라서 네트워크 플러그인마다 네트워크 정책에 대한 지원 수준이 다를 수 있습니다. Calico, Cilium 및 Weave Net과 같은 일부 인기 있는 네트워크 플러그인은 기본적으로 네트워크 정책을 지원하지만, 다른 플러그인은 추가 구성 또는 사용자 지정 개발이 ​​필요할 수도 있습니다.

 

 

네트워크 정책을 설정할 때는 다음 세 가지 요소가 중요합니다.

 

  • podSelector: 정책이 적용될 파드를 지정.
  • policyTypes: 정책이 적용될 트래픽을 지정. 수신(Ingress) 트래픽과 발신(Egress)트래픽이 있음.
  • ingress/egress: 수신 트래픽/발신 트래픽의 세부 내용을 지정.

 

​위 세 가지 요소를 예제를 통해서 살펴보겠습니다. 아래 예제는 네트워크 정책을 설정한 YAML 파일 입니다. 예제에서 ①podSelector를 보면, 정책이 적용될 파드로 database를 지정한 것을 알 수 있습니다. 그리고 ②policyTypes 설정을 통해 네트워크 정책을 수신 트래픽과 발신 트래픽에 동시에 적용합니다. 마지막으로 ③ingress/egress 트래픽 세부 정책을 정의하여, 트래픽을 허용할 네임스페이스, 파드, 프로토콜과 포트 번호, 그리고 IP 대역을 정의합니다. 

 

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: yozm-nwpolicy
  namespace: default
spec:
  podSelector:                       # ① 규칙이 적용될 파드(database) 지정
    matchLabels:
      role: database
  policyTypes:                       # ② 규칙이 적용될 트래픽을  Ingress, Egress로 설정
  - Ingress
  - Egress
  ingress:                              # ③ 수신트래픽 세부 내용 지정
  - from:
    - ipBlock:                              # 특정 IP만 접근 허용
        cidr: 192.17.0.0/16
    - namespaceSelector:          # 특정 네임스페이스(yozm-ns )만 접근 허용
        matchLabels:
          name: yozm-ns
    - podSelector:                       # 특정 파드(yozm-pod)만 접근 허용
        matchLabels:
          app: yozm-pod
    ports:                                     # 허용할 프로토콜과 포트 지정
    - protocol: TCP
      port: 6379
  egress:                               # ③ 발신 트래픽 세부 내용 지정
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

 

위의 예제를 보면, 마치 웹 서버의 방화벽 혹은 클라우드 인스턴스의 보안 그룹처럼 인바운드와 아웃바운드 트래픽을 제어하고 있음을 알 수 있습니다. 이렇게 쿠버네티스는 네트워크 정책을 통해서 파드에 설치된 애플리케이션이 어떤 네트워크 요청을 받을 수 있고 어디로 요청할 수 있는지 결정하고 통제합니다. 그리고 클러스터 내 파드의 네트워크 트래픽을 제한함으로써 다양한 보안 공격으로부터 클러스터를 보호할 수 있습니다.

 


역할 기반 접근 제어를 통한 사용자의 권한 설정하기

쿠버네티스는 서비스, 네트워킹, 네임스페이스, 파드, 노드, 컨테이너 등 많은 리소스로 구성됩니다. 각 리소스에 접근하는 사용자와 서비스를 제한하는 것은 클러스터를 안전하게 유지하는 데 매우 중요합니다.

 

쿠버네티스의 역할 기반 접근 제어(RBAC:Role-Based Access Control)는 사용자 및 서비스 계정의 역할을 정의하고, 역할에 따라 권한을 부여해 클러스터 리소스에 대한 접근을 제어합니다. 사용자나 서비스 계정의 역할을 설정하는 Role, 클러스터 수준에서 역할을 설정하는 ClusterRole을 사용해 보안 규칙을 정의하고, 이 규칙을 사용자의 모음인 그룹(Group)에 추가합니다.

 

 

역할 기반 접근 제어는 다음 세 가지 주요 개념으로 구성됩니다.

 

  • Role: Role은 권한의 집합으로, 클러스터 리소스에 대한 접근 권한을 부여합니다. 예를 들어, ‘pod-reader’라는 Role을 정의하고 동일한 네임스페이스 내 모든 파드에 대한 읽기 권한을 부여할 수 있습니다.
     
  • RoleBinding: 특정 사용자 또는 서비스 계정에 Role을 할당합니다. 즉, 역할(Role)과 계정을 연결(Binding)하는 기능입니다. 예를 들어, ‘user-1’ 사용자에게 ‘pod-reader’ Role을 연결하여 ‘user-1’ 사용자가 동일한 네임스페이스 내 모든 파드를 읽을 수 있게 합니다. 
     
  • ClusterRole: Role과 유사하지만, 권한의 적용 범위가 다릅니다. Role은 특정 네임스페이스 내에서만 유효한 권한을 할당하지만, ClusterRole은 클러스터 전체에서 유효한 권한을 할당합니다. ClusterRole과 사용자 또는 서비스 계정 사이의 연결을 정의하는 ClusterRoleBinding을 필요로 합니다.

 

아래 이미지를 보면, 역할 기반 접근 제어를 한눈에 파악할 수 있습니다.

 

쿠버네티스의 역할 기반 접근 제어
<쿠버네티스의 역할 기반 접근 제어, 출처: 작가>

 

역할 기반 접근 제어도 예제와 함께 살펴보겠습니다. 아래 예제는 ①dev-team이라는 이름의 Role을 정의한 YAML 파일입니다. 이 Role은 ②development 네임스페이스 내에서 ③특정 사용자 혹은 서비스 계정이 실행할 수 있는 작업과 그 대상을 지정합니다. 조금 더 자세히 살펴보면, ④접근할 수 있는 API 그룹을 core, extensions, apps로 정의하고 있습니다. 그리고 ⑤deployments, replicasets, pods 리소스에 접근할 수 있도록 합니다. 마지막으로 ⑥리소스에 대한 get, list, watch 등 7가지 작업 권한을 부여합니다. 이렇게 설정하면, dev-team이라는 Role은 apps API 그룹에 속한 deployment 리소스 (apps/v1/deployments)에 접근할 수 있으며 get 동작을 수행해 해당 리소스의 정보, 상태 등을 확인할 수 있게 됩니다.


<role.yaml>

apiVersion: rbac.authorization.k8s.io/v1     # API 버전
kind: Role
metadata:
  namespace: development        # ② Role이 적용되는 네임스페이스
  name: dev-team             # ① Role의 이름 지정
  rules:                       # ③ rules 정의
- apiGroups: ["core", "extensions", "apps"]          # ④  접근 가능한 API 그룹 지정
  resources: ["deployments", "replicasets", "pods"]         # ⑤ 접근 할 수 있는 리소스 지정  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]  # ⑥ 


이제 이렇게 만들어진 역할을 특정 사용자에게 할당하는 RoleBinding이 필요합니다. 아래 예제는 ① dev-team-binding라는 이름으로 RoleBinding을 선언합니다. 그리고 특정 ② Role을 할당할 User를 설정합니다. 예제에서는 dev1이라는 사용자에게 Role을 할당합니다. 마지막으로 ③사용자에게 dev-team 역할을 부여했습니다. 이렇게 되면 dev1 사용자는 위 role.yaml에서 정의한 역할을 수행할 수 있습니다. 

 

<user-role.yaml>

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: development
  name: dev-team-binding       # ① RoleBinding 이름 정의
subjects:
- kind: User       # ② Role을 할당할 User 설정 
   name: dev1
   apiGroup: ""
roleRef:
  kind: Role       # ③ user에게 할당할 Role 설정
  name: dev-team
  apiGroup: ""

 

추가로 YAML파일을 활용해 Role과 RoleBinding을 생성하는 예시를 보여드리겠습니다. 아래 예제 코드는 ①development 네임스페이스를 생성하고 네임스페이스 내부에서 ②Role과 ③RoleBinding을 생성하는 kubectl 명령을 입력한 결과입니다.

 

$kubectl create namespace development   # ① namespace 생성
namespace/development created

$kubectl create -f role.yaml   # ② role.yaml 파일에 정의된 Role 생성role.rbac.authorization.k8s.io/dev-team created

$kubectl create -f user-role.yaml   # ③ user-role.yaml 파일에 정의된 RoleBinding 생성
rolebinding.rbac.authorization.k8s.io/dev-team-binding created

 

쿠버네티스의 역할 기반 접근 제어를 사용하면 클러스터 관리자는 리소스에 대한 접근 권한을 관리할 수 있습니다. 이에 따라 보안을 강화하고 권한을 남용하는 실수를 방지할 수 있습니다. 또한 다양한 사용자와 서비스 계정 간 접근 권한을 분리하여, 권한이 부여되지 않은 사용자가 민감한 데이터를 볼 수 없도록 보호할 수 있습니다.

 

 

민감한 데이터를 저장하는 쿠버네티스 시크릿

쿠버네티스 시크릿(Secret)은 암호화된 정보, 토큰, 비밀번호와 같은 중요한 데이터를 안전하게 저장하기 위한 리소스입니다. 쿠버네티스에서는 일반적으로 시크릿을 사용하여 API 키, 데이터베이스 비밀번호, OAuth 토큰 등과 같은 인증 정보를 관리합니다. 만약 이런 중요한 정보가 파드의 명세 파일이나 컨테이너 이미지에 평문 형태로 포함된다면 보안에 치명적일 수 있습니다. 그래서 시크릿 정보는 컨테이너 이미지에 포함되지 않고, 애플리케이션을 실행하는 동안 환경 변수 또는 볼륨 마운트를 통해 컨테이너에 전달됩니다.

 

쿠버네티스 시크릿
<쿠버네티스 시크릿, 출처: 작가>

 

시크릿은 일반적으로 Base64로 인코딩된 key-value 쌍으로 정의됩니다. 시크릿은 컨테이너 런타임에서 복호화 되어 사용되므로, 시크릿을 사용하는 애플리케이션에 별도의 복호화 로직을 구현할 필요가 없습니다. 시크릿은 민감한 정보를 사용하는 파드와 독립적으로 생성됩니다. 대신에 민감 정보를 별도의 etcd 저장소에 안전하게 보관하다가 파드가 정보를 필요로 할 때 컨테이너에 제공해 줍니다.

 

간단한 형태의 시크릿의 예제를 만들어봅시다. 특정 사용자의 아이디와 비밀번호를 시크릿으로 생성하여 보존해보겠습니다. USER_NAME=admin, PASSWORD=1f2d1e2e67df라는 사용자 데이터가 있다고 가정합니다. 먼저 아래와 같이 정보를 base64로 인코딩합니다.

 

$echo -n "admin" | base64
YWRtaW4=
$echo -n "1f2d1e2e67df" | base64
MWYyZDFlMmU2N2Rm

 

그리고 인코딩된 데이터로 시크릿을 생성하는 YAML 파일을 만듭니다. USER_NAME과 PASSWORD의 값은 base64로 인코딩된 값이지만, 파드에서 이것을 사용할 때는 워커 노드의 kubelet이 이 값을 디코딩하여 파드와 컨테이너에 제공합니다. 

 

apiVersion: v1
kind: Secret
metadata:
  name: yozm-secret
type: Opaque
data:                                            # base64로 인코딩된 USER_NAME과 PASSWORD 입력
  USER_NAME: YWRtaW4=
  PASSWORD: MWYyZDFlMmU2N2Rm

 

이렇게 생성된 시크릿 정보는 쿠버네티스 클러스터 control plane의 etcd 데이터베이스에 저장됩니다. etcd는 쿠버네티스 클러스터의 중앙 데이터 저장소이며 모든 쿠버네티스 리소스 정보, 설정 정보, 런타임 정보 등 여러 데이터가 저장됩니다. 시크릿도 마찬가지로 etcd에 base64로 인코딩되어 저장됩니다.

 

주의할 점은 시크릿은 암호화가 아닌 인코딩-디코딩 방식을 사용한다는 사실입니다. 정보를 암호화하지 않기 때문에 시크릿을 완벽한 데이터 보호 방법이라 할 수 없습니다. 따라서 추가적인 보안 조치가 필요합니다. 예를 들어, 앞에서 배운 역할 접근 제어 방식을 사용하여 권한이 있는 사용자만 시크릿 정보를 조회하고 사용할 수 있도록 제한할 수 있습니다. 또한 별도의 암호화 플러그인을 사용하여 시크릿 데이터를 완벽하게 암호화할 수도 있습니다. 이때는 Key Management Service(KMS)와 같은 외부 서비스를 필요로 합니다.

 

정리하면, 시크릿은 애플리케이션에서 사용하는 민감한 정보를 안전하게 보호하고 관리하는 중요한 도구입니다. 시크릿을 사용하면 쿠버네티스 클러스터 내에서 중요한 정보를 보호함으로써 많은 보안 취약점을 사전에 방지할 수 있습니다.

 

 

마치며

지금까지 쿠버네티스 보안을 위한 기본적인 기능에 관해 알아보았습니다. 사실 ​쿠버네티스의 보안은 방대한 주제이지만, 이 글에서는 가장 기본적인 핵심 영역 세 가지를 소개했습니다. 그 내용은 첫째, 네트워크 정책을 통한 쿠버네티스 클러스터 접속 제어. 둘째 역할 기반의 권한 설정. 그리고 셋째, 민감한 정보를 클러스터 내부에서 보호하는 것이었습니다. 이 세 가지 보안 기능을 잘 활용해 기본적인 쿠버네티스 보안을 꼭 지키시길 바랍니다.

 

테크유람

편집 김상현 객원 에디터

 

요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.

좋아요

댓글

공유

공유

댓글 0
작가
93
명 알림 받는 중

작가 홈

작가
93
명 알림 받는 중
테크유람(https://blog.naver.com/techtrip) 블로그를 운영하고 있으며 클라우드, 오픈 소스, 웹 성능과 선진적인 DevOps 적용에 관심이 많은 블로거입니다.

삼성SDS에서 웹 개발자로 IT 경력을 시작하였고 이후 마이크로소프트에서는 Xbox 게임 타이틀 개발을, 현재는 클라우드 서비스를 제공하는 IT 기업에서 아시아 지역의 기술 컨설팅을 담당하고 있습니다.

12권의 IT 도서의 저자이기도 하며 글과 콘퍼런스, 교육을 통해 다양한 IT 기술을 많은 이에게 전달하고 공유하며, 상호 작용하는 IT 엔지니어의 삶을 즐기고 있습니다.

좋아요

댓글

스크랩

공유

공유

요즘IT가 PICK한 뉴스레터를 매주 목요일에 만나보세요

요즘IT가 PICK한 뉴스레터를
매주 목요일에 만나보세요

뉴스레터를 구독하려면 동의가 필요합니다.
https://auth.wishket.com/login