private/Get-MsecCertificateMetadata.ps1
|
function Get-MsecCertificateMetadata { <# .SYNOPSIS Reads the certificate's public metadata from Key Vault: SHA-1 thumbprint and key name. .DESCRIPTION Used by Connect-Msec to set up the session. We do NOT pull the cert's PFX (private key); signing happens inside Key Vault via Invoke-MsecKeyVaultSign. 'Key Vault Reader' is the right role for this call: its data action Microsoft.KeyVault/vaults/*/read covers certificates/read, and its control-plane Actions let Az resolve the vault by name. Do NOT grant 'Key Vault Certificate User' for this. That role also carries Microsoft.KeyVault/vaults/secrets/getSecret/action, and a Key Vault-generated certificate is readable as a secret of the same name - which returns the full PFX INCLUDING the private key. Granting it hands over the ability to impersonate the app registration anywhere, which is exactly what keeping the key in Key Vault is meant to prevent. Returns the SHA-1 thumbprint as both hex (informational) and bytes (used directly in the JWT x5t header per RFC 7515), and the key name (same as the cert name when KV created them together via Add-AzKeyVaultCertificate). #> [CmdletBinding()] param( [Parameter(Mandatory)] [string] $VaultName, [Parameter(Mandatory)] [string] $CertificateName ) if (-not (Get-AzContext -ErrorAction SilentlyContinue)) { throw 'No Azure context. Run Connect-AzAccount before Connect-Msec.' } Write-Verbose "Reading certificate metadata for '$CertificateName' from Key Vault '$VaultName'" $kvCert = Get-AzKeyVaultCertificate -VaultName $VaultName -Name $CertificateName -ErrorAction Stop if (-not $kvCert) { throw "Certificate '$CertificateName' not found in Key Vault '$VaultName'." } # Thumbprint comes back as an uppercase hex string. Decode to bytes for x5t. $hex = $kvCert.Thumbprint $bytes = New-Object byte[] ($hex.Length / 2) for ($i = 0; $i -lt $bytes.Length; $i++) { $bytes[$i] = [Convert]::ToByte($hex.Substring($i * 2, 2), 16) } # Tags are stamped on by New-MsecApp so Connect-Msec can recover AppId/TenantId # without the user having to pass them. Missing tags surface as $null - the caller decides. $tags = if ($kvCert.Tags) { $kvCert.Tags } else { @{} } [PSCustomObject]@{ Thumbprint = $hex ThumbprintBytes = [byte[]]$bytes KeyName = $kvCert.Name AppId = $tags['AppId'] TenantId = $tags['TenantId'] } } |