欢迎访问我的博客,你的支持,是我最大的动力!

kubernetes权威指南笔记(二)

Docker 小马奔腾 233℃ 评论
目录:
[显示]

深入分析集群安全机制

集群安全必须考虑的目标
1、保证容器与其所在宿主机的隔离
2、限制容器给基础设施或其他容器带来的干扰
3、最小权限原则,限制单个组件的能力来限制它的权限范围
4、明确组件边界的划分
5、划分普通用户与管理员
6、在必要时允许将管理员权限赋给普通用户
7、允许拥有secret数据(keys/certs/passwords)的应用在集群中运行

ABAC 授权模式

api server启动参数 --authorization-policy-file=<file>

常见ABAC授权示例
- 允许alice用户对所有资源做任何操作
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"alice","namespace":"*","resource":"*","apiGroup":"*"}}
- kubelet可读取任意Pod
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"kubelet","namespace":"*",resource":"pods","readonly":true}}
- kebelet可以读写Event对象
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"kubelet","namespace":"*",resource":"events"}}
- bob只能读取projectCaribou中的Pod
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"bob","namespace":"projectCaribou",resource":"pods","readonly":true}}
- 任何用户都可对非资源类路径进行只读请求
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"group":"system:authenticated","readonly":true,"nonResourcePath":"*"}}
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"group":"system:unauthenticated","readonly":true,"nonResourcePath":"*"}}
添加了新的ABAC策略,需要重启api server生效

对service account授权
sa会自动生成一个abac用户名: system:serviceaccount:<namespace>:<serviceaccountname>
新命名空间的sa为:system:serviceaccount:<namespace>:default
- kube-system 下 default 拥有全部权限
{"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"system:serviceaccount:kube-system:default","namespace":"*",resource":"*","apiGroup":"*"}}

Webhook 授权模式

api server 启动参数添加 --authorization-webhook-config-file=<file> 该配置文件是kubeconfig格式
api server是用户,cluster是webhook服务端
--runtime-config=authorization.k8s.io/v1beta1=true
请求及响应报文格式(略)

RBAC 授权模式

kubeadm安装方式的默认选项
--authorization-mode=RBAC

四个顶级资源对象:Role ClusterRole RoleBinding ClusterRoleBinding
1、角色 Role
角色是一组权限的集合,权限都是许可形式的,不存在拒绝的规则
角色只能对命名空间内的资源进行授权

2、集群角色 ClusterRole
除了命名空间内资源管理能力,还可对集群范围的资源、非资源的路径、包含全部命名空间的资源进行管理

3、角色绑定 RoleBinding 和 集群角色绑定 ClusterRoleBinding
把角色绑定到目标上,绑定目标可以是用户、组或者Service Account

ClusterRoleBinding 中绑定角色只能是集群角色,用于对集群级别或所有命名空间都生效的授权

使用 / 分隔资源和下级资源,如
resources: ["pods","pods/log"]

可以限定到具体的资源,如
resources: ["configmap"]
resourceNames: ["my-configmap"]
# 限定到configmap中的my-configmap

对非资源路径进行限制
nonResourceURLs: ["/healthz","/healthz/*"]

默认角色和角色绑定
基础架构,对这些对象改动可能造成集群故障
所有默认的ClusterRole和ClusterRoleBinding 都会用标签 kubernetes.io/bootstrapping=rbac-defaults 标记
默认角色:
集群级别:cluster-admin
命名空间级别:admin edit view

使用kubectl命令快捷授权
# 在命名空间acme中为用户bob授权admin ClusterRole
kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=bob --namespace=acme
# 在命名空间acme中为名为myapp的授权view ClusterRole
kubectl create rolebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp --namespace=acme
# 在集群范围内为用户root授予 cluster-admin ClusterRole
kubectl create clusterrolebinding root-cluster-admin-binding --clusterrole=cluster-admin --user=root
# 在集群范围内为用户kubelet授予system:node ClusterRole
kubectl create clusterrolebinding kubelet-node-binding --clusterrole=system:node --user=kubelet
# 在集群范围内为名为myapp的sa授予view ClusterRole
kubectl create clusterrolebinding myapp-view-binding --clusterrole=view --serviceaccount=acme:myapp

