第 8 章 - Flatpak 集成
第 8 章:Flatpak 集成
本章介绍 Bubblewrap 与 Flatpak 的深度集成关系,包括 Flatpak 如何使用 bwrap 创建应用沙箱、权限管理机制以及门户 API(Portal API)的使用。
8.1 Flatpak 与 Bubblewrap 的关系
Flatpak 是一个 Linux 桌面应用分发框架,其核心沙箱机制完全依赖 Bubblewrap。
架构关系
┌───────────────────────────────────────────────────┐
│ 用户界面 │
│ (GNOME Software, KDE Discover) │
├───────────────────────────────────────────────────┤
│ Flatpak 框架 │
│ ┌─────────────────────────────────────────────┐ │
│ │ flatpak-builder flatpak run │ │
│ │ (构建工具) (运行时管理) │ │
│ └─────────────────────────────────────────────┘ │
├───────────────────────────────────────────────────┤
│ Bubblewrap 沙箱层 │
│ ┌─────────────────────────────────────────────┐ │
│ │ bwrap --ro-bind ... --unshare-all ... │ │
│ │ (命名空间隔离、文件系统控制) │ │
│ └─────────────────────────────────────────────┘ │
├───────────────────────────────────────────────────┤
│ Linux 内核 │
│ Namespace | seccomp | cgroup | SELinux/AppArmor │
└───────────────────────────────────────────────────┘
Flatpak 使用 bwrap 的方式
当你运行 flatpak run 时,Flatpak 会:
- 根据应用的权限声明,构建
bwrap命令行参数 - 设置文件系统挂载点(运行时、应用、SDK)
- 配置命名空间隔离
- 设置门户 API 通信
- 通过
bwrap启动应用进程
# 查看 Flatpak 实际执行的 bwrap 命令
flatpak run --command=cat org.gnome.Calculator /dev/null 2>&1 &
FLATPAK_PID=$!
# 查看进程树
pstree -p $FLATPAK_PID
# 或者使用 strace 追踪
# strace -f -e clone,clone3 flatpak run org.gnome.Calculator 2>&1 | grep bwrap
8.2 Flatpak 沙箱结构
文件系统布局
Flatpak 应用的文件系统:
/
├── app/ → 应用自身文件 (ro-bind)
│ └── org.gnome.Calculator/
│ ├── bin/
│ ├── lib/
│ └── share/
├── usr/ → 运行时 (ro-bind)
│ ├── bin/
│ ├── lib/
│ └── share/
├── etc/ → 配置 (ro-bind 部分)
├── tmp/ → tmpfs
├── var/ → 应用数据
│ └── data/
│ └── org.gnome.Calculator/
├── home/ → 沙箱化主目录 (tmpfs)
│ └── user/
│ ├── .var/
│ │ └── app/
│ │ └── org.gnome.Calculator/
│ │ ├── data/ → 持久存储
│ │ ├── config/ → 持久配置
│ │ └── cache/ → 缓存
│ └── (其他目录通常是 tmpfs)
├── run/ → tmpfs
│ ├── host/ → 宿主部分目录
│ ├── user/ → 用户运行时
│ └── flatpak/
└── dev/ → 最小 dev
命名空间配置
| 命名空间 | Flatpak 默认 | 说明 |
|---|---|---|
| User | ✅ | 应用在 user namespace 中运行 |
| Mount | ✅ | 独立的文件系统视图 |
| PID | ✅ | 只看到自己的进程 |
| Network | ⚠️ 可选 | 默认共享宿主网络,可禁用 |
| UTS | ✅ | 独立主机名 |
| Cgroup | ✅ | 隐藏宿主 cgroup |
| IPC | ✅ | 隔离 IPC |
8.3 Flatpak 权限管理
权限类型
| 权限类型 | 说明 | 示例 |
|---|---|---|
| 文件系统 | 访问宿主文件系统 | --filesystem=home, --filesystem=xdg-download |
| 设备 | 访问硬件设备 | --device=dri (GPU), --device=all |
| 网络 | 网络访问 | --share=network |
| IPC | 共享 IPC | --allow=bluetooth |
| Socket | 使用特定 socket | --socket=x11, --socket=wayland, --socket=pulseaudio |
| 功能 | 启用特定功能 | --own-name=org.example.App |
| 环境 | 环境变量 | --env=VAR=value |
查看应用权限
# 查看已安装应用的权限
flatpak info --show-permissions org.gnome.Calculator
# 或
flatpak permission-show org.gnome.Calculator
# 查看应用元数据中的权限声明
cat ~/.local/share/flatpak/app/org.gnome.Calculator/current/active/metadata
# 使用 flatpak override 查看/修改权限
flatpak override --show org.gnome.Calculator
管理应用权限
# 授予额外权限
# 允许访问下载目录
flatpak override --filesystem=xdg-download org.gnome.Calculator
# 禁止网络访问
flatpak override --unshare=network org.gnome.Calculator
# 允许访问特定目录
flatpak override --filesystem=/mnt/data org.gnome.Calculator
# 撤销权限
flatpak override --nofilesystem=xdg-download org.gnome.Calculator
# 重置所有覆盖
flatpak override --reset org.gnome.Calculator
权限对照表
| 权限命令 | bwrap 等效 | 说明 |
|---|---|---|
--filesystem=home | --bind $HOME /home/user | 访问整个主目录 |
--filesystem=xdg-download | --bind ~/Downloads /home/user/Downloads | 仅访问下载目录 |
--unshare=network | --unshare-net | 禁用网络 |
--share=network | (不使用 –unshare-net) | 启用网络 |
--device=dri | --dev-bind /dev/dri /dev/dri | GPU 访问 |
--socket=x11 | --bind /tmp/.X11-unix /tmp/.X11-unix | X11 显示 |
8.4 门户 API(Portal API)
什么是门户 API
门户 API 是 Flatpak 的安全 IPC 机制,允许沙箱内的应用通过受控的方式访问宿主系统的资源,而不需要直接的文件系统或设备权限。
沙箱应用 门户守护进程 宿主系统
┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
│ │ D-Bus │ │ │ │
│ 应用代码 │ ──────────→│ xdg-desktop- │ ──────→│ 文件系统 │
│ │ │ portal │ │ 打印机 │
│ "请打开文件"│ ←──────────│ │ ←──────│ 通知系统 │
│ │ │ "用户选择了 │ │ 摄像头 │
│ │ │ 这个文件" │ │ ... │
└──────────────┘ └──────────────────┘ └──────────────┘
常用门户
| 门户 | 功能 | 用户体验 |
|---|---|---|
| 文件选择器 | 打开/保存文件对话框 | 用户通过对话框选择文件 |
| 打印 | 打印文档 | 调用系统打印对话框 |
| 通知 | 发送桌面通知 | 显示在通知栏 |
| 位置 | 获取地理位置 | 弹出权限请求 |
| 屏幕截图 | 截取屏幕 | 用户确认后截图 |
| 屏幕共享 | 共享屏幕内容 | 用户确认后共享 |
| 通知 | 发送通知 | 显示在系统通知中 |
| 打开 URI | 打开 URL | 用默认浏览器打开 |
| 壁纸 | 设置壁纸 | 用户确认 |
使用门户 API
# 测试文件选择器门户(需要 xdg-desktop-portal)
flatpak run --command=bash org.gnome.Calculator -c '
# 使用 gdbus 调用文件选择器门户
gdbus call --session \
--dest org.freedesktop.portal.Desktop \
--object-path /org/freedesktop/portal/desktop \
--method org.freedesktop.portal.OpenFile.OpenFile \
"" "选择文件" "options" "{}"
'
门户 API 安全模型
传统模式(无门户):
应用 → 直接访问文件系统 → 可能访问敏感文件
门户模式:
应用 → 请求文件 → 用户选择 → 应用只能访问用户选择的文件
↑
用户控制点
| 对比项 | 直接访问 | 门户 API |
|---|---|---|
| 安全性 | 低(全盘访问) | 高(用户授权) |
| 用户体验 | 无需交互 | 需要用户确认 |
| 隐私保护 | 弱 | 强 |
| 实现复杂度 | 简单 | 较复杂 |
| 可审计性 | 差 | 好(可记录授权历史) |
8.5 Flatpak 应用开发
创建 Flatpak 应用清单
# org.example.MyApp.yml
app-id: org.example.MyApp
runtime: org.freedesktop.Platform//23.08
runtime-version: '23.08'
sdk: org.freedesktop.Sdk//23.08
command: myapp
# 应用权限
finish-args:
# 允许显示 GUI(Wayland)
- --socket=wayland
# 允许显示 GUI(X11 fallback)
- --socket=fallback-x11
# 允许网络访问
- --share=network
# 允许访问下载目录
- --filesystem=xdg-download
# 禁止访问其他用户的目录
- --no-filesystem=home
# 允许 GPU 加速
- --device=dri
modules:
- name: myapp
buildsystem: meson
sources:
- type: archive
url: https://example.com/myapp-1.0.tar.gz
sha256: abc123...
构建和测试
# 构建 Flatpak 应用
flatpak-builder --force-clean build-dir org.example.MyApp.yml
# 安装本地构建
flatpak-builder --user --install --force-clean build-dir org.example.MyApp.yml
# 运行应用
flatpak run org.example.MyApp
# 查看沙箱配置
flatpak info --show-permissions org.example.MyApp
# 调试模式运行
flatpak run --devel --command=bash org.example.MyApp
查看底层 bwrap 命令
# 使用 strace 捕获 flatpak 的 bwrap 调用
strace -f -e trace=clone,clone3,execve \
flatpak run org.gnome.Calculator 2>&1 | grep bwrap
# 或者通过 Flatpak 的调试选项
flatpak run --verbose org.gnome.Calculator 2>&1 | grep "bwrap\|bubblewrap"
8.6 Flatpak 运行时与 SDK
运行时层次
Flatpak 运行时架构:
┌─────────────────────────────────────┐
│ 应用 (org.example.App) │
│ ┌───────────────────────────────┐ │
│ │ 应用代码 + 独立依赖 │ │
│ └───────────────────────────────┘ │
├─────────────────────────────────────┤
│ 运行时 (Runtime) │
│ ┌───────────────────────────────┐ │
│ │ 共享库、字体、基础工具 │ │
│ │ (GLib, GTK, Mesa, ...) │ │
│ └───────────────────────────────┘ │
├─────────────────────────────────────┤
│ SDK (构建时) │
│ ┌───────────────────────────────┐ │
│ │ 编译器、头文件、开发工具 │ │
│ │ (gcc, meson, pkg-config...) │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
常用运行时
| 运行时 | 版本 | 包含内容 |
|---|---|---|
org.freedesktop.Platform | 23.08 | 基础 Linux 用户空间 |
org.gnome.Platform | 45 | GNOME 库和工具 |
org.kde.Platform | 6.6 | KDE 库和工具 |
8.7 高级:自定义 Flatpak 沙箱
使用 flatpak override 深度定制
# 挂载自定义目录到沙箱
flatpak override --filesystem=/mnt/shared-data org.gnome.TextEditor
# 设置自定义环境变量
flatpak override --env=EDITOR=vim org.gnome.TextEditor
# 禁用 D-Bus 访问
flatpak override --no-talk-name=org.freedesktop.secrets org.gnome.TextEditor
# 限制 socket 访问
flatpak override --no-socket=pulseaudio org.gnome.TextEditor
# 查看所有覆盖
flatpak override --show org.gnome.TextEditor
Flatpak 权限影响 bwrap 的方式
| Flatpak 权限 | 底层 bwrap 效果 |
|---|---|
--filesystem=home | --bind $HOME /home/user |
--filesystem=host | --bind / /run/host (受限) |
--filesystem=/path | --bind /path /run/host/path |
--no-filesystem | 仅 tmpfs 主目录 |
--unshare=network | --unshare-net |
--device=all | --dev-bind /dev /dev |
--device=dri | --dev-bind /dev/dri /dev/dri |
8.8 Flatpak 沙箱调试
进入沙箱调试
# 以开发模式进入沙箱
flatpak run --devel --command=bash org.gnome.Calculator
# 在沙箱内查看环境
ls /
mount
cat /proc/self/uid_map
id
# 检查可用的库
ldconfig -p | grep gtk
# 退出
exit
查看沙箱日志
# 查看 Flatpak 运行时日志
flatpak run --log-session-bus --log-system-bus org.gnome.Calculator
# 使用 journalctl 查看相关日志
journalctl --user -f | grep -i flatpak
# 查看门户日志
journalctl --user -f | grep -i portal
常见问题排查
# 问题: 应用无法访问文件
# 解决: 检查并添加文件系统权限
flatpak override --filesystem=xdg-download org.example.App
# 问题: 应用无法联网
# 解决: 确认网络权限
flatpak info --show-permissions org.example.App | grep network
# 问题: 应用无法显示
# 解决: 检查显示 socket
flatpak override --socket=wayland org.example.App
flatpak override --socket=x11 org.example.App
# 问题: GPU 加速不工作
# 解决: 授予 DRI 权限
flatpak override --device=dri org.example.App
8.9 Flatseal:图形化权限管理
Flatseal 是一个图形化的 Flatpak 权限管理工具。
# 安装 Flatseal
flatpak install flathub com.github.tchx84.Flatseal
# 运行
flatpak run com.github.tchx84.Flatseal
Flatseal 提供的功能:
- 查看和修改每个应用的权限
- 实时预览权限更改
- 权限说明和文档
- 重置到默认权限
8.10 不使用 Flatpak 的 bwrap 集成
模拟 Flatpak 的沙箱模式
即使不使用 Flatpak,你也可以利用 bwrap 创建类似的沙箱环境:
#!/bin/bash
# flatpak-like-sandbox.sh - 模拟 Flatpak 沙箱
APP_NAME="$1"
shift
# 应用数据目录
APP_DATA="$HOME/.local/share/sandbox/$APP_NAME"
mkdir -p "$APP_DATA"/{data,config,cache}
exec bwrap \
--ro-bind / / \
--dev /dev \
--proc /proc \
--tmpfs /tmp \
--tmpfs /run \
--unshare-all \
--hostname "$APP_NAME" \
--die-with-parent \
--new-session \
--bind "$APP_DATA/data" "/home/user/.var/app/$APP_NAME/data" \
--bind "$APP_DATA/config" "/home/user/.var/app/$APP_NAME/config" \
--bind "$APP_DATA/cache" "/home/user/.var/app/$APP_NAME/cache" \
--clearenv \
--setenv HOME /home/user \
--setenv XDG_DATA_HOME /home/user/.var/app/$APP_NAME/data \
--setenv XDG_CONFIG_HOME /home/user/.var/app/$APP_NAME/config \
--setenv XDG_CACHE_HOME /home/user/.var/app/$APP_NAME/cache \
"$@"
使用:
# 在沙箱中运行 vim
./flatpak-like-sandbox.sh myeditor vim /tmp/test.txt
# 在沙箱中运行 Python
./flatpak-like-sandbox.sh mypython python3
8.11 注意事项
⚠️ 重要提醒
Flatpak 的 bwrap 调用是自动生成的:不要尝试手动修改 Flatpak 生成的 bwrap 命令,应使用
flatpak override修改权限。门户 API 需要守护进程:
xdg-desktop-portal必须在宿主上运行,否则门户功能不可用。GPU 访问需要 DRI 权限:
--device=dri对于图形应用至关重要,否则会使用软件渲染。X11 转发的安全性:
--socket=x11允许应用截取屏幕和记录按键。推荐使用 Wayland。运行时版本:保持运行时更新,以获得安全修复。
--filesystem=host是危险权限:授予对宿主文件系统的广泛访问权限,应尽量避免。
8.12 扩展阅读
上一章:第 7 章 - 安全策略 | 下一章:第 9 章 - Docker 中使用