news 2026/9/21 0:23:48

Teleport 通过 Terraform 在 Azure 管理组中发现虚拟机:management-group 示例完全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Teleport 通过 Terraform 在 Azure 管理组中发现虚拟机:management-group 示例完全指南
  • 网络安全
  • 认证鉴权
  • 运维
  • 后端

【免费下载链接】teleport

The easiest, and most secure way to access and protect all of your infrastructure.

项目地址:https://gitcode.com/gh_mirrors/tel/teleport
点击查看免费下载

导读

在拥有大量 Azure 订阅的企业环境中,逐个订阅为 Teleport 配置自动发现既繁琐又难以维护。本文以当前仓库中 Azure Discovery Terraform 模块的 management-group 示例 为主体,完整讲解如何利用 Azure管理组(Management Group)这一层级结构,一次性配置 Teleport 跨所有可见订阅自动发现并纳管虚拟机(VM)。读完本文,你将掌握:management-group 示例的完整main.tf结构与每个参数的含义、通配符订阅匹配器与租户级 allow rule 的原理、模块底层如何推导角色作用域与最小权限集,以及如何用terraform plan/applytctl验证整个链路。

一、示例要解决什么问题

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.7Terraform CLI 最低版本
azurerm provider>= 4.0HashiCorp Azure 资源管理器 Provider
http provider>= 3.0用于探测 Teleport Proxy 的/webapi/find接口
teleport provider>= 18.7.6来自terraform.releases.teleport.dev/gravitational/teleport的官方 Provider

注意 Teleport Provider 的sourceterraform.releases.teleport.dev/gravitational/teleport,与常见的registry.terraform.io不同,terraform init时会从 Teleport 官方发布源拉取。

另外,在运行任何 Terraform 命令之前,还需要两个前置条件(见模块 README 的 Prerequisites 一节):

  1. 安装并配置 Teleport Terraform Provider,确保执行环境能通过 Provider 与你的 Teleport 集群(Proxy)通信;
  2. 被发现的每台 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_idsubscription_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 }

这是整个示例的“题眼”,几个关键点:

  1. source = "../..":指向模块根目录 integrations/terraform-modules/teleport/discovery/azure,即从示例目录上溯两级。这与 README 中 Modules 表 记录的azure_discovery(Source:../..)一致。

  2. teleport_discovery_group_name = "cloud-discovery-group":Teleport Discovery Service 的发现组名。模块 README 明确说明:发现配置要生效,该名称必须与至少一个 Discovery Service 实例配置的discovery_group匹配;Teleport Cloud 集群必须使用cloud-discovery-group(见 variables.tf 中该变量的注释)。

  3. teleport_proxy_public_addr = "example.teleport.sh:443":Proxy 公网地址,格式为host:port不允许带 URL scheme。模块在main.tf中会据此拼出https://${...}并调用{proxy}/webapi/find探测集群信息(见 模块 main.tf 的teleport_proxy_public_urldata.http.teleport_ping及 L35-L39)。variables.tf里还内置了两条 validation:禁止出现://、必须包含:

  4. 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 提权操作)。
  5. 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-mgazure_management_group_idparent-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 创建:

  1. azurerm_user_assigned_identity.teleport_discovery_service:用户分配的托管身份,Discovery Service 用它认证到 Azure API;
  2. 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/readrunCommands/readrunCommands/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_idazure_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 = nulltenant = <当前租户 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_idstring,默认null传管理组 ID 或租户 ID;使用通配符订阅时必填之一
azure_role_assignment_scopeslist(string),默认[]可选;用于把角色分配收窄到子管理组/订阅,设置后azure_management_group_id只作角色定义的 assignable scope
azure_matchers对象列表,必填subscriptions = ["*"]实现全订阅发现;types目前仅支持vmtags默认{"*"=["*"]}即不过滤
teleport_discovery_group_namestring,必填Teleport Cloud 用cloud-discovery-group;自建集群需与 Discovery Service 的 discovery_group 一致
teleport_proxy_public_addrstring,必填host:port格式,禁止 URL scheme
teleport_installer_script_namestring,默认default-installer示例演示了自定义 installer 的接入方式
create_azure_managed_identitybool,默认truefalse时需自备托管身份与角色,且通配符订阅时必须显式传teleport_provision_token_allow_rules
use_oidc_integrationbool,默认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.

项目地址:https://gitcode.com/gh_mirrors/tel/teleport
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/21 0:22:13

国产AI工具“不限额”真相:场景选型与本地部署实战指南

这些年国产AI工具是真的出了不少&#xff0c;工作台上堆着一排图标&#xff0c;但真正敢放心当生产工具用的&#xff0c;没几个。不是国产工具不行&#xff0c;而是大多数人选型时根本没搞清楚一件事&#xff1a;市面上说的“不限额”&#xff0c;和你以为的那个“不限额”&…

作者头像 李华
网站建设 2026/9/21 0:20:48

OpenClaw、Hermes Agent、Claude Code、Codex CLI 四大 AI 编程助手选型与部署指南

1. 四款 AI 编程助手到底怎么选&#xff1a;先搞清楚它们各自是什么AI 编程工具在最近一年里几乎是爆发式增长&#xff0c;从最早的代码补全插件&#xff0c;到如今能独立完成多文件重构、跑测试、提交 PR 的 Agent 型工具&#xff0c;整个赛道已经分化出了非常明显的几条路线。…

作者头像 李华
网站建设 2026/9/21 0:12:25

openclaw-cn 装完起 18789,OpenClaw onboard 的模型认证改填 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/21 0:10:56

Atlas 300V Pro部署YOLOv8全流程实战与踩坑记录

一开始是我手里拿到了一块 Atlas 300V Pro 24G 的时候&#xff0c;说实话心里是带着疑问的&#xff1a;这卡到底算不算“运算加速卡”&#xff1f;跑 YOLO 到底行不行&#xff1f;那时候网上能查到的资料&#xff0c;要么是厂商页面上冷冰冰的参数表&#xff0c;要么是只讲“能…

作者头像 李华
网站建设 2026/9/21 0:10:53

Atlas 300V 24G推理加速卡部署YOLO全流程:从环境搭建到模型转换实战

最近总有人问我&#xff1a;Atlas 300V 24G算不算运算加速卡&#xff0c;能不能用来跑YOLO&#xff0c;跑起来什么效果&#xff0c;部署流程麻不麻烦。说实话&#xff0c;我最早也被这名字搞得有点晕——Atlas这个系列又出加速卡又出AI服务器&#xff0c;300V、300I、300I Pro一…

作者头像 李华
网站建设 2026/9/21 0:10:41

Atlas 300V 24G推理卡部署YOLO完整实战记录

Atlas 300V 24G到底是不是运算加速卡&#xff1f;用它跑通YOLO部署的完整记录先说结论&#xff1a;Atlas 300V 24G是华为昇腾生态里典型的边缘推理加速卡&#xff0c;本质是推理卡&#xff0c;不是训练卡。拿它跑YOLO推理、视频流分析、边缘侧检测这类任务&#xff0c;完全对口…

作者头像 李华