跳至主要内容

远程服务发现

OpenTofu 使用远程服务实现了其大部分功能。虽然在许多情况下,这些都是对许多应用程序有用的通用第三方服务,但其中一些服务是专门针对 OpenTofu 的需求而定制的。我们将这些服务称为“OpenTofu 原生服务”,OpenTofu 通过下面描述的远程服务发现协议与它们进行交互。

面向用户的主机名

从用户的角度来看,OpenTofu 原生服务是在一个面向用户的“友好主机名”下提供的,该主机名作为配置和任何所需身份验证凭据的关键。

发现协议的目的是将用户提供的主机名映射到特定服务的基准 URL。每个主机都可以提供不同组合的服务——或者根本不提供服务!——因此,发现协议的第二个目的是允许 OpenTofu 识别给定主机名下哪些服务是有效的。

例如,模块源字符串可以包含模块注册表主机名作为其第一个片段,例如 example.com/namespace/name/provider,OpenTofu 使用服务发现来确定 example.com 是否具有模块注册表,以及如果存在,其 API 在哪里可用。

面向用户的主机名是使用其 Unicode 形式表示的完整指定的国际化域名(不允许使用相应的“Punycode”形式),并且必须能够在 DNS 中解析到在端口 443 上运行 HTTPS 服务器的地址。

使用标准 Unicode Nameprep 算法对面向用户的主机名进行规范化以进行内部比较,其中包括将所有字母转换为小写,尽可能将组合变音符号规范化为预组合形式,以及其他各种规范化步骤。

发现过程

给定一个主机名,发现过程首先使用该主机名以及 https: 方案和固定路径 /.well-known/terraform.json 形成一个初始发现 URL。

例如,给定主机名 example.com,初始发现 URL 将为 https://example.com/.well-known/terraform.json

然后,OpenTofu 向此发现 URL 发送 GET 请求,并期望收到 JSON 响应。如果响应的状态不是 200,没有 application/json 的媒体类型,或者如果主体无法解析为 JSON 对象,则发现失败,OpenTofu 认为主机不支持任何 OpenTofu 原生服务。

如果响应是 HTTP 重定向,则 OpenTofu 使用新位置作为其发现 URL 重复此步骤。OpenTofu 保证至少遵循一个重定向,但不保证也不推荐嵌套重定向。

如果响应是有效的 JSON 对象,则其键是 OpenTofu 原生服务标识符,由服务类型名称和版本字符串用句点分隔组成。例如,模块注册表协议版本 1 的服务标识符为 modules.v1

每个对象元素的值是相关服务的基准 URL。此 URL 可以是绝对的或相对的,如果是相对的,则相对于最终发现 URL(遵循重定向之后)解析。

以下是一个声明支持模块注册表协议版本 1 的发现文档示例

代码块
{
"modules.v1": "https://modules.example.com/v1/"
}

支持的服务

目前,以下服务标识符正在使用中

身份验证

如果给定主机名的凭据通过 credentials_helper 或特定于主机名的环境变量在 CLI 配置 中可用,则它们将包含在发现文档的请求中。

根据相关服务的需要,凭据也可以提供给发现文档中声明的端点。

用户可见主机名中的非标准端口

强烈建议在标准 HTTPS 端口 443 上提供主机名的发现文档。但是,在开发环境中,这并不总是可行或方便的,因此 OpenTofu 允许主机名以冒号后跟一个或多个十进制数字组成的端口规范结尾。

当存在自定义端口号时,预期该端口上的服务将实现 HTTPS 并响应相同的固定发现路径。

对于日常使用,强烈建议不要依赖此机制,而是应在标准端口上提供发现文档,因为这允许使用最友好的主机名形式。