Secure webhooks with mutual TLS with K3s

This guide shows you how to enable mutual Transport Layer Security (mTLS) for SUSE Security Admission Controller stack webhooks when using K3s as your Kubernetes distribution.

For more information on how to harden the webhooks, refer to the reference page.

Prerequisites

Before installing K3s, you need to create a certificate authority (CA) and a client certificate. You use to secure the communication between the Admission Controller webhooks and the Kubernetes API server.

As a first step, create the /etc/rancher/k3s/admission/certs directory:

sudo mkdir -p /etc/rancher/k3s/admission/certs

Create a root CA and the client certificate

As root user, change directory to the /etc/rancher/k3s/admission/certs directory and create all needed certificates:

export FQDN=mtls.kubewarden.io

# Create openssl config file
cat > openssl.cnf <<EOL
[ req ]
default_keyfile     = rootCA.key
distinguished_name  = req_distinguished_name
x509_extensions     = v3_ca
string_mask         = utf8only

[ req_distinguished_name ]
countryName         = Country Name (2 letter code)
countryName_default = US
stateOrProvinceName = State or Province Name (full name)
localityName        = Locality Name (eg, city)
organizationName    = Organization Name (eg, company)
commonName          = Common Name (eg, your domain or your CA name)

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:1
keyUsage = critical, keyCertSign, cRLSign
EOL

# Create CA
openssl req -nodes -batch -x509 -sha256 -days 3650 -newkey rsa:4096 -keyout rootCA.key -out rootCA.crt \
  -config openssl.cnf

# Create CSR
openssl req -nodes -batch -newkey rsa:4096 -keyout client.key -out client.csr \
    -addext "subjectAltName = DNS:$FQDN"  -config openssl.cnf

# Create CRT
openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in client.csr -out client.crt -days 3650 -CAcreateserial \
    -extfile <(echo "subjectAltName=DNS:$FQDN")

# Print CRT

openssl x509 -text -noout -in client.crt

This creates the following files:

  • client.crt

  • client.csr

  • client.key

  • rootCA.crt

  • rootCA.key

  • rootCA.srl

Create the Kubernetes configuration file

Create the /etc/rancher/k3s/admission/admission.yaml file with the following content:

# /etc/rancher/k3s/admission/admission.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: ValidatingAdmissionWebhook
  configuration:
    apiVersion: apiserver.config.k8s.io/v1
    kind: WebhookAdmissionConfiguration
    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"
- name: MutatingAdmissionWebhook
  configuration:
    apiVersion: apiserver.config.k8s.io/v1
    kind: WebhookAdmissionConfiguration
    kubeConfigFile: "/etc/rancher/k3s/admission/kubeconfig"

Finally, create a kubeconfig file at /etc/rancher/k3s/admission/kubeconfig:

# /etc/rancher/admission/kubeconfig
apiVersion: v1
kind: Config
users:
- name: "*.suse-sec-adm-controller.svc" # namespace where the Admission Controller stack is deployed
  user:
    client-certificate: /etc/rancher/k3s/admission/certs/client.crt
    client-key: /etc/rancher/k3s/admission/certs/client.key

Create a K3s configuration file

Create a K3s configuration file at /etc/rancher/k3s/config.yaml:

# /etc/rancher/k3s/config.yaml
kube-apiserver-arg:
- admission-control-config-file=/etc/rancher/k3s/admission/admission.yaml

Install K3s

Install SUSE Rancher Prime: K3s using the following command, where <PRIME-ARTIFACTS-URL> is the Prime Artifacts URL. See the K3s quick start for how to obtain it:

curl -sfL https://get.k3s.io | INSTALL_K3S_ARTIFACT_URL=<PRIME-ARTIFACTS-URL>/k3s sh -

Wait for the installation to complete.

Install the Admission Controller stack

Prerequisites

The certificate of the root CA, that issued the Kubernetes client certificate, needs to be available to the Admission Controller stack.

The root CA is available at /etc/rancher/k3s/admission/certs/rootCA.crt on the Kubernetes node. You need its content in a ConfigMap under the suse-sec-adm-controller namespace. You store the contents of the rootCA.crt file in the key named client-ca.crt.

First, create the suse-sec-adm-controller namespace:

kubectl create namespace suse-sec-adm-controller

Then create the ConfigMap in it. The following command, run on the Kubernetes node, does that:

kubectl create configmap -n suse-sec-adm-controller api-server-mtls \
    --from-file=client-ca.crt=/etc/rancher/k3s/admission/certs/rootCA.crt

The name of the resulting ConfigMap is api-server-mtls.

Install the Admission Controller stack

Install the Admission Controller stack as described in the quickstart guide. Follow all the steps, except creating the suse-sec-adm-controller namespace, which already exists. When installing the suse-security-admission-controller Helm chart, make sure to enable the following values:

  • mTLS.enable: must be true.

  • mTLS.configMapName: must the name of the previously created ConfigMap.

The ConfigMap name is api-server-mtls. The Helm command to install the suse-security-admission-controller chart is:

helm install --wait -n suse-sec-adm-controller suse-sec-adm-controller oci://dp.apps.rancher.io/charts/suse-security-admission-controller \
    --set global.imagePullSecrets={application-collection} \
    --set mTLS.enable=true \
    --set mTLS.configMapName=api-server-mtls

Once this command finishes, mTLS secures the installation of the Admission Controller stack and its webhooks.