服务主体:Set-AzureRmKeyVaultAccessPolicy:权限不足,无法完成操作

Service Principal : Set-AzureRmKeyVaultAccessPolicy : Insufficient privileges to complete the operation

Post 已更新。问题已解决。下面的脚本将创建资源组、创建服务主体、部署密钥保管库、配置权限并将机密写入保管库。希望这有帮助! :)

问题: 我作为对资源组具有所有者权限的服务主体登录到 PowerShell。 当我尝试创建保管库、在保管库上设置权限以及尝试写入机密时出现权限错误。

解决方法: 第 1 步:创建资源组和服务主体。您必须以管理员身份登录才能执行此脚本

Clear-Host
Import-Module Azure
Import-Module AzureRM.Resources

Add-AzureRmAccount
Get-AzureRmSubscription
Set-AzureRmContext -SubscriptionId <Your subscription id goes here>

$ServicePrincipalDisplayName = "myServicePrincipalName"
$CertificateName = "CN=SomeCertName" 

$cert = New-SelfSignedCertificate -CertStoreLocation "cert:\CurrentUser\My" -Subject $CertificateName -KeySpec KeyExchange
$keyValue = [Convert]::ToBase64String($cert.GetRawCertData())

$ResouceGroupName = "myRessourceGroup"
$location = "North Central US"

# Create the resource group
New-AzureRmResourceGroup -Name $ResouceGroupName -Location $location

$ResouceGroupNameScope = (Get-AzureRmResourceGroup -Name $ResouceGroupName -ErrorAction Stop).ResourceId

# Create the Service Principal that logs in with a certificate
New-AzureRMADServicePrincipal -DisplayName $ServicePrincipalDisplayName -CertValue $keyValue -EndDate $cert.NotAfter -StartDate $cert.NotBefore

$myServicePrincipal = Get-AzureRmADServicePrincipal -SearchString $ServicePrincipalDisplayName
Write-Host "myServicePrincipal.ApplicationId " $myServicePrincipal.ApplicationId -ForegroundColor Green
Write-Host "myServicePrincipal.DisplayName " $myServicePrincipal.DisplayName

# Sleep here for a few seconds to allow the service principal application to become active (should only take a couple of seconds normally)
Write-Host "Waiting 10 seconds"
Start-Sleep -s 10

Write-Host "Make the Service Principal owner of the resource group " $ResouceGroupName

$NewRole = $null
$Retries = 0
 While ($NewRole -eq $null -and $Retries -le 6)
 {  
    New-AzureRMRoleAssignment -RoleDefinitionName Owner -ServicePrincipalName $myServicePrincipal.ApplicationId  -Scope $ResouceGroupNameScope -ErrorAction SilentlyContinue    
    $NewRole = Get-AzureRMRoleAssignment -ServicePrincipalName $myServicePrincipal.ApplicationId
    Write-Host "NewRole.DisplayName " $NewRole.DisplayName
    Write-Host "NewRole.Scope: " $NewRole.Scope
    $Retries++

    Start-Sleep -s 10
 }

Write-Host "Service principal created" -ForegroundColor Green

第 2 步:ARM 部署 Vault。创建一个名为 keyvault2.parameters.json 的文件,更新 ID 以反映您的安装(5479eaf6-31a3-4be3-9fb6-c2cdadc31735 是 Azure Web 应用程序在访问保管库时使用的服务主体。)

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
  "parameters": {
    "vaultName": {
      "value": "valueFromParameterFile"
    },
    "vaultlocation": {
      "value": "valueFromParameterFile"
    },
    "skumode": {
      "value": "Standard"
    },
    "accessPolicyList": {
      "value": [
        {
          "objectId": "The object ID for your AAD user goes here so that you can read secrets etc",
          "tenantId": "Your Tenant Id goes here",
          "permissions": {
            "keys": [
              "Get",
              "List"
            ],
            "secrets": [
              "Get",
              "List"
            ],
            "certificates": [
              "Get",
              "List"
            ]
          }
        },
        {
          "objectId": "The object ID for the service principal goes here Get-AzureRmADServicePrincipal -ServicePrincipalName <Service Principal Application ID>",
          "tenantId": "Your Tenant Id goes here",
          "permissions": {
            "keys": [
              "Get",
              "List",
              "Update",
              "Create",
              "Import",
              "Delete",
              "Recover",
              "Backup",
              "Restore"
            ],
            "secrets": [
              "Get",
              "List",
              "Set",
              "Delete",
              "Recover",
              "Backup",
              "Restore"
            ],
            "certificates": [
              "Get",
              "List",
              "Update",
              "Create",
              "Import",
              "Delete",
              "ManageContacts",
              "ManageIssuers",
              "GetIssuers",
              "ListIssuers",
              "SetIssuers",
              "DeleteIssuers"
            ]
          },
          "applicationId": null
        },
        {
        "objectId": "5479eaf6-31a3-4be3-9fb6-c2cdadc31735",
        "tenantId": "Your Tenant Id goes here",
        "permissions": {
            "keys": [],
            "secrets": [
                "Get"
            ],
            "certificates": []
        },
        "applicationId": null
    }
      ]
    },
    "tenant": {
      "value": "Your Tenant Id goes here"
    },
    "isenabledForDeployment": {
      "value": true
    },
    "isenabledForTemplateDeployment": {
      "value": false
    },
    "isenabledForDiskEncryption": {
      "value": false
    }
  }
}

第 3 步:ARM 部署 Vault。创建一个名为 keyvault2.template.json

的文件
{
    "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
  "parameters": {
    "vaultName": {
      "type": "string"
    },
    "vaultlocation": {
      "type": "string"
    },
    "skumode": {
      "type": "string",
      "defaultValue": "Standard",
      "allowedValues": [
        "Standard",
        "standard",
        "Premium",
        "premium"
      ],
      "metadata": {
        "description": "SKU for the vault"
      }
    },
    "accessPolicyList": {
      "type": "array",
      "defaultValue": [],
      "metadata": {
        "description": "The access policies defined for this vault."
      }
    },
    "tenant": {
      "type": "string"
    },
    "isenabledForDeployment": {
      "type": "bool"
    },
    "isenabledForTemplateDeployment": {
      "type": "bool"
    },
    "isenabledForDiskEncryption": {
      "type": "bool"
    }
  },
    "resources": [
      {
        "apiVersion": "2015-06-01",
        "name": "[parameters('vaultName')]",
        "location": "[parameters('vaultlocation')]",
        "type": "Microsoft.KeyVault/vaults",
        "properties": {
          "enabledForDeployment": "[parameters('isenabledForDeployment')]",
          "enabledForTemplateDeployment": "[parameters('isenabledForTemplateDeployment')]",
          "enabledForDiskEncryption": "[parameters('isenabledForDiskEncryption')]",
          "accessPolicies": "[parameters('accessPolicyList')]",
          "tenantId": "[parameters('tenant')]",
          "sku": {
            "name": "[parameters('skumode')]",
            "family": "A"
          }
        }
      }
    ]
}

第 4 步:部署保管库。启动一个新的 powershell window 并执行此脚本。更新 3 x id's

Clear-Host

Import-Module Azure
Import-Module AzureRM.Resources    

$ServicePrincipalApplicationId = "xxx"
$TenantId = "yyy"
$SubscriptionId = "zzz"
$CertificateName = "CN=SomeCertName"
$ResouceGroupName = "myRessourceGroup"
$location = "North Central US"
$VaultName = "MyVault" + (Get-Random -minimum 10000000 -maximum 1000000000)
$MySecret = ConvertTo-SecureString -String "MyValue" -AsPlainText -Force

$Cert = Get-ChildItem cert:\CurrentUser\My\ | Where-Object {$_.Subject -match $CertificateName }
Write-Host "cert.Thumbprint " $cert.Thumbprint
Write-Host "cert.Subject " $cert.Subject

Add-AzureRmAccount -ServicePrincipal -CertificateThumbprint $cert.Thumbprint -ApplicationId $ServicePrincipalApplicationId -TenantId $TenantId
Get-AzureRmSubscription
Set-AzureRmContext -SubscriptionId $SubscriptionId

Write-Host ""
Write-Host "Creating vault" -ForegroundColor Yellow

New-AzureRmResourceGroupDeployment -ResourceGroupName $ResouceGroupName -vaultName $vaultName -vaultlocation $location -isenabledForDeployment $true -TemplateFile ".\keyvault2.template.json"  -TemplateParameterFile ".\keyvault2.parameters.json"

Write-Host ""
Write-Host "Key Vault " $vaultName " deployed" -ForegroundColor green

Write-Host "Wait 5 seconds"
Start-Sleep -Seconds 5

Write-Host "Write Secret" -ForegroundColor Yellow    
Set-AzureKeyVaultSecret -VaultName $VaultName -Name "MyKey" -SecretValue $MySecret

Write-Host "Wait 10 seconds"
Start-Sleep -Seconds 10

Write-Host "Read secret"
Get-AzureKeyVaultSecret -VaultName $VaultName -Name "MyKey"

根据您的描述,我在我的实验室进行测试,我还使用我的服务委托人登录我的 Azure 订阅。你的 cmdlet 适合我。

你检查我的服务主体角色了吗?您可以在 Azure 门户上查看它。

请确保您的服务委托人具有 ContributorOwner 权限。有关此的更多信息,请参阅此 link.

更新:

我在我的实验室进行了测试,您的 PowerShell 脚本对您来说工作正常。我建议您可以使用 Power Shell 创建密钥库并授予权限。

解决方案是将权限配置移动到 ARM 模板,而不是尝试使用 PowerShell 来完成。一旦我这样做,所有权限问题都得到解决。

在 ARM 模板中,我为服务主体指定的对象 ID 是错误的。它认为它是您可以在应用程序注册下的门户中找到的对象 ID,但不是,它实际上是它想要的 Azure AD 应用程序的服务主体的对象 ID。

即使您使用了错误的 ID 并且所有配置都非常正确,它也可以让您部署 ARM 模板,直到您开始想知道为什么您的服务主体的图标与其他用户相比看起来不同。如果您像我一样只有一个用户,那么您当然要等到很久以后才会注意到...

错误的id(这个图标不同):

正确的ID:

这个 post 给了我最终的解决方案。

Set-AzureRmKeyVaultAccessPolicy -VaultName $name -ObjectId $oId -PermissionsToSecrets get
returns错误
Set-AzureRmKeyVaultAccessPolicy : Insufficient privileges to complete the operation.

解决方法是添加额外的参数-BypassObjectIdValidation

Set-AzureRmKeyVaultAccessPolicy -BypassObjectIdValidation -VaultName $name -ObjectId $oId -PermissionsToSecrets get

解决方案看起来很复杂,但对我有用。在此之后,具有 $oId 的对象可以访问 keyVault。 (要检查访问策略,请使用 Get-AzureRmKeyVault -VaultName $vaultName

本周我在这个问题上苦苦挣扎,因为我没有在我的 AAD 中为服务主体添加 API 权限的权限。我找到了使用 ARM Output 市场项目的解决方案。使用 ARM 输出任务,我可以从 ARM 模板中检索我的对象的主体 ID,并将它们转换为管道变量,而这些变量又可以被 Azure PowerShell 脚本使用,以成功更新 Key vault 访问策略。

在 ARM 模板中,我将此输出变量添加到 return 网站主体 ID - 这是我无法查询 AD 的信息。

"outputs": {
  "websitePrincipalId": {
    "type": "string",
    "value": "[reference(concat(resourceId('Microsoft.Web/sites', variables('webSiteName')), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId]"
  }
}

然后我使用 ARM 输出任务,return 将输出作为管道变量,这在 Azure PowerShell 脚本中很有用,我可以使用它来使用正确的访问策略填充我的密钥保管库:

Set-AzKeyVaultAccessPolicy -VaultName "$(KeyVaultName)" -ObjectId "$(servicePrincipalId)" -PermissionsToSecrets list,get -PassThru -BypassObjectIdValidation