systemd service unit evaluation differences local RHEL vs production
0 reputation · 26 Oct 2023, 19:31 UTC
0 reputation · 26 Oct 2023, 19:31 UTC
A design review is needed for systemd service units on RHEL 8 and RHEL 9 where the same unit file is intended to run in a local development context and in a production environment. The goal is to clarify which configuration behaviors are deterministic across environments and which are dependent on host policy.
Relevant constraints include systemd service hardening directives, SELinux enforcement levels and contexts, resolution of User=, Group= and WorkingDirectory= directives, availability of environment variables set in shell profiles to the service process, and network namespace isolation in containers or cloud deployments. Behavior is known to vary between RHEL 7, 8 and 9 due to systemd and SELinux updates, and production environments often apply additional security modules or compliance policies not present locally.
Which systemd unit directives are evaluated differently when SELinux is enforcing in production compared with a local setup? Does systemd inherit any environment from interactive shell profiles for a service unit on RHEL 8/9, and under what conditions is WorkingDirectory= resolved relative to the service manager? What determines the SELinux context applied to a service process started by systemd in production?
31775 reputation · 27 Oct 2023, 07:18 UTC
When the same systemd unit file runs on a local RHEL workstation and in a production environment, several directives are evaluated differently depending on SELinux state, name service resolution, and namespace configuration. The following breakdown separates confirmed behaviors from environment-dependent ones.
systemd does not read interactive shell profiles such as ~/.bashrc or /etc/profile when starting a service unit. The service process receives a minimal environment supplied by the system manager, plus any variables explicitly set via Environment=, EnvironmentFile=, or systemctl set-environment. This behavior is deterministic and identical whether the unit runs locally or in production. If a unit relies on profile-defined variables, those must be redeclared in the unit file or exported via EnvironmentFile=.
WorkingDirectory= accepts an absolute path. If a relative path is provided, systemd resolves it relative to the service manager's root directory, effectively / for the system manager, not the user's home directory or the shell's current working directory. This resolution is deterministic across all RHEL 8 and RHEL 9 environments. To avoid unexpected paths, always specify an absolute path in WorkingDirectory=.
User= and Group= are resolved at unit start using the Name Service Switch. In environments where /etc/passwd and /etc/group are the source, resolution is predictable and consistent between local and production. If production uses LDAP or SSSD, and the specified user or group is not reachable, the unit may fail to start or fall back to root, depending on configuration. Local file-based resolution is more predictable; always verify the account exists and is reachable on the target host.
The SELinux context applied to a service process is determined by the policy's type-transition rules: systemd running as init_t executes the configured binary, and the binary's file type e.g., httpd_exec_t transitions the process into its domain e.g., httpd_t. Changing SELinux from permissive to enforcing does not recompute the context; it only determines whether access-vector-denial AVC denials block execution. A unit that starts successfully in permissive mode may fail in enforcing mode if AVC denials compound kernel-enforced hardening directives such as ProtectSystem= or NoNewPrivileges=.
Directives such as ProtectSystem=, PrivateTmp=, NoNewPrivileges=, and RestrictAddressFamilies= are enforced by the kernel and namespaces regardless of SELinux mode. In enforcing mode, SELinux denials can add additional restrictions, so a unit that works locally in permissive mode may encounter failures in production enforcing mode. Always test units under the same SELinux enforcement level as the target deployment.
RHEL 8 and RHEL 9 ship systemd versions 239 and 252 respectively; behavior of newer directives may differ on RHEL 7 systemd 219. Units tested under permissive SELinux locally can fail silently in production enforcing mode; always check ausearch/audit logs for AVC denials after deployment.
# Show evaluated properties of a unit
systemctl show myunit.service -p Environment -p WorkingDirectory -p User -p SELinuxContext
# Check SELinux mode and recent AVC denials
getenforce
sestatus
ausearch -m avc -ts recent
# Confirm the binary's label and running process context
ls -Z /usr/bin/mybinary
ps -eZ | grep myunit
# Catch directive errors before deployment
systemd-analyze verify myunit.service
If production starts fail with AVC denials, run ausearch -m avc -ts recent on the production host and review the unit file and binary path to determine whether a policy modification or a change to hardening directives is needed.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.