diff --git a/AGENTS.md b/AGENTS.md index c8425bc..6007bd2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,16 +6,20 @@ file, then load [`skills/claude-egress-guard/SKILL.md`](skills/claude-egress-gua ## What this repository is -A deployment skill plus an installer for a fail-closed egress gate in front of -Claude Code. It is not a proxy and not a VPN: it makes the `claude` binary refuse -to start unless traffic leaves through one verified exit. +A one-stop deployment and operation skill for Claude Code on Linux: host +preflight, fail-closed egress gate, safe-operation baseline and incident drills. +It is not a proxy and not a VPN: it makes the `claude` binary refuse to start +unless traffic leaves through one verified exit, then covers what keeps that true +over time. ## Read order 1. `skills/claude-egress-guard/SKILL.md` — the contract (facts, tiers, guardrails). -2. `skills/claude-egress-guard/references/agent-playbook.md` — commands and decision points. -3. `skills/claude-egress-guard/references/troubleshooting.md` — when a check fails. -4. `SECURITY.md` — threat model, known limitations, what is out of scope. +2. `skills/claude-egress-guard/references/zero-to-deployed.md` — phase-by-phase for a fresh host. +3. `skills/claude-egress-guard/references/safe-operation.md` — credentials, settings, secrets, monitoring, incident response. +4. `skills/claude-egress-guard/references/agent-playbook.md` — commands and decision points. +5. `skills/claude-egress-guard/references/troubleshooting.md` — when a check fails. +6. `SECURITY.md` — threat model, known limitations, what is out of scope. ## Operating contract diff --git a/CHANGELOG.md b/CHANGELOG.md index 07a2d5b..ffd45d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project are documented here. The format follows Keep a Changelog; versions use semantic versioning. +## [1.3.0] - 2026-10-27 + +### Changed + +- Repositioned from "an egress gate" to a one-stop Claude Code deployment and + operation skill. The binary gate stays the enforcement core; the skill now names + four parts explicitly — deploy, egress, operate, respond — in `SKILL.md`, both + READMEs, `AGENTS.md` and `llms.txt`. + +### Added + +- `references/safe-operation.md`: credential handling, client settings (no proxy + in `settings.json`, keep permission prompts, review hooks and MCP servers, + one installation), secrets in the working tree, working-directory blast radius, + monitoring, incident response for exit changes / verification requests / leaked + credentials / suspected bypass, and update discipline. + ## [1.2.0] - 2026-10-27 ### Added diff --git a/README.md b/README.md index 0a4f0d2..15ce794 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,8 @@ [![ci](https://github.com/yinyues2/claude-egress-guard/actions/workflows/ci.yml/badge.svg)](https://github.com/yinyues2/claude-egress-guard/actions/workflows/ci.yml) -**A deployment skill for agents, plus a one-command installer for humans, that -pins Claude Code on a Linux host to one egress and refuses to start when that -path is unavailable.** +**A one-stop skill and installer for running Claude Code safely on a Linux host: +from a bare machine to a gated client, then keeping it that way.** Claude Code on a VPS is easy to install and easy to leak. A shell alias or a `claude()` function only covers interactive shells: Python, `sh -c`, cron, @@ -12,10 +11,20 @@ systemd units and anything calling `/usr/bin/claude` walk straight past it, and proxy that dies mid-session silently turns into a direct connection from the datacenter IP. -This project closes that gap at the binary level: the `claude` command itself -becomes a gate that verifies the proxy's real exit address, injects the proxy -environment, and optionally jails the whole process tree with a kernel IP allow -list. Anything unexpected refuses to start. There is no fallback. +So the project is organized in four parts, with one enforcement core: + +| Part | What it covers | Entry point | +| --- | --- | --- | +| **Deploy** | eligibility, host baseline, proxy proven stable, client installed but not launched, first login through the gate | `preflight`, [`zero-to-deployed.md`](skills/claude-egress-guard/references/zero-to-deployed.md) | +| **Egress** | one verified exit, proxy injection, kernel jail for the whole process tree, self-heal after updates, no fallback | `install`, `verify --deep`, `drill`, `set-exit` | +| **Operate** | credentials, client settings, secrets, blast radius, backups, monitoring | [`safe-operation.md`](skills/claude-egress-guard/references/safe-operation.md) | +| **Respond** | exit changed, verification request, leaked credential, suspected bypass | [`safe-operation.md`](skills/claude-egress-guard/references/safe-operation.md) §6 | + +The enforcement core is still the binary gate: `claude` itself verifies the +proxy's real exit address, injects the proxy environment, and optionally jails the +whole process tree with a kernel IP allow list. Anything unexpected refuses to +start; there is no fallback. The other three parts exist so that the gate is +installed in the right order and stays meaningful after the first week. --- diff --git a/README.zh-CN.md b/README.zh-CN.md index a3db42c..9745edd 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,18 +1,27 @@ # claude-egress-guard(中文说明) -**给 agent 用的部署 skill,也是给人用的一键安装脚本:把 Linux 上的 Claude Code -钉死在一个出口上,出口不对就拒绝启动。** - [![ci](https://github.com/yinyues2/claude-egress-guard/actions/workflows/ci.yml/badge.svg)](https://github.com/yinyues2/claude-egress-guard/actions/workflows/ci.yml) +**一站式 skill + 一键安装:在 Linux 上安全地部署和运行 Claude Code——从裸机到可用、 +可审计的客户端,以及出问题时知道怎么处置。** + 在 VPS 上跑 Claude Code,最容易出问题的不是安装,而是**出口泄漏**:写在 `/etc/profile.d` 里的 `claude()` 函数只覆盖交互式 shell,Python、`sh -c`、 cron、systemd 和任何直接调用 `/usr/bin/claude` 的路径都会绕过去;代理中途挂掉时, 客户端还会悄悄从机房 IP 直连出去。 -这个项目在**二进制层**补上这个洞:`claude` 命令本身变成闸门,启动前核验代理的真实 -出口地址,注入代理变量,并可选地把整个进程树关进内核级 IP 白名单。任何异常都拒绝 -启动,没有「继续执行」的分支。 +所以项目分成四块,只有一个是强制核心: + +| 部分 | 覆盖什么 | 入口 | +| --- | --- | --- | +| **部署** | 资格判断、主机基线、代理先稳定、装客户端但不启动、首次登录走闸门 | `preflight`、[`zero-to-deployed.md`](skills/claude-egress-guard/references/zero-to-deployed.md) | +| **出口** | 固定出口、注入代理、内核白名单、更新自愈、失败不回落 | `install`、`verify --deep`、`drill`、`set-exit` | +| **运行** | 凭据、客户端设置、密钥卫生、影响范围、备份、监控 | [`safe-operation.md`](skills/claude-egress-guard/references/safe-operation.md) | +| **处置** | 出口变化、被要求验证、凭据泄漏、怀疑绕过 | [`safe-operation.md`](skills/claude-egress-guard/references/safe-operation.md) §6 | + +强制核心仍然是二进制闸门:`claude` 命令本身核验代理的真实出口地址、注入代理变量, +可选地把整个进程树关进内核级 IP 白名单。任何异常都拒绝启动,没有回落。另外三块存在 +的意义,是让这道闸门**按正确顺序装上**,并且在第一周之后仍然有意义。 --- diff --git a/install.sh b/install.sh index d2b3fa1..89c9ea4 100755 --- a/install.sh +++ b/install.sh @@ -11,7 +11,7 @@ set -u REPO="yinyues2/claude-egress-guard" -PINNED_REF="v1.2.0" +PINNED_REF="v1.3.0" SELF_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd -P) WORK="" diff --git a/llms.txt b/llms.txt index 396e17c..a51a842 100644 --- a/llms.txt +++ b/llms.txt @@ -1,11 +1,13 @@ # claude-egress-guard -> A deployment skill for agents, plus a one-command installer, that pins Claude -> Code on a Linux host to one verified egress and refuses to start otherwise. +> A one-stop skill and installer for running Claude Code safely on a Linux host: +> host preflight, fail-closed egress gate, safe-operation baseline, incident drills. ## Docs - [Skill](https://github.com/yinyues2/claude-egress-guard/blob/main/skills/claude-egress-guard/SKILL.md): deployment contract — four facts, three authorization tiers, install/verify/drill, guardrails +- [Zero to deployed](https://github.com/yinyues2/claude-egress-guard/blob/main/skills/claude-egress-guard/references/zero-to-deployed.md): nine phases from eligibility to maintenance +- [Safe operation](https://github.com/yinyues2/claude-egress-guard/blob/main/skills/claude-egress-guard/references/safe-operation.md): credentials, client settings, secrets, blast radius, monitoring, incident response - [Agent playbook](https://github.com/yinyues2/claude-egress-guard/blob/main/skills/claude-egress-guard/references/agent-playbook.md): step-by-step commands, allow-list rules, evidence record - [Troubleshooting](https://github.com/yinyues2/claude-egress-guard/blob/main/skills/claude-egress-guard/references/troubleshooting.md): symptom → cause → fix - [AGENTS.md](https://github.com/yinyues2/claude-egress-guard/blob/main/AGENTS.md): machine entry point diff --git a/skills/claude-egress-guard/SKILL.md b/skills/claude-egress-guard/SKILL.md index 7879d2e..2fcf635 100644 --- a/skills/claude-egress-guard/SKILL.md +++ b/skills/claude-egress-guard/SKILL.md @@ -1,7 +1,7 @@ --- name: claude-egress-guard -description: "Use when pinning Claude Code to one egress on Linux — installs a fail-closed gate, kernel net jail, and drills it." -version: 1.2.0 +description: "Use when deploying or auditing Claude Code on Linux — one-stop safe setup: preflight, egress gate, operation baseline, incident drills." +version: 1.3.0 author: claude-egress-guard contributors license: Apache-2.0 platforms: [linux] @@ -11,12 +11,24 @@ metadata: category: devops --- -# Claude Egress Guard +# Claude Code: safe deployment and operation -Install a fail-closed egress gate in front of Claude Code on a Linux host: every -invocation must pass an exit-address check, the client and its children get proxy -variables, and (by default) the whole process tree is jailed with a kernel-level -IP allow list. Anything unexpected refuses to start instead of falling back. +A one-stop skill for running Claude Code on a Linux host you control: bring a bare +machine to a working, gated client, keep it inside one verified egress, and know +what to do when something goes wrong. + +Four parts, in the order they matter: + +| Part | What it covers | Where | +| --- | --- | --- | +| **Deploy** | eligibility, host baseline, proxy proven stable, client installed but not launched, first login through the gate | `references/zero-to-deployed.md`, `preflight` | +| **Egress** | one verified exit, proxy injection, kernel jail for the whole process tree, self-heal after updates, no fallback | `install` / `verify --deep` / `drill` / `set-exit` | +| **Operate** | credentials, client settings, secrets, working-directory blast radius, backups, monitoring | `references/safe-operation.md` §1-5 | +| **Respond** | exit change, verification request, leaked credential, suspected bypass | `references/safe-operation.md` §6 | + +The enforcement core is still one binary: `claude` becomes a gate that refuses to +start when the exit is not the one you configured. The rest of the skill exists so +that the gate is installed in the right order, and stays meaningful afterwards. ## When to use @@ -28,6 +40,9 @@ IP allow list. Anything unexpected refuses to start instead of falling back. already polluted. - The operator asks to "lock down", "pin", or "verify" the Claude egress, or to prove it still works after a package update. +- The operator asks whether an existing Claude deployment is *safe* in general: + credentials, client settings, secrets, backups, monitoring, and what to do in + an incident. Audit against `references/safe-operation.md`. - The host is fresh and the operator has never had an account: start with `references/zero-to-deployed.md` instead of improvising an order of operations. @@ -190,4 +205,5 @@ Left: - `references/agent-playbook.md` — full command sequence, allow-list rules, evidence record - `references/zero-to-deployed.md` — phase-by-phase runbook for a fresh host with no account +- `references/safe-operation.md` — credentials, client settings, secrets, blast radius, monitoring, incident response - `references/troubleshooting.md` — symptom → cause → fix table diff --git a/skills/claude-egress-guard/references/safe-operation.md b/skills/claude-egress-guard/references/safe-operation.md new file mode 100644 index 0000000..c08a790 --- /dev/null +++ b/skills/claude-egress-guard/references/safe-operation.md @@ -0,0 +1,129 @@ +# Safe operation baseline + +The gate decides where traffic leaves. This file decides everything else that +makes a Claude Code deployment safe to keep running: credentials, client +settings, secrets, backups, monitoring and what to do when something looks wrong. + +It applies after `references/zero-to-deployed.md` has taken you to a working, +gated host. + +## 1. Credentials + +- `~/.claude/.credentials.json` is a **session**, not a config file. Mode 600, + owned by the account that runs Claude. Never copy it to another machine, never + put it in a backup that leaves the host. +- Re-login is the rotation mechanism. If the file may have leaked: `claude auth + logout`, sign out the other sessions from the provider's account page, log in + again, then check usage for anything you do not recognise. +- Login codes are single use and short lived. Do not paste them into a chat, a + ticket, a log or a shell history. If an orchestrator passes one through stdin, + it must not echo it. +- Never store a provider token in `CLAUDE.md`, `settings.json`, a git remote URL + or a shell profile. + +## 2. Client settings + +The gate owns egress. The client must not have a second opinion: + +- **No proxy in `~/.claude/settings.json`.** A value there can win over the + environment the gate exports, which is the quietest way to send traffic around + the gate. +- **Keep permission prompts on** unless the directory is a throwaway sandbox. + A blanket "allow everything" setting turns every prompt injection into a shell. +- **Review hooks and MCP servers before enabling them.** Both execute code with + your privileges; a hook added for convenience is a startup script with your + keys in scope. +- **One installation.** `npx`, a second global install, or a wrapper that calls + the real binary are ungated paths. Remove them or accept that the gate does not + cover them. + +## 3. Secrets in the working tree + +- Keep API keys in a `.env` with mode 600, or in a secret manager. Not in + `CLAUDE.md`, not in committed examples, not in prompts. +- Add `.env`, `*.pem`, `*.key` and `credentials*` to `.gitignore` before the first + commit, not after the first leak. +- `~/.claude/` and the project's `.claude/` should not be world-readable: + `chmod 700 ~/.claude`, `chmod -R go-rwx .claude` where it exists. +- When you paste logs into an issue, strip addresses, tokens, account identifiers + and full config files. Documentation ranges (`203.0.113.0/24`) exist for this. + +## 4. Working directory and blast radius + +- Run Claude in a dedicated directory, not `/` and not your home root. A + mistaken `rm` or a wide refactor should hit a project, not a system. +- Keep the project under git. Review diffs before accepting bulk edits; a clean + `git diff` is the cheapest safety net there is. +- Do not run unattended, long-lived agents against production credentials. If you + must, give them a scoped token and a directory they cannot escape. +- Snapshot before large changes (`git stash`, a tarball, a provider snapshot). + +## 5. Monitoring + +- `LOG_REFUSALS=1` turns "did it ever refuse?" into `journalctl -t + claude-egress-guard`. Check it weekly; a burst of refusals means the proxy is + unstable, not that the gate is broken. +- After every package update: `claude-egress-guard verify --deep`. The self-heal + is best effort, verification is proof. +- Keep a one-line change log for policy edits (who changed `EXPECTED_IP`, + `ALLOW_IPS` or `STRICT_NET`, and why). Six months later this is the only thing + that explains an incident. +- Record the version you are on. `claude --version`, `claude-egress-guard status`. + +## 6. Incident response + +Match the symptom, then act in order. Stop the bleeding before you investigate. + +### Exit changed or a leak is suspected + +1. Stop new sessions; let running ones finish or kill them deliberately. +2. Confirm the current exit: `claude-egress-guard status`, then a trace through + the proxy. +3. If the proxy moved, `set-exit --ip NEW --country CC`; if it is dead, leave the + gate refusing. A refusing gate is working correctly. +4. Read `journalctl -t claude-egress-guard` for when refusals started. +5. Only then review IP history and decide whether the provider needs to hear + from you. + +### The provider asks for verification, or the session is signed out + +1. Do not retry from a different address. Address hopping during a review is the + worst possible signal. +2. Stop automation that would keep opening sessions. +3. Follow the provider's instructions truthfully, or stop and reassess + eligibility. Never supply documents or numbers that are not yours. +4. Preserve logs and the deployment record; do not delete evidence. + +### A credential may have leaked + +1. `claude auth logout` on the host. +2. Revoke sessions from the provider's account page. +3. Re-login through the gate, then `verify --deep`. +4. Check usage and recent activity for anything you cannot explain. +5. Fix the path it leaked through (git history, a pasted log, a world-readable + file) before moving on. + +### A bypass is suspected + +1. `claude-egress-guard status` — is the gate still installed at both paths? +2. `npx`, a second install, a wrapper, a container: list every way `claude` can + start on that host. +3. For a running process, `cat /proc//cgroup` should show a `run-r...scope` + when `STRICT_NET=1`. If it does not, that process did not come through the + gate. +4. Fix the entry point, then drill again. + +## 7. Update discipline + +| Change | Follow-up | +| --- | --- | +| Claude Code update | `verify --deep`, one real prompt | +| OS upgrade | re-check systemd version, IPv6 setting, DNS resolvers, then `verify --deep` | +| Proxy change | `set-exit`, then `verify` | +| Policy change | record it, then `verify --deep` | +| Host rebuild | follow `zero-to-deployed.md` from phase 1; do not copy credentials | + +## 8. What stays out of scope + +Account registration, payment, identity verification, and anything that would +misrepresent who you are or where you are. Those are the operator's, permanently. diff --git a/skills/claude-egress-guard/scripts/claude-egress-guard b/skills/claude-egress-guard/scripts/claude-egress-guard index 5bf98ca..6604abe 100755 --- a/skills/claude-egress-guard/scripts/claude-egress-guard +++ b/skills/claude-egress-guard/scripts/claude-egress-guard @@ -14,7 +14,7 @@ # Everything it replaces is copied to the backup directory first. set -u -VERSION="1.2.0" +VERSION="1.3.0" MARKER="claude-egress-guard" CONF_REL="/etc/claude-egress-guard.conf"