- 网络安全
- 认证鉴权
- 运维
- 后端
【免费下载链接】teleport
The easiest, and most secure way to access and protect all of your infrastructure.
导读
在拥有大量 Azure 订阅的企业环境中,逐个订阅为 Teleport 配置自动发现既繁琐又难以维护。本文以当前仓库中 Azure Discovery Terraform 模块的 management-group 示例 为主体,完整讲解如何利用 Azure管理组(Management Group)这一层级结构,一次性配置 Teleport 跨所有可见订阅自动发现并纳管虚拟机(VM)。读完本文,你将掌握:management-group 示例的完整main.tf结构与每个参数的含义、通配符订阅匹配器与租户级 allow rule 的原理、模块底层如何推导角色作用域与最小权限集,以及如何用terraform plan/apply和tctl验证整个链路。
一、示例要解决什么问题
examples/management-group是 Azure Discovery 模块的官方示例之一(另一个是 single-subscription 示例)。两者的区别在于发现资源的作用域(scope):
- single-subscription:只发现当前 Azure 订阅(subscription)内、符合标签条件的虚拟机;
- management-group:以管理组(或 Tenant / 根管理组)为作用域,配合通配符订阅匹配器
subscriptions = ["*"],发现该管理组下所有可见订阅中符合条件的所有虚拟机,一次性完成企业级规模化纳管。
该示例的定位声明只有一句话:"Configure Teleport to discover resources in an Azure management group."(README 首段),但背后涉及 Azure 托管身份、OIDC 联合凭据、自定义角色、Teleport 动态发现配置等多层资源的编排,下面逐步拆解。
二、环境与版本要求
示例的versions.tf(examples/management-group/versions.tf)声明了运行前必须满足的版本基线:
| 组件 | 版本要求 | 说明 |
|---|---|---|
| terraform | >= 1.5.7 | Terraform CLI 最低版本 |
| azurerm provider | >= 4.0 | HashiCorp Azure 资源管理器 Provider |
| http provider | >= 3.0 | 用于探测 Teleport Proxy 的/webapi/find接口 |
| teleport provider | >= 18.7.6 | 来自terraform.releases.teleport.dev/gravitational/teleport的官方 Provider |
注意 Teleport Provider 的source是terraform.releases.teleport.dev/gravitational/teleport,与常见的registry.terraform.io不同,terraform init时会从 Teleport 官方发布源拉取。
另外,在运行任何 Terraform 命令之前,还需要两个前置条件(见模块 README 的 Prerequisites 一节):
- 安装并配置 Teleport Terraform Provider,确保执行环境能通过 Provider 与你的 Teleport 集群(Proxy)通信;
- 被发现的每台 Azure 虚拟机都必须已分配托管身份,且该身份至少具备
Microsoft.Compute/virtualMachines/read权限,Teleport Discovery Service 才能扫描到它。
三、示例 main.tf 逐段精读
示例的全部逻辑集中在 examples/management-group/main.tf,variables.tf为空(示例的 Inputs 声明为 "No inputs"),所有配置都内联在main.tf中。我们按代码顺序逐段分析。
3.1 公共标签与当前客户端信息
locals { apply_azure_tags = { origin = "example" } apply_teleport_resource_labels = { origin = "example" } } data "azurerm_client_config" "current" {}apply_azure_tags/apply_teleport_resource_labels:传递给模块,给本示例创建的 Azure 资源额外打上origin=example标签、给 Teleport 资源额外打上origin=example标签,便于识别示例产物;data "azurerm_client_config" "current":读取执行 Terraform 时所用 Azure 凭证的tenant_id、subscription_id等信息。在 management-group 场景中,它的tenant_id被用作azure_management_group_id,即以租户(根管理组)为角色作用域。
3.2 示例资源组
resource "azurerm_resource_group" "example" { name = "teleport-discovery" location = "eastus" tags = local.apply_azure_tags }模块创建的所有 Azure 资源(托管身份、角色定义等)都放入这个名为teleport-discovery、位于eastus的资源组。它由示例自行创建,而模块内的azure_resource_group_name变量要求传入的是已存在的资源组名称,因此示例将azurerm_resource_group.example.name传入模块。
3.3 模块调用:管理组作用域的核心配置
module "azure_discovery" { source = "../.." teleport_discovery_group_name = "cloud-discovery-group" teleport_proxy_public_addr = "example.teleport.sh:443" azure_resource_group_name = azurerm_resource_group.example.name azure_managed_identity_location = azurerm_resource_group.example.location azure_management_group_id = data.azurerm_client_config.current.tenant_id azure_matchers = [ { types = ["vm"] subscriptions = ["*"] tags = { TeleportEnroll = ["true"] } } ] apply_azure_tags = local.apply_azure_tags apply_teleport_resource_labels = local.apply_teleport_resource_labels teleport_installer_script_name = teleport_installer.example.metadata.name }这是整个示例的“题眼”,几个关键点:
source = "../..":指向模块根目录 integrations/terraform-modules/teleport/discovery/azure,即从示例目录上溯两级。这与 README 中 Modules 表 记录的azure_discovery(Source:../..)一致。teleport_discovery_group_name = "cloud-discovery-group":Teleport Discovery Service 的发现组名。模块 README 明确说明:发现配置要生效,该名称必须与至少一个 Discovery Service 实例配置的discovery_group匹配;Teleport Cloud 集群必须使用cloud-discovery-group(见 variables.tf 中该变量的注释)。teleport_proxy_public_addr = "example.teleport.sh:443":Proxy 公网地址,格式为host:port,不允许带 URL scheme。模块在main.tf中会据此拼出https://${...}并调用{proxy}/webapi/find探测集群信息(见 模块 main.tf 的teleport_proxy_public_url与data.http.teleport_ping及 L35-L39)。variables.tf里还内置了两条 validation:禁止出现://、必须包含:。azure_management_group_id = data.azurerm_client_config.current.tenant_id:把**租户 ID(Tenant ID)**当作管理组 ID 传入。示例注释说得非常清楚(main.tf L26-L31):- 传管理组 ID 或租户 ID 都可以;
- 传租户 ID 会使用根管理组作用域(Root management group scope)作为托管身份角色的作用域;
- 在根作用域上执行操作需要提升权限(Elevated access,即 Azure 的 Global Administrator 提权操作)。
azure_matchers使用通配符订阅:subscriptions = ["*"]表示发现该作用域下所有可见订阅中的 VM,并按标签TeleportEnroll=true过滤。这正是 management-group 场景的标志性写法——*通配符只允许单独出现在 subscriptions 列表中(variables.tf 的 validation 强制了这一约束)。
3.4 可选:把角色分配限制到子作用域
示例中有一段被注释掉的配置(main.tf L33-L41):
# azure_role_assignment_scopes = [ # "/providers/Microsoft.Management/managementGroups/child-mg", # "/subscriptions/00000000-0000-0000-0000-000000000000", # ]它的语义是:如果不希望托管身份在整棵管理组树(或根作用域)上都拥有角色,可以显式指定角色分配的作用域列表。此时通配符订阅匹配器只会发现这些被分配作用域可见的订阅;而azure_management_group_id仅用于角色定义的 assignable scope。这与模块 azure_role_definition.tf 中azure_role_assignment_scopes = coalescelist(...)的推导逻辑一一对应:显式 scopes 优先,其次管理组作用域,最后回退到按 matcher 中的订阅列表逐个推导。
测试用例role_assignment_scopes_with_management_group_assignable_scope(tests/main.tftest.hcl)验证了这一点:当azure_role_assignment_scopes指定child-mg、azure_management_group_id为parent-mg时,角色定义 scope 是parent-mg,但角色只分配给child-mg。
3.5 自定义 Installer 脚本
示例最后创建了一个teleport_installer资源(main.tf L64-L103),并把它的名字custom-azure-installer-example传给模块的teleport_installer_script_name:
resource "teleport_installer" "example" { version = "v1" metadata = { name = "custom-azure-installer-example" description = "Example Teleport Installer" labels = local.apply_teleport_resource_labels } spec = { script = <<EOF #!/usr/bin/env sh set -eu INSTALL_SCRIPT_URL="https://{{.PublicProxyAddr}}/scripts/install.sh" ... sudo -E "$TELEPORT_BINARY" install autodiscover-node --public-proxy-addr={{.PublicProxyAddr}} --teleport-package={{.TeleportPackage}} --repo-channel={{.RepoChannel}} --auto-upgrade={{.AutomaticUpgrades}} --azure-client-id={{.AzureClientID}} $@ EOF } }要点:
- 注释特别说明:这个 "custom" 脚本其实就是默认安装脚本(可用
tctl get installer/default-installer查看),把它复制出来改造成自定义版本,是为了演示如何定制 Discovery Service 下发到 VM 的安装命令; - 脚本中的
{{.PublicProxyAddr}}、{{.TeleportPackage}}、{{.RepoChannel}}、{{.AutomaticUpgrades}}、{{.AzureClientID}}是Go 模板占位符,Discovery Service 在实际下发时会替换为真实值; - 关键动作是
teleport install autodiscover-node,它让被发现的 VM 以azure join 方式安装并注册为 Teleport Node; - 模板中
$${TELEPORT_INSTALL_SUFFIX:-}使用了转义的$$写法,避免与 Terraform 自身的插值语法冲突。
四、模块底层:管理组作用域如何落地
模块位于 integrations/terraform-modules/teleport/discovery/azure,由 5 个资源文件组成。management-group 示例的配置会真实触发以下资源链(见模块 README 的资源清单)。
4.1 托管身份与 OIDC 联合凭据(azure_managed_identity.tf)
azure_managed_identity.tf 创建:
azurerm_user_assigned_identity.teleport_discovery_service:用户分配的托管身份,Discovery Service 用它认证到 Azure API;azurerm_federated_identity_credential.teleport_discovery_service:联合身份凭据,在 Azure 与 Teleport 集群之间建立信任——它把托管身份的信任方(issuer)设为 Teleport Proxy 的 OIDC 地址(从teleport_proxy_public_addr推导),subject 固定为teleport-azure,audience 为api://AzureADTokenExchange。这意味着托管身份可以用 Teleport Proxy 签发的 OIDC 令牌换取 Azure 访问令牌。
4.2 自定义角色与按作用域分配(azure_role_definition.tf)
azure_role_definition.tf 是 management-group 语义的“心脏”:
azure_management_group_scope:把azure_management_group_id规范化为/providers/Microsoft.Management/managementGroups/<id>形式的 Azure 作用域路径(若传入的已是完整路径则原样使用);azure_role_assignment_scopes:按“显式 scopes > 管理组作用域 > matcher 订阅列表”的优先级推导角色分配位置;- 角色权限(
role_actions):至少包含Microsoft.Resources/subscriptions/read,当 matcher 类型含vm时追加 VM 相关的最小权限集(如Microsoft.Compute/virtualMachines/read、runCommands/read、runCommands/write等),保证 Discovery Service 既能扫描 VM 又能通过 Run Command 在 VM 上执行安装脚本; - 一个值得注意的 precondition:如果
azure_role_assignment_scopes包含多个管理组作用域,则必须显式设置azure_management_group_id(因为角色定义的 assignable scope 只能有一个,见 L60-L70)。测试multiple_management_group_assignments_without_azure_management_group_id_error专门验证了这个失败路径(tests/main.tftest.hcl L307-L322); azurerm_role_assignment通过for_each为每个推导出的作用域执行角色分配。
4.3 发现配置:通配符订阅的强约束(teleport_discovery_config.tf)
teleport_discovery_config.tf 生成 Teleport 集群内的动态资源teleport_discovery_config,其中:
spec.azure由 matcher 转换而来,每个 matcher 会被合并进install_params(join_method=azure、join_token、script_name)以及integration(当使用 OIDC 集成时);- 有一个针对 management-group 场景的关键 precondition:使用通配符(
*)订阅匹配器时,必须设置azure_management_group_id或azure_role_assignment_scopes,否则 plan 直接报错(L53-L62)。测试discovery_config_subscription_wildcard_missing_scopes_error验证了这一点(tests/main.tftest.hcl L221-L232)。这也解释了为什么示例必须传入azure_management_group_id; depends_on保证发现配置在集成资源就绪后才创建,避免 Discovery Service 因权限尚未生效而空转约 5 分钟。
4.4 OIDC 集成(teleport_integration.tf)
teleport_integration.tf 创建teleport_integration(sub_kind=azure-oidc),把 Azure 的client_id(托管身份的 client ID)与tenant_id存进 Teleport 集群,Discovery Service 据此代表托管身份执行 Azure OIDC 联合认证。它同样通过depends_on等待联合凭据和角色分配完成。
4.5 加入令牌:租户级 allow rule(teleport_provision_token.tf)
teleport_provision_token.tf 创建teleport_provision_token(join_method=azure、roles=[Node]),这是被发现的 VM 加入集群的凭证。在 management-group + 通配符订阅场景下,其spec.azure.allow规则的生成逻辑非常关键:
- 对含
*的 matcher,生成按租户(tenant)限定的 allow rule(subscription = null、tenant = <当前租户 ID>),因为订阅不可枚举,只能用租户范围约束; - 对显式订阅的 matcher,生成按 subscription(可选 resource_groups)限定的规则;
- 如果显式设置了
teleport_provision_token_allow_rules,则完全采用自定义规则。
测试discovery_config_subscription_wildcard(tests/main.tftest.hcl L234-L259)断言:management-group 模式下令牌恰好包含 1 条 allow rule 且tenant等于 mock 的租户 ID,同时角色分配发生在管理组作用域。wildcard_and_subscription_matchers(L405-L438)则验证通配符与显式订阅混用时两条规则并存、各自限定方式正确。
另一个约束:当create_azure_managed_identity = false(使用外部托管身份)且使用通配符订阅时,必须显式提供teleport_provision_token_allow_rules(L60-L65),因为此时模块无法获知租户 ID 来自动生成租户规则。
五、从示例到落地:操作步骤与验证
5.1 准备与执行
在示例目录 integrations/terraform-modules/teleport/discovery/azure/examples/management-group 下操作:
# 1. 初始化(拉取 azurerm/http/teleport provider) terraform init # 2. 预览将要创建的 Azure 与 Teleport 资源 terraform plan # 3. 应用 terraform apply应用前请务必确认:
- 执行 Terraform 的 Azure 身份具备在根管理组作用域执行角色分配的权限(否则需要 Azure 全局管理员先做提权操作,详见示例注释指向的 Azure 文档);
teleport_proxy_public_addr已替换为真实 Proxy 地址;- 目标 VM 已打上
TeleportEnroll=true标签并分配了带读取权限的托管身份。
5.2 用 tctl 验证结果
模块的 Outputs 文档 给出了三条验证命令:
# 查看动态发现配置(discovery_group、azure matchers 等) tctl get discovery_config/<name> # 查看 Azure OIDC 集成详情(也可在 Web UI 的 Zero Trust Access > Integrations 查看) tctl get integrations/<name> # 查看允许 Azure 节点加入的 provision token tctl get token/<name>其中资源名默认带随机后缀(模块用random_id生成 4 字节 hex 后缀并追加到各类资源名后,见 模块 main.tf L26-L29),可通过terraform output azure_discovery拿到示例模块的所有输出(示例 outputs.tf 原样透出了module.azure_discovery)。如果不想用随机后缀,可将各*_use_name_prefix变量设为false并使用精确名称(测试name_suffix_exact验证了这一行为,tests/main.tftest.hcl L531-L565)。
5.3 自动化测试佐证
模块自带的 Terraform Test 套件 tests/main.tftest.hcl 覆盖了 management-group 模式下的核心行为,可作为你修改配置后的回归验证手段:
create = false时不创建任何资源(L86-L131);use_oidc_integration = false时不创建联合凭据和集成,且发现配置不再引用 integration(L133-L158);- 通配符订阅缺少作用域配置时 plan 失败(L221-L232);
- 多管理组作用域 + 显式
azure_management_group_id时角色定义与分配的行为(L324-L353)。
运行方式:
cd integrations/terraform-modules/teleport/discovery/azure terraform test六、常见参数速查(management-group 场景)
结合模块 variables.tf 与示例用法,将 management-group 场景最常用的参数整理如下:
| 参数 | 类型/默认值 | management-group 场景建议 |
|---|---|---|
azure_management_group_id | string,默认null | 传管理组 ID 或租户 ID;使用通配符订阅时必填之一 |
azure_role_assignment_scopes | list(string),默认[] | 可选;用于把角色分配收窄到子管理组/订阅,设置后azure_management_group_id只作角色定义的 assignable scope |
azure_matchers | 对象列表,必填 | subscriptions = ["*"]实现全订阅发现;types目前仅支持vm;tags默认{"*"=["*"]}即不过滤 |
teleport_discovery_group_name | string,必填 | Teleport Cloud 用cloud-discovery-group;自建集群需与 Discovery Service 的 discovery_group 一致 |
teleport_proxy_public_addr | string,必填 | host:port格式,禁止 URL scheme |
teleport_installer_script_name | string,默认default-installer | 示例演示了自定义 installer 的接入方式 |
create_azure_managed_identity | bool,默认true | 置false时需自备托管身份与角色,且通配符订阅时必须显式传teleport_provision_token_allow_rules |
use_oidc_integration | bool,默认true | 关闭后不创建联合凭据与集成资源 |
七、小结
examples/management-group示例展示了 Teleport Azure 自动发现最具扩展性的形态:以租户/管理组为作用域、以通配符订阅匹配器为扫描范围、以租户级 allow rule 约束加入令牌,配合自定义 installer 脚本下发teleport install autodiscover-node完成 VM 纳管。理解其背后的三个核心机制——作用域推导优先级(显式 scopes > 管理组 > 订阅列表)、通配符订阅的强约束 precondition、租户级令牌规则自动生成——就能在企业多订阅环境中安全、可审计地规模化部署 Teleport 的 Azure 自动发现能力。
进一步阅读:
- 模块 README(完整输入/输出参考)
- single-subscription 示例(对比订阅级发现)
- 模块自动化测试(行为契约)
- 网络安全
- 认证鉴权
- 运维
- 后端
【免费下载链接】teleport
The easiest, and most secure way to access and protect all of your infrastructure.
相关推荐
Watermill与Azure Management Group创建集成:管理组事件配置
Watermill与Azure Management Group创建集成:管理组事件配置 概述 Watermill是一个用于构建事件驱动应用的Go语言框架,通过
消息队列后端微服务Upscheme集成实战:如何在现有PHP项目中无缝接入
Upscheme集成实战:如何在现有PHP项目中无缝接入 Upscheme是一款强大的PHP数据库迁移工具,能够轻松实现数据库模式更新和版本控制。本文将详细介绍
跨平台桌面应用UI组件通过透明代理捕获虚拟机流量:mitmproxy 虚拟机透明代理完整配置指南
通过透明代理捕获虚拟机流量:mitmproxy 虚拟机透明代理完整配置指南 本指南基于 mitmproxy 官方 howto 文档,讲解如何将一台 Ubuntu
网络安全网络开发工具接口测试
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考