Harden OS and K8s deployments 11/4511/1
authorTodd Malsbary <todd.malsbary@intel.com>
Wed, 3 Nov 2021 23:40:10 +0000 (16:40 -0700)
committerTodd Malsbary <todd.malsbary@intel.com>
Mon, 22 Nov 2021 23:13:19 +0000 (15:13 -0800)
Signed-off-by: Todd Malsbary <todd.malsbary@intel.com>
Change-Id: Ic4b917c1cd0d75762ba251cf0fdc2ac9375781da

deploy/clusters/ha-dhcp-values.yaml
deploy/clusters/resources/harden_k8s.sh [new file with mode: 0644]
deploy/clusters/resources/harden_os.sh [new file with mode: 0644]
deploy/clusters/static-values.yaml
deploy/clusters/templates/kubeadmconfigtemplate.yaml
deploy/clusters/templates/kubeadmcontrolplane.yaml
deploy/machines/example-values.yaml
deploy/site/vm/clusters-values.yaml

index b001dad..e36ad63 100644 (file)
@@ -39,8 +39,8 @@ clusters:
     # The user account created in all the machines.
     userData:
       name: ubuntu
-      # mkpasswd --method=SHA-512 --rounds 4096 "mypasswd"
-      hashedPassword: $6$rounds=4096$acxyX2VqfHJSAc2$sgVf5uTHHPCX6u50NHnJmhIoqbcL9J12jlBAaWKvd3w8uYO0iXgcBrEhtvHLgSGU7dcU.eqm9JwXEYbbRjPAi1
+      # mkpasswd --method=SHA-512 --rounds 10000 "mypasswd"
+      hashedPassword: $6$rounds=10000$PJLOBdyTv23pNp$9RpaAOcibbXUMvgJScKK2JRQioXW4XAVFMRKqgCB5jC4QmtAdbA70DU2jTcpAd6pRdEZIaWFjLCNQMBmiiL40.
       # This key will also be authorized to login as the root user
       sshAuthorizedKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrxu+fSrU51vgAO5zP5xWcTU8uLv4MkUZptE2m1BJE88JdQ80kz9DmUmq2AniMkVTy4pNeUW5PsmGJa+anN3MPM99CR9I37zRqy5i6rUDQgKjz8W12RauyeRMIBrbdy7AX1xasoTRnd6Ta47bP0egiFb+vUGnlTFhgfrbYfjbkJhVfVLCTgRw8Yj0NSK16YEyhYLbLXpix5udRpXSiFYIyAEWRCCsWJWljACr99P7EF82vCGI0UDGCCd/1upbUwZeTouD/FJBw9qppe6/1eaqRp7D36UYe3KzLpfHQNgm9AzwgYYZrD4tNN6QBMq/VUIuam0G1aLgG8IYRLs41HYkJ root@jump
 
