RKE2 Security Hardening Guide
This guide provides comprehensive security hardening practices for production RKE2 deployments, focusing on CIS benchmark compliance, FIPS 140-2 compliance, and defense-in-depth strategies.
CIS Benchmark Compliance
RKE2 includes built-in support for CIS Kubernetes Benchmark v1.9 compliance through the CIS profile.
Enabling CIS Profile
Configure RKE2 with the CIS profile to automatically apply security hardening:
# /etc/rancher/rke2/config.yaml
profile: "cis"
secrets-encryption: true
write-kubeconfig-mode: "0640"CIS Profile Features
The CIS profile automatically configures:
- ✅ API Server Hardening: Secure API server flags and authentication
- ✅ etcd Security: Encrypted communication and proper permissions
- ✅ Kubelet Hardening: Secure kubelet configuration
- ✅ Network Policies: Default deny-all network policies
- ✅ Pod Security Standards: Restricted pod security policies
- ✅ RBAC: Least-privilege access controls
Required System Preparation
Create etcd User and Group
CIS compliance requires etcd to run as a non-root user:
# Create etcd group if it doesn't exist
getent group etcd >/dev/null || sudo groupadd --system etcd
# Create etcd user if it doesn't exist
id -u etcd >/dev/null 2>&1 || sudo useradd --system --no-create-home --shell /sbin/nologin --gid etcd etcdSELinux Configuration (RHEL/CentOS/Rocky)
For RHEL-based systems, ensure SELinux is properly configured:
# Check SELinux status
sestatus
# Ensure SELinux is enforcing
sudo setenforce 1
# Install RKE2 SELinux policies
sudo dnf install -y rke2-selinux
# Verify policies are loaded
sudo semodule -l | grep rke2AppArmor Configuration (Ubuntu/Debian)
For Ubuntu-based systems, configure AppArmor:
# Check AppArmor status
sudo aa-status
# Ensure AppArmor is enabled
sudo systemctl enable apparmor
sudo systemctl start apparmor
# Load default profiles
sudo apparmor_parser -r /etc/apparmor.d/*Security Validation
CIS Benchmark Scanning
Using kube-bench
Install and run kube-bench for CIS compliance validation:
# Download kube-bench
curl -Lo kube-bench https://github.com/aquasecurity/kube-bench/releases/latest/download/kube-bench-linux-amd64
chmod +x kube-bench && sudo mv kube-bench /usr/local/bin/
# Run CIS 1.9 benchmark
kube-bench --benchmark cis-1.9
# Generate report
kube-bench --benchmark cis-1.9 --json > cis-report.jsonAutomated CIS Scanning with Rancher
If using Rancher, enable automated CIS scanning:
apiVersion: cis.cattle.io/v1
kind: ClusterScan
metadata:
name: cis-scan-scheduled
spec:
scanProfileName: "cis-1.9"
scoreWarning: 80
runType: "scheduled"
cronSchedule: "0 2 * * 0" # Weekly on Sunday at 2 AMNetwork Security
Cilium Network Policies
Implement defense-in-depth with Cilium network policies:
# Default deny-all policy
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
endpointSelector: {}
ingress: []
egress: []
---
# Allow necessary system communication
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-system-dns
namespace: production
spec:
endpointSelector: {}
egress:
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
- port: "53"
protocol: TCPWireGuard Encryption
Enable transparent WireGuard encryption for all pod-to-pod communication:
# Cilium configuration with WireGuard
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: rke2-cilium
namespace: kube-system
spec:
valuesContent: |-
encryption:
enabled: true
type: "wireguard"
# Additional security configurations
l7Proxy: false # Disable if not needed for performance
# Enable security monitoring
hubble:
enabled: true
metrics:
enabled:
- dns
- drop
- tcp
- flow
- policy-verdictPod Security Standards
Pod Security Policies (Deprecated) vs Pod Security Standards
RKE2 with CIS profile uses Pod Security Standards instead of deprecated Pod Security Policies:
# Namespace with restricted pod security
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restrictedSecurity Context Requirements
Ensure all workloads use secure contexts:
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
namespace: production
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:alpine
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache/nginx
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}RBAC Configuration
Least Privilege Access
Implement strict RBAC policies:
# Service account for application
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-service-account
namespace: production
---
# Minimal role for application
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-role
namespace: production
rules:
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
# Role binding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-role-binding
namespace: production
subjects:
- kind: ServiceAccount
name: app-service-account
namespace: production
roleRef:
kind: Role
name: app-role
apiGroup: rbac.authorization.k8s.ioCluster-Level Security
# Deny all cluster admin access by default
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: no-cluster-admin
rules:
- apiGroups: [""]
resources: ["*"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps", "extensions"]
resources: ["*"]
verbs: ["get", "list", "watch"]Certificate Security
Certificate Management
RKE2 automatically manages certificates with proper security:
# View certificate expiration
for cert in /var/lib/rancher/rke2/server/tls/*.crt; do
echo "=== $cert ==="
openssl x509 -in "$cert" -noout -dates
done
# Check certificate SANs
openssl x509 -in /var/lib/rancher/rke2/server/tls/serving-kube-apiserver.crt -noout -text | grep -A1 "Subject Alternative Name"Custom Certificate Authority
For enterprise environments, use a custom CA:
# /etc/rancher/rke2/config.yaml
cluster-ca-certificate: "/path/to/ca.crt"
cluster-ca-key: "/path/to/ca.key"Secret Management
External Secrets Operator
Integrate with external secret management:
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
namespace: production
spec:
provider:
vault:
server: "https://vault.internal.example.com"
path: "kv"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "rke2-production"
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
namespace: production
spec:
refreshInterval: 300s
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: app-secrets
creationPolicy: Owner
data:
- secretKey: database-password
remoteRef:
key: app/database
property: passwordAudit Logging
Enable Comprehensive Auditing
# /etc/rancher/rke2/config.yaml
audit-log-path: "/var/lib/rancher/rke2/server/logs/audit.log"
audit-log-maxage: 30
audit-log-maxbackup: 10
audit-log-maxsize: 100
audit-policy-file: "/etc/rancher/rke2/audit-policy.yaml"Audit Policy Configuration
# /etc/rancher/rke2/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Log all security-related events
- level: RequestResponse
resources:
- group: ""
resources: ["secrets", "configmaps"]
- group: "rbac.authorization.k8s.io"
resources: ["*"]
# Log administrative actions
- level: Request
users: ["system:admin"]
verbs: ["create", "update", "patch", "delete"]
# Log failed requests
- level: Metadata
omitStages:
- RequestReceived
namespaces: ["kube-system", "kube-public"]Runtime Security
Falco Integration
Deploy Falco for runtime threat detection:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: falco
namespace: security
spec:
selector:
matchLabels:
app: falco
template:
metadata:
labels:
app: falco
spec:
serviceAccount: falco
hostNetwork: true
hostPID: true
containers:
- name: falco
image: falcosecurity/falco:latest
securityContext:
privileged: true
resources:
limits:
cpu: 200m
memory: 512Mi
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: boot
mountPath: /host/boot
readOnly: true
- name: lib-modules
mountPath: /host/lib/modules
readOnly: true
- name: usr
mountPath: /host/usr
readOnly: true
- name: etc
mountPath: /host/etc
readOnly: true
volumes:
- name: proc
hostPath:
path: /proc
- name: boot
hostPath:
path: /boot
- name: lib-modules
hostPath:
path: /lib/modules
- name: usr
hostPath:
path: /usr
- name: etc
hostPath:
path: /etcSecurity Monitoring
Security Metrics Collection
Monitor security events and compliance:
# Prometheus rules for security monitoring
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: security-monitoring
namespace: monitoring
spec:
groups:
- name: security.rules
rules:
- alert: UnauthorizedAPIAccess
expr: increase(apiserver_audit_total{verb="create",objectRef_resource="secrets"}[5m]) > 0
for: 0m
labels:
severity: critical
annotations:
summary: "Unauthorized secret access detected"
- alert: PodSecurityViolation
expr: increase(pod_security_policy_violations_total[5m]) > 0
for: 0m
labels:
severity: warning
annotations:
summary: "Pod security policy violation detected"Compliance Automation
Automated Hardening Script
#!/bin/bash
# RKE2 Security Hardening Automation
set -e
echo "Starting RKE2 security hardening..."
# Create etcd user
getent group etcd >/dev/null || sudo groupadd --system etcd
id -u etcd >/dev/null 2>&1 || sudo useradd --system --no-create-home --shell /sbin/nologin --gid etcd etcd
# Configure SELinux/AppArmor based on OS
if command -v getenforce >/dev/null 2>&1; then
echo "Configuring SELinux..."
sudo setenforce 1
echo "SELINUX=enforcing" | sudo tee /etc/selinux/config
elif command -v aa-status >/dev/null 2>&1; then
echo "Configuring AppArmor..."
sudo systemctl enable apparmor
sudo systemctl start apparmor
fi
# Set proper file permissions
sudo chmod 600 /etc/rancher/rke2/config.yaml
sudo chown root:root /etc/rancher/rke2/config.yaml
# Configure kernel parameters
cat <<EOF | sudo tee /etc/sysctl.d/99-rke2-cis.conf
# Network security
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
EOF
sudo sysctl --system
echo "RKE2 security hardening completed!"This comprehensive security hardening guide ensures your RKE2 deployment meets enterprise security requirements and compliance standards.
