Skip to content

v2.0.0-rc.3 user namespaces stdio permissions #10598

@ctrox

Description

@ctrox

Description

Using v2.0.0-rc.3 together with user namespaces on Kubernetes v1.30, I have ran into an issue running a very basic nginx container:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-userns
spec:
  hostUsers: false
  containers:
  - name: nginx
    image: nginx:1.27.0
    ports:
    - containerPort: 80

Nginx is unable to start due a permission issue:

$ kubectl logs nginx-userns
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (13: Permission denied)
2024/08/15 06:40:40 [emerg] 1#1: open() "/var/log/nginx/error.log" failed (13: Permission denied)

The pod runs fine if I remove hostUsers: false. Looking at the nginx image, what they do is create a symlink to /dev/stderr:

root@nginx-userns:/# ls -l /var/log/nginx/error.log 
lrwxrwxrwx. 1 root root 11 Aug 13 01:11 /var/log/nginx/error.log -> /dev/stderr

A way to get it running with user namespaces is to allocate a tty in the container:

spec:
  hostUsers: false
  containers:
  - name: nginx
    tty: true

So I'm not completely sure what is going on here but I have also been able to reproduce the issue by simply doing a cat /dev/stderr with basically any container image:

spec:
  hostUsers: false
  containers:
  - name: stdio-test
    image: alpine
    command: ["cat"]
    args: ["/dev/stderr"]

resulting in: cat: can't open '/dev/stderr': Permission denied

Steps to reproduce the issue

  1. Create an nginx pod with hostUsers: false as described above
  2. Observe the pod erroring with open() "/var/log/nginx/error.log" failed (13: Permission denied)

Edit: I have also tried to reproduce this using ctr run and using --uidmap etc. but I could not get it to fail that way.

Describe the results you received and expected

/dev/stdout and /dev/stderr are not accessible when using user namespaces and no tty is allocated. This works without user namespaces so I would expect this to also work with them enabled.

What version of containerd are you using?

containerd github.com/containerd/containerd/v2 v2.0.0-rc.3 27de5fe

Any other relevant information

$ runc --version
runc version 1.2.0-rc.2
commit: v1.2.0-rc.2-0-gf2d2ee5e-dirty
spec: 1.2.0
go: go1.22.3
libseccomp: 2.5.5

$ sha256sum /usr/bin/runc
7bf38e9bc6c7a3feb5ec92e5e333015ccd0f360cdd1810a5a13f5ab81731cd62  /usr/bin/runc

