ContainerHandling/Set-BcContainerKeyVaultAadAppAndCertificate.ps1

<#
 .Synopsis
  Import Certificate for Keyvault access to a BC Container
 .Description
  Import Certificate for Keyvault access to a BC Container
 .Parameter containerName
  Name of the container in which you want to import a certificate
 .Parameter pfxFile
  Path or secure url to the pfx certificate file which gives access to AAD app with clientId
 .Parameter pfxPassword
  Password for pfx certificate file which gives access to AAD app with clientId
 .Parameter clientId
  clientId of AAD app with access to Key Vault used in apps
 .Parameter enablePublisherValidation
  include this switch to disallow access to keyvault when running from VS Code (include for production)
 .Parameter doNotRestartServiceTier
  set this switch to defer restart of service tier
 .Example
  Set-BcContainerKeyVaultAadAppAndCertificate -containerName $containerName -pfxFile $pfxFile -pfxPassword $pfxPassword -clientId $clientId
#>

function Set-BcContainerKeyVaultAadAppAndCertificate {
    Param(
        [string] $containerName = $bcContainerHelperConfig.defaultContainerName, 
        [Parameter(Mandatory=$true)]
        [string] $pfxFile,
        [Parameter(Mandatory=$true)]
        [SecureString] $pfxPassword,
        [Parameter(Mandatory=$true)]
        [string] $clientId,
        [switch] $enablePublisherValidation,
        [switch] $doNotRestartServiceTier
    )
    
$telemetryScope = InitTelemetryScope -name $MyInvocation.InvocationName -parameterValues $PSBoundParameters -includeParameters @()
try {

    $ExtensionsFolder = Join-Path $bcContainerHelperConfig.hostHelperFolder "Extensions"
    $sharedPfxFile = Join-Path $ExtensionsFolder "$containerName\my\$([GUID]::NewGuid().ToString()).pfx"
    $removeSharedPfxFile = $true
    if ($pfxFile -like "https://*" -or $pfxFile -like "http://*") {
        Write-Host "Downloading certificate file to container"
        (New-Object System.Net.WebClient).DownloadFile($pfxFile, $sharedPfxFile)
    }
    else {
        if (Get-BcContainerPath -containerName $containerName -path $pfxFile) {
            $sharedPfxFile = $pfxFile
            $removeSharedPfxFile = $false
        }
        else {
            Write-Host "Copying certificate file to container"
            Copy-Item -Path $pfxFile -Destination $sharedPfxFile -Force
        }
    }

    try {
        TestPfxCertificate -pfxFile $sharedPfxFile -pfxPassword $pfxPassword -certkind "KeyVault"
    
        Invoke-ScriptInBcContainer -containerName $containerName -scriptblock { Param($pfxFile, $pfxPassword, $clientId, $enablePublisherValidation, $doNotRestartServiceTier)
    
            # Set AzureKeyVaultAppSecretsPublisherValidationEnabled to false to avoid having to publish with PublisherAzureActiveDirectoryTenantId
            Set-NAVServerConfiguration -ServerInstance $serverInstance -KeyName "AzureKeyVaultAppSecretsPublisherValidationEnabled" -KeyValue $enablePublisherValidation.ToString().ToLowerInvariant() -WarningAction SilentlyContinue
            
            $importedPfxCertificate = Import-PfxCertificate -FilePath $pfxFile -Password $pfxPassword -CertStoreLocation Cert:\LocalMachine\My
            Write-Host "Keyvault Certificate Thumbprint: $($importedPfxCertificate.Thumbprint)"
            
            # Give SYSTEM permission to use the PFX file's private key
            $keyName = $importedPfxCertificate.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
            $keyPath = "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\$keyName"
            $acl = (Get-Item $keyPath).GetAccessControl('Access')
            $permission = 'NT AUTHORITY\SYSTEM',"Full","Allow"
            $accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission
            $acl.AddAccessRule($accessRule)
            Set-Acl $keyPath $acl
            #$acl.Access
            
            Set-NavServerConfiguration -ServerInstance $serverInstance -KeyName AzureKeyVaultClientCertificateStoreLocation -KeyValue "LocalMachine" -WarningAction SilentlyContinue
            Set-NavServerConfiguration -ServerInstance $serverInstance -KeyName AzureKeyVaultClientCertificateStoreName     -KeyValue "My" -WarningAction SilentlyContinue
            Set-NavServerConfiguration -ServerInstance $serverInstance -KeyName AzureKeyVaultClientCertificateThumbprint    -KeyValue $importedPfxCertificate.Thumbprint -WarningAction SilentlyContinue
            Set-NavServerConfiguration -ServerInstance $serverInstance -KeyName AzureKeyVaultClientId                       -KeyValue $clientId -WarningAction SilentlyContinue
            
            if (!$doNotRestartServiceTier) {
                Write-Host "Restarting Service Tier"
                Set-NAVServerInstance -ServerInstance $serverInstance -Restart
                while (Get-NavTenant $serverInstance | Where-Object { $_.State -eq "Mounting" }) {
                    Start-Sleep -Seconds 1
                }
            }
        } -argumentList (Get-BcContainerPath -containerName $containerName -path $sharedPfxFile), $pfxPassword, $clientId, $enablePublisherValidation, $doNotRestartServiceTier
    }
    finally {
        if ($removeSharedPfxFile -and (Test-Path $sharedPfxFile)) {
            Remove-Item -Path $sharedPfxFile -Force
        }
    }
}
catch {
    TrackException -telemetryScope $telemetryScope -errorRecord $_
    throw
}
finally {
    TrackTrace -telemetryScope $telemetryScope
}
}
Export-ModuleMember -Function Set-BcContainerKeyVaultAadAppAndCertificate