autocert

repository·master·Indexed 21 days ago

https://github.com/smallstep/autocert

A Kubernetes add-on that automates the injection of TLS/HTTPS certificates into containers to enable seamless mutual TLS (mTLS) for workload communication. It operates as an admission webhook, using an init container for bootstrapping and a sidecar container for automatic certificate renewal. Certificates are signed by an internal step-ca Certificate Authority or Smallstep Certificate Manager and are mounted at /var/run/autocert.step.sm/.

Tokens
9.3K
Snippets
26
Records
31
Agent score
74%

What's inside autocert

  1. What is Autocert

    master

    Autocert is a Kubernetes add-on that automatically injects TLS/HTTPS certificates into your containers to enable secure communication (mTLS) between workloads.

    By annotating your pods, Autocert automatically creates and mounts an X.509 (TLS/HTTPS) certificate, a private key, and a root certificate at /var/run/autocert.step.sm/. These certificates are signed by an internal step-ca Certificate Authority or by Smallstep Certificate Manager.

  2. What is Mutual TLS (mTLS) and why use it?

    master

    Mutual TLS (mTLS) is a variant of the TLS protocol where both the client and the server authenticate to one another by presenting certificates. This differs from standard server-auth TLS (used by web browsers), where only the server is authenticated.

    Key Benefits

    • Authenticated Encryption: Provides both an identity dialtone and end-to-end encryption.
    • Identity-Aware Workloads: Makes workloads identity-aware, improving observability and enabling granular access control.
    • Secure Public Exposure: Services can be safely exposed to the public internet because only clients possessing a certificate issued by your internal Certificate Authority (CA) will be allowed to connect.

    Requirements for mTLS

    • Root Knowledge: Both client and server must have prior knowledge of the root certificate(s) used to sign the peer's certificate.
    • Correct Configuration: Both parties must be configured with the correct certificate and private key (the certificate must be issued by a CA with a trusted root certificate).
    • Private Key Security: Private keys must never be shared; they are used to prove identity through digital signatures without exposing the key itself.
  3. Understand autocert's security model and certificate management

    master

    Autocert is designed for managing private CA certificates for mTLS service-to-service communication in Kubernetes.

    Key Security Concepts

    • Key Generation: Private keys are generated locally within the workload via an initContainer and managed via volume mounts. This follows PKI best practices by ensuring private keys are never transmitted over the network or stored in plaintext in etcd (unlike Kubernetes Secrets).
    • Bootstrap Tokens: The autocert admission webhook uses Kubernetes Secrets to securely transmit one-time bootstrap tokens to containers. This allows the autocert-bootstrapper to exchange the token for a certificate.
    • RBAC Requirements: autocert requires cluster-wide permissions to create and delete secrets to manage these one-time tokens.
    • Certificate Defaults: By default, it issues ECDSA certificates using the P256 curve with ECDSA-SHA256 signatures.

    Comparison with cert-manager

    While cert-manager is optimized for Web PKI (e.g., Let's Encrypt) for ingress TLS, autocert is purpose-built for private CA mTLS within a cluster.

  4. How autocert works: Architecture and Lifecycle

    master

    Autocert operates as a Kubernetes admission webhook. When a pod creation request is intercepted, autocert patches the pod specification to inject two key components:

    1. Init Container (Bootstrapper): Uses a one-time token (generated by the webhook and passed via a Kubernetes Secret) to mutually authenticate with the Certificate Authority and obtain the initial certificate.
    2. Sidecar Container (Renewer): Runs alongside your application to handle the automatic renewal of certificates before they expire using mTLS with the CA.

    This lifecycle ensures that certificates are automatically provisioned and kept up-to-date without manual intervention.

  5. Uninstall autocert

    master

    To completely uninstall autocert, you must delete the mutating webhook configuration, the step namespace, and the associated RBAC artifacts.

    Afterward, you should remove labels from all namespaces and clean up any remaining one-time token secrets. Sidecar containers will be removed once you remove the relevant annotations from your workloads and redeploy them.

    # 1. Delete webhook, namespace, and RBAC
    kubectl delete mutatingwebhookconfiguration autocert-webhook-config
    kubectl delete namespace step
    kubectl delete clusterrolebinding autocert-controller
    kubectl delete clusterrole autocert-controller
    
    # 2. Clean up namespace labels and stray secrets
    for ns in $(kubectl get namespace --selector autocert.step.sm=enabled -o jsonpath='{$.items[*].metadata.name}'); do
      kubectl label namespace "$ns" autocert.step.sm-
      kubectl -n "$ns" delete secrets --selector="autocert.step.sm/token=true"
    done
  6. Build and deploy hello-mtls dockerized examples

    master

    The hello-mtls examples provide dockerized mTLS (Mutual TLS) clients and servers in various languages. These examples demonstrate best practices such as using internal CA root certificates, implementing client authentication, and supporting short-lived certificate rotation.

    To build the examples, use the multi-stage Docker builds provided in the repository. You will need docker installed locally. Replace <lang> with the specific language implementation you wish to build (e.g., go, node, curl).

    Once built, you can deploy the client and server components to a Kubernetes cluster using the provided YAML manifests.

    # Build the server
    docker build -f Dockerfile.server -t hello-mtls-server-<lang> .
    
    # Build the client
    docker build -f Dockerfile.client -t hello-mtls-client-<lang> .
    
    # Deploy to Kubernetes
    kubectl apply -f hello-mtls.server.yaml
    kubectl apply -f hello-mtls.client.yaml
  7. Enable Autocert for a Namespace

    master

    Autocert must be enabled at the namespace level before it can inject certificates into pods. To enable it, label the target namespace with autocert.step.sm=enabled.

    # Enable for the 'default' namespace
    kubectl label namespace default autocert.step.sm=enabled
    
    # Verify enabled namespaces
    kubectl get namespace -L autocert.step.sm
  8. Manual installation of autocert

    master

    If you cannot use the quickstart method, follow these steps to manually set up the CA and the autocert controller.

    1. Prerequisites

    • Install step CLI version 0.18.2 or later.
    • Ensure you have cluster-admin permissions (on GKE, you may need to explicitly bind the cluster-admin role to your user).

    2. Create a CA

    First, set a temporary STEPPATH to stage CA artifacts:

    export STEPPATH=$(mktemp -d /tmp/step.XXX)

    Initialize the CA using step ca init. You will be prompted for a password to encrypt key material:

    step ca init \
        --name Autocert \
        --dns "ca.step.svc.cluster.local,127.0.0.1" \
        --address ":4443" \
        --provisioner admin \
        --with-ca-url "ca.step.svc.cluster.local"

    Add the autocert provisioner to the CA:

    step ca provisioner add autocert --create

    3. Install the CA in Kubernetes

    Create the step namespace and upload the CA configuration, certificates, and secrets as ConfigMaps. You must also create Kubernetes secrets for the passwords used during CA initialization and provisioner creation.

    Note: Use the exact passwords you entered during the step ca init and step ca provisioner add steps.

    4. Install the autocert controller

    Apply the controller manifest and the RBAC configuration to allow autocert to manage bootstrap token secrets.

    5. Register the mutation webhook

    Finally, register the autocert mutation webhook with Kubernetes to enable automatic certificate injection.

    # 1. Quickstart (Alternative to manual)
    kubectl run autocert-init -it --rm --image smallstep/autocert-init --restart Never
    
    # 2. Manual: Create CA
    export STEPPATH=$(mktemp -d /tmp/step.XXX)
    step ca init \
        --name Autocert \
        --dns "ca.step.svc.cluster.local,127.0.0.1" \
        --address ":4443" \
        --provisioner admin \
        --with-ca-url "ca.step.svc.cluster.local"
    step ca provisioner add autocert --create
    
    # 3. Manual: Kubernetes Setup (Namespace and ConfigMaps)
    kubectl create namespace step
    kubectl -n step create configmap config --from-file $(step path)/config
    kubectl -n step create configmap certs --from-file $(step path)/certs
    kubectl -n step create configmap secrets --from-file $(step path)/secrets
    kubectl -n step create secret generic ca-password --from-literal password=<ca-password>
    kubectl -n step create secret generic autocert-password --from-literal password=<autocert-password>
    
    # 4. Manual: Apply manifests
    kubectl apply -f https://raw.githubusercontent.com/smallstep/autocert/master/install/01-step-ca.yaml
    kubectl apply -f https://raw.githubusercontent.com/smallstep/autocert/master/install/02-autocert.yaml
    kubectl apply -f https://raw.githubusercontent.com/smallstep/autocert/master/install/03-rbac.yaml
  9. Connect to an mTLS service from outside the cluster

    master

    Connecting from outside the cluster requires two things: exposing the service (e.g., via a LoadBalancer) and possessing a valid client certificate issued by the same Certificate Authority (CA).

    To connect using curl when you don't have proper DNS for the internal cluster names, use the --resolve flag to map the service hostname to the LoadBalancer's public IP address.

    # 1. Expose the service
    kubectl expose deployment <deployment-name> --name=<lb-name> --port=443 --type=LoadBalancer
    
    # 2. Get the LoadBalancer IP
    export HELLO_MTLS_IP=$(kubectl get svc <lb-name> -ojsonpath={$.status.loadBalancer.ingress[0].ip})
    
    # 3. Connect using curl with --resolve
    curl --resolve <service-hostname>:443:$HELLO_MTLS_IP \
           --cacert root.crt \
           --cert mike.crt \
           --key mike.key \
           https://<service-hostname>
  10. Inspect a certificate

    master

    You can inspect a certificate managed by autocert by executing the step certificate inspect command within the autocert-renewer container of the target pod.

    kubectl exec -it <pod> -c autocert-renewer -- step certificate inspect /var/run/autocert.step.sm/site.crt
  11. Enable or disable autocert for a namespace

    master

    To enable autocert functionality for a specific namespace, you must apply the autocert.step.sm=enabled label. To disable it, remove the label.

    To verify which namespaces have autocert enabled, use the -L flag with kubectl get namespace to show the label values.

    # Enable autocert for a namespace
    kubectl label namespace <namespace> autocert.step.sm=enabled
    
    # Check which namespaces are labelled
    kubectl get namespace -L autocert.step.sm
    
    # Disable autocert for a namespace
    kubectl label namespace <namespace> autocert.step.sm-
  12. Annotate Pods to receive certificates

    master

    To request a certificate for a workload, add the autocert.step.sm/name annotation to your Pod's metadata. This name will be used as the X.509 Common Name (CN) and Subject Alternative Name (SAN).

    Certificates, keys, and root certificates are mounted at /var/run/autocert.step.sm/ inside the container.

    apiVersion: apps/v1
    kind: Deployment
    metadata: {name: hello-mtls, labels: {app: hello-mtls}}
    spec:
      replicas: 1
      selector: {matchLabels: {app: hello-mtls}}
      template:
        metadata:
          annotations:
            autocert.step.sm/name: hello-mtls.default.svc.cluster.local
          labels: {app: hello-mtls}
        spec:
          containers:
          - name: hello-mtls
            image: smallstep/hello-mtls-server-go:latest