Sienna Meridian Satterwhite 2624a13952 feat(net): TLS support for HTTPS coordination URLs and DERP relays
Production Headscale terminates TLS for both the control plane (via the
TS2021 HTTP CONNECT upgrade endpoint) and the embedded DERP relay.
Without TLS, the daemon could only talk to plain-HTTP test stacks.

- New crate::tls module: shared TlsMode (Verify | InsecureSkipVerify)
  + tls_wrap helper. webpki roots in Verify mode; an explicit
  ServerCertVerifier that accepts any cert in InsecureSkipVerify
  (test-only).
- Cargo.toml: add tokio-rustls, webpki-roots, rustls-pemfile.
- noise/handshake: perform_handshake is now generic over the underlying
  stream and takes an explicit `host_header` argument instead of using
  `peer_addr`. Lets callers pass either a TcpStream or a TLS-wrapped
  stream.
- noise/stream: NoiseStream<S> is generic over the underlying transport
  with `S = TcpStream` as the default. The AsyncRead+AsyncWrite impls
  forward to whatever S provides.
- control/client: ControlClient::connect detects `https://` in
  coordination_url and TLS-wraps the TCP stream before the Noise
  handshake. fetch_server_key now also TLS-wraps when needed. Both
  honor the new derp_tls_insecure config flag (which is misnamed but
  controls all TLS verification, not just DERP).
- derp/client: DerpClient::connect_with_tls accepts a TlsMode and uses
  the shared tls::tls_wrap helper instead of duplicating it. The
  client struct's inner Framed is now generic over a Box<dyn
  DerpTransport> so it can hold either a plain or TLS-wrapped stream.
- daemon/lifecycle: derive the DERP URL scheme from coordination_url
  (https → https) and pass derp_tls_insecure through.
- config.rs: new `derp_tls_insecure: bool` field on VpnConfig.
- src/vpn_cmds.rs: pass `derp_tls_insecure: false` for production.

Two bug fixes found while wiring this up:

- proxy/engine: bridge_connection used to set remote_done on any
  smoltcp recv error, including the transient InvalidState that
  smoltcp returns while a TCP socket is still in SynSent. That meant
  the engine gave up on the connection before the WG handshake even
  finished. Distinguish "not ready yet" (returns Ok(0)) from
  "actually closed" (returns Err) inside tcp_recv, and only mark
  remote_done on the latter.
- proxy/engine: the connection's "done" condition required
  local_read_done, but most clients (curl, kubectl) keep their write
  side open until they read EOF. The engine never closed its local
  TCP, so clients sat in read_to_end forever. Drop the connection as
  soon as the remote side has finished and we've drained its buffer
  to the local socket — the local TcpStream drop closes the socket
  and the client sees EOF.
2026-04-07 15:28:44 +01:00
2026-03-25 18:09:25 +00:00
2026-03-07 14:54:17 +00:00

Sunbeam CLI

Sunbeam CLI is a local development stack manager for Kubernetes-based applications. It simplifies cluster management, service operations, secret handling, and manifest deployment.

License Rust

Quick Start

# Install from source
cargo install --path sunbeam

# Start your local cluster
sunbeam up

# Apply manifests
sunbeam apply

# Check status
sunbeam status

Features

  • Cluster Management: Bring up local Kubernetes clusters with cert-manager, Linkerd, TLS
  • Service Operations: Status, logs, restart, health checks across namespaces
  • Secret Management: OpenBao KV seeding, DB engine config, VSO verification
  • Manifest Management: Kustomize + Helm builds with domain/email substitution
  • User Management: Kratos identity CRUD, onboarding/offboarding with mailbox and project provisioning
  • Image Building: Buildkit-based builds with registry push and rollout deploy
  • Project Management: Unified ticket management across Planka and Gitea
  • Self-Update: Binary update from the latest mainline commit
  • Tool Bundling: kustomize and helm binaries embedded at compile time

Installation

Prerequisites

  • Rust (2024 edition)
  • Docker
  • Lima (for local VM management)
  • A running Kubernetes cluster (kubectl context sunbeam for local dev)

Install from Source

git clone https://src.sunbeam.pt/studio/cli.git
cd cli
cargo install --path sunbeam
sunbeam --help

Self-Update

Once installed, sunbeam can update itself:

sunbeam update

Workspace Layout

cli/
  Cargo.toml                    # [workspace] — sunbeam-sdk + sunbeam
  sunbeam-sdk/                  # Library crate — all logic
    src/
      lib.rs
      error.rs, config.rs, output.rs, constants.rs
      kube/       # client, apply, exec, secrets, kustomize_build, tools
      openbao/    # BaoClient HTTP API
      auth/       # OAuth2 PKCE, token cache
      services/   # status, logs, get, restart
      images/     # build, mirror, per-service builders
      secrets/    # seed, verify, KV seeding, DB engine
      users/      # identity CRUD, provisioning (mailbox, projects, email)
      checks/     # functional health probes, S3 auth
      pm/         # Planka + Gitea ticket management
      cluster/    # cert-manager, Linkerd, TLS
      manifests/  # kustomize apply, namespace filtering
      gitea/      # bootstrap (orgs, repos, OIDC)
      update/     # self-update, version
  sunbeam/                      # Binary crate — thin CLI wrapper
    src/
      main.rs                   # tokio, rustls, tracing init
      cli.rs                    # Clap structs + dispatch

Usage

Basic Commands

sunbeam up                      # Full cluster bring-up
sunbeam status                  # Pod health across all namespaces
sunbeam status ory              # Scoped to namespace
sunbeam apply                   # Build + apply all manifests
sunbeam apply lasuite           # Apply single namespace
sunbeam logs ory/kratos         # Stream logs
sunbeam logs ory/kratos -f      # Follow mode
sunbeam restart                 # Rolling restart all services
sunbeam restart ory/kratos      # Restart specific deployment

Configuration

sunbeam config set --domain sunbeam.pt --host user@server.example.com
sunbeam config get
sunbeam config use-context production

Building and Deploying

sunbeam build proxy             # Build image
sunbeam build proxy --push      # Build + push to registry
sunbeam build proxy --deploy    # Build + push + apply + restart
sunbeam build proxy --no-cache  # Disable buildkit cache
sunbeam mirror                  # Mirror amd64-only images

User Management

sunbeam user list
sunbeam user create user@example.com --name "User Name"
sunbeam user set-password user@example.com
sunbeam user onboard new@example.com --name "New User" --department Engineering
sunbeam user offboard departed@example.com
sunbeam user recover user@example.com

Secret Management

sunbeam seed                    # Generate + store all credentials in OpenBao
sunbeam verify                  # E2E VSO + OpenBao integration test

Project Management

sunbeam pm list                 # List tickets (Planka + Gitea)
sunbeam pm show p:42            # Show Planka card
sunbeam pm show g:studio/cli#7  # Show Gitea issue
sunbeam pm create "Title" --source gitea --target studio/cli
sunbeam pm assign p:42 user@example.com
sunbeam pm close g:studio/cli#7

Health Checks

sunbeam check                   # Run all functional probes
sunbeam check devtools          # Scoped to namespace

Passthrough

sunbeam k8s get pods -A         # kubectl passthrough
sunbeam bao status              # bao CLI inside OpenBao pod

Production

sunbeam config set --domain sunbeam.pt --host user@62.210.145.138
sunbeam config use-context production
sunbeam apply                   # Opens SSH tunnel automatically

Running Tests

cargo nextest run --workspace   # 232 tests
cargo test --workspace          # Alternative

Python CLI (Legacy)

The original Python implementation is in the sunbeam/ package and remains functional:

pip install -e .
python -m sunbeam --help

License

MIT — see LICENSE.

Description
The Sunbeam Studios CLI. It contains tools for Kubernetes, Docker, Lima VM, Cargo, and many other ecosystems. It is designed to be a general-purpose tool for small indie game studios.
https://sunbeam.pt
Readme 131 MiB
2026-03-24 15:29:05 +00:00
Languages
Rust 99.9%
Shell 0.1%