Skip to content

Online Boutique Microservices Demo

This example deploys a microservices e-commerce application (based on Google’s Online Boutique) secured end-to-end with Riptides. Every service receives a SPIFFE identity, and all inter-service communication is encrypted with transparent mTLS — no application code changes required.

The application consists of five core services:

┌──────────┐
┌─────────┤ frontend ├──────────┐
│ └────┬─────┘ │
│ │ │
v v v
┌─────────────┐ ┌───────────┐ ┌─────────────┐
│ product- │ │ cart │ │ checkout │
│ catalog │ │ service │ │ service │
└─────────────┘ └─────┬─────┘ └──┬──┬──┬────┘
│ │ │ │
v │ │ │
┌───────────┐ │ │ │
│ redis │ │ │ │
└───────────┘ │ │ │
┌──────────────────────────┘ │ └────────┐
v v v
┌─────────────┐ ┌──────────────┐ ┌─────────┐
│ product- │ │ payment │ │ email │
│ catalog │ │ service │ │ service │
└─────────────┘ └──────────────┘ └─────────┘

Communication paths:

SourceDestinationProtocolPort
frontendproduct-cataloggRPC3550
frontendcartgRPC7070
frontendcheckoutgRPC5050
checkoutproduct-cataloggRPC3550
checkoutcartgRPC7070
checkoutpaymentgRPC50051
checkoutemailgRPC5000
cartredisTCP6379

All connections are transparently encrypted with mTLS by the Riptides kernel module. The frontend uses PERMISSIVE TLS mode so it can accept plaintext traffic from external load balancers, while backend services enforce MUTUAL TLS for all inbound connections.

Each service gets a unique SPIFFE identity. The allowedSPIFFEIDs fields define which services can communicate, creating a cryptographic service graph.

The frontend accepts traffic from external sources and calls multiple backend services.

apiVersion: core.riptides.io/v1alpha1
kind: WorkloadIdentity
metadata:
name: frontend
namespace: riptides-system
spec:
workloadID: online-boutique/app/frontend
scope:
daemonGroup:
id: riptides/daemongroup/dev-eu-west-1/on-demand-workers
selectors:
- k8s:label:app: frontend
k8s:pod:namespace: online-boutique
process:name: frontend
connection:
tls:
mode: PERMISSIVE
allowedSPIFFEIDs:
outbound:
- spiffe://example.com/online-boutique/app/product-catalog
- spiffe://example.com/online-boutique/app/cart
- spiffe://example.com/online-boutique/app/checkout

Key points:

  • PERMISSIVE TLS mode accepts both plaintext and mTLS connections, allowing ingress from load balancers that do not present a client certificate.
  • outbound allowedSPIFFEIDs list the identities this workload is permitted to connect to.
  • The selectors combine Kubernetes metadata (label, namespace) with process-level attestation (process:name) for defense in depth.
apiVersion: core.riptides.io/v1alpha1
kind: WorkloadIdentity
metadata:
name: product-catalog
namespace: riptides-system
spec:
workloadID: online-boutique/app/product-catalog
scope:
daemonGroup:
id: riptides/daemongroup/dev-eu-west-1/on-demand-workers
selectors:
- k8s:label:app: productcatalogservice
k8s:pod:namespace: online-boutique
process:name: productcatalogservice
connection:
tls:
mode: MUTUAL
allowedSPIFFEIDs:
inbound:
- spiffe://example.com/online-boutique/app/frontend
- spiffe://example.com/online-boutique/app/checkout

Key points:

  • MUTUAL TLS mode requires all clients to present a valid SPIFFE identity. Unauthenticated connections are rejected at the kernel level.
  • Only frontend and checkout are allowed to call this service.
apiVersion: core.riptides.io/v1alpha1
kind: WorkloadIdentity
metadata:
name: cart
namespace: riptides-system
spec:
workloadID: online-boutique/app/cart
scope:
daemonGroup:
id: riptides/daemongroup/dev-eu-west-1/on-demand-workers
selectors:
- k8s:label:app: cartservice
k8s:pod:namespace: online-boutique
process:name: cartservice
connection:
tls:
mode: MUTUAL
allowedSPIFFEIDs:
inbound:
- spiffe://example.com/online-boutique/app/frontend
- spiffe://example.com/online-boutique/app/checkout
outbound:
- spiffe://example.com/online-boutique/app/redis

The checkout service orchestrates the purchase flow, calling multiple downstream services.

