Professional Documents
Culture Documents
05 - Security
05 - Security
05 - Security
(CKA)
Behrad Eslamifar
b.eslamifar@gmail.com
Security
12%
Outlines
[ alt_names ]
DNS.1=kubernetes
DNS.2=kubernetes.default
DNS.3=kubernetes.default.svc
DNS.4=kubernetes.default.svc.cluster
DNS.5=kubernetes.default.svc.cluster.local
DNS.6=kube.server.roo.cloud
DNS.7=ubuntu
IP.1=192.168.13.200
IP.2=10.96.0.1
[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth
subjectAltName=@alt_names
Admin Certificate
# cat /etc/kubernetes/admin.conf # echo <client-certificate-data> | base64 -d | openssl
... x509 -noout -text -in - > admin.crt
users:
- name: kubernetes-admin # echo <client-key-data> | base64 -d | openssl x509 -
user: noout -text -in - > admin.key
client-certificate-data:
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4a
kNDQWRxZ0F3SUJBZ0lJUWxPMXhxangvUzh3RFFZSktvWk
lodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVml
aWEp1WlhSbGN6QWVGUkg0Tm9JdHZJOE45cz0KLS0tLS1F
TkQgQ0VSVElGSUNBVEUtLS0tLQo=
client-key-data:
LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNS
UlFcEFJQkFBS0NBUUVBcjdRMEJMemY1dXpY3BZeWh4WXk
4dQo1eHJxOUFKRU9qcC9KQTNiSWtqUi9nN25rZzUwUHMv
YWFqMnVDNTZiV0ZlemQwOFVvUVJkcVE9PQotLS0tLUVOR
CBSU0EgUFJJVkFURSBLRVktLS0tLQo=
...
Renew Admin Certificate
# cat admin-ssl.conf # openssl req -new -key admin.key -out admin.csr \
[ req ] -config admin-ssl.conf
default_bits = 2048
prompt = no # openssl x509 -req -in admin.csr -CA \
default_md = sha256 /etc/kubernetes/pki/ca.crt \
distinguished_name = dn -CAkey /etc/kubrenetes/pki/ca.key -CAcreateserial \
-out admin-new.crt -days 365 -extensions \
[ dn ] v3_ext -extfile admin-ssl.conf
O=system:masters
CN=kubernetes-admin
[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=clientAuth
● Authentication Modules
○ Basic HTTP Auth
○ Static Bearer Tokens
○ X509 Client Certs
○ Service Account Tokens
○ OpenID Connect
○ Custome Webhook
Basic HTTP Auth
apiVersion: v1
kind: ServiceAccount
metadata:
# ...
secrets:
- name: gitlab-token-2wsdd
apiVersion: v1
data:
ca.crt: (APISERVER'S CA BASE64 ENCODED)
namespace: ZGVmYXVsdA==
token: (BEARER TOKEN BASE64 ENCODED)
Authentication
and Autherization:
● Node
○ A special-purpose authorization mode
○ Grants permissions to kubelets
○ API server option: --authorization-mode=Node
● Attribute-Based Access Control
○ Static file with a single “admin” identity
○ A simple file-based autherization policy
○ API server option: --authorization-mode=ABAC
● Webhook
○ API server option: --authorization-mode=Webhook
API Server GET Requests
API Server POST Requests
API Server PATCH Requests
API Server DELETE Requests
API Workshop
Access to API
$ kubectl proxy
Starting to serve on 127.0.0.1:8001
● Access to API without $ curl localhost:8001/
authentication {
"paths": [
"/api",
"/api/v1",
...
$ curl localhost:8001/api/v1
...
{
"name": "services",
"singularName": "",
"namespaced": true,
"kind": "Service",
"verbs": [
"create",
...
API Structure
/api/v1/namespaces
/api/v1/namespaces/default/secrets/secret-example
/api/v1/namespaces/default/pods/pod-example/log
Create Pod with curl
RBAC Workshop
Namespace Admin
apiVersion: rbac.authorization.k8s.io/v1
kind: Role $ kubectl create serviceaccount behrad
metadata: serviceaccount/behrad created
namespace: default
name: namespace-admin $ kubectl apply -f namespace-admin-role.yaml
rules: role.rbac.authorization.k8s.io/namespace-admin created
- apiGroups:
- "*"
verbs: $ kubectl apply -f namespace-admin-rolebinding.yaml
- "*" rolebinding.rbac.authorization.k8s.io/namespace-admin-behrad created
resources:
- "*"
$ kubectl config set-credentials behrad --token $TOKEN
apiVersion: rbac.authorization.k8s.io/v1 User "behrad" set.
kind: RoleBinding
metadata: $ kubectl config set-context default-admin --cluster kubernetes --user behrad
name: namespace-admin-behrad Context "default-admin" created.
namespace: default
roleRef: $ kubectl --context default-admin -n kube-system get pods
apiGroup: rbac.authorization.k8s.io Error from server (Forbidden): pods is forbidden: User
kind: Role
name: namespace-admin
"system:serviceaccount:default:behrad" cannot list resource
subjects: "pods" in API group "" in the namespace "kube-system"
- kind: ServiceAccount
name: behrad
namespace: default
Securing Cluster Nodes
Allowing the Pod to
Use the Host’s Linux
Namespaces
hostNetwork
hostNetwork
apiVersion: v1 $ Kubectl exec -ti pod-with-hostnetwork ip address show
kind: Pod docker0
metadata: Link encap:Ethernet HWaddr 02:42:14:08:23:47
name: pod-with-hostnetwork inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
spec: ...
lo
hostNetwork: true
...
containers: ens160
- name: main link/ether 00:50:56:9b:d4:c8 brd ff:ff:ff:ff:ff:ff
image: busybox inet 172.19.6.50/24 brd 172.19.6.255 scope .. ens160
command: ["/bin/sleep", "999999"]
hostPort
hostPort
apiVersion: v1 $ Kubectl exec -ti pod-with-hostport ip address show
kind: Pod 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state
metadata: UNKNOWN qlen 1000
name: pod-with-hostport link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
spec:
valid_lft forever preferred_lft forever
containers: 2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen
- image: nginx:stable-alpine 1000
name: nginx link/ipip 0.0.0.0 brd 0.0.0.0
ports: 4: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu
- containerPort: 80 1440 qdisc noqueue state UP
hostPort: 80 link/ether 12:19:08:d8:30:06 brd ff:ff:ff:ff:ff:ff
inet 172.16.39.10/32 scope global eth0
protocol: TCP
valid_lft forever preferred_lft forever
hostPID and hostIPC
apiVersion: v1 $ Kubectl exec -ti pod-with-host-pid-and-ipc ps aux
kind: Pod PID TTY STAT TIME COMMAND
metadata: 1 ? Ss 9:29 /sbin/init
name: pod-with-host-pid-and-ipc 2 ? S 0:01 [kthreadd]
4 ? I< 0:00 [kworker/0:0H]
spec:
6 ? I< 0:00 [mm_percpu_wq]
hostPID: true 7 ? S 3:09 [ksoftirqd/0]
hostIPC: true 8 ? I 18:47 [rcu_sched]
containers: 9 ? I 0:00 [rcu_bh]
- name: main ...
image: busybox
command: ["/bin/sleep", "999999"]
Security Context
Security Context
$ vi /etc/kubernetes/manifests/kube-apiserver.yaml
...
- --enable-admission-
plugins=NodeRestriction,PodSecurityPolicy
...
Default Pod Security Policy
apiVersion: extensions/v1beta1 $ kubectl create clusterrole psp-default \
kind: PodSecurityPolicy --verb=use --resource=podsecuritypolicies \
metadata: --resource-name=default
name: default clusterrole "psp-default" created
spec:
hostIPC: false $ kubectl create clusterrolebinding psp-all-users \
hostPID: false --clusterrole=psp-default \
hostNetwork: false --group=system:authenticated
hostPorts: clusterrolebinding.rbac.authorization.k8s.io/psp-
- min: 10000 all-users created
max: 11000
- min: 13000
max: 14000
privileged: false
readOnlyRootFilesystem: true
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
…
runAsUser, fsGroup, and supplementalGroups
runAsUser: $ kubectl create -f pod-as-user-100.yaml
rule: MustRunAs Error from server (Forbidden): error when creating
ranges: "pod-as-user-100.yaml"
- min: 2 : pods "pod-as-user-guest" is forbidden: unable to
max: 2 validate against any pod
fsGroup: security policy: [securityContext.runAsUser: Invalid
rule: MustRunAs value: 100: UID on
ranges: container main does not match required range. Found
- min: 2 100, allowed: [{2 2}]]
max: 10
- min: 20
max: 30
supplementalGroups:
rule: MustRunAs
ranges:
- min: 2
max: 10
- min: 20
Max: 30
Capabilities
apiVersion: extensions/v1beta1 $ kubectl create -f dep-ingress-nginx-hostnet.yaml
kind: PodSecurityPolicy Error from server (Forbidden): error when creating
spec: "dep-ingress-nginx-hostnet.yaml": pods "ingress-
allowedCapabilities: nginx-controller" is forbidden: unable
- SYS_TIME to validate against any pod security policy:
defaultAddCapabilities: [capabilities.add: Invalid
- CHOWN value: "NET_ADMIN": capability may not be added]
requiredDropCapabilities:
- SYS_ADMIN
- SYS_MODULE
- NET_ADMIN
HostPaths
apiVersion: extensions/v1beta1 $
kind: PodSecurityPolicy
spec:
allowedHostPaths:
# This allows "/foo", "/foo/",
"/foo/bar" etc., but
# disallows "/fool", "/etc/foo" etc.
# "/foo/../" is never valid.
- pathPrefix: "/foo"
readOnly: true # only allow read-only
mounts