群组信息 私有

administrators

成员列表

解决Mac上VirtualBox 虚拟机网络无法连通问题

最近在使用Mac上的VirtualBox 创建出的虚拟机做K8S相关的开发工作, 物理机有时重启后无法连接到虚拟机当中,ICMP拒绝, 但是在VM 内部以及VM间网络通信都是正常的。重启Mac后问题可以解决,但是不是解决问题之道,经过排查,发现Mac上的到虚拟机hostonly 网络的路由丢失,导致连接失败

查看当前物理机上的hostonly 网卡信息

$ VBoxManage list hostonlyifs
Name: vboxnet0
GUID: 786f6276-656e-4074-8000-0a0027000000
DHCP: Disabled
IPAddress: 192.168.50.1
NetworkMask: 255.255.255.0
IPV6Address:
IPV6NetworkMaskPrefixLength: 0
HardwareAddress: 0a:00:27:00:00:00
MediumType: Ethernet
Wireless: No
Status: Up
VBoxNetworkName: HostInterfaceNetworking-vboxnet0

Name: vboxnet1
GUID: 786f6276-656e-4174-8000-0a0027000001
DHCP: Disabled
IPAddress: 192.168.59.1
NetworkMask: 255.255.255.0
IPV6Address:
IPV6NetworkMaskPrefixLength: 0
HardwareAddress: 0a:00:27:00:00:01
MediumType: Ethernet
Wireless: No
Status: Down
VBoxNetworkName: HostInterfaceNetworking-vboxnet1

Name: vboxnet2
GUID: 786f6276-656e-4274-8000-0a0027000002
DHCP: Disabled
IPAddress: 192.168.99.1
NetworkMask: 255.255.255.0
IPV6Address:
IPV6NetworkMaskPrefixLength: 0
HardwareAddress: 0a:00:27:00:00:02
MediumType: Ethernet
Wireless: No
Status: Down
VBoxNetworkName: HostInterfaceNetworking-vboxnet2

添加dhcp server

VBoxManage dhcpserver modify --ifname vboxnet0 --ip 192.168.50.2 --netmask 255.255.255.0 --lowerip 192.168.50.100 --upperip 192.168.50.199 --enable

查看虚拟机网络网关的路由信息

$ route get 192.168.50.1
route to: 192.168.50.1
destination: default
mask: default
gateway: 192.168.1.1
interface: en0
flags: <UP,GATEWAY,DONE,STATIC,PRCLONING>
recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire
0 0 0 0 0 0 1500 0
可以看到此网络的网关走到了192.168.1.1 此地址为Mac机器的网关,所以到该虚拟网络的流量都会通过gw 出去,因此也就到达不了虚拟机内部

添加到虚拟网络地址段的路由

$ sudo route -nv add -net 192.168.50 -interface vboxnet0 2.2.2 /Users/jiangytcn

u: inet 192.168.50.0; u: link vboxnet0:a.0.27.0.0.0; u: inet 255.255.255.0; RTM_ADD: Add Route: len 140, pid: 0, seq 1, errno 0, flags:<UP,STATIC>
locks: inits:
sockaddrs: <DST,GATEWAY,NETMASK>
192.168.50.0 vboxnet0:a.0.27.0.0.0 255.255.255.0
add net 192.168.50: gateway vboxnet0

$ route get 192.168.50.114
route to: 192.168.50.114
destination: 192.168.50.0
mask: 255.255.255.0
interface: vboxnet0
flags: <UP,DONE,CLONING,STATIC,PRCLONING>
recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire
0 0 0 0 0 0 1500 -438
此时可以看到,到该虚拟网络的地址都通过vboxnet0

$ ping 192.168.50.115
PING 192.168.50.115 (192.168.50.115): 56 data bytes
64 bytes from 192.168.50.115: icmp_seq=0 ttl=64 time=0.287 ms
^C
--- 192.168.50.115 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.287/0.287/0.287/0.000 ms

