|
| 1 | +# Converting Azure Templates from Cosmos DB Connection Strings to Managed Identity |
| 2 | + |
| 3 | +This prompt provides step-by-step instructions for converting Azure Bicep templates from using Cosmos DB connection strings to managed identity authentication, ensuring compliance with Azure security policies that disallow local authentication methods. |
| 4 | + |
| 5 | +## Problem Context |
| 6 | + |
| 7 | +Azure security policies often require disabling local authentication methods for Cosmos DB, which means connection strings cannot be used. Templates must be updated to use managed identity authentication instead. |
| 8 | + |
| 9 | +## Prerequisites |
| 10 | + |
| 11 | +Before starting, ensure: |
| 12 | +- The application code already supports managed identity (using `DefaultAzureCredential` and endpoint-based authentication) |
| 13 | +- The template has system-assigned managed identity configured for the app service |
| 14 | +- You understand the structure of your Bicep template files |
| 15 | + |
| 16 | +## Step-by-Step Conversion Process |
| 17 | + |
| 18 | +### 1. Remove Connection String Configuration |
| 19 | + |
| 20 | +**In your Cosmos DB module (e.g., `infra/app/db-avm.bicep`):** |
| 21 | + |
| 22 | +Remove the following parameters and configurations: |
| 23 | +```bicep |
| 24 | +// Remove these parameters |
| 25 | +param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' |
| 26 | +param keyVaultResourceId string |
| 27 | +
|
| 28 | +// Remove this entire secretsExportConfiguration block |
| 29 | +secretsExportConfiguration:{ |
| 30 | + keyVaultResourceId: keyVaultResourceId |
| 31 | + primaryWriteConnectionStringSecretName: connectionStringKey |
| 32 | +} |
| 33 | +
|
| 34 | +// Remove this output |
| 35 | +output connectionStringKey string = connectionStringKey |
| 36 | +``` |
| 37 | + |
| 38 | +**In your main template (e.g., `infra/main.bicep`):** |
| 39 | + |
| 40 | +Remove connection string related configurations: |
| 41 | +```bicep |
| 42 | +// Remove from cosmos module parameters |
| 43 | +keyVaultResourceId: keyVault.outputs.resourceId |
| 44 | +
|
| 45 | +// Remove from app settings |
| 46 | +AZURE_COSMOS_CONNECTION_STRING_KEY: cosmos.outputs.connectionStringKey |
| 47 | +
|
| 48 | +// Remove from template outputs |
| 49 | +output AZURE_COSMOS_CONNECTION_STRING_KEY string = cosmos.outputs.connectionStringKey |
| 50 | +``` |
| 51 | + |
| 52 | +### 2. Enable Managed Identity Authentication |
| 53 | + |
| 54 | +**Add `disableLocalAuth: true` to your Cosmos DB module:** |
| 55 | +```bicep |
| 56 | +module cosmos 'br/public:avm/res/document-db/database-account:0.6.0' = { |
| 57 | + name: 'cosmos-sql' |
| 58 | + params: { |
| 59 | + name: accountName |
| 60 | + location: location |
| 61 | + tags: tags |
| 62 | + disableLocalAuth: true // ← Add this line |
| 63 | + // ... other parameters |
| 64 | + } |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +### 3. Handle Role Assignments Properly |
| 69 | + |
| 70 | +**Critical:** Avoid duplicate Cosmos DB deployments that can override the `disableLocalAuth` setting. |
| 71 | + |
| 72 | +**Create a separate role assignment module** (`infra/app/cosmos-role-assignment.bicep`): |
| 73 | +```bicep |
| 74 | +param cosmosAccountName string |
| 75 | +param apiPrincipalId string |
| 76 | +
|
| 77 | +// Create a role assignment for the API's managed identity to access Cosmos DB |
| 78 | +// Using the built-in "Cosmos DB Built-in Data Contributor" role |
| 79 | +resource apiCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2024-05-15' = { |
| 80 | + name: '${cosmosAccountName}/${guid(apiPrincipalId, cosmosAccountName, '00000000-0000-0000-0000-000000000002')}' |
| 81 | + properties: { |
| 82 | + roleDefinitionId: '${resourceGroup().id}/providers/Microsoft.DocumentDB/databaseAccounts/${cosmosAccountName}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002' |
| 83 | + principalId: apiPrincipalId |
| 84 | + scope: '${resourceGroup().id}/providers/Microsoft.DocumentDB/databaseAccounts/${cosmosAccountName}' |
| 85 | + } |
| 86 | +} |
| 87 | +``` |
| 88 | + |
| 89 | +**In your main template, reference this module:** |
| 90 | +```bicep |
| 91 | +// Give the API access to Cosmos using a separate role assignment |
| 92 | +module apiCosmosRoleAssignment './app/cosmos-role-assignment.bicep' = { |
| 93 | + name: 'api-cosmos-role' |
| 94 | + scope: rg |
| 95 | + params: { |
| 96 | + cosmosAccountName: cosmos.outputs.accountName |
| 97 | + apiPrincipalId: api.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID |
| 98 | + } |
| 99 | +} |
| 100 | +``` |
| 101 | + |
| 102 | +### 4. Important Role Assignment Details |
| 103 | + |
| 104 | +**Use built-in role GUIDs, not custom role names:** |
| 105 | +- Cosmos DB Built-in Data Reader: `00000000-0000-0000-0000-000000000001` |
| 106 | +- Cosmos DB Built-in Data Contributor: `00000000-0000-0000-0000-000000000002` |
| 107 | + |
| 108 | +**Avoid these common mistakes:** |
| 109 | +- Using custom role definition names (like 'writer') instead of GUIDs |
| 110 | +- Creating standalone role assignment resources at subscription scope |
| 111 | +- Having circular dependencies between cosmos and API modules |
| 112 | + |
| 113 | +### 5. Verify Required Components Remain |
| 114 | + |
| 115 | +Ensure these components are preserved: |
| 116 | +- ✅ System-assigned managed identity for the API app service |
| 117 | +- ✅ `AZURE_COSMOS_ENDPOINT` environment variable for the API |
| 118 | +- ✅ Key Vault access policies for the API's managed identity (if using Key Vault) |
| 119 | +- ✅ Proper resource group scope for all resources |
| 120 | + |
| 121 | +### 6. Testing and Validation |
| 122 | + |
| 123 | +**Validate your changes:** |
| 124 | +1. Run `bicep build` on your templates to check for compilation errors |
| 125 | +2. Test deployment in a development environment |
| 126 | +3. Verify the application can authenticate using managed identity |
| 127 | +4. Confirm no connection string references remain in the template |
| 128 | + |
| 129 | +## Common Issues and Solutions |
| 130 | + |
| 131 | +### Issue: "Local authentication methods are not allowed" |
| 132 | +**Solution:** Ensure `disableLocalAuth: true` is set and no duplicate Cosmos DB deployments exist. |
| 133 | + |
| 134 | +### Issue: "Scope 'subscription' is not valid for this resource type" |
| 135 | +**Solution:** Use a module approach instead of standalone role assignment resources. |
| 136 | + |
| 137 | +### Issue: "SQL Role Definition name must be a GUID" |
| 138 | +**Solution:** Use built-in role GUIDs (`00000000-0000-0000-0000-000000000002`) instead of custom names. |
| 139 | + |
| 140 | +### Issue: Circular dependency errors |
| 141 | +**Solution:** Separate role assignment into its own module to break dependency cycles. |
| 142 | + |
| 143 | +## Final Checklist |
| 144 | + |
| 145 | +- [ ] Removed all connection string configuration parameters |
| 146 | +- [ ] Removed secretsExportConfiguration from Cosmos DB module |
| 147 | +- [ ] Added `disableLocalAuth: true` to Cosmos DB account |
| 148 | +- [ ] Created separate role assignment module using built-in role GUID |
| 149 | +- [ ] Removed connection string references from app settings |
| 150 | +- [ ] Verified no duplicate Cosmos DB module deployments exist |
| 151 | +- [ ] Ensured managed identity and Key Vault access are preserved |
| 152 | +- [ ] Tested template compilation and deployment |
| 153 | + |
| 154 | +## Application Code Requirements |
| 155 | + |
| 156 | +Your application code should already be using managed identity: |
| 157 | + |
| 158 | +```csharp |
| 159 | +var credential = new DefaultAzureCredential(); |
| 160 | +var cosmosClient = new CosmosClient(builder.Configuration["AZURE_COSMOS_ENDPOINT"], credential, ...); |
| 161 | +``` |
| 162 | + |
| 163 | +This approach uses the `AZURE_COSMOS_ENDPOINT` environment variable and managed identity instead of connection strings. |
0 commit comments