Production Kubernetes Deployment
This guide explains how to deploy a production-grade SAM cluster (control plane, router, DNS synchronizer, OIDC bridge, and Nodes) in a Kubernetes environment (like GKE, EKS, AKS, or custom bare-metal clusters), based on our official public testnet architectures.
1. Architecture Overview
A production SAM deployment consists of:
- Dex (OIDC Provider): Serves as the identity bridge, federation point, and login broker.
- SAM Control Plane (
sam-control-plane): Runs as a stateless Deployment to verify OIDC tokens and issue capabilities (Biscuits) based on identity policies. - SAM Router (
sam-router): Runs as a StatefulSet to maintain stable network identity. P2P nodes use these bootstrap routers to connect to the GossipSub mesh overlay. - DNS Sync CronJob: Dynamically queries the
sam-routerStatefulSet pod IP addresses and updates DNS A/AAAA records for P2P bootstrap resolution. - SAM Nodes (
sam-node): Deployed as containerized gateways that authenticate securely to the control plane using Kubernetes Workload Identity (ServiceAccount token projection).
graph TD
User([User / Client]) -->|HTTPS / OIDC| Dex[Dex Identity Bridge]
Node[sam-node Gateway Pod] -->|HTTPS Enroll| CP[sam-control-plane Deployment]
Router[sam-router StatefulSet] -->|HTTPS Enroll| CP
Node -->|P2P Mesh Overlay| Router
CP -->|OIDC Discovery Check| Dex
Cron[DNS Sync CronJob] -->|Poll Pod IPs| K8sApi[Kubernetes API]
Cron -->|Update A Records| CloudDNS[Cloud DNS / DNS Registry]
Node -->|Bootstrap DNS Resolution| CloudDNS2. Step 1: Deploying the OIDC Provider (Dex)
Dex maps external accounts (Google, GitHub, LDAP) to standard OIDC identities in the cluster.
1. Provision Dex Secrets
Idempotently create the secret containing your OAuth client applications’ credentials:
kubectl create secret generic dex-secrets \
--namespace=dex \
--from-literal=google-client-id="<my-google-client-id>" \
--from-literal=google-client-secret="<my-google-client-secret>" \
--from-literal=github-client-id="<my-github-client-id>" \
--from-literal=github-client-secret="<my-github-client-secret>" \
--from-literal=cli-oauth-secret="<my-ephemeral-cli-oauth-secret>" \
--dry-run=client -o yaml | kubectl apply -f -
2. Apply Dex Manifests
Deploy the Dex deployment and configuration mapping:
# dex-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: dex-config
namespace: dex
data:
config.yaml: |
issuer: https://AUTH.YOUR-DOMAIN.COM
storage:
type: kubernetes
config:
inCluster: true
web:
http: 0.0.0.0:5556
connectors:
- type: google
id: google
name: Google
config:
clientID: $GOOGLE_CLIENT_ID
clientSecret: $GOOGLE_CLIENT_SECRET
redirectURI: https://AUTH.YOUR-DOMAIN.COM/callback
staticClients:
- id: YOUR-CLI-AUDIENCE
name: 'SAM Mesh native client'
secret: $CLI_OAUTH_SECRET
redirectURIs:
- 'urn:ietf:wg:oauth:2.0:oob'
- 'http://localhost:8000'
Deploy the deployment manifests located in the repository’s .github/k8s/dex-deployment.yaml and wait for readiness:
kubectl rollout status deployment/dex -n dex
3. Step 2: Deploying SAM Control Plane and Router
The Control Plane verifies OIDC tokens and manages access policies. The Routers handle peer discovery and routing within the GossipSub mesh.
1. Configure Access Control Policies (policies.yaml)
Create a ConfigMap defining your global mesh access rules:
apiVersion: v1
kind: ConfigMap
metadata:
name: sam-control-plane-policies
namespace: sam
data:
policies.yaml: |
version: "v1alpha1"
bindings:
- members: ["user:system:serviceaccount:sam-nodes:sam-node-sa"]
role: "node-role"
roles:
node-role:
allowed_services:
- "*"
allowed_targets:
- "*"
kubectl apply -f policies-configmap.yaml
2. Deploy SAM Control Plane
The Control Plane is stateless and can scale horizontally. It connects to a shared PostgreSQL database to persist active leases and rotated capability signing keys.
apiVersion: apps/v1
kind: Deployment
metadata:
name: sam-control-plane
namespace: sam
spec:
replicas: 3
selector:
matchLabels:
app: sam-control-plane
template:
metadata:
labels:
app: sam-control-plane
spec:
containers:
- name: sam-control-plane
image: ghcr.io/google/sam-control-plane:latest
args:
- "--bind-address=0.0.0.0:8080"
- "--db-driver=postgres"
- "--db-dsn=postgres://sam:password@sam-db-service:5432/sam_mesh?sslmode=disable"
- "--issuer=https://AUTH.YOUR-DOMAIN.COM"
- "--allowed-audiences=YOUR-CLIENT-AUDIENCE"
- "--policy-file=/etc/sam/policies/policies.yaml"
ports:
- containerPort: 8080
name: http
volumeMounts:
- name: policies-volume
mountPath: /etc/sam/policies
readOnly: true
volumes:
- name: policies-volume
configMap:
name: sam-control-plane-policies
3. Deploy SAM Router StatefulSet
The Router must be deployed as a StatefulSet to allocate a persistent volume for storing its libp2p identity key, ensuring a stable Peer ID across pod restarts.
apiVersion: v1
kind: ServiceAccount
metadata:
name: sam-router-sa
namespace: sam
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: sam-router
namespace: sam
spec:
serviceName: "sam-router"
replicas: 3
selector:
matchLabels:
app: sam-router
template:
metadata:
labels:
app: sam-router
spec:
serviceAccountName: sam-router-sa
containers:
- name: sam-router
image: ghcr.io/google/sam-router:latest
ports:
- containerPort: 4501
protocol: TCP
name: p2p-tcp
- containerPort: 4501
protocol: UDP
name: p2p-udp
args:
- "--control-plane=http://sam-control-plane.sam.svc.cluster.local:8080"
- "--listen=/ip4/0.0.0.0/tcp/4501"
- "--listen=/ip4/0.0.0.0/udp/4501/quic-v1"
- "--jwt-path=/var/run/secrets/tokens/sam-token"
- "--keys-path=/data/router.key"
volumeMounts:
- name: sam-token
mountPath: /var/run/secrets/tokens
readOnly: true
- name: router-data
mountPath: /data
volumes:
- name: sam-token
projected:
sources:
- serviceAccountToken:
path: sam-token
expirationSeconds: 3600
audience: "sam-control-plane-audience"
volumeClaimTemplates:
- metadata:
name: router-data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
4. Step 3: DNS Synchronization (DHT Bootstrapping)
In a decentralized DHT network, nodes need stable DNS multiaddrs (/dnsaddr/BOOTSTRAP.YOUR-DOMAIN.COM) to resolve bootstrap peers. Since Kubernetes StatefulSet pod IP addresses change on restart, you must deploy a sync cronjob that updates A/AAAA records on your DNS provider.
DNS Sync CronJob Example
The sync script:
- Queries the Kubernetes API for the external/internal IP addresses of the
sam-routerpods. - Updates your Cloud DNS zone (e.g. Google Cloud DNS, AWS Route53) dynamically.
- Announce new multiaddrs via TXT records.
Refer to dns-sync-cronjob-template.yaml for our official Cloud DNS sync cronjob.
5. Step 4: Deploying SAM Nodes (Workload Identity)
To secure nodes without distributing static passwords, configure nodes to authenticate via ServiceAccount projected tokens (Workload Identity Federation).
1. Create a ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: sam-node-sa
namespace: sam-nodes
2. Configure Node Identity and Services
Create a ConfigMap defining the node’s local services and local security target identity (see the Node Configuration Guide for schema details):
apiVersion: v1
kind: ConfigMap
metadata:
name: sam-node-config
namespace: sam-nodes
data:
sam-node.yaml: |
version: "v1alpha1"
services:
- type: mcp
name: db-agent
command: ["echo", "placeholder db-agent service"]
attenuation:
rules:
- 'department("analytics") <- true;'
policies:
- 'deny if user("untrusted_user");'
3. Deploy Nodes using Token Projection
Deploy the nodes. We use a projected volume to request a short-lived token containing the audience expected by the control plane (sam-control-plane-audience):
apiVersion: apps/v1
kind: Deployment
metadata:
name: sam-node
namespace: sam-nodes
spec:
replicas: 5
template:
spec:
serviceAccountName: sam-node-sa
containers:
- name: sam-node
image: ghcr.io/google/sam-node:latest
args:
- "run"
- "--config=/etc/sam/sam-node.yaml"
- "--control-plane=http://sam-control-plane.sam.svc.cluster.local:8080"
- "--jwt-path=/var/run/secrets/tokens/sam-token"
- "--api-token-path=/var/run/secrets/sam/api-token"
volumeMounts:
- name: config-volume
mountPath: /etc/sam
- name: sam-token
mountPath: /var/run/secrets/tokens
readOnly: true
volumes:
- name: config-volume
configMap:
name: sam-node-config
- name: sam-token
projected:
sources:
- serviceAccountToken:
path: sam-token
expirationSeconds: 3600
audience: "sam-control-plane-audience" # Match this with what the control plane expects
6. Local Sandbox Testing (Kind)
If you are looking to test Kubernetes deployments locally in a sandboxed cluster without external cloud dependencies, please follow the Local Kubernetes Testing Guide.