Open rdbartram opened 3 years ago
Same...
I can't seem to figure out how to properly format an array...
param(
[Parameter(Mandatory)]
[string] $KeyVaultName,
[Parameter()]
[ValidateSet('WestEurope', 'NorthEurope', 'WestUs2')]
[string] $Location = 'WestEurope'
)
$azADGroup = Get-AzADGroup -DisplayNameStartsWith 'platform-kv-01_secrets*' |
ForEach-Object {
if ($_.DisplayName.EndsWith('_r')) {
$secrets = @("Get","List")
}
if ($_.DisplayName.EndsWith('_rw')) {
$secrets = @("Get","List","Create", "Delete","Update","Purge")
}
if ($_.DisplayName.EndsWith('_f')) {
$secrets = @("All")
}
[PSCustomObject]@{
ObjectId = $_.id
Secrets = $secrets
}
}
Arm {
Resource $KeyVaultName -Namespace 'Microsoft.KeyVault' -Type 'vaults' -apiVersion '2019-09-01' {
properties {
tenantId (subscription).tenantId
sku {
family 'A'
name 'standard'
}
accessPolicies { $azADGroup[0] | Foreach-Object {
tenantId (subscription).tenantId
objectId $($_.ObjectId)
permissions { $_.Secrets | Foreach-Object {
secrets $($_)
}
}
}
}
}
}
}
I can only generate one $azAdGroup entry at a time...
The JSON file seems fine as far as I can tell for the one entry... I have three azAdGroups...
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "psarm",
"version": "0.1.0.0",
"psarm-psversion": "7.1.3",
"templateHash": "13553475952233288655"
}
},
"resources": [
{
"name": "keyvault",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2019-10-01",
"properties": {
"mode": "Incremental",
"expressionEvaluationOptions": {
"scope": "inner"
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"name": "platform-kv-01",
"apiVersion": "2019-09-01",
"type": "Microsoft.KeyVault/vaults",
"location": "westeurope",
"properties": {
"tenantId": "[subscription().tenantId]",
"sku": {
"family": "A",
"name": "standard"
},
"accessPolicies": [
{
"tenantId": "[subscription().tenantId]",
"objectId": "d427a0ec-ac40-48cd-b74d-56edd3f6945b",
"permissions": {
"keys": [
"Get",
"List"
]
}
}
]
}
}
]
}
}
}
]
}
I haven't seen any AzureAd resource in bicep... Did notice that Terraform has one 😉 If I can use PowerShell to leverage getting the objectId... Just think of the possibilities... 💯
I talked about this with @irwins and found the following syntax does work:
param(
[Parameter(Mandatory)]
[string] $KeyVaultName,
[Parameter()]
[ValidateSet('WestEurope', 'NorthEurope', 'WestUs2')]
[string] $Location = 'WestEurope'
)
$azADGroup = Get-AzADGroup -DisplayNameStartsWith 'platform-kv-01_secrets*' |
ForEach-Object {
if ($_.DisplayName.EndsWith('_r')) {
$secrets = @("Get", "List")
}
if ($_.DisplayName.EndsWith('_rw')) {
$secrets = @("Get", "List", "Create", "Delete", "Update", "Purge")
}
if ($_.DisplayName.EndsWith('_f')) {
$secrets = @("All")
}
[PSCustomObject]@{
ObjectId = $_.id
Secrets = $secrets
}
}
Arm {
Resource $KeyVaultName -Namespace 'Microsoft.KeyVault' -Type 'vaults' -apiVersion '2019-09-01' {
properties {
tenantId (subscription).tenantId
sku {
family 'A'
name 'standard'
}
$azADGroup | Foreach-Object {
accessPolicies {
tenantId (subscription).tenantId
objectId $($_.ObjectId)
permissions { $_.Secrets | Foreach-Object {
secrets $($_)
}
}
}
}
}
}
}
I do feel this is counter intuitive syntax and in my opinion the other suggestion by @rdbartram and Irwins original syntax makes a lot more sense..
It may seem counter intuitive but the end Access Policy in @irwins / @Ba4bes is definable only to a single objectID not an array of ObjectId's so you can only ever have it as you have above as per the Access Policy docs at https://docs.microsoft.com/en-us/azure/templates/microsoft.keyvault/vaults/accesspolicies?tabs=json#accesspolicyentry-object
Which ultimately is a limitation in ARM which @bmoore-msft / @alex-frankel may be able to help nudge the KV team to update the objectID of the AccessPolicyObject to allow an array in a future api-version update
In the docs you linked I see AccessPolicyEntry, which is an object, and accessPolicies, which is an array. The PSARM syntax in this case looks like it is is creating multiple instances of the property accessPolicies. In my opinion it makes more sense if it is making multiple instances of AccessPolicyEntry and combine them into the array accessPolicies. A lot like what @irwins tried to do.
That is already happening in bicep, where the syntax to create a for loop would look something like this:
accessPolicies: [for accessPolicy in accessPolicies: {
tenantId: tenantId
objectId: accessPolicy.objectId
permissions: {
keys: accessPolicy.keys
secrets: accessPolicy.secrets
certificates: accessPolicy.certificates
}
}]
I would expect something similar to this to be an option for PSArm.
Same goes for the example by @rdbartram, where addressPrefixes is an array, not an object.
@Ba4bes Gave me an idea to try...
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"keyVault": {
"value": {
"name": "platform-kv-01",
"sku": {
"family": "A",
"name": "standard"
},
"accessPolicies": [
{
"objectId": "92f011f6-697c-41a2-8584-defca729382f",
"permissions": {
"keys": ["All"],
"secrets": ["All"],
"certificates": ["All"]
}
},
{
"objectId": "d427a0ec-ac40-48cd-b74d-56edd3f6945f",
"permissions": {
"keys": ["Get","List"]
}
},
{
"objectId": "b6555562-e39c-407a-b846-9b3f1878df45",
"permissions": {
"keys": ["Get","List"],
"secrets": [ "All"],
"certificates": ["All"]
}
}
]
}
},
"location": {
"value": "westeurope"
}
}
}
// Parameter definitions
@description('KeyVault properties')
param keyVault object
@description('Resource location, defaults to resourceGroup location')
param location string = resourceGroup().location
// Resources
resource kv 'Microsoft.KeyVault/vaults@2021-04-01-preview' = {
name: keyVault.name
location:location
properties: {
tenantId: subscription().tenantId
sku: keyVault.sku
accessPolicies: [for accessPolicy in keyVault.accessPolicies: {
tenantId: subscription().tenantId
objectId: accessPolicy.objectId
permissions: accessPolicy.permissions
}]
}
}
//Output definitions
output keyVaultUri string = kv.properties.vaultUri
Building this resulted in the following JSON file (Gotta love bicep for authoring...)
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.4.63.48766",
"templateHash": "10484560537251782542"
}
},
"parameters": {
"keyVault": {
"type": "object",
"metadata": {
"description": "KeyVault properties"
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Resource location, defaults to resourceGroup location"
}
}
},
"functions": [],
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2021-04-01-preview",
"name": "[parameters('keyVault').name]",
"location": "[parameters('location')]",
"properties": {
"copy": [
{
"name": "accessPolicies",
"count": "[length(parameters('keyVault').accessPolicies)]",
"input": {
"tenantId": "[subscription().tenantId]",
"objectId": "[parameters('keyVault').accessPolicies[copyIndex('accessPolicies')].objectId]",
"permissions": {
"keys": "[parameters('keyVault').accessPolicies[copyIndex('accessPolicies')].keys]",
"secrets": "[parameters('keyVault').accessPolicies[copyIndex('accessPolicies')].secrets]",
"certificates": "[parameters('keyVault').accessPolicies[copyIndex('accessPolicies')].certificates]"
}
}
}
],
"tenantId": "[subscription().tenantId]",
"sku": "[parameters('keyVault').sku]"
}
}
],
"outputs": {
"keyVaultUri": {
"type": "string",
"value": "[reference(resourceId('Microsoft.KeyVault/vaults', parameters('keyVault').name)).vaultUri]"
}
}
}
it worked as expected...
I can always update the parameter file JIT with PowerShell 😉
This syntax is not powershell friendly and should look more like the second example