Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# All Values Required
AZURE_ENV=<AZURE CLOUD ENVIRONMENT>
ENGINE_APP_ID=<ENGINE APP REGISTRATION CLIENT ID>
ENGINE_APP_SECRET=<ENGINE APP REGISTRATION SECRET>
UI_APP_ID=<UI APP REGISTRATION CLIENT ID>
TENANT_ID=<AZURE AD TENANT ID>
COSMOS_URL=https://<COSMOS NAME>.documents.azure.com
KEYVAULT_URL=https://<KEYVAULT NAME>.vault.azure.net

# Legacy Values
# COSMOS_KEY=<COSMOS ACCESS KEY>
# ENGINE_APP_SECRET=<ENGINE APP REGISTRATION SECRET>
48 changes: 30 additions & 18 deletions deploy/deploy.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -647,11 +647,6 @@ process {
-Scope $scope `
| Out-Null

Write-Host "INFO: Creating Azure IPAM Engine Secret" -ForegroundColor Green

# Create IPAM Engine Secret
$engineSecret = New-AzADAppCredential -ApplicationObject $engineObject -StartDate (Get-Date) -EndDate (Get-Date).AddYears(2)

if (-not $DisableUI) {
Write-Host "INFO: Azure IPAM Engine & UI Applications/Service Principals created successfully" -ForegroundColor Green
}
Expand All @@ -661,7 +656,6 @@ process {

$appDetails = @{
EngineAppId = $engineApp.AppId
EngineSecret = $engineSecret.SecretText
}

# Add UI AppID to AppDetails (If DisableUI not specified)
Expand Down Expand Up @@ -796,8 +790,6 @@ process {
[string]$UIAppId = [GUID]::Empty,
[Parameter(Mandatory = $true)]
[string]$EngineAppId,
[Parameter(Mandatory = $true)]
[string]$EngineSecret,
[Parameter(Mandatory = $false)]
[bool]$DisableUI = $false
)
Expand All @@ -809,14 +801,13 @@ process {

# Update Parameter Values
$parametersObject.parameters.engineAppId.value = $EngineAppId
$parametersObject.parameters.engineAppSecret.value = $EngineSecret

if (-not $DisableUI) {
$parametersObject.parameters.uiAppId.value = $UIAppId
$parametersObject.parameters = $parametersObject.parameters | Select-Object -Property uiAppId, engineAppId, engineAppSecret
$parametersObject.parameters = $parametersObject.parameters | Select-Object -Property uiAppId, engineAppId
}
else {
$parametersObject.parameters = $parametersObject.parameters | Select-Object -Property engineAppId, engineAppSecret
$parametersObject.parameters = $parametersObject.parameters | Select-Object -Property engineAppId
}

# Output updated parameter file for Bicep deployment
Expand All @@ -839,13 +830,12 @@ process {
# Read Values from Parameters
$UIAppId = $parametersObject.parameters.uiAppId.value ?? [GUID]::Empty
$EngineAppId = $parametersObject.parameters.engineAppId.value
$EngineSecret = $parametersObject.parameters.engineAppSecret.value
$script:DisableUI = ($UIAppId -eq [GUID]::Empty) ? $true : $false

if ((-not $EngineAppId) -or (-not $EngineSecret)) {
if ((-not $EngineAppId)) {
Write-Host "ERROR: Missing required parameters from Bicep parameter file" -ForegroundColor Red
Write-Host "ERROR: Please ensure the following parameters are present in the Bicep parameter file" -ForegroundColor Red
Write-Host "ERROR: Required: [engineAppId, engineAppSecret]" -ForegroundColor Red
Write-Host "ERROR: Required: [engineAppId]" -ForegroundColor Red
Write-Host ""
Write-Host "ERROR: Please refer to the deployment documentation for more information" -ForegroundColor Red
Write-Host "ERROR: " -ForegroundColor Red -NoNewline
Expand All @@ -862,7 +852,6 @@ process {
$appDetails = @{
UIAppId = $UIAppId
EngineAppId = $EngineAppId
EngineSecret = $EngineSecret
}

return $appDetails
Expand All @@ -875,8 +864,6 @@ process {
[Parameter(Mandatory = $true)]
[string]$EngineAppId,
[Parameter(Mandatory = $true)]
[string]$EngineSecret,
[Parameter(Mandatory = $false)]
[string]$NamePrefix,
[Parameter(Mandatory = $false)]
[string]$AzureCloud,
Expand All @@ -897,7 +884,6 @@ process {
# Instantiate deployment parameter object
$deploymentParameters = @{
engineAppId = $EngineAppId
engineAppSecret = $EngineSecret
uiAppId = $UiAppId
}

Expand Down Expand Up @@ -1056,6 +1042,26 @@ process {
} while ($publishSuccess -eq $False -and $publishRetries -ge 0)
}

Function New-FederatedCredential {
Param(
[Parameter(Mandatory = $true)]
[string]$EngineAppId,
[Parameter(Mandatory = $true)]
[string]$ManagedIdentityPrincipalId
)

Write-Host "INFO: Creating Federated Credential" -ForegroundColor Green

New-AzADAppFederatedCredential `
-ApplicationObjectId (Get-AzADApplication -ApplicationId $EngineAppId).Id `
-Audience "api://AzureADTokenExchange" `
-Issuer "https://login.microsoftonline.com/$($(Get-AzContext).Tenant.Id)/v2.0" `
-Subject $ManagedIdentityPrincipalId `
-Name "ipam-engine-mi-credential" | Out-Null

Write-Host "INFO: Federated Credential Created" -ForegroundColor Green
}