发布在 Blogs
CloudStack: 线上系统设置debug模式以及子工程编译

此文原写于 12 February 2014, 当时刚做CloudStack 相关开发不久,由于项目需要,需要线上对环境进行调试。CloudStack 本身是Java 编写,可以运行于tomcat 容器当中, 通过对tomcat的配置,可以进行调试

编辑Tomcat
根据tomcat安装的具体情况,进行修改。默认是/usr/sbin/tomcat6
添加参数 -server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8787 到此启动文件当中,大致添加后如下

35 -Djava.io.tmpdir="$CATALINA_TMPDIR"
36 -Djava.util.logging.config.file="${CATALINA_BASE}/conf/logging.properties"
37 -Djava.util.logging.manager="org.apache.juli.ClassLoaderLogManager"
38 -server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8787 \

重启tomcat 容器,之后按照一般的eclipse debug 模式连接进行调试

编译单独的子工程

在项目开发过程当中,对某一个组件进行修改是再正常不过的了,CloudStack 是以maven 进行工程组装打包发布的,以cloud-server为例,如果我们想对修改后的工程,使其能够生效,可以单独编译该工程后,将编译发布后的jar文件替换原有的文件,重启管理节点后即可生效
cd ~/cloudstack4.1.0 mvn clean mvn -pl :cloud-server
在终端可以看到编译过程,最后可以看到如下信息

Total time: 3:01.915s
Finished at: Wed Feb 12 14:56:24 CST 2014
Final Memory: 26M/233M

将新编译后的jar 文件替换原有的 cloud-server-4.1.0.jar, 重启管理节点。


版本信息

软件 版本
CloudStack 4.1.0
tomcat 6
发布在 Blogs
CloudStack: VM Failes to start with error: VDI not available

在使用cloudstack的过程中可能会遇到如下的问题, ssh登录到虚拟机内部,执行关机命令(shutdown -h now), 在NFS backend下的Vm出现通过CloudStack无法启动的问题

产生原因
Xenserver 与存储设备或者Lun失去连接

