Skip to content
Français
Conteneurs & Orchestration medium

Securing Incus: unprivileged containers, limits and restricted projects

10 min de lecture

Read this page in French

incus logo

Incus is safe by default: its containers are unprivileged, meaning the instance root is not the host root. What remains is not undoing that protection, and knowing how to compartmentalise and cap. This guide explains the idmap that isolates containers, shows how to cap resources, and sets up a restricted project that forbids privileged containers. Tested on Incus 7.0. For anyone hosting instances that do not trust each other.

What you will learn

  • Why an unprivileged container is safer (the idmap).
  • Limit the CPU and memory of an instance.
  • Compartmentalise with a restricted project.
  • The security.privileged and security.nesting flags, to handle with care.

Prerequisites

The foundation: unprivileged containers

This is the fundamental protection of Incus, active with nothing to configure. An unprivileged container shifts identifiers (idmap): the instance root (UID 0) corresponds to a harmless, high UID on the host.

Fenêtre de terminal
incus exec sec-lab -- cat /proc/self/uid_map
0 1000000 1000000000

That line reads: UID 0 inside the container starts at 1000000 on the host, across a range of a billion UIDs. In practice, if an attacker becomes root inside the container and escapes, they are only a user with no privilege at all on the host. That is the whole difference from a classic privileged Docker container.

Capping resources

A container with no limit can exhaust the host CPU or memory and starve its neighbours, which is a denial of service. You cap with the limits.* keys.

Fenêtre de terminal
incus config set sec-lab limits.cpu=1 limits.memory=512MiB
incus config show sec-lab | grep limits
limits.cpu: "1"
limits.memory: 512MiB

Those limits apply live and extend further (limits.cpu.allowance for a time quota, limits.memory.swap, limits.processes). On a shared host, capping is a security measure, not only a performance one.

Compartmentalising with a restricted project

A project isolates a set of instances. Setting it to restricted=true forbids dangerous features to everything created inside it, whatever the user types.

  1. Create the project and restrict it:

    Fenêtre de terminal
    incus project create confined
    incus project set confined restricted=true
  2. Check that a privileged container is refused there:

    Fenêtre de terminal
    incus launch images:debian/13 badct --project confined -c security.privileged=true
    Error: ... Invalid value "true" for config "security.privileged" on
    container "badct" of project "confined": Privileged containers are forbidden

The refusal comes from the project, not from a convention: even an administrator cannot create a privileged container inside a restricted project. You then refine with the restricted.* keys (restricted.containers.nesting, restricted.devices.disk, restricted.networks.access) to frame precisely what the project allows.

The flags to handle with care

Two settings undo the default isolation. Enabling them has to be a conscious choice, never a reflex to "make something work".

  • security.privileged=true makes the container privileged (container root equals host root). An escape becomes a host compromise. Rule it out except for a very specific need on a trusted instance.
  • security.nesting=true allows running Incus or Docker inside the container. Handy, since it is what makes nested labs possible, but it widens the attack surface. Reserve it for the cases that demand it.

Other levers

Beyond these basics, Incus applies a per-instance AppArmor profile and seccomp system call filtering by default. For remote API access, prefer TLS certificate or OIDC authentication over broad access, and compartmentalise rights per project. These mechanisms combine: idmap, limits, restricted project and AppArmor form independent layers.

Key points

  • Incus containers are unprivileged by default: the idmap shifts root away from the host.
  • Capping CPU and memory (limits.cpu, limits.memory) protects a shared host.
  • A restricted project (restricted=true) forbids privileged containers, even to an administrator.
  • security.privileged=true cancels the idmap: avoid it; security.nesting widens the surface.
  • A restricted project starts from nothing is permitted: add the allowed pool and network explicitly.

FAQ: common questions about securing Incus

Next steps

Is this site useful to you?

Fewer than 1% of readers support this site.

I maintain more than 700 free guides, with no ads and no tracking. Any support, even a symbolic one, helps cover hosting and keeps these resources free. Thank you for the help.

The form does not show? Open Ko-fi in a new tab.

Subscribe and follow my DevSecOps work on LinkedIn