docker容器如何获取host外设数据

1.查看设备号

Linux的设备管理是和文件系统紧密结合的,把设备和文件关联起来,这样系统调用可以直接用操作文件一样的方法来操作设备。各种设备都以文件的形式存放在/dev目录下,称为设备文件。应用程序可以打开、关闭和读写这些设备文件,完成对设备的操作,就像操作普通的数据文件一样。为了管理这些设备,系统为设备编了号,每个设备号又分为主设备号和次设备号。主设备号用来区分不同种类的设备,而次设备号用来区分同一类型的多个设备。对于常用设备,Linux有约定俗成的编号,如硬盘的主设备号是3。

查看主设备号
:  cat /proc/devices
查看当前设备的主次设备号
: ls -l /dev

2. devices cgroup说明
devices cgroup用于控制分组对设备的使用权限——包括read,write和mknod权限。
查看cgroup下的devices.list文件可以获取当前分组的设备权限
$ cat devices.list
c 1:5 rwm
b *:* m
其每一行的格式为:type(设备类型) major:minor access(访问权限)。

设备类型有三种: 
a 表示所有设备,包括字符设备和块设备。
b 表示块设备。
c 表示字符设备。
major:minor在blkio中已介绍过,在这里可以使用*作为通配符表示所有的编号,例如*:*表示所有设备号。

访问权限是一个字符串,包含一个或多个代表不同权限的字母
r 读权限。
w 写权限。
m 创建设备文件的权限。

除去一些特殊虚拟设备,docker默认禁止容器访问主机的任何设备。可以通过--devices参数为容器添加设备权限,或者使用--privileged参数开启privileged模式,使用--privileged参数启动的容器会获得主机所有设备的所有权限
参考:
https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities
$ container_id=$(docker run -d --privileged nginx)
$ cat /sys/fs/cgroup/devices/docker/$container_id/devices.list
a *:* rwm <--- 所有设备的所有权限

by default, most potentially dangerous kernel capabilities are dropped; including cap_sys_admin (which is required to mount filesystems). However, the --privileged flag will allow it to run:

$ docker run -t -i --privileged ubuntu bash
root@50e3f57e16e6:/# mount -t tmpfs none /mnt
root@50e3f57e16e6:/# df -h
Filesystem      Size  Used Avail Use% Mounted on
none            1.9G     0  1.9G   0% /mnt

The --privileged flag gives all capabilities to the container, and it also lifts all the limitations enforced by the device cgroup controller. In other words, the container can then do almost everything that the host can do. This flag exists to allow special use-cases, like running Docker within Docker.


3.--device解释

Runtime privilege, Linux capabilities, and LXC configuration

--cap-add: Add Linux capabilities
--cap-drop: Drop Linux capabilities
--privileged=false: Give extended privileges to this container
--device=[]: Allows you to run devices inside the container without the --privileged flag.
--lxc-conf=[]: (lxc exec-driver only) Add custom lxc options --lxc-conf="lxc.cgroup.cpuset.cpus = 0,1"

  默认情况下,Docker的container是没有特权的。例如不能再container里面再启动一个container。这是因为默认情况下container是不能访问任何其他设备的。但是通过"privileged",container就拥有了访问任何其他设备的权限。

  当操作者执行docker run --privileged时,Docker将拥有访问host所有设备的权限,同时Docker也会在apparmor或者selinux做一些设置,使container可以容易的访问那些运行在container外部的设备。你可以访问Docker blog来获取更多关于--privileged的用法。

  同时,你也可以限制container只能访问一些指定的设备。下面的命令将允许container只访问一些特定设备:

       $ sudo docker run --device=/dev/snd:/dev/snd ...

  默认情况下,container拥有对设备的读,写,创建设备文件的权限。使用:rwm来配合--device,你可以控制这些权限。


 $ sudo docker run --device=/dev/sda:/dev/xvdc --rm -it ubuntu fdisk  /dev/xvdc

    $ sudo docker run --device=/dev/sda:/dev/xvdc:r --rm -it ubuntu fdisk  /dev/xvdc
    You will not be able to write the partition table.

    $ sudo docker run --device=/dev/sda:/dev/xvdc:w --rm -it ubuntu fdisk  /dev/xvdc
        crash....

    $ sudo docker run --device=/dev/sda:/dev/xvdc:m --rm -it ubuntu fdisk  /dev/xvdc
    fdisk: unable to open /dev/xvdc: Operation not permitted

 

  使用--cap-add和--cap-drop,配合--privileged,你可以更细致的控制container。默认使用这两个参数的情况下,container拥有一系列的内核修改权限。


这两个参数都支持all值,如果你想让某个container拥有除了MKNOD之外的所有内核权限,那么可以执行下面的命令:

 $ sudo docker run --cap-add=ALL --cap-drop=MKNOD ...

  

如果需要修改网络接口数据,那么就建议使用--cap-add=NET_ADMIN,而不是使用--privileged。

$ docker run -t -i --rm  ubuntu:14.04 ip link add dummy0 type dummy
RTNETLINK answers: Operation not permitted
$ docker run -t -i --rm --cap-add=NET_ADMIN ubuntu:14.04 ip link add dummy0 type dummy

  

如果要挂载一个FUSE文件系统,那么就需要--cap-add和--device了。


$ docker run --rm -it --cap-add SYS_ADMIN sshfs sshfs sven@10.10.10.20:/home/sven /mnt
fuse: failed to open /dev/fuse: Operation not permitted

$ docker run --rm -it --device /dev/fuse sshfs sshfs sven@10.10.10.20:/home/sven /mnt
fusermount: mount failed: Operation not permitted

$ docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse sshfs

