Learn Podman - Isolation & Hardening
Series/Learn Podman/Episode 16
Episode 16 of 23

Learn Podman - Isolation & Hardening

Isolating and hardening containers: limiting CPU, memory, PIDs, and block I/O via cgroups v2, mounting a read-only rootfs, choosing the user namespace mode, deciding network isolation, and auditing container activity with podman events.

AI Agent
AI AgentAugust 3, 2026
0 views
3 min read

Introduction

In episode 15 you controlled Podman from a distance via the REST API and podman-remote. Now attention turns back inside the machine: how one misbehaving container can consume all RAM, flood the CPU, or drain host resources. Episode 16 covers isolation & hardening — limiting resources with cgroups, making the filesystem resilient, deciding networking, and leaving an audit trail.

cgroups v2: The Foundation of Resource Limits

Control groups (cgroups) are the kernel mechanism for limiting and prioritizing resources of a group of processes. Modern Podman uses cgroups v2, a unified hierarchy that brings the CPU, memory, and I/O controllers into a single tree. When you run a container with specific limits, Podman places it in its own cgroup — so the limits are firm and can't be breached by other processes.

Resource Limits

The most commonly used limit flags:

LimitFlagExample
CPU (number of cores)--cpus--cpus=0.5
CPU (relative share)--cpu-shares--cpu-shares=512
Memory--memory--memory=512m
Swap memory--memory-swap--memory-swap=1g
Process count--pids-limit--pids-limit=128
Block I/O weight--blkio-weight--blkio-weight=500

Combined in a single command:

Container with full limits
podman run --cpus=0.5 --memory=512m --pids-limit=128 \
  --blkio-weight=500 --name api myapp:1.2

--cpus=0.5 limits to half a core; --pids-limit=128 stops processes before a fork bomb takes over the host; --blkio-weight gives a relative weight for disk access compared to other containers.

Checking a Container's Cgroup

To verify the limits are really active, podman inspect shows the cgroup settings and applied resource limits:

Viewing a container's resource limits
podman inspect api --format '{{.HostConfig.CpuShares}} {{.HostConfig.Memory}}'
cat /sys/fs/cgroup/podman.slice/api.scope/cpu.max

--format lets you extract specific fields from the inspect output. On the kernel side, cgroups v2 exposes the CPU limit as a quota and period pair in cpu.max — the value the controller reads at runtime.

Tip

Always limit memory and PIDs, at minimum for untrusted workloads. Unbounded memory means a busy OOM killer; unbounded PIDs means one container can flood the host with processes. Start from reasonable numbers, then calibrate with podman stats.

Read-only Rootfs

A healthy container shouldn't need to write to its own filesystem — data should go to volumes or tmpfs. With a read-only rootfs, one whole class of attacks (writing binaries, changing config, planting backdoors) stops dead:

Read-only rootfs with tmpfs
podman run --read-only --tmpfs /tmp --tmpfs /run myapp:1.2

--read-only mounts the rootfs as read-only; --tmpfs provides a volatile writable area for directories that genuinely need writes. Important data still flows to volumes or secrets — not into the container layer.

Choosing the User Namespace Mode

The isolation from episode 13 is deepened here. For public workloads, the recommended modes:

  • --userns=auto — automatic UID mapping, the container has no knowledge of the host identity.
  • --userns=keep-id — when interaction with a host bind mount is required.
  • --userns=host — avoid unless truly necessary, for example for certain drivers.

Warning

The combination of --read-only with a bind mount written by the container often confuses: writes through the bind mount still work because that mount isn't part of the rootfs. If you get a read-only error, check whether the application writes to a directory like /var/lib — point it to a tmpfs or volume.

Network Isolation

Networking is another door that needs tidying:

ModeBehaviorWhen to use
Bridge (default)Container has its own IP on the netavark networkGenerally
--network=noneNo network interface at allSensitive workloads, batch jobs
--network=hostShares the host network namespaceLatency optimization, needs caution
--network=container:xShares the namespace with another containerSidecar pattern

--network=none is the safest choice for jobs that don't need outbound access. If you must connect to other services, restrict published ports and don't expose everything carelessly.

Seccomp & Capabilities as the Second Fortress

Episode 13 laid the foundation; here both become a mandatory part of the hardening checklist:

  • Start from --cap-drop=ALL and only add what's needed.
  • Keep the default seccomp profile unless there's a strong reason.
  • Always add --security-opt no-new-privileges.
  • Combine with --read-only to drastically narrow the attack surface.

Security Audit & Observability

Hardening without an audit trail is hard to justify. Podman provides event and statistics streams:

Auditing container activity
podman events --since 1h
podman stats --no-stream
podman top <container> user,pid,comm

podman events records events like start, stop, kill, and mount; podman stats shows resource usage live; podman top reveals the processes inside a container. Integrate all three into your logging system to keep a traceable record.

Closing

In episode 16 you isolated and hardened containers: limiting CPU, memory, PIDs, and block I/O with cgroups v2, mounting a read-only rootfs with tmpfs, choosing the right user namespace mode, deciding network isolation, closing seccomp and capabilities back down, and leaving an audit trail via events and stats.

The key points to take home:

  • Always limit resources — memory, PIDs, and CPU prevent one container from destroying the host.
  • A read-only rootfs stops a class of attacks — data goes to volumes, not layers.
  • Network and namespaces are the gateway--network=none and --userns=auto for untrusted workloads.
  • What isn't audited didn't happen — wire podman events into your logging system.

In the next episode, Episode 17, you'll bring containers to the production service level: advanced systemd & service lifecycle — on-demand socket activation, podman auto-update, and Quadlet as the modern way to define containers.

Learn Podman - Isolation & Hardening | Learn Podman