클러스터 보안 강화

이 문서에서는 Google Distributed Cloud 클러스터의 보안을 강화하는 방법을 설명합니다.

SELinux를 사용하여 컨테이너 보호

Red Hat Enterprise Linux(RHEL)에서 지원되는 SELinux를 사용 설정하여 컨테이너를 보호할 수 있습니다. 호스트 머신이 RHEL을 실행 중이고 클러스터에서 SELinux를 사용 설정하려면 모든 호스트 머신에서 SELinux를 사용 설정해야 합니다. 자세한 내용은 SELinux를 사용하여 컨테이너 보호를 참조하세요.

seccomp를 사용하여 컨테이너 제한

보안 컴퓨팅 모드(seccomp)는 Google Distributed Cloud 버전 1.11 이상에서 사용할 수 있습니다. seccomp 프로필로 컨테이너를 실행하면 컨테이너가 커널에 수행할 수 있는 시스템 호출이 제한되므로 클러스터 보안이 향상됩니다. 이렇게 하면 커널 취약점이 악용될 가능성이 줄어듭니다.

기본 seccomp 프로필에는 컨테이너가 수행할 수 있는 시스템 호출 목록이 포함됩니다. 목록에 없는 시스템 호출은 허용되지 않습니다. seccomp는 Google Distributed Cloud 버전 1.11에서 기본적으로 사용 설정됩니다. 즉, 모든 시스템 컨테이너와 고객 워크로드는 컨테이너 런타임의 기본 seccomp 프로필로 실행됩니다. 구성 파일에 seccomp 프로필을 지정하지 않은 컨테이너 및 워크로드에도 seccomp 제한이 적용됩니다.

seccomp 클러스터 전체 또는 특정 워크로드 사용 중지 방법

클러스터 생성 또는 클러스터 업그레이드 중에만 seccomp를 사용 중지할 수 있습니다. bmctl update를 사용하여 이 기능을 사용 중지할 수 없습니다. 클러스터 내에서 seccomp를 사용 중지하려면 다음 clusterSecurity 섹션을 클러스터의 구성 파일에 추가합니다.

apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: example
  namespace: cluster-example
spec:
...
  clusterSecurity:
    enableSeccomp: false
...

드물지만 일부 워크로드에서 seccomp가 기본적으로 차단하는 시스템 호출을 실행해야 할 경우 전체 클러스터에서 seccomp를 사용 중지할 필요가 없습니다. 대신 특정 워크로드를 선택하여 unconfined mode에서 실행할 수 있습니다. unconfined mode에서 워크로드를 실행하면 seccomp 프로필이 나머지 클러스터에 적용하는 제한으로부터 워크로드가 해제됩니다.

unconfined mode에서 컨테이너를 실행하려면 다음 securityContext 섹션을 포드 매니페스트에 추가합니다.

apiVersion: v1
kind: Pod
....
spec:
  securityContext:
    seccompProfile:
      type: Unconfined
....

root 사용자로 컨테이너 실행 안함

기본적으로 컨테이너의 프로세스는 root로 실행됩니다. 이렇게 하면 컨테이너의 한 프로세스에서 문제가 발생한 경우 이 프로세스가 호스트 머신에서 root로 실행되므로 보안 문제가 발생할 수 있습니다. 따라서 모든 워크로드를 비루트 사용자로 실행하는 것이 좋습니다.

다음 섹션에서는 비루트 사용자로 컨테이너를 실행하는 두 가지 방법을 설명합니다.

방법 #1: DockerfileUSER 명령 추가

이 방법은 Dockerfile을 사용하여 컨테이너가 root 사용자로 실행되지 않도록 합니다. Dockerfile에서는 컨테이너 내에서 프로세스를 실행할 사용자를 지정할 수 있습니다. 다음 Dockerfile 스니펫은 이 방법을 보여줍니다.

....

#Add a user with userid 8877 and name nonroot
RUN useradd −u 8877 nonroot

#Run Container as nonroot
USER nonroot
....

이 예시에서 Linux 명령어 useradd -u는 컨테이너 내에 nonroot라는 사용자를 만듭니다. 이 사용자의 사용자 ID(UID)는 8877입니다.

