Skip to content

Commit ea9de44

Browse files
authored
Merge pull request #34 from cyclops-k8s/ec-cis1.12
Update to CIS Benchmark 1.12
2 parents 8fed49b + a769342 commit ea9de44

File tree

10 files changed

+73
-25
lines changed

10 files changed

+73
-25
lines changed

CIS hardening.md

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# CIS Benchmark
22

3-
I used the CIS Kubernetes Benchmark 1.9
3+
I used the CIS Kubernetes Benchmark 1.12
44

55
## 1.1 - Control plane
66

@@ -42,7 +42,7 @@ We use externalIP services
4242

4343
Set by default
4444

45-
### 1.2.5 - Ensure that the --kubelet-certificate-authority argument is set as appropriate (Automated)
45+
### 1.2.5 - Ensure that the --kubelet-certificate-authority argument is set as appropriate (Automated)
4646

4747
Fixed using automatic certificate renewal and issuing to kubelets
4848

@@ -70,7 +70,7 @@ Set by default
7070

7171
### 1.2.15
7272

73-
New relic uses the profiling data
73+
Fixed
7474

7575
### 1.2.16 - Ensure that the --audit-log-path argument is set
7676

@@ -96,7 +96,11 @@ Set by default
9696

9797
Set by default
9898

99-
### 1.2.29 - Ensure that the API Server only makes use of Strong Cryptographic Ciphers (Manual)
99+
### 1.2.29 - Ensure that the API Server only makes use of Strong Cryptographic Ciphers (Manual)
100+
101+
Fixed
102+
103+
### 1.2.30 - Ensure that the --service-account-extend-token-expiration parameter is set to false
100104

101105
Fixed
102106

@@ -108,7 +112,7 @@ Fixed
108112

109113
### 1.3.2 - Ensure that the --profiling argument is set to false
110114

111-
New Relic uses the profiling information
115+
Fixed
112116

113117
### 1.3.3 - 1.3.7
114118

@@ -118,7 +122,7 @@ Set by default
118122

119123
### 1.4.1 - Ensure that the --profiling argument is set to false
120124

121-
New Relic uses the profiling information
125+
Fixed
122126

123127
### 1.4.2
124128

@@ -164,7 +168,7 @@ Set by default
164168

165169
Set by default - config file is stored in the container
166170

167-
### 4.1.4 - If proxy kubeconfig file exists ensure ownership is set to root:root (Manual)
171+
### 4.1.4 - If proxy kubeconfig file exists ensure ownership is set to root:root (Manual)
168172

169173
Set by default - config file is stored in the container
170174

@@ -206,7 +210,7 @@ Setting serverTLSBootstrap resolves this
206210

207211
Set by default
208212

209-
### 4.2.11 - Verify that the RotateKubeletServerCertificate argument is set to true (Manual)
213+
### 4.2.11 - Verify that the RotateKubeletServerCertificate argument is set to true (Manual)
210214

211215
Set by default
212216

@@ -218,9 +222,13 @@ Fixed
218222

219223
Fixed
220224

225+
### 4.2.14 - Ensure that the --seccomp-default parameter is set to true
226+
227+
Fixed
228+
221229
## 4.3 - Kube Proxy
222230

223-
### 4.3.1 - Ensure that the kube-proxy metrics service is bound to localhost (Automated)
231+
### 4.3.1 - Ensure that the kube-proxy metrics service is bound to localhost (Automated)
224232

225233
Fixed
226234

@@ -238,6 +246,6 @@ Set by default
238246

239247
Fixed for initally created namespaces, it's a mnaul process to maintain the configuration on all default service accounts
240248

241-
### 5.1.6 - 5.1.11
249+
### 5.1.6 - 5.1.13
242250

243251
Set by default

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
## Purpose
1818

19-
The purpose of this playbook and roles is to install a vanilla Kubernetes cluster with OIDC enabled hardened against the CIS Benchmark and DOD Stig.
19+
The purpose of this playbook and roles is to install a vanilla Kubernetes cluster with OIDC enabled hardened against the CIS Benchmark 1.12 and DOD Stig.
2020

2121
It is a vanilla `kubeadm` cluster that can be managed by `kubeadm` going forward, or for easy upgrades you can use the included `upgrade` playbook.
2222

