Notice
Recent Posts
Recent Comments
Link
Archives
Today
Total
관리 메뉴

카레제육 블로그

OpenShift, Security Context Constraints(SCC) 이해 본문

DevOps

OpenShift, Security Context Constraints(SCC) 이해

kare jeyuk 2025. 3. 31. 00:00

항상 스탠더드 형식의 Kubernetes만 사용하다가, 2년 전 고객 환경에서 업무를 하며 처음으로 OpenShift를 사용하게 되었다. 이때 가장 고생했던 부분이 바로 Security Context Constraints였다. 과거에 고생했던 경험과 더불어 이번에 그 환경에서 DR(Disaster Recovery) 구성을 진행하며 다시 한번 만나게된 SCC를 다시 정리하고자 한다.

SCC가 무엇인가?

SCC는 Kubernetes에서 클러스터 수준의 보안 정책을 정의하는 리소스다. 쉽게 말하면, 파드와 컨테이너가 클러스터에서 실행될 때 따라야 할 "보안 규칙"을 설정하는 도구다. SCC는 특히 Red Hat의 OpenShift에서 기본적으로 제공되며, 일반 Kubernetes의 PodSecurityPolicy(현재 deprecated, 현재 Admission Controller쪽으로 넘어가 관리됨)와 비슷한 개념을 구현한다.

SCC의 핵심 목표는 다음과 같다.

  • 보안 강제: 파드가 루트 권한으로 실행되거나 호스트 시스템에 접근하지 못하게 막는다.
  • 정책 일관성: 클러스터 전체에 일관된 보안 기준을 적용한다.
  • 유연성: 관리자가 필요에 따라 세부적인 보안 규칙을 설정할 수 있게 한다.

예를 들어, "모든 파드는 루트 사용자로 실행되면 안 된다."거나 "호스트 네트워크에 접근할 수 없다." 같은 규칙을 SCC로 정의한다. 이런 규칙을 통해 클러스터를 더 안전하게 유지한다. (이 때문에 처음 만났을때 굉장히 고생했다. 보안 규칙이 아주아주아주 강력하고, 세세하며 꼼꼼하다.)

SCC의 구성 요소

SCC는 여타 다른 쿠버네티스 리소스와 같이 YAML 파일로 정의되며, 여러 필드로 구성된다. 주요 구성 요소를 하나씩 살펴본다.

  1. 기본 정보
    apiVersion: security.openshift.io/v1처럼 SCC의 API 버전을 지정한다.
    kind: SecurityContextConstraints로 설정한다.
    metadata: SCC의 이름(name)과 레이블 등을 정의한다.
  2. 권한 제어
    allowPrivilegedContainer: 컨테이너가 privileged 모드로 실행될 수 있는지 여부를 결정한다. 기본은 false다.
    allowPrivilegeEscalation: 권한 상승(예: setuid)을 허용할지 여부를 정한다.
    allowedCapabilities: 컨테이너에 추가할 Linux Capabilities(예: NET_ADMIN)를 지정한다.
    requiredDropCapabilities: 반드시 제거해야 하는 Capabilities(예: SYS_ADMIN)를 정한다.
  3. 사용자 및 그룹
    runAsUser: 파드가 실행되는 사용자 ID(UID)를 제어한다.
    MustRunAsNonRoot: 루트(UID 0) 실행을 금지한다.
    MustRunAsRange: UID 범위를 지정한다(예: 1000~2000).
    runAsGroup: 그룹 ID(GID)를 제어한다.
    supplementalGroups: 추가 그룹 ID를 설정한다.
  4. SELinux와 보안 프로파일
    seLinuxContext: SELinux 레이블을 강제한다(예: level: "s0:c123,c456").
    seccompProfiles: Seccomp 프로파일을 지정한다(예: runtime/default).
  5. 호스트 리소스 접근
    allowHostNetwork: 호스트 네트워크 사용 여부를 결정한다.
    allowHostPID: 호스트 PID namespace 공유 여부를 정한다.
    allowHostDirVolumePlugin: hostPath 볼륨 허용 여부를 설정한다.
  6. 볼륨과 파일 시스템
    volumes: 허용된 볼륨 유형(예: configMap, secret)을 지정한다.
    readOnlyRootFilesystem: 루트 파일 시스템을 읽기 전용으로 강제한다.
  7. 사용자 할당 및 우선순위
    users: SCC를 사용할 사용자(예: system:serviceaccount:default:my-sa)를 정의한다.
    groups: SCC를 사용할 그룹(예: system:authenticated)을 지정한다.
    priority: 여러 SCC 중 우선순위를 정한다.

다음 예시는 루트 실행을 금지하고, configMap과 secret 볼륨만 허용한다.