RBAC和ABAC可并行认证

Admission Control
准入控制器插件列表
- AlwaysAdmit 弃用,允许所有请求
- AlwaysPullImages 适用于多租户共享一个集群时保障镜像安全
- AlwaysDeny 弃用,禁止所有请求
- DefaultStorageClass 添加默认存储类
- DefaultTolerationSeconds 设置默认容忍时间,默认5min
- DenyExecOnPrivileged 弃用,该功能已合并到 DenyEscalatingExec 中,限制在特权容器中执行命令
- DenyEscalatingExec 拦截所有exec/attach到特权容器的请求
- EventReateLimit 应对事件密集情况下对api server造成的洪水攻击
- ExtendedResourceToleration 自动为申请特定资源(有Taint的节点上)的pod加入Toleration定义
- ImagePolicyWebhook
- Initializers 动态准入控制,通过修改待创建资源的元数据完成对该资源的修改
- LimitPodHardAntiAffinityTopology 反亲和性调度策略,要求 topologyKey为kubernetes.io/hostname
- LimitRanger 可对没有资源请求的pod自动设置默认的资源请求
- MutatingAdmissionWebhook 变更符合要求的请求的内容,以串行方式执行
- NamespaceAutoProvision 若命名空间不存在,会自动创建命名空间
- NamespaceExists 若命名空间不存在将拒绝该请求
- NamespaceLifecycle
- NodeRestriction 限制kubelet对node和pod的修改行为
- OnwerReferencesPermissionEnforcement 保护metadata.ownerReferences字段
- PersistentVolumeLabel 弃用,自动根据云供应商添加region和zone标签
- PodNodeSelector 对节点选择器设置默认值或限制取值
- PersistentVolumeClaimResize
- PodPreset 用PodSelector选择pod,为符合条件的pod进行注入
- PodSecurityPolicy 对pod的安全策略进行控制
- PodTolerationRestriction 判断命令空间的Toleration
- Priority 确定优先级
- ResourceQuota 确保ns的资源配额使用不超标,应该放到最后一个
- SecurityContextDeny 禁用容器中定义的SecurityContext配置
- ServiceAccount
- StorageObjectInUseProtection 在新创建的pvc和pv中加入 kubernetes.io/pvc-protection或kubernetes.io/pv-protection
- ValidatingAdmissionWebhook

--enable-admission-plugins 控制器顺序无关(k8s 1.10及以上)
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota

其他

Service Account
spec.serviceAccountName

为pod里的进程提供必要的身份证明
/run/secrets/kubernetes.io/serviceaccount/token
/run/secrets/kubernetes.io/serviceaccount/ca.crt
/run/secrets/kubernetes.io/serviceaccount/namespace

ServiceAccount正常工作需要三个控制器的支撑
Admission Controller,Token Controller,ServiceAccount Controller

Secret

Secret的使用方式
- 在pod创建时,通过指定Service Account来自动使用该secret (api 鉴权)
- 挂载该secret到pod中
- 镜像下载时,通过 spec.imagePullSecrets引用

创建镜像仓库认证
docker login localhost:5000
输入用户名密码后,认证信息会写入 ~/.dockercfg 文件中
cat ~/.dockercfg | base64
将结果作为 data.dockercfg的内容

每个单独的secret不能超过1MB
secret更新事,必须删除旧pod创建新pod才会生效

PodSecurityPolicy

api server启动参数中需要在 --enable-admission-plugins 中添加 PodSecurityPolicy
开启该控制器后,默认不允许创建任何pod,需要创建PodSecurityPolicy策略和相应的BRAC授权策略,pod才能创建成功

# 查看
kubectl get psp xxx