roles/kubernetes-control-plane/tasks/main.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@
2323
register: temp_token
2424
changed_when: true
2525

26+
- name: Get CA certificate hash
27+
ansible.builtin.shell:
28+
cmd: |
29+
set -eo pipefail
30+
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | \
31+
openssl rsa -pubin -outform der 2>/dev/null | \
32+
openssl dgst -sha256 -hex | sed 's/^.* //'
33+
executable: /bin/bash
34+
delegate_to: "{{ first_kube_control_plane }}"
35+
run_once: true
36+
register: cluster_ca_cert_hash_temp
37+
changed_when: false
38+
2639
- name: Upload certificates so they are fresh and not expired
2740
ansible.builtin.command:
2841
cmd: kubeadm init phase --config {{ kubernetes_config_directory }}/kubeadm.yaml upload-certs --upload-certs
@@ -35,6 +48,7 @@
3548
ansible.builtin.set_fact:
3649
join_token: "{{ temp_token.stdout }}"
3750
kubeadm_upload_token: "{{ kubeadm_upload_cert.stdout_lines[-1] | trim }}"
51+
cluster_ca_cert_hash: "sha256:{{ cluster_ca_cert_hash_temp.stdout }}"
3852
run_once: true
3953

4054
- name: Configure additional control planes

roles/kubernetes-control-plane/templates/kubeadm-init-1.33.yaml.j2

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ tlsCipherSuites:
1919
podPidsLimit: {{ kubernetes_podpidslimit }}
2020
# STIG V-242434
2121
protectKernelDefaults: true
22+
# CIS 4.2.14
23+
seccompDefault: {{ kubernetes_seccomp_default }}
2224
---
2325
apiVersion: kubeadm.k8s.io/v1beta4
2426
kind: ClusterConfiguration
@@ -105,6 +107,9 @@ apiServer:
105107
- name: service-account-issuer
106108
value: "{{ kubernetes_service_account_issuer }}"
107109
{% endif %}
110+
# CIS 1.2.30
111+
- name: service-account-extend-token-expiration
112+
value: "{{ kubernetes_service_account_extend_token_expiration | lower }}"
108113
{% if kubernetes_api_server_extra_args is defined and kubernetes_api_server_extra_args | length > 0 %}
109114
{% for arg in kubernetes_api_server_extra_args %}
110115
- name: "{{ arg.name }}"
@@ -203,7 +208,7 @@ skipPhases:
203208
{% endfor %}
204209
{% endif %}
205210
localAPIEndpoint:
206-
advertiseAddress: "{{ kubernetes_api_server_bind_address if kubernetes_api_server_bind_address != None else query('community.dns.lookup', ansible_host)[0] }}"
211+
advertiseAddress: "{{ kubernetes_api_server_bind_address if kubernetes_api_server_bind_address != None else query('community.dns.lookup', ansible_facts['fqdn'])[0] }}"
207212
bindPort: {{ kubernetes_api_server_port }}
208213
nodeRegistration:
209214
kubeletExtraArgs:
@@ -212,7 +217,7 @@ nodeRegistration:
212217
value: "external"
213218
{% endif %}
214219
- name: node-ip
215-
value: "{{ kubernetes_kubelet_node_ip | default(ansible_default_ipv4.address) }}"
220+
value: "{{ kubernetes_kubelet_node_ip | default(ansible_facts['default_ipv4'].address) }}"
216221
patches:
217222
directory: "{{ kubernetes_config_directory }}/patches"
218223
timeouts:

roles/kubernetes-control-plane/templates/kubeadm-init-1.34.yaml.j2

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ tlsCipherSuites:
1919
podPidsLimit: {{ kubernetes_podpidslimit }}
2020
# STIG V-242434
2121
protectKernelDefaults: true
22+
# CIS 4.2.14
23+
seccompDefault: {{ kubernetes_seccomp_default }}
2224
---
2325
apiVersion: kubeadm.k8s.io/v1beta4
2426
kind: ClusterConfiguration
@@ -105,6 +107,9 @@ apiServer:
105107
- name: service-account-issuer
106108
value: "{{ kubernetes_service_account_issuer }}"
107109
{% endif %}
110+
# CIS 1.2.30
111+
- name: service-account-extend-token-expiration
112+
value: "{{ kubernetes_service_account_extend_token_expiration | lower }}"
108113
{% if kubernetes_api_server_extra_args is defined and kubernetes_api_server_extra_args | length > 0 %}
109114
{% for arg in kubernetes_api_server_extra_args %}
110115
- name: "{{ arg.name }}"
@@ -203,7 +208,7 @@ skipPhases:
203208
{% endfor %}
204209
{% endif %}
205210
localAPIEndpoint:
206-
advertiseAddress: "{{ kubernetes_api_server_bind_address if kubernetes_api_server_bind_address != None else query('community.dns.lookup', ansible_host)[0] }}"
211+
advertiseAddress: "{{ kubernetes_api_server_bind_address if kubernetes_api_server_bind_address != None else query('community.dns.lookup', ansible_facts['fqdn'])[0] }}"
207212
bindPort: {{ kubernetes_api_server_port }}
208213
nodeRegistration:
209214
kubeletExtraArgs:
@@ -212,7 +217,7 @@ nodeRegistration:
212217
value: "external"
213218
{% endif %}
214219
- name: node-ip
215-
value: "{{ kubernetes_kubelet_node_ip | default(ansible_default_ipv4.address) }}"
220+
value: "{{ kubernetes_kubelet_node_ip | default(ansible_facts['default_ipv4'].address) }}"
216221
patches:
217222
directory: "{{ kubernetes_config_directory }}/patches"
218223
timeouts:

roles/kubernetes-control-plane/templates/kubeadm-join-1.33.yaml.j2

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,21 @@ tlsCipherSuites:
1919
podPidsLimit: {{ kubernetes_podpidslimit }}
2020
# STIG V-242434
2121
protectKernelDefaults: true
22+
# CIS 4.2.14
23+
seccompDefault: {{ kubernetes_seccomp_default }}
2224
---
2325
apiVersion: kubeadm.k8s.io/v1beta4
2426
kind: JoinConfiguration
2527
discovery:
2628
bootstrapToken:
2729
apiServerEndpoint: "{{ kubernetes_api_endpoint }}:{{ kubernetes_api_port }}"
2830
token: "{{ join_token }}"
29-
unsafeSkipCAVerification: true
31+
caCertHashes:
32+
- "{{ cluster_ca_cert_hash }}"
3033
caCertPath: "{{ kubernetes_pki_directory }}/ca.crt"
3134
controlPlane:
3235
localAPIEndpoint:
33-
advertiseAddress: "{{ kubernetes_api_server_bind_address if kubernetes_api_server_bind_address != None else query('community.dns.lookup', ansible_host)[0] }}"
36+
advertiseAddress: "{{ kubernetes_api_server_bind_address if kubernetes_api_server_bind_address != None else query('community.dns.lookup', ansible_facts['fqdn'])[0] }}"
3437
bindPort: {{ kubernetes_api_server_port }}
3538
certificateKey: "{{ kubeadm_upload_token }}"
3639
nodeRegistration:
@@ -40,6 +43,6 @@ nodeRegistration:
4043
value: "external"
4144
{% endif %}
4245
- name: node-ip
43-
value: "{{ kubernetes_kubelet_node_ip | default(ansible_default_ipv4.address) }}"
46+
value: "{{ kubernetes_kubelet_node_ip | default(ansible_facts['default_ipv4'].address) }}"
4447
patches:
4548
directory: {{ kubernetes_config_directory }}/patches

roles/kubernetes-control-plane/templates/kubeadm-join-1.34.yaml.j2

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,21 @@ tlsCipherSuites:
1919
podPidsLimit: {{ kubernetes_podpidslimit }}
2020
# STIG V-242434
2121
protectKernelDefaults: true
22+
# CIS 4.2.14
23+
seccompDefault: {{ kubernetes_seccomp_default }}
2224
---
2325
apiVersion: kubeadm.k8s.io/v1beta4
2426
kind: JoinConfiguration
2527
discovery:
2628
bootstrapToken:
2729
apiServerEndpoint: "{{ kubernetes_api_endpoint }}:{{ kubernetes_api_port }}"
2830
token: "{{ join_token }}"
29-
unsafeSkipCAVerification: true
31+
caCertHashes:
32+
- "{{ cluster_ca_cert_hash }}"
3033
caCertPath: "{{ kubernetes_pki_directory }}/ca.crt"
3134
controlPlane:
3235
localAPIEndpoint:
33-
advertiseAddress: "{{ kubernetes_api_server_bind_address if kubernetes_api_server_bind_address != None else query('community.dns.lookup', ansible_host)[0] }}"
36+
advertiseAddress: "{{ kubernetes_api_server_bind_address if kubernetes_api_server_bind_address != None else query('community.dns.lookup', ansible_facts['fqdn'])[0] }}"
3437
bindPort: {{ kubernetes_api_server_port }}
3538
certificateKey: "{{ kubeadm_upload_token }}"
3639
nodeRegistration:
@@ -40,6 +43,6 @@ nodeRegistration:
4043
value: "external"
4144
{% endif %}
4245
- name: node-ip
43-
value: "{{ kubernetes_kubelet_node_ip | default(ansible_default_ipv4.address) }}"
46+
value: "{{ kubernetes_kubelet_node_ip | default(ansible_facts['default_ipv4'].address) }}"
4447
patches:
4548
directory: {{ kubernetes_config_directory }}/patches

roles/kubernetes-defaults/defaults/main.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,12 @@ kubernetes_scheduler_extra_args: []
345345
# Directory to store scripts for Kubernetes on the nodes
346346
kubernetes_scripts_directory: /opt/kubernetes/scripts
347347

348+
# CIS 4.2.14 - Ensure that seccomp is enabled by default in the Kubelet
349+
kubernetes_seccomp_default: true
350+
351+
# CIS 1.2.30 - Ensure that the --service-account-extend-token-expiration argument is set to false
352+
kubernetes_service_account_extend_token_expiration: false
353+
348354
# Subnet for the cluster services running in the Kubernetes cluster
349355
kubernetes_service_subnet: 10.96.0.0/16
350356

roles/kubernetes-worker/tasks/main.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
ansible.builtin.set_fact:
1212
kubernetes_needs_to_join_cluster: "{% if inventory_hostname in kubernetes_nodes.stdout_lines or inventory_hostname_short in kubernetes_nodes.stdout_lines %}{{ 'false' | bool }}{% else %}{{ 'true' | bool }}{% endif %}"
1313

14-
- name: Set join token
14+
- name: Set variables from first control plane
1515
ansible.builtin.set_fact:
1616
join_token: "{{ hostvars[first_kube_control_plane].join_token }}"
17+
cluster_ca_cert_hash: "{{ hostvars[first_kube_control_plane].cluster_ca_cert_hash }}"
1718

1819
- name: Create kubeadm file
1920
ansible.builtin.template:

roles/kubernetes-worker/templates/worker-kubeadm.yaml.j2

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ tlsCipherSuites:
1919
podPidsLimit: {{ kubernetes_podpidslimit }}
2020
# STIG V-242434
2121
protectKernelDefaults: true
22+
# CIS 4.2.14
23+
seccompDefault: {{ kubernetes_seccomp_default }}
2224
---
2325
apiVersion: kubeproxy.config.k8s.io/v1alpha1
2426
kind: KubeProxyConfiguration
@@ -29,13 +31,14 @@ kind: JoinConfiguration
2931
discovery:
3032
bootstrapToken:
3133
apiServerEndpoint: "{{ kubernetes_api_endpoint }}:{{ kubernetes_api_port }}"
32-
token: "{{ join_token}}"
33-
unsafeSkipCAVerification: true
34+
token: "{{ join_token }}"
35+
caCertHashes:
36+
- "{{ cluster_ca_cert_hash }}"
3437
nodeRegistration:
3538
kubeletExtraArgs:
3639
{% if kubernetes_cloud_provider == 'external' %}
3740
- name: cloud-provider
3841
value: "external"
3942
{% endif %}
4043
- name: node-ip
41-
value: "{{ kubernetes_kubelet_node_ip | default(ansible_default_ipv4.address) }}"
44+
value: "{{ kubernetes_kubelet_node_ip | default(ansible_facts['default_ipv4'].address) }}"

0 commit comments

Comments
 (0)