Files
YANPM/apps/agent/doc/deployment.md

5.8 KiB

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.