# Podman 挂载目录 Permission Denied：SELinux 导致的一个坑


使用 Podman 挂载主机目录到容器时，即使容器内是 root 用户，也可能遇到 `Permission denied` 错误。本文将解释这一现象的根源——SELinux，并提供修复方法。

## 问题场景

我在配置一个 Quadlet 管理的服务，Quadlet `.container` 文件大致如下：

```ini
[Container]
Entrypoint=/app/entry.sh
Image=docker.io/library/alpine:3.15
Pod=sniproxy.pod
Volume=/home/nite/pod/sniproxy/data/bin:/app:ro
Volume=/home/nite/pod/sniproxy/data/etc:/config:ro

[Service]
Restart=always

[Install]
WantedBy=default.target
```

配置完成后，`systemctl --user daemon-reload` 并 `systemctl --user start sniproxy.service`，服务启动失败。

通过 `journalctl` 查看日志，发现是 `Permission denied` 错误。为验证，我将 Entrypoint 注释掉，设置 `Exec=sleep infinity`，重启服务后 `podman exec` 进入容器，执行 `ls -l /app` 同样报 `Permission denied`。

容器内是 root 用户，传统的文件权限（owner、group、other）检查应该放行，问题显然出在别处。

## 根本原因：SELinux

在 Fedora、CentOS、RHEL 等启用了 SELinux 的发行版上，文件访问受到 SELinux 安全上下文的额外约束。

Podman 启动容器时，容器内的进程会被赋予一个 SELinux 标签，通常是 `container_t`。而主机家目录下创建的目录（如 `~/sniproxy/data`），默认标签是 `user_home_t`。

SELinux 的默认策略明确禁止持有 `container_t` 标签的进程访问 `user_home_t` 标签的目录。这是出于安全考虑：防止容器内的进程（即使被攻破）读取或破坏主机上的个人文件。

所以`Permission denied` 并不是因为传统权限不够，而是 SELinux 策略阻止了 `container_t` 对 `user_home_t` 的访问。

## 解决方案：修改 SELinux 标签

解决方法是让 Podman 在挂载时修改目录的 SELinux 标签。在卷定义的末尾加上：

- `:z`：将目录标签改为 `container_file_t`，这是一个**共享**标签，多个容器都可以访问。
- `:Z`：为目录创建一个**私有**标签，仅该容器可访问。

对于大多数场景，`:z` 是最常用的选择。

**修改前**：

```ini
Volume=/home/nite/pod/sniproxy/data/bin:/app:ro
Volume=/home/nite/pod/sniproxy/data/etc:/config:ro
```

**修改后**：

```ini
Volume=/home/nite/pod/sniproxy/data/bin:/app:ro,z
Volume=/home/nite/pod/sniproxy/data/etc:/config:ro,z
```

修改完 Quadlet 文件后，执行：

```bash
systemctl --user daemon-reload
systemctl --user restart sniproxy.service
```

现在 `podman exec` 进入容器，`ls -l /app` 可以正常工作了。


---

> 作者: Nite  
> URL: https://www.nite07.com/zh-cn/posts/podman-selinux/  

