Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

🏠 Back to Blog

Cluster Setup (10%)

CIS Benchmark

What is a security benchmark?

  • A security benchmark is a set of standard benchmarks that define a state of optimized security for a given system (servers, network devices, etc.)
  • CIS (Center for Internet Security) provides standardized benchmarks (in the form of downloadable files) that one can use to implement security on their system.
  • CIS provides benchmarks for public clouds (Azure, AWS, GCP, etc.), operating systems (Linux, Windows, MacOS), network devices (Cisco, Juniper, HP, etc.), mobile devices (Android and Apple), desktop and server software (such as Kubernetes)
  • View more info here
  • You must register at the CIS website to download benchmarks
  • Each benchmark provides a description of a vulnerability, as well as a path to resolution.
  • CIS-CAT is a tool you can run on a system to generate recommendations for a given system. There are two versions available for download, CIS-CAT Lite and CIS-CAT Pro. The Lite version only includes benchmarks for Windows 10, MacOS, Ubuntu, and desktop software (Google Chrome, etc.). The Pro version includes all benchmarks.
  • CIS Benchmarks for Kubernetes
    • Register at the CIS website and download the CIS Benchmarks for kubernetes
    • Includes security benchmarks for master and worker nodes

KubeBench

  • KubeBench is an alternative to CIS-CAT Pro to run benchmarks against a Kubernetes cluster.
  • KubeBench is open source and maintained by Aqua Security
  • KubeBench can be deployed as a Docker container or a pod. It can also be invoked directly from the binaries or compiled from source.
  • Once run, kube-bench will scan the cluster to identify if best-practices have been implemented. If will output a report specifying which benchmarks have passed/failed. It will tell you how to fix any failed benchmarks.
  • You can view the report by tailing the pod logs of the kube-bench pod.

Cluster Upgrades

  • The controller-manager and kube-scheduler can be one minor revision behind the API server.
    • For example, if the API server is at version 1.10, controller-manager and kube-scheduler can be at 1.9 or 1.10
  • The kubelet and kube-proxy can be up to 2 minor revisions behind the API server
  • kubectl can be x+1 or x-1 minor revisions from the kube API server
  • You can upgrade the cluster one minor version at a time

Upgrade Process

  • Drain and cordon the node before upgrading it
    • kubectl drain <node name> --ignore-daemonsets
  • Upgrade the master node first.
  • Upgrade worker nodes after the master node.

Upgrading with Kubeadm

  • If the cluster was created with kubeadm, you can use kubeadm to upgrade it.
  • The upgrade process with kubeadm:
    # Increase the minor version in the apt repository file for kubernetes:
      sudo vi /etc/apt/sources.list.d/kubernetes.list
    
    # Determine which version to upgrade to
      sudo apt update
      sudo apt-cache madison kubeadm
    
    # Upgrade kubeadm first
      sudo apt-mark unhold kubeadm && \
      sudo apt-get update && sudo apt-get install -y kubeadm='1.31.x-*' && \
      sudo apt-mark hold kubeadm
    
    # Verify the version of kubeadm
      kubeadm version
    
    # Check the kubeadm upgrade plan
      sudo kubeadm upgrade plan
    
    # Apply the upgrade plan
      sudo kubeadm upgrade apply v1.31.x
    
    # Upgrade the nodes
      sudo kubeadm upgrade node
    
    # Upgrade kubelet and kubectl
      sudo apt-mark unhold kubelet kubectl && \
      sudo apt-get update && sudo apt-get install -y kubelet='1.31.x-*' kubectl='1.31.x-*' && \
      sudo apt-mark hold kubelet kubectl
    
    # Restart the kubelet
      sudo systemctl daemon-reload
      sudo systemctl restart kubelet
    

Network Policies

