Skip to main content

权限模型

SPC(系统权限控制)概述

TOS 7 引入 SPC(System Permission Control,系统权限控制) 系统,遵循最小权限原则,对应用的系统访问行为进行管控:

  • 应用无法直接修改系统文件或获取 root 权限,所有权限请求需通过平台 API 提交
  • 开发者需在权限声明中明确应用的权限需求,应用只有经平台审核通过后才能获得对应的访问权限
  • 禁止任何绕过 SPC 权限检查的行为,此类应用将无法通过审核或被下架

概述

TOS7 遵循 最小权限原则。应用只能请求运行所必需的最小权限。TOS7 应用与 SPC(系统权限控制) 系统交互。应用必须:

  • 在权限声明(第 8 节)中声明权限需求
  • 不得绕过 SPC 权限检查
  • 使用平台 API 进行权限请求,而不是直接修改系统文件

平台为 Deb 和 Docker 应用提供结构化的权限模型。

用户与用户组模型

严禁应用用户使用 root 权限。所有应用必须以非 root 专属用户运行。

Deb 应用:

场景用户说明配置要求
专属用户<appid>必须使用。由 preinst 脚本创建。权限最小。强制

强制要求: 所有 Deb 应用必须创建专属用户(<appid>),并以该用户运行应用,严禁使用 root 权限。专属用户需在 preinst 脚本中创建,确保应用运行时权限最小化。应用数据目录(如 /Volume*/@apps/<appid>/)的权限需设置为专属用户所有,避免权限不足或越权访问。

创建专属用户:

# 在 preinst 中
# 系统将自动为新用户分配唯一的 UID
useradd --system --no-create-home --shell /usr/sbin/nologin <appid>

Docker 应用:

场景用户说明
非 rootUID:GID(如 1000:1000必须使用。在 compose 中通过 user 字段指定。

文件系统权限

Deb 应用的标准目录权限:

路径归属权限说明
/Volume*/@apps/<appid>/<appid>:<appid>755应用目录(服务只读)
/Volume*/@apps/<appid>/bin/<appid>:<appid>755可执行文件
/Volume*/@apps/<appid>/config/<appid>:<appid>750配置文件(服务只读)
/Volume*/@apps/<appid>/site/<appid>:<appid>755Web UI 文件
/Volume*/@apps/<appid>/data/<appid>:<appid>750运行时数据(读写)
/Volume*/@apps/<appid>/logs/<appid>:<appid>750应用日志(读写)

注意 1: /Volume*/ 中的 * 表示用户在安装时所选的卷号(例如 Volume1、Volume2)。
注意 2: 应用二进制和配置文件对服务用户应为只读。只有数据和日志目录应为可写。
注意 3:数据类型

  • 运行时数据/Volume*/@apps/<appid>/data/)—— 应用生成的缓存、临时文件和运行时状态。此数据由应用管理,可安全重新生成。
  • 用户数据(通过 ter_share_add 创建的共享文件夹)—— 持久化的业务数据(文档、照片、数据库)。此数据必须存储在 /Volume*/ 下的共享文件夹中,以便用户通过 SMB/NFS 访问。

网络权限

权限Deb 应用Docker 应用说明
绑定端口在服务配置中绑定指定端口在 compose 中映射端口不得与系统端口冲突
访问本地服务默认允许使用 network_mode: host 或显式链接尽量减少网络暴露
出站连接允许允许出站无限制

共享文件夹访问

TNAS 共享文件夹是主要的数据访问机制。需要访问用户数据的应用必须:

  1. 创建共享文件夹,通过 ter_share_add
ter_share_add -name <appid>-data -owner <appid>
  1. 或请求访问现有共享文件夹,通过加入 allusers 组:
usermod -aG allusers <appid>
  1. Docker 应用通过卷挂载共享文件夹:
Volumes:
- /Volume*/<共享文件夹>:/data:rw # 读写访问
- /Volume*/<共享文件夹>:/media:ro # 只读访问
重要

应用不得直接修改共享文件夹权限。使用 TOS 共享文件夹管理 API 或让用户手动配置访问权限。

权限请求流程

当应用需要访问共享文件夹时:

  1. 专用应用文件夹(推荐):

    • 在 postinst 中通过 ter_share_add 创建
    • 应用拥有完整的读写权限
    • 无需用户授权
  2. 用户共享文件夹(需要授权):

    • 应用请求 allusers 组成员资格
    • 用户通过 TOS 共享文件夹设置授权文件夹访问
    • 应用在权限声明中注明只读或读写需求
  3. 权限格式

    # Docker 卷
    - /Volume*/<共享文件夹>:/data:rw # 读写访问
    - /Volume*/<共享文件夹>:/media:ro # 只读访问

系统资源限制

应用安装路径

第三方应用完整安装在 存储卷(数据盘)上的 /Volume*/@apps/<appid>/而不是系统盘(/)

  • * 表示用户在安装时所选的卷号(例如 Volume1、Volume2 等)。
  • 所有应用文件——包括二进制文件、配置文件、日志、脚本和 Web UI 文件——均存储在 /Volume*/@apps/<appid>/ 下。
  • 系统盘上仅保留轻量级的 注册/入口记录(用于 TOS 识别已安装的应用)。此记录占用空间可忽略不计,不构成任何容量问题。
  • 只有系统内置应用才驻留在系统盘(/usr/local/system_app_data/)上。

对第三方开发者而言: 由于整个应用(包括程序文件、配置和日志)安装在数据盘上,系统盘容量对您的应用不是问题。所有业务数据也应存储在数据盘(/Volume*/)上,数据盘没有容量限制。

按应用类型的默认资源配额:

应用类型CPU 限制内存限制示例
媒体服务器200%(2 核)2048MJellyfin, Plex, Emby
下载管理器100%(1 核)512MAria2, qBittorrent
实用工具50%256M文件管理器, 文本编辑器
Web 服务100%(1 核)512MCMS, 博客, Wiki
数据库200%(2 核)2048MMySQL, PostgreSQL, Redis
安全类50%256M防火墙, 杀毒软件

以上为平台默认值。开发者可在权限声明中附合理理由申请更高的限制。

Deb 应用(通过 systemd):

[Service]
# 内存限制
MemoryMax=512M
# CPU 配额(200% = 2 核)
CPUQuota=200%
# 文件描述符限制
LimitNOFILE=65536
# 进程数限制
LimitNPROC=256

Docker 应用(通过 compose):

services:
myapp:
deploy:
resources:
limits:
cpus: '2.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 128M

权限声明

注意: 下表是一个 示例,展示如何记录应用的权限需求。请将表中的值(端口号、文件路径、用户名)替换为应用实际使用的值。

为保持透明,应用应在 README.md 中记录其权限需求:

权限理由
网络:端口 <你的端口>Web UI 访问
文件系统:<你的数据路径>运行时数据存储
用户:<你的 appid>(系统用户)隔离的服务执行
共享文件夹:无不需要用户数据访问

权限红线(自动驳回)

以下权限请求将导致 自动驳回

违规行为说明
Root 执行请求 root 用户运行应用(包括在 systemd 服务文件中设置 User=root,以及在 Docker 中不指定 user 字段(默认以 root 运行)两种情况)
特权模式请求 --privileged Docker 模式
系统目录写入请求写入 /etc//usr//boot/ 等系统目录
跨应用数据访问请求访问其他应用的数据目录
无限制网络访问未提供书面合理理由而申请 network_mode: host(仅系统级网络工具可申请)
过多端口暴露请求超过功能所需的端口数量