PodSecurityPolicy配置
- 特权模式
-- privileged
- 宿主机资源
-- hostPID 共享宿主机进程空间
-- hostIPC 共享宿主机IPC命名空间
-- hostNetwork 网络命名空间
-- hostPorts 使用宿主机的端口号 可通过 hostPortRange设置允许的端口号范围
-- volumes 允许的存储卷类型 * 表示任意类型 包括:configMap,downwardAPI,emptyDir,persistentVolumeClaim,secret,projected
-- allowedHostPaths 允许使用的宿主机的hostPath路径,可通过 pathPrefix设置路径前缀
-- fsGroup 允许访问某些Volume的Group ID的范围,可为 MustRunAs,MayRunAs,RunAsAny
-- readOnlyRootFilesystem 要求容器运行的根文件系统是只读的
-- allowedFlexVolumes 对类型为flexVolume的存储卷,设置允许的驱动类型
- 用户和组相关
-- runAsUser 运行容器的用户ID范围,可为 MustRunAs,MustRunAsNonRoot,RunAsAny
-- runAsGroup 运行容器的Group ID范围,可为 MustRunAs,MustRunAsNonRoot,RunAsAny
-- supplementalGroups 设置容器可额外添加的Group ID范围,可为 MustRunAs,MayRunAs,RunAsAny
- 提权相关
-- allowPrivilegeEscalation 容器子进程是否可以提权,常在设置非root用户时
-- defaultAllowPrivilegeEscalation 设置allowPrivilegeEscalation的默认值,设置为disallow时,还可显式设置allowPrivilegeEscalation来指定是否允许提权
- linux能力相关
-- allowedCapabilities 可使用的linux能力列表,* 表示允许全部
-- requiredDropCapabilities 不允许使用的linux能力列表
-- defaultAddCapabilities 默认为容器添加的linux能力 如SYS_TIME
- selinux相关
-- seLinux 设置selinux参数,可为 MustRunAs,RunAsAny
- 其他
-- allowedProcMountTypes 允许的ProcMountTypes类型列表,可为 allowedProcMountTypes,DefaultProcMount
-- appArmor 对容器可执行程序的访问控制权限
-- seccomp 允许容器使用的系统调用的profile
-- sysctl 允许调整的内核参数

pod或container的securityContext中设置安全策略,如果pod和container级别都设置了相同的安全类型字段,将以container级别的为准

网络原理

IP-per-Pod 方案

linux 网络基础

命名空间

# 创建网络命名空间
ip netns add <name>
# 在命名空间中执行命令
ip netns exec <name> <command>
# 进入内部的shell界面 然后执行命令 退出exit
ip netns exec <name> bash

网络设备在命名空间中转移
NETIF_F_ETNS_LOCAL 属性值需为 off 才可转移
lo设备、vxlan设备、ppp设备、bridge设备是不可转移的;veth设备是可转移的

# 转移设备
ethtool -k br0 #netns-local: on 不可转移
ip link set br0 netns ns1

veth 设备对
# 创建 veth 设备对
ip link add veth0 type veth peer name veth1
# 查看刚创建的veth设备对
ip link show
# 将veth1移到另一个网络空间
ip link set veth1 netns netns1
# 在netns1中查看移入的veth1
ip netns exec netns1 ip link show
# 为veth设备分配地址
ip netns exec netns1 ip addr add 10.1.1.1/24 dev veth1
ip addr add 10.1.1.2/24 dev veth0
# 启动设备
ip netns exec netns1 ip link set dev veth1 up
ip link set dev veth0 up
# 两个网络空间可互通了
ping 10.1.1.1
ip netns exec netns1 ping 10.1.1.2
# 查看veth设备的对端
## 在命名空间 netns1中查询veth设备对端接口在设备列表中的序列号
ip netns exec netns1 ethtool -S veth1 #peer_ifindex: 5
## 再到另一端查看序列号为5的设备
ip netns exec netns2 ip link | grep 5

网桥
mac地址表默认超时时间为5min
linux网桥可以绑定若干个以太网设备,将它们桥接起来,此外它自身还可以有一个ip地址