diff --git a/deploy/clusters/resources/harden_k8s.sh b/deploy/clusters/resources/harden_k8s.sh
new file mode 100644 (file)
index 0000000..7c7780b
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+set -eux -o pipefail
+
+# Remove visibility of /version
+kubectl --kubeconfig=/etc/kubernetes/admin.conf replace -f - <<EOF
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  annotations:
+    rbac.authorization.kubernetes.io/autoupdate: "false"
+  labels:
+    kubernetes.io/bootstrapping: rbac-defaults
+  name: system:public-info-viewer
+rules:
+- nonResourceURLs:
+  - /healthz
+  - /livez
+  - /readyz
+  verbs:
+  - get
+EOF
+
+# Opt out of automatic mounting of SA token
+kubectl --kubeconfig=/etc/kubernetes/admin.conf replace -f - <<EOF
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: default
+automountServiceAccountToken: false
+EOF
diff --git a/deploy/clusters/resources/harden_os.sh b/deploy/clusters/resources/harden_os.sh
new file mode 100644 (file)
index 0000000..8af1893
--- /dev/null
@@ -0,0 +1,143 @@
+#!/usr/bin/env bash
+set -eux -o pipefail
+
+function append {
+    local -r line=$1
+    local -r file=$2
+    if [[ $(grep -c "${line}" ${file}) == 0 ]]; then
+       echo "${line}" >>${file}
+    fi
+}
+
+function replace_or_append {
+    local -r pattern=$1
+    local -r line=$2
+    local -r file=$3
+    sed -i -E '/'"${pattern}"'/ s/.*/'"${line}"'/w /tmp/changelog.txt' ${file}
+    if [[ ! -s /tmp/changelog.txt ]]; then
+       echo "${line}" >>${file}
+    fi
+}
+
+function replace_or_insert_before {
+    local -r pattern=$1
+    local -r line=$2
+    local -r before=$3
+    local -r file=$4
+    sed -i -E '/'"${pattern}"'/ s/.*/'"${line}"'/w /tmp/changelog.txt' ${file}
+    if [[ ! -s /tmp/changelog.txt ]]; then
+       cp ${file} ${file}.bak
+       awk '/'"${before}"'/ {print "'"${line}"'"}1' ${file}.bak >${file}
+       rm ${file}.bak
+    fi
+}
+
+function replace_or_insert_after {
+    local -r pattern=$1
+    local -r line=$2
+    local -r after=$3
+    local -r file=$4
+    sed -i -E '/'"${pattern}"'/ s/.*/'"${line}"'/w /tmp/changelog.txt' ${file}
+    if [[ ! -s /tmp/changelog.txt ]]; then
+       cp ${file} ${file}.bak
+       awk '/'"${after}"'/ {print; print "'"${line}"'"; next}1' ${file}.bak >${file}
+       rm ${file}.bak
+    fi
+}
+
+# Check for GRUB boot password
+# Set user and password in GRUB configuration
+# Password hash generated with grub-mkpasswd-pbkdf2, password: root
+# TODO This is currently disabled as it interferes with the reboot in set_kernel_cmdline.sh
+# cat <<END >>/etc/grub.d/00_header
+# cat <<EOF
+# set superusers="root"
+# password_pbkdf2 root grub.pbkdf2.sha512.10000.E4F52CBE09DFC3C338A314E9EDC8AA682BB2832A35FF2FF9E1D12D30EB3D58E9DDE023F88B8A82CD7BF5FC8138500CD0E67174EBA6EFACF98635A693C5AD4BB9.BB41DC42C8E2C68723B94F14F5F1E43845054A7D443C80F074E9B41C44927FEA2832B0E23C83E6B7C5E1D740B67756FA3093DA9A99B2E461A20F4831BBB289AF
+# EOF
+# END
+# update-grub
+
+# Check password hashing methods
+# Check /etc PAM and configure algorithm rounds
+sed -i -E 's/^(password\s+.*sha512)$/\1 rounds=10000/' /etc/pam.d/common-password
+echo "Passwords in /etc/shadow must be encrypted with new values"
+
+# Check group password hashing rounds
+# Configure minimum encryption algorithm rounds in /etc/login.defs
+replace_or_insert_after '^\s*SHA_CRYPT_MIN_ROUNDS\s+' 'SHA_CRYPT_MIN_ROUNDS 10000' '^#\s+SHA_CRYPT_MIN_ROUNDS' /etc/login.defs
+# Configure maximum encryption algorithm rounds in /etc/login.defs
+replace_or_insert_after '^\s*SHA_CRYPT_MAX_ROUNDS\s+' 'SHA_CRYPT_MAX_ROUNDS 10000' '^#\s+SHA_CRYPT_MAX_ROUNDS' /etc/login.defs
+
+# Checking user password aging
+# Set PASS_MAX_DAYS option in /etc/login.defs
+# PASS_MAX_DAYS of 99999 is considered unconfigued by lynis
+replace_or_insert_before '^\s*PASS_MAX_DAYS\s+' 'PASS_MAX_DAYS 99000' '^PASS_MIN_DAYS' /etc/login.defs
+
+# Default umask values
+# Set default umask in /etc/login.defs to more strict
+replace_or_append '^\s*UMASK\s+' 'UMASK 027' /etc/login.defs
+
+# Check for presence of USBGuard
+# Ensure USBGuard is installed
+apt-get -y install usbguard
+# TODO USB hubs and HID device must be enabled for BMC Console Redirection
+# Authorize USB hubs in USBGuard daemon
+append 'allow with-interface equals { 09:00:\* }' /etc/usbguard/rules.conf
+# Authorize multi-function Human Interface Devices
+append 'allow with-interface equals { 03:\*:\* 03:\*:\* }' /etc/usbguard/rules.conf
+# Set PresentControllerPolicy to apply-policy in USBGuard daemon
+sed -i -E 's/^PresentControllerPolicy\s*=\s*keep/PresentControllerPolicy=apply-policy/' /etc/usbguard/usbguard-daemon.conf
+chmod 0600 /etc/usbguard/rules.conf
+systemctl restart usbguard
+
+# Checking for debsums utility
+# Install debsums utility
+apt-get -y install debsums
+
+# Check SSH specific defined options
+# Disable AllowTcpForwarding
+replace_or_append '^\s*AllowTcpForwarding\s+' 'AllowTcpForwarding no' /etc/ssh/sshd_config
+# Set ClientAliveCountMax to 2
+replace_or_append '^\s*ClientAliveCountMax\s+' 'ClientAliveCountMax 2' /etc/ssh/sshd_config
+# Set MaxAuthTries to 3
+replace_or_append '^\s*MaxAuthTries\s+' 'MaxAuthTries 3' /etc/ssh/sshd_config
+# Set MaxSessions to 2
+# TODO MaxSessions of 2 prevents lynis from running under bluval
+replace_or_append '^\s*MaxSessions\s+' 'MaxSessions 10' /etc/ssh/sshd_config
+# Set server Port to 2222
+# TODO lynis, etc. robot files need to be updated to handle a different port
+replace_or_append '^\s*Port\s+' 'Port 22' /etc/ssh/sshd_config
+# Set client Port to 2222
+# TODO lynis, etc. robot files need to be updated to handle a different port
+replace_or_append '^\s*Port\s+' '    Port 22' /etc/ssh/ssh_config
+# Disable TCPKeepAlive
+replace_or_append '^\s*TCPKeepAlive\s+' 'TCPKeepAlive no' /etc/ssh/sshd_config
+# Restrict SSH to administrators
+replace_or_append '^\s*AllowGroups\s+' 'AllowGroups root sudo' /etc/ssh/sshd_config
+# Restart SSH
+systemctl restart ssh
+
+# Check sysctl key pairs in scan profile
+cat <<EOF >/etc/sysctl.d/99-zzz-icn.conf
+fs.suid_dumpable = 0
+kernel.core_uses_pid = 1
+kernel.dmesg_restrict = 1
+kernel.kptr_restrict = 2
+kernel.sysrq = 0
+net.ipv4.conf.all.accept_redirects = 0
+# TODO forwarding required by k8s
+# net.ipv4.conf.all.forwarding = 0
+net.ipv4.conf.all.log_martians = 1
+net.ipv4.conf.all.rp_filter = 1
+net.ipv4.conf.all.send_redirects = 0
+net.ipv4.conf.default.accept_redirects = 0
+net.ipv4.conf.default.accept_source_route = 0
+net.ipv4.conf.default.log_martians = 1
+net.ipv6.conf.all.accept_redirects = 0
+net.ipv6.conf.default.accept_redirects = 0
+EOF
+sysctl --system
+
+# Check compiler permissions
+# Uninstall compilers
+apt-get -y remove gcc binutils
index 4df5373..f4ecfe0 100644 (file)
@@ -35,8 +35,8 @@ clusters:
     # The user account created in all the machines.
     userData:
       name: ubuntu
