파드와 컨테이너의 Linux 커널 보안 제약
파드와 컨테이너의 Linux 커널 보안 제약 (Linux kernel security constraints for Pods and containers)
이 페이지는 쿠버네티스 워크로드에서 사용할 수 있는 Linux 커널에 내장된 보안 기능 중 일부를 설명해요. 이 기능을 파드와 컨테이너에 적용하는 방법을 배우려면 파드 또는 컨테이너의 SecurityContext 구성하기를 참고해요. 이미 Linux와 쿠버네티스 워크로드의 기본에 익숙해야 해요.
출처: 문서
본문
root 권한 없이 워크로드 실행하기
쿠버네티스에 워크로드를 배포할 때 Pod 스펙을 사용해 그 워크로드가 노드에서 root 사용자로 실행되는 것을 제한해요. Pod securityContext 를 사용해 파드의 프로세스에 대한 특정 Linux 사용자와 그룹을 정의하고, 컨테이너가 root 사용자로 실행되는 것을 명시적으로 제한할 수 있어요. Pod 매니페스트에서 이 값을 설정하면 컨테이너 이미지의 유사한 값보다 우선하며, 특히 소유하지 않은 이미지를 실행할 때 유용해요.
주의:
이 페이지의 커널 보안 기능을 구성하면 클러스터의 프로세스가 취할 수 있는 동작에 대한 세밀한 제어를 제공하지만, 이 구성을 대규모로 관리하는 것은 까다로울 수 있어요. 컨테이너를 root가 아닌 사용자로 실행하거나(또는 root 권한이 필요한 경우 사용자 네임스페이스에서 실행) 구성한 커널 보안 기능을 강제해야 할 필요성을 줄이는 데 도움이 돼요.
Linux 커널의 보안 기능
쿠버네티스는 컨테이너화된 워크로드를 강화하고 격리를 개선하기 위해 Linux 커널 기능을 구성·사용할 수 있게 해줘요. 일반적인 기능은 다음과 같아요:
- Secure computing mode (seccomp): 프로세스가 할 수 있는 시스템 호출을 필터링해요
- AppArmor: 개별 프로그램의 접근 권한을 제한해요
- Security Enhanced Linux (SELinux): 더 관리하기 쉬운 보안 정책 강제를 위해 객체에 보안 라벨을 할당해요
이 기능 중 하나의 설정을 구성하려면 노드에 선택한 운영 체제가 커널에서 그 기능을 활성화해야 해요. 예를 들어 Ubuntu 7.10 이상은 기본으로 AppArmor를 활성화해요. OS가 특정 기능을 활성화하는지 알아보려면 OS 문서를 참고해요.
Pod 스펙의 securityContext 필드로 그 프로세스에 적용되는 제약을 정의해요. securityContext 필드는 특정 Linux capabilities 또는 UID·GID를 사용한 파일 접근 권한 같은 다른 보안 설정도 지원해요. 자세한 내용은 파드 또는 컨테이너의 SecurityContext 구성하기를 참고해요.
seccomp
일부 워크로드는 노드의 호스트 머신에서 root 사용자로 특정 동작을 수행하는 권한이 필요할 수 있어요. Linux는 capabilities 로 사용 가능한 권한을 범주로 나누므로, 프로세스가 모든 권한을 부여받지 않고 특정 동작을 수행하는 데 필요한 권한을 얻을 수 있어요. 각 capability에는 프로세스가 만들 수 있는 시스템 호출(syscalls) 집합이 있어요. seccomp는 이 개별 syscall을 제한하게 해줘요. 프로세스가 사용자 공간에서 커널로 만들 수 있는 호출을 제한해 프로세스의 권한을 샌드박스화하는 데 사용할 수 있어요.
쿠버네티스에서 각 노드의 컨테이너 런타임 을 사용해 컨테이너를 실행해요. 예시 런타임에는 CRI-O, Docker, containerd가 있어요. 각 런타임은 기본적으로 Linux capabilities의 일부만 허용해요. seccomp 프로필을 사용해 허용된 syscall을 개별적으로 더 제한할 수 있어요. 컨테이너 런타임은 보통 기본 seccomp 프로필을 포함해요. 쿠버네티스는 노드에 로드된 seccomp 프로필을 파드와 컨테이너에 자동으로 적용하게 해줘요.
참고:
쿠버네티스에서 seccomp를 구현하는 방법을 배우려면 seccomp로 컨테이너의 Syscall 제한하기 또는 Seccomp 노드 참조를 참고해요.
seccomp에 대해 더 알아보려면 Linux 커널 문서에서 Seccomp BPF를 참고해요.
seccomp 고려 사항
seccomp는 Linux syscall에 대한 세밀한 제어가 필요한 경우에만 직접 구성해야 하는 저수준 보안 구성이에요. 특히 대규모로 seccomp를 사용하면 다음 위험이 있어요:
- 애플리케이션 업데이트 중 구성이 깨질 수 있어요
- 공격자가 허용된 syscall을 사용해 취약점을 악용할 수 있어요
- 개별 애플리케이션에 대한 프로필 관리는 대규모에서 어려워져요
권장 사항: 컨테이너 런타임과 함께 번들된 기본 seccomp 프로필을 사용해요. 더 격리된 환경이 필요하다면 gVisor 같은 샌드박스 사용을 고려해요. 샌드박스는 커스텀 seccomp 프로필에서 앞선 위험을 해결하지만 노드에서 더 많은 컴퓨팅 리소스가 필요하고 GPU나 다른 특수 하드웨어와의 호환성 문제가 있을 수 있어요.
AppArmor와 SELinux: 정책 기반 강제 접근 제어
쿠버네티스 워크로드를 강화하기 위해 AppArmor와 SELinux 같은 Linux 정책 기반 강제 접근 제어(MAC) 메커니즘을 사용할 수 있어요.
AppArmor
AppArmor는 표준 Linux 사용자·그룹 기반 권한을 보완해 프로그램을 제한된 리소스 집합으로 제한하는 Linux 커널 보안 모듈이에요. AppArmor는 잠재적 공격 표면을 줄이고 더 깊은 방어를 제공하기 위해 어떤 애플리케이션이든 구성될 수 있어요. 특정 프로그램이나 컨테이너가 필요한 접근(Linux capabilities, 네트워크 접근, 파일 권한 등)을 허용하도록 조정된 프로필로 구성돼요. 각 프로필은 금지된 리소스에 대한 접근을 차단하는 enforcing 모드 또는 위반만 보고하는 complain 모드로 실행될 수 있어요.
AppArmor는 컨테이너가 할 수 있는 일을 제한해 더 안전한 배포를 실행하는 데 도움을 주고, 및/또는 시스템 로그를 통한 더 나은 감사를 제공해요. 사용하는 컨테이너 런타임이 기본 AppArmor 프로필을 제공할 수도 있고 커스텀 프로필을 사용할 수도 있어요.
쿠버네티스에서 AppArmor를 사용하는 방법을 배우려면 AppArmor로 컨테이너의 리소스 접근 제한하기를 참고해요.
SELinux
SELinux는 프로세스 같은 특정 주체(subject) 가 시스템의 파일에 갖는 접근을 제한할 수 있게 해주는 Linux 커널 보안 모듈이에요. 특정 SELinux 라벨이 있는 주체에 적용되는 보안 정책을 정의해요. SELinux 라벨이 있는 프로세스가 파일에 접근하려 하면, SELinux 서버는 그 프로세스의 보안 정책이 접근을 허용하는지 확인하고 인가 결정을 내려요.
쿠버네티스에서 매니페스트의 securityContext 필드에 SELinux 라벨을 설정할 수 있어요. 지정된 라벨이 그 프로세스에 할당돼요. 그 라벨에 영향을 주는 보안 정책을 구성했다면 호스트 OS 커널이 이 정책을 강제해요.
쿠버네티스에서 SELinux를 사용하는 방법을 배우려면 컨테이너에 SELinux 라벨 할당하기를 참고해요.
AppArmor와 SELinux의 차이
Linux 노드의 운영 체제는 보통 AppArmor 또는 SELinux 중 하나를 포함해요. 두 메커니즘 모두 비슷한 유형의 보호를 제공하지만 다음과 같은 차이가 있어요:
- 구성: AppArmor는 프로필을 사용해 리소스에 대한 접근을 정의해요. SELinux는 특정 라벨에 적용되는 정책을 사용해요.
- 정책 적용: AppArmor에서 파일 경로를 사용해 리소스를 정의해요. SELinux는 리소스의 인덱스 노드(inode)를 사용해 리소스를 식별해요.
기능 요약
다음 표는 각 보안 제어의 사용 사례와 범위를 설명해요. 이 모든 제어를 함께 사용해 더 강화된 시스템을 만들 수 있어요.
| 보안 기능 | 설명 | 사용 방법 | 예시 |
|---|---|---|---|
| seccomp | 사용자 공간에서 개별 커널 호출을 제한해요. 제한된 syscall을 사용하는 취약점이 시스템을 손상시킬 가능성을 줄여요. | Pod 또는 컨테이너 스펙에 로드된 seccomp 프로필을 지정해 그 제약을 파드의 프로세스에 적용해요. | CVE-2022-0185에서 사용된 unshare syscall을 거부해요. |
| AppArmor | 프로그램의 특정 리소스 접근을 제한해요. 프로그램의 공격 표면을 줄여요. 감사 로깅을 개선해요. | 컨테이너 스펙에 로드된 AppArmor 프로필을 지정해요. | 읽기 전용 프로그램이 시스템의 어떤 파일 경로에도 쓰는 것을 제한해요. |
| SELinux | 라벨과 보안 정책을 사용해 파일, 애플리케이션, 포트, 프로세스 같은 리소스에 대한 접근을 제한해요. | 특정 라벨에 대한 접근 제한을 지정해요. 그 라벨로 프로세스를 태그해 라벨과 관련된 접근 제한을 강제해요. | 컨테이너가 자신의 파일 시스템 밖의 파일에 접근하는 것을 제한해요. |
참고:
커스텀 구성 관리 고려 사항
seccomp, AppArmor, SELinux는 보통 기본 보호를 제공하는 기본 구성을 가져요. 워크로드의 요구 사항을 충족하는 커스텀 프로필과 정책을 만들 수도 있어요. 특히 세 기능을 모두 함께 사용한다면 이 커스텀 구성을 대규모로 관리·배포하는 것은 까다로울 수 있어요. 이 구성을 대규모로 관리하는 데 도움을 주려면 Kubernetes Security Profiles Operator 같은 도구를 사용해요.
커널 수준 보안 기능과 privileged 컨테이너
쿠버네티스는 일부 신뢰된 컨테이너가 privileged 모드로 실행되도록 지정하게 해줘요. 파드의 어떤 컨테이너든 privileged 모드로 실행해 그렇지 않으면 접근할 수 없는 운영 체제의 관리 기능을 사용할 수 있어요. 이것은 Windows와 Linux 모두에서 사용할 수 있어요.
Privileged 컨테이너는 워크로드에서 사용할 수 있는 일부 Linux 커널 제약을 명시적으로 재정의해요:
- seccomp: Privileged 컨테이너는 매니페스트에서 지정한 어떤 seccomp 프로필이든 재정의해
Unconfinedseccomp 프로필로 실행돼요. - AppArmor: Privileged 컨테이너는 적용된 모든 AppArmor 프로필을 무시해요.
- SELinux: Privileged 컨테이너는
unconfined_t도메인으로 실행돼요.
Privileged 컨테이너
컨테이너의 securityContext 필드에 privileged: true 필드를 설정하면 파드의 어떤 컨테이너든 Privileged mode 를 활성화할 수 있어요. Privileged 컨테이너는 적용된 seccomp 프로필, AppArmor 프로필, SELinux 제약 같은 많은 다른 하드닝 설정을 재정의하거나 되돌려요. Privileged 컨테이너는 필요하지 않은 capabilities를 포함한 모든 Linux capabilities를 부여받아요. 예를 들어 privileged 컨테이너의 root 사용자는 런타임 seccomp 구성과 다른 제한을 우회해 노드에서 CAP_SYS_ADMIN 과 CAP_NET_ADMIN capabilities를 사용할 수 있을지도 몰라요.
대부분의 경우 privileged 컨테이너 사용을 피하고, 대신 securityContext 필드의 capabilities 필드로 컨테이너가 필요로 하는 특정 capabilities를 부여해야 해요. securityContext로 부여할 수 없는 capability가 있을 때만 privileged 모드를 사용해요. 이는 네트워크 스택을 조작하거나 하드웨어 장치에 접근하는 것 같은 운영 체제 관리 기능을 사용하려는 컨테이너에 유용해요.
쿠버네티스 1.26 이상에서는 Pod 스펙의 보안 컨텍스트에 windowsOptions.hostProcess 플래그를 설정해 Windows 컨테이너도 비슷한 privileged 모드로 실행할 수 있어요. 자세한 내용과 지침은 Windows HostProcess Pod 만들기를 참고해요.
권장 사항과 모범 사례
- 커널 수준 보안 기능을 구성하기 전에 네트워크 수준 격리 구현을 고려해야 해요. 자세한 내용은 보안 체크리스트를 읽어요.
- 필요하지 않다면 Pod 매니페스트에서 특정 사용자·그룹 ID를 설정하고
runAsNonRoot: true를 지정해 Linux 워크로드를 non-root로 실행해요.
추가로 Pod 매니페스트에서 hostUsers: false 를 설정해 워크로드를 사용자 네임스페이스에서 실행할 수 있어요. 이렇게 하면 사용자 네임스페이스에서 컨테이너를 root 사용자로 실행하지만, 노드의 호스트 네임스페이스에서는 non-root 사용자로 실행할 수 있어요. 이것은 아직 개발 초기 단계이며 필요할 수준의 지원이 없을 수 있어요. 지침은 Pod와 함께 사용자 네임스페이스 사용하기를 참고해요.