Skip to content

Beacon Relay Connectivity

The beacon relay is customer-deployed infrastructure. Its one job is to let your EU-hosted secret store and your US-cloud Kubernetes cluster establish an mTLS tunnel without either side exposing an inbound port. Both the bridge (next to your secret store) and the operator broker (in your cluster) connect outbound to a stateless beacon process that you run; the beacon matches them cryptographically and forwards encrypted bytes between them. It sees TLS ciphertext only — no keys, no plaintext, no configuration state.

No dependency on cloudtaser-operated infrastructure

Production deployments run their own beacon. The beacon is a ~2 MB static Go binary with no persistent state; the Helm chart (cloudtaser-beacon) deploys it in minutes. cloudtaser does not operate any beacon in your data path. A public demo relay at beacon.cloudtaser.io exists exclusively for the live demo at cloudtaser.io/demo-lab and quick-look pilots; it is not for production use and is documented as such in the trust model.

The architectural goal of the beacon pattern is zero inbound exposure on either side: no public OpenBao/Vault listener, no cluster LoadBalancer, no VPN. That compliance and security property is the reason the beacon exists. A vendor sitting in the TCP path would defeat it; customer-operated is the only posture that actually delivers the property.


When to use beacon relay

Beacon relay is the default connectivity mode. Use it when:

  • Your OpenBao and cluster have no direct network path
  • Both sides are behind NAT or firewalls
  • You only allow outbound TCP 443 traffic
  • You want zero-config connectivity (no VPN, no IPsec, no SSH tunnels)

Use reverse-connect (--mode reverse) instead when:

  • You have a direct network path and want lower latency
  • You can expose a LoadBalancer or public endpoint on the cluster

Use direct (--mode direct) only for legacy setups where pods connect directly to OpenBao.

Default mode

Beacon relay is the default when running cloudtaser-cli target install. You do not need to specify --mode beacon unless overriding a previous configuration.


Architecture

                  EU Jurisdiction                        Beacon                        US Cloud Provider
         ┌──────────────────────────┐          ┌────────────────────┐       ┌──────────────────────────┐
         │                          │          │                    │       │                          │
         │   OpenBao / Vault        │          │   Stateless relay  │       │   Managed Kubernetes     │
         │   + Bridge               │─────────>│   port 443 only   │<──────│   + Operator (broker)    │
         │                          │ outbound │                    │       │                          │
         └──────────────────────────┘          │   Matches by       │       │   ┌──────────────────┐   │
                                               │   info_hash        │       │   │ Protected pods   │   │
                                               │                    │       │   │ → Broker → Beacon │   │
                                               │   Relays encrypted │       │   │   → Bridge → Vault│   │
                                               │   mTLS bytes       │       │   └──────────────────┘   │
                                               └────────────────────┘       └──────────────────────────┘

Data flow for secret delivery:

Protected pod → Operator broker (port 8199) → Beacon relay → Bridge → EU Vault
  1. The bridge runs alongside OpenBao and connects outbound to the beacon
  2. The operator (broker) connects outbound to the beacon from the K8s cluster
  3. The beacon matches them by their shared info hash (SHA-256 of the bridge CA certificate)
  4. After matching, the beacon relays bytes bidirectionally
  5. Through the relay, bridge and broker establish mTLS (end-to-end encrypted)
  6. The beacon never sees plaintext -- it only relays encrypted traffic

Security

mTLS end-to-end

Bridge and broker authenticate each other via certificates generated during the self-bootstrap protocol. The beacon relay is transparent -- it forwards bytes without inspecting or modifying them. Even if the beacon is compromised, the attacker cannot decrypt the traffic.

Info hash as capability

The info hash is the SHA-256 of the bridge CA certificate. Only parties that possess the same CA certificate compute the same hash. The beacon uses this hash to match bridge and broker connections. Without the correct info hash, a connection cannot be paired.

Beacon is stateless

The beacon holds no secrets, no keys, no configuration state. It is a pure relay: accept connections, match by info hash, forward bytes. If the beacon process restarts, bridge and broker reconnect automatically.

Zero trust

The security model does not trust the beacon. Even under full compromise of the beacon server, the attacker sees only TLS-encrypted bytes. Secrets remain protected by the mTLS tunnel between bridge and broker.

Connection hardening (May 2026)

The beacon applies TCP keepalive probes immediately after Accept, before the TLS handshake begins, preventing half-open connections from accumulating under adverse network conditions. The per-IP rate limiter aggregates IPv6 addresses to /64 prefixes (preventing rotation-based bypass) and caps the rate-limit map at 10,000 entries with oldest-entry eviction. The /admin/drain endpoint is served on a dedicated loopback-only listener when the health server binds to a non-loopback address, so access is enforced at the network layer rather than by inspecting RemoteAddr. See Upgrade Section E1 for operator-facing details.