# 新增网桥设备
brctl addbr xxxxx
# 将网卡与网桥连接起来
brctl addif xxxxx ethx
此时网卡会作为网桥的一个网口,处理链路层工作,网卡的ip地址会失效
ifconfig ethx 0.0.0.0
# 给网桥配置ip地址
ifconfig brxxx xxx.xxx.xxx.xxx

Netfilter / iptables
规则表优先级: RAW>MANGLE>NAT>FILTER

iptables -save 以命令的方式打印iptables内容
iptables -vnL 以另一种格式显示 Netfilter 表的内容

路由

路由表包括至少两张表 LOCAL 和 MAIN
# 查看 LOCAL 表内容
ip route show table local type local
# 查看路由表
ip route list
netstat -rn #标志 U-可达路由;G-网关

docker 网络

docker 四类网络模式
- host模式 --net=host
- container模式 --net=container:NAME_or_ID
- none模式 --net=none
- bridge模式 --net=bridge 默认

k8s 网络

CNI 网络模型

一个容器可以通过绑定多个网络插件加入多个网络中
CNI仅关注在创建容器时分配网络资源,在销毁容器时删除网络资源
CNI插件包括两种类型:CNI Plugin和IPAM Plugin
CNI Plugin负责为容器配置网络资源;IPAM Plugin负责对容器IP地址进行分配和管理
IPAM Plugin作为CNI Plugin的一部分,与CNI Plugin一起工作

CNI Plugin提供增加,删除,检查,版本查询

kubelet启动参数
--network-plugin="cni"
--cni-conf-dir CNI插件的配置文件目录,默认为 /etc/cni/net.d
--cni-bin-dir CNI插件的可执行文件目录,默认为 /opt/cni/bin

当前的插件有:Calico,Canal,Cilium,Contiv,Flannel,Romana,Weave Net等

k8s 网络策略

Network Policy 对Pod间的网络通信进行限制和准入控制
将Pod的Label作为查询条件,设置允许访问或禁止访问的客户端Pod列表;查询条件可作用于pod和namespace级别

策略控制器+策略
其中策略控制器由第三方网络组件提供,如Calico,Cilium,Kube-router,Romana,Weave Net

开源网络组件

Flannel
通过覆盖网络,将数据包原封不动地传递到目标容器内
创建flannel0网桥,该网桥一端连接docker0网桥,另一端连接flanneld服务进程
底层通信可选 UDP、VxLan
源flanneld封包,目标flanneld解包,对容器应用来说是透明的,但会引入一些网络的时延损耗