解决方法
从CloudStack的管理节点中查找出该虚拟机的VDI 设备的编号(UUID)
日志文件地址默认是 /var/log/cloud/management/management-server.log, 可能的VDI UUID 值为 6f97582c-xxxx-xxxx-xxxx-9aa5686bcbd36. 并会伴有类似 VM are failing to start with “errorInfo: [SR_BACKEND_FAILURE_46, The VDI is not available 这样的日志记录。

登录到Xenserver 中, 执行以下命令

查找出该UUID 对应的vid 设备的的信息, 包含sr-uuid 以及name-label 信息
xe vdi-list uuid=<日志文件中查找出的VDI uuid> params=sr-uuid, name-label
xe vdi-forget uuid=<日志文件中查找出的VDI uuid>
xe sr-scan uuid=<SR uuid>
xe vdi-param-set uuid=< 日志文件中查找出的VDI uuid> name-label=< 之前查找出的name-label >

重启cloudstack 管理节点来使数据同步


版本信息

软件 版本
CloudStack 4.2.1
Xenserver 6.2.0
发布在 Blogs
Windows 2016 server 单机版配置ldaps 以及ubuntu 客户端ssl 连接配置

Windows 2016 server上配置Active Directory 以及Domain Controller,CA 并启用ldaps认证功能

  1. Windows 2016 安装
    通过微软官网下载iso 镜像进行安装,下载后有180的试用期。注意安装时选择带有桌面功能的数据中心版本。
    具体过程省略, 可自行搜索

  2. AD 安装配置
    系统启动后进行ad的安装配置,安装配置过程没有特殊之处。

  3. CA 安装以及配置
    具体过程省略。

  4. 证书导出
    需要注意的是,到处的是AD server的证书

  5. Ubuntu 客户端配置

    1. 安装OpenSSL 以及Ca 管理工具
      apt update && apt install openssl ca-certifcates ldap-utils

    2. 更新CA database
      mkdir /usr/share/ca-certificates/devbox/
      将导出的server的证书上传至上述创建的目录中
      编辑ca配置,加载新的证书

      root@a9ad14a3288f:/# tail -n 2 /etc/ca-certificates.conf
      mozilla/thawte_Primary_Root_CA_-_G3.crt
      devbox/server_certificate.cer

      root@a9ad14a3288f:/# update-ca-certificates
      Updating certificates in /etc/ssl/certs...
      1 added, 0 removed; done.
      Running hooks in /etc/ca-certificates/update.d...
      done.

      验证证书配置

      openssl s_client -connect WIN-2PHSJD5NH12.ad.devbox.int:636 -showcerts

      通过ldaps 连接AD server

      root@a9ad14a3288f:/# ldapsearch -x -H ldaps://WIN-2PHSJD5NH12.ad.devbox.int -D 'administrator@ad.devbox.int' -w 'Passw0rd' -b "DC=ad,dc=devbox,dc=int" "(objectclass=user)" dn

发布在 Blogs
K8S Ingress Controller 之 traefiker

关于K8S的Ingress Controller, 顾名思义,是负责处理Ingress请求的模块。如果熟悉CloudFoundry的话,可以把它想像成Gorouter的功能,由于在PaaS/CaaS中,每一个业务后端实际是由多个容器来支撑,如何将用户的请求按照一定的算法,round-robin 抑或是least-connection,分配到不同的容器当中,这个是Ingress Controller的作用。
关于K8S当中的Ingress 的定义,可以参考 官方文档

Traefik 其功能是HTTP层的方向代理以及负载均衡器,可以在其它的容器调度平台,如K8S、Mesos、Docker上部署微服务。本文主要介绍如何通过 traefik 在Minikube上配合 nip.io 为微服务提供访问服务。


前置条件

【1】 kubernetes 环境 本文以minikube 为例
【2】kubectl 客户端安装
【3】internet 访问权限

安装 traefik

在其官方文档中,提供了安装步骤,抽取了关键步骤,想要看详细介绍的,移步 ->

RBAC 配置

如果k8s cluster启用了RBAC之后,需要对Traefik 授权 ClusterRole 以及ClusterRoleBinding 来使用Kubernets 的API

kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-rbac.yaml

安装Traefik

关于DeploymentSet 以及 Deployment有以下的区别

  1. 相比较DaemonSet 而言,Deployment 有更好的扩展性,如果使用了DS,那么在每一个node上只有一个pod

  2. 通过taints tolerations, DS可以在专有的机器上运行Service.可以参考

  3. 除此之外, DS可以直接访问任意Node上面的80, 443 端口,但是如果使用Deployment的话,那么需要设置一个Service 对象.

通过DaemonSet 安装

kubectl apply -f https://raw.githubusercontent.com/containous/traefik/master/examples/k8s/traefik-ds.yaml

配置Ingress 并启用UI

Traefik 提供了webui供查看其上的配置信息

kubectl apply -f https://raw.githubusercontent.com/yacloud-io/k8s-hands-on/master/ingress-controller/traefik-ui.yml

通过浏览器访问 http://traefik-ui.192.168.99.100.nip.io/dashboard/#/

Treafik UI with nip.io

安装terrific 并为其配置ingress

terrific web server,访问后,会显示所运行的容器/宿主机的IP 地址信息

安装terrific deployment

kubectl apply -f https://raw.githubusercontent.com/yacloud-io/k8s-hands-on/master/ingress-controller/terrific-deployment.yml

为其配置Service
kubectl apply -f https://raw.githubusercontent.com/yacloud-io/k8s-hands-on/master/ingress-controller/terrific-service.yml

配置Ingress 规则
kubectl apply -f https://raw.githubusercontent.com/yacloud-io/k8s-hands-on/master/ingress-controller/nip.io-ingress.yml

在deployment的pod 启动后,访问 http://my-terrific.192.168.99.100.nip.io/ 查看结果

terrific ingress
刷新浏览器,可以看到访问到不同的容器上

总结

traefik作为K8S的负载均衡器,为其上部署的应用提供外部访问的能力。默认情况下,K8S提供了NodePort、LoadBalancer 的方式来访问,但是在IP资源有限的情况下,特别是以NodePort报露外部请求时,Worker 节点有时不是公网IP,用Traefik可以很方便的解决这个问题,并提供负载均衡。

发布在 Blogs
云磁盘加密之 LUKS

任何在云上部署的应用都离不开持久化盘或者说是数据盘,在的虚拟机的使用场景里面,云服务提供商都会提供这样的一个服务。很多人可能不会理解为什么我创建的虚拟机不可以直接在上面写数据,而需要单独的去创建额外的磁盘进行数据的读写。

以OpenStack为例,其虚拟机的配置由Flavor 来觉得,让我们来看下创建flavor 的属性是什么
OpenStack Flavor Details

可以看到其中定义了该VM的vCPU、内存以及root磁盘大小可以理解为sda。另外有一项比较特殊的是 ephemeral, 如果定义了该值后,在操作系统当中会额外的有一个存储设备sdb. 但是如果虚拟机所在的物理机或者由于删除该虚拟机的话,那么其上所写入的数据也会随之删除。所以有了个数据盘(Persistent Disk)的产生,该存储设备可以通过挂载的方式添加到虚拟机里面,OpenStack 里面有Cinder提供这样的服务,对于其它的云服务提供商来说,会有不同的服务。但是无论是那种,无论以什么协议添加到了虚拟机当中,其上面的数据如果不是人为的删除的话,可以放心使用。

虽然persistent disk 解决了数据存储持久化的问题,但是也随之带来了另外的问题。
其上存储的数据如何保护? 如果后端的存储服务器被黑客攻陷的话,那么其上的所有客户数据都会收到威胁, 如何防护云存储(对象 & 块存储)的安全变得直观重要。

下面提供一种简单的但是有效的方式进行数据盘加密,即使是云服务提供商也无法任意的查看你的数据。


Linux Unified Key Setup-on-disk-format (or LUKS) allows you to encrypt partitions on your Linux computer. This is particularly important when it comes to mobile computers and removable media. LUKS allows multiple user keys to decrypt a master key, which is used for the bulk encryption of the partition.

该方法主要通过Linux 提供的LUKS进行磁盘的加密, 其全称为 Linux Unified Key Setup-on-disk-format (or LUKS). 对于移动设备或者可插拔的设备来说尤其的重要。LUKS允许多个用户用其Key 去解密 Master的Key。
关于更多的介绍,请自行 Google Luks

实验步骤

ubuntu@ubuntu-xenial:~$ sudo shred -v --iterations=1 /dev/sdc
sudo: unable to resolve host ubuntu-xenial
shred: /dev/sdc: pass 1/1 (random)...

ubuntu@ubuntu-xenial:~$ sudo cryptsetup --verbose --verify-passphrase >luksFormat /dev/sdc
sudo: unable to resolve host ubuntu-xenial

WARNING!
= =======
This will overwrite data on /dev/sdc irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase:
Verify passphrase:
Command successful.

需要注意的是在确认时需要大写的 YES

ubuntu@ubuntu-xenial:~$ sudo cryptsetup luksOpen /dev/sdc encrypted
sudo: unable to resolve host ubuntu-xenial
Enter passphrase for /dev/sdc:

任何要操作该设备的操作都要之前输入的秘钥

ubuntu@ubuntu-xenial:~$ ls -l /dev/mapper/ | grep encrypted
lrwxrwxrwx 1 root root 7 Sep 21 04:27 encrypted -> ../dm-0

ubuntu@ubuntu-xenial:~$ sudo mkfs.ext4 /dev/mapper/encrypted
sudo: unable to resolve host ubuntu-xenial
mke2fs 1.42.13 (17-May-2015)
Creating filesystem with 261632 4k blocks and 65408 inodes
Filesystem UUID: b84e4ca5-44f7-453a-a14b-0f0115c9913e
Superblock backups stored on blocks:
32768, 98304, 163840, 229376

Allocating group tables: done
Writing inode tables: done
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

磁盘挂载

ubuntu@ubuntu-xenial:~$ sudo mount /dev/mapper/encrypted /mnt/
sudo: unable to resolve host ubuntu-xenial
ubuntu@ubuntu-xenial:~$ df -h | grep mnt
/dev/mapper/encrypted 990M 1.3M 922M 1% /mnt


通过👇的vagrant file 创建有附加磁盘的虚拟机供实验

 file_to_disk = 'encrypted-disk.vdi'
 
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"
  config.vm.provider "virtualbox" do |vb|
    vb.gui = false
    vb.memory = "1024"
    vb.name = "luks"
  
    if !File.exist?(file_to_disk)
       vb.customize ['createhd', '--filename', file_to_disk, '--size',  1024]
    end
    vb.customize ['storageattach', :id, '--storagectl', 'SCSI', '--port', 2, '--device', 0, >'--type', 'hdd', '--medium', file_to_disk]
  end

  config.vm.provision "shell", inline: <<-SHELL
       apt-get update
       apt-get install -y ubuntu-desktop
  SHELL
 end

参考

Redhat Docs

发布在 Security
User Namespaces 加固Docker container 宿主机

Docker 容器以及其所运行的宿主机的安全防护是维护可信的服务的关键。 以专业的安全领域的DevOps角度来看, 对container 以及container 的调度平台想OpenShift、Docker Swarm以及如日中天的K8S进行安全防护其实很简单。 主要是因为在技术革新如此快速的时代,目标变化的也如此频繁。

由于新技术的发展,其产生的许多挑战需要去解决,在解决这些问题的方法当中,有一项是有着重大意义,即在docker container当中对其宿主机的 UID和GID 映射到不同的值。

有一些没有威胁性的配置的变更,通过一个不是那么新的技术User Namespaces 可以将在Container当中root user 与Host的root user进行隔离。这一特性在2016年2月前后发布的Docker 1.10 版本中已经可以使用。之所以称其为“不是那么新的技术” 是因为任何一个从事容器化以及调度层系统开发的人知道,一个功能如果发布了6个月以上就会被认为是一个”古董“ ;)

