1. user namespace

user namespace 主要隔离了安全相关的标识符和属性,包括用户 ID,用户组 ID,key 和 capabilities 等。同样一个用户 id 在不同 user namespace 中会有不同的权限。比如,进程属于一个普通用户,但是它创建的 user namespace 确属于拥有所有权限的超级用户。使用 unshare 创建 user namespace:

chunqiu@chunqiu:/root/chunqiu/docker/mount/disk1$ unshare --user -r --mount /bin/bash
root@chunqiu:/root/chunqiu/docker/mount/disk1# id
uid=0(root) gid=0(root) groups=0(root)
root@chunqiu:/root/chunqiu/docker/mount/disk1# echo $$
13905

打开另一个 shell 窗口,查看进程 13905 所属用户:

root@chunqiu:~/chunqiu/docker/mount/disk1# ps -ef | grep 13905 | grep -v grep
chunqiu 13905 13880 0 08:26 pts/0 00:00:00 /bin/bash

从上例可以看出,进程 13905 在容器(user namespace)外属于一个普通用户,但是在 user namespace 里却属于 root 用户。

继续对上例进行深挖,unshare 的 -r 选项指明了 user namespace 用户和容器外用户的映射,查看 uid_map 和 gid_map:

root@chunqiu:/root/chunqiu/docker/mount/disk1# cat /proc/13905/uid_map
0 1002 1
root@chunqiu:/root/chunqiu/docker/mount/disk1# cat /proc/13905/gid_map
0 1002 1

可以看到 user namespace 内的 root(0) 用户/组和 user namespace 外的 chunqiu(1002) 用户/组建立映射。因此,在 user namespace 内的特权用户只是 user namespace 的普通用户,无法访问“权限不够”的文件/文件夹。如:

// user namespace 外
root@chunqiu:~/chunqiu/docker/mount/disk1# ls -l
total 1
-rw-r----- 1 root root 21 May 3 08:20 rootfile // user namespace 内
root@chunqiu:/root/chunqiu/docker/mount/disk1# ls -l
total 1
-rw-r----- 1 nobody nogroup 21 May 3 08:20 rootfile
root@chunqiu:/root/chunqiu/docker/mount/disk1# cat rootfile
cat: rootfile: Permission denied

-r 选项建立 user namespace 内外的用户映射。如果不用 -r 选项 则需手动填写 uid_map 和 gid_map,实现用户的映射。创建 user namespace 如下:

chunqiu@chunqiu:~$ unshare --user --mount /bin/bash
nobody@chunqiu:~$ id
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
nobody@chunqiu:~$ echo $$
14641

这里 user namespace 的用户是 nobody ,是因为未建立用户映射。修改 uid_map 和 gid_map 文件,注意写这两个文件的进程必须是该 user namespace 的父 namespace 或者子 namespace:

在父 user namespace 中写文件 uid_map,gid_map:

chunqiu@chunqiu:~$ echo '0 1002 1' > /proc/14641/uid_map
-su: echo: write error: Operation not permitted
chunqiu@chunqiu:~$ echo '0 1002 1' > /proc/14641/gid_map
-su: echo: write error: Operation not permitted
chunqiu@chunqiu:~$ ls -l /proc/14641/uid_map
-rw-r--r-- 1 chunqiu chunqiu 0 May 3 08:57 /proc/14641/uid_map
chunqiu@chunqiu:~$ ls -l /proc/14641/gid_map
-rw-r--r-- 1 chunqiu chunqiu 0 May 3 08:57 /proc/14641/gid_map

尝试写入 uid_map 和 gid_map 显示没有权限,但是这两个文件确实是属于用户 chunqiu。查看当前进程的 capability:

chunqiu@chunqiu:~$ cat /proc/$$/status | egrep 'Cap(Inh|Prm|Eff)'
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000

查看 capability 知道当前进程没 CAP_SETUID 和 CAP_SETGID 权限,为其加上权限重新写:

chunqiu@chunqiu:~$ sudo setcap cap_setgid,cap_setuid+ep /bin/bash
chunqiu@chunqiu:~$ echo '0 1002 1' > /proc/14641/uid_map
chunqiu@chunqiu:~$ echo '0 1002 1' > /proc/14641/gid_map

在子 user namespace 中执行 bash 查看用户:

nobody@chunqiu:~$ exec bash
root@chunqiu:~# id
uid=0(root) gid=0(root) groups=0(root)

可以看到 nobody 改成了用户 root,实现了user namespace 内外用户的映射。

有一点需要注意的是当 user namespace 和其它 namespace 混合使用时,依旧需要 root 权限。解决方案是先以普通用户身份运行 user namespace,然后在 user namespace 中以 root 身份运行其它 namespace。内核会保证 user namespace 先执行。

2. docker 容器中的 uid 和 gid

docker 默认并没有使用 user namespace,它创建的容器和宿主机是同一 user namespace。意味着,docker 并未隔离宿主机和容器的用户。

在 docker 中指定用户身份有两种方式:

  1. Dockerfile 中指定用户身份
  2. 命令行参数指定用户身份

这里介绍第二种命令行参数指定用户身份:

# docker run -d --user 9999:9999 --name chunqiu 32c400c35bc2 sleep infinity
c588d1c1487a802aad016d5b82080f675bebc3111c33b103852408c56ff9b2e9
[root@chunqiu ~ (Master)]# docker ps | grep chunqiu
c588d1c1487a 32c400c35bc2 "sleep infinity" 11 seconds ago Up 8 seconds chunqiu
[root@chunqiu ~ (Master)]# ps -ef | grep sleep | grep -v grep
9999 3212381 3212189 2 13:53 ? 00:00:00 /usr/bin/sleep infinity
[root@chunqiu ~ (Master)]# readlink /proc/$$/ns/user
user:[4026531837]

命令行参数中使用 --user 指定用户 id 和用户组 id。在容器外查看进程所属的用户 id 是命令行参数指定的用户 9999,进入 container 中查看用户信息:

[root@chunqiu ~ (Master)]# docker exec -it chunqiu /bin/bash
bash-5.0$ ps -ef
UID PID PPID C STIME TTY TIME CMD
9999 1 0 0 05:53 ? 00:00:00 /usr/bin/sleep infinity
9999 7 0 10 05:54 pts/0 00:00:00 /bin/bash
9999 13 7 0 05:54 pts/0 00:00:00 ps -ef
bash-5.0$ id
uid=9999 gid=9999 groups=9999
bash-5.0$ readlink /proc/$$/ns/user
user:[4026531837]

进入容器中发现 user namespace 和宿主机上 user namespace 是一样的。同时,容器使用了 PID namespace,容器外的 3212381 进程在容器是容器内 PID 为 1 的 init 进程,并且进程的所属用户是命令行参数指定的用户。

容器和宿主机共用内核,内核使用的是 uid 和 gid,而不是用户名和组名, 因此这里不指定用户名也是可以工作的。内核会将用户 9999 当作普通用户对待,建立文件查看 9999 的访问权限:

[root@chunqiu ~ (Master)]# docker exec -it chunqiu /bin/bash
bash-5.0$ ls
commonfile chunqiufile
bash-5.0$ ls -l
total 0
-rw-rw----. 1 7779 7779 0 May 3 10:18 commonfile
-rw-rw-r--. 1 7779 7779 0 Apr 30 05:31 chunqiufile
bash-5.0$ cat chunqiufile
bash-5.0$ cat commonfile
cat: commonfile: Permission denied
bash-5.0$

将文件 commonfile 和 chunqiufile mount 到容器内,文件的所属用户和用户组改成了 7779,它是宿主机上的 chunqiu 普通用户,在这里以 id 的形式显示。发现用户只能读取 chunqiufile,因为它开放了读权限给不属于其用户组的其它用户。

2.1 kubernetes 指定 uid 和 gid 方式

在 kubernetes 中通过配置 security Context 来配置 Pod 或容器 container 的 uid 和 gid,kubernetes 默认也是不使用 user namespace 的。

如下创建 container 所属 uid 和 gid:

spec:
securityContext:
runAsUser: 9999
runAsGroup: 9999
...

详细信息看 这里

3. docker 和 user namespace

上节说了 docker 默认不开启 user namespace,实际上 docker 已经实现了相关功能,参看 这里 进行配置使用,本文就不赘述啦~

docker 原理之 user namespace(下)的更多相关文章

  1. docker原理

    Docker原理11 Linux Namespace 11 AUFS文件系统17 重新理解Docker的各种命令18 Docker原理 Linux Namespace docker是一个容器引擎,容器 ...

  2. Docker容器的原理与实践 (下)

    欢迎访问网易云社区,了解更多网易技术产品运营经验. Docker原理分析 Docker架构 镜像原理 镜像是一个只读的容器模板,含有启动docker容器所需的文件系统结构及内容Docker以镜像和在镜 ...

  3. Docker原理:Namespace

    目录 Namespace UTS Namespae PID Namespace Mount Namespace User Namespace Network Namespace 参考 Namespac ...

  4. 一篇不一样的docker原理解析

    转自:https://zhuanlan.zhihu.com/p/22382728 https://zhuanlan.zhihu.com/p/22403015 在学习docker的过程中,我发现目前do ...

  5. Docker原理探究

    问题思考:-------------------------------------Docker浅显原理理解-------------------------------------P1. ubunt ...

  6. docker原理(转)

    转自:https://zhuanlan.zhihu.com/p/22382728 https://zhuanlan.zhihu.com/p/22403015 在学习docker的过程中,我发现目前do ...

  7. Docker原理(图解+秒懂+史上最全)

    背景:下一个视频版本,从架构师视角,尼恩为大家打造高可用.高并发中间件的原理与实操. 目标:通过视频和博客的方式,为各位潜力架构师,彻底介绍清楚架构师必须掌握的高可用.高并发环境,包括但不限于: 高可 ...

  8. docker 深入理解之namespace

    namespace 名称空间 docker容器主要通过资源隔离来实现的,应该具有的6种资源隔 namespace 的六项隔离 namespace 系统调用参数 隔离的内容 UTS CLONE_NEWU ...

  9. 如何使用不同dll的相同namespace下的相同接口

    问题: 程序里加载了2个dll,这2个dll里都声明了同样的命名空间(这个不违法),然后在这个同样的命名空间下,他俩又定义了同名的interface. 然后我程序里直接using这个命名空间,使用这个 ...

  10. docker原理与上帝进程

    做个笔记, 先水一会. 虚拟机指的是: 在软件的层面上通过模拟硬件进行的输入输出. docker原理:docker就是一个linux系统的进程, 它通过 Linux 的 namespaces 对不同的 ...

随机推荐

  1. Roaring bitmaps

    Roaring bitmaps 最近看一篇文章,里面涉及到使用roaring bitmaps来推送用户广告并通过计算交集来降低用户广告推送次数.本文给出roaring bitmaps的原理和基本用法, ...

  2. 数字孪生结合GIS会给矿业带来怎样的改变

    数字孪生技术和GIS的结合为矿业带来了革命性的改变.矿业作为重要的经济支柱,其发展与资源的开采.生产过程的管理密切相关.通过数字孪生和GIS的融合,矿业行业可以实现更高效.可持续的运营和管理,带来许多 ...

  3. [笔记01]---solr

    什么是Solr 1.直接使用sql搜索存在的问题 大多数搜索引擎应用都必须具有某种搜索功能 搜索功能往往是巨大的资源消耗 它们由于沉重的数据库加载而拖垮你的应用的性能 所有我们一般在做搜索的时候 会把 ...

  4. 【scikit-learn基础】--『监督学习』之 逻辑回归分类

    逻辑回归这个算法的名称有一定的误导性.虽然它的名称中有"回归",当它在机器学习中不是回归算法,而是分类算法.因为采用了与回归类似的思想来解决分类问题,所以它的名称才会是逻辑回归. ...

  5. 序列化性能测试:jdk和fastjson

    序列化性能测试:jdk和fastjson 我开发一个认证授权框架时,需要添加数据库存储token或者会话,于是想测试使用jdk的blob存储解析快还是存储string的json序列化解析快,从而选择他 ...

  6. 文心一言 VS 讯飞星火 VS chatgpt (144)-- 算法导论12.1 4题

    四.用go语言,对于一棵有 n 个结点的树,请设计在 O(n)时间内完成的先序遍历算法和后序遍历算法. 我个人喜欢 灵小智 . 文心一言: 在 Go 语言中,我们可以使用递归来实现树的前序遍历和后序遍 ...

  7. LeetCode 贪心篇(455、55)

    455. 分发饼干 假设你是一位很棒的家长,想要给你的孩子们一些小饼干.但是,每个孩子最多只能给一块饼干.对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸:并且每块饼干 ...

  8. 实战解析丨如何对Mysql连接请求的tcpdump内容进行分析

    摘要:tcpdump是通过拦截发送和收到的网络连接中的TCP/IP和其他数据包,通过tcpdump工具帮助我们分析三次握手或者四次挥手的数据包情况,就能很容易的帮助我们分析出网络在哪一个步骤出的问题. ...

  9. 一文带你了解两种Transformer文字识别方法

    摘要:受Transformer模型的启发,目前一些学者将该结构应用到文本行识别中,以替代RNN,取得了良好的效果,如在HGA-STR和 SRN. 当前的文本行识别器为拥有更强的序列语义能力,模型多采用 ...

  10. 拥抱时序数据库,构筑IoT时代下智慧康养数据存储底座

    摘要:在HDZ城市行广州站中,来自华为云华为云数据库创新Lab向宇从时序数据库的技术角度,解读一下华为云时序数据库GaussDB(for Influx)如何应用在智慧健康养老行业. 本文分享自华为云社 ...