Flannel安装
1、安装etcd
2、安装Flannel
需要在每个节点都安装,将 flanneld 和 mk-docker-opts.sh 复制到 /usr/bin 或$PATH目录
3、配置Flannel
# /usr/lib/systemd/system/flanneld.service
[Unit]
Description=flanneld overlay address etcd agent
After=network.target
Before=docker.service
[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/flanneld
ExecStart=/usr/bin/flanneld -etcd-endpoints=${FLANNEL_ETCD} $FLANNEL_OPTIONS
[Install]
RequiredBy=docker.service
WantedBy=multi-user.target
编辑配置文件 /etc/sysconfig/flannel
FLANNEL_ETCD="http://192.168.18.3:2379"
FLANNEL_ETCD_KEY="/coreos.com/network"
在etcd中添加网络配置记录,用于分配给每个docker的虚拟ip地址段
etcdctl set /coreos.com/network/config '{"Network":"10.1.0.0/16"}'
停止 docker 服务
4、启动flanneld服务
systemctl restart flanneld
5、设置docker0网桥的ip地址
mk-docker-opts.sh -i
source /run/flannel/subnet.env
ifconfig docker0 ${FLANEL_SUBNET}
#验证docker0的ip是否属于flannel0子网
ip addr
6、重启docker服务
systemctl restart docker
7、查看etcd中的配置
etcdctl ls /coreos.com/network/subnets
etcdctl get /coreos.com/network/subnets/10.1.10.0-24


Open vSwitch

开源虚拟交换机软件
需要删除docker0网桥,添加对端需要对每个节点,如果集群规模比较大,会稍麻烦
通过建立 GRE/VxLAN隧道实现跨节点pod通信,也属于覆盖网络,会引入额外的网张开销

部署Open vSwitch
1、在所有节点上安装ovs
yum install openvswitch-2.4.0-1.x86_64.rpm
禁用selinux
service openvswitch status
2、创建网桥和GRE隧道
# 创建ovs网桥
ovs-vsctl add-br br0
# 创建GRE隧道连接对端,remote_ip为对端ip
ovs-vsctl add-port br0 gre1 -- set interface gre1 type=gre option:remote_ip=192.168.18.128
# 添加br0到本地docker0 让br0接管来自docker0的流量
brctl addif docker0 br0
# 启动br0与docker0网桥
ip link set dev br0 up
ip link set dev docker0 up
# 添加路由规则
ip route add 172.17.0.0/16 dev docker0
# 清空docker自带iptables规则及linux规则
iptables -t nat -F; iptables -F


直接路由

route add -net 10.1.20.0 netmask 255.255.255.0 gw 192.168.1.129
全人工维护,当新增机器或重启机器时,如果docker0地址有变化,需要同步修改
可以使用动态路由软件辅助,如 Quagga,Zebra等
docker pull index.alauda.cn/georce/router #Quagga容器
docker run -itd --name=router --privileged --net=host index.alauda.cn/georce/router
对于路由表太大的影响,实际没有什么影响,因为路由表都有高速缓存,查找速度非常快,除非上千个node,则需要测试和评估路由表性能


Calico

Calico是基于BGP的纯三层网络方案,在每个node实现一个vRouter负责数据转发,路由交换使用BGP
没有额外的封包解包,能节点cpu运算提高网络效率
对于大规模集群,可通过BGP route reflector来完成
Calico还提供网络策略功能,可对网络可达性进行控制

Calico组件
- Felix 运行在每个node,Calico Agent,为容器设置网络资源(IP,路由,iptables),保证跨主机容器网络互通
- etcd 后端存储
- BGP Client 把Felix在每个节点的路由信息通过BGP广播到Calico网络
- Router Reflector 完成大规模集群的分级路由分发
- CalicoCtl 命令行管理工具

部署Calico
1、修改启动参数
kube-apiserver --allow-privileged=true (因为calico-node需要以特权模式运行在各节点)
kubelet --network-plugin=cni
2、创建Calico服务,包括 calico-node和calico policy controller
http://docs.projectcalico.org/v3.5/getting-started/kubernetes/installation/hosted/calico.yaml
需要修改以下内容
ConfigMap:calico-config
- etcd_endpoints 为实际的etcd地址 以及认证证书等
- 设置backend类型,默认为 bird calico_backend: "bird"
- 设置MTU值 veth_mtu: "1440"
- 设置CNI网络配置文件内容 "type": "calico" "ipam":{"type":"calico-ipam"} 表示kubelet从/opt/cni/bin中搜索 calico calico-ipam可执行文件
Secret:calico-etcd-secrets 连接etcd的证书等
DaemonSet: 启用IPIP模式 CALICO_IPV4POOL_IPIP=Always;
设置容器IP网段 CALICO_IPV4POOL_CIDR;设置IPIP模式 CALICO_IPV$POOL_IPIP=Always; 查询网卡名的正则表达式 IP_AUTODETECTION_METHOD="interface=ens.*"
禁用IPv6模式 FELIX_IPV6SUPPORT="false"; 设置日志级别 FELIX_LOGSEVERITYSCREEN="info"
其中 install-cni容器功能是安装二进制文件到 /opt/cni/bin目录 并安装相应的网络配置文件到 /etc/cni/net.d 目录
calico-node 服务程序,用于设置pod网络资源,需要以hostNetwork模式运行
Deployment:calico-kube-contrllers 负责Network Policy

IP Pool有两种模式:BGP 或 IPIP 通过CALICO_IPV4POOL_IPIP控制,always和off
启用ipip会创建tunl0的虚拟网络接口

转载请注明:轻风博客 » kubernetes权威指南笔记(二)

喜欢 (0)or分享 (0)