- docker的安全主要有三个方面,内核的namespace和控制组机制提供的容器内在安全,程序本身的安全,内核的加强机制
- 内核命名空间 通过docker run启动一个容器时,在后台docker为容器创建了一个独立的命名空间和控制组集合,在容器中运行的进程不会被其他进程和容器发现
- 控制组 负责实现资源的审计和限制,不负责隔离容器之间相互访问
- docker服务端的防护 docker服务的运行需要root权限,docker运行主机和容器间共享文件夹,防止容器共享主机的关键目录。将容器的root用户映射到本地主机的非root用户,防止容器用户提权,允许docker服务端在非root权限运行
内核能力机制 可以提供细粒度的权限访问控制,
- docker底层实现
- 核心技术包括linux的命名空间namespace、控制组control groups、union文件系统和容器格式
- linux os的虚拟化 物理资源的虚拟化,是lxc linux container的基础
- 虚拟内存,为了满足内存不足,利用硬盘虚拟出一块逻辑内存,被称为交换空间swap,内核会将暂时不用的内存块信息放到swap;
- 分时调度,每个进程可以获得cpu
- namespace 权限隔离,非物理资源的虚拟化,如用户权限、网络协议、文件系统等,是对全局资源的一种封装隔离
- 用来隔离linux内核资源的方式,通过把一个或多个进程的相关资源放到一个namespace中,保证进程间的隔离
- 支持8中全局资源的虚拟化,比如cgroup、ipc 共享内存和信号量、network 网络资源,如协议栈 网络设备 防火墙 路由表 端口等、mount 独立的目录层次、 pid 有自己的进程号、time 启动时间、 user 有自己的用户权限管理机制,如独立的uid、uts 独立的主机信息
- 用户可以创建指令类型的namespace,并将程序放入该namespace中运行,表示从当前的系统运行环境中隔离出一个进程的运行环境,linux会默认创建一个root namespace
- control groups(cgroups) 资源分配,是linux内核提供的一种限制进程组所使用的物理资源的机制。
- 每一组进程就是一个cgroups,可以配置cpu、内存的上限,从而限制容器的资源使用
- 基本架构
- docker采用了cs架构,包括客户端和服务端,docker守护进程作为服务端接收来自客户端的请求,并处理,比如创建、运行、分发容器等。客户端和服务端既可以在一台机器上,也可以通过socker或rest接口进行通信。
- docker daemon进程一般在宿主机主机后台运行
- 命名空间 namespace,每个容器都有自己的命名空间,容器之间运行彼此互不影响
- pid namespace,不用用户的进程就是通过pid来隔离的 。所有的lxc进程在Docker中的父进程为Docker进程,每个LXC有自己的命名空间
- net namespace,每个net命名空间有自己独立的网络设备,ip地址,路由表,/proc/net目录,从而隔离每个容器的网络。Docker默认采用veth pair的方式,将容器的虚拟网卡eth0同host上的docker网桥docker0连接在一起
- ipc namespace,进程间交互方法,interprocess communication,包括信号量、消息队列和共享内存等。容器的进程间交互实际还是宿主机上具有相同pid命名空间中的进程间交互
- mount namespace 允许不同namespace的进程看到的文件结构不同
- uts namespace unix time-sharing system,允许每个容器拥有独立的hostname和domain name,使其在网络上可以被视作一个独立的节点而非主机上的一个进程
- user namespace,每个容器可以有不同的用户和组id
- 控制组 cgroups,对共享资源进行隔离、限制、审计,避免多个容器对系统资源竞争,可以对容器的内存、cpu、io进行限制
- 联合文件系统 unionfs,是一种分层、轻量级并且高性能的文件系统,是docker镜像的基础
- 他支持对文件系统的修改作为一次提交来一层层的提价,同时可以将不同目录挂载到同一个虚拟文件系统下
- 镜像可以通过分层来继承,基于基础镜像可以制作其他镜像
- 不同docker容器可以共享一些基础的文件系统层,再加上自己的存储层
- 容器格式 lxc->libcontainer->runc / containerd
- 网络 docker的网络实现其实是利用了linux上的net namespace和虚拟网络设备 veth pair
- veth pair,virtual ethernet pair,是一个成对的端口,所有从一段进入的数据包都会从另一端出来,利用他,可以将两个net namespace连接起来
- bridge veth pair打破了net namespace的限制,实现了不同net之间的通信,但是缺陷就是只能实现两个网络接口之间的通信,多个网络接口就需要bridge。
- 要实现网络通信,机器至少需要一个网络接口(物理接口或虚拟接口)来收发数据包,此外,如果不同子网间要进行通信,还需要路由机制
- Docker的网络接口默认都是虚拟接口,转发效率高,linux通过内核中进行数据复制来实现虚拟接口之间的转发,看似一个正常的一台网卡,不需要真正同外部网络设备通信
- 创建网络参数
docker创建一个容器的时候,会执行如下操作:
-
-
-
- 创建一对虚拟接口,一端在宿主机,一端在容器内;
- 主机的接口桥接到网桥docker0或其他网桥中,并具有唯一的名字vethXXX
- 容器的接口名字为eth0
- 从网桥的可用ip地址中获取一个空闲的分配给容器的eth0,并配置默认路由到桥接网卡vethXXX
-
-
完成这些操作之后,容器就可以通过eth0虚拟网卡连接其他容器或网络
-
-
- docker run的时候可以使用 -- net 参数来指定容器的网路配置,有4个可选值:
- --net=bridge,使用默认的docker网桥
- --net=host ,告诉docker不要讲容器网络放到隔离的命名空间中,使用宿主机的网络,拥有完全的宿主机接口访问权限,容器进程可以跟主机其他root进程一样打开低范围的端口,可以访问本地网络服务,还可以影响主机系统,比如重启主机
- --net=container:NAME_or_ID,让Docker将新建容器的进程放到一个已存在容器的网络栈中,新容器有自己的文件系统、进程列表和资源限制,但是会和已存在容器共享IP和端口等网络资源,通过lo环回接口通信
- --net=none 让Docker将新容器放到隔离的网络栈中,但是不进行网络配置
- docker run的时候可以使用 -- net 参数来指定容器的网路配置,有4个可选值:
-
标签:容器,namespace,安全,linux,进程,docker,net,底层 From: https://www.cnblogs.com/weizhenlu/p/17059697.html