前言

网络安全实验居然有k8s,可惜要去实习了,所以提前了解一下

k8s结构

一个K8S系统,通常称为一个K8S集群(Cluster)。
a08d050f104a43d6bb877979f996dd6d

这个集群主要包括两个部分:

一个Master节点(负责管理和控制):包括API Server、Scheduler、Controller manager、etcd。
API Server是整个系统的对外接口,供客户端和其它组件调用,相当于“营业厅”。
Scheduler负责对集群内部的资源进行调度,相当于“调度室”。
Controller manager负责管理控制器,相当于“大总管”。
一群Node节点(具体的主机容器): 包含Docker、kubelet、kube-proxy、Fluentd、kube-dns(可选),还有就是Pod
Docker,创建容器的
Pod(Kubernetes最基本的操作单元)
Kubelet,主要负责监视指派到它所在Node上的Pod,包括创建、修改、监控、删除等。
Kube-proxy,主要负责为Pod对象提供代理。
Fluentd,主要负责日志收集、存储与查询。

kubectl

kubectl是Kubernetes的命令行工具,用于与Kubernetes集群进行交互

k8s-Pod(豆荚)

southeast
一个Pod代表着集群中运行的一个进程,一个Pod有一个或多个容器组成,Pod中容器共享存储和网络,如nginx+web服务+mysql就是一个pod

获取 Pod 的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
kubectl get namespace
NAME STATUS AGE
default Active 143m
kube-node-lease Active 143m
kube-public Active 143m
kube-system Active 143m
kubernetes-dashboard Active 138m

kubectl get pods -A #返回所有命名空间中的 pod
kubectl get pods -A -o wide #详细信息,如IP,NODE等

kubectl get pods #在默认(default)的命名空间中找资源
kubectl get pods -n kubernetes-dashboard #查看特定命名空间下的 Pod 信息
NAME READY STATUS RESTARTS AGE
dashboard-metrics-scraper-7db978b848-sb78p 1/1 Running 1 (120m ago) 140m
kubernetes-dashboard-6f4c897964-8k45v 1/1 Running 0 140m

kubectl logs kubernetes-dashboard-6f4c897964-8k45v -n kubernetes-dashboard #查看 Pod 日志,如果多个容器-c

kubectl describe pod kubernetes-dashboard-6f4c897964-8k45v -n kubernetes-dashboard # 查看 pod 详情
kubectl get pod batch-check-job-mrd2q -o yaml #这个是以配置文件的形式

kubectl exec -it pod-name -- bash # 进入 Pod 容器终端,如果节点包含多个contain -c container-name可以指定进入哪个容器
kubectl port-forward my-pod 8080:80 # 把Pod上的80端口映射到node上的8080端口

kubectl delete pod <pod名>

命名空间

默认情况下,k8s内部的namespace可以相互访问

1
2
3
4
5
6
7
8
#显示所以命名空间
kubectl get namespaces
# 创建命名空间
kubectl create namespace testapp
# 切换命名空间
kubens kube-system
# 回到上个命名空间
kubens -

Pod 控制器

Pod 控制器又被称为工作负载,是用于实现管理pod的中间层,Pod 控制器包括 ReplicaSet、Deployment、StatefulSet 和 DaemonSet 等。这些控制器提供了对 Pod 的声明性定义和自动化管理,确保集群中的 Pod 始终处于所需的状态

Deployment

ReplicaSet(RS):代用户创建指定数量的pod副本,确保pod副本数量符合预期状态(负载均衡),并且支持滚动式自动扩容和缩容功能
Deployment:通过管理ReplicaSet来间接管理Pod,用于管理无状态应用。支持滚动更新(滚动更新允许在不中断服务的情况下逐步更新应用程序)和版本回滚,还提供声明式配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
kubectl apply -f app.yaml #部署应用,没加-n或者配置文件没有namespace就是默认
kubectl get deployment -o wide #查看deployment
kubectl get deploy <deply-name> -n deepflow -o yaml #以yaml的形式输出配置信息
kubectl scale deployment test-k8s --replicas=5 # 伸缩扩展副本

kubectl rollout history deployment test-k8s # 查看历史
kubectl rollout undo deployment test-k8s # 回到上个版本
kubectl rollout undo deployment test-k8s --to-revision=2 # 回到指定版本

kubectl set image deployment test-k8s test-k8s=ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v2-with-error --record #更新镜像为test-k8s:v2
kubectl rollout pause deployment test-k8s # 暂停滚动更新
kubectl rollout status deploy test-k8s #观察更新状态
kubectl rollout resume deployment test-k8s # 恢复滚动更新

Horizontal Pod Autoscaler(HPA)

上面的Deployment已经写死了副本数量,有没有一种方法可以根据访问流量自动调整pod副本数量使其符合预期状态,这就是HorizontalPodAutoscaler的作用,此处暂时不演示

StatefulSet

StatefulSet 是用来管理有状态的应用
前面我们部署的应用,它只是处理 HTTP 请求,本身不生产数据(日志除外),不需要记住状态的,可以随意扩充实例,实例之间是无关的,启动的顺序不固定,Pod 的名字、IP 地址、域名也都是完全随机的
而像数据库、消息队列、缓存系统等 这类有状态的,这些节点的启动和停止需要遵循严格的顺序,重启时都需要挂载原来的数据卷

DaemonSet(DS)

DaemonSet 用于确保集群中的每一个节点(如果主节点没有污点,也会调度到主节点上)只运行特定的pod副本,通常用于日志收集、节点监控等场景。它的服务是无状态的。

Taint

污点可以用来避免Pod被分配到不合适的节点上,有三种模式
PreferNoschedule:表示k8s将尽量避免将Pod调度到具有该污点的Node上
NoSchedule:表示k8s将不会将Pod调度到具有该污点的Node上
NoExecute:表示k8s将不会将Pod调度到具有该污点的Node上,同时会将Node上已经存在的Pod驱逐出去

(k8s从1.6开始,不会再将DaemonSet调度到主节点上。由于主节点上有node-role.kubernetes.io/master及NoSchedule污点)

1
2
3
kubectl taint nodes <node-name> key=value:taint-effect #设置污点
kubectl get nodes #查看节点
kubectl describe nodes|grep Taints #查看节点中关于污点的设置

所以如果某个节点有污点,是不会创建ds的

Tolerations
设置了污点的Node将根据taint的effect : Noschedule, PreferNoschedule, NoExecute和Pod之间产生互斥的关系, Pod将在一定程度上不会被调度到Node上。但我们可以在Pod上设置容忍(Tolerations) ,意思是设置了容忍的Pod

job

Job,主要用于负责批量处理短暂的一次性任务。当Job创建的pod执行成功结束时,Job将记录成功结束的pod数量,当成功结束的pod达到指定的数量时,Job将完成执行

1
2
kubectl get jobs -A
kubectl get pods --namespace default -l "job-name=batch-check-job" #获取job对应的pods

Service

Service 把一类Pods上的应用程序抽象成服务,为一组 Pod 提供流量路由,允许 Kubernetes 中的 Pod 死亡和复制,而不会影响应用,使用户感觉不到变化

Service的三种主要形式

1
2
3
kubectl get svc #查看服务
kubectl expose deployment source-ip-app --name=clusterip --port=80 --target-port=8080
kubectl expose deployment source-ip-app --name=nodeport --port=80 --target-port=8080 --type=NodePort
  1. ClusterIP: 仅仅使用一个集群内部的IP地址 - 这是默认值。选择这个值意味着你只想这个服务在集群内部才可以被访问到。
  2. NodePort: NodePort Service 是在 ClusterIP Service 的基础上,为 Service 在集群所有 Node 节点上绑定一个端口,外部客户端通过nodeIP:nodePort就可以访问服务。暴露的端口号范围为 30000-32767。
  3. LoadBalancer: 在使用一个集群内部IP地址和在NodePort上开放一个服务之外,向云提供商申请一个负载均衡器,会让流量转发到这个在每个节点上以:NodePort的形式开放的服务上

Service 自己会有一个域名,格式是对象名. 名字空间

存储(volumes)

数据持久化

hostPath 挂载:把节点上的一个目录直接挂载到 Pod

pv挂载:在pod中定义一个存储卷(该存储卷类型为pvc),定义的时候直接指定大小,**Persistent Volume Claim (PVC)必须与对应的Persistent Volume (PV)**建立关系,pvc会根据定义去pv申请,而pv是由存储空间创建出来的。pv和pvc是k8s抽象出来的一种存储资源

基于动态storageclass挂载:StorageClass是一个存储类,通过创建StorageClass可以动态生成一个存储卷,供k8s用户使用。使用StorageClass可以根据PVC动态的创建PV,减少管理员手工创建PV的工作

配置信息

ConfigMapSecret 都是 Kubernetes 中用于存储和管理配置信息的资源对象,ConfigMap 适用于存储非敏感数据,而 Secret 则适用于存储敏感数据

1
kubectl create configmap example-config --from-literal=database_url=mysql://localhost:3306 --from-literal=api_key=abc123

Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。 这样的信息可能会被放在 Pod 规约中或者镜像中。 使用 Secret 意味着你不需要在应用程序代码中包含机密数据。

1
2
3
kubectl create secret generic example-secret --from-literal=username=myusername --from-literal=password=mypassword
kubectl get secrets #查看当前命名空间下Secret
kubectl get secret example-secret -o yaml

网络

Kubernetes 使用平面网络架构。默认情况下,集群内的命名空间没有任何网络安全限制。

访问权限控制(RBAC)

主体(subject):
User:用户
Group:用户组
ServiceAccount:服务账号
角色:
Role:授权特定命名空间的访问权限
ClusterRole:授权所有命名空间的访问权限

角色绑定:
RoleBinding:将角色绑定到主体(即subject)
ClusterRoleBinding:将集群角色绑定到主体

实战

于之前写内网渗透文章结构不同,以下方法并没有顺序性,比如如果你拿下k8s当然可以node节点内横向,这样写只是为了好区分,具体实战根据实际情况判断

检测是否是K8s环境

1
2
3
df -T #存在 /run/secrets/kubernetes.io,确认是 K8s 环境
/proc/1/cgroup #内若包含docker或kube字符串则是在docker环境或k8s pod 之中
env #查看环境变量中是否有k8s或者docker字符串

本地权限提升

CVE-2021-22555
其他见之前写的内网渗透

node节点内横向

docker 逃逸

自动扫描逃逸漏洞
./cdk_linux_amd64 evaluate

见之前写的 Docker 实践

K8S节点集群内横向

敏感信息泄露

1
2
3
4
5
6
kubectl auth can-i --list #我们具有的权限

kubectl get secrets -o yaml

docker pull docker.io/eksclustergames/base_ext_image #私有镜像库暴露可以代码审计
docker history add093cd268d --no-trunc

其他还有 k8s configfile 泄露,云账号AK泄露

API Server未授权(8080,6443)+污点横向

1
2
3
4
5
6
cat /run/secrets/kubernetes.io/serviceaccount/token
curl -ks -H "Authorization: Bearer XXXXXXXXXX" https://10.x.x.1:6443/api/v1/namespaces/node

# 上传Kubectl 上去
./kubectl auth can-i --list
./kubectl apply -f 1.yaml #创建带有容忍参数并且挂载宿主机根目录的Pod

K8s 集群间的横向