成功运行进入到容器内部
# sshfs sven@10.10.10.20:/home/sven /mnt
The authenticity of host '10.10.10.20 (10.10.10.20)' can't be established.
ECDSA key fingerprint is 25:34:85:75:25:b0:17:46:05:19:04:93:b5:dd:5f:c6.
Are you sure you want to continue connecting (yes/no)? yes
sven@10.10.10.20's password:
root@30aa0cfaf1b5:/# ls -la /mnt/src/docker
total 1516
drwxrwxr-x 1 1000 1000   4096 Dec  4 06:08 .
drwxrwxr-x 1 1000 1000   4096 Dec  4 11:46 ..
-rw-rw-r-- 1 1000 1000     16 Oct  8 00:09 .dockerignore
-rwxrwxr-x 1 1000 1000    464 Oct  8 00:09 .drone.yml
drwxrwxr-x 1 1000 1000   4096 Dec  4 06:11 .git
-rw-rw-r-- 1 1000 1000    461 Dec  4 06:08 .gitignore
复制代码

4.linux权能
1,基本概念
传统UNIX的访问控制模型非常简单,就是“超级用户对普通用户”模型。在这种模型中,一个进程或帐户要么什么都能做即具有全部的系统权限,要么几乎什么也不能做即只有很小的权限,这取决于进程的UID。例如,如果一个进程需要加载/卸载内核模块以及管理文件系统等操作时,就需要完全的root权限。很显然这样做对系统安全存在很大的威胁。
2,进程权能
Linux是如何使用POSIX capabilities代替传统的信任状模型的?每个进程有三个和能力有关的位图:inheritable(I)、permitted(P)和effective(E),对应进程描述符 task_struct(include/linux/sched.h)里面的cap_effective, cap_inheritable, cap_permitted。每种能力由一位表示,1表示具有某种能力,0表示没有。
 cap_effective。当一个进程要进行某个特权操作时,操作系统会检查 cap_effective的对应位是否有效,而不再是检查进程的有效UID是否为0。例如,如果一个进程要设置统的时钟,Linux的内核就会检查 cap_effective的CAP_SYS_TIME位(第25位)是否有效,
 cap_permitted表示进程能够使用的能力。在cap_permitted中可以包含cap_effective中没有的能力,这些能力是被进程自己临时放弃的,也可以说cap_effective是cap_permitted的一个子集。进程放弃没有必要的能力对于提高安全性大有助益。例如,ping只需要CAP_NET_RAW,如果它放弃除这个能力之外的其它能力,即使存在安全缺陷,也不会对系统造成太大的损害。
 cap_inheritable表示能够被当前进程执行的程序继承的能力。
能力 编号 解释
CAP_CHOWN 0 允许改变文件的所有权
CAP_DAC_OVERRIDE 1 忽略对文件的所有DAC访问限制
CAP_DAC_READ_SEARCH 2 忽略所有对读、搜索操作的限制
CAP_FOWNER 3 如果文件属于进程的UID,就取消对文件的限制
CAP_FSETID 4 允许设置setuid位
CAP_KILL 5 允许对不属于自己的进程发送信号
CAP_SETGID 6 允许改变组ID
CAP_SETUID 7 允许改变用户ID
CAP_SETPCAP 8 8 允许向其它进程转移能力以及删除其它进程的任意能力
CAP_LINUX_IMMUTABLE 9 允许修改文件的不可修改(IMMUTABLE)和只添加(APPEND-ONLY)属性
CAP_NET_BIND_SERVICE 10 允许绑定到小于1024的端口
CAP_NET_BROADCAST 11 允许网络广播和多播访问
CAP_NET_ADMIN 12 允许执行网络管理任务:接口、防火墙和路由等,详情请参考/usr/src/linux/include/linux/capability.h文件
CAP_NET_RAW 13 允许使用原始(raw)套接字
CAP_IPC_LOCK 14 允许锁定共享内存片段
CAP_IPC_OWNER 15 忽略IPC所有权检查
CAP_SYS_MODULE 16 插入和删除内核模块
CAP_SYS_RAWIO 17 允许对ioperm/iopl的访问 
CAP_SYS_CHROOT 18 允许使用chroot()系统调用
CAP_SYS_PTRACE 19 允许跟踪任何进程
CAP_SYS_PACCT 20 允许配置进程记帐(process accounting)
CAP_SYS_ADMIN 21 允许执行系统管理任务:加载/卸载文件系统、设置磁盘配额、开/关交换设备和文件等。详情请参考/usr/src/linux/include/linux/capability.h文件。
CAP_SYS_BOOT 22 允许重新启动系统
CAP_SYS_NICE 23 允许提升优先级,设置其它进程的优先级//
CAP_SYS_RESOURCE 24 忽略资源限制
CAP_SYS_TIME 25 允许改变系统时钟
CAP_SYS_TTY_CONFIG 26 允许配置TTY设备
CAP_MKNOD 27 允许使用mknod()系统调用
CAP_LEASE 28 Allow taking of leases on files

5.使用主机网络栈
 host 网络实际上和宿主机共享了同一 Network Namespace。

6.实例

需要在docker里面获取usb的状态和数据

使用如下命令:

docker run --rm --device /dev/snd:/dev/snd:rwm --device-cgroup-rule="c 189:*rwm" 

--cap-add=SYS_ADMIN -v /dev:/dev --network=host -it <img id> /bin/bash

参数--device-cgroup-rule,可以添加你需要的规则 比如'c 13:* rwm' 这里的13是设备的major number, 那么在容器里面通过udev的规则执行添加/删除设备的脚本比如mknod/rm, 就可以实现动态添加和删除设备的功能啦。
       


posted @ 2020-11-27 17:54  luoyuna  阅读(3837)  评论(0编辑  收藏  举报