docker 原理之 user namespace(下)
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 中指定用户身份有两种方式:
- Dockerfile 中指定用户身份
- 命令行参数指定用户身份
这里介绍第二种命令行参数指定用户身份:
# 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(下)的更多相关文章
- docker原理
Docker原理11 Linux Namespace 11 AUFS文件系统17 重新理解Docker的各种命令18 Docker原理 Linux Namespace docker是一个容器引擎,容器 ...
- Docker容器的原理与实践 (下)
欢迎访问网易云社区,了解更多网易技术产品运营经验. Docker原理分析 Docker架构 镜像原理 镜像是一个只读的容器模板,含有启动docker容器所需的文件系统结构及内容Docker以镜像和在镜 ...
- Docker原理:Namespace
目录 Namespace UTS Namespae PID Namespace Mount Namespace User Namespace Network Namespace 参考 Namespac ...
- 一篇不一样的docker原理解析
转自:https://zhuanlan.zhihu.com/p/22382728 https://zhuanlan.zhihu.com/p/22403015 在学习docker的过程中,我发现目前do ...
- Docker原理探究
问题思考:-------------------------------------Docker浅显原理理解-------------------------------------P1. ubunt ...
- docker原理(转)
转自:https://zhuanlan.zhihu.com/p/22382728 https://zhuanlan.zhihu.com/p/22403015 在学习docker的过程中,我发现目前do ...
- Docker原理(图解+秒懂+史上最全)
背景:下一个视频版本,从架构师视角,尼恩为大家打造高可用.高并发中间件的原理与实操. 目标:通过视频和博客的方式,为各位潜力架构师,彻底介绍清楚架构师必须掌握的高可用.高并发环境,包括但不限于: 高可 ...
- docker 深入理解之namespace
namespace 名称空间 docker容器主要通过资源隔离来实现的,应该具有的6种资源隔 namespace 的六项隔离 namespace 系统调用参数 隔离的内容 UTS CLONE_NEWU ...
- 如何使用不同dll的相同namespace下的相同接口
问题: 程序里加载了2个dll,这2个dll里都声明了同样的命名空间(这个不违法),然后在这个同样的命名空间下,他俩又定义了同名的interface. 然后我程序里直接using这个命名空间,使用这个 ...
- docker原理与上帝进程
做个笔记, 先水一会. 虚拟机指的是: 在软件的层面上通过模拟硬件进行的输入输出. docker原理:docker就是一个linux系统的进程, 它通过 Linux 的 namespaces 对不同的 ...
随机推荐
- HBase应用方案
HBase性能优化方法:
- 组合式api的使用方式
方式一:通过setup选项 <script> export default { setup(){ // 提供数据 // 提供函数 // 提供计算属性等等..... } } </scr ...
- NetSuite 开发日记 —— 估价单(Estimate)新建项目(Project)自动填入项目字段
Background 用户在估价单(Estimate)点击「项目」字段旁边+按钮新建项目(Project),在项目的自定义字段中自动填入估价单ID 用户在项目记录存在切换自定义表格行为 Analysi ...
- MagicArray:像php一样,让Go业务代码不再卷!
卷!一个字形容了当今码农行业的现状.一层一层的代码结构,一个一个dto,entity,vo,req,resp.这些对象越来越多,让码农们非常劳于奔命,加一个字段,改一个字段,影响面有多少.代码量也越来 ...
- 在Linux服务器上装jenkins(方式一:war包)
官网下载jenkins https://www.jenkins.io/zh/download/ 官网下载太慢,可以去清华镜像下载(百度搜索:清华镜像) 下载的文件是jenkins.war 把安装文件放 ...
- ElasticSearch之cat master API
命令样例如下: curl -X GET "https://localhost:9200/_cat/master?v=true&pretty" --cacert $ES_HO ...
- zabbix-server 报错记录
数据库磁盘满导至zabbix挂了 登陆zabbix页面提示错误信息,查看系统磁盘: /目录已满,导致mariadb数据库无法正常运行,如果有介质将会一直收取: 解决方法:扩容/目录,达到理想值,重启m ...
- P2343 宝石管理系统 做题记录
随机跳的. 一眼带修第 \(\text{k}\) 大,平衡树 / 权值线段树 / set 随便搞就行. (set 可能要双 \(\log\),所以没写) 很快啊,权值线段树就 \(\text{A}\) ...
- 新晋“网红”Cat1 是什么
摘要:此Cat非彼Cat,它是今年物联网通信圈新晋网红"靓仔". 引言 今年5月,工信部发布了<关于深入推进移动物联网全面发展的通知>,明确提出推动存量2G.3G物联网 ...
- VUE3/TS/TSX入门手册指北
VUE3入门手册 vue3入门 首先 查看 官方文档:https://cn.vuejs.org/guide/quick-start.html 如果有vue2基础,速成课程:https://www.zh ...