- 虚拟化
- 开发工具
- 云原生
【免费下载链接】multipass
Multipass orchestrates virtual Ubuntu instances
本文围绕 Multipass 官方安全文档(docs/explanation/about-security.md)展开,深入解析 Multipass 守护进程(multipassd)的本地访问模型、跨平台 socket 传输方式,以及"TLS 客户端证书 +local.passphrase口令"两阶段认证体系。读完本文,你将掌握 Multipass 信任边界所在、为何必须限制 socket 访问权限、如何为多用户环境设置口令并完成authenticate认证,以及常见认证故障的修复方法,并可对照仓库源码验证每一处实现细节。
关联文档:Authentication · 如何为 Multipass 服务认证用户 ·
authenticate命令参考 ·local.passphrase设置参考
使用前提与安全警告:Multipass 不是生产环境方案
在深入安全机制之前,必须先明确 Multipass 的定位。官方安全文档在开篇即给出醒目的WARNING(docs/explanation/about-security.md):
Multipass 主要用于开发、测试和本地环境,并非为生产环境设计。在部署 Multipass 虚拟机之前,请仔细评估本页列出的安全考量。
这一告诫并非空话,而是由 Multipass 的架构直接决定的:Multipass 以**客户端-守护进程(client-daemon)**分离架构运行,守护进程multipassd在后台常驻,处理来自命令行客户端(CLI)和 GUI 客户端的全部请求,并负责实例(instance)的完整生命周期管理(参见 Service 文档)。客户端与守护进程之间通过本地 socket 通信,而"谁能访问 socket,谁就能完全控制 Multipass"——包括挂载宿主机文件系统、修改所有实例的安全特性等。因此:
- 不要把 Multipass 暴露到不可信网络或用于承载敏感生产负载;
- 必须把对守护进程的访问严格限制在可信用户范围内;
- 在多用户主机上,应主动配置口令认证并善用文档提供的故障排查手段。
守护进程的本地访问模型:谁拿到 socket,谁就拿到一切
Multipass 守护进程以root 身份运行,并对外提供本地通信端点。官方文档给出的访问控制模型是分阶段的:
- 初始阶段:访问控制基于组权限(group membership)——只有属于 socket 所属管理组(如
sudo、wheel、adm,具体取决于操作系统)的用户才能连接; - 认证阶段:一旦某个管理组成员完成首次连接,其 TLS 客户端证书被守护进程信任后,socket 对所有用户开放连接,此后的访问控制转由用户 TLS 证书 + 口令接管。
从源码可以印证这一模型的实现。守护进程的 gRPC 服务在DaemonRpc构造时即根据地址类型设置 socket 限制(src/daemon/daemon_rpc.cpp):
// src/daemon/daemon_rpc.cpp server{make_server(server_address, cert_provider, this)}, server_socket_type{server_socket_type_for(server_address)}, client_cert_store{client_cert_store}, ... handle_socket_restrictions(server_address, client_cert_store->empty());其中client_cert_store->empty()用于判断"是否尚无任何客户端证书被信任"——这正是"第一个用户自动认证、之后需要口令"这一行为的分支依据:证书库为空时按组权限限制 socket,证书库非空后 socket 面向所有用户开放,改由证书与口令把关。
各平台的传输通道差异
官方安全文档明确指出,守护进程的通信端点因平台而异:
| 平台 | 通信方式 | 默认地址 |
|---|---|---|
| Linux | Unix domain socket | 由 src/platform/platform_linux.cpp 返回"unix:" + base_dir + "/multipass_socket" |
| macOS | Unix domain socket | 由 src/platform/platform_osx.cpp 返回"unix:/var/run/multipass_socket" |
| Windows | TCP socket(TLS 加密) | 由 src/platform/platform_win.cpp 返回"localhost:50051" |
关键差异在于:
- Linux / macOS:Unix domain socket 具有文件所有权与组权限概念,因此可以借助
sudo/wheel/adm组实现初始访问控制; - Windows:TCP socket 没有文件所有权概念,端口 50051 上的 socket 对所有用户开放,任何 Multipass 用户都可以连接并发出任意命令。正因如此,Windows 上的认证要求更为关键——文档特别说明,安装新版 Multipass 的用户会自动完成客户端认证,而其他用户则必须使用管理员设置的
local.passphrase进行认证。
认证体系:OpenSSL 加持的 x509 证书与 EC 密钥
Multipass 的认证机制建立在x509 证书 + 椭圆曲线(EC)密钥之上,由 OpenSSL 提供密码学支撑(见 Authentication 文档):用户每次连接时,Multipass 都会校验其客户端证书,确保只有通过验证的用户才能访问服务。
从 gRPC 服务端的实现可以看到证书的提取与信任流程(src/daemon/daemon_rpc.cpp):
// 从 gRPC 上下文的认证属性中提取客户端 x509 证书 std::string client_cert_from(grpc::ServerContext* context) { std::string client_cert; auto client_certs{context->auth_context()->FindPropertyValues("x509_pem_cert")}; if (!client_certs.empty()) client_cert = client_certs.front().data(); return client_cert; } // 首次连接的管理组成员,其证书被写入信任库 void accept_cert(mp::CertStore* client_cert_store, const std::string& client_cert, ...) { client_cert_store->add_cert(client_cert); }同时,服务端自身也通过CertProvider提供签名密钥与证书,构建带 TLS 的 gRPC 服务(src/daemon/daemon_rpc.cpp):
opts.pem_key_cert_pairs.push_back( {cert_provider.PEM_signing_key(), cert_provider.PEM_certificate()});这一 TLS 通道在 Linux/macOS 上承载于 Unix socket 之上,在 Windows 上则直接构成 TCP 50051 端口的加密层。文档中"Windows 使用 TLS socket"的表述,正对应源码中 gRPC 服务始终以pem_key_cert_pairs配置 TLS 的实现。
首个用户自动信任的机制
综合 about-security.md 与 authentication.md,"第一个用户"的自动认证流程为:
- 首次使用时,socket 只允许属于其所属管理组(
sudo/admin/wheel等)的用户连接; - 首个来自管理组成员的客户端连接成功后,该用户的 OpenSSL 证书被守护进程接受(写入客户端证书信任库);
- 此后 socket 面向所有用户开放连接,其余用户必须先用管理员设置的
local.passphrase完成authenticate认证。
这意味着一个重要的运维事实:安装 Multipass 的用户默认即被视为可信用户,自动完成认证;管理员身份(root/admin 与普通用户)的不匹配,是后续认证故障的常见根源(详见下文排查章节)。
口令认证的底层实现:scrypt 哈希与两阶段校验
认证体系的第二道关卡是口令。管理员通过multipass set local.passphrase设置口令后,后续用户通过multipass authenticate提交口令完成认证。源码揭示了口令存储与校验的完整链路。
口令存储:设置时即转为 scrypt 哈希
local.passphrase是守护进程侧注册的一个自定义设置项,其解释器(interpreter)会在写入时立即对口令做 scrypt 哈希(src/daemon/daemon_init_settings.cpp):
settings.insert(std::make_unique<CustomSettingSpec>(mp::passphrase_key, "", [](QString val) { return val.isEmpty() ? val : QString::fromStdString(MP_UTILS.generate_scrypt_hash_for(val.toStdString())); }));哈希函数本身位于 src/utils/utils.cpp,基于 OpenSSL 的EVP_PBE_scrypt实现,并指定了固定的 KDF 参数:
std::string mp::Utils::generate_scrypt_hash_for(const std::string& passphrase) const { unsigned char digest[EVP_MAX_MD_SIZE] = {0}; if (!EVP_PBE_scrypt(passphrase.c_str(), passphrase.size(), nullptr, // salt 为 nullptr,长度为 0 0, 1 << 14, // N = 16384 8, // r = 8 1, // p = 1 0, digest, sizeof(digest))) throw std::runtime_error("Cannot generate passphrase hash"); return fmt::format("{:02x}", fmt::join(digest, digest + sizeof(digest), "")); }即:口令以N=16384、r=8、p=1的 scrypt 参数计算哈希后存储,服务端保存的是哈希而非明文——这是值得在安全文档中强调的实现事实:即使配置文件泄露,攻击者也无法直接读取明文口令。
口令校验:authenticate 的比对流程
当用户执行multipass authenticate <passphrase>时,守护进程的Daemon::authenticate(src/daemon/daemon.cpp)按以下逻辑处理:
void mp::Daemon::authenticate(const AuthenticateRequest* request, ...) { auto stored_hash = MP_SETTINGS.get(mp::passphrase_key); if (stored_hash.isNull() || stored_hash.isEmpty()) // 返回 FAILED_PRECONDITION: // "Incorrect passphrase. No passphrase is set." 并提示先让已认证用户设置口令 auto hashed_passphrase = MP_UTILS.generate_scrypt_hash_for(request->passphrase()); if (stored_hash != hashed_passphrase) // 返回 INVALID_ARGUMENT:"Passphrase is not correct. Please try again." // 校验通过,返回 OK }可以看到校验是恒定的时间成本上的逐字节哈希比较:对用户提交的口令再次执行相同的 scrypt KDF,再与存储值比对。这解释了为什么authenticate报错信息能够区分"未设置口令"与"口令错误"两种情形,也印证了 authentication.md 中"验证证书以确保只有验证过的用户能访问服务"的完整链路:证书决定 socket 是否放行连接,口令决定该用户是否被授予执行命令的资格。
实战操作:配置口令与完成用户认证
以下操作步骤完整继承自 官方认证指南 与 authenticate 命令参考,可直接照做。
第一步:管理员设置口令
设置口令的用户必须已经是已认证用户(通常是安装者)。两种方式任选其一:
无回显交互式输入(推荐,口令不出现在命令行历史与进程列表中):
multipass set local.passphrase系统随后提示输入并确认口令:
Please enter passphrase: Please re-enter passphrase:命令行直接给出(口令可见):
multipass set local.passphrase=foo
local.passphrase的取值类型为任意字符串,默认值为"未设置"(multipass get会以false表达),详见 local.passphrase 设置参考。
第二步:新用户执行 authenticate
未被授权的用户直接运行multipass命令会失败,例如:
list failed: The user is not authenticated with the Multipass service. Please authenticate before proceeding (e.g. via 'multipass authenticate'). Note that you first need an authenticated user to set and provide you with a trusted passphrase (e.g. via 'multipass set local.passphrase').此时需要提供管理员设置的口令,同样有两种方式:
无回显交互式输入:
multipass authenticate提示如下,输入口令后回车:
Please enter passphrase:命令行直接给出:
multipass authenticate foo
authenticate还支持multipass auth别名以缩减输入量。命令的完整选项(authenticate 命令参考)如下:
Usage: multipass authenticate [options] [<passphrase>] Authenticate with the Multipass service. A system administrator should provide you with a passphrase to allow use of the Multipass service. Options: -h, --help Displays help on commandline options -v, --verbose Increase logging verbosity. Repeat the 'v' in the short option for more detail. Maximum verbosity is obtained with 4 (or more) v's, i.e. -vvvv. Arguments: passphrase Passphrase to register with the Multipass service. If omitted, a prompt will be displayed for entering the passphrase.认证成功后,该用户即可正常执行list、launch等全部命令。
故障排查:用户无法认证、口令无法设置
官方文档收录了一类典型故障场景:本应有权连接 socket 的用户先连接并"占位",导致后续用户既无法设置local.passphrase也无法完成认证。这通常发生在 Multipass 以 root/admin 安装、却以其他用户运行(或反之)时。
典型报错组合如下(详见 认证指南的 Troubleshooting 章节):
multipass list:list failed: The user is not authenticated with the Multipass service.multipass authenticate:Please enter passphrase: authenticate failed: No passphrase is set. Please ask an authenticated user to set one and provide it to you. They can achieve so with 'multipass set local.passphrase'. Note that only the user who installs Multipass is automatically authenticated.multipass set local.passphrase:Please enter passphrase: Please re-enter passphrase: set failed: The user is not authenticated with the Multipass service.
注意:此时即使使用sudo也未必能解决问题。官方提供的解决办法是手动把本机客户端证书导入守护进程的信任库,并重启 multipass 服务(以下命令适用于 snap 安装,需要sudo时请自行加上):
cat ~/snap/multipass/current/data/multipass-client-certificate/multipass_cert.pem | sudo tee -a /var/snap/multipass/common/data/multipassd/authenticated-certs/multipass_client_certs.pem > /dev/null snap restart multipass这一操作把本机multipass客户端持有的 TLS 证书(multipass_cert.pem)追加写入守护进程信任的客户端证书文件(authenticated-certs/multipass_client_certs.pem),再重启multipass使信任库生效。执行完成后,当前用户即被 Multipass 服务认证——这条命令实际上手动完成了"首个用户自动导入证书"这一本应自动发生的流程,印证了信任库文件(client_cert_store)在认证体系中的核心地位(对应源码 src/daemon/daemon_rpc.cpp 中的accept_cert/add_cert调用链)。
安全最佳实践小结
综合 about-security.md 及上述源码与操作细节,面向管理员的建议如下:
- 坚守非生产定位:Multipass 仅用于开发、测试与本地环境;承载敏感负载前必须评估本页所述安全模型。
- 限制 socket 访问:Unix socket 的组权限是初始防线,务必确保只有可信用户属于
sudo/wheel/adm等管理组;Windows 因 TCP socket 无所有权概念,更需依赖口令认证兜底。 - 主动设置
local.passphrase:安装完成后即由可信用户执行multipass set local.passphrase,让后续用户走口令认证,而非放任证书自动信任之外的无约束访问。 - 口令只经可信渠道分发:
local.passphrase可被任意字符串设置,且设置与认证均支持命令行明文传入;在共享主机上应优先使用无回显交互式输入,并通过安全渠道(而非明文聊天/日志)传递口令。 - 牢记"安装者默认可信"规则:安装用户自动获得认证资格;root/admin 与普通用户身份不一致时,可参照上文命令将本机证书导入
/var/snap/multipass/common/data/multipassd/authenticated-certs/multipass_client_certs.pem后重启服务恢复。
通过理解"证书管连接、口令管授权、socket 管边界"三层结构,以及源码中 scrypt 哈希存储(src/utils/utils.cpp)、TLS gRPC 服务与证书信任库(src/daemon/daemon_rpc.cpp)、口令解释器(src/daemon/daemon_init_settings.cpp)等实现事实,你即可在多用户开发机上安全、可控地部署与使用 Multipass。
- 虚拟化
- 开发工具
- 云原生
【免费下载链接】multipass
Multipass orchestrates virtual Ubuntu instances
相关推荐
洛雪音乐音源全解析:如何为你的音乐播放器注入无限活力
洛雪音乐音源全解析:如何为你的音乐播放器注入无限活力 在数字音乐时代,你是否曾因找不到心仪歌曲的高品质版本而烦恼?是否厌倦了在不同音乐平台间来回切换的繁琐操作?
音视频Multipass `local.passphrase` 配置详解:服务认证口令的设定、校验与安全机制
Multipass local.passphrase 配置详解:服务认证口令的设定、校验与安全机制 导读 local.passphrase 是 Multipas
虚拟化开发工具云原生ADK.js认证机制:AuthScheme与安全访问控制
ADK.js认证机制:AuthScheme与安全访问控制 ADK.js是一个开源的、代码优先的TypeScript工具包,用于构建、评估和部署复杂的AI代理,提
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考