Infraestructura de clave pública (PKI) para las operaciones desconectadas en Azure Local

En este artículo se explican los requisitos de infraestructura de clave pública (PKI) para las operaciones desconectadas en Azure Local. Aprenderá a crear certificados para proteger los puntos de conexión del dispositivo y a garantizar una comunicación segura en su entorno.

Información general de PKI para operaciones desconectadas

La PKI para las operaciones desconectadas es esencial para proteger los puntos de conexión que proporciona el dispositivo de operaciones desconectadas. Cree y administre certificados digitales para garantizar la comunicación segura y la transferencia de datos en el entorno local de Azure.

Requisitos de PKI

Los certificados deben proceder de una entidad de certificación pública (CA) o de una entidad de certificación de empresa. Asegúrese de que los certificados forman parte del Programa raíz de confianza de Microsoft. Para obtener más información, vea Lista de participantes: Programa raíz de confianza de Microsoft.

Agrupe los certificados obligatorios por área con el Nombre Alternativo del Sujeto (SAN) adecuado. Antes de crear los certificados, revise estos requisitos:

  • No se admite el uso de certificados autofirmados. Se recomienda usar certificados emitidos por una entidad de certificación empresarial.
  • Las operaciones desconectadas requieren 23 certificados externos para los puntos de conexión que expone.
  • Genere certificados individuales para cada punto de conexión y cópielos en la estructura de directorios o carpetas correspondiente. Estos certificados son necesarios para la implementación de operaciones desconectadas.
  • Defina el asunto y el SAN para todos los certificados, como lo requieren la mayoría de los navegadores.
  • Todos los certificados deben compartir la misma cadena de confianza y tener al menos una expiración de dos años desde el día de la implementación.
  • Exporte todos los certificados raíz en formato codificado en Base64. El archivo resultante normalmente tiene una extensión .cer, .crt o .pem.
  • Para implementaciones totalmente desconectadas:
    • Use una entidad de certificación (CA) privada o interna.
    • Solo se requiere acceso de red interno al punto de conexión de lista de revocación de certificados (CRL).
    • No se requiere conectividad a Internet.
    • Asegúrese de que la infraestructura de operaciones desconectadas pueda alcanzar el punto de distribución de la CRL especificado en la extensión CRL Distribution Point (CDP) de los certificados.
    • Use el script del apéndice para validar los puntos de conexión de CRL si no está seguro de si la configuración es correcta.
    • No use una ENTIDAD de certificación pública o externa. Se produce un error en las implementaciones si los certificados proceden de una entidad de certificación pública, ya que se requiere conectividad a Internet para acceder a los servicios CRL y Protocolo de estado de certificado en línea (OCSP) para HTTPS.

Requisitos de certificado de punto de conexión de entrada

En esta tabla se enumeran los certificados obligatorios necesarios para las operaciones desconectadas en Azure Local.

Servicio Sujeto del certificado requerido y Nombre Alternativo del Sujeto (SAN)
almacenamiento de blobs de Azure *.blob.fqdn
Azure Container Registry (Registro de Contenedores de Azure) *.edgeacr.fqdn
Azure Queue Storage *.queue.fqdn
Azure Service Bus (bus de servicios de Azure) *.servicebus.fqdn
Azure Almacenamiento de Tablas *.table.fqdn
Azure Key Vault *.vault.fqdn
Gestión de administradores adminmanagement.fqdn
Servicio de datos de Arc for Server Agent agentserviceapi.fqdn
Agente de supervisión de Arc amcs.monitoring.fqdn
Plano de datos de configuración de Arc

Kubernetes habilitado con Azure Arc
arckubernetesconfig.fqdn
Azure Resource Manager armmanagement.fqdn

