ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

用 spk 为 Sandstorm 手工打包应用:原始打包(Raw Packaging)完整实战指南

用 spk 为 Sandstorm 手工打包应用:原始打包(Raw Packaging)完整实战指南 后端容器运行时安全云原生【免费下载链接】sandstormSandstorm is a self-hostable web productivity suite. Its implemented as a security-hardened web app package manager. | Actively sponsored by our friends at TestMu AI项目地址https://gitcode.com/gh_mirrors/sa/sandstorm点击查看免费下载Sandstorm 应用本质上是一个包含完整用户态全部二进制、库、模块的加密签名压缩包.spk而spk工具链允许你跳过vagrant-spk等辅助框架直接手工构建这种包。本指南以官方原始打包教程为主体结合本仓库的spk实现源码与真实包定义示例带你从零走完编写应用 →spk init生成包定义 →spk dev采集依赖 →spk pack产出可分发包的完整流程并深入理解包定义文件的每个字段、签名与密钥环机制使你能独立打包任何能在 Linux 上运行的技术栈应用。什么是原始打包Raw PackagingSandstorm 的打包工具有两代思路vagrant-spk通过虚拟机辅助构建适合快速上手而本文介绍的raw packaging直接使用spk命令行工具让你完全掌控包的生成过程从而更深入地理解 Sandstorm 的包格式与运行模型。本仓库的 spk.c 就是该工具的实现其命令行帮助信息将其定位为Tool for building and checking Sandstorm package files.构建与校验 Sandstorm 包文件的工具一个 Sandstorm 应用包包含运行应用所需的整个用户态——所有二进制、库、模块等。正常情况下逐一手工确定该把哪些文件放进包是极其繁琐的。Sandstorm 用一个巧妙的技巧解决这个问题它在你开发机器上观察正在运行的服务器把服务器实际用到的所有文件自动拉入包中。这个观察机制在源码层面由 FUSE 文件系统实现见下文开发模式一节。提示如果你是打包新手或主力操作系统不是 Linux建议先阅读 五分钟打包教程再回到本文深入学习。环境准备前置条件在开始之前你需要满足以下条件了解 Sandstorm 的基本概念先实际试用 Sandstorm官方演示站以感受其运行方式阅读 App 开发者手册 理解 Sandstorm 应用面临的更高层设计问题。在本地机器安装 Sandstorm 开发环境安装 Linux内核版本需为 3.10 或以上Ubuntu 14.04 及以上即可满足安装 Sandstorm 官方服务器curl https://install.sandstorm.io | bash该本地服务器将用于开发联调请确保其处于运行状态务必把自己加入服务器用户组通常名为sandstorm。修改用户组后可能需要注销并重新登录才能生效——spk dev依赖这个组成员身份与本地服务器通信spk.c 中dev命令的说明明确要求Your user account must be a member of the servers group, typically sandstorm。安装完成后spk可执行文件位于 Sandstorm 安装目录如/opt/sandstorm/latest/bin/spk默认的包定义 schema 文件位于/opt/sandstorm/latest/usr/include/sandstorm/package.capnp仓库内的 package.capnp 就是它的同源副本注释中包含对包定义格式的完整说明。框架特化工具一览对某些框架Sandstorm 社区提供了特化工具或指南可以更轻松地打包Meteor使用meteor-spk工具本仓库的 meteor-testapp/sandstorm-pkgdef.capnp 就是一个基于 Meteor 的真实包定义示例其myCommand通过sandstorm-http-bridge启动node start.jsPython参见 Python 打包指南Ruby on Rails参见 Ruby on Rails 打包指南纯客户端 / 浏览器端应用Unhosted / remoteStorage 风格参见 纯客户端应用移植指南。即使你的框架在上面的列表里也仍然应该完整阅读本页以便更深入地理解 Sandstorm 的运行机制。打包流程从编写应用到产出 .spk下面用一个最简单的 Node.js 应用走完五个通用步骤。第一步编写应用你可以用任何能在 Linux 上运行的技术栈编写应用按平时的方式写 Web 应用即可。唯一的硬性约束是应用的所有数据必须存放在/var下因为在 Sandstorm 中运行时文件系统的其余部分都是只读的。为了本教程我们使用下面这个极简 Node.js 应用文件名为main.jsvar http require(http); http.createServer(function (req, res) { res.writeHead(200, {Content-Type: text/plain}); res.end(Hello World\n); }).listen(10000, 127.0.0.1); console.log(Server running at http://127.0.0.1:10000/);确保本机已安装 Node使你在应用源码目录执行node main.js时它能够正常运行。第二步创建包定义spk init在应用的源码目录中执行spk init -p 10000 -- node main.js该命令告诉 Sandstorm启动应用的命令是node main.js应用启动后监听 10000 端口的 HTTP 接口。命令执行后会生成sandstorm-pkgdef.capnp文件其中保存了新的配置——你可以打开查看大量字段都可以自行调整。spk init的完整选项来自 spk.c 中getInitMain()的实现L535-L563选项含义-p port设置应用监听的 HTTP 端口即command将绑定的端口应用将使用 Sandstorm 的 HTTP 桥sandstorm-http-bridge而不是裸 Sandstorm API。端口必须在 1024~65535 之间低于 1024 的特权端口在沙箱内不可用同时-p与-r互斥-r/--raw声明应用直接实现裸 Sandstorm APICapn Proto 协议不经过 HTTP 桥与-p互斥。-p与-r至少必须指定其一-A/--include-all直接包含-I指定目录下的全部内容而不是在 dev 模式下动态探测所需文件使用-A时必须至少指定一个-I-I path向依赖文件的搜索路径中追加一个目录可多次指定不指定时默认搜索.当前目录再搜索/系统根目录且默认隐藏敏感目录-o filename把包定义写到指定文件而非sandstorm-pkgdef.capnp-o -表示写到标准输出-i app-id使用给定的应用 ID 而非新生成一个ID 只能包含字母数字spk init生成的包定义默认采用开发模式动态收集依赖方案即写入fileList sandstorm-files.list。如果你在 dev 模式下没有运行过应用就执行spk pack工具会提示sandstorm-files.list does not exist. Have you run spk dev yet?见 spk.c L1047-L1052。第三步开发模式测试spk dev仍然在包目录下执行spk devspk dev会临时把你正在开发的应用注册到本地 Sandstorm 服务器上。此时浏览服务器打开文件菜单就能看到该应用并创建新实例——请创建实例并确认其工作正常。开发模式下的关键注意事项务必测试应用的所有功能。Sandstorm 正在观察应用运行时打开的所有文件并据此生成运行时依赖清单。如果某个功能在 dev 模式下没有测试到那么它用到的文件可能不会被收录进包生产环境就会出问题应用的控制台debug输出可以通过点击顶栏的控制台图标查看如果应用日志不足以定位问题可以查看 Sandstorm 服务器的主日志/opt/sandstorm/var/log/sandstorm.log测试结束后在终端按CtrlC退出 dev 模式。从源码层面看spk dev的运行机制非常精巧spk.c L1890-L2156它首先定位本地 Sandstorm 服务器默认根据spk可执行文件的安装位置推断或通过/etc/init.d/sandstorm定位找不到时可用-s dir显式指定通过 Unix socketpair 向服务器的sandstorm dev子命令传递应用 ID并接收服务器返回的FUSE 文件描述符spk用makeUnionFs()将sourceMap映射的目录含sourceMap指定的所有源路径与运行时目录合并挂载成一个 FUSE 文件系统L2056应用进程对文件的每次打开open都会被 FUSE 层拦截路径被记录进usedFiles集合L2053-L2055退出时spk dev把usedFiles与既有sandstorm-files.list合并后重写该文件L2123-L2156。新文件会被加入但旧文件不会被自动移除想重置清单直接删除sandstorm-files.list再跑一次spk dev即可这也是 package.capnp 中fileList字段注释明确说明的行为。spk dev的常用选项选项含义-s dir连接到安装在dir的 Sandstorm 服务器-m dir不连接服务器仅把包内容挂载到dir便于手动探查-c/--cache开启 FUSE 文件系统激进缓存以提升性能但意味着每次修改代码后都必须重启spk dev才能生效--proc在沙箱内挂载/proc便于调试仅开发模式可用打包后的应用不会获得/proc访问权第四步检查文件清单spk已经生成了一个名为sandstorm-files.list的文本文件列出应用用到的所有文件。用文本编辑器打开并确认内容合理重点检查是否混入了你系统中的个人文件。默认配置会隐藏/home和/var能阻止大多数泄漏具体而言spk init生成的默认sourceMap在映射系统根目录/时会隐藏home、proc、sys、etc/passwd、etc/hosts、etc/host.conf、etc/nsswitch.conf、etc/resolv.confspk.c L653-L662而/dev、/var、/tmp由 Sandstorm 自身提供因此隐式隐藏特别留意来自/etc的文件。很多应用依赖/etc中的配置才能基本运行但/etc里的文件通常与你的主机系统高度绑定未必适合放进应用包。若应用需要覆盖某个/etc文件只需在源码树中创建etc目录并放入不同版本的文件——默认的sandstorm-pkgdef.capnp把.映射到包根目录/因此./etc/foo会优先于/etc/foo满足包对etc/foo的需求。如果发现清单中混入了不应包含的文件可以从清单中手动删除该行编辑sandstorm-pkgdef.capnp把这些文件列入hidePaths这样下次运行 dev 模式时不会被重新加入建议重新运行spk dev并再次测试应用。提示sandstorm-files.list是自动生成文件每次 dev 模式运行结束都会被按排序重写文件头有*** WARNING: GENERATED FILE ***警告spk.c L2148-L2155。你可以手动增删条目但不要依赖其中的注释与顺序。第五步构建分发包spk pack执行spk pack my-app.spk这会构建出可分发、可安装的my-app.spk。你可以通过任意 Sandstorm 服务器的/install路径上传安装它。spk pack的实现spk.c L959-L1073大致如下读取sandstorm-files.list若使用-A收集模式则跳过并通过sourceMap把每个条目映射到真实源文件同时合并alwaysInclude中列出的文件/目录目录会递归包含全部内容自动向包中注入特殊文件空的dev、tmp、var目录与空的proc/cpuinfo这些会在运行时被 supervisor 覆盖挂载、序列化后的sandstorm-manifest、以及使用 HTTP 桥时所需的sandstorm-http-bridge与sandstorm-http-bridge-configL1039-L1043、L1236-L1259对未压缩的归档做 SHA-512 哈希用应用私钥Ed25519/libsoodiumcrypto_sign对哈希签名把魔数 XZ 压缩后的签名 归档写入最终文件包的解压大小上限为1 GiB超限会直接拒绝打包L984-L989该限制是为了宿主机的安全。验证与解包spk verify与spk unpack发布前建议用spk verify my-app.spk校验包签名并查看从 manifest 提取的详细信息默认输出 JSON 格式含 appId、packageId、标题、版本、作者 PGP 指纹、元数据等见 spk.c L1814-L1880 与 package.capnp 的VerifiedInfo结构。spk unpack my-app.spk [outdir]则在校验签名后将包解压到指定目录默认去掉.spk后缀作为输出目录名。spk.h中声明的unpackSpk()与verifySpk()正是这两个操作的底层实现——它们在校验失败时会在写出任何文件之前抛出异常。发布到应用市场如果打包了一个很棒的应用可以查看 应用发布指南了解如何把应用提交到 Sandstorm 官方应用市场App Market。市场会自动处理包 ID 与版本相关事务。剖析 sandstorm-pkgdef.capnp包定义的每个字段spk工具会查找文件中名为pkgdef、类型为PackageDefinition的常量定义于 package.capnp L29-L70。仓库中的 meteor-testapp/sandstorm-pkgdef.capnp 是一个带完整注释的真实示例可作为模板参考。PackageDefinition 顶层结构字段说明id应用 ID 字符串实际是应用公钥的文本编码形如h37dm17aa89yrd8zuqpdn36p6zntumtv08fjpu8a8zrte7q1cn60。通常由spk init自动生成也可用spk keygen生成新 ID。向spk pack传-i标志可指定备选 ID适用于做非官方构建、不想用真实私钥的场景manifest写入包内sandstorm_manifest的清单描述应用如何启动与展示sourceMap指示从哪里搜索要纳入包的文件fileList指向一个逐行列出包内文件路径的文本文件即sandstorm-files.list每条路径按包内位置书写经sourceMap映射到源文件alwaysInclude无论是否出现在fileList中都必须包含的文件/目录目录递归包含。适合收录应用运行中不会打开、但应当随包分发的文件如 README、版权声明、难以完整测试的运行时依赖bridgeConfig使用sandstorm-http-bridge的应用的桥接配置manifest启动命令、动作与应用元数据Manifest结构定义于 package.capnp L72-L167关键字段actions定义新建文档处理器。每个Action通过nounPhrase声明创建对象的种类如文档编辑器创建documentUI 中显示为新建nounPhrasecommand指定首次启动实例时执行的命令continueCommand实例因空闲被关闭后重新启动时执行的命令。可以复用actions中的命令也可以为两种场景配置不同命令appTitle向用户显示的应用名appVersion整数版本号仅用于判断包的新旧版本更高的包视为更新版本不必与对外宣传版本号一致每次发布递增minUpgradableAppVersion本包可安全替换的最低旧版本若历史上有过破坏性数据格式变更可设为非零appMarketingVersion人类可读版本号如2.9.17用于展示minApiVersion/maxApiVersion应用已知可工作的平台 API 版本区间metadata不参与执行、但用于展示与市场分发的数据见下文。Command结构由argv参数列表argv[0]为程序名与environ环境变量列表组成。注意两点package.capnp L112-L131命令不经过 shell 解释。如果确实需要 shell 展开必须把 shell 二进制也打进包并显式调用它environ定义了应用看到的全部环境——除此之外的环境是空的。仓库示例中myCommand设置PATH/usr/local/bin:/usr/bin:/bin并导出SANDSTORM1应用可据此在运行时检测自己是否运行于 Sandstorm 内见 meteor-testapp/sandstorm-pkgdef.capnp。metadatapackage.capnp L301-L535主要字段icons四种上下文的图标——appGrid128×12864KB 上限、grain24×244KB、market150×15064KB、marketBig300×300256KB优先使用 SVG 格式website/codeUrl应用主页与源码仓库地址若许可证要求提供源码则codeUrl必填licensenone默认版权禁止再分发、openSourceOSI 批准的开源许可证枚举如 MIT、Apache-2.0、GPL-3.0、AGPL-3.0 等、proprietary专有许可证全文用户首次使用时需明确同意或publicDomainnotices用于附带第三方版权声明categories应用分类列表Productivity、Communications、Office、DevTools 等枚举authorcontactEmail务必填写真实有效的支持邮箱、upstreamAuthor若你只是打包了别人的应用、pgpSignature用 GPG 对I am the author of the Sandstorm.io app with the following ID: app-id消息做二进制分离签名用于在市场中验证作者身份pgpKeyring包含上述 PGP 公钥的 GPG keyring 数据descriptionGithub 风格 Markdown不允许含 HTML 与图片标签、shortDescription1~3 个词显示在市场网格视图、screenshots以设备无关像素标注宽高高 DPI 截图应把宽高填为实际像素的一半、changeLog。sourceMap依赖文件从哪来SourceMappackage.capnp L169-L193由若干Mapping组成每个映射定义sourcePath本地系统中该目录的路径相对路径相对于包定义文件所在位置解析packagePath该目录在包内的目标路径必须规范、不以/开头省略则映射到包根目录hidePaths映射时隐藏的文件/子目录名列表仅允许规范路径不得使用.、..或前导/。spk init默认生成两条映射(sourcePath .)优先搜索当前目录然后(sourcePath /)搜索系统根目录并隐藏home、proc、sys等敏感路径。多目录会以合并方式工作——若多个 sourcePath 都包含同一目标路径pack会合并这些目录的内容这正解释了源码树中放etc/foo即可覆盖系统/etc/foo的行为spk.c L1272-L1310。fileList 与 alwaysInclude两种文件收集模式动态收集模式默认fileList sandstorm-files.list由spk dev观察运行中的应用自动维护。优点上手快缺点清单可能因测试不充分而不完整全量包含模式alwaysInclude [.]配合-A/-I使用把指定目录下所有文件原样打入包。spk pack时若alwaysInclude含.则文件清单不再重要spk.c L2158-L2166。这种方式更接近确定性构建适合需要精确控制包内容的场景。仓库中的 meteor-testapp/sandstorm-pkgdef.capnp 正是使用alwaysInclude [.]的全量模式示例。bridgeConfigHTTP 桥接与权限角色BridgeConfigpackage.capnp L195-L299专为使用sandstorm-http-bridge的应用设计viewInfo定义可共享的权限permissions与角色roles。每次请求时桥接进程会把用户当前拥有的权限以逗号分隔的列表写入X-Sandstorm-Permissions请求头角色则显示在共享 UI 中。注意权限列表只能追加绝不能重排或删除已有字段否则会改变既有实例的行为与权限仓库示例 meteor-testapp/sandstorm-pkgdef.capnp 定义了一个editor权限和 editor/viewer 两个角色apiPath所有 API 请求经 API 端点进入的请求的前缀路径必须以/结尾。它只用于让 API URL 与 UI URL 分离不会限制 API 令牌持有者的访问范围——真正的访问控制必须通过权限并在 UI/API 两侧同时强制实施参见 HTTP API 文档saveIdentityCaps为true时新用户首次访问实例桥会保存其身份能力后续可通过getSavedIdentity获取做通知类功能通常需要它expectAppHooks为true时桥期望应用通过/tmp/sandstorm-api建立 Capn Proto 连接并实现AppHooks用于动态生成getViewInfo()或导出额外的持久能力powerboxApis声明应用通过 powerbox 对外导出的 HTTP API含名称、展示信息、路径前缀、tag与所需权限。签名、密钥环与应用 ID密码学机制你的应用包使用Ed25519算法做加密签名底层是 libsodium 的crypto_sign见 spk.h 与 package.capnp L689-L720。公钥就是应用的全局 ID——所有用同一把密钥签名的包都被视为同一应用的不同版本spk pack输出中会打印 app ID。spk init会为新应用自动创建一对密钥。密钥环文件对应的私钥被放入你的 Sandstorm 密钥环默认存储在$HOME/.sandstorm-keyringspk.c L394-L400可用-k path选项改用其他密钥环文件。这个文件必须妥善保管丢失它你将无法再为应用构建更新版本被窃取攻击者可以发布你的应用的更新包。spk的密钥相关命令命令作用spk listkeys列出密钥环上的所有密钥对应的应用 IDspk getkey app-id从密钥环中取出指定 ID 的密钥以 Capn Proto 消息形式输出到 stdoutspk help getkey查看用法spk keygen生成新的应用 ID 与签名密钥并存入密钥环新建应用时更推荐用spk initkeygen适用于更换密钥的场景密钥环合并直接把两个密钥环文件用cat拼接即可合并cat keys ~/.sandstorm-keyring这也是spk getkey帮助信息中推荐的把收到的密钥加入自己密钥环的方式。因此可以只把特定应用 ID 的密钥导出spk getkey发给发布负责人。开发模式不需要私钥spk dev在本地服务器注册应用时服务器直接信任你给出的 ID反正你对本地服务器有完全控制权因此私钥不需要分发给每个开发者——只有负责构建发布版本的人需要持有密钥。已知限制目前密钥环未加密因此对任何在你用户账号下运行的软件都可见。这在将来会改进但一般来说如果恶意软件能以你的身份运行问题就已经很严重了。包 ID数据包 ID如需获取某个包的数据包 ID可运行sha256sum package.spk | head -c 32; echo即取包文件 SHA-256 哈希的前 32 个十六进制字符。应用市场上线后这部分通常已自动处理手动计算已不再是重点。.spk 文件内部格式一个.spk包在磁盘上是这样组织的package.capnp L700-L7528 字节魔数\x8f\xc6\xcd\xef\x45\x1a\xea\x96——若未来包格式破坏兼容性此魔数会改变后续全部内容经XZ 压缩spk pack实际调用系统xz --threads0 --compress --stdout见 spk.c L1012-L1016压缩流内是两个 Capn Proto 消息SignaturepublicKey32 字节 libsodium 签名公钥其文本形式即应用 ID与signature对归档部分 SHA-512 哈希的签名Archive文件树files列表每个文件记录名称、纳秒精度修改时间以及内容regular / executable / symlink / directory 四种类型。spk verify正是解压后校验该签名并输出应用 IDspk unpack则在签名有效的前提下把文件树落地到目录。进阶技巧与最佳实践访问外部资源默认情况下应用没有任何网络访问权包括服务器端——它只能响应来自用户的 HTTP 请求。如果需要访问外部世界发起出站 HTTP 请求、收发电子邮件等必须通过 Sandstorm 的 API 申请相应能力。各类外部资源出站 HTTP、邮件等的接入指南见完整开发者文档。可复现构建上述直接从开发机复制文件的方式适合快速启动但不利于长期维护。当项目变得正式后应建立密闭hermetic构建环境让其他开发者可以轻松复现构建。方法是编辑sandstorm-pkgdef.capnp通过修改sourceMap让spk不从真实主机系统、而从你自己准备好的其他目录查找文件。例如在独立目录中搭建一个干净的 chroot 环境然后把sourceMap指向那里。chroot 环境的搭建细节超出本文范围属于通用的、与 Sandstorm 无关的成熟技术。测试升级兼容性当应用后续发生改动时可以用spk dev针对旧版本产生的既有数据做升级测试任何时候运行spk dev开发版应用都会临时覆盖已安装的版本——包括打开既有实例的场景。这让你可以在真实数据上验证升级路径而无需先卸载旧版本。什么样的应用适合 Sandstorm并非每个 Web 应用都适合做成 Sandstorm 应用。Sandstorm 面向的是数据逻辑上归用户所有的应用每个实例由单个终端用户拥有而非应用开发者用户可以与他人共享并协作但实例最终归属于个人。适合的场景文档编辑器、电子表格等内容创作工具邮件 / 聊天 / 通讯应用日历、待办清单、个人任务管理RSS 阅读器个人文件 / 媒体存储博客含微博客个人主页联邦式社交网络。不适合的场景公共搜索引擎新闻门户大型讨论论坛不过每个用户拥有自己创建的帖子线程的联邦式论坛可以成立内容分发服务在线商店中心化社交网络。用户可以为安装的任何应用创建多个实例。默认情况下每个实例相互隔离、可独立共享。应用应把实例粒度设计到共享有意义的最小单元例如文档编辑器应让每篇文档对应一个独立实例这样用户就能借助 Sandstorm 平台的共享功能来分享文档访问权。纯客户端应用Unhosted 风格在这点上尤其简单——把保存/加载位置选择删掉改为自动保存到/var下的固定路径即可参见纯客户端应用指南。常见问题与更多资料打包过程中卡住时先查 打包故障排查想深入理解 Sandstorm 应用设计的高层问题读 App 开发者手册涉及认证、权限、HTTP API、通知、调试等主题的完整文档见开发者文档总目录。最后如果你打包出了酷炫的 Sandstorm 应用并希望更多人用上它请按照应用发布指南提交到官方应用市场——带上spk原始打包学到的这层理解你会比大多数打包者更清楚自己的包里装的是什么。赞分享后端容器运行时安全云原生【免费下载链接】sandstormSandstorm is a self-hostable web productivity suite. Its implemented as a security-hardened web app package manager. | Actively sponsored by our friends at TestMu AI项目地址https://gitcode.com/gh_mirrors/sa/sandstorm点击查看免费下载相关推荐Moya响应式请求终极指南RxSwift、ReactiveSwift与Combine三大扩展实战对比Moya响应式请求终极指南RxSwift、ReactiveSwift与Combine三大扩展实战对比 Moya 是一个用 Swift 编写的网络抽象层库它基后端容器运行时安全云原生Sandstorm 打包定制实战深入理解并自定义 vagrant-spk 的 .sandstorm 目录Sandstorm 打包定制实战深入理解并自定义 vagrant spk 的 .sandstorm 目录 vagrant spk 是 Sandstorm 官方后端容器运行时安全云原生Johnny-Five 湿度传感器 DHT11 I2C Nano Backpack 接入指南Hygrometer 控制器用法与固件原理Johnny Five 湿度传感器 DHT11 I2C Nano Backpack 接入指南Hygrometer 控制器用法与固件原理 本文以 Johnny后端容器运行时安全云原生上一篇Klavis 仓库 Slack MCP Server 实战指南Stealth/OAuth 双模式、Smart History 与安全发信配置下一篇Node.js 12.0.0 发布全解读V8 7.4 与 TLS 1.3 带来的里程碑式升级Current 版创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表