实现细节

以下会通过一些实验来验证 host 级别,确切来说是内核级别的 User Namespace 安全防护方法

首先, 在谈到对Docker 容器或者其它平台的容器进行安全防防护时,有2个常见的相关联的术语。
也许你会想到的是Cgroup,cgroup 可以将进程在内核当中进行限定。我所说的限定指的是限制其能占有系统资源的能力,包括CPU,RAM 以及 IO

通过namespace 来控制一个进程其对系统资源的可视度并不会令你产生疑惑 。也许你并不想令某一个进程可以访问所有的网络协议栈或者其它在进程表当中的进程

在接下来的实验当中,会选取Docker 作为容器的运行时环境。本文会对user和group在host当中的container进行重新的映射。host指的时运行docker 后台守护进程的服务器。
更进一步,实验会通过改变容器进程对其资源的可视度来防护Host。

对user和group的重映射即对user namespace 的操作来改变用户对系统当中其它进程的可视度。如果想更深入的了解其内部机制,没有什么比用户手册更适合不过的了。
“User Namespace 对安全相关的标示、属性进行隔离,特别是User Id 和Group ID...”。
“在一个user namespace当中的进程所属的User以及Group可以与其有所不同。特别是,进程在user namespace外可以有普通的非特权user 同时在user 命名空间中有特权用户0,也就是在内部可以有所有的操作权限,但是在外部只能进行非特权相关的操作”。

下表提供了我们通过user namespace 想要实现的隔离

username space 说明

图片来源 https://endocode.com/blog/2016/01/22/linux-containers-and-user-namespaces/

再来说明下我们想要达成的目标, 将host 上的超级用户(其user id 是 UID = 0)与容器当中的root 用户进行隔离。

通过以上变更后,我们会得到神奇的效果,即使容器当中的应用 以root 用户去运行 并且其UID 是0,但是在现实当中并不会与host的超级用户有任何关联,也不会对系统造成影响。

你可能会觉得这无足轻重。但是,可以想象以下这样的场景,如果容器的的权限被贡献了,因为使用了这一技术,攻击者无法在跳出了容器后进行权限的升级以控制宿主机上的其它服务, 也就无法控制宿主机。


对docker 守护进程进行修改

首要的条件是启用Docker 守护进程的 userns-remap

值得指出的是,在现阶段你需要使用K8S V1.5 以上的版本以免由于使用了user namespaces 会对network namespace 进行破坏。从我观察到的是,K8S本身并不会产生问题,但是这是Network Namespace 的问题。

另外,由于docker 版本的变化,对docker daemon添加参数有可能有所变化。如果你所使用的版本滞后1个月以上的化,那么十分的不幸。对于持续的更新是有代价的;向后兼容性或者说会耗费大量的精力。对于我来说,这并不是问题毕竟技术很fantastic。

开始实验

第一步是使docker 守护进程通过json 配置文件来启动, 而不是通过unix 类型的配置。
添加 DOCKER_OPTS 到文件 /etc/default/docker 中。通过这种方式比通过修改 systemd 的unit 文件会简单的多。

在所提到的文件当中,添加下面的配置,

DOCKER_OPTS="--config-file=/etc/docker/daemon.json"

没错 /etc/docker/daemon.json 文件中包含是json类型的配置文件,简单起见,省略了其它的配置信息,添加了--userns-remap 选项

{

"userns-remap": "default"

}

对于老得版本或者说是不同的linux 发新版 或者是个人的偏好,也可以直接添加这个参数DOCKER_OPTS="--user-remap=default"至文件/etc/default/docker 当中而不使用json 配置文件

通过以下方式启动docker 守护进程

$ dockerd --userns-remap=default

希望通过以上的步骤对你来说是生效, 如果以上的配置对你来说不起作用还是Google吧


到这一阶段,会注意到在上面的例子当中为了方便起见default 作为重新映射的用户。稍后我们会接着讨论。现在,你可以跳转到其它必须的配置参数来启用user namespace。

如果你坚持像我上面所用的default 作为参数的化, 你应该添加以下的配置到下面的文件当中。对于Reahat 相关的发行版, 在重启按以上的配置后的docker daemon以前修改下列文件。对于其它的发行版,此文件有可能不存在,通过 echo 或者其它的命令创建此文件。

echo "dockremap:123000:65536" >> /etc/subuid

echo "dockremap:123000:65536" >> /etc/subgid

按照不同的发行版执行相关的命令 重启docker daemon,如

$ systemctl restart docker

  • 注意: 此种启动方式只适用于修改了daemon.json文件

核心内容

通过在上面的文件当中添加subordinate dockerremap user 和group 配置, 意思是说需要将容器的user ID和Group ID映射到宿主机的从123000到65536当中的一个值。理论上来说可以用65536 作为以上的起始值,但是实际来看这有所不同。在目前的版本当中, Docker 仅对第一个,UID进行映射。Docker 官方生成会在以后的版本中进行改进。

上面说过会对所使用的default 的配置进行说明。这个值是是docker 内部可以像我们所看到的那样使用用户名和组名dockerremap。可以使用任意的名,但是要在重启docker daemon 之前对文件 /etc/subuid/etc/subgid进行正确的修改。

