diff --git a/Installation/ImportAzureADApplicationProxy.ps1 b/Installation/ImportAzureADApplicationProxy.ps1 index ca1c614..c2da3a7 100644 --- a/Installation/ImportAzureADApplicationProxy.ps1 +++ b/Installation/ImportAzureADApplicationProxy.ps1 @@ -1,17 +1,11 @@ <# .SYNOPSIS -Imports a cert from simple-acme (WACS) renewal into Azure AD Application Proxy for all applications that are using it. You likely want to use a wildcard certificate for this purpose. +Imports a cert from simple-acme renewal into Azure AD Application Proxy for all applications that are using it. You likely want to use a wildcard certificate for this purpose. .DESCRIPTION -Note that this script is intended to be run via the install script plugin from simple-acme (WACS) via the batch script wrapper. As such, we use positional parameters to avoid issues with using a dash in the cmd line. +Note that this script is intended to be run via the install script plugin from simple-acme via the batch script wrapper. As such, we use positional parameters to avoid issues with using a dash in the cmd line. -Proper information should be available here - -https://github.com/simple-acme/simple-acme/wiki/Install-Script - -or more generally, here - -https://github.com/simple-acme/simple-acme/wiki/Example-Scripts +Uses Microsoft Graph API instead of deprecated AzureAD module. .PARAMETER PfxPath The absolute path to the pfx file that will be uploaded to Azure. Typically use '{CacheFile}' @@ -20,77 +14,83 @@ The absolute path to the pfx file that will be uploaded to Azure. Typically use The password for the pfx file. Typically use '{CachePassword}' .PARAMETER Username -Username of account to login with Connect-AzureAD. This account must have the "Application administrator" role to allow it to change the proxy certificate. +Username of account to login with Connect-MgGraph. This account must have the "Application administrator" role. .PARAMETER Password -Password for the azure account +Password for the account .EXAMPLE - -ImportAzureApplicationGateway.ps1 +ImportAzureApplicationGateway.ps1 .NOTES -Wanted to use a service principal instead of an account for this, but since there is a bug with the cmdlets used, we can't. Instead a regular account must be specified. -https://github.com/Azure/azure-docs-powershell-azuread/issues/200 - - +This uses the Microsoft Graph API instead of the deprecated Azure AD module which no longer works. +Unfortunately, the graph API doesn't have good (or any really) documentation about managing certificates. #> param( - [Parameter(Position=0,Mandatory=$false)][string]$PfxPath, + [Parameter(Position=0,Mandatory=$true)][string]$PfxPath, [Parameter(Position=1,Mandatory=$true)][string]$CertPass, [Parameter(Position=2,Mandatory=$true)][string]$Username, [Parameter(Position=3,Mandatory=$true)][string]$Password - - ) -# Convert the password for the certificate to a secure string -$SecureCertPass = ConvertTo-SecureString -String $CertPass -AsPlainText -Force +if (!(Get-Command "Get-MGBetaApplication" -ErrorAction SilentlyContinue)) { + Throw "Missing Microsoft.Graph.Beta module, install with 'Install-Module -Name Microsoft.Graph.Beta -Scope AllUsers'" +} + +# Connect to Microsoft Graph using username/password +$SecurePassword = ConvertTo-SecureString -String $Password -AsPlainText -Force +$ClientId = "1950a258-227b-4e31-a9cf-717495945fc2" # Microsoft Azure PowerShell app ID + +# Get access token +$body = @{ + grant_type = "password" + client_id = $ClientId + username = $Username + password = $Password + scope = "https://graph.microsoft.com/.default" +} +$tokenResponse = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/organizations/oauth2/v2.0/token" -Body $body +$accessToken = $tokenResponse.access_token | ConvertTo-SecureString -AsPlainText -Force -if (!(Get-Command "Set-AzureAdApplicationProxyApplicationCustomDomainCertificate" -erroraction SilentlyContinue)) { - Throw "Missing AzureAD module, install with 'Install-Module -name AzureAD -Scope AllUsers'" -} +Connect-MgGraph -AccessToken $accessToken -NoWelcome -# Connect to Azure -$Pass = ConvertTo-SecureString -String $Password -AsPlainText -Force -$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username, $Pass -$null = Connect-AzureAD -Credential $Credential -# It's easier, apparently, to search for the service principals that are tagged with WindowsAzureActiveDirectoryOnPremApp, -# then match them to the Get-AzureADApplication output by AppId. -# Get-AzureADApplication doesn't have any way to filter only for ones using the application proxy, and -# Get-AzureADApplicationProxyApplication requires an ObjectId, there's no way to just list them all. -$aadapServPrinc = Get-AzureADServicePrincipal -Top 100000 | where-object {$_.Tags -Contains "WindowsAzureActiveDirectoryOnPremApp"} -# Now we get a list of all Azure AD Applications -$aadapps = Get-AzureADApplication -All $true -# The AppId between $aadapServPrinc and $aadapps is the same for each of the applications using Azure AD Application Proxy. -# What we need to get is the ObjectId from $aadapps for each application that was in $aadapServPrinc -$aadproxyapps = $aadapServPrinc | Foreach-Object { $aadapps -match $_.AppId} -# Now $aadaproxyapps has just the Get-AzureADApplication objects for applications that use the Azure AD Application Proxy. +# Get service principals tagged with WindowsAzureActiveDirectoryOnPremApp +$aadapServPrinc = Get-MgBetaServicePrincipal -All | Where-Object {$_.Tags -Contains "WindowsAzureActiveDirectoryOnPremApp"} -"Found $($aadproxyapps.count) applications to update" +# Get all applications +$aadapps = Get-MgBetaApplication -All -# Get the matching objects from Get-AzureADApplicationProxyApplication and show the certificate being used -#$aadproxyapps | Foreach-Object { -# $proxyapp = Get-AzureADApplicationProxyApplication -ObjectId $_.ObjectId -# Write-Host "Checking $($proxyapp.ExternalUrl)" -# Write-Host "Existing certificate is: $($proxyapp.VerifiedCustomDomainCertificatesMetadata)" -# -#} +# Match by AppId to get proxy applications +$aadproxyapps = $aadapServPrinc | ForEach-Object { $aadapps | Where-Object AppId -eq $_.AppId } -# The documentation says "If you have one certificate that includes many of your applications, you only need to upload it with one application and it will also be assigned to the other relevant applications." -# That does not seem to be the case. Updating the certificate for one application only updated that single application, the rest keep using the old certificate. -# Perhaps it just takes a bit to update, but I thought it safer to just update all of them. +"Found $($aadproxyapps.count) applications to update" -$aadproxyapps | Foreach-Object { +# Read certificate and convert to Base64 +$certBytes = [System.IO.File]::ReadAllBytes($PfxPath) +$certBase64 = [System.Convert]::ToBase64String($certBytes) + +# Update each application +$aadproxyapps | ForEach-Object { "Updating certificate for $($_.DisplayName)" - Set-AzureADApplicationProxyApplicationCustomDomainCertificate -ObjectId $_.ObjectId -PfxFilePath $PfxPath -Password $SecureCertPass + + $body = @{ + onPremisesPublishing = @{ + verifiedCustomDomainKeyCredential = @{ + type="X509CertAndPassword"; + value = $certBase64 + }; + + verifiedCustomDomainPasswordCredential = @{ value = $CertPass }; + } + } | ConvertTo-Json -Depth 10 + + Update-MgBetaApplication -applicationid $_.Id -BodyParameter $body } - -Disconnect-AzureAD \ No newline at end of file +$null = Disconnect-MgGraph