在nginx
podman 容器中nginx
,用户用于运行nginx
服务器。
在主机上ls -alh
:
drwxrwx--- 2 myuser myuser 4.0K Aug 10 22:23 .
drwxrwx--- 3 myuser myuser 4.0K Aug 10 22:59 ..
-rw-rw---- 1 myuser myuser 46 Aug 10 22:24 .htpasswd
容器内的同一文件夹ls -alh
:
drwxrwx--- 2 root root 4.0K Aug 10 22:23 .
drwxr-xr-x 1 root root 4.0K Aug 10 11:05 ..
-rw-rw---- 1 root root 46 Aug 10 22:24 .htpasswd
nginx
.htpasswd
容器内的用户由于无法访问o-rwx
。
问题:处理此类案件的常用模式是什么?无根容器通用吗?也许可以创建一个组(稍后用作文件组所有者),该组收集来自subuid
/subgid
针对特定主机用户的所有范围 - 但如何实现这一点?
答案1
通过使用命令行选项,--uidmap
您可以指定我的用户UID 和我的用户子 UID 被映射到容器中。(参见手册页为了podman run
)。
命令行选项的--gidmap
工作方式相同,但针对的是 GID 而不是 UID。
让我们查找用户的 UID 和 GIDnginx在容器镜像中docker.io/library/nginx
$ podman run --rm docker.io/library/nginx grep nginx /etc/passwd
nginx:x:101:101:nginx user,,,:/nonexistent:/bin/false
$
结果:
- 唯一标识:101
- 性别识别号码:101
稍后在设置两个 shell 变量时会使用这些数字
$ container_uid=101
$ container_gid=101
(shell 变量container_uid和容器_gid在这篇文章之外没有任何意义。它们只是为了让答案更容易阅读而引入的)
查看主机上的文件 /etc/subuid 和 /etc/subgid
用户我的用户具有这些子 UID 和子 GID。
$ grep myuser /etc/subuid
myuser:231072:65536
$ grep myuser /etc/subgid
myuser:231072:65536
$
结果:
我的用户有 65536 个子 UID 和 65536 个子 GID。
稍后在设置两个 shell 变量时会使用这些数字
$ subuid_size=65536
$ subgid_size=65536
(shell 变量subuid_size和subgid_size在这篇文章之外没有任何意义。它们只是为了让答案更容易阅读而引入的)
而不是抬头subuid_size和subgid_size 在/etc/subuid和/etc/subgid,更通用的方法是运行命令
subuid_size=$(( $(podman info --format "{{ range .Host.IDMappings.UIDMap }}+{{.Size }}{{end }}" ) - 1 ))
subgid_size=$(( $(podman info --format "{{ range .Host.IDMappings.GIDMap }}+{{.Size }}{{end }}" ) - 1 ))
优点是,当文件/etc/nsswitch.conf用来代替/etc/subuid和/etc/subgid。 (看man subuid
)
演示 1:映射用户我的用户在主机上到用户根容器内部
没有必要指定--uidmap
,--gidmap
因为这是标准映射。
创建全世界可写的目录演示1
$ mkdir demo1
$ chmod 777 demo1
$
创建新文件,运行为根容器内部:
$ podman run --rm \
-v ./demo1:/dir:Z \
docker.io/library/nginx touch /dir/created_by_root
$
创建新文件,运行为nginx容器内部:
$ podman run --rm \
--user 101:101 \
-v ./demo1:/dir:Z \
docker.io/library/nginx touch /dir/created_by_nginx
$
列出主机上的文件
$ ls -l demo1
total 0
-rw-r--r--. 1 231172 231172 0 Aug 27 20:24 created_by_nginx
-rw-r--r--. 1 myuser myuser 0 Aug 27 20:22 created_by_root
$
结果:文件由根创建归我的用户:我的用户
演示 2:映射用户我的用户在主机上到用户nginx容器内部
创建全世界可写的目录演示2
$ mkdir demo2
$ chmod 777 demo2
$
创建新文件,运行为根容器内部:
$ subuid_size=65536
$ subgid_size=65536
$ container_uid=101
$ container_gid=101
$ podman run --rm \
--uidmap=0:1:$container_uid \
--uidmap=$((container_uid + 1)):$((container_uid + 1)):$((subuid_size - $container_uid)) \
--uidmap=$container_uid:0:1 \
--gidmap=0:1:$container_gid \
--gidmap=$((container_gid + 1)):$((container_gid + 1)):$((subgid_size - $container_gid)) \
--gidmap=$container_gid:0:1 \
-v ./demo2:/dir:Z \
docker.io/library/nginx touch /dir/created_by_root
$
创建新文件,运行为nginx在容器内。
$ subuid_size=65536
$ subgid_size=65536
$ container_uid=101
$ container_gid=101
$ podman run --rm \
--user $container_uid:$container_gid \
--uidmap=0:1:$container_uid \
--uidmap=$((container_uid + 1)):$((container_uid + 1)):$((subuid_size - $container_uid)) \
--uidmap=$container_uid:0:1 \
--gidmap=0:1:$container_gid \
--gidmap=$((container_gid + 1)):$((container_gid + 1)):$((subgid_size - $container_gid)) \
--gidmap=$container_gid:0:1 \
-v ./demo2:/dir:Z \
docker.io/library/nginx touch /dir/created_by_nginx
$
列出主机上的文件
$ ls -l demo2
total 0
-rw-r--r--. 1 myuser myuser 0 Aug 27 20:26 created_by_nginx
-rw-r--r--. 1 231072 231072 0 Aug 27 20:25 created_by_root
$
结果:文件由 nginx 创建归我的用户:我的用户
结论
使用方法--uidmap
与--gidmap
演示 2。
故障排除提示
我写了一个故障排除提示: 在无根容器中无法访问传入的设备或文件(UID/GID 映射问题)包含描述的方法演示 2
答案2
你应该弄清楚容器的初始主机 UID 是什么nginxUID(只需使用正在运行的用户从容器中触摸文件nginx
,或检查其日志文件,或检查正在运行的nginx进程。然后使用stat
或ls -ln
来自初始主机用户):一些大的 UID 值,我们假设它是 100030。
然后从初始主机的非特权用户可以使用setfactl
授予用户 100030 额外的访问权限。这应该是这样的:
setfacl -R -m u:100030:rX,d:u:100030:rX folder
如果你想要nginx用户能够写入(这可能不是一个好主意),您可以替换rX
为rwX
或仅在选定目录中执行此操作。以开头的重复d:
代表默认ACL,因此新创建的目录和文件也会继承相同的附加 ACL。设置 ACL 后,输出将ls
显示 a+
和 ACL 掩码而不是组,因此看起来可能会令人惊讶。
以下是有关 ACL 的各种参考:
- Debian LXC 的自述文件(这给了我这个想法),
- Linux 上的 POSIX 访问控制列表
acl(5)