5.8 KiB
Deployment and Permissions
Socket location and permissions
- The agent binds a unix socket at the path given by
--sockorYANPM_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 tosock_gid
- create the parent directory (best-effort) and attempt to set its permissions to
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_gidso clients can access the socket. - The repository provides a runtime image built by
apps/agent/Dockerfilewhich packagesnginxtogether with theyanpm-agentbinary 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 -tmay fail due to inability to access/run/nginx.pidor other privileged files. The agent attempts a best-effort sequence:
- Run
nginx -tdirectly. - If that fails with permission errors, try a privileged wrapper (e.g.
/usr/local/sbin/yanpm-nginx-validateoryanpm-nginx-validate-file) viasudo -n. - If wrapper is unavailable or fails, retry
nginx -twith a writable PID override via-g 'pid /tmp/yanpm-validate-<pid>.pid;'.
Security considerations
- Avoid setting
sock_permto allow world access unless explicitly intended. - Prefer controlling socket group membership via
sock_gidrather than making the socket world-writable.
s6 init scripts, wrappers and sudoers (runtime)
-
Purpose: The image built by
apps/agent/Dockerfileusess6-overlayas PID 1 (the Dockerfile setsENTRYPOINT ["/init"]). The repository includesdocker/s6/cont-init.dscripts that run at container startup (one-shot) anddocker/s6/services.dentries 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 theyanpm-agentuser and group exist (honoringYANPM_AGENT_UID,YANPM_AGENT_GID, andYANPM_AGENT_SOCK_GID), adds the user to thenginxgroup, and attempts to chown runtime directories like/var/run/yanpmand/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 theyanpm-agentuser can perform narrowly-scoped privileged operations without a password.
-
Wrapper scripts installed by
20-install-reload-wrapper:/usr/local/sbin/yanpm-nginx-reload— runsnginx -c /etc/nginx/nginx.conf -s reload(used for reloading the running nginx master process)./usr/local/sbin/yanpm-nginx-validate— runsnginx -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 theyanpm-agentuser, enforces it's not world-writable, then runsnginx -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-agentwith a rule allowing the configured agent user (defaultyanpm-agent) to run only the three wrappers withNOPASSWD. This gives the agent a limited, auditable privilege escalation surface; the agent code attempts to use these wrappers viasudo -nbefore falling back to less privileged strategies.
- The init script writes
-
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, default660).YANPM_AGENT_SOCK_GID— desired GID for the socket (optional).YANPM_AGENT_UID,YANPM_AGENT_GID— runtime UID/GID used to create theyanpm-agentuser in the container.
-
How the agent uses these runtime helpers:
ValidateCommandandReloadCommandin the agent code trynginxoperations directly; when permission problems occur they attempt the privileged wrappers viasudo -n /usr/local/sbin/yanpm-nginx-validateor...-validate-fileand...-reload. The cont-init script's wrappers plus the sudoers entry implement that intended secure upgrade path.
-
Notes and recommendations:
- The
validate-filewrapper performs ownership and permission checks; ensure written fragments are created by theyanpm-agentuser (the agent writes files as that user when running inside the container due to10-create-app-user). - The cont-init scripts attempt to install
sudoif missing; in minimal images you may prefer providingsudoat 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 andYANPM_AGENT_SOCK_GIDso the socket and files are accessible as intended.
- The