Overview

  • Kubernetes Network Policies allow you to control the flow of traffic to and from pods. They define rules that specify:

    • What traffic is allowed to reach a set of pods.
    • What traffic a set of pods can send out.
  • Pods can communicate with each other by default. Network Policies allow you to restrict this communication.

  • Network Policies operate at Layer 3 and Layer 4 (IP and TCP/UDP). They do not cover Layer 7 (application layer).

  • Network Policies are additive. Meaning, to grant more permissions for network communication, simply create another network policy with more fine-grained rules.

  • Network Policies are implemented by the network plugin. The network plugin must support NetworkPolicy for the policies to take effect.

  • Network Policies are namespace-scoped. They apply to pods in the same namespace.

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata: 
      name: default-deny-all
      namespace: secure-namespace
    spec:
        podSelector: {}
        policyTypes
        - Ingress
    
  • Say we now want to grant the ‘frontend’ pods with label ‘teir: frontend’ in the ‘app’ namespace access to the ‘backend’ pods in ‘secure-namespace’. We can do that by creating another Network Policy like this:

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: allow-app-pods
      namespace: secure-namespace
    spec:
        podSelector:
          matchLabels:
            tier: backend
        policyTypes:
        - Ingress
        ingress:
        - from:
          - namespaceSelector:
              matchLabels:
                name: app
            podSelector:
              matchLabels:
                teir: frontend
          ports:
          - protocol: TCP
            port: 3000
    
    

Key Concepts

  1. Namespace Scope: Network policies are applied at the namespace level.
  2. Selector-Based Rules:
    • Pod Selector: Select pods the policy applies to.
    • Namespace Selector: Select pods based on their namespace.
  3. Traffic Direction:
    • Ingress: Traffic coming into the pod.
    • Egress: Traffic leaving the pod.
  4. Default Behavior:
    • Pods are non-isolated by default (accept all traffic).
    • A pod becomes isolated when a network policy matches it.

Common Fields in a Network Policy

  • podSelector: Specifies the pods the policy applies to.
  • ingress/egress: Lists rules for ingress or egress traffic.
  • from/to: Specifies allowed sources/destinations (can use IP blocks, pod selectors, or namespace selectors).
  • ports: Specifies allowed ports and protocols.

Example Network Policies

Allow All Ingress Traffic

````
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
  namespace: default
spec:
  podSelector: {}
  ingress:
  - {}
```

Deny All Ingress and Egress Traffic

````
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
    name: deny-all
    namespace: defaulT
spec:
    podSelector: {}
    ingress: []
    egress: []

```

Allow Specific Ingress from a Namespace

```
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
    name: allow-namespace-ingress
    namespace: default
spec:
    podSelector:
        matchLabels:
            app: my-app
    ingress:
    - from:
      - namespaceSelector:
        matchLabels:
        team: frontend
```

Allow Egress to a Specific IP

```
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
    name: allow-egress-specific-ip
    namespace: default
spec:
    podSelector:
        matchLabels:
            app: my-app
    egress:
    - to:
      - ipBlock:
        cidr: 192.168.1.0/24
        ports:
      - protocol: TCP
        port: 8080
```

Cilium Network Policy

  • Cilium Network Policies provide more granularity, flexibility, and features than traditional Kubernetes Network Policies
  • Cilium Network Policies operate up to layer 7 of the OSI model. Traditional Network Policies only operate up to layer 4.
  • Cilium Network Policies perform well due to the fact that they use eBPF
  • Hubble allows you to watch traffic going to and from pods
  • You can add Cilium to the cluster by:
    • Deploying with helm
    • Running cilium install after you install the cilium CLI tool

Cilium Network Policy Structure

  • Cilium Network Policies are defined in YAML files
  • The structure is similar to Kubernetes Network Policies

Layer 3 Rules

  • Endpoints Based - Apply the policy to pods based on Kubernetes label selectors
  • Services Based - Apply the policy based on kubernetes services, controlling traffic based on service names rather than individual pods
  • Entities Based - Cilium has pre-defined entities like cluster, host, and world. This type of policy uses these entities to determine what traffic the policy is applied to.
    • Cluster - Represents all kubernetes endpoints
      • Example:
        apiVersion: cilium.io/v2
        kind: CiliumNetworkPolicy
        metadata:
          name: allow-egress-to-cluster-resources
        spec:
          endpointSelector: {}
          egress:
          - toEntities:
            - cluster
        
    • World - Represents any external traffic, but not cluster traffic
      apiVersion: cilium.io/v2
      kind: CiliumNetworkPolicy
      metadata:
        name: allow-egress-to-external-resources
      spec:
        endpointSelector: {}
        egress:
        - toEntities:
          - world
      
    • Host - Represents the local kubernetes node
    • Remote-node - Represents traffic from a remote node
    • All - Represents all endpoints both internal and external to the cluster
      apiVersion: cilium.io/v2
      kind: CiliumNetworkPolicy
      metadata:
        name: allow-egress-to-external-resources
      spec:
        endpointSelector: {}
        egress:
        - toEntities:
          - all
      
  • Node Based - Apply the policy based on nodes in the cluster
  • IP/CIDR Based - Apply the policy based on IP addresses or CIDR blocks

