# CIS Kubernetes Benchmark Remediation Guide for K3s

Common CIS benchmark failures specific to K3s clusters managed by Citadel,
with tested remediation steps.

## Control Plane (Section 1)

### 1.1.x — API Server Configuration Files

**Finding:** API server configuration files have overly permissive permissions.

K3s bundles the API server into a single binary (`/var/lib/rancher/k3s/server`),
so file permission checks may report false positives compared to a kubeadm cluster.

**Remediation:**
```bash
# Ensure K3s data directory permissions
chmod 700 /var/lib/rancher/k3s/server
chmod 600 /var/lib/rancher/k3s/server/cred/*
chmod 600 /etc/rancher/k3s/k3s.yaml
```

### 1.2.1 — Anonymous Auth

**Finding:** `--anonymous-auth` is not set to `false`.

K3s enables anonymous auth by default for health check endpoints.
Disable it unless required by your monitoring stack.

**Remediation:**
```yaml
# /etc/rancher/k3s/config.yaml
kube-apiserver-arg:
  - "anonymous-auth=false"
```

Restart K3s after modifying:
```bash
sudo systemctl restart k3s
```

### 1.2.6 — RBAC Authorization

**Finding:** Authorization mode does not include RBAC.

K3s uses `--authorization-mode=Node,RBAC` by default. If this check fails,
verify the K3s configuration:

```bash
ps aux | grep k3s | grep authorization-mode
```

### 1.2.10 — Admission Controllers

**Finding:** Required admission controllers are not enabled.

K3s enables most admission controllers by default. For additional controllers:

**Remediation:**
```yaml
# /etc/rancher/k3s/config.yaml
kube-apiserver-arg:
  - "enable-admission-plugins=NodeRestriction,PodSecurity,ServiceAccount"
```

### 1.2.16 — Audit Logging

**Finding:** Audit logging is not enabled.

**Remediation:**

Use the Citadel audit logging script:
```bash
./scripts/07-enable-audit-logging.sh
```

Or configure manually:
```yaml
# /etc/rancher/k3s/config.yaml
kube-apiserver-arg:
  - "audit-log-path=/var/log/kubernetes/audit.log"
  - "audit-log-maxage=30"
  - "audit-log-maxbackup=10"
  - "audit-log-maxsize=100"
  - "audit-policy-file=/etc/rancher/k3s/audit-policy.yaml"
```

### 1.2.22 — Encryption at Rest

**Finding:** Encryption provider is not configured.

**Remediation:**

Use the Citadel encryption script:
```bash
./scripts/08-enable-encryption.sh
```

Or see `security/encryption-config.yaml` for the encryption configuration.

## etcd (Section 2)

### 2.1 — etcd Data Directory Permissions

**Finding:** etcd data directory permissions are too permissive.

K3s uses an embedded etcd or SQLite backend. For embedded etcd:

**Remediation:**
```bash
chmod 700 /var/lib/rancher/k3s/server/db/etcd
chown root:root /var/lib/rancher/k3s/server/db/etcd
```

### 2.6 — etcd Peer TLS

**Finding:** etcd peer communication is not encrypted.

K3s automatically configures TLS for embedded etcd in HA mode.
For single-node clusters using SQLite, this check is not applicable.

## Worker Nodes (Section 3)

### 3.2.1 — Kubelet Anonymous Auth

**Finding:** Kubelet allows anonymous authentication.

K3s disables kubelet anonymous auth by default. Verify:

```bash
ps aux | grep kubelet | grep anonymous-auth
```

**Remediation:**
```yaml
# /etc/rancher/k3s/config.yaml
kubelet-arg:
  - "anonymous-auth=false"
```

### 3.2.2 — Kubelet Authorization Mode

**Finding:** Kubelet authorization is set to AlwaysAllow.

**Remediation:**
```yaml
# /etc/rancher/k3s/config.yaml
kubelet-arg:
  - "authorization-mode=Webhook"
```

### 3.2.9 — Kubelet TLS Certificates

**Finding:** Kubelet does not rotate TLS certificates.

K3s manages kubelet certificates automatically. If this check fails:

**Remediation:**
```yaml
# /etc/rancher/k3s/config.yaml
kubelet-arg:
  - "rotate-certificates=true"
  - "rotate-server-certificates=true"
```

## Policies (Section 5)

### 5.1.1 — Cluster Admin Role

**Finding:** `cluster-admin` role is bound to too many subjects.

Review and limit cluster-admin bindings:

```bash
kubectl get clusterrolebindings -o json | \
  jq '.items[] | select(.roleRef.name=="cluster-admin") | .subjects'
```

**Remediation:**
Create namespace-scoped admin roles instead of cluster-wide access.
Citadel creates minimal RBAC bindings — review any additions.

### 5.2.x — Pod Security Standards

**Finding:** Namespaces are not enforcing Pod Security Standards.

**Remediation:**

Apply Pod Security Standards labels to namespaces:
```bash
kubectl label namespace default \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted
```

For Citadel managed namespaces, this is configured in the
Cilium network policies (`policies/` directory).

### 5.3.1 — Network Policies

**Finding:** Default namespace does not have network policies.

Citadel uses Cilium for network policies. Verify:
```bash
kubectl get ciliumnetworkpolicies -A
```

**Remediation:**
Apply the default deny policies:
```bash
./scripts/05-test-policies.sh
```

### 5.7.1 — Service Account Tokens

**Finding:** Default service account tokens are auto-mounted.

**Remediation:**
Disable auto-mounting for the default service account:
```bash
kubectl patch serviceaccount default -n <namespace> \
  -p '{"automountServiceAccountToken": false}'
```

## K3s-Specific Considerations

K3s bundles multiple Kubernetes components into a single binary, which
means some CIS benchmark checks designed for kubeadm may report
differently:

1. **Config file paths** differ from standard K8s (`/var/lib/rancher/k3s/` vs `/etc/kubernetes/`)
2. **Embedded etcd/SQLite** — etcd-specific checks may not apply in SQLite mode
3. **Bundled containerd** — container runtime checks reference K3s paths
4. **Auto-TLS** — K3s auto-generates TLS certificates for all components

When running kube-bench, always use `--benchmark cis-1.8` with the K3s
configuration to get accurate results.

## Automated Scanning

Citadel runs kube-bench automatically via CronJob:
- **Schedule:** Daily at 02:00 UTC
- **Results:** Stored in ConfigMaps in `citadel-compliance` namespace
- **Dashboard:** Grafana "Citadel Compliance" dashboard

Check latest results:
```bash
# View latest scan summary
kubectl get configmap -n citadel-compliance -l app.kubernetes.io/name=kube-bench \
  --sort-by=.metadata.creationTimestamp -o name | tail -1 | \
  xargs kubectl get -n citadel-compliance -o jsonpath='{.data.summary\.txt}'

# Programmatic access via Python
python -c "
from citadel_operator.k3s.compliance import ComplianceScanner
scanner = ComplianceScanner()
result = scanner.run_cis_benchmark()
print(f'Score: {result.score}%, Failed: {result.failed}, Warnings: {result.warnings}')
for f in result.failures:
    print(f'  [{f.severity}] {f.check_id}: {f.description}')
"
```
