Self-hosted service
containers/udica avatar
containers/udica

udica: generating SELinux policies for containers

This repository contains a tool for generating SELinux security profiles for containers

587 stars48 forksPythonGPL-3.0

At a glance

What is it?
udica is a Python tool that builds an SELinux policy for a running container, combining rules inherited from CIL template blocks with rules discovered by inspecting the container's JSON metadata. The generated module is loaded with semodule and the container is then started with a custom label.
Who is it for?
udica fits a platform engineer who wants containers to keep meaningful SELinux confinement instead of falling back to an unconfined label, since the tool derives the policy from what the container actually mounts and publishes rather than asking you to write the rules by hand.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 64 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Block inheritance is the mechanism

udica contains a tool for generating SELinux security profiles for containers, and the whole concept is based on the block inheritance feature inside the CIL intermediate language supported by the SELinux userspace. The tool creates a policy that combines two things: rules inherited from specified CIL blocks, which are templates, and rules discovered by inspection of the container JSON file, which contains the mountpoint and port definitions. The first half means you start from known good building blocks rather than from nothing, and the second half means the result reflects the specific container you are running rather than a generic container profile. The final policy can be loaded immediately or moved to another system where it is loaded via semodule, which is what makes the tool usable in a pipeline where the container runs in one place and the policy is applied in another. The repository is under the containers organisation, the primary language is Python, and the licence is GPL-3.0.

A fishing rod, not a fisherman

The README explains the name with some care, and the explanation is a fair description of the tool's value. The name is derived from the Slovak word udica, which means fishing rod, and it is a reference to the saying about giving a man a fish and teaching him to fish. Here udica is the fishing rod that lets you get the fish, the container policy, yourself, instead of always having to ask your local fisherman, the SELinux expert, to catch it for you. The origin of the project is given too: it was created based on a proof of concept describing the process of creating policy, and the tool itself is described as still in an early phase of development, with feedback, ideas and pull requests welcome, and with new features, parameters and policy blocks still being added. That framing matters for expectations, because an early phase tool in security tooling is a tool you run carefully and read the output of, rather than one you wire in and forget.

Installing it, and the enforcing mode requirement

The installation section gives three routes. The first installs the tool with all its dependencies from a source checkout:

bash
    $ sudo dnf install -y podman setools-console git container-selinux
    $ git clone https://github.com/containers/udica
    $ cd udica && sudo python3 ./setup.py install

The second is running it straight from git without installing, with `python3 -m udica --help`. The third is a package install, either from the Fedora repository or from the Python Package Index. The README then insists on a precondition, and it is the one step you should not skip, which is that SELinux must be in enforcing mode, checked with setenforce and getenforce. Generating a policy for a permissive host achieves nothing, because a permissive kernel logs the denials instead of enforcing them, so the tool would appear to work and the container would be no more confined than before. The package metadata also records that the tool installs an Ansible deploy module and a set of macros for confined users under the share directory, and the console entry point is registered as `udica`.

What the tool sees in a container that is not confined

The README walks through the problem the tool solves, using a container that runs with the container type and two categories. The container bind mounts the home directory read only and the spool directory read and write, and it publishes the container's port 21 on the host. The point of the example is that access to the mounted home directory does not work, and the listing fails with a permission denied, and the reason given is that there is no allow rule for the container type to access that path. The same happens in the spool directory, where even creating a file fails, again for want of an allow rule. Network access is by contrast completely allowed, and the documentation shows the allow rules for the network domains binding, connecting, receiving and sending on TCP and UDP sockets, and then makes the point that it would be good to restrict this and allow the container to bind only on the TCP port 21 or with the same label. The permission denied and the sesearch queries used to confirm the absence of rules are what you would run yourself to work out why a container cannot see its own volumes.

From container ID to loaded policy

The generation flow is short. You find the container ID from the podman listing, then either write the container JSON to a file and pass it with the `-j` parameter together with a policy name, or pipe the inspect output straight into the tool:

bash
    # podman inspect 37a3635afb8f > container.json
    # udica -j container.json  my_container

