Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
harden-docker-seccomp — Docker 완화 도구 for CVE-2026-31431('Copy Fail'). Kubernetes 템플릿도 포함되어 있습니다. | Kitploit
도구/GitHubGitHub/devstuff/harden-docker-seccomp
Cloud Infrastructure SecurityDefensive ToolsContainer SecurityVulnerability AnalysisConfiguration AuditingDevSecOps
GitHubdevstuff/harden-docker-seccomp

harden-docker-seccomp

Docker 완화 도구 for CVE-2026-31431('Copy Fail'). Kubernetes 템플릿도 포함되어 있습니다.

저장소 보기
213개월 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

harden-docker-seccomp

호스트의 모든 Docker 컨테이너에서 AF_ALG 소켓 생성을 차단하는 멱등 스크립트로, CVE-2026-31431("Copy Fail")에 대한 완화 조치입니다.

배경

CVE-2026-31431은 Linux 커널의 authencesn 암호화 템플릿에서 발생하는 로컬 권한 상승 취약점으로, 2017년부터 업스트림 수정(mainline 커밋 a664bf3d603d)이 적용되기 전까지 빌드된 커널에 존재합니다. 권한이 없는 사용자는 AF_ALG 소켓 연산을 splice()와 연결하여 읽기 가능한 모든 파일의 페이지 캐시에 통제된 4바이트 쓰기를 수행할 수 있으며, setuid 바이너리를 대상으로 하여 루트 셸을 획득할 수 있습니다. 732바이트 크기의 Python 개념 증명 코드는 레이스 조건이나 배포판별 오프셋 없이, 영향을 받는 커널을 탑재한 모든 주요 Linux 배포판에서 안정적으로 이 취약점을 악용합니다.

이 취약점의 필수 첫 단계는 AF_ALG 소켓(socket(AF_ALG, SOCK_SEQPACKET, 0))을 여는 것입니다. seccomp를 통해 해당 syscall을 차단하면 패치되지 않은 커널에서도 악용을 방지할 수 있습니다. Docker의 기본 제공 seccomp 프로필은 AF_ALG를 차단하지 않으며, RuntimeDefault만으로는 충분하지 않습니다. 테스트한 클러스터에서 PSS Restricted 하에 허용된 파드도 여전히 AF_ALG 소켓을 열 수 있음을 확인했습니다.

전체 기술적 세부 사항과 배포판별 패치 제공 여부는 원본 연구원 권고문 https://copy.fail 및 CERT-EU 권고문 https://cert.europa.eu/publications/security-advisories/2026-005/을 참조하세요.

이 도구의 범위

이 스크립트는 Docker Engine 전역 데몬 구성을 다룹니다. Kubernetes의 경우 아래 Kubernetes 섹션을 참조하세요. 베어메탈 또는 VM 워크로드(비컨테이너화)의 경우 대신 algif_aead 커널 모듈을 비활성화하세요:

root@kitploit:~
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
rmmod algif_aead 2>/dev/null || true

이 방법은 dm-crypt/LUKS, kTLS, IPsec/XFRM, OpenSSL, GnuTLS, NSS 또는 SSH에 영향을 미치지 않습니다.

작동 방식

  1. Docker의 활성 기본 제공 seccomp 프로필 추출 — 수명이 짧은 컨테이너의 HostConfig.SecurityOpt를 검사하여 추출합니다. 이는 원격 URL에 대한 의존성을 피하고 기본 프로필이 실제 설치된 Docker 버전과 일치하도록 보장합니다. moby/profiles에서의 GitHub 가져오기는 컨테이너 검사 결과가 없을 때만 폴백으로 사용됩니다.

  2. 프로필 패치 — Docker의 허용 목록 항목에서 socket을 제거하고, SCMP_CMP_NE를 사용하여 AF_ALG(값 38)를 제외한 모든 주소 패밀리를 허용하는 인자 필터와 함께 다시 추가합니다. 다른 모든 Docker 기본 seccomp 동작은 유지됩니다.

  3. 패치된 프로필을 원자적으로 작성 — /etc/seccomp/docker-block-af-alg.json에 임시 파일 + 이름 변경 방식으로 작성합니다. 디스크의 내용이 이미 동일하면 건너뜁니다.

  4. /etc/docker/daemon.json 업데이트 — "seccomp-profile"을 패치된 프로필 경로로 설정합니다. 원본 파일은 첫 수정 시 daemon.json.bak으로 백업됩니다. 이미 올바르게 구성된 경우 건너뜁니다.

  5. dockerd 재로드 — 를 통해 수행합니다(SIGHUP — 재시작 불필요). 두 파일 모두 변경되지 않은 경우 건너뜁니다.