Function Update-UIApplication {
Param(
[Parameter(Mandatory = $true)]
Expand Down Expand Up @@ -1200,6 +1206,12 @@ process {
-Endpoint $deployment.Outputs["appServiceHostName"].Value
}

if ($PSCmdlet.ParameterSetName -notin 'AppsOnly') {
New-FederatedCredential `
-EngineAppId $appDetails.EngineAppId `
-ManagedIdentityPrincipalId $deployment.Outputs["managedIdentityPrincipalId"].Value
}

if ($PSCmdlet.ParameterSetName -in ('App', 'Function')) {
if (-Not $ZipFilePath) {
try {
Expand Down
6 changes: 1 addition & 5 deletions deploy/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ param uiAppId string = '00000000-0000-0000-0000-000000000000'
@description('IPAM-Engine App Registration Client/App ID')
param engineAppId string

@secure()
@description('IPAM-Engine App Registration Client Secret')
param engineAppSecret string

@description('Tags')
param tags object = {}

Expand Down Expand Up @@ -92,7 +88,6 @@ module keyVault './modules/keyVault.bicep' = {
identityClientId: managedIdentity.outputs.clientId
uiAppId: uiAppId
engineAppId: engineAppId
engineAppSecret: engineAppSecret
workspaceId: logAnalyticsWorkspace.outputs.workspaceId
}
}
Expand Down Expand Up @@ -186,3 +181,4 @@ output appServiceName string = deployAsFunc ? resourceNames.functionName : resou
output appServiceHostName string = deployAsFunc ? functionApp!.outputs.functionAppHostName : appService!.outputs.appServiceHostName
output acrName string = privateAcr ? containerRegistry!.outputs.acrName : ''
output acrUri string = privateAcr ? containerRegistry!.outputs.acrUri : ''
output managedIdentityPrincipalId string = managedIdentity.outputs.principalId
3 changes: 0 additions & 3 deletions deploy/main.parameters.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
"engineAppId": {
"value": "<ENGINE APP REGISTRATION APP/CLIENT ID>"
},
"engineAppSecret": {
"value": "<ENGINE APP REGISTRATION CLIENT SECRET>"
},
"deployAsFunc": {
"value": false
},
Expand Down
4 changes: 0 additions & 4 deletions deploy/modules/appService.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,6 @@ resource appService 'Microsoft.Web/sites@2021-02-01' = {
name: 'ENGINE_APP_ID'
value: '@Microsoft.KeyVault(SecretUri=${keyVaultUri}secrets/ENGINE-ID/)'
}
{
name: 'ENGINE_APP_SECRET'
value: '@Microsoft.KeyVault(SecretUri=${keyVaultUri}secrets/ENGINE-SECRET/)'
}
{
name: 'TENANT_ID'
value: '@Microsoft.KeyVault(SecretUri=${keyVaultUri}secrets/TENANT-ID/)'
Expand Down
6 changes: 1 addition & 5 deletions deploy/modules/functionApp.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,6 @@ resource functionApp 'Microsoft.Web/sites@2021-03-01' = {
name: 'ENGINE_APP_ID'
value: '@Microsoft.KeyVault(SecretUri=${keyVaultUri}secrets/ENGINE-ID/)'
}
{
name: 'ENGINE_APP_SECRET'
value: '@Microsoft.KeyVault(SecretUri=${keyVaultUri}secrets/ENGINE-SECRET/)'
}
{
name: 'TENANT_ID'
value: '@Microsoft.KeyVault(SecretUri=${keyVaultUri}secrets/TENANT-ID/)'
Expand Down Expand Up @@ -248,7 +244,7 @@ resource diagnosticSettingsApp 'Microsoft.Insights/diagnosticSettings@2021-05-01
enabled: true
retentionPolicy: {
days: 0
enabled: false
enabled: false
}
}
]
Expand Down
12 changes: 0 additions & 12 deletions deploy/modules/keyVault.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ param uiAppId string
@description('IPAM-Engine App Registration Client/App ID')
param engineAppId string

@secure()
@description('IPAM-Engine App Registration Client Secret')
param engineAppSecret string

@description('Log Analytics Worskpace ID')
param workspaceId string

Expand Down Expand Up @@ -73,14 +69,6 @@ resource engineId 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = {
}
}

resource engineSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = {
parent: keyVault
name: 'ENGINE-SECRET'
properties: {
value: engineAppSecret
}
}

resource appTenant 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = {
parent: keyVault
name: 'TENANT-ID'
Expand Down
66 changes: 37 additions & 29 deletions engine/app/routers/common/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from azure.cosmos.aio import CosmosClient
from azure.identity.aio import (
ClientSecretCredential,
ClientAssertionCredential,
ManagedIdentityCredential,
OnBehalfOfCredential,
)
Expand Down Expand Up @@ -107,44 +108,51 @@ def get_user_id_from_jwt(token):

return decoded['oid']

async def get_obo_token(assertion):
"""DOCSTRING"""

azure_arm_url = 'https://{}/user_impersonation'.format(globals.AZURE_ARM_URL)

credential = OnBehalfOfCredential(
tenant_id=globals.TENANT_ID,
client_id=globals.CLIENT_ID,
client_secret=globals.CLIENT_SECRET,
user_assertion=assertion
)
obo_token = await credential.get_token(azure_arm_url)
await credential.close()

return obo_token

async def get_client_credentials():
"""DOCSTRING"""

credential = ClientSecretCredential(
tenant_id=globals.TENANT_ID,
client_id=globals.CLIENT_ID,
client_secret=globals.CLIENT_SECRET,
authority=globals.AUTHORITY_HOST
)
# If CLIENT_SECRET is defined, use it for credentials. Otherwise, use the Managed Identity
if globals.CLIENT_SECRET:
credential = ClientSecretCredential(
tenant_id=globals.TENANT_ID,
client_id=globals.CLIENT_ID,
client_secret=globals.CLIENT_SECRET,
authority=globals.AUTHORITY_HOST
)
else:
mi_token = await managed_identity_credential.get_token("api://AzureADTokenExchange")

credential = ClientAssertionCredential(
tenant_id=globals.TENANT_ID,
client_id=globals.CLIENT_ID,
func=lambda: mi_token.token,
authority=globals.AUTHORITY_HOST
)

return credential

async def get_obo_credentials(assertion):
"""DOCSTRING"""

credential = OnBehalfOfCredential(
tenant_id=globals.TENANT_ID,
client_id=globals.CLIENT_ID,
client_secret=globals.CLIENT_SECRET,
user_assertion=assertion,
authority=globals.AUTHORITY_HOST
)
# If CLIENT_SECRET is defined, use it for credentials. Otherwise, use the Managed Identity
if globals.CLIENT_SECRET:
credential = OnBehalfOfCredential(
tenant_id=globals.TENANT_ID,
client_id=globals.CLIENT_ID,
client_secret=globals.CLIENT_SECRET,
user_assertion=assertion,
authority=globals.AUTHORITY_HOST
)
else:
mi_token = await managed_identity_credential.get_token("api://AzureADTokenExchange")

credential = OnBehalfOfCredential(
tenant_id=globals.TENANT_ID,
client_id=globals.CLIENT_ID,
client_assertion_func=lambda: mi_token.token,
user_assertion=assertion,
authority=globals.AUTHORITY_HOST
)

return credential

Expand Down
2 changes: 1 addition & 1 deletion engine/requirements.lock.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ azure-mgmt-datafactory==9.2.0
azure-mgmt-managementgroups==1.0.0
azure-mgmt-network==29.0.0
azure-mgmt-resource==25.0.0
azure-mgmt-resource-subscriptions==1.1.0
azure-mgmt-resource-subscriptions==1.0.0b1
azure-mgmt-resourcegraph==8.0.0
certifi==2025.8.3
cffi==2.0.0
Expand Down
4 changes: 0 additions & 4 deletions migrate/modules/appService.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,6 @@ resource appService 'Microsoft.Web/sites@2021-02-01' = {
name: 'ENGINE_APP_ID'
value: '@Microsoft.KeyVault(SecretUri=${keyVaultUri}secrets/ENGINE-ID/)'
}
{
name: 'ENGINE_APP_SECRET'
value: '@Microsoft.KeyVault(SecretUri=${keyVaultUri}secrets/ENGINE-SECRET/)'
}
{
name: 'TENANT_ID'
value: '@Microsoft.KeyVault(SecretUri=${keyVaultUri}secrets/TENANT-ID/)'
Expand Down