Le Blog Utux

HTTP 200 GET /

SELinux: playing with podman + syncthing

Rédigé par uTux Aucun commentaire

For some reasons I use syncthing inside a container with a volume that is located in my home directory. While it's designed to run on Docker, it also works fine with podman which is rootless.

Until SELinux kicks in.

In this post I will try to explained how I managed to make syncthing work inside a podman container on a host where SELinux is present and enforced.

Major warning: I'm not an SELinux expert, and I noticed that policies generated by udica are quite permissive. This is a quick & dirty & easy solution for those who don't want to turn off SELinux.

Here is my compose file:

services:
  syncthing:
    image: "docker.io/syncthing/syncthing:latest"
    hostname: myhostnamehere
    volumes:
      - /home/utux/syncthing:/var/syncthing:rw
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Paris
    ports:
      - 127.0.0.1:8384:8384
# Run with:
# PODMAN_USERNS=keep-id podman-compose -f syncthing.yaml up

You can use compose files with podman using podman-compose. That manifest works fine on Debian and Mageia. However it does not work on AlmaLinux, complaining about missing permissions. This is of course due to SELinux.

Red Hat provides udica, a tool that takes a podman inspect as an input in order to build an SELinux policy. Following the documentation, here are the first steps:

## Fire up the container and let it fail.
$ PODMAN_USERNS=keep-id podman-compose -f syncthing.yaml up

## Find the id of your stopped container.
$ podman ps -a

## Inspect your container
$ podman inspect 189a4eb9e03a > syncthing.json

The next command must be run as root:

udica -j syncthing.json podman_syncthing

A new file podman_syncthing.cil should be present:

(block podman_syncthing
    (blockinherit container)
    (blockinherit restricted_net_container)
    (allow process unreserved_port_t ( tcp_socket (  name_bind ))) 
    (allow process unreserved_port_t ( udp_socket (  name_bind ))) 
    (allow process unreserved_port_t ( tcp_socket (  name_bind ))) 
    (allow process unreserved_port_t ( udp_socket (  name_bind ))) 
    (allow process user_home_t ( dir ( add_name create getattr ioctl lock open read remove_name rmdir search setattr write ))) 
    (allow process user_home_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write ))) 
    (allow process user_home_t ( fifo_file ( getattr read write append ioctl lock open ))) 
    (allow process user_home_t ( sock_file ( append getattr open read write ))) 
)

You can now load it using :

semodule -i podman_syncthing.cil /usr/share/udica/templates/{base_container.cil,net_container.cil}

You also have to change the compose file to add:

[...]
ports:
  - 127.0.0.1:8384:8384
security_opt:
  - label=type:podman_syncthing.process

But that proven to be insufficient for two reasons:

  • Syncthing was unable to spawn a "watcher". From what I understand this is a special process that monitors all changes on your synced folders. The later was blocked by SELinux because it requires a special permission (watch).
  • It was also unable to connect to remote instances, because it was not allowed to open TCP connections. This also requires a special permission (name_connect).

So I had to edit the CIL file like this:

(block podman_syncthing
    (blockinherit container)
    (blockinherit restricted_net_container)
    (allow process unreserved_port_t ( tcp_socket (  name_bind name_connect ))) 
    (allow process unreserved_port_t ( udp_socket (  name_bind ))) 
    (allow process user_home_t ( dir ( add_name create getattr ioctl lock open read remove_name rmdir search setattr watch write ))) 
    (allow process user_home_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write ))) 
    (allow process user_home_t ( fifo_file ( getattr read write append ioctl lock open ))) 
    (allow process user_home_t ( sock_file ( append getattr open read write ))) 
)

Notice that I also removed the udp_socket and tcp_socket duplicates. Syncthing should now run fine on Podman + Selinux.

Remember this policy is not really restrictive. If somehow your container has a volume mounted in a bad directory in your home, SELinux won't prevent access. It's like whitelisting your container for SELinux.

If it still does not work, grep for "AVC" entries in /var/log/audit/audit.log.

Écrire un commentaire

Quelle est le deuxième caractère du mot 8gtce ?