이 스크립트는 멱등적입니다: 여러 번 실행해도 동일한 결과를 생성하며 실제로 변경된 사항이 있을 때만 Docker를 재로드합니다.

참고: --privileged 컨테이너는 이 구성과 관계없이 모든 seccomp 프로필을 우회합니다. Compose 파일과 privileged 컨테이너의 실행 명령을 별도로 감사하세요.

요구 사항

  • Python 3.12+
  • 호스트에서 실행 중인 Docker Engine(Docker Desktop 아님)
  • PATH에 있는 docker CLI
  • PATH에 있는 curl(폴백 전용)
  • systemctl(systemd 호스트)
  • /etc/seccomp 및 /etc/docker 쓰기, systemctl reload docker 실행을 위한 루트/sudo 권한

사용법

root@kitploit:~
# 완화 조치 적용 및 검증(일반 사용)
sudo python3 harden-docker-seccomp.py

# 아무것도 쓰지 않고 Docker를 재로드하지 않고 변경 사항만 표시
sudo python3 harden-docker-seccomp.py --dry-run

# 컨테이너 검증만 재실행(구성 변경 없음)
python3 harden-docker-seccomp.py --verify-only

# 상세 출력
sudo python3 harden-docker-seccomp.py --verbose

예상 출력(첫 실행)

root@kitploit:~
INFO Written: /etc/seccomp/docker-block-af-alg.json
INFO Updated: /etc/docker/daemon.json
INFO Reloading Docker daemon (SIGHUP)…
INFO Docker daemon reloaded.
INFO Verifying AF_ALG is blocked inside a container…
OK: AF_ALG blocked — [Errno 1] Operation not permitted
INFO All done. CVE-2026-31431 (Copy Fail) mitigation is active.

예상 출력(이후 실행)

root@kitploit:~
INFO Profile unchanged: /etc/seccomp/docker-block-af-alg.json
INFO daemon.json already configured correctly.
INFO No changes — Docker daemon reload not required.
INFO Verifying AF_ALG is blocked inside a container…
OK: AF_ALG blocked — [Errno 1] Operation not permitted
INFO All done. CVE-2026-31431 (Copy Fail) mitigation is active.

종료 코드

코드의미
0성공 — 완화 조치 활성화됨
1스크립트가 루트로 실행되지 않음(패치 시), 또는 복구 불가능한 오류
2검증 실패 — AF_ALG가 차단되지 않음

Kubernetes

Kubernetes 파드는 호스트 커널을 공유하므로, 영향을 받는 노드의 모든 파드에서 동일한 AF_ALG 소켓 프리미티브에 접근할 수 있습니다. RuntimeDefault seccomp만으로는 충분하지 않습니다. 테스트한 클러스터에서 PSS Restricted 하에 허용된 파드도 여전히 AF_ALG 소켓을 열 수 있음을 확인했습니다. 명시적 거부 규칙이 있는 Localhost 프로필이 필요합니다.

완화 조치에는 두 가지가 필요합니다: 모든 노드의 파일 시스템에 프로필 JSON이 존재해야 하고, 모든 파드 스펙이 이를 참조해야 합니다. 아래 섹션에서는 개별 파드 스펙을 수정하지 않고 프로필을 전역적으로 주입하는 방법을 포함하여 두 가지를 모두 다룹니다.

1단계 — 프로필을 모든 노드에 배포

