Overview
CloudNET@ KANS3기 스터디에서 실습한 자료를 공유합니다.
컨테이너의 세부 원리를 이해하고, 도커 없이 컨테이너를 구성하겠습니다.
또한, KISA 도커 보안 취약점을 확인하겠습니다.
컨테이너
컨테이너는 애플리케이션과 실행에 필요한 모든 파일, 라이브러리, 의존성 등을 하나의 패키지로 묶어서 독립적으로 실행할 수 있는 가상화된 환경입니다. 가상 머신(VM)과 비교하였을 때 컨테이너 환경은 호스트 운영체제의 커널을 공유하므로 실행에 필요한 리소스가 적고, 가볍습니다. 또한 CPU, 메모리, 디스크 등의 자원을 보다 효율적으로 사용할 수 있습니다.
컨테이너 환경은 호스트 운영체제의 커널을 공유하나, 프로세스는 격리합니다.
프로세스 격리는 리눅스의 독립된 환경(pivot-root, namespace, Overlay filesystem, cgroup)을 통해 보장받습니다.
pivot-root
|
리눅스 커널에서 루트 파일 시스템을 전환합니다. 컨테이너 내에서 고유한 파일 시스템을 루트 파일 시스템으로 할당하여 호스트 파일시스템과 격리된 환경을 가질 수 있게 합니다.
|
namespace
|
프로세스가 시스템의 특정 리소스(프로세스 ID, 파일시스템, 네트워크, 사용자, IPC, UTS)들을 서로 독립적으로 사용할 수 있도록 격리하는 기술입니다. 네임스페이스를 통해 프로세스 간의 자원 충돌을 방지하며, 컨테이너가 독립된 환경을 가질 수 있도록 격리합니다.
|
Overlay filesystem
|
리눅스에서 다중 계층 파일 시스템을 지원하는 파일 시스템입니다. 컨테이너에서는 여러 파일 시스템 레이어를 하나로 합쳐 이미지로 관리합니다.
|
cgroup
|
리소스의 사용량을 제어하고, 모니터링하고, 제한할 수 있도록 합니다. 컨테이너에서는 컨테이너의 리소스 사용을 제한하는데 사용합니다. 이를 통해 프로세스 간의 자원 경쟁을 최소화하고 서비스의 안정성을 보장합니다.
|
위 기술들을 서버에서 확인하겠습니다.
프로세스 확인
ubuntu 서버 22.04
격리 환경 구성 전 프로세스 정보를 확인하겠습니다.
lsb_release -a
ps auf
- VSZ는 가상 메모리 사용량, RSS는 실제 메모리 사용량을 나타냅니다.
- TTY: 프로세스가 연결된 터미널입니다. 예를 들어, pts/0는 가상 터미널이고 tty1, ttyS0는 물리적 터미널입니다.
- STAT: 프로세스 상태를 나타냅니다. Ss는 대기 중(Sleeping)의 상태이고, 세션 리더(Session leader)임을 나타냅니다. R+는 실행 중(Running) 상태입니다.
pstree -p
- 부모 - 자식 프로세스 PID가 독립적인 것을 확인할 수 있습니다.
리눅스 /proc 디렉토리는 커널이 동적으로 생성하는 정보(시스템 상태, 프로세스, HW)를 실시간으로 제공합니다.
- 넘버 디렉토리는 위 프로세스의 PID입니다.
- loadavg: 부하 상태 확인(1분, 5분, 15분간의 부하 평균, 현재 실행 중인 프로세스와 총 프로세스, 마지막 숫자는 마지막에 실행된 프로세스 PID
- uptime : 구동 시간 확인(가동 시간, 유휴시 간)
ls /proc > 1.txt
# 터미널 1
sleep 10000
# 터미널 2
ls /proc > 2.txt
diff 1.txt 2.txt
ps -C sleep
pgrep sleep
tree /proc/$(pgrep sleep) -L 1
도커 구성
도커는 컨테이너 관리 가상화 플랫폼입니다. Client-Host 구조로 Host에서 이미지를 통해 컨테이너를 실행하게 됩니다.
도커 내 Clinet 와 Docker Host 는 Unix Socket 을 통해 통신합니다.
도커 설치 후 소켓과 기본 정보를 확인하겠습니다.
# 도커 설치
curl -fsSL https://get.docker.com | sh
# 도커 서비스 상태 확인
systemctl status docker -l --no-pager
ss -xl | grep -i docker
lsof /run/docker.sock
여기서 non-root user로 해당 소켓을 통해 접근시 권한 에러가 떨어집니다.
위 소켓 파일(/run/docker.sock) 사용 그룹인 도커 그룹에 ubuntu 유저를 추가하여 접근이 가능한 지 확인합시다.
# 사용자 그룹 확인
ls -l /run/dockek.sock
# ubuntu 계정 추가
sudo usermod -aG docker ubuntu
Jenkins 와 같이 컨테이너 안에서 다시 컨테이너를 빌드해야 한다면, jenkins에서 Host docker socket file 공유로 도커를 실행해야 합니다.
# Jenkins 컨테이너 실행
docker run -d -p 8080:8080 -p 50000:50000 --name jenkins-server --restart=on-failure -v jenkins_home:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker jenkins/jenkins
- -v /var/run/docker.sock:/var/run/docker.sock : socket 공유
- -v /usr/bin/docker:/usr/bin/docker jenkins/jenkins : 유저 명령어 공유
젠킨스 내부에서 도커 실행시 root 유저로 설정해야 합니다.
docker exec -it jenkins-server docker ps
docker exec -it --user 0 jenkins-server docker ps
- Host에서 jenkins 프로세스를 확인할 수 있습니다.
Host로 돌아와 도커 설치 기본정보를 확인합시다.
docer0 이라는 네트워크 인터페이스와 iptables 정책이 여러 추가되었습니다.
ip -br -c addr # 네트워크 인터페이스 IP 주소 확인
ip -br -c link # 네트워크 인터페이스 상태 확인
ip -br -c route # 네트워크 인터페이스 라우터 확인
brctl show # 브릿지 인터페이스 확인
iptables -t filter -S
iptables -t nat -S
- 컨테이너 간 통신 및 외부와의 트래픽에 대한 허용 규칙이 적용되어 있으며, docker0을 통해 나가는 연결된 상태의 트래픽은 허용됩니다. 또한 컨테이너 간 통신도 허용하지만, 네트워크 격리 규칙(ISOLATION)에 따라 일부 트래픽은 차단합니다.
- 도커가 MASQUERADE 규칙을 통해 컨테이너가 외부 네트워크와 통신할 때 컨테이너의 사설 IP를 호스트 IP로 변환하는 역할을 합니다.
컨테이너 격리
그렇다면 도커 없이 컨테이너를 구성하여 프로세스 격리가 어떻게 되는 지 확인하겠습니다.
프로세스 격리에 활용되는 기술은 다음의 표입니다.
pivot-root
|
리눅스 커널에서 루트 파일 시스템을 전환합니다. 컨테이너 내에서 고유한 파일 시스템을 루트 파일 시스템으로 할당하여 호스트 파일시스템과 격리된 환경을 가질 수 있게 합니다.
|
namespace
|
프로세스가 시스템의 특정 리소스(프로세스 ID, 파일시스템, 네트워크, 사용자, IPC, UTS)들을 서로 독립적으로 사용할 수 있도록 격리하는 기술입니다. 네임스페이스를 통해 프로세스 간의 자원 충돌을 방지하며, 컨테이너가 독립된 환경을 가질 수 있도록 격리합니다.
|
Overlay filesystem
|
리눅스에서 다중 계층 파일 시스템을 지원하는 파일 시스템입니다. 컨테이너에서는 여러 파일 시스템 레이어를 하나로 합쳐 이미지로 관리합니다.
|
cgroup
|
리소스의 사용량을 제어하고, 모니터링하고, 제한할 수 있도록 합니다. 컨테이너에서는 컨테이너의 리소스 사용을 제한하는데 사용합니다. 이를 통해 프로세스 간의 자원 경쟁을 최소화하고 서비스의 안정성을 보장합니다.
|
pivot-root + Mount 네임스페이스
pivot-root와 mount 네임스페이스를 사용하여 호스트에 영향없이 파일시스템을 격리시킬 수 있습니다.
pivot-root를 사용하면 이전 루트 파일 시스템이 남지 않기에 탈옥이 불가능해집니다.
터미널 두개로 파일시스템을 격리하겠습니다.
unshare --mount /bin/sh
mkdir new_root
mount -t tmpfs none new_root
- 처음 mount unshare 시 부모 프로세스의 마운트 정보를 복사해서 자식 네임스페이스로 복사하기때문에 같아보임
다만, 루트 디렉토리는 동일한 것으로 확인됩니다.
여기서 루트 디렉토리 변경을 위해 pivot_root 를 사용하겠습니다.
#격리 프로세스 내 명령어 사용을 위한 복사
mkdir bin
cp /bin/ls bin/
mkdir -p usr/bin
cp /usr/bin/vi usr/bin
## pivot_root 실행
cd new_root # pivot_root 는 실행 시, 변경될 root 파일시스템 경로로 진입
pivot_root . put_old # [신규 루트] [기존 루트]
- pivot_root로 루트 디렉토리를 put_old로 변경시 명령어 실행이 사라져 호출이 안되는 것을 확인할 수 있습니다.
네임스페이스
네임스페이스는 리눅스가 제공하는 커널 기능으로 프로세스에 격리된 환경을 제공합니다.
모든 프로세스는 타입별로 네임스페이스에 속하며, 자식 프로세스는 부모의 네임스페이스를 상속합니다.
ls -l /proc/$$/ns
lsns -p $$
네임스페이스 종류
|
설명
|
컨테이너 격리 사용
|
Cgroup
|
프로세스 그룹에 대한 리소스(예: CPU, 메모리) 할당과 제한을 관리
|
컨테이너에서 리소스 사용을 제한하고 관리하기 위해 사용
|
IPC
|
프로세스 간 통신(예: 메시지 큐, 세마포어, 공유 메모리)을 격리
|
컨테이너 간의 IPC 리소스 격리
|
Mount
|
파일 시스템 마운트 포인트를 격리하여 독립적인 파일 시스템 뷰 제공
|
컨테이너의 파일 시스템 격리 및 독립적인 파일 시스템 구축
|
Network
|
네트워크 인터페이스, 라우팅 테이블 등을 격리하여 독립적인 네트워크 스택 제공
|
컨테이너 간 네트워크 격리 및 가상 네트워크 구성
|
PID
|
프로세스 ID를 격리하여 독립적인 프로세스 번호 공간 제공
|
컨테이너 내부에서 프로세스 ID 격리 및 고립된 실행 환경 제공
|
Time
|
시스템 시간과 시계(Clock) 설정을 격리하여 독립적인 시간 공간 제공
|
컨테이너나 가상 머신에서 시간대 또는 시스템 시간을 독립적으로 설정
|
User
|
사용자 및 그룹 ID를 격리하여 독립적인 사용자 공간 제공
|
비루트 사용자에게 루트 권한을 부여하면서도 격리된 환경 제공
|
UTS
|
호스트 이름과 도메인 이름을 격리하여 독립적으로 설정 가능
|
컨테이너에서 호스트 이름을 독립적으로 설정하여 식별 가능하게 함
|
네임스페이스 별 격리는 unshare 를 통해 할 수 있습니다.
unshare -h
Usage:
unshare [options] [<program> [<argument>...]]
Run a program with some namespaces unshared from the parent.
Options:
-m, --mount[=<file>] unshare mounts namespace
-u, --uts[=<file>] unshare UTS namespace (hostname etc)
-i, --ipc[=<file>] unshare System V IPC namespace
-n, --net[=<file>] unshare network namespace
-p, --pid[=<file>] unshare pid namespace
-U, --user[=<file>] unshare user namespace
-C, --cgroup[=<file>] unshare cgroup namespace
-T, --time[=<file>] unshare time namespace
#터미널 1 실행 후 비교
unshare -m
lsns -p $$
unshare -fp --mount-proc /bin/sh
- pid 네임스페이스 격리시 자식 Pid 네임스페이스의 pid 1로 실행됩니다. pid 1은 init 프로세스(커널이 생성), 시그널 처리, 좀비, 고아 프로세스 처리로 죽으면 시스템 패닉이 발생합니다.
컨테이너는 이런 타입별 네임스페이스 분리를 통해 프로세스를 격리함을 알 수 있습니다.
컨테이너 네트워크
컨테이너는 네트워크 네임스페이스로 네트워크 격리 환경이 구성됩니다. 그렇다면 컨테이너가 어떻게 네트워크 격리 환경 구성하는 지 직접 구성하여 확인해보겠습니다.
RED < - > BlUE 격리 네트워크 네임스페이스간 통신 환경 구성
- 네트워크(가상 이더넷) 네임스페이스 생성
- 네임스페이스 생성
- 네트워크 인터페이스를 생성 네임스페이스로 배치
- 네트워크 인터페이스 활성화 & IP 할당
- 네트워크 네임스페이스 별 통신 확인
# 1. 가상의 이더넷 네임스페이스 생성
ip link add veth0 type veth peer name veth1
- 이더넷 네임스페이스는 veth0, veth1 이며 @ 표시는 peer 관계를 의미함 이더넷 네임스페이스는 DOWN 상태임
# 2. 네트워크 인터페이스 생성
ip netns add RED
ip netns add BLUE
# 3. 네임스페이스 배치
ip link set veth0 netns RED
ip link set veth1 netns BLUE
- 네트워크 인터페이스 변경 확인
# 4. 가상 네트워크 인터페이스 활성화
ip netns exec RED ip link set veth0 up
ip netns exec BLUE ip link set veth1 up
# ip 할당
ip netns exec RED ip addr add 11.11.11.2/24 dev veth0
ip netns exec BLUE ip addr add 11.11.11.3/24 dev veth1
# 5. 통신 확인
ip -c route
nsenter --net=/var/run/netns/BLUE
tcpdump -i veth1
ping 11.11.11.3 -c 1
RED ↔ Brdige ↔ Blue 간 통신 환경 구성
네트워크 인터페이스별 경유를 위해 브릿지를 생성하여 통신을 확인하겠습니다.
- 네트워크 네임스페이스 생성
- 브릿지 생성
- 네트워크 네임스페이스 브릿지 연결
- 네트워크 네임스페이스 활성화, IP 설정 및 브릿지 활성화
- 통신 확인
# 1. 브릿지 생성 및 네트워크 네임스페이스 할당
ip link add reth0 type veth peer name reth1
ip link set reth0 netns RED
ip link add beth0 type veth peer name beth1
ip link set beth0 netns BLUE
# 2. 브릿지 생성
ip link add br0 type bridge
# 3. 네트워크 네임스페이스를 브릿지에 연결
ip link set reth1 master br0
ip link set beth1 master br0
# 4. 활성화
ip netns exec RED ip addr add 11.11.11.2/24 dev reth0
ip netns exec BLUE ip addr add 11.11.11.3/24 dev beth0
ip netns exec RED ip link set reth0 up; ip link set reth1 up
ip netns exec BLUE ip link set beth0 up; ip link set beth1 up
ip link set br0 up
# 5. 통신 확인
# 터미널 1 (RED)
ping -c 1 11.11.11.2
# 터미널 2 (호스트)
tcpdump -l -i br0
# 터미널 3 (BLUE)
tcpdump -l -i beth0
패킷 로스가 발생합니다. 이는 Iptables 에서 FORWARD가 DROR 로 설정되어 있기 때문입니다.
Netfilter는 리눅스 커널에서 패킷 필터링을 처리하는 프레임워크이고, iptables는 이 Netfilter에 규칙을 설정하고 관리하는 사용자 공간의 도구입니다. Netfilter hook 처리 과정은 5개로 나뉘며 목적지에 따라 구분됩니다.
- 목적지가 호스트의 애플리케이션인 경우 PREROUTING > INPUT > OUTPUT > POSTROUNTING
- 목적지가 호스트가 아닌 경우 PREROURING > FORWARD > POSTROUNTING
브릿지 통신의 경우 목적지가 달라 FORWARD하는 과정에서 Iptables이 DROP 설정으로 통신이 안된 것입니다.
통신을 위해 Iptabels에 설정을 추가하겠습니다.
# iptables 설정 추가 -t(table), -I(insert chain), -j(jump to - ACCEPT 허용)
iptables -t filter -I DOCKER-USER -j ACCEPT
RED/BLUE → 호스트 & 외부(인터넷) 통신 환경 구성
위 실습에서 구성 환경에서 외부 인터넷 통신을 위해서는 추가 네트워크 설정이 필요합니다.
- 호스트에서 네임스페이스(RED, BLUE)로 통신 가능 여부
- 네임스페이스에서 외부 통신 가능 여부
호스트에서 네임스페이스(RED, BLUE)로 통신
브릿지 네트워크 네임스페이스를 확인하면 IP할당이 안되어 있습니다.
br0(브릿지)에 IP 를 추가하여 통신 여부를 확인하겠습니다.
ip addr add 11.11.11.1/24 dev br0
네임스페이스에서 외부 인터넷 통신 여부
네트워크 네임스페이스에서 외부로 통신이 가능하도록 설정하겠습니다.
네임스페이스에 외부 통신을 위한 라우팅 설정과 IP 변환(POSTROUTE, SNAT) 설정이 필요합니다.
# 호스트
iptables -t nat -A POSTROUTING -s 11.11.11.0/24 -j MASQUERADE
# 네트워크 네임스페이스(RED)
ip route add default via 11.11.11.1
여기까지 도커에서 기본적으로 제공하는 네트워크 환경을 구성하였습니다.
구성 과정이 정말 복잡하며 격리시마다 수동으로 설정이 필요합니다.
도커는 위 컨테이너의 네트워크 환경을 자동으로 설정하고 관리해줍니다.
KISA 도커 보안 취약점 조치
위에서 컨테이너 원리와 도커 통신 방식를 이해했습니다.
이를 기반으로 KISA(한국인터넷진흥원) 도커 보안 취약점을 확인하겠습니다.
도커 취약점 진단 항목
|
이유
|
도커 최신 보안 패치 적용
|
최신 보안 패치를 적용하여 알려진 취약점을 방지하고 보안을 강화합니다.
|
도커 그룹에 불필요한 사용자 제거
|
도커 그룹에 속한 사용자는 루트 권한에 준하는 권한을 가질 수 있으므로, 불필요한 사용자 제거가 필요합니다.
|
Docker daemon audit 설정
|
도커 데몬에 대한 감사 로그를 활성화하여 비정상적인 활동을 모니터링하고 감시할 수 있습니다.
|
/var/lib/docker, /etc/docker, docker.service, docker.socket, /etc/default/docker에 대한 감사 설정
|
중요한 도커 관련 파일과 서비스에 대한 접근을 모니터링하여 보안 사고를 예방합니다.
|
기본 브리지 네트워크 제한 (--icc=false)
|
컨테이너 간의 네트워크 통신을 제한하여 불필요한 네트워크 공격 벡터를 줄입니다.
|
도커 클라이언트 인증 활성화
|
도커 클라이언트와 데몬 간의 통신을 보호하여 인증되지 않은 접근을 방지합니다.
|
Legacy registry (v1) 비활성화
|
보안이 강화된 새로운 버전을 사용하여 레거시 레지스트리의 보안 취약점을 제거합니다.
|
추가 권한 획득 제한 (no-new-privileges)
|
컨테이너 내에서 추가 권한을 획득할 수 없도록 하여 권한 상승 공격을 방지합니다.
|
docker.service, docker.socket, /etc/docker, /var/run/docker.sock, daemon.json, /etc/default/docker 파일의 소유권 및 접근 권한 설정
|
중요한 도커 설정 파일에 대한 접근을 제한하여 권한 없는 사용자가 파일을 수정하거나 열람할 수 없도록 합니다.
|
루트가 아닌 사용자로 컨테이너 실행
|
루트 사용자로 실행하는 것은 보안 위험을 증가시키므로, 비루트 사용자로 실행하여 위험을 줄입니다.
|
도커 콘텐츠 신뢰성 활성화 (DOCKER_CONTENT_TRUST)
|
이미지의 무결성과 신뢰성을 보장하여, 신뢰할 수 없는 이미지가 실행되지 않도록 합니다.
|
컨테이너 SELinux 보안 옵션 설정
|
SELinux를 사용하여 컨테이너 내에서의 보안 정책을 강화하고, 프로세스 간의 격리를 개선합니다.
|
컨테이너에서 SSH 사용 금지
|
SSH 서버는 불필요한 공격 벡터가 될 수 있으므로 컨테이너 내에서 사용하지 않도록 합니다.
|
Privileged 포트 매핑 금지
|
보안이 중요한 포트를 임의로 매핑하는 것을 제한하여, 컨테이너가 호스트 시스템을 공격할 수 없도록 합니다.
|
PIDs cgroup 제한 설정
|
컨테이너 내에서 생성할 수 있는 프로세스 수를 제한하여 DoS 공격을 방지합니다.
|
도커 기본 브리지 사용 제한 (docker0)
|
기본 브리지는 보안 설정이 부족할 수 있으므로, 보안이 강화된 네트워크 설정을 사용합니다.
|
호스트의 user namespaces 공유 제한
|
컨테이너와 호스트 간의 사용자 네임스페이스를 분리하여 권한 상승 공격을 방지합니다.
|
위 항목에서 이번 스터디에서 학습한 내용이 많습니다. 그 중 일부를 확인하겠습니다.
default bridge를 통한 컨테이너간 네트워크 트래픽 제한
위 컨테이너 RED ↔ Brdige ↔ Blue 간 통신 환경 구성에서 브릿지를 통해 컨테이너간 통신이 가능한 것을 확인하였습니다. docker0도 브릿지로 docker0를 통해 컨테이너간 통신이 가능하며 docker0에 IP가 할당된 경우 호스트에서도 통신이 가능합니다. 도커 옵션을 통해 컨테이너간 통신을 할 수 없도록 합시다.
# 도커 중지
systemctl stop docker.service
systemctl stop docker.socket
vi /lib/systemd/system/docker.service
----
# 아래 내용 추가
EnviromnetFile=/etc/default/docker
ExecStart=/usr/bin/dockerd --icc=false
# 도커 재시작
sudo systemctl daemon-reload
sudo systemctl restart docker
# 도커
docker network ls --quiet | xargs docker network inspect --format '{{
.Name}}: {{ .Options }}'
- 네트워크 네임스페이스는 그대로이나 도커 내 옵션을 통해 확인이 가능함
docker.socket 소유권 & 파일 접근 권한 설정
docker API를 통해 컨테이너 접근이 가능하기 때문에 접근 권한이 root 인지 확인이 필요합니다.
기본 ubuntu에서 도커 설치시 root로 확인되긴 합니다.
ls -ld /etc/docker
ls -l /lib/systemd/system/docker.socket
Host의 user namespaces 공유 제한
네임스페이스를 분리하여 호스트와 컨테이너간 프로세스 격리를 했으나, use namespace를 컨테이이너와 공유하게 되면 컨테이너 ↔ 호스트간 접근이 가능해져 조치가 필요합니다.
docker ps --quiet --all | xargs docker inspect --format '{{ .Id }}
:UsernsMode={{ .HostConfig.UsernsMode }}'
도커에서 명령어 실행시 호스트를 공유하는 네임스페이스가 있는 지 확인하고 다음과 같이 조치해주세요.
docker run --rm -it --userns=host ubuntu bash (취약)
docker run --rm -it ubuntu bash (양호)
항목 검사 스크립트 구성
위 항목별 검사 명령어를 종합하여 검사 스크립트 구성하고 기본 Ubuntu 22.04 환경에서 점검하겠습니다.
Ubuntu 22.04 기준
#!/bin/bash
echo "=== Docker Security Check Script ==="
# 1. 도커 최신 보안 패치 확인
echo "[1] Checking Docker version..."
docker_version=$(docker version --format '{{.Server.Version}}')
echo "Docker version: $docker_version"
echo "Ensure that Docker is up-to-date."
# 2. 도커 그룹 사용자 확인
echo "[2] Checking Docker group users..."
docker_users=$(getent group docker | cut -d: -f4)
echo "Docker group members: $docker_users"
if [ -z "$docker_users" ]; then
echo "No users found in the Docker group."
else
echo "Docker group members: $docker_users"
fi
# 3. 도커 데몬 감사 설정 확인
echo "[3] Checking audit settings for Docker daemon..."
auditctl -l | grep -E '/usr/bin/docker|/var/lib/docker|/etc/docker|docker.service|docker.socket|/etc/default/docker'
if [ $? -ne 0 ]; then
echo "Audit rules for Docker daemon are not set up."
else
echo "Audit rules for Docker daemon are in place."
fi
# 4. 도커 기본 브리지 네트워크 제한 확인 (--icc=false)
echo "[4] Checking Docker network settings..."
docker_network_icc=$(ps -ef | grep dockerd | grep -o '\--icc=[^ ]*')
if [ -z "$docker_network_icc" ]; then
echo "Docker network ICC setting is not explicitly set. Consider setting '--icc=false' for better security."
else
echo "Docker network ICC setting: $docker_network_icc"
fi
# 5. 도커 클라이언트 인증 활성화 확인
echo "[5] Checking Docker client authentication..."
tls_verify=$(ps -ef | grep dockerd | grep -o '\--tlsverify')
if [ -z "$tls_verify" ]; then
echo "Docker client authentication (TLS) is not enabled."
else
echo "Docker client authentication (TLS) is enabled."
fi
# 6. Legacy registry (v1) 비활성화 확인
echo "[6] Checking Legacy registry settings..."
disable_legacy_registry=$(ps -ef | grep dockerd | grep -o '\--disable-legacy-registry=[^ ]*')
if [ -z "$disable_legacy_registry" ]; then
echo "Legacy registry (v1) is not explicitly disabled. Consider disabling it for better security."
else
echo "Legacy registry setting: $disable_legacy_registry"
fi
# 7. 컨테이너 루트 사용 제한 확인
echo "[7] Checking if containers are running as non-root..."
docker ps --quiet --all | xargs -I {} docker inspect --format '{{ .Id }}: User={{.Config.User }}' {} | grep -v 'User='
if [ $? -eq 0 ]; then
echo "Some containers are running as root. Consider running containers as non-root for better security."
else
echo "All running containers are configured to run as non-root."
fi
# 8. 도커 콘텐츠 신뢰성 활성화 확인
echo "[8] Checking Docker Content Trust setting..."
if [ -z "$DOCKER_CONTENT_TRUST" ]; then
echo "Docker Content Trust is not enabled. Consider enabling it by setting DOCKER_CONTENT_TRUST=1."
else
echo "Docker Content Trust is enabled."
fi
# 9. SELinux 보안 옵션 설정 확인
echo "[9] Checking SELinux settings for containers..."
selinux_enabled=$(ps -ef | grep dockerd | grep -o '\--selinux-enabled')
if [ -z "$selinux_enabled" ]; then
echo "SELinux is not enabled for Docker. Consider enabling it for better security."
else
echo "SELinux is enabled for Docker."
fi
# 10. 컨테이너에서 SSH 사용 금지 확인
echo "[10] Checking if SSH is disabled in containers..."
docker ps --quiet | xargs -I {} docker exec {} ps -e | grep sshd
if [ $? -eq 0 ]; then
echo "SSH service is running in some containers. Consider disabling SSH in containers."
else
echo "No SSH services are running in any containers."
fi
# 11. Privileged 포트 매핑 금지 확인
echo "[11] Checking for privileged port mappings..."
docker ps --quiet --all | xargs -I {} docker inspect --format '{{ .Id }}:Ports={{.NetworkSettings.Ports}}' {} | grep -E ':[0-9]{1,3}->'
if [ $? -eq 0 ]; then
echo "Some containers are using privileged port mappings. Consider avoiding the use of privileged ports (below 1024)."
else
echo "No containers are using privileged port mappings."
fi
# 12. PIDs cgroup 제한 설정 확인
echo "[12] Checking PIDs cgroup limits..."
docker ps --quiet --all | xargs -I {} docker inspect --format '{{ .Id }}: PidsLimit={{ .HostConfig.PidsLimit }}' {} | grep -E 'PidsLimit=0'
if [ $? -eq 0 ]; then
echo "Some containers do not have a PIDs limit set. Consider setting a PIDs limit for better security."
else
echo "All containers have appropriate PIDs limits set."
fi
# 13. 기본 브리지 docker0 사용 제한 확인
echo "[13] Checking default bridge (docker0) usage..."
ifconfig docker0 &> /dev/null
if [ $? -eq 0 ]; then
echo "The default bridge (docker0) is in use. Consider using custom bridge networks for better security."
else
echo "The default bridge (docker0) is not in use."
fi
# 14. 호스트의 user namespaces 공유 제한 확인
echo "[14] Checking user namespaces sharing..."
docker ps --quiet --all | xargs -I {} docker inspect --format '{{ .Id }}: UsernsMode={{ .HostConfig.UsernsMode }}' {} | grep -v 'UsernsMode='
if [ $? -eq 0 ]; then
echo "Some containers are not using user namespaces. Consider enabling user namespaces for better security."
else
echo "All containers are using user namespaces."
fi
echo "=== Docker Security Check Completed ==="
점검 결과 데몬 감사 설정, Docker 네트워크 설정(ICC), 클라이언트 인증, 레지스트리 비활성화, Content Trust 설정, Selinux 설정, 기본 브리지(docker 0) 사용 검토한 것으로 확인됩니다.
'Cloud Tech' 카테고리의 다른 글
Calico CNI 이해 (0) | 2024.09.20 |
---|---|
쿠버네티스 네트워크이해하기(Kind, Pause, Ephemeral Container, FlannelCNI) (0) | 2024.09.06 |
OpenTofu 와 Atlantis 연동하기 (0) | 2024.08.03 |
Kafka on EKS (0) | 2024.07.27 |
EKS에서 Atlantis 구성하기 (0) | 2024.07.14 |