Operator-visible limits

The beacon enforces three hard limits to protect against unauthenticated abuse. All are compile-time defaults with no runtime configuration knobs -- the values are chosen to be generous for legitimate traffic while capping the blast radius of sustained attacks.

Limit Default Scope Behaviour when exceeded
Forward rate limit 100 connections/min Per source IP (IPv6 bucketed by /64) Connection closed with rateLimit error
Concurrency cap 1,000 simultaneous forwarded connections Global (per beacon process) New connections block until a slot frees (backpressure, not rejection)
Gossip value size 8,192 bytes Per ACME gossip entry Entry rejected with errGossipValueTooLarge

Scanner-triggered log lines (TLS handshake failures, unexpected protocols, premature close) are logged at DEBUG, not WARN, to reduce noise in production log pipelines. See Upgrade Section G for the full changelog and operator-action guidance.

In-memory certificates

All mTLS certificates for the bridge-to-broker connection are stored in OpenBao and loaded into operator process memory at runtime. No certificates are stored in Kubernetes Secrets. See Zero Kubernetes Secrets Architecture for details.

For how per-pod child vault tokens are minted on top of this tunnel and delivered into wrapper memory via the HKDF-v2 unseal envelope, see Trust Chain & Per-Pod Isolation.


Setup

The recommended setup uses the self-bootstrap protocol, which requires only a cluster fingerprint and a single Helm parameter. See Self-Bootstrap Protocol for the full walkthrough.

Quick setup (self-bootstrap)

1. Get cluster fingerprint (target side):

cloudtaser-cli target fingerprint

2. Register cluster (OpenBao side):

cloudtaser-cli source register \
  --fingerprint <cluster-fingerprint> \
  --secretstore-address https://vault.eu.example.com \
  --secretstore-token $TOKEN

This generates mTLS certificates, stores them in OpenBao, and registers the cluster. The bridge detects the new registration and connects to the beacon automatically.

3. Deploy operator (target side):

helm repo add cloudtaser https://charts.cloudtaser.io
helm install cloudtaser cloudtaser/cloudtaser \
  --namespace cloudtaser-system \
  --create-namespace \
  --set operator.broker.beacon.address=beacon.example.com:443

The operator self-bootstraps through the beacon relay -- it receives its certificates from the bridge and transitions to operational mode automatically. No certificates, tokens, or OpenBao addresses in the Helm values.

4. Deploy workloads:

Annotate pods with cloudtaser annotations -- no OpenBao address needed in beacon mode:

annotations:
  cloudtaser.io/inject: "true"
  cloudtaser.io/secret-paths: "secret/data/myapp/config"
  cloudtaser.io/env-map: "password=DB_PASSWORD"

Secrets are fetched through the beacon relay automatically. The wrapper connects to the in-cluster broker, which tunnels requests through the beacon to the bridge, which forwards them to the local OpenBao instance.

Manual setup

For environments where self-bootstrap is not suitable, you can configure the beacon relay manually.

1. Connect cluster to OpenBao:

cloudtaser-cli target connect \
  --secretstore-address https://vault.example.com \
  --secretstore-token $TOKEN \
  --beacon-address beacon.example.com:443

This command performs the following:

  1. Generates mTLS certificates (CA, bridge cert, broker cert)
  2. Stores the certificates and configuration in OpenBao
  3. Computes the info hash from the CA certificate
  4. Configures the Kubernetes auth backend in OpenBao
  5. Creates an OpenBao namespace for the cluster at cloudtaser/<fingerprint[:8]>

Preview before applying

Use --dry-run to see what changes will be made before applying them:

cloudtaser-cli target connect \
  --secretstore-address https://vault.example.com \
  --secretstore-token $TOKEN \
  --beacon-address beacon.example.com:443 \
  --dry-run

2. Start the bridge (OpenBao side):

cloudtaser-bridge \
  --vault-addr https://127.0.0.1:8200 \
  --beacon-address beacon.example.com:443 \
  --beacon-info-hash <generated-hash> \
  --tls-cert /path/to/client.crt \
  --tls-key /path/to/client.key \
  --tls-ca /path/to/ca.crt

Or via the cloudtaser-onprem Helm chart which includes the bridge as a sidecar:

helm install cloudtaser-onprem cloudtaser/cloudtaser-onprem \
  --set bridge.beacon.enabled=true \
  --set bridge.beacon.address=beacon.example.com:443 \
  --set bridge.beacon.infoHash=<generated-hash>

Or as a systemd service for bare-metal OpenBao deployments:

[Unit]
Description=cloudtaser Bridge (Beacon Relay)
After=network-online.target vault.service
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/cloudtaser-bridge \
  --vault-addr https://127.0.0.1:8200 \
  --beacon-address beacon.example.com:443 \
  --beacon-info-hash <generated-hash> \
  --tls-cert /etc/cloudtaser/bridge/client.crt \
  --tls-key /etc/cloudtaser/bridge/client.key \
  --tls-ca /etc/cloudtaser/bridge/ca.crt
Restart=always
RestartSec=5
User=vault

[Install]
WantedBy=multi-user.target

3. Install operator with beacon config:

helm install cloudtaser cloudtaser/cloudtaser \
  --namespace cloudtaser-system \
  --create-namespace \
  --set operator.broker.beacon.enabled=true \
  --set operator.broker.beacon.address=beacon.example.com:443 \
  --set operator.broker.beacon.infoHash=<generated-hash>

Beacon deployment

The beacon is a static Go binary (~2 MB, zero dependencies, no persistent state). Production deployments run their own; the examples in the Setup section above use beacon.example.com:443 as a placeholder — substitute your deployed endpoint.

Customer-deployed (production)

The recommended path: deploy the beacon yourself, in your infrastructure, on a public IP or DNS name reachable from both the secret-store side and the cluster side on TCP 443. The beacon needs no access to either your secret store or your cluster — it is a pure byte forwarder that matches TLS streams by their info hash.

Helm chart:

helm install cloudtaser-beacon cloudtaser/cloudtaser-beacon \
  --namespace cloudtaser-beacon \
  --create-namespace \
  --set service.type=LoadBalancer \
  --set tls.existingSecret=beacon-tls

Standalone binary (systemd, bare metal, or a small VM):

curl -sfL https://github.com/cloudtaser/cloudtaser-beacon/releases/latest/download/cloudtaser-beacon-linux-amd64 \
  -o /usr/local/bin/cloudtaser-beacon
chmod +x /usr/local/bin/cloudtaser-beacon

cloudtaser-beacon \
  --addr :443 \
  --tls-cert /etc/cloudtaser/beacon/cert.pem \
  --tls-key /etc/cloudtaser/beacon/key.pem

For high availability, run multiple beacon instances behind a load balancer or configure clients with comma-separated addresses:

cloudtaser-bridge \
  --beacon-address beacon1.example.com:443,beacon2.example.com:443 \
  ...

Public pilot beacon (NOT for production)

A public demo relay at beacon.cloudtaser.io:443 exists to support the live demo at cloudtaser.io/demo-lab and quick-look pilots. It is not for production use:

  • It is not in any production support SLA.
  • It can be taken down for maintenance at any time.
  • Using it places connection metadata (source/destination IPs, timestamps, byte counts, info hashes) on infrastructure you do not operate — which defeats the whole point of the beacon pattern (eliminating third-party exposure).

Production deployments — and any deployment under a DPIA, regulated workload, or procurement review — run their own beacon. See Beacon Trust Model for the threat-model framing.


Network requirements

Side Direction Destination Port Protocol
OpenBao (bridge) Outbound Beacon server 443 TCP/TLS
Cluster (broker) Outbound Beacon server 443 TCP/TLS
Beacon server Inbound From bridge and broker 443 TCP/TLS

No inbound ports are required on either OpenBao or the cluster. Both sides initiate outbound connections only.


Comparison of connectivity modes

Feature Direct Reverse-Connect Beacon Relay
Network requirement OpenBao reachable from pods Broker reachable from OpenBao Outbound TCP 443 only
Configuration OpenBao address per pod Bridge endpoint Zero-config (info hash)
NAT traversal No Partial Full
Default mode No No Yes
Latency Lowest Low Low (+1 hop)
OpenBao inbound ports Required None None
Cluster inbound ports None Required (LoadBalancer) None
Third-party dependency None None None (beacon is customer-deployed)

Troubleshooting

Symptom Cause Fix
Broker cannot connect to beacon Egress firewall blocking TCP 443 to beacon address Allow outbound TCP 443 to your beacon's public DNS name or IP
Bridge cannot connect to beacon Secret-store-side egress restricted Allow outbound TCP 443 to your beacon's public DNS name or IP
Bridge and broker connected but mTLS fails Mismatched info hash or certificates Re-run cloudtaser-cli source register to regenerate certificates
Secrets not fetching after relay established OpenBao Kubernetes auth not configured Verify with cloudtaser-cli target validate
High latency on secret fetch Beacon server geographically distant Self-host a beacon closer to both sides, or use reverse-connect mode
cloudtaser-cli target debug shows relay errors Beacon connection dropping Check network stability; create a DebugReport CR for diagnostics