Skip to content

feat(satellite): run the snapshot stream over mutual TLS - #219

Open
Andrei Kvapil (kvaps) wants to merge 1 commit into
fix/csi-clone-and-restore-idempotencyfrom
feat/satellite-stream-mtls
Open

Andrei Kvapil (kvaps) wants to merge 1 commit into
fix/csi-clone-and-restore-idempotencyfrom
feat/satellite-stream-mtls

Conversation

@kvaps

@kvaps Andrei Kvapil (kvaps) commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

The satellite served GET /v1/satellite/snapshots/... on every node address with no authentication, and the answer is the raw send stream of a snapshot. Any pod that could reach a node IP could read any volume with a snapshot on that node; in Cozystack, platform pods without an egress policy could.

The stream now runs over HTTPS with mutual TLS:

  • Every satellite presents a certificate for the fixed name blockstor-satellite, and each side verifies the other against the stream CA. Satellites dial each other by node address, so the name is fixed rather than an address.
  • The files are read on every handshake, so a rotated certificate is picked up without a restart. A transfer is one handshake for minutes of data, and the connection closes with it.
  • New flags --stream-tls-cert-file, --stream-tls-key-file, --stream-tls-ca-file. With none set the satellite serves and fetches nothing, and cross-node clone and restore fall back to a DRBD initial sync, as they already did when no peer had the snapshot. A partial set refuses to start.
  • The stand issues one certificate for all satellites from a CA of its own rather than blockstor-api-ca. A stream certificate is also a client certificate, and the apiserver accepts any client certificate from its CA, so sharing it would have given every satellite the REST API.

Packaging needs the same: a Certificate, the Secret mounted into the DaemonSet, and the three flags. cozystack/cozystack#2942 picks that up with the pin.

Stacked on #190.

Fixes #208

Testing

  • New tests run a real TLS server: a satellite of the same CA gets through, a client with no certificate, a plain HTTP client, a client certificate from another CA against a server it trusts, and a server certificate for another name are all refused, a rotated server certificate is served without a restart, fetches leave no connection open, and an unconfigured client and server are off. Weakening the server's client-certificate check or re-enabling keep-alives reddens a test.
  • During a rolling upgrade a fetch between an old and a new satellite fails as a connection error rather than "no snapshot here", so the restore retries until the peer is upgraded instead of falling back to a resync.
  • go test ./...: green apart from the known pkg/rest shutdown flake.
  • golangci-lint on the changed lines: clean.
  • Not run on a stand. The stand manifests are updated but I had no stand for this round.

@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2913de02-152d-404b-9696-43aa53caa93a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

The satellite served GET /v1/satellite/snapshots/... on every node
address with no authentication, and the answer is the raw send stream
of a snapshot. Any pod that could reach a node IP could read any volume
with a snapshot on that node; in Cozystack, platform pods without an
egress policy could.

The stream now runs over HTTPS with mutual TLS. Every satellite
presents a certificate for the fixed name blockstor-satellite, signed
by a stream CA, and verifies the peer's against it in both directions.
The files are read on every handshake, so a rotated certificate is
picked up without a restart. A satellite started without the three
--stream-tls-* flags serves and fetches nothing, and cross-node clone
and restore fall back to a DRBD initial sync; a partial set refuses to
start.

The stand issues the certificate from a CA of its own rather than
blockstor-api-ca, since a stream certificate is also a client
certificate and the apiserver accepts any from its CA.

Fixes #208

Assisted-by: LLM
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant