抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

docker文件夹映射权限问题思考及可能解决方法

背景分析

在多用户服务器上公用docker搭建环境时,初步设想为宿主机用户为普通用户,容器内用户为root,

用户在容器内自由搭建自己所需的环境,而不影响其他人以及容器外的环境.

但当用户在使用docker挂载磁盘的时候,由于容器内使用root运行程序,会导致挂载中产生的文件属于root:root。而容器外用户并不是root,会使的文件共享甚至阅读日志产生权限上的问题,导致不可读或不可写之类的问题。

本文旨在宿主机使用普通用户,而容器内仍然使用root用户,且不会产生文件权限的问题.

案例截图:

image-20210923104601353

可以看到创建映射的 srssrsRAN 文件夹 因为是由docker run 命令自动创建的,权限被化为root

普通用户在这个文件夹下没有权限!,

image-20210923104827265

需求

容器外使用普通用户(没有sudo权限等管理员权限)

容器内使用带管理员权限的root用户

文件挂载原理

简而言之,docker的文件挂载中,容器内外uid与gid相同

最简单的挂载磁盘,例如:docker run -v $PWD:/data bash,就是将当前目录挂载到容器内的/data目录。文件的权限可以通过ls -l查看。

容器内可能有使用root用户和非root用户运行程序的两种情况。

  • 若容器内使用root运行程序,可以想象,产生的文件属于0:0,也就是root:root。容器外文件也会属于0:0,同样是root:root。这样产生的文件就需要容器外的root权限才可以操作。
  • 若容器内使用非root运行程序,例如demo:x:1000:1000::/home/blog:/bin/bash,产生的文件属于1000:1000。容器外文件也会属于1000:1000,而容器外uid为1000的用户可能是test,这是若碰巧你就是test,你就可以顺利读取这个文件。但若你是uid为1001的test2,而且t是个test2讨厌鬼,你就告别这个文件了。甚至容器外根本没有uid为1000的用户,那这个文件就不属于任何人。

docker用户组

docker用户组的出现,目的在于当普通用户既无sudo权限,有想运行docker命令时出现.

一般来说,在linux环境下安装完成docker,系统会自动创建id=999docker组 . 此时只需要将普通用户加入到docker组中即可.

具体 docker组的id, 请自行查看

image-20210923103642016

方式有两种(需要在拥有sudo权限的账号下修改):

  • 使用usermod命令

    $ sudo usermod -aG docker <用户名>
    # e.g sudo usermod -aG docker test1
  • 直接修改 /etc/groupdocker 所在组

    $ sudo vim /etc/group
    # 在docker所在行,按格式在后面添加用户名即可

    修改完成后,重启ssh或重新登即可, 使用id <用户名> 检查是否在docker所在组

三种可能解决方法

1. 限定开启用户

即运行 docker run -u <xxx>:<xxx>

但这个方法无法解决上述的需求

2.使用子用户

若容器内外文件的uid:gid可以不同,这个问题就可以很容易解决。的确有这么一个方案,让容器内所有的uid:gid以一定的规则映射,我推荐使用这一方案。文章的方案演示节中我会演示这一方案。

在官方文档中,这个方案本身是为了解决安全问题,见这里。发生容器挂载磁盘root权限提权也不是一次两次了,这算是一个官方的解决方案。

https://docs.docker.com/engine/security/userns-remap/

但这个方案会有一些限制

  • 不可使用--pid=host--network=host
  • 不可使用无法识别或使用用户映射的挂载磁盘
  • 若使用docker run --privileged则必须同时使用--userns=host

都是不大的限制,使用的时候留个心眼即可。

解释:

因为docker 权限映射的原理是, 容器内外uid与gid相同,

那么我是否可以 通过 userns-remap 命令实现, 将容器内的root 映射到容器外宿主机上一个具有管理员(sudo)的用户(称为siz)上呢,而其他普通用户(test<xxx>)只需要在这个siz所在的组即可. 而这个组的小组管理员即为siz.