Layer 4 Rules

  • If no layer 4 rules are defined, all traffic is allowed for layer 4
  • Example:
      apiVersion: "cilium.io/v2"
      kind: CiliumNetworkPolicy
      metadata:
        name: allow-external-80
      spec:
        endpointSelector:
          matchLabels:
            run: curl
        egress:
          - toPorts:
            - ports:
              - port: "80"
                protocol: TCP
    

Layer 7 Rules

Deny Policies

  • You can create deny policies to explicitly block traffic
  • Deny policies take higher precedence over allow policies
  • ingressDeny Example:
    apiVersion: "cilium.io/v2"
    kind: CiliumNetworkPolicy
    metadata:
      name: deny-ingress-80-for-backend
    spec:
      endpointSelector:
        matchLabels:
          app: backend
      ingressDeny:
      - fromEntities:
        - all
      - toPorts:
        - ports:
          - port: "80"
            protocol: TCP
    
  • egressDeny Example:
    apiVersion: "cilium.io/v2"
    kind: CiliumNetworkPolicy
    metadata:
      name: "deny-egress"
    spec:
      endpointSelector:
        matchLabels:
          app: random-pod
      egress:
      - toEntities:
        - all
      egressDeny:
      - toEndpoints:
        - matchLabels:
            app: server
    

Examples

Default Deny All

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: default-deny-all
spec:
  endpointSelector: {}
  ingress:
  - fromEntities:
    - world

Kubernetes Ingress

What is Ingress?

  • Ingress is an API object that manages external access to services in a Kubernetes cluster, typically HTTP and HTTPS.
  • Provides:
    • Load balancing
    • SSL termination
    • Name-based virtual hosting

Why Use Ingress?

  • To consolidate multiple service endpoints behind a single, externally accessible URL.
  • Reduce the need for creating individual LoadBalancers or NodePort services.

Key Components of Ingress

  1. Ingress Controller

    • Software that watches for Ingress resources and implements the rules.
    • Popular Ingress controllers:
      • ingress-nginx
      • Traefik
      • HAProxy
      • Istio Gateway
    • Must be installed separately in the cluster.
  2. Ingress Resource

    • The Kubernetes object that defines how requests should be routed to services.

Ingress Resource Configuration

  • As of Kubernetes 1.20, you can create an ingress using kubectl:
    kubectl create ingress  --rule="host/path=service:port"
    

Basic Structure

```
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: example-service
                port:
                  number: 80
```