The tool then reports that the policy was created and prints the semodule command to load it, which loads the generated module along with the template modules for the base container, the network container and the home container. The last step is to restart the container with the security option that selects the new type, and the documentation shows the full run command with the label, the same two mounts and the same published port. The effect is visible in the process listing, where the container process now carries the custom type instead of the default one, and the mount points become readable and writable as intended, while the container can bind to the TCP port 21 and not to port 80. That last detail is the clearest demonstration of the value, because the policy is not merely permissive, it is specific.

The engine support and the packaging

The supported container engines are listed with minimum versions, and the spread tells you which generations the tool has been kept up with. CRI-O from v1.14.10, docker from v1.13, podman from v2.0, containerd from v1.5.0 using either nerdctl v0.14 or crictl, and LXD from v5.21.1. The repository layout matches a project that is more than a script. There is a `udica/` package directory, a `tests/` directory, a `contrib/` directory, a `hack/` directory, a `plans/` directory, a `logo/`, a `Dockerfile`, a `Makefile`, a `setup.py` and a `.packit.yaml` for packaging into Fedora, plus a Cirrus CI configuration. The Dockerfile builds on Fedora 30 and installs the SELinux tooling, then the Python packages, and the entrypoint is the udica binary itself. The Makefile has the ordinary targets, install, lint, format, format-check and test, where the test target runs the unit tests, and an image target that builds the container image with podman by default.

Where this is the wrong choice

The limits are worth being clear about. First, this is a host level tool that assumes you already understand SELinux well enough to read the generated CIL and to know what you are loosening. The output is a policy module, and reviewing a policy module is a specialised skill, so the tool shifts work rather than removing it. Second, the state of the project. The README says the tool is still in an early phase of development and that features, parameters and policy blocks are still being added, and the release history backs that up, with v0.2.8 in 2023 and v0.2.9 in 2026. Third, the workflow is manual at the two points that matter. The container has to be running for the tool to inspect it, and the policy has to be loaded and the container restarted with the right label, so this is not something that composes into a declarative deployment pipeline on its own, even though the policy can be moved to another system. Fourth, the model is per container, so a fleet of similar containers means a policy per container unless you write the templates yourself, and writing the templates is the part the tool was meant to spare you. Fifth, and most simply, if your containers already get a suitable type from the standard container policies, there is nothing for udica to add.

Editorial conclusion

udica fits a platform engineer who wants containers to keep meaningful SELinux confinement instead of falling back to an unconfined label, since the tool derives the policy from what the container actually mounts and publishes rather than asking you to write the rules by hand. It is the wrong choice if your containers are already labelled by a policy that already covers their mount points, because then the tool is redundant, and the wrong choice if you want per workload policy management, since the output is a set of CIL modules rather than something the policy build system owns. Before you use it, make sure SELinux is in enforcing mode, since generating a policy for a permissive host achieves nothing, and read the state section, which says plainly that the tool is still in an early phase of development. The last push was on 2026-08-20 with v0.2.9 released on 2026-06-02, and the licence is GPL-3.0.

Frequently asked questions

What does udica do?

It generates SELinux security profiles for containers. The tool creates a policy combining rules inherited from specified CIL blocks, which are templates, and rules discovered by inspecting the container JSON file, which contains the mountpoint and port definitions. The resulting policy can be loaded immediately or moved to another system and loaded with semodule.

How do I install udica?

From a source checkout you install the dependencies with `sudo dnf install -y podman setools-console git container-selinux`, clone the repository and run `sudo python3 ./setup.py install` in it. You can also run it straight from git with `python3 -m udica --help`, install it from the Fedora repository, or install it from the Python Package Index. SELinux must be in enforcing mode.

Which container engines does udica support?

CRI-O v1.14.10 and later, docker v1.13 and later, podman v2.0 and later, containerd v1.5.0 and later using nerdctl v0.14 or crictl, and LXD v5.21.1 and later.

How do you apply the policy udica generates?

You load it with semodule, together with the template modules for the base container, the network container and the home container, then restart the container with the security option that selects the new type. The README's example loads `my_container.cil` with the three templates and runs the container with `--security-opt label=type:my_container.process`.

Official sources

  1. containers/udica on GitHub
  2. Issues
  3. License: GPL-3.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/containers-udica.svg)](https://hysenlabs.com/projects/containers-udica)

Was this useful?