---
# System prepended metadata

title: 'misconfig - II: Security Context'
tags: [Kubernetes, SecurityContext]

---

---
tags: Kubernetes,SecurityContext
description: Kubernetes Security Context Issue
robots: index, follow
---
# misconfig - II: Security Context
相信很多人由容器環境轉到Kubernetes時，最常做的一件事就是上傳好image後，就很直覺的把服務開到叢集中，非常直覺、快速、幫自己挖了坑。
例如：
```yaml=
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: mycontainer
  name: mycontainer
spec:
  containers:
  - args:
    - client
    image: nginx
    name: mycontainer
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
```

前一篇文章我們有提到一些需要補充的東西，就讓我們來看看會發生什麼事。

## 1.1. 環境資訊
**K8S: v1.20.12**
**NAME         STATUS   ROLES**
g1-master1     Ready    controlplane,etcd
g1-master2     Ready    controlplane,etcd
g1-master3     Ready    controlplane,etcd
g1-worker1     Ready    worker
g1-worker2     Ready    worker
g1-worker3     Ready    worker

## 1.2. Lab操作

1. 建立一個pod，快速的把他對外服務、確認狀態。
```shell=
└[~]> kubectl run mycontainer
pod/mycontainer created

└[~]> kubectl expose pod mycontainer --type=NodePort --target-port 80 --port 80
service/mycontainer exposed

└[~]> kubectl get svc
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes    ClusterIP   10.43.0.1       <none>        443/TCP        74d
mycontainer   NodePort    10.43.194.42    <none>        80:31065/TCP    1m

└[~]> curl 172.24.2.16:31065
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
...
(略)
```

