rstream-operator manages rstream tunnels from Kubernetes. It lets teams expose a Kubernetes Service through rstream with a small declarative API instead of running tunnel commands manually.
The operator is built with standard controller-runtime/Kubebuilder patterns:
RstreamConnectionstores shared project, engine, and credential settings.RstreamTunneldeclares one managed tunnel to a KubernetesService.- The controller creates a dedicated tunnel-agent
DeploymentperRstreamTunnel. - The tunnel agent owns the data plane and reports tunnel readiness back into
RstreamTunnel.status.
Release images are published on Docker Hub as rstream/rstream-operator.
The API is currently v1alpha1. Treat field names and semantics as production-quality, but not yet immutable.
Install the operator:
helm upgrade --install rstream-operator ./charts/rstream-operator \
--namespace rstream-system \
--create-namespaceCreate an application Service:
kubectl apply -f config/samples/http_server.yamlCreate a Secret containing a rstream token with access to the project:
kubectl -n rstream-demo create secret generic rstream-credentials \
--from-literal=token="$RSTREAM_TOKEN"Create the rstream connection and tunnel:
apiVersion: tunnels.rstream.io/v1alpha1
kind: RstreamConnection
metadata:
name: default
namespace: rstream-demo
spec:
projectEndpoint: "<project-endpoint>"
tokenSecretRef:
name: rstream-credentials
key: token
---
apiVersion: tunnels.rstream.io/v1alpha1
kind: RstreamTunnel
metadata:
name: web
namespace: rstream-demo
spec:
target:
service:
name: http-server
port: http
publish: true
protocol: http
http:
version: http/1.1Check readiness and the public address:
kubectl -n rstream-demo get rstreamtunnel web
kubectl -n rstream-demo describe rstreamtunnel webUse RstreamConnection when multiple tunnels share the same rstream project and credentials:
apiVersion: tunnels.rstream.io/v1alpha1
kind: RstreamConnection
metadata:
name: default
namespace: platform
spec:
projectEndpoint: "<project-endpoint>"
apiURL: https://rstream.io
region: auto
tokenSecretRef:
name: rstream-credentials
key: tokenprojectEndpoint is the preferred hosted rstream path. The operator resolves the current engine address through the Control plane and stores the result in RstreamConnection.status.engine. A Global project uses its global endpoint with region: auto; an explicit authorized region keeps the agent control channel on that regional endpoint.
For self-hosted engines or internal test environments without a Control plane, specify engine directly instead:
apiVersion: tunnels.rstream.io/v1alpha1
kind: RstreamConnection
metadata:
name: default
namespace: platform
spec:
engine: engine.internal.example.com:443
tokenSecretRef:
name: rstream-credentials
key: tokenUse RstreamTunnel to expose a Service:
apiVersion: tunnels.rstream.io/v1alpha1
kind: RstreamTunnel
metadata:
name: web
namespace: platform
spec:
connectionRef:
name: default
target:
service:
name: web
port: http
publish: true
protocol: http
labels:
app: web
http:
version: http/1.1
auth:
token: true
rstream: true
allowCrossRegionRouting: falseallowCrossRegionRouting is a per-tunnel policy. It permits a cross-region payload path when ingress and tunnel owner differ, but same-region traffic remains direct. It applies to every supported protocol.
Published TCP tunnels are also supported for services such as SSH:
spec:
target:
service:
name: ssh-server
port: ssh
protocol: tcp
tcpPort: 10042tcpPort is optional. When present, it must be a port reserved for the project through the rstream CLI or Dashboard. Published TCP does not add downstream encryption; use a secure application protocol or a TLS tunnel.
See docs/002-api-reference.md for the field reference.
The controller does not proxy application traffic. For each RstreamTunnel, it creates:
- a
ConfigMapcontaining non-secret agent configuration; - a dedicated
ServiceAccount,Role, andRoleBinding; - a single-replica
Deploymentrunning/rstream-agent; - a restricted Pod security context and read-only root filesystem.
The agent reads credentials from Kubernetes Secrets at runtime, opens an outbound control channel to the rstream engine, forwards traffic to the target Service, and patches RstreamTunnel.status.
This model keeps traffic isolation simple: restarting or deleting one RstreamTunnel only impacts its own agent Pod.
Helm:
helm upgrade --install rstream-operator ./charts/rstream-operator \
--namespace rstream-system \
--create-namespace \
--set image.repository=rstream/rstream-operator \
--set image.tag=latestKustomize:
make install
make deploy IMAGE=rstream/rstream-operator:latestAGENT_IMAGE defaults to IMAGE for make deploy; set it explicitly only when agents should run a different image.
For local development:
make run AGENT_IMAGE=rstream/rstream-operator:latestkubectl get rstreamtunnel shows readiness, protocol, target, and forwarding address. The CRD also exposes tunnel, rtun, and rtunnel as short aliases for interactive use.
kubectl describe rstreamtunnel <name> shows conditions:
Accepted: theRstreamTunnelspec is valid.Resolved: referenced Service, port, connection, and Secret keys exist.AgentReady: the managed Deployment is available.TunnelReady: the agent has an active rstream tunnel.Ready: aggregate user-facing readiness.
Agent logs are JSON and include tunnel ID, forwarding address, target, and reconnect errors.
Credentials stay in Kubernetes Secrets and are not copied into ConfigMaps.
The managed agent Pod runs non-root, drops Linux capabilities, disables privilege escalation, uses the runtime-default seccomp profile, and has a read-only root filesystem.
The per-tunnel agent Role is limited to:
getits ownRstreamTunnel;get,patch, andupdateits ownRstreamTunnel/status.
The manager needs cluster-wide watch access because RstreamTunnel can target Services in another namespace. If you do not need cross-namespace targets, keep spec.target.service.namespace unset.
The repository keeps tools local under bin/.
make generate
make manifests
make test
make helm-lint
make buildFor local development next to a sibling ../rstream-go checkout, create an uncommitted Go workspace:
go work init . ../rstream-gogo.mod pins the SDK as a normal module dependency so release builds do not depend on local filesystem layout.
Release builds use the public module metadata from go.mod and do not require GitHub SSH credentials. The runtime smoke script automatically uses the sibling ../rstream-go checkout when present, which keeps unreleased SDK changes testable before a module tag is cut. Set RSTREAM_GO_REPO=/path/to/rstream-go when your local SDK checkout lives somewhere else.
With Docker, Kind, kubectl, Helm, and a usable rstream token:
export RSTREAM_PROJECT_ENDPOINT="project-endpoint"
export RSTREAM_TOKEN=...
hack/runtime-smoke.shUse RSTREAM_ENGINE=... instead of RSTREAM_PROJECT_ENDPOINT when testing a self-hosted or internal engine without a Control plane.
The script builds the image, loads it into Kind, installs the chart, creates a demo HTTP Service and RstreamTunnel, waits for Ready, and curls the forwarding address.
More details are in docs/003-runtime-testing.md.