Ingress with TLS

  • Kubernetes automatically creates a self-signed certificate for HTTPS. To view it, first determine the HTTPS port of the ingress controller service:

    kubeadmin@kube-controlplane:~$ k get svc -n ingress-nginx
    NAME                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
    ingress-nginx-controller             NodePort    10.103.169.156   <none>        80:31818/TCP,443:30506/TCP   38m
    ingress-nginx-controller-admission   ClusterIP   10.103.26.228    <none>        443/TCP                      38m
    kubeadmin@kube-controlplane:~$
    
  • The HTTPS port is 30506 in this case. To view the self-signed certificate, we can use curl:

     λ notes $ curl https://13.68.211.113:30506/service1 -k -v
    * (304) (OUT), TLS handshake, Finished (20):
    } [52 bytes data]
    * SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 / [blank] / UNDEF
    * ALPN: server accepted h2
    * Server certificate:
    *  subject: O=Acme Co; CN=Kubernetes Ingress Controller Fake Certificate             <<<<<<<<<<<<<<<<
    *  start date: Dec 20 14:23:08 2024 GMT
    *  expire date: Dec 20 14:23:08 2025 GMT
    *  issuer: O=Acme Co; CN=Kubernetes Ingress Controller Fake Certificate
    *  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
    * using HTTP/2
    * [HTTP/2] [1] OPENED stream for https://13.68.211.113:30506/service1
    * [HTTP/2] [1] [:method: GET]
    * [HTTP/2] [1] [:scheme: https]
    * [HTTP/2] [1] [:authority: 13.68.211.113:30506]
    * [HTTP/2] [1] [:path: /service1]
    * [HTTP/2] [1] [user-agent: Mozilla/5.0 Gecko]
    * [HTTP/2] [1] [accept: */*]
    > GET /service1 HTTP/2
    > Host: 13.68.211.113:30506
    > User-Agent: Mozilla/5.0 Gecko
    > Accept: */*
    
  • To configure a ingress resource to use TLS (HTTPS), we first need to create a certificate:

    # create a new 2048-bit RSA private key and associated cert
    openssl req -nodes -new -x509 -keyout my.key -out my.crt -subj "/CN=mysite.com"
    
  • Next, create a secret for the tls cert:

    kubectl create secret tls mycert --cert=my.crt --key=my.key -n my-namespace
    
  • Create the ingress:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: secure-ingress
      annotations:
        nginx.ingress.kubernetes.io/ssl-redirect: "true"
    spec:
      tls:
        - hosts:
            - example.com
          secretName: mycert
      rules:
        - host: example.com
          http:
            paths:
              - path: /
                pathType: Prefix
                backend:
                  service:
                    name: secure-service
                    port:
                      number: 80
    

Annotations

  • Extend the functionality of Ingress controllers.
  • Common examples (specific to nginx):
    • nginx.ingress.kubernetes.io/rewrite-target: Rewrite request paths.
    • nginx.ingress.kubernetes.io/ssl-redirect: Force SSL.
    • nginx.ingress.kubernetes.io/proxy-body-size: Limit request size.

Protecting Node Metadata and Endpoints

Protecting Endpoints

- Kubernetes clusters expose information on various ports:

    | Port Range | Purpose  |
    | ---------- | -------  | 
    | 6443       | kube-api |
    | 2379 - 2380 | etcd    |
    | 10250       | kubelet api |
    | 10259       | kube-scheduler |
    | 10257       | kube-controller-manager |

- Many of these ports are configurable. For example, to change the port that kube-api listens on, just modify `--secure-port` in the kube-api manifest.
- Setup firewall rules to minimize the attack surface

Securing Node Metadata

  • A lot of information can be obtained from node metadata

    • Node name
    • Node state
    • annotations
    • System Info
    • etc.
  • Why secure node metadata?

    • If node metadata is tampered with, pods may be assigned to the wrong nodes, which has security implications to considers
    • You can determine the version of kubelet and other kubernetes components from node metadata
    • If an attacker can modify node metadata, they could taint all the nodes, making all nodes unscheduleable
  • Protection Strategies

    • Use RBAC to control who has access to modify node metadata
    • Node isolation using labels and node selectors
    • Audit logs to determine who is accessing the cluster and respond accordingly
    • Update node operating systems regularly
    • Update cluster components regularly
  • Cloud providers such as Amazon and Azure often expose node information via metadata endpoints on the node. These endpoints are important to protect.

  • This endpoint can be accessed at 169.254.169.254 on nodes in both Azure and AWS. An example for Azure:

    curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance?api-version=2021-02-01" | jq
    
  • Node metadata endpoints can be prevented from being accessed by pods by creating network policies.

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: default-deny-ingress-metadata-server
      namespace: a12
    spec:
      policyTypes:
      - Egress
      podSelector: {}
      egress:
      - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
            - 169.254.169.254/32
    

Verify Kubernetes Binaries

  • The SHA sum of a file changes if the content within the file is changed
  • You can download the binaries from github using wget. Example: wget -O /opt/kubernetes.tar.gz https://dl.k8s.io/v1.31.1/kubernetes.tar.gz
  • To validate that a binary downloaded from the internet has not been modified, check the hash code:
    echo $(cat kubectl.sha256) kubectl | sha256sum --check
    

Securing etcd

  • etcd is a distributed key-value store that Kubernetes uses to store configuration data
  • etcd by default listens on port 2379/tcp

Play with etcd

Step 1: Create the Base Binaries Directory

```sh
    mkdir /root/binaries
    cd /root/binaries
```

Step 2: Download and Copy the ETCD Binaries to Path

```sh
    wget https://github.com/etcd-io/etcd/releases/download/v3.5.18/etcd-v3.5.18-linux-amd64.tar.gz

    tar -xzvf etcd-v3.5.18-linux-amd64.tar.gz

    cd /root/binaries/etcd-v3.5.18-linux-amd64/

    cp etcd etcdctl /usr/local/bin/
```

Step 3: Start etcd

```sh
    cd /tmp
    etcd
```

Step 4: Verification - Store and Fetch Data from etcd

```sh
    etcdctl put key1 "value1"
```

```sh
    etcdctl get key1
```

Encrypting data in transit in etcd

  • etcd supports TLS encryption for data in transit
  • By default, etcd packaged with kubeadm is configured to use TLS encryption
  • One can capture packets from etcd using tcpdump:
          root@controlplane00:/var/lib/etcd/member# tcpdump -i lo -X port 2379
    
          tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
          listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
          16:10:01.691453 IP localhost.2379 > localhost.42040: Flags [P.], seq 235868994:235869033, ack 3277609642, win 640, options [nop,nop,TS val 1280288044 ecr 1280288042], length 39
                  0x0000:  4500 005b 35e4 4000 4006 06b7 7f00 0001  E..[5.@.@.......
                  0x0010:  7f00 0001 094b a438 0e0f 1342 c35c 5aaa  .....K.8...B.\Z.
                  0x0020:  8018 0280 fe4f 0000 0101 080a 4c4f a52c  .....O......LO.,
                  0x0030:  4c4f a52a 1703 0300 2289 00d8 5dcc 7b88  LO.*...."...].{.
                  0x0040:  6f7a 290f 536b 0fd0 f7d9 1fb4 f83f 4aab  oz).Sk.......?J.
                  0x0050:  a6e7 0af8 0835 e597 a93d 4d              .....5...=M
          16:10:01.691479 IP localhost.42040 > localhost.2379: Flags [.], ack 39, win 14819, options [nop,nop,TS val 1280288044 ecr 1280288044], length 0
                  0x0000:  4500 0034 7174 4000 4006 cb4d 7f00 0001  E..4qt@.@..M....
                  0x0010:  7f00 0001 a438 094b c35c 5aaa 0e0f 1369  .....8.K.\Z....i
                  0x0020:  8010 39e3 fe28 0000 0101 080a 4c4f a52c  ..9..(......LO.,
                  0x0030:  4c4f a52c                                LO.,
          16:10:01.691611 IP localhost.2379 > localhost.42040: Flags [P.], seq 39:1222, ack 1, win 640, options [nop,nop,TS val 1280288044 ecr 1280288044], length 1183
                  0x0000:  4500 04d3 35e5 4000 4006 023e 7f00 0001  E...5.@.@..>....
                  0x0010:  7f00 0001 094b a438 0e0f 1369 c35c 5aaa  .....K.8...i.\Z.
                  0x0020:  8018 0280 02c8 0000 0101 080a 4c4f a52c  ............LO.,
                  0x0030:  4c4f a52c 1703 0304 9ac0 c579 d4ed 808c  LO.,.......y....
    
                  ..... redacted
    
  • The traffic captured in the output above is encrypted.

Encrypting data at rest in etcd

  • By default, the API server stores plain-text representations of resources into etcd, with no at-rest encryption.

  • etcd stores data in the /var/lib/etcd/member directory. When the database is not encrypted, one can easily grep the contents of this directory, looking for secrets:

    root@controlplane00:/var/lib/etcd/member# ls -lisa
    total 16
    639000 4 drwx------ 4 root root 4096 Mar 21 10:53 .
    385187 4 drwx------ 3 root root 4096 Mar 21 10:52 ..
    639002 4 drwx------ 2 root root 4096 Mar 21 14:43 snap
    638820 4 drwx------ 2 root root 4096 Mar 21 11:59 wal
    
    root@controlplane00:/var/lib/etcd/member# grep -R test-secret .
    grep: ./wal/00000000000000ac-0000000000a9340b.wal: binary file matches
    grep: ./wal/00000000000000a8-0000000000a721c1.wal: binary file matches
    grep: ./wal/00000000000000aa-0000000000a83f1e.wal: binary file matches
    grep: ./wal/00000000000000a9-0000000000a7b97e.wal: binary file matches
    grep: ./wal/00000000000000ab-0000000000a8d8a7.wal: binary file matches
    grep: ./snap/db: binary file matches
    
  • The kube-apiserver process accepts an argument –encryption-provider-config that specifies a path to a configuration file. The contents of that file, if you specify one, control how Kubernetes API data is encrypted in etcd.

  • If you are running the kube-apiserver without the –encryption-provider-config command line argument, you do not have encryption at rest enabled. If you are running the kube-apiserver with the –encryption-provider-config command line argument, and the file that it references specifies the identity provider as the first encryption provider in the list, then you do not have at-rest encryption enabled (the default identity provider does not provide any confidentiality protection.)

  • If you are running the kube-apiserver with the –encryption-provider-config command line argument, and the file that it references specifies a provider other than identity as the first encryption provider in the list, then you already have at-rest encryption enabled. However, that check does not tell you whether a previous migration to encrypted storage has succeeded.

  • Example EncryptionConfiguration:

      apiVersion: apiserver.config.k8s.io/v1
      kind: EncryptionConfiguration
      resources:
        - resources:
            - secrets
            - configmaps
            - pandas.awesome.bears.example # a custom resource API
          providers:
            # This configuration does not provide data confidentiality. The first
            # configured provider is specifying the "identity" mechanism, which
            # stores resources as plain text.
            #
            - identity: {} # plain text, in other words NO encryption
            - aesgcm:
                keys:
                  - name: key1
                    secret: c2VjcmV0IGlzIHNlY3VyZQ==
                  - name: key2
                    secret: dGhpcyBpcyBwYXNzd29yZA==
            - aescbc:
                keys:
                  - name: key1
                    secret: c2VjcmV0IGlzIHNlY3VyZQ==
                  - name: key2
                    secret: dGhpcyBpcyBwYXNzd29yZA==
            - secretbox:
                keys:
                  - name: key1
                    secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
        - resources:
            - events
          providers:
            - identity: {} # do not encrypt Events even though *.* is specified below
        - resources:
            - '*.apps' # wildcard match requires Kubernetes 1.27 or later
          providers:
            - aescbc:
                keys:
                - name: key2
                  secret: c2VjcmV0IGlzIHNlY3VyZSwgb3IgaXMgaXQ/Cg==
        - resources:
            - '*.*' # wildcard match requires Kubernetes 1.27 or later
          providers:
            - aescbc:
                keys:
                - name: key3
                  secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw==
    
  • Each resources array item is a separate config and contains a complete configuration. The resources.resources field is an array of Kubernetes resource names (resource or resource.group) that should be encrypted like Secrets, ConfigMaps, or other resources.

  • https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/

  • After enabling encryption in etcd, any resources that you created prior to enabling encryption will not be encrypted. For example, you can encrypt secrets by running:

kubectl get secrets -A -o yaml | kubectl replace -f -
  • Example of getting a secret in etcd:
root@controlplane00:/etc/kubernetes/pki# ETCDCTL_API=3 etcdctl --cacert=./etcd/ca.crt --cert=./apiserver-etcd-client.crt --key=./apiserver-etcd-client.key get /registry/secrets/default/mysecret

/registry/secrets/default/mysecret
k8s:enc:aescbc:v1:key1:ܨt>;8ܑ%TUIodEs*lsHGwjeF8S!Aqaj\Pq;9Ⱥ7dJe{B2=|p4#'BuCxUY,*IuFM
                                                                                   wxx@
2Q0e5UzH^^)rX_H%GUɈ-XqC.˽pC `kBW>K12 n

The path to the resource in the etcd database is ‘/registry///’

Securing kube-apiserver

  • Kube-apiserver acts as the gateway for all resources in kubernetes. Kube-apiserver is the only component in kubernetes that communicates with etcd
  • kube-apiserver authenticates to etcd using TLS client certificates.
  • Kube-apiserver should encrypt data before it is stored in etcd
  • kube-apiserver should only listen on an HTTPS endpoint. There was an option to host kube-apiserver on an HTTP endpoint, but this option has been deprecated as of 1.10 and removed in 1.22
  • kube-apiserver should have auditing enabled

Authentication

  • One can authentication to the KubeAPI server using certificates or a kubeconfig file

Access Controls

  • After a request is authenticated, it is authorized. Authorization is the process of determining what actions a user can perform.
  • Multiple authorization modules are supported:
    • AlwaysAllow - Allows all requests
    • AlwaysDeny - Blocks all requests
    • RBAC - Role-based access control for requests. This is the default authorization module in kubernetes
    • Node - Authorizes kubelets to access the kube-api server