Docker 컨테이너의 프로세스가 루트로 실행되어서는 안 되는 이유

게시 됨: 2022-08-19

Docker 로고를 보여주는 그래픽

Docker 컨테이너의 프로세스는 루트로 실행하면 안 됩니다. Dockerfile의 일부로 지정하거나 docker run 을 사용할 때 루트가 아닌 사용자로 애플리케이션을 실행하는 것이 더 안전합니다. 이렇게 하면 컨테이너의 모든 위협에 대한 공격 표면이 줄어들어 위험이 최소화됩니다.

이 기사에서는 컨테이너화된 애플리케이션을 루트로 실행할 때의 위험성에 대해 알아봅니다. 또한 루트가 아닌 사용자를 만들고 이것이 불가능한 상황에서 네임스페이스를 설정하는 방법도 볼 수 있습니다.

루트로 실행하는 것이 위험한 이유는 무엇입니까?

컨테이너는 기본적으로 루트로 실행됩니다. Docker 데몬은 호스트에서 루트로 실행되며 실행 중인 컨테이너도 루트가 됩니다.

컨테이너 내부의 루트가 독립적인 사용자인 것처럼 보일 수 있지만 실제로는 호스트의 루트 계정과 동일합니다. 분리는 Docker의 컨테이너 격리 메커니즘에서만 제공됩니다. 강한 물리적 경계가 없습니다. 호스트 커널에서 루트 사용자가 실행하는 컨테이너의 다른 프로세스입니다. 즉, 애플리케이션, Docker 런타임 또는 Linux 커널의 취약점으로 인해 공격자가 컨테이너에서 벗어나 시스템에서 루트 권한 작업을 수행할 수 있습니다.

이러한 일이 발생할 위험을 줄이는 몇 가지 기본 제공 보호 기능이 있습니다. 컨테이너 내부의 루트는 권한이 없으며 기능이 제한됩니다. 이렇게 하면 컨테이너를 시작할 때 기능을 수동으로 추가하거나 권한 모드를 사용하지 않는 한 컨테이너에서 시스템 관리 명령을 사용할 수 없습니다.

이러한 완화에도 불구하고 응용 프로그램을 루트로 실행하는 것은 여전히 ​​위험합니다. 기존 환경에서 루트 사용을 제한하는 것처럼 컨테이너 내에서 불필요하게 루트를 사용하는 것은 현명하지 않습니다. 침해가 발생하는 경우 공격자에게 더 많은 발판을 제공하는 과도한 권한 환경을 제공하고 있습니다.

루트가 아닌 사용자로 컨테이너화된 애플리케이션 실행

컨테이너화된 애플리케이션은 일반 사용자로 실행하는 것이 가장 좋습니다. 대부분의 소프트웨어는 루트 액세스가 필요하지 않으므로 사용자를 변경하면 컨테이너 브레이크아웃에 대한 즉각적인 방어 계층이 제공됩니다.

Dockerfile의 마지막 단계 중 하나로 새 사용자 계정을 만들어야 합니다. USER 명령어로 이것을 달성할 수 있습니다:

 FROM 기본 이미지:최신
적절한 설치 데모 패키지 실행
USER 데모 사용자:데모 그룹
ENTRYPOINT ["데모 바이너리"]

이 이미지에서 시작된 컨테이너는 demo-user 로 실행됩니다. 사용자는 demo-group 그룹의 구성원이 됩니다. 사용자가 그룹에 속할 필요가 없으면 그룹 이름을 생략할 수 있습니다.

 USER 데모 사용자

이름 대신 사용자 ID(UID) 및 그룹 ID(GID)를 지정할 수 있습니다.

 사용자 950:950

알려진 UID 및 GID를 할당하는 것이 일반적으로 진행하는 가장 안전한 방법입니다. 컨테이너의 사용자가 과도한 권한을 가진 호스트 계정에 매핑되는 것을 방지합니다.

USER 는 종종 Dockerfile에서 두 번째 단계로 지정됩니다. 즉, 이미지 빌드 초기에 루트가 필요한 작업을 계속 실행할 수 있습니다. 위의 예에서 apt install 명령에는 루트가 합법적으로 필요합니다. USER 명령이 그 위에 있으면 apt 는 필요한 권한이 없는 demo-user 로 실행됩니다. Dockerfile 지침은 컨테이너를 실행하지 않고 이미지 빌드에만 적용되므로 Dockerfile에서 나중에 사용자를 변경하는 것이 안전합니다.

컨테이너가 실행되는 사용자를 변경하려면 컨테이너가 액세스하는 파일 및 폴더에 대한 권한을 업데이트해야 할 수 있습니다. 애플리케이션에서 사용할 모든 경로에 대한 소유권을 설정합니다.

 복사 초기 구성.yaml /data/config.yaml

USER 데모 사용자:데모 그룹
실행 chown 데모 사용자: 데모 그룹 / 데이터

이 예에서 /data 디렉토리는 demo-user 가 소유해야 애플리케이션이 구성 파일을 변경할 수 있습니다. 이전 COPY 문은 파일을 루트로 복사했습니다. copy 와 함께 --chown 플래그를 사용하여 속기를 사용할 수 있습니다.

 복사 --chown=demo-user:demo-group initial-config.yaml /data/config.yaml

컨테이너 시작 시 사용자 변경

자체 Dockerfile에서 사용자를 쉽게 변경할 수 있지만 많은 타사 응용 프로그램이 계속 루트로 실행됩니다. docker run 을 호출할 때마다 --user 플래그를 설정하여 이러한 사용과 관련된 위험을 줄일 수 있습니다. 이는 이미지의 Dockerfile에 설정된 사용자를 재정의합니다.

 $ docker run -d --user 데모 사용자: 데모 그룹 데모 이미지: 최신
$ docker run -d --user 데모 사용자 데모 이미지:최신
$ docker run -d --user 950:950 데모 이미지:최신

--user 플래그는 지정된 사용자로 컨테이너의 프로세스를 실행합니다. 모든 docker run 명령에 개별적으로 적용해야 하기 때문에 Dockerfile USER 명령보다 덜 안전합니다. 정기적으로 사용되는 이미지에 대한 더 나은 옵션은 새 사용자 계정을 설정할 수 있는 고유한 파생 이미지를 만드는 것입니다.

 루트로 실행되는 이미지에서:최신
USER 데모 사용자
 $ 도커 빌드 . -t image-that-now-runs-as-non-root:latest

타사 이미지의 사용자를 변경하면 문제가 발생할 수 있습니다. 컨테이너가 루트로 실행될 것으로 예상되거나 루트가 소유한 파일 시스템 경로에 액세스해야 하는 경우 애플리케이션을 사용할 때 오류가 표시됩니다. 문제를 일으키는 경로에 대한 권한을 수동으로 변경할 수 있습니다. 또는 공급업체에 권한이 없는 사용자 계정으로 응용 프로그램을 실행하는 데 지원되는 방법이 있는지 확인하십시오.

루트로 실행해야 하는 애플리케이션 처리

사용자 네임스페이스는 일부 루트 권한이 필요한 응용 프로그램을 처리하기 위한 기술입니다. 컨테이너 내부의 루트를 호스트의 루트가 아닌 사용자에게 매핑할 수 있습니다. 컨테이너 내부의 시뮬레이션된 루트에는 필요한 권한이 있지만 브레이크아웃은 호스트에 대한 루트 액세스를 제공하지 않습니다.

/etc/docker/daemon.json 파일에 userns-remap 필드를 추가하면 네임스페이스 재매핑이 활성화됩니다.

 {
    "userns-remap": "기본값"
}

defaultuserns-remap 의 값으로 사용하면 Docker가 호스트에 dockremap 이라는 새 사용자를 자동으로 생성하도록 지시합니다. 컨테이너 내의 루트는 호스트의 dockremap 에 다시 매핑됩니다. UID/GID 또는 사용자 이름/그룹 이름 조합을 사용하여 선택적으로 기존 사용자 및 그룹을 대신 지정할 수 있습니다.

 {
    "userns-remap": "데모 사용자"
}

변경 사항을 적용한 후 Docker 데몬을 다시 시작합니다.

 $ sudo 서비스 도커 재시작

nsuser-remap: default 를 사용하는 경우 이제 dockremap 사용자가 호스트에 있어야 합니다.

 $ id 도크레맵

uid=140(dockremap) gid=119(dockremap) 그룹=119(dockremap)

사용자는 /etc/subuid/etc/subgid 하위 ID 파일에도 나타나야 합니다.

 $ 도크레맵:231500:65535

사용자는 231500부터 시작하여 65,535개의 하위 ID 범위를 할당받았습니다. 사용자 네임스페이스 내에서 ID 2315000 에 매핑되어 컨테이너의 루트 사용자가 됩니다. 높은 번호의 UID인 231500은 호스트에 대한 권한이 없으므로 컨테이너 브레이크아웃 공격이 그렇게 많은 피해를 입힐 수 없습니다.

시작하는 모든 컨테이너는 docker run --userns=host 로 옵트아웃하지 않는 한 다시 매핑된 사용자 네임스페이스를 사용하여 실행됩니다. 이 메커니즘은 네임스페이스 사용자의 하위 UID 및 GID가 소유하는 /var/lib/docker 내부에 네임스페이스 디렉토리를 생성하여 작동합니다.

 $ sudo ls -l /var/lib/docker/231500.231500

총 14
drwx------ 5 231500 231500 13 7월 22일 19:00 aufs
drwx------ 3 231500 231500 13 7월 22일 19:00 컨테이너
...

사용자 네임스페이스는 컨테이너 격리를 높이고, 브레이크아웃을 방지하고, 루트 권한이 필요한 응용 프로그램과의 호환성을 유지하는 효과적인 방법입니다. 하지만 몇 가지 장단점이 있습니다. 이 기능은 새로운 Docker 인스턴스에서 가장 잘 작동하고, 호스트에서 마운트된 볼륨은 권한을 조정해야 하며, 일부 외부 저장소 드라이버는 사용자 매핑을 전혀 지원하지 않습니다. 이 옵션을 채택하기 전에 문서를 검토해야 합니다.

요약

컨테이너화된 애플리케이션을 루트로 실행하는 것은 보안 위험입니다. 간과하기 쉽지만 컨테이너가 제공하는 격리는 커널 사용자를 컨테이너 사용자와 완전히 분리할 만큼 강력하지 않습니다. 컨테이너의 루트는 호스트의 루트와 동일하므로 성공적인 손상으로 시스템을 제어할 수 있습니다.

이미지 작성자는 Dockerfile에 USER 명령을 포함하여 애플리케이션이 루트 없이 실행되도록 해야 합니다. 이미지 사용자는 docker run --user 로 이를 재정의하여 특정 UID 및 GID를 할당할 수 있습니다. 이는 이미지가 일반적으로 루트를 사용하는 경우를 완화하는 데 도움이 됩니다.

--cap-drop=ALL 을 사용하여 컨테이너에서 모든 기능을 삭제한 다음 --cap-add 플래그로 필요한 것을 허용 목록에 추가하여 보안을 더욱 강화할 수 있습니다. 이러한 기술을 결합하면 필요한 최소한의 권한으로 루트가 아닌 사용자로 애플리케이션을 실행하여 보안 상태를 개선할 수 있습니다.