Add Flatcar and Cilium kube-proxy-free architecture
Kube-bench CIS scan / Scan ephemeral K3s cluster (push) Failing after 3m11s
Kube-bench CIS scan / Scan ephemeral K3s cluster (push) Failing after 3m11s
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
# Kubernetes Security Baseline
|
# Kubernetes Security Baseline
|
||||||
|
|
||||||
An auditable, GitOps-managed Kubernetes security baseline: local k3d for a
|
An auditable, GitOps-managed Kubernetes security baseline: local k3d for a
|
||||||
fast reproducible demo, optional Terraform + Ansible for a cloud K3s host, CIS
|
fast reproducible demo, optional Flatcar plus Terraform and Ansible for a cloud
|
||||||
Benchmark checks in CI, Kyverno admission policies, and Falco runtime
|
K3s host, Cilium eBPF networking, CIS Benchmark checks in CI, Kyverno
|
||||||
detection.
|
admission policies, and Falco runtime detection.
|
||||||
|
|
||||||
## Phase 1: provision a local cluster
|
## Phase 1: provision a local cluster
|
||||||
|
|
||||||
@@ -22,8 +22,10 @@ Delete the lab with `k3d cluster delete security-baseline`.
|
|||||||
## Production-style option
|
## Production-style option
|
||||||
|
|
||||||
`terraform/cloud-cluster/` and `ansible/bootstrap-k3s.yml` provide an optional,
|
`terraform/cloud-cluster/` and `ansible/bootstrap-k3s.yml` provide an optional,
|
||||||
documented AWS path. It requires your own AWS credentials, an existing EC2 key
|
documented AWS path. It uses Flatcar as the host OS, disables Flannel and
|
||||||
pair, an Ubuntu AMI ID for the chosen region, and a tightly scoped admin CIDR.
|
kube-proxy, and installs Cilium as the CNI and eBPF service datapath. It
|
||||||
|
requires your own AWS credentials, an existing EC2 key pair, a Flatcar AMI ID
|
||||||
|
for the chosen region, and a tightly scoped admin CIDR.
|
||||||
It is not needed for the portfolio demo and is not run in CI.
|
It is not needed for the portfolio demo and is not run in CI.
|
||||||
|
|
||||||
## Build status
|
## Build status
|
||||||
@@ -31,6 +33,7 @@ It is not needed for the portfolio demo and is not run in CI.
|
|||||||
- [x] Phase 1: local k3d definition and optional Terraform/Ansible path
|
- [x] Phase 1: local k3d definition and optional Terraform/Ansible path
|
||||||
- [ ] Phase 2: ArgoCD app-of-apps deployment (scaffolded; runtime verification pending)
|
- [ ] Phase 2: ArgoCD app-of-apps deployment (scaffolded; runtime verification pending)
|
||||||
- [x] Phase 3: kube-bench CI scan
|
- [x] Phase 3: kube-bench CI scan
|
||||||
|
- [ ] Architecture revision: Flatcar hosts and Cilium kube-proxy replacement (configured; runtime verification pending)
|
||||||
- [ ] Phase 4: Kyverno policy set and CIS mapping
|
- [ ] Phase 4: Kyverno policy set and CIS mapping
|
||||||
- [ ] Phase 5: Falco rules and webhook alerting
|
- [ ] Phase 5: Falco rules and webhook alerting
|
||||||
- [ ] Phase 6: test workloads and evidence capture
|
- [ ] Phase 6: test workloads and evidence capture
|
||||||
|
|||||||
+55
-38
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
- name: Harden host and install K3s
|
- name: Configure Flatcar host and install K3s
|
||||||
hosts: k3s_servers
|
hosts: k3s_servers
|
||||||
become: true
|
become: true
|
||||||
gather_facts: true
|
gather_facts: true
|
||||||
@@ -7,44 +7,22 @@
|
|||||||
vars:
|
vars:
|
||||||
k3s_version: "v1.30.6+k3s1"
|
k3s_version: "v1.30.6+k3s1"
|
||||||
k3s_install_url: "https://get.k3s.io"
|
k3s_install_url: "https://get.k3s.io"
|
||||||
|
k3s_api_server_port: 6443
|
||||||
|
|
||||||
pre_tasks:
|
pre_tasks:
|
||||||
- name: Require a supported Ubuntu release
|
- name: Require Flatcar Linux
|
||||||
ansible.builtin.assert:
|
ansible.builtin.assert:
|
||||||
that:
|
that:
|
||||||
- ansible_distribution == "Ubuntu"
|
- ansible_distribution == "Flatcar"
|
||||||
- ansible_distribution_version is version("22.04", ">=")
|
fail_msg: "This playbook expects Flatcar Linux. Use the Ubuntu fallback playbook if needed."
|
||||||
fail_msg: "This playbook expects Ubuntu 22.04 or newer."
|
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- name: Install host security prerequisites
|
- name: Disable swap if a swap device is present
|
||||||
ansible.builtin.apt:
|
|
||||||
name:
|
|
||||||
- apparmor
|
|
||||||
- apparmor-utils
|
|
||||||
- curl
|
|
||||||
- ca-certificates
|
|
||||||
- unattended-upgrades
|
|
||||||
state: present
|
|
||||||
update_cache: true
|
|
||||||
|
|
||||||
- name: Ensure unattended security upgrades are enabled
|
|
||||||
ansible.builtin.service:
|
|
||||||
name: unattended-upgrades
|
|
||||||
state: started
|
|
||||||
enabled: true
|
|
||||||
|
|
||||||
- name: Disable swap for Kubernetes node
|
|
||||||
ansible.builtin.command: swapoff -a
|
ansible.builtin.command: swapoff -a
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
- name: Remove swap entries from fstab
|
- name: Set restrictive SSH authentication
|
||||||
ansible.builtin.replace:
|
|
||||||
path: /etc/fstab
|
|
||||||
regexp: '^([^#].*\sswap\s+.*)$'
|
|
||||||
replace: '# Disabled for Kubernetes: \1'
|
|
||||||
|
|
||||||
- name: Set restrictive SSH password authentication
|
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
dest: /etc/ssh/sshd_config.d/60-k8s-baseline.conf
|
dest: /etc/ssh/sshd_config.d/60-k8s-baseline.conf
|
||||||
owner: root
|
owner: root
|
||||||
@@ -53,23 +31,62 @@
|
|||||||
content: |
|
content: |
|
||||||
PasswordAuthentication no
|
PasswordAuthentication no
|
||||||
PermitRootLogin no
|
PermitRootLogin no
|
||||||
notify: Restart ssh
|
notify: Restart sshd
|
||||||
|
|
||||||
|
- name: Create K3s configuration directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/rancher/k3s
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0750'
|
||||||
|
|
||||||
|
- name: Configure K3s for Cilium kube-proxy replacement
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/rancher/k3s/config.yaml
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0600'
|
||||||
|
content: |
|
||||||
|
write-kubeconfig-mode: "0600"
|
||||||
|
flannel-backend: none
|
||||||
|
disable-network-policy: true
|
||||||
|
disable-kube-proxy: true
|
||||||
|
disable:
|
||||||
|
- traefik
|
||||||
|
https-listen-port: {{ k3s_api_server_port }}
|
||||||
|
|
||||||
|
- name: Download pinned K3s installer
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: "{{ k3s_install_url }}"
|
||||||
|
dest: /var/lib/rancher/k3s-install.sh
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0700'
|
||||||
|
|
||||||
- name: Install pinned K3s server
|
- name: Install pinned K3s server
|
||||||
ansible.builtin.shell: |
|
ansible.builtin.command:
|
||||||
curl -sfL {{ k3s_install_url }} | INSTALL_K3S_VERSION={{ k3s_version }} sh -s - server --write-kubeconfig-mode 600
|
cmd: /var/lib/rancher/k3s-install.sh server
|
||||||
args:
|
|
||||||
creates: /usr/local/bin/k3s
|
creates: /usr/local/bin/k3s
|
||||||
|
environment:
|
||||||
|
INSTALL_K3S_VERSION: "{{ k3s_version }}"
|
||||||
|
|
||||||
- name: Enable and start K3s
|
- name: Enable and start K3s
|
||||||
ansible.builtin.service:
|
ansible.builtin.systemd:
|
||||||
name: k3s
|
name: k3s
|
||||||
state: started
|
state: started
|
||||||
enabled: true
|
enabled: true
|
||||||
|
daemon_reload: true
|
||||||
|
|
||||||
|
- name: Wait for K3s API port
|
||||||
|
ansible.builtin.wait_for:
|
||||||
|
host: 127.0.0.1
|
||||||
|
port: "{{ k3s_api_server_port }}"
|
||||||
|
timeout: 120
|
||||||
|
|
||||||
handlers:
|
handlers:
|
||||||
- name: Restart ssh
|
- name: Restart sshd
|
||||||
ansible.builtin.service:
|
ansible.builtin.systemd:
|
||||||
name: ssh
|
name: sshd
|
||||||
state: restarted
|
state: restarted
|
||||||
|
|
||||||
|
|||||||
@@ -34,3 +34,8 @@ kubectl -n argocd get secret argocd-initial-admin-secret \
|
|||||||
|
|
||||||
The initial admin secret is for local bootstrap only. A later hardening phase
|
The initial admin secret is for local bootstrap only. A later hardening phase
|
||||||
should replace this with SSO/RBAC and remove the bootstrap credential.
|
should replace this with SSO/RBAC and remove the bootstrap credential.
|
||||||
|
|
||||||
|
For a kube-proxy-free Cilium cluster, install Cilium before ArgoCD using the
|
||||||
|
profile in `local-quickstart/cilium.md` or the Flatcar cloud bootstrap. The
|
||||||
|
Cilium Application is stored under `argocd/optional-apps/` and is not watched
|
||||||
|
by the default root app until the cluster is ready for it.
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: cilium
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "-4"
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
sources:
|
||||||
|
- repoURL: https://helm.cilium.io/
|
||||||
|
chart: cilium
|
||||||
|
targetRevision: 1.20.0
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/cilium/cilium-values.yaml
|
||||||
|
- repoURL: https://git.swaphb.com/swaphb/kubernetes-security-baseline-lab.git
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: kube-system
|
||||||
|
# Apply this Application manually only after bootstrapping a kube-proxy-free
|
||||||
|
# cluster and replacing the API endpoint placeholder.
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Cilium is the CNI, network-policy engine, and eBPF service datapath for the
|
||||||
|
# production-style K3s profile. Set this endpoint before bootstrapping a
|
||||||
|
# cluster because kube-proxy is intentionally disabled.
|
||||||
|
kubeProxyReplacement: true
|
||||||
|
k8sServiceHost: "127.0.0.1"
|
||||||
|
k8sServicePort: 6443
|
||||||
|
|
||||||
|
ipam:
|
||||||
|
mode: kubernetes
|
||||||
|
|
||||||
|
routingMode: tunnel
|
||||||
|
tunnelProtocol: vxlan
|
||||||
|
|
||||||
|
hubble:
|
||||||
|
enabled: true
|
||||||
|
relay:
|
||||||
|
enabled: true
|
||||||
|
ui:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
operator:
|
||||||
|
replicas: 1
|
||||||
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# Cilium local profile
|
||||||
|
|
||||||
|
The standard k3d profile is the default quick start. This profile is for
|
||||||
|
demonstrating Cilium with kube-proxy replacement.
|
||||||
|
|
||||||
|
Create it with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
k3d cluster create --config local-quickstart/k3d-cilium-cluster-config.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Before installing Cilium, set the API server endpoint in a temporary values
|
||||||
|
file. The endpoint must be reachable directly from every node. Do not use the
|
||||||
|
Kubernetes service VIP because kube-proxy is disabled during bootstrap.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl config current-context
|
||||||
|
kubectl get nodes -o wide
|
||||||
|
cp cilium/cilium-values.yaml /tmp/cilium-values.yaml
|
||||||
|
# Replace REPLACE_WITH_API_SERVER_DNS_OR_PRIVATE_IP with the reachable API endpoint.
|
||||||
|
helm repo add cilium https://helm.cilium.io/
|
||||||
|
helm repo update
|
||||||
|
helm upgrade --install cilium cilium/cilium \
|
||||||
|
--namespace kube-system \
|
||||||
|
--version 1.20.0 \
|
||||||
|
--values /tmp/cilium-values.yaml
|
||||||
|
kubectl -n kube-system rollout status daemonset/cilium --timeout=300s
|
||||||
|
kubectl -n kube-system get pods -l k8s-app=cilium
|
||||||
|
```
|
||||||
|
|
||||||
|
Install ArgoCD only after Cilium is Ready. Apply
|
||||||
|
`argocd/optional-apps/cilium.yaml` manually after the endpoint is configured;
|
||||||
|
it is intentionally outside the root app-of-apps watched directory until the
|
||||||
|
cluster has been bootstrapped without kube-proxy.
|
||||||
|
|
||||||
|
Delete the profile with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
k3d cluster delete security-baseline-cilium
|
||||||
|
```
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
apiVersion: k3d.io/v1alpha5
|
||||||
|
kind: Simple
|
||||||
|
metadata:
|
||||||
|
name: security-baseline-cilium
|
||||||
|
|
||||||
|
# This is an advanced local profile. The standard k3d profile remains the
|
||||||
|
# lowest-friction quick start and keeps Flannel enabled.
|
||||||
|
servers: 1
|
||||||
|
agents: 2
|
||||||
|
|
||||||
|
options:
|
||||||
|
k3s:
|
||||||
|
extraArgs:
|
||||||
|
- arg: --flannel-backend=none
|
||||||
|
nodeFilters:
|
||||||
|
- server:*
|
||||||
|
- arg: --disable-network-policy
|
||||||
|
nodeFilters:
|
||||||
|
- server:*
|
||||||
|
- arg: --disable-kube-proxy
|
||||||
|
nodeFilters:
|
||||||
|
- server:*
|
||||||
|
- arg: --disable=traefik
|
||||||
|
nodeFilters:
|
||||||
|
- server:*
|
||||||
|
k3d:
|
||||||
|
wait: true
|
||||||
|
timeout: 180s
|
||||||
|
kubeconfig:
|
||||||
|
updateDefaultKubeconfig: true
|
||||||
|
switchCurrentContext: true
|
||||||
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
# Optional production-style path
|
# Optional production-style path
|
||||||
|
|
||||||
This directory provisions one encrypted Ubuntu EC2 host with a deliberately
|
This directory provisions one encrypted Flatcar EC2 host with a deliberately
|
||||||
small network surface. It is a scaffold for the documented cloud path; the
|
small network surface. It is a scaffold for the documented cloud path; the
|
||||||
local k3d path remains the primary, cost-free portfolio demo.
|
local k3d path remains the primary, cost-free portfolio demo.
|
||||||
|
|
||||||
The AWS account, region, AMI, SSH key pair, and administrator CIDR are inputs,
|
The AWS account, region, Flatcar AMI, SSH key pair, and administrator CIDR are inputs,
|
||||||
not repository values. Do not commit a real `terraform.tfvars` file or private
|
not repository values. Do not commit a real `terraform.tfvars` file or private
|
||||||
keys. The security group intentionally exposes SSH and the Kubernetes API only
|
keys. The security group intentionally exposes SSH and the Kubernetes API only
|
||||||
to `admin_cidr`; add any public application ports explicitly when needed.
|
to `admin_cidr`; add any public application ports explicitly when needed.
|
||||||
@@ -21,7 +21,7 @@ terraform apply
|
|||||||
terraform output -raw public_ip
|
terraform output -raw public_ip
|
||||||
```
|
```
|
||||||
|
|
||||||
Then run `ansible/bootstrap-k3s.yml` against the output IP. `terraform destroy`
|
Then run `ansible/bootstrap-k3s.yml` against the output IP. Configure the
|
||||||
|
Cilium API endpoint before installing Cilium. `terraform destroy`
|
||||||
removes the lab resources when finished. This path is not required for the
|
removes the lab resources when finished. This path is not required for the
|
||||||
portfolio demo and is not invoked by CI.
|
portfolio demo and is not invoked by CI.
|
||||||
|
|
||||||
|
|||||||
@@ -3,5 +3,4 @@ availability_zone = null
|
|||||||
instance_type = "t3.medium"
|
instance_type = "t3.medium"
|
||||||
ssh_key_name = "replace-with-existing-key-pair"
|
ssh_key_name = "replace-with-existing-key-pair"
|
||||||
admin_cidr = "203.0.113.10/32"
|
admin_cidr = "203.0.113.10/32"
|
||||||
ami_id = "replace-with-ubuntu-22.04-ami-for-your-region"
|
ami_id = "replace-with-flatcar-stable-ami-for-your-region"
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ variable "admin_cidr" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
variable "ami_id" {
|
variable "ami_id" {
|
||||||
description = "Ubuntu 22.04 LTS AMI ID for the selected region."
|
description = "Flatcar Stable AMI ID for the selected region and architecture."
|
||||||
type = string
|
type = string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user