-      # mkpasswd --method=SHA-512 --rounds 4096 "mypasswd"
-      hashedPassword: $6$rounds=4096$acxyX2VqfHJSAc2$sgVf5uTHHPCX6u50NHnJmhIoqbcL9J12jlBAaWKvd3w8uYO0iXgcBrEhtvHLgSGU7dcU.eqm9JwXEYbbRjPAi1
+      # mkpasswd --method=SHA-512 --rounds 10000 "mypasswd"
+      hashedPassword: $6$rounds=10000$PJLOBdyTv23pNp$9RpaAOcibbXUMvgJScKK2JRQioXW4XAVFMRKqgCB5jC4QmtAdbA70DU2jTcpAd6pRdEZIaWFjLCNQMBmiiL40.
       # This key will also be authorized to login as the root user
       sshAuthorizedKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrxu+fSrU51vgAO5zP5xWcTU8uLv4MkUZptE2m1BJE88JdQ80kz9DmUmq2AniMkVTy4pNeUW5PsmGJa+anN3MPM99CR9I37zRqy5i6rUDQgKjz8W12RauyeRMIBrbdy7AX1xasoTRnd6Ta47bP0egiFb+vUGnlTFhgfrbYfjbkJhVfVLCTgRw8Yj0NSK16YEyhYLbLXpix5udRpXSiFYIyAEWRCCsWJWljACr99P7EF82vCGI0UDGCCd/1upbUwZeTouD/FJBw9qppe6/1eaqRp7D36UYe3KzLpfHQNgm9AzwgYYZrD4tNN6QBMq/VUIuam0G1aLgG8IYRLs41HYkJ root@jump
 
