mirror of
https://github.com/tiennm99/composes.git
synced 2026-10-13 14:15:58 +00:00
feat(paseo): give the paseo user sudo, authenticated with PASEO_PASSWORD
The base image installs no sudo and leaves paseo out of the sudo group, so add both. The password cannot be baked in at build time -- it is a secret and would land in a layer -- and it cannot be set after the base entrypoint, which ends in `exec gosu paseo` and never returns. Wrap that entrypoint instead and set the password while still root, on every start: /etc/shadow lives in the image, not on the /home/paseo volume, so it reverts on each recreate.
This commit is contained in:
1 parent
914474953f
commit
cb1d38f147
4 files changed
+45
-6
No files matched your search
+2
-1
@@ -2,7 +2,8 @@
|
||||
#
|
||||
# cp .env.example .env
|
||||
|
||||
# Password for the daemon API and web UI.
|
||||
# Password for the daemon API and web UI. Doubles as the paseo user's login
|
||||
# password, so it is also what `sudo` asks for inside a terminal.
|
||||
# Generate one with: openssl rand -base64 24
|
||||
PASEO_PASSWORD=
|
||||
|
||||
|
||||
+12
-3
@@ -7,11 +7,13 @@
|
||||
FROM ghcr.io/getpaseo/paseo:latest
|
||||
|
||||
# --- system packages -------------------------------------------------------
|
||||
# Everyday shell tooling. git and curl are already in the base image.
|
||||
# Everyday shell tooling. git and curl are already in the base image; sudo is
|
||||
# not, despite Debian's base-passwd shipping an (empty) sudo group.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
less jq unzip zip lsof psmisc ugrep bfs zsh \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
less jq unzip zip lsof psmisc ugrep bfs zsh sudo \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& usermod -aG sudo paseo
|
||||
|
||||
# --- python ----------------------------------------------------------------
|
||||
# Debian 12 only carries 3.11, so fetch a standalone CPython build with uv
|
||||
@@ -49,3 +51,10 @@ RUN install -d -m 0755 /etc/apt/keyrings \
|
||||
# it is not a Node wrapper. Do not swap it for the `curl | bash` installer,
|
||||
# which writes to $HOME/.local. Last because it changes most often.
|
||||
RUN npm install -g @anthropic-ai/claude-code
|
||||
|
||||
# --- entrypoint ------------------------------------------------------------
|
||||
# Wraps the image's entrypoint to set the paseo user's password while still
|
||||
# root -- see entrypoint.sh. tini stays in front of it, as in the base image.
|
||||
# Last so that editing the script rebuilds only this layer.
|
||||
COPY --chmod=0755 entrypoint.sh /usr/local/bin/paseo-sudo-entrypoint
|
||||
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/paseo-sudo-entrypoint"]
|
||||
+10
-2
@@ -31,7 +31,7 @@ the old entry is cached in `localStorage`.
|
||||
|
||||
| Variable | Purpose |
|
||||
| --- | --- |
|
||||
| `PASEO_PASSWORD` | Web UI and API login. Generate with `openssl rand -base64 24`. |
|
||||
| `PASEO_PASSWORD` | Web UI and API login, and the `paseo` user's `sudo` password. Generate with `openssl rand -base64 24`. |
|
||||
| `PASEO_HOSTNAMES` | Domains allowed to reach the daemon, comma-separated. Your domain must be listed. |
|
||||
| `PASEO_TRUSTED_PROXIES` | Set to `uniquelocal`, or the UI loads but never connects. |
|
||||
| `PASEO_LABEL` | Container hostname. Paseo shows it as the host label in the UI; without it you get a random container ID. |
|
||||
@@ -71,7 +71,7 @@ but anything written outside `$HOME` (`chsh`, `apt install`) is lost on rebuild.
|
||||
| `gh` | GitHub's signed apt repo | Debian does not package it |
|
||||
| Go (`GO_VERSION`) | Official go.dev tarball | Debian 12 ships 1.19 |
|
||||
| Python (`PYTHON_VERSION`) | `uv python install` | Debian 12 ships 3.11 |
|
||||
| `less jq unzip zip lsof psmisc ugrep bfs zsh` | apt | — |
|
||||
| `less jq unzip zip lsof psmisc ugrep bfs zsh sudo` | apt | — |
|
||||
|
||||
Bump a language with a build arg, e.g. `--build-arg GO_VERSION=1.27.1`. Add
|
||||
other agent providers to the `npm install` line:
|
||||
@@ -89,6 +89,14 @@ RUN npm install -g @anthropic-ai/claude-code @openai/codex opencode-ai
|
||||
a notice at startup. Rebuild to update.
|
||||
- The image stays root on purpose: the entrypoint chowns the volumes, then
|
||||
drops to the `paseo` user (uid 1000) with `gosu`.
|
||||
- `sudo` prompts for `PASEO_PASSWORD`. `entrypoint.sh` wraps the image's own
|
||||
entrypoint to set it — it has to run at start, since baking a password into a
|
||||
layer would commit the secret and `/etc/shadow` is not on a volume, so it
|
||||
reverts on every recreate. Leave `PASEO_PASSWORD` empty and the account stays
|
||||
locked, which means no `sudo`.
|
||||
- `sudo` resets `PATH` to its `secure_path`, which does not include
|
||||
`/usr/local/go/bin`. `sudo go ...` therefore fails; use `sudo env PATH="$PATH"
|
||||
go ...` or the full path.
|
||||
- Nothing installs into `$HOME`. That is `/home/paseo`, a volume mount that
|
||||
hides anything baked in at build time — hence `/opt/python` and
|
||||
`/usr/local/go` rather than the defaults.
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
# Sets the paseo user's login password from PASEO_PASSWORD, then hands off to
|
||||
# the image's own entrypoint.
|
||||
#
|
||||
# Has to happen at start, not build: the password is a secret and would
|
||||
# otherwise be baked into a layer. Has to happen here, not in a later hook: the
|
||||
# base entrypoint ends in `exec gosu paseo`, so it never comes back, and by then
|
||||
# we are no longer root and cannot write /etc/shadow. And it has to run every
|
||||
# time -- /etc/shadow sits in the image, not in the /home/paseo volume, so it
|
||||
# reverts on every container recreate.
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "$(id -u)" == "0" && -n "${PASEO_PASSWORD:-}" ]]; then
|
||||
# Piped rather than passed as an argument: arguments are visible in ps.
|
||||
# chpasswd splits on the first colon, so a colon in the password is fine.
|
||||
printf 'paseo:%s\n' "$PASEO_PASSWORD" | chpasswd
|
||||
fi
|
||||
|
||||
# With PASEO_PASSWORD unset the account keeps its locked password and sudo just
|
||||
# refuses. The base entrypoint already warns about the missing variable.
|
||||
exec /usr/local/bin/paseo-docker-entrypoint "$@"
|
||||
Reference in new issue
Block a user