Skip to content

Fix/tailscale sidecar hardening#19

Open
greenarmor wants to merge 14 commits intobettergovph:mainfrom
greenarmor:fix/tailscale-sidecar-hardening
Open

Fix/tailscale sidecar hardening#19
greenarmor wants to merge 14 commits intobettergovph:mainfrom
greenarmor:fix/tailscale-sidecar-hardening

Conversation

@greenarmor
Copy link
Contributor

Summary

This PR updates docker-compose.tailscale.yaml to harden the tailscale sidecar container so it behaves more like a managed network companion instead of a best-effort helper. The changes make startup more reliable, force correct configuration, expose the daemon socket in a predictable way, and continuously publish the node's IPv4 address for govchaind.


Key Changes

1. Enforce valid auth configuration

  • The sidecar now requires a populated TS_AUTHKEY at runtime.
  • If TS_AUTHKEY is empty, the container logs an error and exits instead of silently running in an unauthenticated / unusable state.
if [ -z "$${TS_AUTHKEY:-}" ]; then
  echo 'Error: TS_AUTHKEY is required for the tailscale sidecar.' >&2
  exit 1
fi

This prevents accidental "tailscaled is running but not actually joined to the tailnet" situations.

2. Hostname handling is now deterministic and container-aware

  • Replaced the old hardcoded TS_HOSTNAME=my-node-ts with:
  • TS_HOSTNAME=${TS_HOSTNAME:-} in the Compose env block, and
  • a runtime fallback to tailscale-$(hostname) if the var is still empty.
    This guarantees each container registers in Tailscale with a stable, unique, human-readable name without forcing the operator to manually set one every time.
if [ -z "$${TS_HOSTNAME:-}" ]; then
  TS_HOSTNAME="tailscale-$(hostname)"
fi

3. Stable Tailscale socket exposure

  • Added TAILSCALE_SOCKET=/var/run/tailscale/tailscaled.sock to the environment.
  • tailscaled is now launched with --socket=$${TAILSCALE_SOCKET}.
  • This gives downstream services (like govchaind) a known, explicit socket path for talking to the running daemon.

4. Replaced the previous one-shot sleep infinity command with a managed lifecycle script
The command: for the tailscale service is now an inline shell supervisor that does all of the following:

  • Starts tailscaled in the background and stores its PID.
  • Registers a trap to gracefully:
    • kill the daemon on container exit,
    • clean up temporary IP files.
  • Defines a bring_up() routine that:
    • runs tailscale up --authkey=... --hostname=... --accept-routes
    • retries up to 5 times with a short delay if it fails
    • bails out with an error if we can’t authenticate after multiple attempts.
      This prevents flaky first-boot networking from leaving the container half-configured.

5. Continuous IPv4 publishing to govchaind

  • Instead of writing the Tailscale IPv4 once and going to sleep forever, the script now enters a loop that:
    • checks that the tailscaled daemon PID is still alive,
    • runs tailscale ip -4 | awk 'NR==1' every 30 seconds,
    • atomically updates /var/run/tailscale-ip/ts_ip via a temp file.

This means govchaind always has an up-to-date view of the sidecar's Tailscale IPv4, even if the address changes over time.
If the daemon exits unexpectedly, the script logs an error and terminates the container instead of pretending everything is fine.

Why this matters

  • Reliability: The sidecar now self-heals on startup (retry loop) and fails loudly if it can’t auth.
  • Security & correctness: An empty TS_AUTHKEY is now treated as a hard error, not a “shrug.”
  • Observability: govchaind gets a continuously refreshed ts_ip file rather than a stale snapshot.
  • Operability: Consumers now have a consistent TAILSCALE_SOCKET and predictable hostnames.

Files touched

docker-compose.tailscale.yaml

greenarmor and others added 14 commits October 12, 2025 17:44
…s validator model, and IPFS-powered data registry map onto the DATU reference architecture and detailed the changes needed across consensus, modules, data anchoring, governance, application, and security layers to reach feature parity
…rint a skip message when secrets are absent, and guard the scan and quality gate steps so they only run when both the token and host URL are available.
…ials, skip analysis when secrets are unavailable, and pass both the token and host URL when present to prevent scanner failures.
…plicit mapping and clarified how to add optional local variables without breaking schema validation.
…rk supplies one, so the upstream pipeline keeps using the key in sonar-project.properties.
…r, DisbursementTracker, AccountabilityScores, and GovernanceVoting—with placeholder AppModule definitions to prepare for future Cosmos SDK wiring.

Added baseline genesis structures and key-prefix helpers for each new module so state initialization and store wiring can evolve alongside the DATU roadmap.
…plying a default hostname derived from the container, and wiring the socket path through the environment.

Replaced the one-shot startup with a managed shell script that retries tailscale up, cleans up the daemon on exit, and continually refreshes the shared IPv4 file to keep govchaind informed of address changes.
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