Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ both Python CLIs report it with `--version`.
downloads. When [GitHub CLI](https://cli.github.com/) `gh` (>= 2.93.0) is present, the
installer runs `gh attestation verify` on the downloaded release tarball after the
`SHA256SUMS` checksum, narrowed to this repo's `.github/workflows/release.yml` on the
exact `refs/tags/<tag>` at `github.com`. A missing, older, or unrecognized `gh` degrades
to checksum-only and never fails for that reason (the token-leak GHSA-8xvp-7hj6-mcj9 and
exact `refs/tags/<tag>` at `github.com`. A missing, older, unrecognized, or
unauthenticated `gh` degrades to checksum-only and never fails for that reason
(`gh attestation verify` requires a github.com credential even for public repos and
exits with gh's documented authentication code 4; the token-leak GHSA-8xvp-7hj6-mcj9 and
false-pass GHSA-fgw4-v983-mgp8 advisories are avoided by requiring 2.93.0); an attestation
a usable `gh` actively rejects is fatal. `TAILSCALE_AI_EGRESS_SKIP_ATTESTATION=1` opts out
an authenticated `gh` actively rejects is fatal. `TAILSCALE_AI_EGRESS_SKIP_ATTESTATION=1` opts out
(offline installs or a non-GitHub mirror) — the checksum still runs, publisher provenance
does not. The release workflow already produces these attestations, so no `release.yml`
change was needed; the unverified `TAILSCALE_AI_EGRESS_BRANCH` path is unaffected.
Expand Down
5 changes: 4 additions & 1 deletion PRIVACY.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ directory.
| Tailscale control plane (e.g. `login.tailscale.com`, `controlplane.tailscale.com`, DERP relays) | `tailscale up` registers the node and joins your tailnet | Always |
| GitHub release downloads (`github.com/.../releases/download/...`, often redirected to GitHub's release asset storage) | Downloads the tagged source artifact and `SHA256SUMS` | Only if you run `install.sh` outside a checkout without `TAILSCALE_AI_EGRESS_BRANCH` |
| GitHub branch archive (`codeload.github.com` via `install.sh`) | Downloads an unverified development branch tarball | Only if you run `install.sh` outside a checkout with `TAILSCALE_AI_EGRESS_BRANCH` |
| GitHub Attestations API (`api.github.com`) and TUF trust-root hosts (`tuf-repo.github.com`, `tuf-repo-cdn.sigstore.dev`, `tmaproduction.blob.core.windows.net`) | `gh attestation verify` fetches the release's build-provenance attestation and the Sigstore/TUF trust roots that validate it | Only on a release install when `gh` >= 2.93.0 is present and `TAILSCALE_AI_EGRESS_SKIP_ATTESTATION=1` is not set. An unauthenticated `gh` may still contact the API before the installer degrades to checksum-only; full verification needs an authenticated `gh` |
| `https://ifconfig.co/country-iso` | Detect the VPS country code for the derived connector identity | Only in non-dry-run `bootstrap.sh` when `REGION` is unset and `curl` or `wget` is available |
| `https://ifconfig.co` | The post-install `diagnose.sh` run (see below) | At the end of a non-dry-run bootstrap |
| `https://api.tailscale.com` | Advanced Mode policy automation (see below) | Only if you explicitly opt into Advanced Mode |

`install.sh` is a thin wrapper. By default it verifies downloaded release
artifacts against `SHA256SUMS`; branch archives are intentionally called out as
unverified. For stricter provenance, clone a reviewed tag and run
unverified. When it invokes `gh` for the optional attestation verification, it
sets `GH_TELEMETRY=false` and `GH_NO_UPDATE_NOTIFIER=1` on every call, so gh
sends no telemetry and performs no update check on this project's behalf. For stricter provenance, clone a reviewed tag and run
`./bootstrap.sh` directly instead of piping `install.sh` from the network. See
[docs/Stability.md](docs/Stability.md).

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ See [SECURITY.md](SECURITY.md) for the full security model. Highlights:

- Auth keys and API tokens are read from environment variables or hidden terminal input and are never written to repo files or logs. Use `tskey-api-...` only for Admin Console policy updates and `tskey-auth-...` only for registering the VPS node.
- `tailscale up` uses `--auth-key=file:...` so keys never appear in shell history. Non-interactive runs must set `TAILSCALE_AUTHKEY`, or the installer exits instead of waiting for browser login.
- `install.sh` verifies downloaded release artifacts against the release `SHA256SUMS` by default. When [GitHub CLI](https://cli.github.com/) `gh` (>= 2.93.0) is present it additionally verifies the release tarball's **build provenance attestation**, narrowed to this repo's release workflow on the exact tag; a missing, older, or unrecognized `gh` degrades to checksum-only (never failing), while an attestation that a usable `gh` actively rejects is fatal. Set `TAILSCALE_AI_EGRESS_SKIP_ATTESTATION=1` to opt out (e.g. offline installs or a non-GitHub mirror) — the checksum still runs, but publisher provenance is no longer verified. `bootstrap.sh` will not pass `tailscale up --reset` on a fresh node without asking first.
- `install.sh` verifies downloaded release artifacts against the release `SHA256SUMS` by default. When [GitHub CLI](https://cli.github.com/) `gh` (>= 2.93.0) is present it additionally verifies the release tarball's **build provenance attestation**, narrowed to this repo's release workflow on the exact tag; a missing, older, unrecognized, or unauthenticated `gh` degrades to checksum-only (never failing — `gh attestation verify` needs `gh auth login`/`GH_TOKEN` even for public repos), while an attestation that an authenticated `gh` actively rejects is fatal. Set `TAILSCALE_AI_EGRESS_SKIP_ATTESTATION=1` to opt out (e.g. offline installs or a non-GitHub mirror) — the checksum still runs, but publisher provenance is no longer verified. `bootstrap.sh` will not pass `tailscale up --reset` on a fresh node without asking first.
- Advanced Mode writes an auditable plan (with the original `current.hujson` and SHA-256 checks) before applying, and `apply-plan` uses the planning `ETag` with `If-Match` to detect concurrent edits instead of overwriting them silently.
- The generated policy grants `autogroup:member` access to `autogroup:internet` and auto-approves `0.0.0.0/0` and `::/0` for the connector tag — required for broad app-connector egress, but it widens a restrictive tailnet policy, so protect ownership of `tag:ai-egress-*`.
- Manual mode needs no Tailscale API credential. This project collects no telemetry and sends no logs to project-owned servers.
Expand Down
2 changes: 1 addition & 1 deletion README.zh-HK.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ AI_EGRESS_DOMAINS_FILE=/path/to/domains.txt

- Auth keys 和 API tokens 只從 environment variables 或 hidden terminal input 讀取,不會寫入 repo files 或 logs。`tskey-api-...` 只用於 Admin Console policy 更新,`tskey-auth-...` 只用於註冊 VPS node。
- `tailscale up` 使用 `--auth-key=file:...`,避免 key 出現在 shell history。非互動執行必須設定 `TAILSCALE_AUTHKEY`,否則 installer 會退出而不會一直等 browser login。
- `install.sh` 預設會用 release 的 `SHA256SUMS` 驗證下載的 artifact。若系統有 [GitHub CLI](https://cli.github.com/) `gh`(>= 2.93.0),還會額外驗證 release tarball 的 **build provenance attestation**,並收窄到本 repo 的 release workflow 及該 exact tag;`gh` 缺失、過舊或版本無法辨識會退回只做 checksum(不會失敗),但當一個可用的 `gh` 主動拒絕 attestation 時則屬 fatal。設 `TAILSCALE_AI_EGRESS_SKIP_ATTESTATION=1` 可以退出此驗證(例如離線安裝或非 GitHub mirror)——checksum 仍會執行,但不再驗證 publisher provenance。`bootstrap.sh` 在 fresh node 上不會未經詢問就傳入 `tailscale up --reset`。
- `install.sh` 預設會用 release 的 `SHA256SUMS` 驗證下載的 artifact。若系統有 [GitHub CLI](https://cli.github.com/) `gh`(>= 2.93.0),還會額外驗證 release tarball 的 **build provenance attestation**,並收窄到本 repo 的 release workflow 及該 exact tag;`gh` 缺失、過舊、版本無法辨識或未登入(`gh attestation verify` 即使對 public repo 也需要 `gh auth login`/`GH_TOKEN`)會退回只做 checksum(不會失敗),但當一個已驗證身分的 `gh` 主動拒絕 attestation 時則屬 fatal。設 `TAILSCALE_AI_EGRESS_SKIP_ATTESTATION=1` 可以退出此驗證(例如離線安裝或非 GitHub mirror)——checksum 仍會執行,但不再驗證 publisher provenance。`bootstrap.sh` 在 fresh node 上不會未經詢問就傳入 `tailscale up --reset`。
- Advanced Mode 在套用前會寫入可審核 plan(包含原始 `current.hujson` 和 SHA-256 checks),`apply-plan` 會用 planning 時的 `ETag` 搭配 `If-Match`,偵測之後發生的 policy 變更而不是靜默覆寫。
- 產生的 policy 會 grant `autogroup:member` → `autogroup:internet`,並為 connector tag auto-approve `0.0.0.0/0` 和 `::/0`——這是 broad app-connector egress 所需,但會擴大 restrictive policy,請小心保護 `tag:ai-egress-*` ownership。
- Manual mode 不需要任何 Tailscale API credential。本專案不收集 telemetry,也不會把 logs 傳到 project-owned servers。
Expand Down
14 changes: 9 additions & 5 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,20 @@ window for a fix before any public write-up.
- Does not proxy traffic through servers owned by this project.
- Does not store API keys or auth keys in repo files.
- Does not communicate with external services beyond package repositories,
Tailscale services, public IP/DNS checks, and the Tailscale API when you
explicitly opt into Advanced Mode. See [PRIVACY.md](PRIVACY.md) for the exact
list of endpoints.
Tailscale services, public IP/DNS checks, GitHub's release-download /
branch-archive and attestation (API + TUF) endpoints used by `install.sh`
downloads and its optional release verification (branch archives are
downloaded unverified), and the Tailscale API when you explicitly opt into
Advanced Mode. See [PRIVACY.md](PRIVACY.md) for the exact list of endpoints.

## No Telemetry, No Project Servers

There is no analytics, phone-home, crash reporting, or update check. The project
operates no servers. Every network call is either to your own infrastructure,
your OS package mirrors, Tailscale's own services, or well-known public IP/ASN
lookups used by diagnostics. The full inventory is in [PRIVACY.md](PRIVACY.md).
your OS package mirrors, Tailscale's own services, GitHub's release-download /
branch-archive / attestation (API + TUF) endpoints used by `install.sh`, or
well-known public IP/ASN lookups used by diagnostics. The full inventory is in
[PRIVACY.md](PRIVACY.md).

## Secret Handling

Expand Down
16 changes: 11 additions & 5 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,21 @@ TAILSCALE_AI_EGRESS_SKIP_ATTESTATION=1 # skip gh provenance verification (see be
against the release `SHA256SUMS`. If [GitHub CLI](https://cli.github.com/) `gh`
(>= 2.93.0) is on `PATH`, it then runs `gh attestation verify` on the tarball,
narrowed to the repo's `.github/workflows/release.yml` on `refs/tags/<tag>` at
`github.com`. This needs network access and a `gh` new enough to be free of the
token-leak (GHSA-8xvp-7hj6-mcj9) and false-pass (GHSA-fgw4-v983-mgp8) advisories;
2.93.0 is the first such release.
`github.com`. This needs network access, a `gh` new enough to be free of the
token-leak (GHSA-8xvp-7hj6-mcj9) and false-pass (GHSA-fgw4-v983-mgp8) advisories
(2.93.0 is the first such release), and an **authenticated** `gh` —
`gh attestation verify` requires a github.com credential (`gh auth login` or
`GH_TOKEN`) even for public repositories.

- `gh` absent, older than 2.93.0, or reporting an unrecognized version → the
installer prints a note and proceeds on the checksum alone (never fails for
this reason). The vulnerable command is never invoked.
- `gh` present and usable but the attestation is rejected → the install aborts,
matching the checksum's fail-closed posture.
- `gh` new enough but **not authenticated** (gh's documented "requires
authentication" exit code 4) → the installer prints a note and proceeds on the
checksum alone. Run `gh auth login` (or set `GH_TOKEN`) to enable provenance
verification.
- `gh` present, usable, and authenticated but the verification fails → the
install aborts, matching the checksum's fail-closed posture.
- **`TAILSCALE_AI_EGRESS_SKIP_ATTESTATION=1`** skips attestation entirely, even
when a usable `gh` is present. Use it for offline installs or a non-GitHub
mirror. The `SHA256SUMS` checksum still runs, but **publisher provenance is no
Expand Down
2 changes: 1 addition & 1 deletion docs/Release-Checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ runs:
- [ ] Verify the release has the three artifacts plus `SHA256SUMS`.
- [ ] Verify the release notes match the changelog section.
- [ ] Download an artifact and re-check its checksum against `SHA256SUMS`.
- [ ] With `gh` (>= 2.93.0), confirm the attestation `install.sh` relies on
- [ ] With an authenticated `gh` (>= 2.93.0; `gh auth login`), confirm the attestation `install.sh` relies on
verifies for the real `tar.gz` asset — the same check the installer runs:

```bash
Expand Down
34 changes: 17 additions & 17 deletions docs/Roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,43 +22,43 @@ Every item below is tagged so the compatibility impact is explicit up front.

Highest user value first.

- **Custom connector-tag detection in `diagnose.sh`.** `1.x additive-safe`.
Today diagnostics assume the `tag:ai-egress-*` convention. Prefer the tag from
`generated/connector-identity.env`, then a `--connector-tag` flag, then fall
back to the convention.
- **Custom connector-tag detection in `diagnose.sh`.** `1.x additive-safe`. (**done**)
Diagnostics no longer assume the `tag:ai-egress-*` convention; detection
precedence is the `--connector-tag` flag, then the `CONNECTOR_TAG` environment
variable, then `generated/connector-identity.env`, then the convention.
*Acceptance:* diagnose works against a non-`ai-egress-*` tag with no regression
to the default path; covered by fake-command tests.
- **`FAILOVER_NOTIFY_CMD` hook.** `1.x additive-safe`.
- **`FAILOVER_NOTIFY_CMD` hook.** `1.x additive-safe`. (**done**)
Opt-in command run on switch success/failure, with `role` / `label` / `reason`
passed via the environment. No telemetry, no server — just a user command.
*Acceptance:* fires on switch with the documented environment; absence is a
no-op; a failing hook never changes the switch outcome.
- **macOS CI job.** `1.x additive-safe`, high maintainer value — **land early.**
- **macOS CI job.** `1.x additive-safe`, high maintainer value — **land early.** (**done**)
A `macos-*` runner running `bash -n`, the smoke test, and a shell-test subset
to cover Bash 3.2 + BSD userland (`stat -f`, `route -n get`) that only
fake-command tests exercise today. This protects the shared-shell-library
fake-command tests exercised before this job. This protects the shared-shell-library
migration (see design docs) as real shell code starts moving.
*Acceptance:* a green macOS job on the matrix; catches a BSD-only regression.
- **Broad-wildcard blocklist + warn list.** `1.x additive-safe`.
- **Broad-wildcard blocklist + warn list.** `1.x additive-safe`. (**done**)
Keep the fail-list, add a warn-list for CDN/infra wildcards
(`cloudfront.net`, `amazonaws.com`, `googleusercontent.com`, `azureedge.net`,
`akamaihd.net`, `fastly.net`, …) that warn rather than block.
*Acceptance:* warned domains validate with a warning; blocked ones still fail;
tests for both.
- **IPv6 route check in `check-client-routes.sh`.** `1.x additive-safe`.
- **IPv6 route check in `check-client-routes.sh`.** `1.x additive-safe`. (**done**)
Add AAAA + `ip -6 route get` as a new check id; JSON schema only gains fields.
*Acceptance:* new check id present; existing `schema_version: 1` consumers
unaffected.
- **`install.sh` optional attestation verify.** `1.x additive-safe`.
- **`install.sh` optional attestation verify.** `1.x additive-safe`. (**done**)
When `gh` is present, run `gh attestation verify` on the downloaded release,
using the attestation the release workflow already produces.
*Acceptance:* verify runs when `gh` exists; absence degrades gracefully.
- **OpenRC service example.** `1.x additive-safe`.
`docs/examples/` currently has systemd/launchd/cron; bootstrap supports Alpine,
so add an OpenRC unit.
- **OpenRC service example.** `1.x additive-safe`. (**done**)
`docs/examples/` previously had only systemd/launchd/cron; bootstrap supports
Alpine, so OpenRC init scripts now ship alongside them.
*Acceptance:* an OpenRC service file under `docs/examples/` that starts the
controller/monitor on Alpine, referenced from the examples README.
- **Remove deprecated `policy_tool.py apply`.** `1.x allowed exception`.
- **Remove deprecated `policy_tool.py apply`.** `1.x allowed exception`. (**done**)
[Stability](Stability.md) already flags it for removal; the CLI has printed a
"deprecated; will be removed after one release" warning since v1.0, and v1.1.0
has shipped. Use `plan` + `apply-plan`.
Expand Down Expand Up @@ -147,8 +147,8 @@ Per [Stability](Stability.md), to keep the trust boundary small:

## Process (any time)

- **Dependabot** for the SHA-pinned GitHub Actions.
- **Dependabot** for the SHA-pinned GitHub Actions. (**done**)
- **Coverage ratchet** — the CI floor is now 70% (ratcheted up from 55%), focused
on `policy_tool` API error branches.
on `policy_tool` API error branches. (**done**)
- **Bilingual doc drift check** in CI comparing the entrypoint lists in
`README.md` and `README.zh-HK.md`.
`README.md` and `README.zh-HK.md`. (**done**)
2 changes: 1 addition & 1 deletion docs/Stability.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ the tagged release artifact for `VERSION` (or `TAILSCALE_AI_EGRESS_VERSION`) and
verifies it against that release's `SHA256SUMS` before running `bootstrap.sh`.
When `gh` (>= 2.93.0) is present it also verifies the tarball's build-provenance
attestation against the release workflow on the exact tag; a missing/older/
unrecognized `gh` degrades to checksum-only, and `TAILSCALE_AI_EGRESS_SKIP_ATTESTATION=1`
unrecognized/unauthenticated `gh` degrades to checksum-only, and `TAILSCALE_AI_EGRESS_SKIP_ATTESTATION=1`
opts out (see [Configuration.md](Configuration.md#remote-installer-installsh)).
Setting `TAILSCALE_AI_EGRESS_BRANCH` switches to a development branch archive
and prints an unverified-download warning.
Expand Down
Loading