其它的更改

注意,需要重新的拉取docker 镜像文件 之后会在宿主机的新的子目录进行更新。

如果查看 /var/lib/docker 目录后,你会发现镜像存储目录由我们所熟悉的UID.GID 数字格式命名。

$ ls /var/lib/docker

drwx------. 9 dockremap dockremap 4096 Nov 11 11:11 123000.123000/

从现在开始,如果像以下方式这样进入容器内部,你会发现所运行的应用程序是以root 和UID 为0 的方式运行。
运行容器

ubuntu@ubuntu-xenial:~$ sudo docker run --rm -d redis
sudo: unable to resolve host ubuntu-xenial
Unable to find image 'redis:latest' locally
latest: Pulling from library/redis
065132d9f705: Downloading 5.291MB/30.11MB
be9835c27852: Download complete
065132d9f705: Downloading 17.43MB/30.11MB
ea1f878b621a: Downloading 5.799MB/8.268MB
065132d9f705: Pull complete
be9835c27852: Pull complete
f4a0d1212c38: Pull complete
ea1f878b621a: Pull complete
7a838393b4b9: Pull complete
9f48e489da12: Pull complete
Digest: sha256:8a54dcc711406447b3631a81ef929f500e6836b43e7d61005fa27057882159da
Status: Downloaded newer image for redis:latest
4eb610618d04254245bbe29f3523641f2c4c1c9731e4c139f9e68a7e1c47de16

$ docker exec -it 4eb610618d04 bash

在物理机上,可以通过ps 命令来查看尽管该容器是以UID 为的0的用户来运行,但是实际上在物理机上,其值是UID=123000。

$ ps -ef | grep redis

如果系统支持的话,可以通过在宿主机和容器当中运行以下命令来获得相应的UID相关信息。

$ ps -eo uid,gid,args

限制条件

和所有非原生的安全方案一样,也有一些取舍,然而对于User namespace来说不那么的繁重。

注意,通过以上的配置后,在启动容器时就无法使用--net=host 或者使用--pid=host来共享 PID 。而且,你不能使用--read-only 的容器,因为对于一个使用了User Namespace的无状态的容器来说没有什么作用。

此外,--privileged 模式的参数也无法使用,并且需要确保任何所挂载的文件系统,如NFS,允许UIDsGIDs访问

对于像RedHat及其衍生的发行版,如Centos, 需要在boot loader中开启kernel的配置来启用User Namespace,通过grubby 命令进行配置:

$ grubby --args="user_namespace.enable=1" --update-kernel="$(grubby --default-kernel)"

重启机器后使参数生效。

通过以下配置禁用该模式:

$ grubby --remove-args="user_namespace.enable=1"
--update-kernel="$(grubby --default-kernel)";

结束语

希望以上简单的配置能够对Docker 主机的安全防护有所帮助。

最后一点, 任何人都不想获取了超级用户访问权限攻击者潜伏在主机当中,经过数月的学习研究配置的漏洞,即APT(Advanced Persistent Threat)的情况发生. 当然,任何人都不想要这一结果, 但是这却在你毫不知情的情况下实实在在的发生。仅仅是因为你从Docker hub中拉取了一个没有更新有漏洞包的镜像。保持警惕!

On that ever so cheery note: Stay vigilant!


实验playback

环境信息

ubuntu@ubuntu-xenial:~$ uname -r
4.4.0-96-generic
ubuntu@ubuntu-xenial:~$ cat /etc/issue.net
Ubuntu 16.04.3 LTS

ubuntu@ubuntu-xenial:~$ docker --version
Docker version 17.06.2-ce, build cec0b72

参考

Introduction to User Namespaces in Docker Engine
Control and configure Docker with systemd
Its all about linux

发布在 Security

与 YACLOUD 的连接断开,我们正在尝试重连,请耐心等待