apiVersion: core.riptides.io/v1alpha1
kind: WorkloadIdentity
metadata:
name: checkout
namespace: riptides-system
spec:
workloadID: online-boutique/app/checkout
scope:
daemonGroup:
id: riptides/daemongroup/dev-eu-west-1/on-demand-workers
selectors:
- k8s:label:app: checkoutservice
k8s:pod:namespace: online-boutique
process:name: checkoutservice
connection:
tls:
mode: MUTUAL
allowedSPIFFEIDs:
inbound:
- spiffe://example.com/online-boutique/app/frontend
outbound:
- spiffe://example.com/online-boutique/app/product-catalog
- spiffe://example.com/online-boutique/app/cart
- spiffe://example.com/online-boutique/app/payment
- spiffe://example.com/online-boutique/app/email
apiVersion: core.riptides.io/v1alpha1
kind: WorkloadIdentity
metadata:
name: payment
namespace: riptides-system
spec:
workloadID: online-boutique/app/payment
scope:
daemonGroup:
id: riptides/daemongroup/dev-eu-west-1/on-demand-workers
selectors:
- k8s:label:app: paymentservice
k8s:pod:namespace: online-boutique
process:name: node
connection:
tls:
mode: MUTUAL
allowedSPIFFEIDs:
inbound:
- spiffe://example.com/online-boutique/app/checkout
apiVersion: core.riptides.io/v1alpha1
kind: WorkloadIdentity
metadata:
name: email
namespace: riptides-system
spec:
workloadID: online-boutique/app/email
scope:
daemonGroup:
id: riptides/daemongroup/dev-eu-west-1/on-demand-workers
selectors:
- k8s:label:app: emailservice
k8s:pod:namespace: online-boutique
process:name: python
connection:
tls:
mode: MUTUAL
allowedSPIFFEIDs:
inbound:
- spiffe://example.com/online-boutique/app/checkout
apiVersion: core.riptides.io/v1alpha1
kind: WorkloadIdentity
metadata:
name: redis
namespace: riptides-system
spec:
workloadID: online-boutique/app/redis
scope:
daemonGroup:
id: riptides/daemongroup/dev-eu-west-1/on-demand-workers
selectors:
- k8s:label:app: redis-cart
k8s:pod:namespace: online-boutique
process:name: redis-server
connection:
tls:
mode: MUTUAL
allowedSPIFFEIDs:
inbound:
- spiffe://example.com/online-boutique/app/cart

Service resources tell Riptides where each workload listens, and provide labels used by egress rules.

apiVersion: core.riptides.io/v1alpha1
kind: Service
metadata:
name: online-boutique-frontend
namespace: riptides-system
spec:
addresses:
- address: frontend.online-boutique.svc.cluster.local
port: 80
labels:
app: online-boutique
service: frontend
---
apiVersion: core.riptides.io/v1alpha1
kind: Service
metadata:
name: online-boutique-product-catalog
namespace: riptides-system
spec:
addresses:
- address: productcatalogservice.online-boutique.svc.cluster.local
port: 3550
labels:
app: online-boutique
service: productcatalogservice
---
apiVersion: core.riptides.io/v1alpha1
kind: Service
metadata:
name: online-boutique-cart
namespace: riptides-system
spec:
addresses:
- address: cartservice.online-boutique.svc.cluster.local
port: 7070
labels:
app: online-boutique
service: cartservice
---
apiVersion: core.riptides.io/v1alpha1
kind: Service
metadata:
name: online-boutique-checkout
namespace: riptides-system
spec:
addresses:
- address: checkoutservice.online-boutique.svc.cluster.local
port: 5050
labels:
app: online-boutique
service: checkoutservice
---
apiVersion: core.riptides.io/v1alpha1
kind: Service
metadata:
name: online-boutique-payment
namespace: riptides-system
spec:
addresses:
- address: paymentservice.online-boutique.svc.cluster.local
port: 50051
labels:
app: online-boutique
service: paymentservice
---
apiVersion: core.riptides.io/v1alpha1
kind: Service
metadata:
name: online-boutique-email
namespace: riptides-system
spec:
addresses:
- address: emailservice.online-boutique.svc.cluster.local
port: 5000
labels:
app: online-boutique
service: emailservice
---
apiVersion: core.riptides.io/v1alpha1
kind: Service
metadata:
name: online-boutique-redis
namespace: riptides-system
spec:
addresses:
- address: redis-cart.online-boutique.svc.cluster.local
port: 6379
labels:
app: online-boutique
service: redis-cart

Once these resources are applied, the Riptides control plane distributes them to daemons running on each node.

  1. Attests each workload — The daemon uses the configured selectors (Kubernetes labels, namespace, and process name) to match running processes. Only processes matching all selector criteria receive a SPIFFE identity.

  2. Issues X.509 certificates — The control plane issues short-lived SVIDs (SPIFFE Verifiable Identity Documents) for attested workloads and rotates them before expiry.

  3. Encrypts connections transparently — When the frontend opens a TCP connection to the cart service on port 7070, the kernel module intercepts the socket, performs a mutual TLS handshake, and validates both identities against the allowedSPIFFEIDs policy — all without any changes to application code.

  4. Blocks unauthorized traffic — If an attacker compromises the email service and attempts to connect to the payment service, the connection is denied because spiffe://example.com/online-boutique/app/email is not in the payment service’s allowedSPIFFEIDs.inbound list.

Terminal window
# Apply all Riptides resources
riptides-cli ctl apply -f workload-identities.yaml
riptides-cli ctl apply -f services.yaml
# Deploy the application (standard Kubernetes manifests, no sidecars needed)
kubectl apply -f online-boutique/kubernetes-manifests.yaml

No application changes, no sidecar containers, no service annotations. The kernel module handles identity and encryption at the socket level.