Daemon Deployment on Kubernetes
This guide covers deploying the Riptides daemon as a DaemonSet on Kubernetes clusters. The daemon runs on every node, loads the Riptides kernel module, and connects to the control plane for identity issuance and policy enforcement.
Prerequisites
Section titled “Prerequisites”- Kubernetes 1.24+
- Helm 3.2.0+
- Privileged container support (required for kernel module loading)
- Network connectivity from workload nodes to the control plane (ports 8443, 9443, 8001)
- A running Riptides control plane (see Control Plane Deployment)
Installation
Section titled “Installation”Install the daemon using the Riptides OCI Helm chart:
helm install riptides-daemon oci://ghcr.io/riptides-packages/helm/daemon --version version \ --namespace riptides-system \ --create-namespace \ -f daemon-values.yamlHow It Works
Section titled “How It Works”The daemon Helm chart deploys a DaemonSet that runs on every node in your cluster. Each pod consists of:
-
Driver loader init container — Loads the Riptides kernel module onto the host before the daemon starts. The init container runs privileged and uses a pre-built image matching your kernel version and distribution.
-
Daemon container — The main daemon process that communicates with the kernel module (via
/dev/riptides), connects to the control plane, manages certificates, and applies policies.
Configuration Reference
Section titled “Configuration Reference”Daemon Core Settings
Section titled “Daemon Core Settings”All daemon settings live under config.daemon:
| Parameter | Description | Default |
|---|---|---|
config.daemon.trustDomain | SPIFFE trust domain (must match control plane) | example.com |
config.daemon.defaultCertTTL | Default TTL for issued workload certificates | 2h |
config.daemon.dataDir | Persistent data directory inside the container | /data/riptides |
config.daemon.kernelModuleDevice | Path to the kernel module character device | /host/dev/riptides |
Control Plane Connection
Section titled “Control Plane Connection”Settings under config.daemon.controlPlane:
| Parameter | Description | Default |
|---|---|---|
config.daemon.controlPlane.enabled | Enable control plane connection | true |
config.daemon.controlPlane.url | HTTPS base URL of the control plane | https://controlplane:8443 |
config.daemon.controlPlane.grpcServerAddress | gRPC endpoint (host:port) | none |
config.daemon.controlPlane.tokenBrokerBaseURL | Token broker endpoint URL | none |
config.daemon.controlPlane.allowInsecureConnection | Skip TLS verification (development only) | false |
config.daemon.controlPlane.authPlugin.type | Authentication plugin type (see below) | joinToken |
When using separate DNS records for each control plane service (typical in production), configure all three endpoints:
config: daemon: controlPlane: url: https://cp.example.com grpcServerAddress: grpc.example.com:443 tokenBrokerBaseURL: https://cp.example.com/token-brokerTunnel Server
Section titled “Tunnel Server”For daemons behind NAT or restrictive firewalls, configure a tunnel connection:
| Parameter | Description | Default |
|---|---|---|
config.daemon.tunnelServer.address | Tunnel server endpoint (host:port) | none |
config: daemon: tunnelServer: address: tunnel.example.com:443Authentication Plugins
Section titled “Authentication Plugins”The daemon authenticates to the control plane using one of these plugins:
Join Token
Section titled “Join Token”A static shared token, suitable for development or initial bootstrapping:
config: daemon: controlPlane: authPlugin: type: joinToken config: token: "your-join-token-here"Create the corresponding resources on the control plane:
apiVersion: auth.riptides.io/v1alpha1kind: Verifiermetadata: name: jointoken namespace: riptides-systemspec: joinToken: {}---apiVersion: auth.riptides.io/v1alpha1kind: JoinTokenmetadata: name: my-join-token namespace: riptides-systemspec: token: "your-join-token-here"AWS Instance Identity Document (AWSIID)
Section titled “AWS Instance Identity Document (AWSIID)”Recommended for AWS deployments. The daemon uses the EC2 instance identity document for attestation — no shared secrets required:
config: daemon: controlPlane: authPlugin: type: AWSIIDGCP Instance Identity Token (GCPIIT)
Section titled “GCP Instance Identity Token (GCPIIT)”Recommended for GCP deployments. Uses the GCP instance identity token:
config: daemon: controlPlane: authPlugin: type: GCPIITMetadata Collectors
Section titled “Metadata Collectors”Metadata collectors enrich workload identity information with context from the runtime environment. Configure under config.daemon.metadataCollectors:
| Collector | Description | Default |
|---|---|---|
procfs | Collects process information from /proc | enabled: true |
procfs.extractEnvs | Also collect environment variables | false |
linuxos | Collects OS release information | enabled: true |
sysfsdmi | Collects DMI/SMBIOS hardware info | enabled: true |
ec2 | AWS EC2 instance metadata | enabled: true |
gcp | GCP instance metadata | enabled: true |
azure | Azure instance metadata | enabled: true |
kubernetes | Kubernetes pod and node metadata | enabled: true |
docker | Docker container metadata | enabled: false |
For the Kubernetes metadata collector:
| Parameter | Description | Default |
|---|---|---|
kubernetes.kubeletHost | Kubelet API host | localhost |
kubernetes.kubeletPort | Kubelet API port | 10250 |
kubernetes.kubeletCA | Path to kubelet CA certificate | /etc/kubernetes/pki/ca.crt |
kubernetes.skipKubeletVerification | Skip kubelet TLS verification | true |
kubernetes.credentials | Path to service account token | /var/run/secrets/kubernetes.io/serviceaccount/token |
Disable cloud provider collectors that do not apply to your environment to avoid unnecessary metadata API calls:
config: daemon: metadataCollectors: ec2: enabled: true gcp: enabled: false azure: enabled: falseDriver Loader
Section titled “Driver Loader”The driver loader init container loads the Riptides kernel module before the daemon starts:
| Parameter | Description | Default |
|---|---|---|
driverLoader.image.repository | Driver loader image | ghcr.io/riptides-packages/images/driver-loader |
driverLoader.image.pullPolicy | Pull policy | IfNotPresent |
driverLoader.driverVersion | Driver version (git branch, tag, or commit) | main |
driverLoader.commandTimeout | Timeout in seconds for load commands | 5 |
driverLoader.dynDBG | Enable kernel dynamic debug for the module | false |
Health Check
Section titled “Health Check”| Parameter | Description | Default |
|---|---|---|
healthStatus.port | Daemon health check port | 10100 |
Example: AWS EKS Deployment
Section titled “Example: AWS EKS Deployment”A complete daemon-values.yaml for an AWS EKS cluster:
image: tag: "v0.1.0" pullPolicy: Always
driverLoader: image: tag: "v0.5.2" driverVersion: "v0.1.0" commandTimeout: 5 dynDBG: false
config: daemon: trustDomain: example.com defaultCertTTL: 2h dataDir: /data/riptides metadataCollectors: procfs: enabled: true extractEnvs: false linuxos: enabled: true sysfsdmi: enabled: true ec2: enabled: true gcp: enabled: false azure: enabled: false kubernetes: enabled: true kubeletHost: localhost kubeletPort: 10250 kubeletCA: /etc/kubernetes/pki/ca.crt skipKubeletVerification: true credentials: /var/run/secrets/kubernetes.io/serviceaccount/token docker: enabled: false controlPlane: enabled: true url: https://cp.example.com grpcServerAddress: grpc.example.com:443 tokenBrokerBaseURL: https://cp.example.com/token-broker authPlugin: type: AWSIID tunnelServer: address: tunnel.example.com:443
healthStatus: port: 10100
resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi
tolerations: - operator: ExistsVerifying the Deployment
Section titled “Verifying the Deployment”Check that daemon pods are running on all nodes:
kubectl get pods -n riptides-system -l app.kubernetes.io/name=daemon -o wideCheck the driver loader init container logs to confirm the kernel module loaded:
kubectl logs -n riptides-system -l app.kubernetes.io/name=daemon -c daemon-driver-loaderCheck the daemon logs for control plane connectivity:
kubectl logs -n riptides-system -l app.kubernetes.io/name=daemon -fVerify health:
kubectl port-forward -n riptides-system daemonset/riptides-daemon 10100:10100curl http://localhost:10100/healthzTroubleshooting
Section titled “Troubleshooting”Driver loader fails
Section titled “Driver loader fails”If the init container fails, the kernel module loader may have failed. Check the kernel module loader init container.
kubectl logs -n riptides-system <failed-daemon-pod> -c daemon-driver-loaderDaemon cannot reach control plane
Section titled “Daemon cannot reach control plane”Verify network connectivity from a workload node to the control plane endpoints:
kubectl run -n riptides-system netcheck --rm -it --image=busybox -- \ wget -qO- --timeout=5 https://cp.example.com:8443/healthzEnsure your security groups or network policies allow outbound traffic to ports 8443, 9443, and 8001 on the control plane.
Authentication failures
Section titled “Authentication failures”Check that the trust domain in the daemon configuration exactly matches the trust domain configured on the control plane. For join token auth, verify the token value matches the JoinToken resource on the control plane.
Upgrading
Section titled “Upgrading”helm upgrade riptides-daemon oci://ghcr.io/riptideslabs/helm/daemon \ --namespace riptides-system \ -f daemon-values.yamlThe DaemonSet performs a rolling update by default. The driver loader init container will reload the kernel module on each node as pods restart.