Skip to content

cmd/tail-watch: add the tls: certificate expiry check - #12

Open
rshade wants to merge 1 commit into
mainfrom
add-tls-expiry-check
Open

rshade wants to merge 1 commit into
mainfrom
add-tls-expiry-check

Conversation

@rshade

@rshade rshade commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator

A tls:<port> check dials the target through netEnv, completes a TLS handshake and fails when the leaf certificate expires within 7 days or is not yet valid. Nothing was watching certificate expiry before, and tls: was rejected at load time.

The verified name is the DNS name of the peer that owns the address, taken from the live peer view and then the status cache, so a Tailscale IP, a short name and a full *.ts.net name all verify against the certificate Tailscale issued. A subnet route never supplies the name. insecure_tls skips chain and name verification but still enforces the leaf dates, so a self-signed NAS certificate can be watched. The check does not fetch a CRL or OCSP response.

An expiry or name failure classifies as service without an ICMP probe, the same as a TCP refusal or an HTTP status mismatch. The window is fixed at 7 days; a per-check window is a new ROADMAP item.

The monitor UI gains a TLS certificate row. bindChecks now goes through a checkBinder interface, the DNS lookup helpers moved to peerdns.go, and the main specs and CHANGELOG are updated. The add-tls-expiry-check OpenSpec change is archived.

Tested with go test ./..., golangci-lint, govulncheck and the Playwright monitor UI tests. Not run against a real tailnet.

A `tls:<port>` check dials the target through netEnv, completes a TLS
handshake and fails when the leaf certificate expires within 7 days or
is not yet valid. Nothing was watching certificate expiry before, and
`tls:` was rejected at load time.

The verified name is the DNS name of the peer that owns the address,
taken from the live peer view and then the status cache, so a Tailscale
IP, a short name and a full `*.ts.net` name all verify against the
certificate Tailscale issued. A subnet route never supplies the name.
`insecure_tls` skips chain and name verification but still enforces the
leaf dates, so a self-signed NAS certificate can be watched. The check
does not fetch a CRL or OCSP response.

An expiry or name failure classifies as `service` without an ICMP
probe, the same as a TCP refusal or an HTTP status mismatch. The window
is fixed at 7 days; a per-check window is a new ROADMAP item.

The monitor UI gains a TLS certificate row. `bindChecks` now goes
through a `checkBinder` interface, the DNS lookup helpers moved to
peerdns.go, and the main specs and CHANGELOG are updated. The
add-tls-expiry-check OpenSpec change is archived.

Tested with go test ./..., golangci-lint, govulncheck and the
Playwright monitor UI tests. Not run against a real tailnet.

Signed-off-by: Richard Shade <rshade@tailscale.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.

2 participants