4

尝试以 root 身份连接到正在运行的 docker 容器仍然会出现 Operation not allowed 错误apt-get update,但我仍然可以看到敏感文件,例如/etc/passwd. 以下是我的配置以及来自apt-get update. 我的主机操作系统是Ubuntu 18.04.3. 我的码头工人版本是Docker version 19.03.5, build 633a0ea838

我使用以下 Dockerfile 创建了一个容器

FROM python:3.8-slim-buster
RUN useradd -ms /bin/bash andrej
WORKDIR /home/andrej
COPY . /home/andrej/

RUN apt-get update && \
    apt-get install -y gcc && \
    pip install -r requirements.txt && \
    apt-get remove -y gcc && apt-get -y autoremove

RUN chown andrej:andrej pycurl && \
    chmod 0744 pycurl

USER andrej
ENTRYPOINT ["uwsgi"]
CMD ["--ini", "uwsgi.ini"]

从 docker compose 开始,如下所示:

version: "3.3"

services:

  andrej-cv:
    build: ./andrej_cv
    container_name: andrej-cv
    restart: always
    security_opt:
      - no-new-privileges
    expose:
      - 5000
    healthcheck:
      test: ./pycurl --host=127.0.0.1 --port=5050 --uri=/health_check
      interval: 1m30s
      timeout: 10s
      retries: 3

我的 docker 守护进程配置:

{
    "icc": false,
    "userns-remap": "default",
    "log-driver": "syslog",
    "live-restore": true,
    "userland-proxy": false,
    "no-new-privileges": true
}

我使用以下命令(以 root 身份)连接到容器: docker exec -it -u root <container_hash> /bin/bash但是当我尝试更新时,我得到了以下信息:

root@ed984abff684:/home/andrej# apt-get update 
E: setgroups 65534 failed - setgroups (1: Operation not permitted)
E: setegid 65534 failed - setegid (1: Operation not permitted)
E: seteuid 100 failed - seteuid (1: Operation not permitted)
E: setgroups 0 failed - setgroups (1: Operation not permitted)
Hit:1 http://deb.debian.org/debian buster InRelease
Ign:2 http://deb.debian.org/debian buster-updates InRelease
Err:4 http://deb.debian.org/debian buster-updates Release
  Could not open file /var/lib/apt/lists/partial/deb.debian.org_debian_dists_buster-updates_Release - open (13: Permission denied) [IP: 151.101.36.204 80]
Hit:3 http://security-cdn.debian.org/debian-security buster/updates InRelease
rm: cannot remove '/var/cache/apt/archives/partial/*.deb': Permission denied
Reading package lists... Done
W: chown to _apt:root of directory /var/lib/apt/lists/partial failed - SetupAPTPartialDirectory (1: Operation not permitted)
W: chmod 0700 of directory /var/lib/apt/lists/partial failed - SetupAPTPartialDirectory (1: Operation not permitted)
W: chown to _apt:root of directory /var/lib/apt/lists/auxfiles failed - SetupAPTPartialDirectory (1: Operation not permitted)
W: chmod 0700 of directory /var/lib/apt/lists/auxfiles failed - SetupAPTPartialDirectory (1: Operation not permitted)
E: setgroups 65534 failed - setgroups (1: Operation not permitted)
E: setegid 65534 failed - setegid (1: Operation not permitted)
E: seteuid 100 failed - seteuid (1: Operation not permitted)
W: Download is performed unsandboxed as root as file '/var/lib/apt/lists/partial/deb.debian.org_debian_dists_buster_InRelease' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
E: setgroups 0 failed - setgroups (1: Operation not permitted)
W: Problem unlinking the file /var/lib/apt/lists/partial/deb.debian.org_debian_dists_buster_InRelease - PrepareFiles (13: Permission denied)
W: Problem unlinking the file /var/lib/apt/lists/partial/deb.debian.org_debian_dists_buster-updates_InRelease - PrepareFiles (13: Permission denied)
W: Problem unlinking the file /var/lib/apt/lists/partial/deb.debian.org_debian_dists_buster-updates_Release - PrepareFiles (13: Permission denied)
E: The repository 'http://deb.debian.org/debian buster-updates Release' no longer has a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
W: Problem unlinking the file /var/lib/apt/lists/partial/security.debian.org_debian-security_dists_buster_updates_InRelease - PrepareFiles (13: Permission denied)

容器中 /etc/subuid/etc/subgid看起来像这样(两者):

andrej:100000:65536

主机 /etc/subuid/etc/subgid看起来像这样(两者):

andrej:100000:65536
dockremap:165536:65536

Apparmor 在 Ubuntu 主机上运行,​​状态如下(仅docker-default配置文件):

andrej@machine:/etc/apparmor.d$ sudo aa-status 
apparmor module is loaded.
38 profiles are loaded.
36 profiles are in enforce mode.
   /sbin/dhclient
   /snap/core/8268/usr/lib/snapd/snap-confine
   /snap/core/8268/usr/lib/snapd/snap-confine//mount-namespace-capture-helper
   /usr/bin/evince
   /usr/bin/evince-previewer
   /usr/bin/evince-previewer//sanitized_helper
   /usr/bin/evince-thumbnailer
   /usr/bin/evince//sanitized_helper
   /usr/bin/man
   /usr/lib/NetworkManager/nm-dhcp-client.action
   /usr/lib/NetworkManager/nm-dhcp-helper
   /usr/lib/connman/scripts/dhclient-script
   /usr/lib/cups/backend/cups-pdf
   /usr/lib/snapd/snap-confine
   /usr/lib/snapd/snap-confine//mount-namespace-capture-helper
   /usr/sbin/cups-browsed
   /usr/sbin/cupsd
   /usr/sbin/cupsd//third_party
   /usr/sbin/ippusbxd
   /usr/sbin/tcpdump
   docker-default
   libreoffice-senddoc
   libreoffice-soffice//gpg
   libreoffice-xpdfimport
   man_filter
   man_groff
   snap-update-ns.core
   snap-update-ns.gnome-calculator
   snap-update-ns.gnome-characters
   snap-update-ns.gnome-logs
   snap-update-ns.gnome-system-monitor
   snap.core.hook.configure
   snap.gnome-calculator.gnome-calculator
   snap.gnome-characters.gnome-characters
   snap.gnome-logs.gnome-logs
   snap.gnome-system-monitor.gnome-system-monitor
2 profiles are in complain mode.
   libreoffice-oopslash
   libreoffice-soffice
17 processes have profiles defined.
14 processes are in enforce mode.
   docker-default (1101) 
   docker-default (1102) 
   docker-default (1111) 
   docker-default (1600) 
   docker-default (1728) 
   docker-default (1729) 
   docker-default (1730) 
   docker-default (1731) 
   docker-default (1732) 
   docker-default (1798) 
   docker-default (1799) 
   docker-default (1800) 
   docker-default (1801) 
   docker-default (1802) 
0 processes are in complain mode.
3 processes are unconfined but have a profile defined.
   /sbin/dhclient (491) 
   /usr/sbin/cups-browsed (431) 
   /usr/sbin/cupsd (402) 

Selinux 似乎被禁用,因为没有/etc/selinux/config文件getenfoce并且sestatus命令不可用。

命令以 root 身份运行(其中andrejsu andrej是容器中的非特权用户)错误输出su: cannot set groups: Operation not permitted

4

6 回答 6

2

在以 Manjaro 作为主机系统的无根 Podman 中运行基于 Ubuntu-16.04 的容器时,我遇到了同样的问题。

TL;DR:尝试重建图像。这对我有帮助。

问题可能是 Docker 无法将/var/lib/apt/lists/package目录的所有者 (_apt) UID 映射到主机的 UID 命名空间。/etc/sub{u,g}id如果在拉取/构建映像后修改 ,则可能会发生这种情况。

这只是一个猜测,但原因可能是 Docker 先对图像执行 UID 映射,然后修改/etc/sub{u,g}id导致不同的 UID 映射规则 -> Docker 无法映射容器内的用户。

您可以通过运行docker inspect <image name>并检查“LowerDir”部分中的目录来验证这一点。在其中一个目录中,应该存在一个var/lib/apt/lists/packageUID 超出为 .dockremap 指定的范围的目录/etc/sub{u,g}id。podman 的确切命令是,podman image inspect <image name> --format '{{.GraphDriver.Data.LowerDir}}'但 Podman 和 Docker 的 CLI API 应该相同,因此相同的命令也应该适用于 Docker。

例如,我有一个条目tlammi:100000:65536/etc/sub{u,g}id但在主机端/var/lib/apt/lists/package归 UID 所有,165538超出范围[100000, 100000 + 65536)

于 2020-11-27T09:03:40.287 回答
1

我们在使用 rootless podman 时遇到了同样的问题。

我们更改了用户的 subuid/subgid 范围。这意味着需要修复使用旧范围存储的文件,或者只是从容器存储目录中删除临时文件:

$ podman info|grep GraphRoot
GraphRoot: /opt/tmp/container_graphroot/.local/share/containers/storage
$ rm -rf /opt/tmp/container_graphroot/.local/share/containers/storage/*
于 2021-02-02T12:47:04.587 回答
0

不确定 Docker,但在 runc 容器中的 kubernetes 中对我有帮助:

  1. 获取容器的 root 访问权限 列出所有容器
minikube ssh docker container ls

连接到您的容器(使用上一个命令中的容器 id 而不是44a7ad70d45b):

minikube ssh "docker container exec -it -u 0 44a7ad70d45b /bin/bash"
  1. 作为root内部容器:
root@mycontainer:/# apt-config dump | grep Sandbox::User
APT::Sandbox::User "_apt";

root@mycontainer:/# cat <<EOF > /etc/apt/apt.conf.d/sandbox-disable
APT::Sandbox::User "root";
EOF

请确保,该结果是有效的:

root@mycontainer:/# apt-config dump | grep Sandbox::User
APT::Sandbox::User "root";
  1. apt update看看
Get:1 http://archive.ubuntu.com/ubuntu hirsute InRelease [269 kB]
Get:2 http://apt.postgresql.org/pub/repos/apt hirsute-pgdg InRelease [16.7 kB]
...   
于 2022-02-12T21:32:40.177 回答
0

您描述的 docker 容器按设计工作。具有默认功能。

如果您缺少功能,请快速测试。

使用完整/所有容器功能运行您的容器 ( --privileged)

Docker 文档中有关功能的更多解释

Linux 内核能够将 root 用户的权限分解为不同的单元,称为能力。例如,CAP_CHOWN 功能允许 root 用户对文件 UID 和 GID 进行任意更改。CAP_DAC_OVERRIDE 功能允许 root 用户绕过对文件读取、写入和执行操作的内核权限检查。几乎所有与 Linux root 用户相关的特殊权限都分解为单独的功能。

将 root 权限分解为细粒度的功能允许您:

Remove individual capabilities from the root user account, making it less powerful/dangerous.
Add privileges to non-root users at a very granular level.

功能适用于文件和线程。文件功能允许用户以更高的权限执行程序。这类似于 setuid 位的工作方式。线程功能跟踪运行程序中功能的当前状态。

Linux 内核允许您设置能力边界集,对文件/线程可以获得的能力施加限制。

Docker 施加了某些限制,使得使用功能变得更加简单。例如,文件功能存储在文件的扩展属性中,而扩展属性在构建 Docker 映像时被剥离。这意味着您通常不必过多关注容器中的文件功能。

It is of course possible to get file capabilities into containers at runtime, however this is not recommended.

在没有基于文件的能力的环境中,应用程序不可能将其权限提升到超出边界集(能力无法增长的集合)之外。Docker 在启动容器之前设置边界集。您可以使用 Docker 命令向边界集添加或删除功能。

默认情况下,Docker 使用白名单方法删除除所需功能之外的所有功能。

于 2022-02-13T10:19:32.593 回答
0

注意:仅当您安装了 docker 和 docker-compose 如果最初您没有以 root 身份运行并重建映像,请运行prune

docker system prune -f
docker-compose up 

这样可以确保您在新版本上运行

于 2021-06-24T20:46:38.017 回答
0

这还不是答案(截至 2021 年 5 月 10 日),但我目前对此问题的研究。希望它能给其他人一些关于在哪里进一步研究的提示。也许我会回来编辑这篇文章以使其成为真正的答案。

据我所知,“问题”是由使用安全选项引起的no-new-privileges。请注意,它在 OP 的docker-compose文件和 Docker 守护程序的配置文件中指定。

这是Docker 文档中的描述

--security-opt="no-new-privileges:true" 禁止容器进程获得新权限

...

如果你想阻止你的容器进程获得额外的权限,你可以执行以下命令:

$ docker run --security-opt no-new-privileges -it centos bash

no-new-privileges是自 3.5 以来添加到 Linux 内核的标志。这是它的文档

no_new_privs位(自 Linux 3.5 起)是一种新的通用机制,可让进程安全地以跨execve. 任何任务都可以设置no_new_privs。一旦设置了该位,它将在 fork、clone 中继承,并且execve不能取消设置。使用no_new_privsset,execve()承诺不授予特权去做任何没有execve调用就无法完成的事情。例如,setuidandsetgid位将不再改变uidor gid; 文件功能不会添加到允许的集合中,并且 LSM 不会在 execve 之后放松约束。

注意最后一句“the setuidand setgidbits will not become the uidor gid”。这可能是您会看到以下错误消息的原因:

E: setgroups 65534 failed - setgroups (1: Operation not permitted)
E: setegid 65534 failed - setegid (1: Operation not permitted)
E: seteuid 100 failed - seteuid (1: Operation not permitted)
E: setgroups 0 failed - setgroups (1: Operation not permitted)

我发现一篇文章通过示例清楚地讨论了它:更安全地运行 Docker 应用程序容器

我目前的想法:

  • 我不将失败的“apt-get update”称为“问题”或“问题”,因为这应该是出于安全考虑的故意行为。换句话说,这是一件好事。
  • 因为引用的内核文档说“一旦设置了位,它......就不能取消设置”,我相信你将无法在现有容器中“修复”它。
  • 我不认为删除no-new-privileges是正确的解决方案。至少在你与你的团队充分讨论之前是不对的。
  • 或者,创建一个仅no-new-privileges用于测试目的的容器。
于 2021-05-10T16:14:46.687 回答