Dockerfile의 다음 줄은 USER nonroot 명령어를 실행합니다. 이 명령어는 이미지의 이 시점에서 명령어가 nonroot 사용자로 실행되도록 지정합니다.

컨테이너 프로세스가 nonroot에 대해 올바르게 실행될 수 있도록 UID 8877에 권한을 부여합니다.

방법 #2: Kubernets 매니페스트 파일에 securityContext 필드 추가

이 방법은 Kubernetes 매니페스트 파일을 사용해서 컨테이너가 root 사용자로 실행되지 않도록 합니다. 포드에 대해 보안 설정이 지정되고 이러한 보안 설정은 다시 포드 내에 있는 모든 컨테이너에 적용됩니다.

다음 예시에서는 지정된 포드에 대한 매니페스트 파일의 일부를 보여줍니다.

apiVersion: v1
kind: Pod
metadata:
  name: name-of-pod
spec:
  securityContext:
    runAsUser: 8877
    runAsGroup: 8877
....

runAsUser 필드는 포드에 있는 모든 컨테이너에 대해 모든 프로세스가 사용자 ID 8877로 실행되도록 지정합니다. runAsGroup 필드는 이러한 프로세스의 기본 그룹 ID(GID)를 8877로 지정합니다. 컨테이너 프로세스가 올바르게 실행될 수 있도록 UID 8877에 필요 충분한 권한을 부여하는 것도 잊지 않아야 합니다.

그러면 컨테이너 내부의 프로세스가 루트보다 적은 권한을 갖는 UID 8877로 실행됩니다.

Google Distributed Cloud의 시스템 컨테이너는 클러스터를 설치하고 관리하는 데 도움이 됩니다. 이러한 컨테이너에서 사용하는 UID 및 GID는 클러스터 사양의 startUIDRangeRootlessContainers 필드에서 제어될 수 있습니다. startUIDRangeRootlessContainers는 선택적 필드로, 지정하지 않으면 값은 2000입니다. startUIDRangeRootlessContainers에 허용되는 값은 1000-57000입니다. 업그레이드 중에만 startUIDRangeRootlessContainers 값을 변경할 수 있습니다. 시스템 컨테이너는 startUIDRangeRootlessContainers~startUIDRangeRootlessContainers + 2999 범위 내 UID 및 GID를 사용합니다.

다음 예시에서는 클러스터 리소스의 매니페스트 파일 일부를 보여줍니다.

apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: name-of-cluster
spec:
 clusterSecurity:
    startUIDRangeRootlessContainers: 5000
...

시스템 컨테이너에서 사용하는 UID 및 GID 공간이 사용자 워크로드에 할당된 공간과 겹치지 않도록 startUIDRangeRootlessContainers 값을 선택합니다.

루트 없는 모드를 사용 중지하는 방법

Google Distributed Cloud 출시 버전 1.10부터는 Kubernetes 컨트롤 플레인 컨테이너 및 시스템 컨테이너가 기본적으로 루트가 아닌 사용자로 실행됩니다. Google Distributed Cloud는 이러한 사용자에게 2000~4999 범위 내의 UID 및 GID를 할당합니다. 그러나 해당 UID 및 GID가 사용자 환경 내에서 실행 중인 프로세스에 이미 할당된 경우 이 할당으로 인해 문제가 발생할 수 있습니다.

Google Distributed Cloud 출시 버전 1.11부터는 클러스터를 업그레이드할 때 루트 없는 모드를 중지할 수 있습니다. 루트 없는 모드가 중지되면 Kubernetes 컨트롤 플레인 컨테이너와 시스템 컨테이너는 루트 사용자로 실행됩니다.

루트 없는 모드를 중지하려면 다음 단계를 수행합니다.

  1. 클러스터 구성 파일에 다음 clusterSecurity 섹션을 추가합니다.

    apiVersion: baremetal.cluster.gke.io/v1
    kind: Cluster
    metadata:
      name: example
      namespace: cluster-example
    spec:
    ...
      clusterSecurity:
        enableRootlessContainers: false
    ...
    
  2. 클러스터를 업그레이드합니다. 자세한 내용은 클러스터 업그레이드를 참조하세요.

워크로드가 자체 수정하는 기능을 제한

특정 Kubernetes 워크로드, 특히 시스템 워크로드에는 자체 수정 권한이 있습니다. 예를 들어 일부 워크로드는 수직적으로 자동 확장됩니다. 이렇게 하면 노드를 이미 손상시킨 공격자가 클러스터에서 추가로 에스컬레이션할 수 있습니다. 예를 들어 공격자는 노드에 있는 워크로드가 동일 네임스페이스에 존재하는 권한이 높은 서비스 계정으로 실행되도록 변경할 수 있습니다.

워크로드에 자체 수정 권한이 애초에 부여되지 않는 것이 좋습니다. 자체 수정이 필요한 경우 몇 가지 유용한 보안 정책을 제공하는 오픈소스 Gatekeeper 라이브러리에서 NoUpdateServiceAccount와 같은 Gatekeeper 또는 정책 컨트롤러 제약조건을 적용하여 권한을 제한할 수 있습니다.

정책을 배포할 때는 일반적으로 클러스터 수명 주기를 관리하는 컨트롤러에서 정책을 우회할 수 있도록 해야 합니다. 이는 컨트롤러가 클러스터 업그레이드 적용과 같이 클러스터를 변경할 수 있도록 하기 위해 필요합니다. 예를 들어 Google Distributed Cloud에 NoUpdateServiceAccount 정책을 배포하는 경우 Constraint에 다음 매개변수를 설정해야 합니다.

parameters:
  allowedGroups:
  - system:masters
  allowedUsers: []

kubelet 읽기 전용 포트 사용 중지

Google Distributed Cloud 출시 버전 1.15.0부터는 기본적으로 kubelet 읽기 전용 포트인 10255 포트가 사용 중지됩니다. 이 안전하지 않은 kubelet 포트 10255에서 데이터를 읽도록 구성된 모든 고객 워크로드는 보안 kubelet 포트 10250을 사용하도록 마이그레이션되어야 합니다.

버전 1.15.0 이상으로 생성된 클러스터에서만 이 포트가 기본으로 사용 중지됩니다. kubelet 읽기 전용 포트 10255는 클러스터를 버전 1.15.0 이상으로 업그레이드한 후에도 1.15.0 미만 버전에서 생성된 클러스터에 계속 액세스할 수 있습니다.

이렇게 변경한 이유는 kubelet에서 인증되지 않은 포트 10255를 통해 민감도가 낮은 정보를 유출하기 때문입니다. 이 정보에는 공격자에게 유리한 노드에서 실행되는 모든 포드에 대한 전체 구성 정보가 담겨 있습니다. 또한 측정항목과 상태 정보를 노출하여 비즈니스에 민감한 정보를 제공할 수 있습니다.

CIS Kubernetes 벤치마크에서 kubelet 읽기 전용 포트를 중지하는 것이 좋습니다.

유지보수

클러스터가 작동되고 실행된 다음에는 보안 유지를 위해 보안 게시판을 모니터링하고 클러스터를 업그레이드해야 합니다.

보안 게시판 모니터링

GKE 보안팀에서는 심각도가 높거나 매우 높은 취약점에 대한 보안 게시판을 게시합니다.

이 게시판은 일반적인 Google Cloud 취약점 번호 지정 스킴을 따르며 기본 Google Cloud 게시판 페이지 및 Google Distributed Cloud 출시 노트에서 연결됩니다.

이 XML 피드를 사용하여 Google Distributed Cloud 및 관련 제품의 보안 게시판을 구독하세요. 구독

심각도가 높거나 매우 높은 취약점을 해결하기 위해 고객의 조치가 필요한 경우 Google에서는 이메일로 고객에게 연락합니다. 또한 지원 채널의 지원 계약을 통해 고객에게 연락할 수도 있습니다.

Google이 GKE 및 GKE Enterprise의 보안 취약점과 패치를 관리하는 방법에 대한 자세한 내용은 보안 패치 적용을 참조하세요.

클러스터 업그레이드

