Azure / bicep-types-az

Bicep type definitions for ARM resources
MIT License
81 stars 26 forks source link

Microsoft.ManagedIdentity: Improve Federated Credentials Handling Issue with Bicep #2054

Open johnpetersjr opened 6 months ago

johnpetersjr commented 6 months ago

I filed a property/type issue here, but I'm wondering if this is really a feature request? (Or I am just doing this all wrong)

I am running into some difficulties deploying multiple federatedIdentityCredentials to a managed identity using Bicep. Seems that I cannot deploy an array of federatedCredentials at the same time, as you will get this error:

Too many Federated Identity Credentials are written concurrently for the managed identity 
Concurrent Federated Identity Credentials writes under the same managed identity are not supported

So I changed my logic to use a batchSize of 1, to loop through the array, but now I've lost idempotency... each iteration through the batch doesn't know about pre-existing federatedCredentials, and the bicep deployment fails with this error:

Issuer and subject combination already exists for this Managed Identity.

Which destroys my whole purpose of building FederatedCredentials in Managed Identities via an IaC bicep pipeline.

Is there another way to use Bicep to create Managed Identities, and assign a list of Federated Credentials to them, and keep them in sync? I really wanted to use the '--mode Complete' and have Bicep create / update / delete any managed identities, and their federated identity credentials, in one fell swoop / from one Bicep MI repo.

Bicep Repro

main.bicep

// Bicep file for building a Managed Identity with optional OIDC Federated Credential(s)
type managedIdentitiesArray = {
  managedIdentityOwnerEmail: string
  managedIdentityName: string
  optionalFederatedCredentials: federatedCredentialsArray[]
}

type federatedCredentialsArray = {
  @description('The name of the fed cred')
  @minLength(10)
  name: string
  @description('subject')
  @minLength(10)
  subject: string
}

@description('List of Managed Identities to build in this resource group/subscription')
param managedIdentities managedIdentitiesArray[] = []

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = [for item in managedIdentities: {
  name: item.managedIdentityName
  location: location
}]

module managedIdentityFederatedCredentials 'managed_identity_federated_credentials.bicep' = [for (item, i) in managedIdentities: {
    name: item.managedIdentityName
    params: {
      managedIdentityName: item.managedIdentityName
      managedIdentityFederatedCredentialsArray: item.optionalFederatedCredentials
    }
}]

managed_identity_federated_credentials.bicep

// Bicep file for building a Managed Identity with optional OIDC Federated Credential(s)

param managedIdentityName string
param managedIdentityFederatedCredentialsArray array

// Get the managed identity created in main
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = {
  name: managedIdentityName
}

// Now add/update federated credentials to it
@batchSize(1)
resource federatedCredential 'Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials@2023-01-31' = [for item in managedIdentityFederatedCredentialsArray: {
  parent: managedIdentity
  name: item.name
  properties: {
    audiences: [
      'api://AzureADTokenExchange'
    ]
    issuer: 'https://token.actions.githubusercontent.com'
    subject: item.subject
  }
}
]

BicepParam File

using '../../../bicep_files/main.bicep'

param managedIdentities = [
  {
      managedIdentityOwnerEmail: 'email@example.com'
      managedIdentityName: 'some_mi_name_0'
      optionalFederatedCredentials: [
        {
          name: 'some_fedcred_name_0_fed_1'
          subject: 'repo:myorg/myrepo1:ref:refs/heads/main'
        }
        {
          name: 'some_fedcred_name_0_fed_2'
          subject: 'repo:myorg/myrepo2:ref:refs/heads/main'
        }
      ]
  }
  {
    managedIdentityOwnerEmail: 'email@example.com'
    managedIdentityName: 'some_mi_name_1'
    optionalFederatedCredentials: []
}
{
    managedIdentityOwnerEmail: 'email@example.com'
    managedIdentityName: 'some_mi_name_2'
    optionalFederatedCredentials: [
      {
        name: 'some_fedcred_name_2_fed_1'
        subject: 'repo:my_org/my_repo:ref:refs/heads/main'
      }
      {
        name: 'some_fedcred_name_2_fed_2'
        subject: 'repo:my_org/my_repo2:ref:refs/heads/main'
      }
    ]
  }
]

Last comment on this, I think I might just need to figure out how to do a dependsOn in Bicep for an array of federated credentials, but not quite sure how to go about that. Looks like I've run into a known limitation, that terraform has a solution for, but not clear how to solve for this in Bicep:

https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation-considerations#concurrent-updates-arent-supported-user-assigned-managed-identities

Seems like someone else had a similar issue, and this was solved with a dependsOn statement like this:

https://github.com/Azure/bicep/issues/10928

But since I'm looping through an unknown number of array elements, I am too new to this to know how to refer to the previous array element to 'depend' on? Is this possible?

Thanks in advance for any help!

stephaniezyen commented 6 months ago

It looks like your workaround of changing the batch size to 1 should have solved the issue, but since it didn't, it is most likely a Microsoft.ManagedIdentity RP issue. Please open a support ticket if you would like this to be streamlined, otherwise we will try to route it to the right team.

johnpetersjr commented 6 months ago

It looks like your workaround of changing the batch size to 1 should have solved the issue, but since it didn't, it is most likely a Microsoft.ManagedIdentity RP issue. Please open a support ticket if you would like this to be streamlined, otherwise we will try to route it to the right team.

Done and done, thanks!

microsoft-github-policy-service[bot] commented 6 months ago

Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @varunkch. Please see https://aka.ms/biceptypesinfo for troubleshooting help.

johnpetersjr commented 4 months ago

FYI I received feedback from Microsoft Support that this is not currently supported, and is in the works on their roadmap.

sdherr commented 2 months ago

I encountered this Issuer and subject combination already exists for this Managed Identity error when trying to create/update one single Federated Credential on one Managed Identity (ie not a concurrency problem), when they're in a resource group other than the one that the main bicep deployment is running as. I was attempting to define them in a module and then run the module with a scope: resourceGroup(otherResourceGroupName) attribute, and it would throw the error if the FedCred already existed, destroying the idempotency of the bicep deployment.

However it seems to work fine if I simply separate things out into two different deployments based on resource group, which is an acceptable work-around for me.

thecmdradama commented 2 months ago

FYI I received feedback from Microsoft Support that this is not currently supported, and is in the works on their roadmap.

Also keen to see this implemented. Have a few use cases that would benefit from this being supported. Currently I can work around this by retriggering the deployment but really not the best as the deployment will always fail.