View Source K8sWebhoox (k8s_webhoox v0.1.0)

Kubernetes webhook endpoints need to be TLS terminated. This module and the only exported functions ensure_certificates/5, update_admission_webhook_configs/3 and update_crd_conversion_configs/3 help initializing TLS termination for your webhook endpoint.

how-it-works

How it works

The function ensure_certificates/5 generates a CA and a SSL certificate and stores them in a secret, together with their private keys. If the secret already exists, it reads the certificates from that secret and doesn't generate them again.

update_admission_webhook_configs/3 searches the cluster for resources of type admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration and admissionregistration.k8s.io/v1/MutatingWebhookConfiguration and updates them in place, setting the caBundle entry to the value of the generated CA certificate.

update_crd_conversion_configs/3 searches the cluster for resources of type apiextensions.k8s.io/v1/CustomResourceDefinition and updates them in place, setting the caBundle entry to the value of the generated CA certificate.

usage

Usage

rbac

RBAC

I assume you already have a Kubernetes deployment running your applicaiton bundled with this library. Make sure the service account used by the pods can read and patch secrets and webhook configurations. You can create and assign it the following RBAC role:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: your-operator
  namespace: default
rules:
  - apiGroups:
      - admissionregistration.k8s.io
    resources:
      - validatingwebhookconfigurations
      - mutatingwebhookconfigurations
    verbs: ["*"]
  - apiGroups: [""]
    resources: ["secrets", "customresourcedefinitions"]
    verbs: ["*"]

mounting-the-certificates

Mounting the certificates

In the main container of your deployment, mount a secret as volume. In the example below, the secret is called admission-webhook-cert and is mounted to /mnt/cert. The path should correlate to where you load the certificate from in your HTTP Server configuration (see K8sWebhoox.Plug).

The secret does not exist at this moment which is why we set optional: true:

apiVersion: apps/v1
kind: Deployment
...
spec:
  template:
    spec:
      containers:
        - name: your-operator
          ...
          volumeMounts:
            - name: cert
              mountPath: "/mnt/cert"
              readOnly: true
      volumes:
        - name: cert
          secret:
            secretName: admission-webhook-cert
            optional: true

use-init-container-to-create-certificates

Use Init Container to Create Certificates

In your code base, implement a function that calls the functions of this module in order to initialize the TLS configuration:

defmodule MyOperator.K8sWebhooxTLS do
  def bootstrap_tls() do
    # Initialize connection to Kubernetes
    conn = ...

    # Create certificates if necessary
    {:ok, ca_bundle_base_64} =
      K8sWebhoox.ensure_certificates(
        conn,
        "default",
        "my-operator",
        "default",
        "webhook-tls-certificate"
      )

    # Patch admission webhook configurations
    :ok = K8sWebhoox.update_admission_webhook_configs(conn, "my-operator", ca_bundle_base_64)

    # Patch conversion webhook configurations in CRDs
    :ok = K8sWebhoox.update_crd_conversion_configs(conn, "myoperator.com", ca_bundle_base_64)
  end
end

In your deployment, add an init container with the same image as the main container and call your TLS bootstrap function using eval:

      ...
      initContainers:
        - name: bootstrap-tls
          image: SAME_AS_MAIN_CONTAINER
          args: ["eval", "MyOperator.K8sWebhooxTLS.bootstrap_tls()"]
          ...

Link to this section Summary

Functions

Gets the certificate bundle from the Kubernetes Secret. Creates new CA and certificate if necessary. Returns the CA bundle Base64 encoded.

Searches the cluster for ValidatingWebhookConfiguration and MutatingWebhookConfiguration resources with the given admission_config_name and sets the .webhooks[*].clientConfig.caBundle fields to ca_bundle_base_64

Searches the cluster for CustomResourceDefinition resources for the given group and sets the .spec.conversion.webhook.clientConfig.caBundle fields to ca_bundle_base_64.

Link to this section Functions

Link to this function

ensure_certificates(conn, service_namespace, service_name, secret_namespace, secret_name, opts \\ [])

View Source
@spec ensure_certificates(
  conn :: K8s.Conn.t(),
  service_namespace :: binary(),
  service_name :: binary(),
  secret_namespace :: binary(),
  secret_name :: binary(),
  opts :: keyword()
) :: :error | {:ok, binary()}

Gets the certificate bundle from the Kubernetes Secret. Creates new CA and certificate if necessary. Returns the CA bundle Base64 encoded.

Link to this function

update_admission_webhook_configs(conn, admission_config_name, ca_bundle_base_64)

View Source
@spec update_admission_webhook_configs(
  conn :: K8s.Conn.t(),
  admission_config_name :: binary(),
  ca_bundle_base_64 :: binary()
) :: :ok | :error

Searches the cluster for ValidatingWebhookConfiguration and MutatingWebhookConfiguration resources with the given admission_config_name and sets the .webhooks[*].clientConfig.caBundle fields to ca_bundle_base_64

Link to this function

update_crd_conversion_configs(conn, group, ca_bundle_base_64)

View Source
@spec update_crd_conversion_configs(
  conn :: K8s.Conn.t(),
  group :: binary(),
  ca_bundle_base_64 :: binary()
) :: :ok | :error

Searches the cluster for CustomResourceDefinition resources for the given group and sets the .spec.conversion.webhook.clientConfig.caBundle fields to ca_bundle_base_64.