Skip to content
Draft
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
22 changes: 16 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ Let's Encrypt cert against `<eip>.sslip.io`.
| eu-central-1 (Frankfurt) | [Launch stack →](https://console.aws.amazon.com/cloudformation/home?region=eu-central-1#/stacks/quickcreate?stackName=agent-box&templateURL=https%3A%2F%2Fdefang-agent-box.s3.us-west-2.amazonaws.com%2Ftemplate.yaml) |
| eu-west-1 (Ireland) | [Launch stack →](https://console.aws.amazon.com/cloudformation/home?region=eu-west-1#/stacks/quickcreate?stackName=agent-box&templateURL=https%3A%2F%2Fdefang-agent-box.s3.us-west-2.amazonaws.com%2Ftemplate.yaml) |

Choose `Agent` (`claude` or `codex`), set a `WebPassword` (16+ chars from
`[A-Za-z0-9._~-]`), pick an instance size, launch. The stack reports
Choose `Agent` (`claude` or `codex`), set a `WebPassword` (any 16&ndash;64
characters, including password-manager symbols), pick an instance size,
launch. The stack reports
CREATE_COMPLETE only after the box phones home from its first successful
rebuild — a first boot that goes wrong (issue 106 has one way) rolls the
stack back visibly instead of leaving a green stack with a dead URL. The agent runs as the
Expand Down Expand Up @@ -86,6 +87,13 @@ one CAPABILITY_IAM checkbox to the Launch Stack form; opt out with
[aws/README.md](./aws/README.md#root-access-via-ssm-session-manager) for
details.

**Changing the web password.** Open the settings page (the gear icon next to
the terminal), choose **Change password**, and enter the current password plus
the new password twice. The new password follows the launch-time 16&ndash;64
character policy. Saving replaces the root-owned password hash using Caddy's
recommended Argon2id algorithm, reloads Caddy,
and signs out every browser by rotating the authentication-cookie secret.

**Updating the box.** Click "Update box" on the settings page (the gear icon
next to your terminal; the card also shows the running agent-box rev, linked
to its GitHub commit), or ask the agent in its terminal to run
Expand Down Expand Up @@ -330,10 +338,12 @@ arbitrary command execution as the agent user.
- **Tight sudo:** whatever's in `sudoAllowlist` is the entire root-capable
surface. `NOPASSWD` only - no `SETENV`, no blanket sudo, no ALL.
- **Nothing anonymous, brute-force damping (web deployments):** every path
on the vhost — terminal workspace, per-session terminals, settings — sits behind the
login (the CI tests assert the 401s), the password hash is bcrypt via
Caddy, and a fail2ban jail bans IPs that repeatedly fail it (default on,
`web.fail2ban`; it only counts requests that actually carried
on the vhost — terminal workspace, per-session terminals, settings — sits
behind the
login (the CI tests assert the 401s), new password hashes use Caddy's
recommended Argon2id algorithm (legacy bcrypt hashes remain accepted until
the password changes), and a fail2ban jail bans IPs that repeatedly fail it
(default on, `web.fail2ban`; it only counts requests that actually carried
credentials). Discovery isn't assumed to be hard — the ACME cert for
`<ip>.sslip.io` lands in public CT logs minutes after launch — auth is
simply required everywhere.
Expand Down
15 changes: 9 additions & 6 deletions aws/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,17 +149,20 @@ band — the launch page copy leads with this.

`WebPassword` is marked `NoEcho` and is not emitted in stack Outputs. It still
exists as plaintext in the substituted EC2 user-data, and the current
implementation interpolates it into first-boot Nix/systemd material so Caddy can
derive its Basic Auth hash. Treat principals that can read instance user-data or
the instance's local system configuration as inside the web terminal trust
implementation interpolates a reversible base64 projection into first-boot
Nix/systemd material, then decodes it in the activation script so Caddy can
derive its Basic Auth hash. Treat principals that can read instance user-data
or the instance's local system configuration as inside the web terminal trust
boundary.

Caddy does not compare the plaintext password at request time. On first boot an
activation script runs `caddy hash-password` and stores only the bcrypt hash at
activation script runs `caddy hash-password --algorithm argon2id` and stores
only the Argon2id hash at
`/var/lib/agent-box-web/password-hash` (the file the module's
`users.agent.web.passwordHashFile` points at). On every boot
`agent-web-auth-secrets.service` writes that hash (`WEB_PASSWORD_HASH_AGENT`)
plus a random cookie secret (`WEB_COOKIE_SECRET_AGENT`) to
`agent-web-auth-secrets.service` writes that hash and its detected algorithm
(`WEB_PASSWORD_HASH_AGENT` / `WEB_PASSWORD_ALGORITHM_AGENT`) plus a random
cookie secret (`WEB_COOKIE_SECRET_AGENT`) to
`/run/agent-box-web/env` (`0600`), and Caddy reads that environment file. The
cookie secret is generated on the instance and stored separately at
`/var/lib/agent-box-web/cookie-secret-agent` (`0700` parent directory).
Expand Down
32 changes: 22 additions & 10 deletions aws/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -169,17 +169,17 @@ Parameters:
NoEcho: true
MinLength: 16
MaxLength: 64
AllowedPattern: ^[A-Za-z0-9._~-]{16,64}$
AllowedPattern: ^.{16,64}$
Description: >-
Shared secret for the browser terminal. Log in with the UserName chosen
above (default "agent") and this password; Caddy then sets an HttpOnly
Secure cookie so the WebSocket upgrade can authenticate without putting
the secret in the URL. Use 16-64
chars from [A-Za-z0-9._~-]. AWS masks this field with dots after you type
it and never emits it in stack outputs, so save it somewhere before you
launch — there is no way to recover it later. Even Claude Code stacks
that plan to drive the box via Remote Control need this the first time,
to complete `claude login` in the browser terminal.
the secret in the URL. Use any 16-64 characters; password-manager symbols
are supported. AWS masks this field with dots after you type it and never
emits it in stack outputs, so save it somewhere before you launch — there
is no way to recover it later. Even Claude Code stacks that plan to drive
the box via Remote Control need this the first time, to complete `claude
login` in the browser terminal.

AgentsMd:
Type: String
Expand Down Expand Up @@ -605,7 +605,11 @@ Resources:
sha256 = pin.sha256;
};
hostname = "${WebHostname}";
webPassword = "${WebPassword}";
# Fn::Sub receives a base64 projection of WebPassword so every
# password-manager symbol remains inert Nix source. The
# activation script decodes it only into a shell variable and
# pipes it to Caddy over stdin.
webPasswordBase64 = "${WebPasswordBase64}";
in {
imports = [
"${!modulesPath}/virtualisation/amazon-image.nix"
Expand Down Expand Up @@ -667,8 +671,14 @@ Resources:
if [ ! -s /var/lib/agent-box-web/password-hash ]; then
(
umask 077
${!pkgs.caddy}/bin/caddy hash-password --plaintext ${!lib.escapeShellArg webPassword} \
> /var/lib/agent-box-web/password-hash
webPassword="$(
${!pkgs.coreutils}/bin/printf '%s' ${!lib.escapeShellArg webPasswordBase64} \
| ${!pkgs.coreutils}/bin/base64 --decode
)"
${!pkgs.coreutils}/bin/printf '%s\n' "$webPassword" \
| ${!pkgs.caddy}/bin/caddy hash-password --algorithm argon2id \
> /var/lib/agent-box-web/password-hash
unset webPassword
)
chmod 0600 /var/lib/agent-box-web/password-hash
fi
Expand Down Expand Up @@ -701,6 +711,8 @@ Resources:
- IpDashed: !Join
- '-'
- !Split [':', !GetAtt NetworkInterface.PrimaryIpv6Address]
WebPasswordBase64:
Fn::Base64: !Ref WebPassword
StackName: !Ref AWS::StackName
# First-boot health signal (issue 106): tell CloudFormation the
# user-data config actually APPLIED. This unit only exists once
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/settings-change-password.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading