Install the gateway¶
The gateway is a single stateless Go binary, run in the cluster as a Deployment. It is the only part of Axiom that needs cluster credentials, and it needs three things: its RBAC, a TLS keypair, and a way for Postgres to reach it.
A Helm chart is coming
(#116). Until then, the
gateway installs from two manifests in
deploy/k8s/:
gateway-rbac.yaml: theaxiom-systemnamespace, theaxiom-gatewayServiceAccount, and the ClusterRoles that decide what it may read and write.gateway-deployment.yaml: the Deployment and aNodePortService on port30443.
1. A TLS keypair¶
The gateway has no plaintext mode. Its certificate must name the address Postgres will dial, because the extension verifies that name.
GATEWAY_HOST=gateway.example.internal # the name Postgres will dial
mkdir -p certs
docker run --rm -v "$PWD/certs:/certs" -w /certs \
--entrypoint /bin/sh alpine/openssl:3.3.3 -c "
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes \
-days 365 -subj '/CN=axiom-ca' -keyout ca.key -out ca.crt
openssl req -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes \
-subj '/CN=gateway' -keyout gateway.key -out gateway.csr
printf 'subjectAltName=DNS:$GATEWAY_HOST,DNS:axiom-gateway.axiom-system.svc\nextendedKeyUsage=serverAuth\n' > san.cnf
openssl x509 -req -in gateway.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-days 365 -extfile san.cnf -out gateway.crt
rm -f gateway.csr san.cnf ca.srl ca.key
chown $(id -u):$(id -g) ca.crt gateway.crt gateway.key
"
Keep ca.crt: Postgres needs it to trust the gateway. A certificate from your
own CA works the same way, as long as it uses named-curve EC or RSA keys and
SHA-256 signatures.
Generate it in that container on macOS
macOS ships LibreSSL, whose certificates the gateway and extension reject:
EC keys with explicit curve parameters crash-loop the gateway with
x509: invalid ECDSA parameters, and SHA-1 signatures fail the handshake
with UnsupportedSignatureAlgorithmContext.
2. Apply the manifests¶
Use the manifests from the release you are installing, so they match the image:
V=0.2.0
RAW=https://raw.githubusercontent.com/dhilipkumars/axiom/v$V/deploy/k8s
kubectl apply -f "$RAW/gateway-rbac.yaml"
kubectl -n axiom-system create secret generic axiom-gateway-tls \
--from-file=tls.crt=certs/gateway.crt --from-file=tls.key=certs/gateway.key
kubectl apply -f "$RAW/gateway-deployment.yaml"
kubectl -n axiom-system set image deploy/axiom-gateway \
gateway=ghcr.io/dhilipkumars/axiom-gateway:v$V
kubectl -n axiom-system rollout status deploy/axiom-gateway
The manifest names axiom-gateway:latest, which follows releases; the
set image pins the version instead.
Reaching it from Postgres¶
Postgres runs outside the cluster. That is the point of Axiom, and it is why the gateway has to be exposed.
NodePort, as the manifest ships, on port30443. Stable across pod replacement, and it holds the long-lived HTTP/2 streams that watch-backed tables need. Dial a node address Postgres can route to.- A
LoadBalancer, or an ingress with gRPC passthrough, for production. Whatever sits in front must not terminate TLS, because the extension verifies the gateway's own certificate. A proxy that re-encrypts needs its certificate in Postgres'sca_certinstead. - Not
kubectl port-forward, except for a one-off. It drops long-lived streams, which is exactly what a watch-backed table depends on.
Whichever you choose, the address goes in the endpoint option when you
create the server, and must be one
of the names in the certificate. A name missing from the certificate is a
handshake failure, not a warning.
How it runs¶
- No kubeconfig. The Deployment runs on the projected ServiceAccount token, which kubelet rotates. If you find yourself mounting a kubeconfig into the gateway, that replaces a rotating, audience-bound token with a static credential.
strategy: Recreate. With one replica, a rolling update briefly runs two gateways, and requests can reach the one shutting down. A short gap during a restart is the better trade: queries see a connection error, and watch-backed tables keep serving cached rows with aWARNING.- A TCP readiness probe. Kubernetes' built-in gRPC probe dials plaintext, and this server is TLS-only, so it would never pass. The gateway loads its TLS material and builds its Kubernetes client before it listens, so an open port does mean it got that far.
Operating it¶
Restarting is safe at any time, and needed after an RBAC grant is revoked or narrowed: what the gateway is allowed is cached for the life of the process. A new grant needs no restart.
kubectl -n axiom-system rollout restart deploy/axiom-gateway
Watch-backed tables go DEGRADED across a restart, keep serving cached rows
with a WARNING, and resume from their bookmark rather than relisting.
Upgrading: move the gateway first. A newer gateway serves an older extension, because protocol changes are additive.
Logs record each call, with the filters a List received:
kubectl -n axiom-system logs deploy/axiom-gateway --tail=50