I am trying to set up the security polices in the cluster. I enabled pod security and created a restricted psp
1.Step 1 - Created PSP
2.Step 2 - Created Cluster Role
3.Step 3 - Create ClusterRoleBinding
PSP
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
annotations:
serviceaccount.cluster.cattle.io/pod-security: restricted
serviceaccount.cluster.cattle.io/pod-security-version: "2315292"
creationTimestamp: "2022-02-28T20:48:12Z"
labels:
cattle.io/creator: norman
name: restricted-psp
spec:
allowPrivilegeEscalation: false
fsGroup:
ranges:
- max: 65535
min: 1
rule: MustRunAs
requiredDropCapabilities:
- ALL
runAsUser:
rule: RunAsAny
seLinux:
rule: RunAsAny
supplementalGroups:
ranges:
- max: 65535
min: 1
rule: MustRunAs
volumes:
- configMap
- emptyDir
- projected
- secret
- downwardAPI
- persistentVolumeClaim
Cluster Role -
apiVersion: rbac.authorization.k8s.io/v1
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
serviceaccount.cluster.cattle.io/pod-security: restricted
labels:
cattle.io/creator: norman
name: restricted-clusterrole
rules:
- apiGroups:
- extensions
resourceNames:
- restricted-psp
resources:
- podsecuritypolicies
verbs:
- use
ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: restricted-crb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: restricted-clusterrole
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:serviceaccounts:security
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:authenticated
Create couple of yams one for deplyment and other for pod
kubectl create ns security
$ cat previleged-pod.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: privileged-deploy
name: privileged-pod
spec:
containers:
- image: alpine
name: alpine
stdin: true
tty: true
securityContext:
privileged: true
hostPID: true
hostNetwork: true
$ cat previleged-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: privileged-deploy
name: privileged-deploy
spec:
replicas: 1
selector:
matchLabels:
app: privileged-deploy
template:
metadata:
labels:
app: privileged-deploy
spec:
containers:
- image: alpine
name: alpine
stdin: true
tty: true
securityContext:
privileged: true
hostPID: true
hostNetwork: true
The expectation was both pod and deployment to be prevented . But the pod got created and deployment failed
$ kg all -n security
NAME READY STATUS RESTARTS AGE
**pod/privileged-pod 1/1 Running 0 13m**
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/privileged-deploy 0/1 0 0 13m
NAME DESIRED CURRENT READY AGE
replicaset.apps/privileged-deploy-77d7c75dd8 1 0 0 13m
As Expected Error for Deployment came as below
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedCreate 3m10s (x18 over 14m) replicaset-controller Error creating: pods "privileged-deploy-77d7c75dd8-" is forbidden: PodSecurityPolicy: unable to admit pod: [spec.securityContext.hostNetwork: Invalid value: true: Host network is not allowed to be used spec.securityContext.hostPID: Invalid value: true: Host PID is not allowed to be used spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed spec.securityContext.hostNetwork: Invalid value: true: Host network is not allowed to be used spec.securityContext.hostPID: Invalid value: true: Host PID is not allowed to be used spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed spec.securityContext.hostNetwork: Invalid value: true: Host network is not allowed to be used spec.securityContext.hostPID: Invalid value: true: Host PID is not allowed to be used spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed]
But the pod created directly though yaml worked . Is PSP only for pods getting created through deplyment/rs ? Please help , how can we prevent users from creating pods which are previleged and dangerous
But the pod created directly though yaml worked . Is PSP only for pods
getting created through deplyment/rs ?
That's because when you create a bare pod (creating a pod directly) it will be created by the user called kubernetes-admin (in default scenarios), who is a member of the group system:masters, which is mapped to a cluster role called cluster-admin, which has access to all the PSPs that get created on the cluster. So the creation of bare pods will be successful.
Whereas pods that are created by deployment,rs,sts,ds (all the managed pods) will be created using the service account mentioned in their definition. The creation of these pods will be successful only if these service accounts have access to PSP via a cluster role or role.
how can we prevent users from creating pods which are previleged and dangerous
We need to identify what is that user and group that will be creating these pods (by checking ~/kube/config or its certificate) and then make sure, it does not have access to PSP via any cluster role or role.
Related
I have two clusters.
Kubernetes 1.25 and Openshift 4.11
apiVersion: apps/v1
kind: Deployment
metadata:
name: testcustom
#namespace: ics-e2e-pods-456
namespace: ics-e2e-deploy-7887
labels:
app: testcustom
spec:
replicas: 1
selector:
matchLabels:
app: testcustom
template:
metadata:
labels:
app: testcustom
spec:
containers:
- image: busybox #image name which should be avilable within cluster
name: container-name # name of the container inside POD
volumeMounts:
- mountPath: /myvolumepath # mount path for pvc from container
name: pvc-name # pvc name for this pod
securityContext:
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop: ["ALL"]
volumes:
- name: pvc-name # volume resource name in this POD, user can choose any name as per kubernetes
persistentVolumeClaim:
claimName: csi-block-pvc-custom-one # pvc name which was created by using claim.yaml file
When I try to deploy this pod, it fails in either of the above cluster throwing errors related to security context. If I fix issue for one cluster, the same spec doesn't work in other cluster. I am wondering how to get a common deployment file which can be used in both clusters
Error
Error creating: pods "testcustom-589767ccd5-" is forbidden: unable to validate against any security context constraint: [provider "anyuid": Forbidden: not usable by user or serviceaccount, spec.containers[0].securityContext.runAsUser: Invalid value: 1000: must be in the ranges: [1000640000, 1000649999], provider "restricted": Forbidden: not usable by user or serviceaccount, provider "nonroot-v2": Forbidden: not usable by user or serviceaccount, provider "nonroot": : Forbidden: not usable by user or serviceaccount, provider "privileged": Forbidden: not usable by user or serviceaccount]
In openshift when namespace/project is created please ensure below ranges specified properly. the values should be mapped to security context specified in yaml definition for fsgroup and runAsUser. More details are in openshift documentation. the same pod definition will work in k8s and openshift.
openshift.io/sa.scc.uid-range
openshift.io/sa.scc.supplemental-groups
I'm trying to apply podSecurityPolicy and try to test whether it's allowing me to create privileged pod.
Below is the podSecurityPolicy resource manifest.
kind: PodSecurityPolicy
apiVersion: policy/v1beta1
metadata:
name: podsecplcy
spec:
hostIPC: false
hostNetwork: false
hostPID: false
privileged: false
readOnlyRootFilesystem: true
hostPorts:
- min: 10000
max: 30000
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
seLinux:
rule: RunAsAny
volumes:
- '*'
current psp as below
[root#master ~]# kubectl get psp
NAME PRIV CAPS SELINUX RUNASUSER FSGROUP SUPGROUP READONLYROOTFS VOLUMES
podsecplcy false RunAsAny RunAsAny RunAsAny RunAsAny true *
[root#master ~]#
After submitted the above manifest,i'm trying to create privileged pod using below manifest.
apiVersion: v1
kind: Pod
metadata:
name: pod-privileged
spec:
containers:
- name: main
image: alpine
command: ["/bin/sleep", "999999"]
securityContext:
privileged: true
Without any issues the pod is created.I hope it should throw error since privileged pod creation is restricted through podSecurityPolicy.
Then i realized,it may be a admission controller plugin is not enabled and i saw which admission controller plugins are enabled by describe the kube-apiserver pod(Removed some lines for readability purpose) and able to see only NodeRestriction is enabled
[root#master ~]# kubectl -n kube-system describe po kube-apiserver-master.k8s
--client-ca-file=/etc/kubernetes/pki/ca.crt
--enable-admission-plugins=NodeRestriction
--enable-bootstrap-token-auth=true
**Attempt:**
Tried to edit /etc/systemd/system/multi-user.target.wants/kubelet.service and changed ExecStart=/usr/bin/kubelet --enable-admission-plugins=Initializers,NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota
restarted kubelet service.But no luck
Now how to enable other admission controller plugins?
1. Locate the static pod manifest-path
From systemd status, you will be able to locate the kubelet unit file
systemctl status kubelet.service
Do cat /etc/systemd/system/kubelet.service (replace path with the one you got from above command)
Go to the directory which is pointing to --pod-manifest-path=
2. Open the yaml which starts kube-apiserver-master.k8s Pod
Example steps to locate YAML is below
cd /etc/kubernetes/manifests/
grep kube-apiserver-master.k8s *
3. Append PodSecurityPolicy to flag --enable-admission-plugins= in YAML file
4. Create a PSP and corresponding bindings for kube-system namespace
Create a PSP to grant access to pods in kube-system namespace including CNI
kubectl apply -f - <<EOF
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
name: privileged
spec:
allowedCapabilities:
- '*'
allowPrivilegeEscalation: true
fsGroup:
rule: 'RunAsAny'
hostIPC: true
hostNetwork: true
hostPID: true
hostPorts:
- min: 0
max: 65535
privileged: true
readOnlyRootFilesystem: false
runAsUser:
rule: 'RunAsAny'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'RunAsAny'
volumes:
- '*'
EOF
Cluster role which grants access to the privileged pod security policy
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: privileged-psp
rules:
- apiGroups:
- policy
resourceNames:
- privileged
resources:
- podsecuritypolicies
verbs:
- use
EOF
Role binding
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: kube-system-psp
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: privileged-psp
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:nodes
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:serviceaccounts:kube-system
EOF
I'm trying to restrict all pods except few from running with the privileged mode.
So I created two Pod security policies:
One allowing running privileged containers and one for restricting privileged containers.
[root#master01 vagrant]# kubectl get psp
NAME PRIV CAPS SELINUX RUNASUSER FSGROUP SUPGROUP READONLYROOTFS VOLUMES
privileged true RunAsAny RunAsAny RunAsAny RunAsAny false *
restricted false RunAsAny RunAsAny RunAsAny RunAsAny false *
Created the Cluster role that can use the pod security policy "restricted" and binded that role to all the serviceaccounts in the cluster
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: psp-restricted
rules:
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames:
- restricted
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: psp-restricted
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: psp-restricted
subjects:
- kind: Group
name: system:serviceaccounts
apiGroup: rbac.authorization.k8s.io
Now I deploying a pod with "privileged" mode. But it is getting deployed. The created pod annotation indicating that the psp "privileged" was validated during the pod creation time. Why is that ? the restricted PSP should be validated right ?
apiVersion: v1
kind: Pod
metadata:
name: psp-test-pod
namespace: default
spec:
serviceAccountName: default
containers:
- name: pause
image: k8s.gcr.io/pause
securityContext:
privileged: true
[root#master01 vagrant]# kubectl create -f pod.yaml
pod/psp-test-pod created
[root#master01 vagrant]# kubectl get pod psp-test-pod -o yaml |grep kubernetes.io/psp
kubernetes.io/psp: privileged
Kubernetes version: v1.14.5
Am i missing something here ? Any help is appreciated.
Posting the answer to my own question. Hope it will help someone
All my PodSecurityPolicy configurations are correct. The issue was, I tried to deploy a pod by its own not via any controller manager like Deployment/Replicaset/Daemonset etc..
Most Kubernetes pods are not created directly by users. Instead, they are typically created indirectly as part of a Deployment, ReplicaSet or other templated controller via the controller manager.
In the case of a pod deployed by its own, pod is created by kubectl not by controller manager.
In Kubernetes there is one superuser role named "cluster-admin". In my case, kubectl is running with superuser role "cluster-admin". This "cluster-admin" role has access to all the pod security policies. Because, to associate a pod security policy to a role, we need to use 'use' verbs and set 'resources' to 'podsecuritypolicy' in 'apiGroups'
In the cluster-admin role 'resources' * include 'podsecuritypolicies' and 'verbs' * include 'use'. So all policies will also enforce on the cluster-admin role as well.
[root#master01 vagrant]# kubectl get clusterrole cluster-admin -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: cluster-admin
rules:
- apiGroups:
- '*'
resources:
- '*'
verbs:
- '*'
- nonResourceURLs:
- '*'
verbs:
- '*'
pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: psp-test-pod
namespace: default
spec:
serviceAccountName: default
containers:
- name: pause
image: k8s.gcr.io/pause
securityContext:
privileged: true
I deployed the above pod.yaml using the command kubectl create -f pod.yaml
Since I had created two pod security policies one for restriction and one for privileges, cluster-admin role has access to both policies. So the above pod will launch fine with kubectl because cluster-admin role has access to the privileged policy( privileged: false also works because admin role has access to restriction policy as well). This situation happens only if either a pod created directly by kubectl not by kube control managers or a pod has access to the "cluster-admin" role via serviceaccount
In the case of a pod created by Deployment/Replicaset etc..first kubectl pass the control to the controller manager, then the controller will try to deploy the pod after validating the permissions(serviceaccount, podsecuritypolicies)
In the below Deployment file, pod is trying to run with privileged mode. In my case, this deployment will fail because I already set the "restricted" policy as the default policy for all the serviceaccounts in the cluster. So no pod will able to run with privileged mode. If a pod needs to run with privileged mode, allow the serviceaccount of that pod to use the "privileged" policy
apiVersion: apps/v1
kind: Deployment
metadata:
name: pause-deploy-privileged
namespace: kube-system
labels:
app: pause
spec:
replicas: 1
selector:
matchLabels:
app: pause
template:
metadata:
labels:
app: pause
spec:
serviceAccountName: default
containers:
- name: pause
image: k8s.gcr.io/pause
securityContext:
privileged: true
I can't start pod which requires privileged security context.
PodSecurityPolicy:
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: pod-security-policy
spec:
privileged: true
allowPrivilegeEscalation: true
readOnlyRootFilesystem: false
allowedCapabilities:
- '*'
allowedProcMountTypes:
- '*'
allowedUnsafeSysctls:
- '*'
volumes:
- '*'
hostPorts:
- min: 0
max: 65535
hostIPC: true
hostPID: true
hostNetwork: true
runAsUser:
rule: 'RunAsAny'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'RunAsAny'
fsGroup:
rule: 'RunAsAny'
ClusterRole:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: privileged
rules:
- apiGroups:
- '*'
resourceNames:
- pod-security-policy
resources:
- '*'
verbs:
- '*'
ClusterRoleBinding:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: privileged-role-binding
roleRef:
kind: ClusterRole
name: privileged
apiGroup: rbac.authorization.k8s.io
subjects:
# Authorize specific service accounts:
- kind: ServiceAccount
name: default
namespace: kube-system
- kind: ServiceAccount
name: default
namespace: default
- kind: Group
# apiGroup: rbac.authorization.k8s.io
name: system:authenticated
# Authorize specific users (not recommended):
- kind: User
apiGroup: rbac.authorization.k8s.io
name: admin
$ k auth can-i use psp/pod-security-policy
Warning: resource 'podsecuritypolicies' is not namespace scoped in group 'extensions'
yes
$ k apply -f daemonset.yml
The DaemonSet "daemonset" is invalid: spec.template.spec.containers[0].securityContext.privileged: Forbidden: disallowed by cluster policy
Not sure if it is needed but I have added PodSecurityContext to args/kube-apiserver --enable-admission-plugins
Any advice and insight is appreciated. WTF is this: "It looks like your post is mostly code; please add some more details." !?!
Just checked your Pod Security Policy configuration on my current environment:
kubeadm version: &version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.1"
Client Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.1"
Server Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.1"
I assume that you've included Privileged securityContext in the current DaemonSet manifest file.
securityContext:
privileged: true
In order to allow Kubernetes API spawning Privileged containers you might have to set kube-apiserver flag --allow-privileged to true value.
--allow-privileged=true
Therefore, I'm facing the same issue in my k8s cluster, once I disallow to run privileged containers with false option.
I am creating a Pod Security Policy to stop ALL users from creating a Pod as Root user. My cluster is on GKE.
The steps Ive carried out till now are
1) Enable PodSecurityPolicy in my cluster
gcloud beta container clusters update standard-cluster-11 --enable-pod-security-policy
2) Define the Policy. The policy is simple and restricts root user.
apiVersion: extensions/v1beta1
kind: PodSecurityPolicy
metadata:
name: a-restrict-root
spec:
privileged: false
runAsUser:
rule: MustRunAsNonRoot # <------ Root user restricted.
seLinux:
rule: RunAsAny
fsGroup:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
volumes:
- '*'
3) And then ofcourse implementing the correct RBAC rules so that it can be implemented for ALL users.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gce:podsecuritypolicy:a-restrict-root
labels:
addonmanager.kubernetes.io/mode: Reconcile
kubernetes.io/cluster-service: "true"
rules:
- apiGroups:
- policy
resourceNames:
- a-restrict-root
resources:
- podsecuritypolicies
verbs:
- use
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: gce:podsecuritypolicy:a-restrict-root
labels:
addonmanager.kubernetes.io/mode: Reconcile
kubernetes.io/cluster-service: "true"
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: gce:podsecuritypolicy:a-restrict-root
subjects:
- kind: Group
apiGroup: rbac.authorization.k8s.io
name: system:serviceaccounts
Now comes the part where I try to spin up a Pod. The pod definition looks like this :
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 0
fsGroup: 0
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: gcr.io/google-samples/node-hello:1.0
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
securityContext:
allowPrivilegeEscalation: false
As you can see, the runAsUser is set to 0 meaning root.
When I run kubectl create -f pod.yaml, the pod is creating and goes into Running state.
When I exec into the Pod, I can see all process running as root
$ kubectl exec -it security-context-demo -- sh
# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 4336 812 ? Ss 19:25 0:00 /bin/sh -c node server.js
root 6 0.4 0.5 772124 22656 ? Sl 19:25 0:00 node server.js
root 11 0.0 0.0 4336 724 ? Ss 19:26 0:00 sh
root 16 0.0 0.0 17500 2072 ? R+ 19:26 0:00 ps aux
But based on my PodSecurityPolicy this should NOT be allowed. Is there something I have missed ?
UPDATE :
I spun up a default nginx pod that I know always starts as root user. Its manifest is :
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
And when I create it, it too starts up successfully.
$ kubectl get po
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 2m
Whereas because of the PSP, it should not start up.
If you fetch the created pod from the API, it will contain an annotation indicating which PSP allowed the pod. I expect a different PSP is in place which allows the pod
I got what you are missing just add this in your pod config file:
Before that, make sure to create the user (say, appuser) uid -> say, 999 and group (say, appgroup) gid ->say, 999 in the Docker container, and then try starting the container with that user and add:
securityContext:
runAsUser: 999
This might be a good read: SecurityContext
Also, when you are doing this:
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 0
fsGroup: 0
You are overriding the PodSecurityPolicy see here
Update: 1
How to fix this:
apiVersion: extensions/v1beta1
kind: PodSecurityPolicy
metadata:
name: a-restrict-root
spec:
privileged: false
defautlAllowPrivilegeEscalation: false
# This is redundant with non-root + disallow privilege escalation,
# but we can provide it for defense in depth.
requiredDropCapabilities:
- ALL
hostIPC: false
hostPID: false
runAsUser:
# Require the container to run without root privileges.
rule: 'MustRunAsNonRoot'
seLinux:
# This policy assumes the nodes are using AppArmor rather than SELinux.
rule: 'RunAsAny'
supplementalGroups:
rule: 'MustRunAs'
ranges:
# Forbid adding the root group.
- min: 1
max: 65535
fsGroup:
rule: 'MustRunAs'
ranges:
# Forbid adding the root group.
- min: 1
max: 65535