Connect a worker to a Temporal Cloud namespace through the proxy using an API key. The worker and starter carry no
Cloud configuration: they talk plaintext to localhost:7233, and the proxy adds TLS, the API key, and the namespace
rewrite on the way to Cloud.
flowchart LR
client["worker / starter<br/>plaintext gRPC<br/>no TLS, no creds"]
proxy["proxy (local)<br/>gateway :7233"]
cloud["Temporal Cloud<br/>quickstart.<account>.tmprl.cloud:7233"]
client -->|"namespace: quickstart"| proxy
proxy -->|"TLS + Bearer <key><br/>rewrite ns → quickstart.<account>"| cloud
- A Temporal Cloud namespace. Note its fully-qualified name, shown in the Cloud UI as
<namespace>.<account>(for examplequickstart.a1b2c); you split it across two environment variables below. See Namespaces. - An API key, and API key authentication enabled on the namespace (namespaces default to mTLS, so this is a separate step). See API keys.
- Go, and a checkout of this repository (the proxy runs from source).
Set three environment variables. TEMPORAL_NAMESPACE is your namespace's short name and TEMPORAL_ACCOUNT is the
account id after the dot in the fully-qualified name (a namespace quickstart.a1b2c means
TEMPORAL_NAMESPACE=quickstart and TEMPORAL_ACCOUNT=a1b2c):
export TEMPORAL_NAMESPACE=quickstart
export TEMPORAL_ACCOUNT=a1b2c
export TEMPORAL_API_KEY=<your-api-key>Open three terminals in this directory (examples/cloud). The proxy lives in the repository's root module, so its
command changes to the repo root and runs it from source:
cd ../../ && go run ./cmd/proxy serve -c examples/cloud/config.yamlThe proxy logs Running with insecure credentials for the local gateway and its internal sockets. That is expected:
those are local hops. The connection to Temporal Cloud is TLS.
Start the worker:
go run ./workerRun the starter:
go run ./starterThe starter prints:
Hello, Temporal!
The workflow execution is also visible in the Temporal Cloud UI for your namespace.
The worker and starter connected to the proxy on localhost:7233 with no TLS and no credentials, using the short
namespace name quickstart. For each request the proxy:
- terminated the local plaintext connection and dialed Temporal Cloud over TLS;
- attached the API key as an
Authorization: Bearerheader; and - rewrote the namespace from
quickstarttoquickstart.<account>(and back on responses).
config.yaml uses two upstreams, which is the pattern for reaching Temporal Cloud by namespace endpoint:
cloudhandles namespaced requests. ItshostPortis a template ({{ .RemoteNamespace }}.tmprl.cloud:7233) resolved per request from the translated namespace, so one config serves any number of namespaces - point more workers at the proxy with different namespaces and each reaches its own Cloud endpoint, no config change.systemhandles the namespace-less calls the SDK makes (for exampleGetSystemInfoon connect). With no namespace there is nothing to derive a host from, so this upstream uses a fixed endpoint. Any namespace endpoint in the account answers these calls.
Note
With a single namespace both upstreams resolve to the same host; the split is what lets the same config scale to many.
config.yaml ends with a commented-out encryption: block. Uncomment it and restart the proxy to encrypt workflow and
activity payloads on the hop to Cloud: the worker and starter keep exchanging cleartext, the proxy seals payloads before
they leave and opens them on the way back, and Cloud only ever stores ciphertext (workflow inputs and results show as
encrypted bytes in the Cloud UI).
The block uses a testing:// key, which holds its key material in the config itself with no cloud KMS. That is fine for
this toy but never for real data; in production point the key at awskms://, azurekeyvault://, or gcpkms://
instead.