management.fqdn
API de catálogo del portal público catalogapi.fqdn
directiva de datos de Azure data.policy.fqdn
Plano de datos del puente de recursos de Azure Arc dp.appliances.fqdn
Licencias dp.aszrp.fqdn
Dispositivos de interfaz frontal frontend.appliances.fqdn
Gráfico graph.fqdn
Servicio de notificaciones de invitado de Arc guestnotificationservice.fqdn
Arc para el servidor his.fqdn
Hospedaje del portal público hosting.fqdn
Servicio de token seguro login.fqdn
Métricas de arco metricsingestiongateway.monitoring.fqdn
Portal Público portal.fqdn

Puntos de conexión de administración

El punto de conexión de administración requiere dos certificados. Coloque estos certificados en la misma carpeta, ManagementEndpointsCerts. Los certificados son:

Certificado de punto de conexión de administración Sujeto del certificado requerido
Servidor Dirección IP del punto de conexión de administración: $ManagementIngressIpAddress.
Si la dirección IP del punto de conexión de administración es 192.168.50.100, el nombre del firmante del certificado de servidor debe coincidir exactamente. Por ejemplo, Subject = 192.168.50.100. También puede usar un nombre de dominio completo (FQDN) como nombre de servidor (SN) siempre que se resuelva en la dirección IP de administración.
Cliente Utilice un asunto de certificado que lo ayude a distinguirlo de otros. Cualquier cadena es aceptable.
Por ejemplo, Subject = ManagementEndpointClientAuth.

Creación de certificados para proteger puntos de conexión

Puntos de conexión de entrada

En la máquina host o la máquina virtual (VM) de Active Directory, siga los pasos descritos en esta sección para crear certificados para el tráfico de entrada y los puntos de conexión externos del dispositivo de operaciones desconectados. OperationsModule proporciona métodos auxiliares para generar solicitudes de firma de certificados o automatizar la creación completa de certificados.

Necesita estos certificados para implementar el dispositivo de operaciones desconectado. También necesita la clave pública para la infraestructura local para proporcionar una cadena de confianza segura.

Nota:

IngressEndpointsCerts es la carpeta donde se almacenan todos los archivos de certificado. IngressEndpointPassword es una cadena segura con la contraseña del certificado.

  1. Conéctese a la Autoridad de Certificación.
  2. Cree una carpeta denominada IngressEndpointsCerts. Use esta carpeta para almacenar todos los certificados.
  3. Cree los certificados mediante el método auxiliar OperationsModule con la carpeta IngressEndpointsCerts de destino.
  4. Vea y copie los certificados (23 archivos .pfx) exportados a IngressEndpointsCerts.

El siguiente script muestra cómo usar OperationsModule para generar certificados. El script crea solicitudes de firma de certificados (CSR), las envía a su entidad de certificación (CA) y luego exporta los certificados generados con protección de contraseña.

Nota:

Ejecute este script en una máquina unida a un dominio mediante una cuenta con acceso de administrador de dominio para emitir certificados.

# Make sure you have the OperationsModule in this folder
# In the Appendix you can find an alternative to the OperationModule if you prefer writing your own automation

$applianceConfigBasePath = "C:\AzureLocalDisconnectedOperations\"
$fqdn = "autonomous.cloud.private" 
$IngressEndpointsCertsFolder = 'C:\Certs\IngressEndpointsCerts'
$certPassword  = Read-Host 'Password for output certificate file .pfx' -AsSecureString
## Automation alternative
## $certPassword =  (ConvertTo-SecureString "REPLACEME" -AsPlainText -Force)
$caName = "mycaserver.contoso.com\Contoso-RootCA" # Replace with your CA server and CA name (Run certutil -config - -ping to find the names)

Import-Module "$applianceConfigBasePath\OperationsModule\Azure.Local.DisconnectedOperations.psd1" -Force

New-ApplianceExternalCertificatesFromCA -ExternalFQDN $fqdn -OutputFolder $IngressEndpointsCertsFolder -CAConfig $caName -CertificatePassword $certPassword

Punto de conexión de administración

Este es un ejemplo de cómo crear certificados para proteger el punto de conexión de administración.