$ crictl info
{
  "status": {
    "conditions": [
      {
        "type": "RuntimeReady",
        "status": true,
        "reason": "",
        "message": ""
      },
      {
        "type": "NetworkReady",
        "status": true,
        "reason": "",
        "message": ""
      },
      {
        "type": "ContainerdHasNoDeprecationWarnings",
        "status": true,
        "reason": "",
        "message": ""
      }
    ]
  },
  "cniconfig": {
    "PluginDirs": [
      "/opt/cni/bin"
    ],
    "PluginConfDir": "/etc/cni/net.d",
    "PluginMaxConfNum": 1,
    "Prefix": "eth",
    "Networks": [
      {
        "Config": {
          "Name": "cni-loopback",
          "CNIVersion": "0.3.1",
          "Plugins": [
            {
              "Network": {
                "ipam": {},
                "type": "loopback"
              },
              "Source": "{\"type\":\"loopback\"}"
            }
          ],
          "Source": "{\n\"cniVersion\": \"0.3.1\",\n\"name\": \"cni-loopback\",\n\"plugins\": [{\n  \"type\": \"loopback\"\n}]\n}"
        },
        "IFName": "lo"
      },
      {
        "Config": {
          "Name": "portmap",
          "CNIVersion": "0.3.1",
          "Plugins": [
            {
              "Network": {
                "ipam": {},
                "type": "cilium-cni"
              },
              "Source": "{\"enable-debug\":false,\"log-file\":\"/var/run/cilium/cilium-cni.log\",\"type\":\"cilium-cni\"}"
            },
            {
              "Network": {
                "capabilities": {
                  "portMappings": true
                },
                "ipam": {},
                "type": "portmap"
              },
              "Source": "{\"capabilities\":{\"portMappings\":true},\"type\":\"portmap\"}"
            }
          ],
          "Source": "\n{\n  \"cniVersion\": \"0.3.1\",\n  \"name\": \"portmap\",\n  \"plugins\": [\n    {\n       \"type\": \"cilium-cni\",\n       \"enable-debug\": false,\n       \"log-file\": \"/var/run/cilium/cilium-cni.log\"\n    },\n    {\n      \"type\": \"portmap\",\n      \"capabilities\": {\"portMappings\": true}\n    }\n  ]\n}\n"
        },
        "IFName": "eth0"
      }
    ]
  },
  "config": {
    "containerd": {
      "defaultRuntimeName": "runc",
      "runtimes": {
        "runc": {
          "runtimeType": "io.containerd.runc.v2",
          "runtimePath": "",
          "PodAnnotations": null,
          "ContainerAnnotations": null,
          "options": {
            "BinaryName": "",
            "CriuImagePath": "",
            "CriuWorkPath": "",
            "IoGid": 0,
            "IoUid": 0,
            "NoNewKeyring": false,
            "Root": "",
            "ShimCgroup": "",
            "SystemdCgroup": true
          },
          "privileged_without_host_devices": false,
          "privileged_without_host_devices_all_devices_allowed": false,
          "baseRuntimeSpec": "",
          "cniConfDir": "",
          "cniMaxConfNum": 0,
          "snapshotter": "",
          "sandboxer": "podsandbox",
          "io_type": ""
        }
      },
      "ignoreBlockIONotEnabledErrors": false,
      "ignoreRdtNotEnabledErrors": false
    },
    "cni": {
      "binDir": "/opt/cni/bin",
      "confDir": "/etc/cni/net.d",
      "maxConfNum": 1,
      "setupSerially": false,
      "confTemplate": "",
      "ipPref": "",
      "useInternalLoopback": false
    },
    "enableSelinux": false,
    "selinuxCategoryRange": 1024,
    "maxContainerLogSize": 16384,
    "disableCgroup": false,
    "disableApparmor": false,
    "restrictOOMScoreAdj": false,
    "disableProcMount": false,
    "unsetSeccompProfile": "",
    "tolerateMissingHugetlbController": true,
    "disableHugetlbController": true,
    "device_ownership_from_security_context": false,
    "ignoreImageDefinedVolumes": false,
    "netnsMountsUnderStateDir": false,
    "enableUnprivilegedPorts": true,
    "enableUnprivilegedICMP": true,
    "enableCDI": true,
    "cdiSpecDirs": [
      "/etc/cdi",
      "/var/run/cdi"
    ],
    "drainExecSyncIOTimeout": "0s",
    "ignoreDeprecationWarnings": null,
    "containerdRootDir": "/var/lib/containerd",
    "containerdEndpoint": "/run/containerd/containerd.sock",
    "rootDir": "/var/lib/containerd/io.containerd.grpc.v1.cri",
    "stateDir": "/run/containerd/io.containerd.grpc.v1.cri"
  },
  "golang": "go1.22.4",
  "lastCNILoadStatus": "OK",
  "lastCNILoadStatus.default": "OK"
}

$ uname -a
Linux hostname 6.6.36-flatcar #1 SMP PREEMPT_DYNAMIC Mon Jul  1 22:47:51 -00 2024 x86_64 Intel(R) Xeon(R) Silver 4210R CPU @ 2.40GHz GenuineIntel GNU/Linux

Note: I'm not sure why this runc version is "dirty", the checksum matches the one of the release artifacts.

Show configuration if it is related to CRI plugin.

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions