【问题标题】:How do I automatically create service principals or MSIs with Terraform for use in Azure Pipelines to manage AKS resources?如何使用 Terraform 自动创建服务主体或 MSI 以在 Azure Pipelines 中使用以管理 AKS 资源?
【发布时间】:2022-02-09 00:03:16
【问题描述】:

我是following the official docs to create Azure Kubernetes clusters。文档说明我需要先手动创建服务主体,并提供 client_id 和 client_secret。

手动操作不是一种选择。

这是我的服务主体的代码。它装饰有最新 Terraform 文档的链接以供参考。

data "azurerm_subscription" "current" {}
data "azuread_client_config" "current" {}

resource "random_id" "current" {
  byte_length = 8
  prefix      = "ExternalDnsTf"
}

# Create Azure AD App.
# https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/application
resource "azuread_application" "current" {
  display_name = random_id.current.hex
  owners       = [data.azuread_client_config.current.object_id]

}

# Create Service Principal associated with the Azure AD App
# https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/service_principal
resource "azuread_service_principal" "current" {
  application_id               = azuread_application.current.application_id
  app_role_assignment_required = false
  owners                       = [data.azuread_client_config.current.object_id]
}

# Create Service Principal password
# https://registry.terraform.io/providers/hashicorp/azuread/latest/docs/resources/application_password
resource "azuread_application_password" "current" {
  application_object_id = azuread_application.current.object_id
}

# Create role assignment for service principal
# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment
resource "azurerm_role_assignment" "current" {
  scope                = data.azurerm_subscription.current.id
  role_definition_name = "Contributor"

 # When assigning to a SP, use the object_id, not the appId
 # see: https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-cli
  principal_id = azuread_service_principal.current.object_id
}

我的管道中不断出现以下错误:(注意,我是订阅的所有者)

ApplicationsClient.BaseClient.Post(): unexpected status 403 with OData
│ error: Authorization_RequestDenied: Insufficient privileges to complete the
│ operation.

我想要做的是消除设置支持服务的手动步骤。以外部 DNS 为例。 The Azure docs表示我需要使用az ad sp create-for-rbac -n ExternalDnsServicePrincipal; az role assignment create --role "Reader" --assignee <appId GUID> --scope <resource group resource id>; az role assignment create --role "Contributor" --assignee <appId GUID> --scope <dns zone resource id>

最终,我正在尝试创建 azure cli 命令的 terraform 版本。

支持create-for-rbacwas a feature request on github。这曾经很好用,但已经发生了很大变化,它不适用于当前的 API 版本。此外,随着 AAD Graph 被弃用以支持 Microsoft Graph API,我想知道我是否对此感到困惑。

ExternalDNS 文档还建议使用托管服务身份 (MSI)。服务主体、MSI、MSGraph API 集成,老实说,我不在乎使用哪一个。无论当前的最佳实践是什么都可以只要我不必登录门户来手动创建或授予权限,或手动运行az cli 命令。

编辑:权限说明

当然,我正在使用 Terraform 来配置资源。如果我在没有 terraform(手动或使用 bash 脚本)的情况下完成所有这些操作,我会使用 azure cli 我通过执行以下操作开始设置权限:

  • az login
  • az account set -s <my-subscription-id>

我是我的订阅的所有者。我可以毫无问题地运行所有命令、创建 SP、MSI、分配角色等。

在管道中,I am using the charleszipp az pipelines terraform 插件。在日志中,我看到:

  • az login --service-principal -t <my-tenant-id> -u *** -p ***
  • az account set -s <my-subscription-id>

我不确定这是否会有所不同。我将其解释为最终,命令在登录并设置帐户订阅后执行,就像我手动执行的那样。

从技术上讲,我没有在其中几个任务中使用服务连接。但是,在需要的地方,我创建了一个服务连接并将其范围定义为订阅级别。它的类型为 Azure 资源管理器。

但是,如果我单击“管理服务主体”,它会将我带到没有定义权限的门户。

虽然我是订阅的所有者,但我不是根管理组。我由其他人拥有/提供。最终,他们控制了 Active Directory。我无法添加或编辑权限。如果我尝试添加任何权限 API 并选择 Microsoft Graph,它会说需要授权。 Grant Admin Consent for <parent organization 显示为灰色。

但是,如果我是订阅的所有者,这为什么会很重要?如果我可以通过 az cli 命令行做任何我想做的事,是什么阻止我在管道中做同样的事情?

【问题讨论】:

  • 我猜您在 Azure 管道中使用服务连接,您在订阅中的权限级别是多少?喜欢所有者或贡献者?
  • Service 连接有哪些 Microsoft Graph API 权限?
  • @AnsumanBal-MT 请参阅上面的编辑以获取权限说明。我拥有我的订阅。有一个父组织维护对 Active Directory 的控制。我无法在 Permissions API 中授予管理员同意。管道中的所有服务连接都在订阅级别范围内属于 Azure 资源管理器类型。我需要不同的连接类型吗?

标签: azure-devops azure-active-directory terraform azure-aks terraform-provider-azure


【解决方案1】:

为此,我使用的是用户管理的身份,这对我来说似乎最简单且效果很好。

resource "azurerm_user_managed_identity", "mi" {
    resource_group_name = "rg"
    name = "mi"
    location = "eastus"
}

resource "azurerm_role_assignment" "ra" {
    scope = azurerm_subnet.sn.id  // subnet I created earlier
    role_definition_name = "Network Contributor"  // required with kubenet
    principal_id = azurerm_user_managed_identity.mi.principal_id
}

resource "azurerm_kubernetes_cluster" "aks" {
    name = "aks"
    identity {
        type = "UserAssigned"
        user_assigned_identity_id = azurerm_user_managed_identity.mi.id
    }
    <...remaining attributes...>
    depends_on = [azurerm_role_assignment.ra] // just to be safe
}

【讨论】:

    猜你喜欢
    • 2021-04-18
    • 2015-10-07
    • 2021-05-26
    • 2021-11-22
    • 2020-11-18
    • 2020-01-05
    • 2021-06-03
    • 2021-12-02
    • 2018-11-24
    相关资源
    最近更新 更多