-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrestinpieces.service
More file actions
216 lines (181 loc) · 9.2 KB
/
Copy pathrestinpieces.service
File metadata and controls
216 lines (181 loc) · 9.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
[Unit]
Description=restinpieces app server
Documentation=https://github.com/caasmo/restinpieces
After=network-online.target
Wants=network-online.target # Ensures network is fully up
[Service]
# User and Group
User=${RESTINPIECES_APP}
Group=${RESTINPIECES_APP}
# Working Directory
WorkingDirectory=/home/${RESTINPIECES_APP}
# Command to start the service
ExecStart=/home/${RESTINPIECES_APP}/bin/${RESTINPIECES_APP} -dbpath data/app.db -agekey age.key
ExecReload=/bin/kill -HUP $MAINPID
# Capabilities:
# This grants the ability to bind to privileged ports (<1024)
AmbientCapabilities=CAP_NET_BIND_SERVICE
# CapabilityBoundingSet limits the *maximum* capabilities the process can ever have.
# It's good practice to set this to the same as AmbientCapabilities or a superset if needed.
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
# === FILESYSTEM HARDENING ===
# What it does: It ensures that the service process and any of its children can
# never gain more privileges than they had at startup. Specifically, it ignores
# the "Set-User-ID" (SUID) and "Set-Group-ID" (SGID) bits on binaries.
#
# Why use it: It prevents privilege escalation attacks. Even if an attacker
# finds a way to run a shell, they cannot run sudo or use binaries like passwd
# to gain root access.
NoNewPrivileges=true
# It mounts the entire file system hierarchy as Read-Only for
# this service, with very few exceptions (usually /dev, /proc, and /sys).
# It prevents an attacker from modifying system files, installing
# permanent malware, or tampering with configuration files in /etc.
#
# ProtectHome for services running from their own home is redundant with
# ProtectSystem
#
# Use ProtectSystem=strict + ReadWritePaths=/home/${RESTINPIECES_APP}/data, no
# need for BindReadOnlyPaths
#
# ProtectSystem=full
ProtectSystem=strict
# It mounts a temporary, empty filesystem (tmpfs) over /home, /root, and
# /run/user. It protects user data. The service sees an empty /home directory.
# This ensures the service cannot steal SSH keys, documents, or personal data
# from real users on the server. Example: If your service tries to list
# /home/ubuntu/.ssh/id_rsa, it will likely see an empty directory or "file not
# found," protecting your SSH keys.
#
# - The Host Layer (Real Disk): On your actual hard drive,
# /home/myapp/data/db.sqlite exists physically.
# - The Protection Layer (ProtectHome=tmpfs): When the service starts, systemd
# creates a "sandbox" (a namespace). Inside this sandbox, it mounts a tmpfs
# (RAM disk) over /home. To the app, /home now looks empty. The real hard drive
# underneath is effectively covered by a blanket.
# The Exception Layer (ReadWritePaths): This is the crucial step.
# ReadWritePaths doesn't just grant permission; it creates a Bind Mount.
# How the Bind Mount works
# When systemd sees ReadWritePaths=/home/myapp/data, it performs the following
# logic sequence during startup: Mount tmpfs: It covers the real /home with the
# empty temporary filesystem. Punch the Hole: It looks at the real host system,
# finds the actual folder /home/myapp/data, and mounts it on top of the temporary
# /home/myapp/data inside the sandbox.
#
#ProtectHome=true
#ProtectHome=tmpfs
# Systemd takes the real file. Mounts it inside the sandbox. Sets flags: RW
ReadWritePaths=/home/${RESTINPIECES_APP}/data
# This directive does exactly what you are asking for. It creates the "tunnel"
# from the real hard drive into the sandbox (just like ReadWritePaths), but it
# mounts that specific path as Read-Only.
# Systemd takes the real file. Mounts it inside the sandbox. Sets flags: RO
#
# Use ProtectSystem=strict + ReadWritePaths=/home/${RESTINPIECES_APP}/data, no
# need for BindReadOnlyPaths
#BindReadOnlyPaths=/home/${RESTINPIECES_APP}/age.key
#BindReadOnlyPaths=/home/${RESTINPIECES_APP}/bin
# It gives the service its own isolated /tmp and /var/tmp directories. These
# are separate from the host system's /tmp. Prevents "tmp race" attacks where
# one user guesses the filename of another user's temp file to inject malicious
# data. Other users cannot see the temporary files this service
# creates.
PrivateTmp=true
# === KERNEL PROTECTION ===
# It prevents the service from loading or unloading kernel modules (drivers).
# It stops rootkits. If an attacker gains root access inside the service, they
# might try to load a malicious kernel module to hide their presence or control
# the server at the hardware level. This blocks that.
ProtectKernelModules=true
# It mounts kernel tuning directories (like /proc/sys and /sys) as read-only.
# It prevents the service from changing OS-level settings, such as enabling IP
# forwarding, changing memory management logic, or altering network stack
# behavior. Example: An attacker cannot execute echo 1 >
# /proc/sys/net/ipv4/ip_forward to turn your server into a router for their
# traffic.
ProtectKernelTunables=true
# It prevents the service from reading the kernel log buffer (output usually
# seen via dmesg). Kernel logs often contain memory addresses of kernel
# structures. Attackers use these addresses to bypass ASLR (Address Space
# Layout Randomization) to craft sophisticated buffer overflow exploits.
# Example: If the process tries to run the command dmesg, it will be denied
# permission.
ProtectKernelLogs=true
# It mounts the cgroup hierarchy (/sys/fs/cgroup) as read-only. It prevents
# the service from modifying its own resource limits (CPU/Memory quotas) or
# escaping the cgroup sandbox. Example: The process cannot increase its own
# CPU priority or disable its memory limits.
ProtectControlGroups=true
# === PROCESS VISIBILITY ===
# It modifies the /proc filesystem so that the service can only see its own
# process and its children. It cannot see any other processes running on the
# system. It prevents information gathering. An attacker cannot run ps aux to
# see if an Antivirus, SSH daemon, or database is running on the same server.
# Example: If the service runs ps aux, it will look like it is the only program
# running on the entire computer.
ProtectProc=invisible
# It restricts the contents of /proc to only contain numerical process ID
# folders. It hides system status files like /proc/cpuinfo, /proc/meminfo, or
# /proc/uptime. It hides hardware details and system uptime (which can help an
# attacker guess unpatched kernel vulnerabilities based on how long the system
# has been running). Example: Running cat /proc/cpuinfo to determine the
# processor type will fail.
ProcSubset=pid
# === NAMESPACE RESTRICTIONS ===
# It prevents the service from creating new Linux Namespaces (using unshare or
# clone).
# Namespaces are complex and often have security vulnerabilities. Attackers
# often use them to create a new user namespace where they gain "fake" root
# privileges to exploit the kernel.
# Example: The application cannot launch a Docker container or create a
# chroot-like environment within itself.
RestrictNamespaces=true
# It prevents the process from requesting "Real-time" scheduling priority. This
# is an Anti-DoS (Denial of Service) measure. If a process gets Real-time
# priority and goes into an infinite loop, it can freeze the entire CPU, making
# the server unresponsive to even SSH login attempts. Example: The process
# cannot use chrt to set its priority to SCHED_RR.
RestrictRealtime=true
# It prevents the service from creating files that have the SUID or SGID bit
# set. Even if ReadWritePaths allows writing to a folder, an attacker might
# try to create a file there, give it SUID root permissions, and execute it
# later to become root. This directive stops the creation of such files.
# Example: chmod u+s malicious_script will fail.
RestrictSUIDSGID=true
# === NETWORK ===
# It restricts which type of network sockets the application can use. Here, it
# allows only IPv4 (AF_INET) and IPv6 (AF_INET6). It reduces the attack
# surface of the kernel networking stack. It blocks AF_PACKET (used for packet
# sniffing/Wireshark). It blocks AF_NETLINK (used to communicate deeply with
# the kernel/configure network interfaces). It blocks AF_UNIX (unless added),
# preventing the app from talking to local sockets like /var/run/docker.sock.
# Example: If an attacker tries to open a raw socket to sniff traffic passing
# through the server, the kernel will block the request because AF_PACKET is
# not in the allowed list.
# RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictAddressFamilies=AF_INET AF_INET6
# === RESTART ===
# Restart behavior
Restart=on-failure
RestartSec=5s # Time to wait before restarting
# === LOGGING ===
# Standard output and error logging
# 'journal' sends logs to the systemd journal
StandardOutput=journal
StandardError=journal
# Alternatively, to append to files (ensure mygoappuser has write permissions):
# StandardOutput=append:/var/log/mygoapp/app.log
# StandardError=append:/var/log/mygoapp/error.log
# === LOGGING ===
# Environment variables (optional)
# Environment="GIN_MODE=release"
# Environment="PORT=80"
# EnvironmentFile=/etc/mygoapp/environment.conf # For many variables
# Resource limits (optional)
# LimitNOFILE=65536 # Max open files
# Type of service
# 'simple' is common for Go apps that don't fork and run in the foreground.
# If your Go app uses systemd's sd_notify mechanism, use Type=notify
Type=simple
[Install]
WantedBy=multi-user.target