Kubernetes에는 새로운 보안 기능과 보안 패치가 정기적으로 제공됩니다. Google Distributed Cloud 출시 버전에는 클러스터에 영향을 줄 수 있는 보안 취약점을 해결하는 Kubernetes 보안 향상 기능이 포함되어 있습니다.

사용자는 Google Distributed Cloud 클러스터를 최신 상태로 유지해야 합니다. 각 출시 버전의 출시 노트를 검토합니다. 클러스터에 대한 보안 위험이 최소화되도록 매달 새로운 패치 출시 버전으로 업데이트하고 4개월마다 부 버전으로 업데이트하도록 계획합니다.

클러스터 업그레이드의 여러 장점 중 하나는 클러스터 kubeconfig 파일을 자동으로 새로고침된다는 점입니다. kubeconfig 파일은 사용자를 클러스터에 인증합니다. kubeconfig 파일은 bmctl로 클러스터를 만들 때 클러스터 디렉터리에 추가됩니다. 기본 이름과 경로는 bmctl-workspace/CLUSTER_NAME/CLUSTER_NAME-kubeconfig입니다. 클러스터를 업그레이드하면 클러스터의 kubeconfig 파일이 자동으로 갱신됩니다. 그렇지 않으면 kubeconfig 파일은 생성된 지 1년 후에 만료됩니다.

클러스터 업그레이드 방법에 대한 자세한 내용은 클러스터 업그레이드를 참조하세요.

Cloud Interconnect 또는 Cloud VPN에 VPC 서비스 제어 사용

Cloud Interconnect는 지연 시간이 짧고 가용성이 높은 연결을 제공하므로, 온프레미스 베어메탈 머신과 Google Cloud 가상 프라이빗 클라우드(VPC) 네트워크 간에 안정적으로 데이터를 전송할 수 있습니다. Cloud Interconnect에 대한 자세한 내용은 Dedicated Interconnect 프로비저닝 개요를 참조하세요.

Cloud VPN은 IPsec VPN 연결을 통해 피어 네트워크를 가상 프라이빗 클라우드(VPC) 네트워크에 안전하게 연결합니다. Cloud VPN에 대한 자세한 내용은 Cloud VPN 개요를 참조하세요.

VPC 서비스 제어는 Cloud Interconnect 또는 Cloud VPN과 함께 작동하여 클러스터에 대해 추가 보안을 제공합니다. VPC 서비스 제어를 사용하면 데이터 무단 반출 위험을 줄일 수 있습니다. VPC 서비스 제어를 사용하면 서비스 경계에 프로젝트를 추가하여 외부 요청으로부터 리소스와 서비스를 보호할 수 있습니다. 서비스 경계에 대한 자세한 내용은 서비스 경계 세부정보 및 구성을 참조하세요.

Google Distributed Cloud를 완벽하게 보호하려면 제한된 VIP를 사용하고 다음 API를 서비스 경계에 추가해야 합니다.

  • Artifact Registry API(artifactregistry.googleapis.com)
  • Resource Manager API(cloudresourcemanager.googleapis.com)
  • Compute Engine API(compute.googleapis.com)
  • Connect Gateway API(connectgateway.googleapis.com)
  • Google Container Registry API(containerregistry.googleapis.com)
  • GKE Connect API(gkeconnect.googleapis.com)
  • GKE Hub API(gkehub.googleapis.com)
  • GKE On-Prem API(gkeonprem.googleapis.com)
  • Identity and Access Management(IAM) API(iam.googleapis.com)
  • Cloud Logging API(logging.googleapis.com)
  • Cloud Monitoring API(monitoring.googleapis.com)
  • Config Monitoring for Ops API(opsconfigmonitoring.googleapis.com)
  • Service Control API(servicecontrol.googleapis.com)
  • Cloud Storage API(storage.googleapis.com)

bmctl을 사용하여 클러스터를 만들거나 업그레이드할 때 --skip-api-check 플래그를 사용하여 Service Usage API(serviceusage.googleapis.com) 호출을 우회합니다. VPC 서비스 제어에서는 Service Usage API가 지원되지 않습니다.