2. 然後我們就可以幫他安裝套件了，前後不用5分鐘完成。(擦汗
```shell=
└[~]> kubectl exec -it mycontainer -- /bin/bash
root@mycontainer:/# apt update
Get:1 http://deb.debian.org/debian bullseye InRelease [116 kB]
Get:2 http://security.debian.org/debian-security bullseye-security InRelease [44.1 kB]
Get:3 http://deb.debian.org/debian bullseye-updates InRelease [39.4 kB]
Get:4 http://deb.debian.org/debian bullseye/main amd64 Packages [8183 kB]
...
root@mycontainer:/# apt install recon-ng
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  javascript-common libgpm2 libjs-jquery libjs-skeleton libjs-sphinxdoc
(略)
```
:::info
1. [recon-ng](https://www.kali.org/tools/recon-ng/ "recon-ng"): Recon-ng is a full-featured Web Reconnaissance framework.
:::

![](https://i.imgur.com/nGjw58W.png)
沒有模組可以用，就安裝或enable自己想要的囉。

3. 用一個沒有安裝任何服務的nginx來做範例似乎說不過去，我們用一個可以執行系統指令的網頁服務來看看。

[1. 小網頁程式-github、dockerfile](https://github.com/yansheng133/securitycontext "security context")
[2. 已經build好的docker image](https://hub.docker.com/r/yansheng133/securitycontext "")
:::danger
1. 上述兩個連結，僅用於本文展示透過網頁執行系統指令所產生的可能問題，不負責任何濫用後產生的任何損失。
:::

**source code**
```go=
package main

import (
	"os/exec"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/ping/:exec", func(c *gin.Context) {
		exe := c.Params.ByName("exec")
		out, err := exec.Command(exe).Output()
		if err != nil {
			c.JSON(200, gin.H{
				"message": err,
			})
		}
		output := string(out[:])
		c.JSON(200, gin.H{
			"CLI return message": output,
			"Warning: ":          "This is training sample, DO NOT USE IT FOR BAD!",
		})
	})
	r.Run()
}
```

4. 能夠執行指令的web服務：testweb.yaml。
```yaml=
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: testweb
  name: testweb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: testweb
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: testweb
    spec:
      containers:
      - image: yansheng133/securitycontext:0.3
        name: securitycontext
        resources: {}
status: {}
---
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: testweb
  name: testweb
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: testweb
  type: NodePort
status:
  loadBalancer: {}
```

5. 建立相關的服務。
```shell=
└[~]> kubectl create -f testgo.yaml
deployment.apps/testweb created
service/testweb created

└[~]> kubectl get svc,deploy,pod
NAME                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/kubernetes    ClusterIP   10.43.0.1       <none>        443/TCP        73d
service/mycontainer   NodePort    10.43.194.42    <none>        80:31065/TCP   23h
service/testweb       NodePort    10.43.91.239    <none>        80:30344/TCP   12m

NAME                                 READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/testweb              1/1     1            1           12m

NAME                                      READY   STATUS    RESTARTS   AGE
pod/mycontainer                           1/1     Running   0          23h
pod/testweb-5f8f8bcb9f-pq5sk              1/1     Running   0          12m
```

6. 傳指令進去，確認回應是什麼，也可用瀏覽器打開，透過網址輸入一樣的內容就可以了。
```shell=
└[~]> curl 172.24.2.15:30344/ping/ls
{"CLI return message":"go.mod\ngo.sum\nmain.go\n","Warning: ":"This is training sample, DO NOT USE IT FOR BAD!"}%

└[~]> curl 172.24.2.15:30344/ping/whoami
{"CLI return message":"root\n","Warning: ":"This is training sample, DO NOT USE IT FOR BAD!"}%

└[~]> curl 172.24.2.15:30344/ping/'%20check%20ascii.'
{"message":{"Name":" check ascii.","Err":{}}}{"CLI return message":"","Warning: ":"This is training sample, DO NOT USE IT FOR BAD!"}%

└[~]> curl 172.24.2.15:30344/ping/id
{"CLI return message":"uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)\n","Warning: ":"This is training sample, DO NOT USE IT FOR BAD!"}%
```

7. 從回應我們可以觀察到以下狀況：
:::info
1. 可以列出當前的資料夾。
2. 自己的權限是root。
3. 有些ascii碼會做轉換。
:::

撇除ASCII碼會做轉換這個網頁程式面的問題，發現可以進行一些基本指令的呼叫，這個問題一樣會發生在登入容器或透過特定的指令、程式反向連結到想要的IP位置。
不過我們可以在服務建立的時候，就把系統權限全部拔掉。
例如拔掉所有的系統權限(capabilities)、拿掉切換到root的權限(allowPrivilegeEscalation)、把權限切換到指定的使用者(runAsUser)等。
```yaml=
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: dropall
  name: dropall
spec:
  containers:
  - args:
    - /bin/sleep
    - "3600"
    image: busybox
    name: dropall
    resources: {}
    securityContext:
      runAsUser: 2000
      capabilities:
        drop:
          - all
      allowPrivilegeEscalation: false
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
```

8. 確認一下id, whoami, ping與系統能夠執行哪些東西。
```shell=
└[~]> kubectl exec -it dropall -- /bin/sh
/ $ id
uid=2000 gid=0(root)

/ $ whoami
whoami: unknown uid 2000

/ $ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
ping: permission denied (are you root?)

/ $ cat /proc/1/status |grep Cap
CapInh:	0000000000000000
CapPrm:	0000000000000000
CapEff:	0000000000000000
CapBnd:	0000000000000000
CapAmb:	0000000000000000
##想確認可以操作哪些東西可以透過capsh --decode=值來做檢查，整排0就是無任何權限。
```

經過調整之後，就可以把非必要的權限等都移除，能夠有效的縮小被攻擊面，另外搭配一些network policy能夠更加明確的指定容器與容器間相互存取的方式，建議讀者可以參考先前的calico network policy，強化網路活動可視性，避免惡意人士對整體環境的偵查作業。

## 1.3. 參考資料
[1. official - security contex](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ "")
[2. Open Policy Agent](https://www.openpolicyagent.org/ "OPA")
[3. kubesec](https://kubesec.io/ "kubesec")