index 2bfc97d..741bf69 100644 (file)
@@ -31,6 +31,7 @@ spec:
       - apt-get install -y kubelet={{ $cluster.kubeVersion }} kubeadm={{ $cluster.kubeVersion }} kubectl={{ $cluster.kubeVersion }}
       - systemctl enable --now kubelet
       postKubeadmCommands:
+      - /usr/local/bin/harden_os.sh
       # This must be done after kubeadm as the cabpk provider relies
       # on files in /var/run, which won't persist after a reboot
       - /usr/local/bin/set_kernel_cmdline.sh
@@ -39,6 +40,10 @@ spec:
       - path: /etc/systemd/system/containerd.service.d/override.conf
         content: |
 {{ $.Files.Get "resources/override.conf" | indent 10 }}
+      - path: /usr/local/bin/harden_os.sh
+        permissions: '0777'
+        content: |
+{{ $.Files.Get "resources/harden_os.sh" | indent 10 }}
       - path: /usr/local/bin/set_kernel_cmdline.sh
         permissions: '0777'
         content: |
@@ -51,6 +56,7 @@ spec:
         sshAuthorizedKeys:
         - {{ $cluster.userData.sshAuthorizedKey }}
         sudo: "ALL=(ALL) NOPASSWD:ALL"
+        groups: sudo # Necessary to allow SSH logins (see /etc/ssh/sshd_config)
       - name: root
         sshAuthorizedKeys:
         - {{ $cluster.userData.sshAuthorizedKey }}
index a3881b6..a77d992 100644 (file)
@@ -43,6 +43,13 @@ spec:
     - mkdir -p /home/ubuntu/.kube
     - cp /etc/kubernetes/admin.conf /home/ubuntu/.kube/config
     - chown ubuntu:ubuntu /home/ubuntu/.kube/config
+    - mkdir -p /root/.kube
+    - cp /etc/kubernetes/admin.conf /root/.kube/config
+    - /usr/local/bin/harden_os.sh
+    # Normally any bootstrap resources needed would be applied with a
+    # ClusterResourceSet.  However instead of apply, replace must be
+    # used to harden K8s.
+    - /usr/local/bin/harden_k8s.sh
     # This must be done after kubeadm as the cabpk provider relies on
     # files in /var/run, which won't persist after a reboot
     - /usr/local/bin/set_kernel_cmdline.sh
@@ -52,6 +59,14 @@ spec:
     - path: /etc/systemd/system/containerd.service.d/override.conf
       content: |
 {{ $.Files.Get "resources/override.conf" | indent 8 }}