apiVersion: security.openshift.io/v1
kind: SecurityContextConstraints
metadata:
  name: restricted-scc
spec:
  allowPrivilegedContainer: false
  runAsUser:
    type: MustRunAsNonRoot
  volumes:
    - configMap
    - secret

SCC의 동작 과정

SCC가 실제로 어떻게 작동하는지 단계를 나눠 살펴보자.

  1. 파드 생성 요청
    사용자가 kubectl apply로 파드를 배포하려고 한다. 이 파드는 특정 서비스 어카운트(예: my-sa)를 사용한다.
  2. SCC 매핑
    Kubernetes는 요청을 보낸 사용자나 서비스 어카운트에 연결된 SCC를 찾는다. 예를 들어, users 필드에 system:serviceaccount:default:my-sa가 명시된 SCC가 적용된다.
  3. 정책 검증
    API 서버는 파드의 사양(spec)을 SCC 규칙과 비교한다.
    • 파드의 securityContext에 runAsUser: 0(루트)이 있으면, SCC의 MustRunAsNonRoot 규칙을 위반한다.
    • hostPath 볼륨을 사용하려는데 SCC에서 허용하지 않으면 실패한다.
      이 과정은 Admission Controller가 담당한다. SCC를 위반하면 파드 생성이 거부되고 오류 메시지가 반환된다.
  4. 파드 실행
    규칙을 모두 통과하면 파드가 스케줄링되고 실행된다. 필요하면 SCC의 기본값(예: defaultAddCapabilities)이 적용된다.

위 예시를 적용했다면, 아래 정의를 가진 파드 배포는 실패한다.

spec:
  containers:
  - name: nginx
    image: nginx
    securityContext:
      runAsUser: 0  # 루트

SCC가 MustRunAsNonRoot 이기 때문에 규칙 위배로 오류가 발생한다. Error: runAsUser 0 is forbidden.

SCC와 Security Context의 차이

SCC를 이해하려면 파드 수준의 securityContext와의 차이를 아는 것이 중요하다.

  • securityContext: 개별 파드나 컨테이너에 적용되는 보안 설정(예: runAsUser, capabilities)을 정의한다.
  • Security Context Constraints: 클러스터 전체에 걸친 강제 정책을 설정한다. 파드의 설정이 SCC를 벗어나면 거부한다.
    즉, SCC는 "최소 기준"을 강제하고, securityContext는 그 안에서 세부 조정을 한다.

추가로 알아야 하는 것!

RBAC와의 연계

SCC를 사용하려면 RBAC로 권한을 부여한다.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: scc-role
rules:
- apiGroups: ["security.openshift.io"]
  resources: ["securitycontextconstraints"]
  resourceNames: ["restricted-scc"]
  verbs: ["use"]

위와 같이 적용해야 서비스 어카운트가 restricted-scc를 사용할 수 있다.

OpenShift와 Kubernetes: PodSecurity 표준

SCC는 OpenShift에서 기본 제공된다. 반면, 일반 Kubernetes에서는 PodSecurityPolicy(PSP)로 비슷한 기능을 했지만, PSP가 Kubernetes 1.21에서 deprecated되고 1.25에서 제거됐다. 이를 대체하기 위해 Pod Security Standards가 등장했다.
Pod Security StandardsAdmission ControllerPod Security Admission 통해 동작하며, 별도의 CRD(Custom Resource Definition) 대신, 네임스페이스 레이블을 사용해 보안 정책을 적용한다.

세 가지 수준이 있다.

  • Privileged: 제한이 거의 없다.
  • Baseline: 기본적인 보안 설정(예: 루트 실행 허용, 일부 Capabilities 제한)을 강제한다.
  • Restricted: 가장 엄격하다. 루트 실행 금지, 호스트 리소스 접근 차단 등을 적용한다.

아래는 네임스페이스에 레이블을 추가하는 예시이다.

apiVersion: v1
kind: Namespace
metadata:
  name: my-namespace
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest

이 설정은 Admission Controller(PodSecurity Admission)가 파드 생성 시 Restricted 정책을 검증한다. SCC처럼 세밀한 제어는 어렵지만, 간단하고 표준화된 접근 방식을 제공한다.

디버깅

글 초반에서 이야기한 고생한 이유는 바로 쿠버네티스에 대한 학습도 부족했던 점과 더불어 SCC의 존재를 몰랐기 때문에, 파드 자체가 뜨지 않아서 무엇부터 디버깅해야할 지 몰랐기 때문이다.

OpenShift에서 파드가 실행되지 않거나 실패하게 되는 경우 아래의 경우를 생각해보자

  • kubectl describe pod로 오류를 본다.
  • SCC 설정을 kubectl get scc -o yaml로 점검한다.
  • RBAC 권한 누락도 의심한다.