feat: add comprehensive documentation for yanpm-agent, including API reference, configuration, deployment, usage examples, and troubleshooting
This commit is contained in:
62
apps/agent/doc/deployment.md
Normal file
62
apps/agent/doc/deployment.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Deployment and Permissions
|
||||
|
||||
Socket location and permissions
|
||||
|
||||
- The agent binds a unix socket at the path given by `--sock` or `YANPM_AGENT_SOCK`. The agent will:
|
||||
- create the parent directory (best-effort) and attempt to set its permissions to `0770`
|
||||
- remove an existing socket file if it is a socket, or fail if the path exists and is not a socket
|
||||
- apply the `sock_perm` (3-digit octal) to the socket file and optionally change its GID to `sock_gid`
|
||||
|
||||
Systemd socket/unit example
|
||||
|
||||
Create a `yanpm-agent.socket` unit that creates and owns the unix socket, and a `yanpm-agent.service` that runs the agent. Ensure the socket path used by systemd matches `--sock`.
|
||||
|
||||
Docker / container notes
|
||||
|
||||
- If running the agent inside a container and writing to host nginx config, bind-mount the host nginx config directory into the container at the path provided to `--nginx-config-dir`.
|
||||
- Consider running the agent as a user with permission to write the nginx config directory or use a shared group and `sock_gid` so clients can access the socket.
|
||||
- The repository provides a runtime image built by `apps/agent/Dockerfile` which packages `nginx` together with the `yanpm-agent` binary and s6-overlay service scripts. This image runs nginx and the agent in one container which is useful when the agent is acting as the runtime companion for the API (`apps/api`).
|
||||
|
||||
Privilege escalation for validation
|
||||
|
||||
- In many systems `nginx -t` may fail due to inability to access `/run/nginx.pid` or other privileged files. The agent attempts a best-effort sequence:
|
||||
|
||||
1. Run `nginx -t` directly.
|
||||
2. If that fails with permission errors, try a privileged wrapper (e.g. `/usr/local/sbin/yanpm-nginx-validate` or `yanpm-nginx-validate-file`) via `sudo -n`.
|
||||
3. If wrapper is unavailable or fails, retry `nginx -t` with a writable PID override via `-g 'pid /tmp/yanpm-validate-<pid>.pid;'`.
|
||||
|
||||
Security considerations
|
||||
|
||||
- Avoid setting `sock_perm` to allow world access unless explicitly intended.
|
||||
- Prefer controlling socket group membership via `sock_gid` rather than making the socket world-writable.
|
||||
|
||||
s6 init scripts, wrappers and sudoers (runtime)
|
||||
|
||||
- Purpose: The image built by `apps/agent/Dockerfile` uses `s6-overlay` as PID 1 (the Dockerfile sets `ENTRYPOINT ["/init"]`). The repository includes `docker/s6/cont-init.d` scripts that run at container startup (one-shot) and `docker/s6/services.d` entries to run long-lived services (nginx and the agent). The cont-init scripts prepare runtime users, permissions, and helper wrappers the agent uses for privileged operations.
|
||||
|
||||
- Key cont-init scripts (in the repo):
|
||||
- `docker/s6/cont-init.d/10-create-app-user` — ensures the `yanpm-agent` user and group exist (honoring `YANPM_AGENT_UID`, `YANPM_AGENT_GID`, and `YANPM_AGENT_SOCK_GID`), adds the user to the `nginx` group, and attempts to chown runtime directories like `/var/run/yanpm` and `/app/yanpm-agent` (logs warnings if chown fails for bind mounts or rootless containers).
|
||||
- `docker/s6/cont-init.d/20-install-reload-wrapper` — installs three helper wrappers and a sudoers entry so the `yanpm-agent` user can perform narrowly-scoped privileged operations without a password.
|
||||
|
||||
- Wrapper scripts installed by `20-install-reload-wrapper`:
|
||||
- `/usr/local/sbin/yanpm-nginx-reload` — runs `nginx -c /etc/nginx/nginx.conf -s reload` (used for reloading the running nginx master process).
|
||||
- `/usr/local/sbin/yanpm-nginx-validate` — runs `nginx -c /etc/nginx/nginx.conf -t` (validates the main nginx config).
|
||||
- `/usr/local/sbin/yanpm-nginx-validate-file` — securely validates a single nginx config file: it resolves the absolute path, ensures the target is a regular file (not a symlink), checks the file is owned by the `yanpm-agent` user, enforces it's not world-writable, then runs `nginx -c <file> -t`. This defends against symlink and race attacks when an unprivileged agent requests privileged validation.
|
||||
|
||||
- Sudoers entry:
|
||||
- The init script writes `/etc/sudoers.d/yanpm-agent` with a rule allowing the configured agent user (default `yanpm-agent`) to run only the three wrappers with `NOPASSWD`. This gives the agent a limited, auditable privilege escalation surface; the agent code attempts to use these wrappers via `sudo -n` before falling back to less privileged strategies.
|
||||
|
||||
- Relevant environment variables (settable in the Dockerfile or at runtime):
|
||||
- `YANPM_AGENT_SOCK` — unix socket path (default set in Dockerfile: `/var/run/yanpm/yanpm-agent.sock`).
|
||||
- `YANPM_NGINX_CONFIG_DIR` — nginx config dir (default `/etc/nginx/conf.d`).
|
||||
- `YANPM_AGENT_SOCK_PERM` — socket permissions (octal string, default `660`).
|
||||
- `YANPM_AGENT_SOCK_GID` — desired GID for the socket (optional).
|
||||
- `YANPM_AGENT_UID`, `YANPM_AGENT_GID` — runtime UID/GID used to create the `yanpm-agent` user in the container.
|
||||
|
||||
- How the agent uses these runtime helpers:
|
||||
- `ValidateCommand` and `ReloadCommand` in the agent code try `nginx` operations directly; when permission problems occur they attempt the privileged wrappers via `sudo -n /usr/local/sbin/yanpm-nginx-validate` or `...-validate-file` and `...-reload`. The cont-init script's wrappers plus the sudoers entry implement that intended secure upgrade path.
|
||||
|
||||
- Notes and recommendations:
|
||||
- The `validate-file` wrapper performs ownership and permission checks; ensure written fragments are created by the `yanpm-agent` user (the agent writes files as that user when running inside the container due to `10-create-app-user`).
|
||||
- The cont-init scripts attempt to install `sudo` if missing; in minimal images you may prefer providing `sudo` at build time to avoid runtime installation attempts.
|
||||
- If you bind-mount host directories (e.g., `/etc/nginx/conf.d`) into the container, ensure ownership and permissions are compatible with the agent user and `YANPM_AGENT_SOCK_GID` so the socket and files are accessible as intended.
|
||||
Reference in New Issue
Block a user