kubelet은 Localhost seccomp 프로필을 seccomp 루트(기본값 /var/lib/kubelet/seccomp)를 기준으로 해석합니다. 프로필은 워크로드를 스케줄링할 수 있는 모든 노드의 해당 경로에 존재해야 합니다.

이 저장소의 ConfigMap과 DaemonSet을 적용하세요:

root@kitploit:~
kubectl apply -f templates/configmap-seccomp-profile.yaml
kubectl apply -f templates/daemonset-distribute-profile.yaml

DaemonSet은 init 컨테이너를 실행하여 ConfigMap에서 프로필을 노드의 kubelet seccomp 루트로 복사한 다음, 최소한의 pause 컨테이너를 유지하여 상태 모니터링을 위해 파드가 계속 표시되도록 합니다. 모든 taint를 허용하므로 컨트롤 플레인 노드에서도 실행됩니다.

비표준 kubelet seccomp 루트: RKE2는 /var/lib/rancher/rke2/agent/kubelet/seccomp를 사용합니다. 적용 전에 DaemonSet의 init 컨테이너 env에서 NODE_SECCOMP_ROOT를 설정하여 경로를 재정의하세요.

노드에 파일이 존재하는지 확인:

root@kitploit:~
kubectl -n kube-system exec -it \
  $(kubectl -n kube-system get pod -l app.kubernetes.io/name=distribute-af-alg-seccomp \
    -o jsonpath='{.items[0].metadata.name}') -- \
  cat /var/lib/kubelet/seccomp/block-af-alg.json

2단계 — 모든 파드에 프로필 주입(파드 스펙 변경 불필요)

개별 파드 스펙이나 Helm 차트를 수정하는 대신, 변경 허용 웹훅(mutating admission webhook)을 사용하여 허용 시점에 seccompProfile을 자동으로 주입합니다. Kyverno와 OPA Gatekeeper 두 가지 옵션이 제공됩니다.

두 접근 방식 모두 파드가 이미 프로필을 선언하지 않은 경우에만 프로필을 주입하므로, 명시적 프로필이 있는 파드는 변경되지 않습니다.

중요: 기존 실행 중인 파드는 소급 변경되지 않습니다. 정책 적용 후 배포를 롤아웃하여 주입된 프로필을 적용하세요:

root@kitploit:~
kubectl rollout restart deployment -A

옵션 A — Kyverno

이 템플릿은 Kyverno 1.17에서 GA에 도달한 MutatingPolicy API(policies.kyverno.io/v1)를 사용합니다. 레거시 ClusterPolicy API(kyverno.io/v1)는 Kyverno 1.17(2026년 1월)에서 더 이상 사용되지 않으며 1.20(2026년 10월)에서 제거될 예정이므로 새 정책에는 사용하지 마세요.

matchConditions CEL 표현식은 변경 전에 seccompProfile이 없는지 확인하므로, 이미 프로필을 선언한 파드는 변경되지 않습니다.

root@kitploit:~
# Kyverno 설치(아직 없는 경우)
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm upgrade --install kyverno kyverno/kyverno -n kyverno --create-namespace

# 정책 적용
kubectl apply -f templates/kyverno-mutate-seccomp.yaml

새 파드가 주입된 프로필을 받는지 확인:

root@kitploit:~
kubectl run test --image=busybox --restart=Never -- sleep 30
kubectl get pod test -o jsonpath='{.spec.securityContext.seccompProfile}'
# 예상: {"localhostProfile":"block-af-alg.json","type":"Localhost"}
kubectl delete pod test

templates/kyverno-mutate-seccomp.yaml 참조.

옵션 B — OPA Gatekeeper

Gatekeeper의 Assign 변경 CRD는 pathTests 조건을 사용하여 spec.securityContext.seccompProfile이 아직 존재하지 않을 때만 프로필을 주입합니다. 변경 기능은 Gatekeeper 3.10+부터 안정적이며 기능 플래그가 필요하지 않습니다.

root@kitploit:~
# Gatekeeper 설치(아직 없는 경우)
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
helm install -n gatekeeper-system gatekeeper gatekeeper/gatekeeper \
  --create-namespace

# 변경 규칙 적용
kubectl apply -f templates/gatekeeper-assign-seccomp.yaml

확인:

root@kitploit:~
kubectl run test --image=busybox --restart=Never -- sleep 30
kubectl get pod test -o jsonpath='{.spec.securityContext.seccompProfile}'
# 예상: {"localhostProfile":"block-af-alg.json","type":"Localhost"}
kubectl delete pod test

templates/gatekeeper-assign-seccomp.yaml 참조.

Gatekeeper vs. Kyverno: Assign 접근 방식은 필드 수준에서 작동하며 Gatekeeper 변경 웹훅이 활성화되어 있어야 합니다. Kyverno의 MutatingPolicy는 CEL matchCondition으로 조건부를 인라인으로 처리합니다. 둘 다 동일한 결과를 얻습니다 — 클러스터에 이미 배포된 것을 선호하세요.

이 도구가 다루지 않는 것

hostPID: true, hostNetwork: true 또는 securityContext.privileged: true가 있는 파드는 seccomp만으로는 완전히 통제할 수 없는 높은 접근 권한을 가집니다. 해당 워크로드를 별도로 감사하고 가능한 경우 권한을 제거하세요.

템플릿 설계 참고 사항

ConfigMap을 단일 소스로 사용. 프로필 JSON은 DaemonSet에 포함하거나 여러 파일에 중복하지 않고 configmap-seccomp-profile.yaml에 있습니다. DaemonSet은 이를 마운트하여 노드에 복사합니다. 프로필을 업데이트하려면 하나의 ConfigMap을 편집하고 DaemonSet 파드를 재시작하면 됩니다 — 다른 파일은 변경되지 않습니다.

DaemonSet은 system-node-critical 우선순위 사용. 이는 보호 대상 워크로드가 스케줄링되기 전에 배포 파드가 축출되지 않도록 보장합니다. 그렇지 않으면 노드에 프로필 파일이 없어 파드가 CreateContainerError 상태로 멈출 수 있습니다.

Gatekeeper는 kube-system 및 gatekeeper-system을 제외. DaemonSet 설치 이전에 존재할 수 있는 시스템 파드에 Localhost 프로필을 주입하면 파일이 아직 노드에 없을 때 잘못된 프로필 참조가 발생할 위험이 있습니다. Kyverno 정책은 웹훅 순서를 더 우아하게 처리하므로 이 제외가 필요하지 않지만, 필요한 경우 exclude 규칙을 추가할 수 있습니다.

조건부 주입, 재정의 아님. Kyverno MutatingPolicy CEL matchCondition과 Gatekeeper MustNotExist 경로 테스트 모두 허용 정책이 기존 seccompProfile이 없는 파드에만 작동함을 의미합니다. 자체 프로필을 이미 선언한 워크로드 — 사용자 지정 허용 목록을 통해 AF_ALG를 정당하게 필요로 하는 워크로드 포함 — 는 변경되지 않습니다.

참조

  • https://copy.fail — 원본 연구원 권고문(Xint)
  • https://cert.europa.eu/publications/security-advisories/2026-005/ — CERT-EU 권고문
  • https://www.cve.org/CVERecord?id=CVE-2026-31431 — CVE 레코드
  • https://security-tracker.debian.org/tracker/CVE-2026-31431 — Debian 보안 추적기
  • https://docs.docker.com/engine/security/seccomp/ — Docker seccomp 문서
  • https://github.com/moby/profiles — 표준 Docker 기본 seccomp 프로필
  • https://kyverno.io/docs/kyverno-policies/ — Kyverno 정책 문서
  • https://open-policy-agent.github.io/gatekeeper/website/docs/mutation/ — Gatekeeper 변경 문서

네, Claude가 대부분의 작업을 수행했습니다. 여기 채팅이 있습니다

https://gist.github.com/devstuff/3ff3ca0139e2a2da7f1ee5875802f76f

도구 다운로드
systemctl reload docker
  • 차단 활성 여부 검증 — 위 단계에서 변경 사항이 있었는지와 관계없이 컨테이너 내부에서 프로브를 실행하여 확인합니다.