背景
etcd作为kubernetes的基础组件之一,在kubernetes集群中是以static pod的方式部署的,社区中的经典部署方式kubeadm,etcd都是用root 用户启动的,使用root用户启动赋予了容器过高的权限,存在很大的安全问题,所以本文介绍如何使用普通用户以static pod的方式部署etcd.
问题
- etcd的存储数据目录
--data-dir=/var/lib/etcd的ownership
etcd运行在container中,/var/lib/etcd目录作为存储etcd数据的目录是通过hostPath方式将主机目录挂载到对应的容器目录中。当etcd通过normal user的方式启动时,要保证volume的ownership在容器内部和外部是相同的,内外ownership不同,将会导致etcd 没有权限读写该目录同步数据。 - 不同的user namespace是相互隔离的
etcd部署在容器中,容器内部和主机分别在两个相互隔离的namespace中。
Kubernete 中pod的安全策略
kubernetes会对集群中的容器进行限制,限制不可信的容器,以免对系统或者其他容器造成影响。
按照作用的范围不同,分为以下三种规则对容器进行限制:
- Pod Security Policy(PSP):应用到集群中所有的pod和volume
- Security Context(Pod-level):应用到集群中的Pod
- Security Context(Container-level):仅应用到单个container中
Pod Security Policy
Pod Security Policy 简称PSP,是集群级别的安全策略,是kubernetes中的一种resource。当集群中开启了此功能,会自动的为集群的pod和volume设置Security Context。此外在etcd作为非root用户运行时,应该检查集群中的PSP是否有限制。
如何开启Pod Security Policy
在API server中的配置项--enable-admission-plugins中增加PodSecurityPolicy 参数
--enable-admission-plugins=NodeRestriction,PodSecurityPolicy
创建一个简单的PSP
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: example
spec:
privileged: false # Don't allow privileged pods!
# The rest fills in some required fields.
seLinux:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
volumes:
- '*'
重启API server服务,此时如果集群中没有创建出任何可用的policy,API server在阻止任何pod的创建。
Security Context(Pod-level)
Pod-level Security Context应用到Pod内所有容器,还会影响volume(包括fsGroup和selinuxOptions)。
apiVersion: v1
kind: Pod
metadata:
name: hello-world
spec:
containers:
# specification of the pod's containers
# ...
securityContext:
fsGroup: 1234
supplementalGroups: [5678]
seLinuxOptions:
level: "s0:c123,c456"
Security Context(Container-level)
Container-level Security Context仅应用到指定的容器上,并且不会影响Volume。比如设置容器运行在特权模式:
apiVersion: v1
kind: Pod
metadata:
name: hello-world
spec:
containers:
- name: hello-world-container
# The container definition
# ...
securityContext:
privileged: true
etcd是static pod,pod中只有一个container,所以我们选择在pod level配置Security Context。
如何通过normal user部署
- 在etcd image中添加normal user,使用normal user运行etcd.
目前社区中的etcd还是默认运行在root用户下,所以我们需要自己build etcd的binary,修改etcd的Dockerfile,在Dockerfile中创建一个特定的normal user,user在创建的时候我们需要指定一个ID,只有指定ID,我们才能在host上也创建出一个ID相同的user。
FROM alpine:latest
ADD etcd /usr/local/bin/
ADD etcdctl /usr/local/bin/
RUN mkdir -p /var/etcd/
RUN mkdir -p /var/lib/etcd/
# RUN groupadd -r etcd
# RUN useradd -r -g etcd etcd -u 2375
RUN adduser etcd -u 2375 -D
RUN chown -R etcd:etcd /var/etcd/ /var/lib/etcd/
# Alpine Linux doesn't use pam, which means that there is no /etc/nsswitch.conf,
# but Golang relies on /etc/nsswitch.conf to check the order of DNS resolving
# (see https://github.com/golang/go/commit/9dee7771f561cf6aee081c0af6658cc81fac3918)
# To fix this we just create /etc/nsswitch.conf and add the following line:
RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf
USER etcd
EXPOSE 2379 2380
# Define default command.
CMD ["/usr/local/bin/etcd", "--data-dir=/var/lib/etcd" ]
etcd的base image是alpine,添加user的命令与普通的Linux不太相同,见Dockerfile中注释
- 在host上创建与1中相同ID的user,并且创建好
/var/lib/etcd目录,将此目录的ownership修改为自己创建的normal user
useradd -U etcd -u 2375
chown -R etcd:etcd /var/lib/etcd/
- 在etcd的pod.json文件中添加Security Context配置
"securityContext": {
"privileged": true,
"runAsUser": 2375
}
接下来就可以通过etcd user部署etcd啦。









网友评论