Udica
This repository contains a tool for generating SELinux security profiles for containers
Install / Use
/learn @containers/UdicaREADME
udica - Generate SELinux policies for containers!
<a href="https://copr.fedorainfracloud.org/coprs/lvrabec/udica/package/udica/"><img src="https://copr.fedorainfracloud.org/coprs/lvrabec/udica/package/udica/status_image/last_build.png" /></a>
Overview
This repository contains a tool for generating SELinux security profiles for containers. The whole concept is based on "block inheritence" feature inside CIL intermediate language supported by SELinux userspace. The tool creates a policy which combines rules inherited from specified CIL blocks(templates) and rules discovered by inspection of container JSON file, which contains mountpoints and ports definitions.
Final policy could be loaded immediately or moved to another system where it could be loaded via semodule.
What's with the weird name?
The name of this tool is derived from the Slovak word "udica" [uɟit͡sa], which means "fishing rod". It is a reference to the saying "Give a man a fish and you feed him for a day; teach a man to fish and you feed him for a lifetime." Here udica is the fishing rod that allows you to get the fish (container policy) yourself, instead of always having to ask your local fisherman (SELinux expert) to catch (create) it for you ;)
State
This tool is still in early phase of development. Any feedback, ideas, pull requests are welcome. We're still adding new features, parameters and policy blocks which could be used.
Proof of concept
Tool was created based on following PoC where process of creating policy is described: https://github.com/fedora-selinux/container-selinux-customization
Supported container engines
Udica supports following container engines:
- CRI-O v1.14.10+
- docker v1.13+
- podman v2.0+
- containerd v1.5.0+ (using
nerdctlv0.14+ or crictl)
Installing
Install udica tool with all dependencies
$ sudo dnf install -y podman setools-console git container-selinux
$ git clone https://github.com/containers/udica
$ cd udica && sudo python3 ./setup.py install
Alternatively you can run udica directly from git:
$ python3 -m udica --help
Another way how to install udica is to use fedora repository:
# dnf install udica -y
Or you can use Python Package Index (Pypi):
# pip install udica
Make sure that SELinux is in Enforcing mode
# setenforce 1
# getenforce
Enforcing
Current situation
Let's start podman container with following parameters:
# podman run -v /home:/home:ro -v /var/spool:/var/spool:rw -p 21:21 -it fedora bash
- Container will bind mount /home with read only perms
- Container will bind mount /var/spool with read/write perms
- Container will publish container's port 21 to the host
Container runs with container_t type and c447,c628 categories.
Access mounted /home is not working:
[root@37a3635afb8f /]# cd /home/
[root@37a3635afb8f home]# ls
ls: cannot open directory '.': Permission denied
Because there is no allow rule for container_t to access /home
# sesearch -A -s container_t -t home_root_t
#
Access mounted /var/spool is not working:
[root@37a3635afb8f home]# cd /var/spool/
[root@37a3635afb8f spool]# ls
ls: cannot open directory '.': Permission denied
[root@37a3635afb8f spool]# touch test
touch: cannot touch 'test': Permission denied
Because there is no allow rule for container_t to access /var/spool
# sesearch -A -s container_t -t var_spool_t -c dir -p read
#
On the other hand, what is completely allowed is network access.
# sesearch -A -s container_t -t port_type -c tcp_socket
allow container_net_domain port_type:tcp_socket { name_bind name_connect recv_msg send_msg };
allow sandbox_net_domain port_type:tcp_socket { name_bind name_connect recv_msg send_msg };
# sesearch -A -s container_t -t port_type -c udp_socket
allow container_net_domain port_type:udp_socket { name_bind recv_msg send_msg };
allow sandbox_net_domain port_type:udp_socket { name_bind recv_msg send_msg };
It would be great to restrict this access and allow container bind just on tcp port 21 or with the same label.
Creating SELinux policy for container
To create policy for container, it's necessary to have running container for which a policy will be generated. Container from previous chapter will be used.
Let's find container id using podman ps command:
# podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
37a3635afb8f docker.io/library/fedora:latest bash 15 minutes ago Up 15 minutes ago heuristic_lewin
Container ID is 37a3635afb8f.
To create policy for it udica tool could be used. Parameter '-j' is for container json file and SELinux policy name for container.
# podman inspect 37a3635afb8f > container.json
# udica -j container.json my_container
or
# podman inspect 37a3635afb8f | udica my_container
Policy my_container with container id 37a3635afb8f created!
Please load these modules using:
# semodule -i my_container.cil /usr/share/udica/templates/{base_container.cil,net_container.cil,home_container.cil}
Restart the container with: "--security-opt label=type:my_container.process" parameter
Policy is generated. Let's follow instructions from output:
# semodule -i my_container.cil /usr/share/udica/templates/{base_container.cil,net_container.cil,home_container.cil}
# podman run --security-opt label=type:my_container.process -v /home:/home:ro -v /var/spool:/var/spool:rw -p 21:21 -it fedora bash
Container is now running with my_container.process type:
# ps -efZ | grep my_container.process
unconfined_u:system_r:container_runtime_t:s0-s0:c0.c1023 root 2275 434 1 13:49 pts/1 00:00:00 podman run --security-opt label=type:my_container.process -v /home:/home:ro -v /var/spool:/var/spool:rw -p 21:21 -it fedora bash
system_u:system_r:my_container.process:s0:c270,c963 root 2317 2305 0 13:49 pts/0 00:00:00 bash
SELinux now allows access to /home and /var/spool mount points:
[root@814ec56079e5 /]# cd /home
[root@814ec56079e5 home]# ls
lvrabec
[root@814ec56079e5 ~]# cd /var/spool/
[root@814ec56079e5 spool]# touch test
[root@814ec56079e5 spool]#
SELinux now allows binding to tcp/udp port 21, but not to 80:
[root@5bd8cb2ad911 /]# nc -lvp 21
Ncat: Version 7.60 ( https://nmap.org/ncat )
Ncat: Generating a temporary 1024-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.
Ncat: SHA-1 fingerprint: 6EEC 102E 6666 5F96 CC4F E5FA A1BE 4A5E 6C76 B6DC
Ncat: Listening on :::21
Ncat: Listening on 0.0.0.0:21
[root@5bd8cb2ad911 /]# nc -lvp 80
Ncat: Version 7.60 ( https://nmap.org/ncat )
Ncat: Generating a temporary 1024-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.
Ncat: SHA-1 fingerprint: 6EEC 102E 6666 5F96 CC4F E5FA A1BE 4A5E 6C76 B6DC
Ncat: bind to :::80: Permission denied. QUITTING.
Creating SELinux policy for confined user
Each Linux user on an SELinux-enabled system is mapped to an SELinux user. By default administrators can choose between the following SELinux users when confining a user account: root, staff_u, sysadm_u, user_u, xguest_u, guest_u (and unconfined_u which does not limit the user's actions).
To give administrators more options in confining users, udica now provides a way to generate a custom SELinux user (and corresponding roles and types) based on the specified parameters. The new user policy is assembled using a set of predefined policy macros based on use-cases (managing network, administrative tasks, etc.).
To generate a confined user, use the "confined_user" keyword followed by a list of options:
| Option | Use case | | ------------- | ------------- | | -a, --admin_commands | Use administrative commands (vipw, passwd, ...) | | -g, --graphical_login | Use graphical login environment | | -m, --mozilla_usage | Use mozilla firefox | | -n, --networking | Manage basic networking (ip, ifconfig, traceroute, tcpdump, ...) | | -d, --security_advanced | Manage SELinux settings (semanage, semodule, sepolicy, ...) | | -i, --security_basic | Use read-only security-related tools (seinfo, getsebool, sesearch, ...) | | -s, --sudo | Run commands as root using sudo | | -l, --user_login | Basic rules common to all users (tty, pty, ...) | | -c, --ssh_connect | Connect over SSH | | -b, --basic_commands | Use basic commands (date, ls, ps, man, systemctl -user, journalctl -user, passwd, ...) |
The new user also needs to be assigned an MLS/MCS level and range. These are set to s0 and s0:c0.c1023 respectively by default to work well in targeted policy mode.
For more details see Red Hat Multi-Level Security documentation.
$ udica confined_user -abcdgilmns --level s0 --range "s0:c0" custom_user
Created custom_user.cil
Run the following commands to apply the new policy:
Install the new policy module
# semodule -i custom_user.cil /usr/share/udica/macros/confined_user_macros.cil
Create a default context file for the new user
# sed -e ’s|user|custom_user|g’ /etc/selinux/targeted/contexts/users/user_u > /etc/selinux/targeted/contexts/users/custom_user_u
Map the new selinux user to an existing user account
# semanage login -a -s custom_user_u custom_user
Fix labels in the user's home directory
# restorecon -RvF /home/custom_user
As prompted by udica, the new user policy needs to be installed into the system along with the confined_user_macros file and a default context file needs to be created bef
Related Skills
node-connect
343.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
90.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
343.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
343.1kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