但此时一个新的问题出现了: 当普通用户创建文件夹映射时, 此文件夹的所属者为siz,但小组权限仅为xr 即所在组的成员没有修改的权限,只有读和运行的权限, 并且此时普通用户(test<xxx> 并没有sudo权限,也就无法通过chmod g+w 等命令来实现提权. 此时该如何解决呢?

答: 通过进入容器内提权实现,

​ 因为容器内的用户为root,即对应的权限为小组管理员siz, 而小组管理员拥有(sudo) 权限, 又因为文件映射是容器内外相同的, 在容器内修改了文件权限, 那么在容器外普通用户就有了读写执行的权限.

操作实现

  1. 修改/etc/subuid/etc/subgid

    查看小组的管理员id

    $ id siz
    uid=1000(siz) gid=1000(siz) groups=1000(siz)
    # 得到 siz的id 为 1000

    使用带sudo的权限账号修改 /etc/subuid/etc/subgid 文件

    格式为: <name>:start:number

    对应方式: 如果组管理员id 1000 , 则对应容器内的root1 , 即<name>:1000:1

    如果组管理员id1003 ,则对应容器内的root1+(1003-1000)=4<name>:1003:4

    根据组管理员id 对应设置好映射

    例如本文组管理员sizid 为1000 , 则修改为如下样式, 并保存修改

    # sudo vim /etc/subuid
    siz:1000:1
    siz:100000:65536
    test1:165536:65536
    test2:231072:65536
    demo:296608:65536
    # sudo vim /etc/subgid
    siz:1000:1
    siz:100000:65536
    test1:165536:65536
    test2:231072:65536
    demo:296608:65536
  2. 修改docker 守护程序 /etc/docker/daemon.json

    注意修改 /etc/docker/daemon.json 文件后, 会导致之前的 镜像与容器不被识别, 所以请做好备份.

    容器->打包成镜像-> 推送到hub

    Enabling userns-remap effectively masks existing image and container layers, as well as other Docker objects within /var/lib/docker/. This is because Docker needs to adjust the ownership of these resources and actually stores them in a subdirectory within /var/lib/docker/. It is best to enable this feature on a new Docker installation rather than an existing one.

    # 没有这个文件的化, 请创建
    # sudo vim /etc/docker/daemon.json
    {
    	"userns-remap":"<组管理员名称>"
    }
    # sudo service docker restart
    # 查看docker 状态 sudo systemctl status docker.service 

    这里 `“userns-remap”:"<组管理员名称>"的格式 参考官方文档

    https://docs.docker.com/engine/security/userns-remap/

    Edit /etc/docker/daemon.json. Assuming the file was previously empty, the following entry enables userns-remap using user and group called testuser. You can address the user and group by ID or name. You only need to specify the group name or ID if it is different from the user name or ID. If you provide both the user and group name or ID, separate them by a colon (:) character. The following formats all work for the value, assuming the UID and GID of testuser are 1001:

    • testuser
    • testuser:testuser
    • 1001
    • 1001:1001
    • testuser:1001
    • 1001:testuser
  3. 修改普通用户的组

    当在进行测试的时候发现一个新的问题:

    即组内普通用户创建的文件在容器中因为没有相应的`uid:gid` 映射, 并且容器中的`root`用户的权限很低时(组管理员拥有sudo权限,但需要输入sudo才可以; 而容器中时没有sudo命令的,所有说这里的`root`权限很低)在这种情况下: 就会出现普通用户创建的文件,在容器中被识别为: `nobody ,nogroups 现象

    image-20210923191103296

    暂时的解决方法
    1. 普通用户删除私有组,即让普通用户的主组为(docker容器映射的管理员所在的组)

      ​ 例如: 本文演示小组管理员为siz, 组名为(siz) 则让 普通用户test<xxx> 的主组为siz

      # 命令:  sudo usermod -g <小组管理员名称> <普通用户名称>
      # 将普通用户的主组从私有组改为小组管理员所在的组
      $ sudo usermod -g  test1 siz
      1. 对宿主机(容器外)组成员中普通用户创建的文件或文件夹提升组权限

      目的: 使容器内root获得对这个文件夹拥有修改(w) 权限

      $ chmod g+wxr <xxx>
      1. 对容器内root 创建的文件或文件夹提升组权限

      目的: 使宿主机(容器外) 组成员普通用户获得对这个文件夹拥有修改(w) 权限

      $ chmod g+wxr <xxx>

    缺陷:

    当内外创建新的文件和文件夹使, 内外要不断的使用chmod 命令进行授权,

演示:

组成员

image-20210923112729409

  • 组管理员(siz) 进行映射测试:

    image-20210923112454090

  • 组成员test1 进行映射测试

    image-20210923113945262

image-20210923114231331

  1. 使用entrypoint.sh 定制脚本

    这个过程是在编写Dockerfile文件时使用的,

    目的是让容器内外对应的用户相等来解决文件夹映射目录权限的问题.

    主要的思路是,从主机中读取当前用户的id, 然后再创建容器时相应的在容器内部新建一个对应的用户,

    这样保证了容器内外的uid:gid 相等.

    但在这个里不符合我们的需求, 故不讨论.

总结

为了解决让宿主机使用普通用户来使用docker,而在容器中相对给与较高的root 权限用户需求.

本文采用了修改docker守护程序的方法,其官方文件本意是docker为了解决容器内root升权的问题

所谓升权, 即不做任何修改情况下, 容器内root 与宿主机root相对应, 虽然这个容器内的权限是有一定限制的root 权限, 但可以通过映射宿主机根目录,将所有内容映射到容器中, 实现在容器中获得所有文件的权限,来实现恶意攻击.

通过映射用户, 容器中的root 权限与宿主机被映射的用户权限相等,

可以思考这样一个问题: 如果我映射的宿主机用户是一个普通用户(没有sudo)权限,那么容器里的root 有没有sudo权限呢?

答案

答案是没有的, 可以尝试一下. 容器的的root 仅仅是个名称, 它可以叫做superhero 也可以叫做 tom , 只是个名字,并无所谓,真正相关的是uid:gid

评论吧



本站总访问量为 访客数为

鲁 ICP 备 20018157 号-1
Copyright 2021 - 2022 sizaif. All Rights Reserved