Nota:

Ejecute este script en una máquina unida a un dominio mediante una cuenta con acceso de administrador de dominio para emitir certificados.

Después de crear los certificados, copie los certificados de administración (*.pfx) en la estructura de directorios representada en ManagementEndpointCerts.

$applianceConfigBasePath = "C:\AzureLocalDisconnectedOperations\"
$fqdn = "autonomous.cloud.private" 
$managementEndpointIp = '192.168.100.25'
$managementEndpointCertsFolder = 'C:\Certs\ManagementEndpointsCerts'
$certPassword  = Read-Host 'Password for output certificate file .pfx' -AsSecureString
## Automation alternative
## $certPassword =  (ConvertTo-SecureString "REPLACEME" -AsPlainText -Force)
$caName = "mycaserver.contoso.com\Contoso-RootCA" # Replace with your CA server and CA name (Run certutil -config - -ping to find the names)

Import-Module "$applianceConfigBasePath\OperationsModule\Azure.Local.DisconnectedOperations.psd1" -Force

New-ApplianceManagementCertificatesFromCA -ManagementEndpoint $managementEndpointIp -OutputFolder $managementEndpointCertsFolder -CAConfig $caName -CertificatePassword $certpassword

Exportar certificado de CA raíz

Necesita la clave pública del certificado raíz para la implementación. Exporte el certificado raíz con codificación base64.

Este es un ejemplo de cómo exportar la clave pública del certificado raíz:

$applianceRootcert = "C:\AzureLocalDisconnectedOperations\applianceRoot.cer"
$dcName = "corp.contoso.com"
$caName = "$($dcname)$\Contoso-RootCA" # Replace with your CA server and CA name (Run certutil -config - -ping to find the names)

# Option 1) Get the Root CA certificate by its name:
$RootCACert = Get-ChildItem -Path Cert:\LocalMachine\Root | Where-Object { $_.Subject -like "*$($dcname)*" } | Select-Object -First 1

# # Option 2) Get the Root CA certificate by its thumbprint:
$RootCACert = Get-ChildItem -Path Cert:\LocalMachine\Root | Where-Object { $_.Thumbprint -eq "AA11BB22CC33DD44EE55FF66AA77BB88CC99DD00" } | Select-Object -First 1

# Check you have the correct Root CA certificate:
$RootCACert

# If it matches, export in CER (DER) format
Export-Certificate -Cert $RootCACert -FilePath "C:\Temp\RootCA-DER.cer" -Type CERT

# Finally, convert from CER (DER) to Base-64 CER (and store it in $applianceRootcert)
certutil -encode "C:\Temp\RootCA-DER.cer" $applianceRootcert

## Alternative method (If CA is setup and responds)
# certutil -ca.cert $applianceRootCert

Para obtener más información, consulte Active Directory Certificate Services (Servicios de certificados de Active Directory).

Nota:

Se requiere el certificado raíz. Use el certificado raíz explícito, no un certificado intermedio. Se produce un error en la implementación si falta la cadena de plena confianza para los certificados de punto de conexión de entrada.

Obtener información del certificado para la integración de identidades

Para proteger la integración de identidades, pase estos dos parámetros:

  • LdapsCertChainInfo
  • OidcCertChainInfo

Estas comprobaciones confirman que los certificados y la cadena de estos puntos de conexión no se modifican ni manipulan.

Use un método auxiliar en OperationsModule para rellenar estos parámetros.

Este es un ejemplo de cómo rellenar los parámetros necesarios:

Import-Module "$applianceConfigBasePath\OperationsModule\Azure.Local.DisconnectedOperations.psd1" -Force
$oidcCertChain = Get-CertificateChainFromEndpoint -requestUri 'https://adfs.azurestack.local/adfs'
$ldapsCertChain = Get-CertificateChainFromEndpoint -requestUri 'https://dc01.azurestack.local'

