Wireguard: service wg-quick@interface fails to start

Hi,
I installed package wireguard-tool and configured a wireguard-connection /etc/wireguard/ivpn-ch.conf.

I can start this interface w/o issues using command sudo wg-quick up ivpn-ch.
However I cannot start wireguard using corresponding sytem unit sudo systemd service start wg-quick@ivpn-ch.service.

The error message is:

❯ sudo systemctl status wg-quick@ivpn-ch.service
× wg-quick@ivpn-ch.service - WireGuard via wg-quick(8) for ivpn/ch
     Loaded: loaded (/usr/lib/systemd/system/wg-quick@.service; disabled; preset: disabled)
     Active: failed (Result: exit-code) since Sun 2024-01-14 15:02:44 CET; 2s ago
       Docs: man:wg-quick(8)
             man:wg(8)
             https://www.wireguard.com/
             https://www.wireguard.com/quickstart/
             https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8
             https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8
    Process: 4050 ExecStart=/usr/bin/wg-quick up ivpn-ch (code=exited, status=1/FAILURE)
   Main PID: 4050 (code=exited, status=1/FAILURE)
        CPU: 7ms

Jan 14 15:02:44 eliza systemd[1]: Starting WireGuard via wg-quick(8) for ivpn/ch...
Jan 14 15:02:44 eliza wg-quick[4050]: wg-quick: `/etc/wireguard/ivpn-ch.conf' does not exist
Jan 14 15:02:44 eliza systemd[1]: wg-quick@ivpn-ch.service: Main process exited, code=exited, status=1/FAILURE
Jan 14 15:02:44 eliza systemd[1]: wg-quick@ivpn-ch.service: Failed with result 'exit-code'.
Jan 14 15:02:44 eliza systemd[1]: Failed to start WireGuard via wg-quick(8) for ivpn/ch.

Looking closely to the error message there’s a misleading
Jan 14 15:02:44 eliza wg-quick[4050]: wg-quick: /etc/wireguard/ivpn-ch.conf’ does not exist`
because this file does exist:

❯ sudo file /etc/wireguard/ivpn-ch.conf
/etc/wireguard/ivpn-ch.conf: ASCII text

But the last entry
Jan 14 15:02:44 eliza systemd[1]: Failed to start WireGuard via wg-quick(8) for ivpn/ch.
is pointing to a file thas does not exist.

Is this a bug?

Update:
The issue remains after renaming wireguard config file to /etc/wireguard/ivpn_ch.conf.

Is the odd slash conversion ivpn/ch still observed with the new underscore named instance (wg-quick@ivpn_ch)?

No. The issue is actually the same:

Jan 14 18:35:45 eliza systemd[1]: Starting WireGuard via wg-quick(8) for ivpn_ch...
Jan 14 18:35:45 eliza wg-quick[27823]: wg-quick: `/etc/wireguard/ivpn_ch.conf' does not exist
Jan 14 18:35:45 eliza systemd[1]: wg-quick@ivpn_ch.service: Main process exited, code=exited, status=1/FAILURE
Jan 14 18:35:45 eliza systemd[1]: wg-quick@ivpn_ch.service: Failed with result 'exit-code'.
Jan 14 18:35:45 eliza systemd[1]: Failed to start WireGuard via wg-quick(8) for ivpn_ch.

Does it work if you run the same start command manually?

I just confirmed on my system that it works both with file names containing slashes and ones containing underscores. The hyphens are rewritten to slashes in the unit description but it does not affect functionality.

It should be noted that /usr/bin/wg-quick just just a shell script. The “does not exist” line you observe is coming from:

        CONFIG_FILE="$1"
        [[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15}$ ]] && CONFIG_FILE="/etc/wireguard/$CONFIG_FILE.conf"
        [[ -e $CONFIG_FILE ]] || die "\`$CONFIG_FILE' does not exist"

I don’t see it mangling “ivpn-ch” in any particular way. In case you feel comfortable with modifying the script, you could some debug statement before the line it dies in.

For example

...
echo "DEBUG: $CONFIG_FILE"
ls -l $CONFIG_FILE
test -e $CONFIG_FILE ; echo $?
[[ -e $CONFIG_FILE ]] || die "\`$CONFIG_FILE' does not exist"
...

That way you could check if the path is correctly constructed to point to a file which exists.

Adding debugging code to /usr/bin/wg-quick does not deliver information that points to the root cause:

Jan 15 17:48:26 eliza systemd[1]: Starting WireGuard via wg-quick(8) for ivpn/ch...
Jan 15 17:48:26 eliza wg-quick[3599]: DEBUG: /etc/wireguard/ivpn-ch.conf
Jan 15 17:48:26 eliza wg-quick[3601]: ls: cannot access '/etc/wireguard/ivpn-ch.conf': Permission denied
Jan 15 17:48:26 eliza systemd[1]: wg-quick@ivpn-ch.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Jan 15 17:48:26 eliza systemd[1]: wg-quick@ivpn-ch.service: Failed with result 'exit-code'.
Jan 15 17:48:26 eliza systemd[1]: Failed to start WireGuard via wg-quick(8) for ivpn/ch.

Assumption:
I installed package wireguard-tool using transactional-update, but configuration files in /etc/wireguard/ have been created in “regular” filesystem.

That is helpful - it cannot read the file, so I think the problem is outside of wg-quick. The service should run it as root and it should not have any issues reading /etc/wireguard/.

I installed package wireguard-tool using transactional-update

Unfortunately I don’t know as much about the transactional systems, though I don’t think there is anything wrong with your installation/configuration routine. Given the Micro operating systems being shipped with SELinux - are there any denials (AVC messages) recorded in /var/log/audit/audit.log?

MicroOS defaults to SELinux in enforcing mode so it may well be the reason.

Indeed in /var/log/audit/audit.log are many entries like this:
type=SERVICE_START msg=audit(1705337306.943:128): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=wg-quick@ivpn-ch comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=failed'

Although I wish that this is the root cause I want to add this comment:
There are other services running w/o issues which don’t have relevant rules, at least I didn’t create any rules, e.g.

ivpn-service.service
zramswap.service

Entries like type=SERVICE_START are only informative, nothing was blocked there - we are mostly interested in denials, such lines would contain type=AVC and, I think, denied.

There are other services running w/o issues

Right … I’m not so sure about SELinux but assuming wg-quick is executed as root (you can double check if there are no user or group lines in systemctl cat wg-quick@, I can’t think of many other reasons why it would not be able to read the file). The systemd unit shipped with the wireguard-tools package does not seem to have any systemd side security confinements either.

@cmonty28 and after install you ran transactional-update apply or rebooted the system to be in the next snapshot?

Certainly I rebootet OS.

I always start service or wg-quick with sudo.

Here’s the content of the service file:

❯ sudo systemctl cat wg-quick@ivpn-ch.service
# /usr/lib/systemd/system/wg-quick@.service
[Unit]
Description=WireGuard via wg-quick(8) for %I
After=network-online.target nss-lookup.target
Wants=network-online.target nss-lookup.target
PartOf=wg-quick.target
Documentation=man:wg-quick(8)
Documentation=man:wg(8)
Documentation=https://www.wireguard.com/
Documentation=https://www.wireguard.com/quickstart/
Documentation=https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8
Documentation=https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/wg-quick up %i
ExecStop=/usr/bin/wg-quick down %i
ExecReload=/bin/bash -c 'exec /usr/bin/wg syncconf %i <(exec /usr/bin/wg-quick strip %i)'
Environment=WG_ENDPOINT_RESOLUTION_RETRIES=infinity

[Install]
WantedBy=multi-user.target

And I checked audit.log again:

type=AVC msg=audit(1705240964.465:167): avc:  denied  { dac_override } for  pid=4050 comm="wg-quick" capability=1  scontext=system_u:system_r:wireguard_t:s0 tcontext=system_u:system_r:wireguard_t:s0 tclass=capability permissive=0
type=AVC msg=audit(1705253745.366:420): avc:  denied  { dac_read_search } for  pid=27823 comm="wg-quick" capability=2  scontext=system_u:system_r:wireguard_t:s0 tcontext=system_u:system_r:wireguard_t:s0 tclass=capability permissive=0

However, I doubt the theory of SELinux is correct.
Why can I run command /usr/bin/wg-quick up <interface>, but the same command fails when service is started?

@cmonty28 Try adding the the config into the service EnvironmentFile=-/etc/wireguard/ivpn-ch.conf is it really a oneshot, perhaps try forking instead.

Disable SELinux enforcing mode and check if it changes anything.

After disabling SELinux enforce mode the service starts w/o errors:

❯ setenforce 0
setenforce:  security_setenforce() failed:  Permission denied
❯ sudo setenforce 0
❯ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   permissive
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     actual (secure)
Max kernel policy version:      33
❯ sudo systemctl start wg-quick@ivpn-ch.service
❯ sudo wg show
interface: ivpn-ch
  public key: +rlda8/en5AQ8yVoSelnxhASxxxxx/0AL1g7A7zW9RE=
  private key: (hidden)
  listening port: 53191
  fwmark: 0xca6c

peer: jVZJ61i1xxkAfriDHpwvF/GDuTvZUxxxxxSjkOJvaUA=
  endpoint: 141.255.164.66:2049
  allowed ips: 0.0.0.0/0, ::/0
  latest handshake: 9 seconds ago
  transfer: 32.66 KiB received, 19.75 KiB sent

This confirms w/o any doubt your statements point to SELinux.

Next question: How can this issue be fixed?

I have no first hand experience with SELinux, but the most obvious google search and five minutes reading brings up sealert -l "*" that suggests corrective actions.

What are permissions of /etc/wireguard and /etc/wireguard/ivpn-ch.conf? You have never shown them.

Nobody asked this before.
File permission is 644, directory is 755.

However, I can only list directory /etc/wireguard if I use root permission (sudo).
Without root permission directory /etc/wireguard does not exist.

What is this?

If you installed wireguard-tools from the official repositories, please file a SELinux bug report and include the AVC messages.
The SELinux policy should cover this and you as the user should not have to adjust anything to get the service working with it.

Show the actual output of “ls -l”, not your description of it.

dac_override and dac_read_search are indications of incorrect file permissions. So far there is no indication of any issue with SELinux policy itself. But as long as we only have vague description and truncated log entries it is also impossible to decide. At the very list full audit log entries are needed.