+    - path: /usr/local/bin/harden_os.sh
+      permissions: '0777'
+      content: |
+{{ $.Files.Get "resources/harden_os.sh" | indent 8 }}
+    - path: /usr/local/bin/harden_k8s.sh
+      permissions: '0777'
+      content: |
+{{ $.Files.Get "resources/harden_k8s.sh" | indent 8 }}
     - path: /usr/local/bin/set_kernel_cmdline.sh
       permissions: '0777'
       content: |
@@ -64,6 +79,7 @@ spec:
       sshAuthorizedKeys:
       - {{ $cluster.userData.sshAuthorizedKey }}
       sudo: "ALL=(ALL) NOPASSWD:ALL"
+      groups: sudo # Necessary to allow SSH logins (see /etc/ssh/sshd_config)
     - name: root
       sshAuthorizedKeys:
       - {{ $cluster.userData.sshAuthorizedKey }}
index 3c68b2d..3138baa 100644 (file)
@@ -22,6 +22,6 @@ machines:
     # Optional
     userData:
       name: ubuntu
-      hashedPassword: $6$rounds=4096$acxyX2VqfHJSAc2$sgVf5uTHHPCX6u50NHnJmhIoqbcL9J12jlBAaWKvd3w8uYO0iXgcBrEhtvHLgSGU7dcU.eqm9JwXEYbbRjPAi1
+      hashedPassword: $6$rounds=10000$PJLOBdyTv23pNp$9RpaAOcibbXUMvgJScKK2JRQioXW4XAVFMRKqgCB5jC4QmtAdbA70DU2jTcpAd6pRdEZIaWFjLCNQMBmiiL40.
       sshAuthorizedKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrxu+fSrU51vgAO5zP5xWcTU8uLv4MkUZptE2m1BJE88JdQ80kz9DmUmq2AniMkVTy4pNeUW5PsmGJa+anN3MPM99CR9I37zRqy5i6rUDQgKjz8W12RauyeRMIBrbdy7AX1xasoTRnd6Ta47bP0egiFb+vUGnlTFhgfrbYfjbkJhVfVLCTgRw8Yj0NSK16YEyhYLbLXpix5udRpXSiFYIyAEWRCCsWJWljACr99P7EF82vCGI0UDGCCd/1upbUwZeTouD/FJBw9qppe6/1eaqRp7D36UYe3KzLpfHQNgm9AzwgYYZrD4tNN6QBMq/VUIuam0G1aLgG8IYRLs41HYkJ root@jump
       fqdn: machine-1.akraino.icn.org
index dd8baaf..5a8d277 100644 (file)
@@ -17,7 +17,7 @@ clusters:
         interface: ens5
     userData:
       name: ubuntu
-      hashedPassword: $6$rounds=4096$acxyX2VqfHJSAc2$sgVf5uTHHPCX6u50NHnJmhIoqbcL9J12jlBAaWKvd3w8uYO0iXgcBrEhtvHLgSGU7dcU.eqm9JwXEYbbRjPAi1
+      hashedPassword: $6$rounds=10000$PJLOBdyTv23pNp$9RpaAOcibbXUMvgJScKK2JRQioXW4XAVFMRKqgCB5jC4QmtAdbA70DU2jTcpAd6pRdEZIaWFjLCNQMBmiiL40.
       sshAuthorizedKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrxu+fSrU51vgAO5zP5xWcTU8uLv4MkUZptE2m1BJE88JdQ80kz9DmUmq2AniMkVTy4pNeUW5PsmGJa+anN3MPM99CR9I37zRqy5i6rUDQgKjz8W12RauyeRMIBrbdy7AX1xasoTRnd6Ta47bP0egiFb+vUGnlTFhgfrbYfjbkJhVfVLCTgRw8Yj0NSK16YEyhYLbLXpix5udRpXSiFYIyAEWRCCsWJWljACr99P7EF82vCGI0UDGCCd/1upbUwZeTouD/FJBw9qppe6/1eaqRp7D36UYe3KzLpfHQNgm9AzwgYYZrD4tNN6QBMq/VUIuam0G1aLgG8IYRLs41HYkJ root@jump
     flux:
       repositoryName: icn