Docker Compose check · high

seccomp:unconfined and apparmor:unconfined

Docker applies a default seccomp profile, which blocks system calls containers rarely need, and on hosts with AppArmor a default AppArmor profile. security_opt: seccomp:unconfined or apparmor:unconfined turns one of them off for the service. The explainer marks this high. Keep the default, or write a custom profile that allows only the extra calls the service needs.

$ explain docker-compose.yml
! app disables a security profile high
line 4
fix: see below
$ 

What the free Docker Compose explainer reports on the risky example below.

Why it matters

Seccomp filters which system calls a process may make. Docker's default profile blocks calls such as loading kernel modules or rebooting, which shrinks the kernel surface a compromised container can reach.

AppArmor limits which files and operations a process may use. Docker's default profile blocks writes to sensitive parts of /proc and /sys, among other things.

Turning either off is usually done to fix one blocked call (often while debugging or running a tool like strace), and leaves every other call open too.

Risky and safer docker-compose.yml

Riskydocker-compose.yml
services:
  app:
    image: example/app:1.4.2
    security_opt:
      - seccomp:unconfined
    restart: unless-stopped
    mem_limit: 512m
Saferdocker-compose.yml
services:
  app:
    image: example/app:1.4.2
    # Default seccomp and AppArmor profiles stay on
    security_opt:
      - no-new-privileges:true
    restart: unless-stopped
    mem_limit: 512m

How to fix it

  • Remove the seccomp:unconfined or apparmor:unconfined entry.
  • If something breaks, find the blocked system call and write a custom profile that starts from Docker's default and allows only that call, then reference it with seccomp:./profile.json.
  • Add no-new-privileges:true while you are there, so processes cannot gain privileges through setuid binaries.

When it's acceptable

  • Short local debugging sessions with tools that need blocked calls, removed afterwards.

Check your own docker-compose.yml

The risky example is loaded below. Paste your own file to check it for this and every other Docker Compose rule. It runs in your browser; nothing is uploaded.

docker-compose.yml

Parsed in your browser. Nothing is uploaded.

Explanation

1 service0 networks0 volumes1 high

Top level

appexample/app:1.4.2

  • Docs for image (opens in a new tab)

    Runs the image example/app:1.4.2.

  • Docs for security_opt (opens in a new tab)

    Security options: seccomp:unconfined.

    Turning off seccomp or AppArmor removes the syscall and file filtering that limits what a compromised container can do.

    Safer: Remove the unconfined option and use the default profile, or a custom profile that allows only what is needed.

  • Docs for restart (opens in a new tab)

    Restarts if it stops or after a daemon restart (unless-stopped), but stays down if you stopped it manually.

  • Docs for mem_limit (opens in a new tab)

    Limits memory to 512m. The container is killed if it exceeds this.

Questions

What does seccomp:unconfined do in Docker?

It runs the container without a seccomp filter, so processes inside can make any system call the kernel and their capabilities allow, instead of the reduced set Docker's default profile permits.

Is apparmor:unconfined flagged too?

Yes. The explainer treats seccomp and AppArmor the same way, with either a colon or an equals sign, and reports one finding per service.

How do I allow one blocked syscall without disabling seccomp?

Copy Docker's default seccomp profile, add the call you need, and point security_opt at that file with seccomp:./profile.json.