If you want to improve the security on your cluster and make it compliant with the CIS Benchmarks, here you can find a configuration to harden your kubernetes installation.
To apply the hardening configuration, create a file (eg. hardening.yaml
) and paste the content of the following code snippet into that.
The kubernetes version should be at least v1.23.6
to have all the most recent security features (eg. the new PodSecurity
admission plugin, etc).
N.B. Some of these configurations have just been added to kubespray, so ensure that you have the latest version to make it works properly. Also, ensure that other configurations doesn't override these.
hardening.yaml
:
# Hardening
---
## kube-apiserver
authorization_modes: ['Node', 'RBAC']
# AppArmor-based OS
# kube_apiserver_feature_gates: ['AppArmor=true']
kube_apiserver_request_timeout: 120s
kube_apiserver_service_account_lookup: true
# enable kubernetes audit
kubernetes_audit: true
audit_log_path: "/var/log/kube-apiserver-log.json"
audit_log_maxage: 30
audit_log_maxbackups: 10
audit_log_maxsize: 100
tls_min_version: VersionTLS12
tls_cipher_suites:
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
# enable encryption at rest
kube_encrypt_secret_data: true
kube_encryption_resources: [secrets]
kube_encryption_algorithm: "secretbox"
kube_apiserver_enable_admission_plugins: ['EventRateLimit,AlwaysPullImages,ServiceAccount,NamespaceLifecycle,NodeRestriction,LimitRanger,ResourceQuota,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,PodNodeSelector,PodSecurity']
kube_apiserver_admission_control_config_file: true
# EventRateLimit plugin configuration
kube_apiserver_admission_event_rate_limits:
limit_1:
type: Namespace
qps: 50
burst: 100
cache_size: 2000
limit_2:
type: User
qps: 50
burst: 100
kube_profiling: false
## kube-controller-manager
kube_controller_manager_bind_address: 127.0.0.1
kube_controller_terminated_pod_gc_threshold: 50
# AppArmor-based OS
# kube_controller_feature_gates: ["RotateKubeletServerCertificate=true", "AppArmor=true"]
kube_controller_feature_gates: ["RotateKubeletServerCertificate=true"]
## kube-scheduler
kube_scheduler_bind_address: 127.0.0.1
kube_kubeadm_scheduler_extra_args:
profiling: false
# AppArmor-based OS
# kube_scheduler_feature_gates: ["AppArmor=true"]
## etcd
etcd_deployment_type: kubeadm
## kubelet
kubelet_authentication_token_webhook: true
kube_read_only_port: 0
kubelet_rotate_server_certificates: true
kubelet_protect_kernel_defaults: true
kubelet_event_record_qps: 1
kubelet_rotate_certificates: true
kubelet_streaming_connection_idle_timeout: "5m"
kubelet_make_iptables_util_chains: true
kubelet_feature_gates: ["RotateKubeletServerCertificate=true", "SeccompDefault=true"]
kubelet_seccomp_default: true
kubelet_systemd_hardening: true
# In case you have multiple interfaces in your
# control plane nodes and you want to specify the right
# IP addresses, kubelet_secure_addresses allows you
# to specify the IP from which the kubelet
# will receive the packets.
kubelet_secure_addresses: "192.168.10.110 192.168.10.111 192.168.10.112"
# additional configurations
kube_owner: root
kube_cert_group: root
# create a default Pod Security Configuration and deny running of insecure pods
# kube_system namespace is exempted by default
kube_pod_security_use_default: true
kube_pod_security_default_enforce: restricted
Let's take a deep look to the resultant kubernetes configuration:
- The
anonymous-auth
(onkube-apiserver
) is set totrue
by default. This is fine, because it is considered safe if you enableRBAC
for theauthorization-mode
. - The
enable-admission-plugins
has not thePodSecurityPolicy
admission plugin. This because it is going to be definitely removed from kubernetesv1.25
. For this reason we decided to set the newestPodSecurity
(for more details, please take a look here: https://kubernetes.io/docs/concepts/security/pod-security-admission/). Then, we set theEventRateLimit
plugin, providing additional configuration files (that are automatically created under the hood and mounted inside thekube-apiserver
container) to make it work. - The
encryption-provider-config
provide encryption at rest. This means that thekube-apiserver
encrypt data that is going to be stored before they reachetcd
. So the data is completely unreadable frometcd
(in case an attacker is able to exploit this). - The
rotateCertificates
inKubeletConfiguration
is set totrue
along withserverTLSBootstrap
. This could be used in alternative totlsCertFile
andtlsPrivateKeyFile
parameters. Additionally it automatically generates certificates by itself, but you need to manually approve them or at least using an operator to do this (for more details, please take a look here: https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/). - If you are installing kubernetes in an AppArmor-based OS (eg. Debian/Ubuntu) you can enable the
AppArmor
feature gate uncommenting the lines with the comment# AppArmor-based OS
on top. - The
kubelet_systemd_hardening
, both withkubelet_secure_addresses
setup a minimal firewall on the system. To better understand how these variables work, here's an explanatory image:
Once you have the file properly filled, you can run the Ansible command to start the installation:
ansible-playbook -v cluster.yml \
-i inventory.ini \
-b --become-user=root \
--private-key ~/.ssh/id_ecdsa \
-e "@vars.yaml" \
-e "@hardening.yaml"
N.B. The vars.yaml
contains our general cluster information (SANs, load balancer, dns, etc..) and hardening.yaml
is the file described above.
Once completed the cluster deployment, don't forget to approve the generated certificates (check them with kubectl get csr
, approve with kubectl certificate approve <csr_name>
). This action is necessary because the secureTLSBootstrap
option and RotateKubeletServerCertificate
feature gate for kubelet
are enabled (CIS 4.2.11, 4.2.12).