Este es un ejemplo de la salida de Get-CertificateChainFromEndpoint

# Returns: System.Security.Cryptography.X509Certificates.X509Certificate2[]
>> Get-CertificateChainFromEndpoint
>>
Thumbprint                                Subject
----------                                -------
TESTING580E20618EA15357FC1028622518DDC4D  CN=www.website.com, O=Contoso Corporation, L=Redmond, S=WA, C=US
TESTINGDAA2345B48E507320B695D386080E5B25  CN=www.website.com, O=Contoso Corporation, L=Redmond, S=WA, C=US
TESTING9BFD666761B268073FE06D1CC8D4F82A4  CN=www.website.com, O=Contoso Corporation, L=Redmond, S=WA, C=US

Apéndice

Validación de CRL mediante el script de PowerShell

  • Copie el siguiente script en un archivo y asígnelo el nombre ValidateCRL.ps1
  • Invocación del script mediante .\ValidateCRL.ps1 -domainFQDN 'cloud.contoso.com'
# Powershell script for validation of certificates

param (
[Parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [string] $domainFQDN = "cloud.contoso.com"
)


$portalURI = "https://portal.$domainFQDN"
$armURI = "https://armmanagement.$domainFQDN/metadata/endpoints?api-version=2022-09-01"


Add-Type -AssemblyName System.Net.Http


foreach ($uri in @($portalURI, $armURI)) {
    Write-Host "`n============================================" -ForegroundColor Cyan
    Write-Host "Testing: $uri" -ForegroundColor Cyan
    Write-Host "============================================" -ForegroundColor Cyan


    # --- Test 1: CRL check ENABLED (matches your failing code) ---
    Write-Host "`n[CRL CHECK = TRUE]" -ForegroundColor Yellow
    try {
        $handler = [System.Net.Http.HttpClientHandler]::new()
        $handler.CheckCertificateRevocationList = $true
        $client = [System.Net.Http.HttpClient]::new($handler)
        $task = $client.GetAsync($uri)
        $response = $task.GetAwaiter().GetResult()
        Write-Host "  Status: $([int]$response.StatusCode) ($($response.StatusCode))" -ForegroundColor Green
    }
    catch {
        Write-Host "  FAILED:" -ForegroundColor Red
        $ex = $_.Exception
        $depth = 0
        while ($ex) {
            $indent = "  " + ("  " * $depth)
            Write-Host "${indent}[$($ex.GetType().FullName)]" -ForegroundColor Red
            Write-Host "${indent}Message: $($ex.Message)" -ForegroundColor Red
            Write-Host "${indent}HResult: 0x$($ex.HResult.ToString('X8'))" -ForegroundColor DarkYellow
            $ex = $ex.InnerException
            $depth++
        }
    }
    finally {
        if ($client) { $client.Dispose() }
        if ($handler) { $handler.Dispose() }
    }


    # --- Test 2: CRL check DISABLED (matches your passing PowerShell test) ---
    Write-Host "`n[CRL CHECK = FALSE]" -ForegroundColor Yellow
    try {
        $handler2 = [System.Net.Http.HttpClientHandler]::new()
        $handler2.CheckCertificateRevocationList = $false
        $client2 = [System.Net.Http.HttpClient]::new($handler2)
        $task2 = $client2.GetAsync($uri)
        $response2 = $task2.GetAwaiter().GetResult()
        Write-Host "  Status: $([int]$response2.StatusCode) ($($response2.StatusCode))" -ForegroundColor Green
    }
    catch {
        Write-Host "  FAILED:" -ForegroundColor Red
        $ex2 = $_.Exception
        $depth2 = 0
        while ($ex2) {
            $indent2 = "  " + ("  " * $depth2)
            Write-Host "${indent2}[$($ex2.GetType().FullName)]" -ForegroundColor Red
            Write-Host "${indent2}Message: $($ex2.Message)" -ForegroundColor Red
            $ex2 = $ex2.InnerException
            $depth2++
        }
    }
    finally {
        if ($client2) { $client2.Dispose() }
        if ($handler2) { $handler2.Dispose() }
    }
}



Creación de scripts de certificados basados en scripts

Si prefiere controlar la generación de certificados, aquí hay un ejemplo que puede modificar para crear solicitudes de firma de certificados y emitir certificados.

$fqdn = "autonomous.cloud.private" 
$caName = "<CA Computer Name>\<CA Name>" # Replace with your CA server and CA name (Run certutil -config - -ping to find the names)

$extCertFilePath = "C:\AzureLocalDisconnectedOperations\Certs\IngressEndpointsCerts"
# Making sure to create this directory if it does not exist
[void](New-Item -ItemType Directory -path $extCertFilePath -force)

$certPassword = Read-Host -AsSecureString -Message 'CertPass' -Force  
# Alternative
# $certPassword = "REPLACEME"|ConvertTo-SecureString -AsPlainText -Force
# Make sure the certificate list matches the table. Refer to the "Ingress endpoint certificate requirements" section for details.
$AzLCerts = @(    
  "*.edgeacr.$fqdn"      
  "*.vault.$fqdn"
  "*.queue.$fqdn"    
  "*.table.$fqdn"
  "*.blob.$fqdn" 
  "*.servicebus.$fqdn"   
  "data.policy.$fqdn"
  "arckubernetesconfig.$fqdn"
  "agentserviceapi.$fqdn"
  "his.$fqdn"
  "guestnotificationservice.$fqdn"
  "metricsingestiongateway.monitoring.$fqdn"
  "amcs.monitoring.$fqdn"
  "dp.appliances.$fqdn"
  "armmanagement.$fqdn"
  "adminmanagement.$fqdn"
  "management.$fqdn"
  "frontend.appliances.$fqdn"
  "graph.$fqdn"
  "dp.aszrp.$fqdn"
  "portal.$fqdn"
  "hosting.$fqdn"    
  "catalogapi.$fqdn"    
  "login.$fqdn"    
  # Multi-San could be added with comma seperated list x.$fqdn,y.$fqdn    
)

$AzLCerts | ForEach-Object {
    # Check if this is a multi SAN certificate
    if ($_.Contains(',')) {
        $certSubject = "CN=$($_.Split(',')[0])"
        $dns = $_.Replace(',', '&DNS=').Replace(' ', '')
        $filePrefix = $_.Split(',')[0].Replace('*.', '')
    }
    else {
        $certSubject = "CN=$_"
        $dns = $certSubject.Split('=')[1]
        $filePrefix = $dns.Replace('*.', '')
    }
    $certFilePath = "$extCertFilePath\INF"
    New-Item -ItemType Directory -Path $certFilePath -Force | Out-Null
    Remove-Item "$certFilePath\$filePrefix.*" -Force -ErrorAction SilentlyContinue
    $csrPath = Join-Path -Path $certFilePath -ChildPath "$filePrefix.csr"
    $infPath = Join-Path -Path $certFilePath -ChildPath "$filePrefix.inf"

    # Create the INF file for the CSR
    @"
[NewRequest]
Subject = "$certSubject"
KeySpec = 1
KeyLength = 2048
Exportable = TRUE
MachineKeySet = TRUE
SMIME = FALSE
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = PKCS10
KeyUsage = 0xa0
HashAlgorithm = sha256

[Extensions]
2.5.29.17 = "{text}"
_continue_ = "DNS=$dns"
"@ | Out-File -FilePath $infPath

    # Generate the CSR
    certreq -new $infPath $csrPath
    # Define parameters to submit the CSR
    $certPath = Join-Path $certFilePath -ChildPath "$filePrefix.cer"

    # Submit the CSR to the CA
    certreq -submit -attrib "CertificateTemplate:WebServer" -config $caName $csrPath $certPath
    Write-Verbose "Certificate request submitted. Certificate saved to $certPath" -Verbose

    # Accept the certificate and install it.
    $certReqOutput = certreq.exe -accept $certPath

    # Parse the thumbprint and export the certificate
    $match = $certReqOutput -match 'Thumbprint:\s*([a-fA-F0-9]+)'
    if ($null -ne $match) {
        $thumbprint = (($match[0]).Split(':')[1]).Trim()
        Write-Verbose "Thumbprint: $thumbprint" -Verbose
    }
    else {
        Write-Verbose "Thumbprint not found" -Verbose
        #return;
    }

    # Export the certificate to a PFX file
    $cert = Get-Item -Path "Cert:\LocalMachine\My\$thumbprint"
    $cert | Export-PfxCertificate -FilePath "$extCertFilePath\$filePrefix.pfx" -Password $certPassword -Force
    Write-Verbose "Certificate for $certSubject and private key exported to $extCertFilePath" -Verbose
}
# Management certs alternative method
$caName = "mycaserver.contoso.com\Contoso-RootCA" # Replace with your CA server and CA name (Run certutil -config - -ping to find the names)

# For more info on how to find your CA: https://mms.heiai.top/en-us/troubleshoot/windows-server/certificates-and-public-key-infrastructure-pki/find-name-enterprise-root-ca-server 
$certPassword = Read-Host -AsSecureString -Message 'ManagementCertPass' -Force 
# Alternative
# $certPassword = "REPLACEME"|ConvertTo-SecureString -AsPlainText -Force

$managementendpointPath = "C:\AzureLocalDisconnectedOperations\Certs\ManagementEndpointsCerts"
[void](New-Item -ItemType Directory -path $managementendpointPath -force)
$managementEndpointIPAddress = '192.168.100.25'
$fileNames = @('ManagementEndpointSsl', 'ManagementEndpointClientAuth')
$subjects = @($managementEndpointIPAddress,'ManagementEndpointClientAuth')  

$subjects|Foreach-Object {
    $subject=$_    
    $filename = $fileNames[$subjects.IndexOf($_)] 
    $infFilename = "$($managementendpointPath)\$($filename).inf"
    $csrPath = "$($managementendpointPath)\$($filename).csr"
    $certPath = "$($managementendpointPath)\$($filename).cer"
    $pfxPath = "$($managementendpointPath)\$($filename).pfx"
@"
[NewRequest]
Subject = "CN=$subject"
KeySpec = 1
KeyLength = 2048
Exportable = TRUE
MachineKeySet = TRUE
SMIME = FALSE
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = PKCS10
KeyUsage = 0xa0
HashAlgorithm = sha256

[Extensions]
2.5.29.17 = "{text}"
_continue_ = "DNS=$subject"
"@ | Out-File -FilePath $infFilename

    # Generate the CSR
    certreq -new $infFilename $csrPath

    # Submit the CSR to the CA
    certreq -submit -attrib "CertificateTemplate:WebServer" -config $caName $csrPath $certPath
    Write-Verbose "Certificate request submitted. Certificate saved to $certPath" -Verbose

    # Accept the certificate and install it.
    $certReqOutput = certreq.exe -accept $certPath

    # Parse the thumbprint and export the certificate
    $match = $certReqOutput -match 'Thumbprint:\s*([a-fA-F0-9]+)'
    if ($null -ne $match) {
        $thumbprint = (($match[0]).Split(':')[1]).Trim()
        Write-Verbose "Thumbprint: $thumbprint" -Verbose
    }
    else {
        Write-Verbose "Thumbprint not found" -Verbose
        #return;
    }

    # Export the certificate to a PFX file
    $cert = Get-Item -Path "Cert:\LocalMachine\My\$thumbprint"
    $cert | Export-PfxCertificate -FilePath $pfxPath -Password $certPassword -Force
    Write-Verbose "Certificate for $subject and private key exported to $certPath" -Verbose
}

Esta característica solo está disponible en Azure Local 2602 o posterior.