Transición a diferentes modos de PKI

Google Distributed Cloud (GDC) aislado proporciona una API de infraestructura de clave pública (PKI) para obtener certificados web. En esta página, se proporcionan instrucciones para cambiar de un modo de certificado de PKI a otro. Para obtener más información sobre los tipos de configuración del modo de PKI, consulta Configuración de certificados TLS web.

Antes de comenzar

Para obtener los permisos que necesitas para configurar la entidad emisora de certificados predeterminada de la PKI, pídele a tu administrador de IAM de la organización que te otorgue el rol de administrador de PKI de Infraestructura (infra-pki-admin) en el espacio de nombres del sistema.

Transición al modo de subCA BYO

En esta sección, se proporcionan una serie de pasos para realizar la transición al modo de certificado de SubCA propio (BYO).

Crea una sub-CA BYO

Para crear una subCA externa, aplica un recurso personalizado a tu zona de Distributed Cloud.

  1. Crea un recurso CertificateAuthority y guárdalo como un archivo YAML. En el siguiente ejemplo, verás un recurso CertificateAuthority de muestra.

    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateAuthority
    metadata:
      name: CA_NAME
      namespace: pki-system
    spec:
      caProfile:
        commonName: COMMON_NAME
        duration: DURATION
        renewBefore: RENEW_BEFORE
      caCertificate:
        externalCA: {}
      certificateProfile:
        keyUsage:
        - digitalSignature
        - keyCertSign
        - crlSign
        extendedKeyUsage:
        - serverAuth
      secretConfig:
        secretName: SECRET_NAME
    

    Reemplaza las siguientes variables:

    • CA_NAME: Es el nombre de la sub-CA.
    • COMMON_NAME: Es el nombre común del certificado de CA.
    • DURATION: Es la vida útil solicitada del certificado de CA.
    • RENEW_BEFORE: Es el tiempo de rotación antes de que venza el certificado de la CA.
    • SECRET_NAME: Es el nombre del Secret de Kubernetes que contendrá la clave privada y el certificado de CA firmado.
  2. Aplica el recurso personalizado a tu zona de Distributed Cloud.

    kubectl apply -f byo-subca.yaml --kubeconfig MANAGEMENT_API_SERVER
    

    Reemplaza MANAGEMENT_API_SERVER por el archivo kubeconfig del servidor de la API de Management.

Se genera un CSR para la sub-CA y espera a que lo firmes. Para firmar la CSR, sigue las instrucciones de la sección Firma el certificado de subCA BYO.

Firma el certificado de la subCA externa

  1. Obtén las solicitudes de firma de certificado (CSR) de tu entorno de GDC:

    kubectl get certificateauthorities CA_NAME -n pki-system -ojson | jq -j '"echo ",
    .status.externalCA.csr, " | base64 -d > ","sub_ca.csr\n"' | bash
    

    El comando genera el archivo sub_ca.csr en el directorio actual. Este archivo contiene una CSR para un certificado de CA X.509.

  2. Usa el protocolo de la CA raíz del cliente para solicitar certificados de CA firmados para el archivo sub_ca.csr.

  3. En el caso de una solicitud de firma de certificado aprobada, obtendrás un certificado de CA firmado por la CA raíz del cliente. Almacena el certificado en el archivo sub_ca.crt del directorio actual. Además, obtén el certificado de CA raíz del cliente y almacénalo en el archivo ca.crt del directorio actual. Comunícate con la PMO para obtener instrucciones exactas.

  4. Verifica lo siguiente para garantizar la integridad y la precisión de los certificados:

    1. Asegúrate de que sub_ca.crt cumpla con el formato estándar de certificado codificado con PEM:

      -----BEGIN CERTIFICATE-----
            <Certificate>
      -----END CERTIFICATE-----
      
    2. Verifica que sub_ca.crt sea una autoridad certificadora (CA) válida en la extensión "Restricciones básicas":

      openssl x509 -text -noout -in sub_ca.crt | grep -A 1 "Basic Constraints"
      

      El resultado debe incluir CA:TRUE, o bien se requiere una mayor investigación:

      X509v3 Basic Constraints: critical
          CA:TRUE
      
    3. Verifica las extensiones de nombre alternativo del sujeto (SAN) en el certificado:

      openssl x509 -text -noout -in sub_ca.crt | grep -A 1 "Subject Alternative Name"
      

      Si el certificado de la CA tiene un nombre común (CN) en lugar de un SAN, verifica el CN en el certificado:

      openssl x509 -text -noout -in sub_ca.crt | grep -A 1 "Subject: CN"
      
  5. Genera la especificación para aplicar parches al recurso CertificateAuthority:

     echo "spec:
    caCertificate:
      externalCA:
        signedCertificate:
          certificate: $(base64 -w0 sub_ca.crt)
          ca: $(base64 -w0 ca.crt)" > patch.txt
    

    El contenido del archivo patch.txt es similar al siguiente fragmento:

     spec:
      caCertificate:
       externalCA:
        signedCertificate:
         certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURSekNDQ…
         ca: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURRVENDQ…
    
  6. Edita la especificación del recurso CertificateAuthority:

    kubectl patch certificateauthority CA_NAME -n pki-system --patch-file patch.txt --type='merge'
    
  7. Verifica la preparación de la subCA externa:

    kubectl get certificateauthority CA_NAME -n pki-system -ojson | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id))'
    

    Verás un resultado similar al siguiente:

    {
      "lastTransitionTime": "2024-04-30T22:10:50Z",
      "message": "Certificate authority is ready for use",
      "observedGeneration": 3,
      "reason": "Ready",
      "status": "True",
      "type": "Ready"
    }
    
  8. Verifica el vencimiento de los certificados de CA firmados:

    kubectl -n pki-system get secret SECRET_NAME -ojson | jq -j '"echo ",
    .metadata.name, " $(echo ", .data["tls.crt"], "| base64 -d | openssl x509 -enddate -noout)\n"' | bash
    
  9. Crea un archivo YAML de recursos CertificateIssuer y guárdalo. Por ejemplo, byo-subca-issuer.yaml:

    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateIssuer
    metadata:
      name: BYO_SUBCA_ISSUER
      namespace: pki-system
    spec:
      caaasConfig:
        certificateAuthorityRef:
          namespace: pki-system
          name: CA_NAME
    

    Reemplaza BYO_SUBCA_ISSUER por el nombre de la subCA externa emisora.

  10. Aplica el recurso personalizado a tu zona de Distributed Cloud en el servidor de la API de Management con la CLI de kubectl:

    kubectl apply -f byo-subca-issuer.yaml --kubeconfig MANAGEMENT_API_SERVER
    
  11. Verifica que la nueva entidad emisora esté lista:

    kubectl -n pki-system get certificateissuer.pki.security.gdc.goog/BYO_SUBCA_ISSUER -ojson | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id))'
    

Transición al modo de certificado BYO

En esta sección, se proporcionan una serie de pasos para realizar la transición al modo de certificado propio.

Crea un CertificateIssuer BYO

  1. Crea un recurso CertificateIssuer y guárdalo como un archivo YAML, por ejemplo, byo-cert-issuer.yaml. Esta entidad emisora de certificados BYO usa la CA administrada default-tls-ca como CA de resguardo:

    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateIssuer
    metadata:
      name: BYO_CERT_ISSUER_NAME
      namespace: pki-system
    spec:
      byoCertConfig:
        fallbackCertificateAuthority:
          name: default-tls-ca
          namespace: pki-system
    

    Reemplaza BYO_CERT_ISSUER_NAME por el nombre de la entidad emisora del certificado externo.

  2. Aplica el recurso personalizado a tu zona de Distributed Cloud en el servidor de la API de Management:

    kubectl apply -f byo-cert-issuer.yaml --kubeconfig MANAGEMENT_API_SERVER
    
  3. Verifica que la nueva entidad emisora esté lista.

    kubectl -n pki-system get certificateissuer.pki.security.gdc.goog/BYO_CERT_ISSUER_NAME -ojson | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id))'
    

    El resultado es similar al siguiente:

    {
      "lastTransitionTime": "2024-05-01T22:25:20Z",
      "message": "",
      "observedGeneration": 1,
      "reason": "FallbackCAReady",
      "status": "True",
      "type": "Ready"
    }
    

Firma el certificado BYO

  1. Mientras se espera que se firme externamente la CSR, una CA de respaldo especificada en la entidad emisora del certificado BYO puede emitir temporalmente un certificado BYO. Obtén el estado actual de default-wildcard-cert de BYO-cert:

    kubectl get certificate.pki.security.gdc.goog/default-wildcard-cert -n istio-system -o json | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id))'
    

    El resultado es similar al siguiente:

    {
      "lastTransitionTime": "2024-05-03T08:42:10Z",
      "message": "Certificate is issued by a fallback CA",
      "observedGeneration": 1,
      "reason": "UsingFallbackCA",
      "status": "True",
      "type": "Ready"
    }
    

    El motivo de preparación indica UsingFallbackCA para señalar que la CA de respaldo emitió el certificado. Luego, se almacena en el secreto y está lista para usarse.

  2. Obtén el nombre del secreto del certificado:

    kubectl -n istio-system get certificate.pki.security.gdc.goog/default-wildcard-cert -ojson | jq -r '.spec.secretConfig.secretName'
    

    El resultado es similar al siguiente:

    web-tls
    
  3. Verifica la entidad emisora del secreto:

    kubectl get secret web-tls -n istio-system -o jsonpath='{.data.tls\.crt}' |
    base64 -d | openssl x509 -text -noout | grep Issuer
    

    El resultado es similar al siguiente:

    Issuer: CN = GDC Managed ORG TLS CA
    

    Un certificado propio (BYO-cert) puede usar temporalmente un certificado coincidente mientras espera su propia firma de CSR. Un certificado de ejemplo-servicio con dnsName como example-service.org-1.zone1.google.gdch.test coincide con el default-wildcard-certcon DNSName *.org-1.zone1.google.gdch.test del mismo emisor de certificados. El certificado de ejemplo puede tener los siguientes estados mientras espera a que se firme su CSR:

    {
      "lastTransitionTime": "2024-05-03T22:30:51Z",
      "message": "Using a matched issued Certificate: default-wildcard-cert/istio-system",
      "observedGeneration": 1,
      "reason": "UsingMatchedCert",
      "status": "True",
      "type": "Ready"
    }
    
  4. Obtén la CSR del estado del certificado:

    kubectl -n istio-system get certificate.pki.security.gdc.goog/default-wildcard-cert -ojson | jq -r ' .status.byoCertStatus.csrStatus'
    

    El resultado es similar al siguiente:

    {
      "conditions": [
        {
          "lastTransitionTime": "2024-05-03T18:14:19Z",
          "message": "",
          "observedGeneration": 1,
          "reason": "WaitingForSigning",
          "status": "False",
          "type": "Ready"
        }
      ],
      "csr": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSB..."
    }
    
  5. Existen diferentes métodos para firmar una CSR según la configuración de la CA externa. Cuando firmes, usa el SAN de la CSR. Por ejemplo:

    function signCert() {
       certName=$1
       ns=$2
    
       # Download the CSR from the certificate
       kubectl get certificate.pki.security.gdc.goog $certName -n $ns -o jsonpath='{.status.byoCertStatus.csrStatus.csr}' | base64 -d > $certName.csr
    
       # Get SAN from the csr
       san=$(openssl req -in $certName.csr -noout -text | grep 'DNS:' | sed -s 's/^[ ]*//')
    
       # Save SAN to extension config
       cat <<EOF >$certName-csr.ext
     keyUsage=digitalSignature,keyEncipherment
     extendedKeyUsage=serverAuth,clientAuth
     subjectAltName=${san}
     EOF
    
       # Sign the CSR with an external CA. You need to prepare the external CA cert and key
       openssl x509 -req -in $certName.csr -days 365 -CA ext-ca.crt -CAkey ext-ca.key -CAcreateserial -extfile $certName-csr.ext -out $certName-signed.crt
       openssl x509 -in $certName-signed.crt -text -noout
    
       # Upload the externally signed certificate by patching.
       echo "spec:
         byoCertificate:
            certificate: $(base64 -w0 $certName-signed.crt)
            ca: $(base64 -w0 ext-ca.crt)" > patch.txt
    
       kubectl patch certificate.pki.security.gdc.goog $certName -n $ns --patch-file patch.txt --type='merge'
     }
    
     # Use the function to sign the default-wildcard-cert in the istio-system namespace
     signCert default-wildcard-cert istio-system
    
  6. Verifica los siguientes detalles:

    • El estado de la CSR del certificado es Ready
    kubectl -n istio-system get certificate.pki.security.gdc.goog/default-wildcard-cert -ojson | jq -r ' .status.byoCertStatus.csrStatus.conditions'
    
    [
       {
          "lastTransitionTime": "2024-05-03T21:56:25Z",
          "message": "",
          "observedGeneration": 2,
          "reason": "Signed",
          "status": "True",
          "type": "Ready"
       }
    ]
    
    • El certificado es Ready con el motivo Issued.
    kubectl get certificate.pki.security.gdc.goog/default-wildcard-cert -n istio-system -o json | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id))'
    

    El resultado es similar al siguiente:

    {
      "lastTransitionTime": "2024-05-03T08:42:10Z",
      "message": "Certificate is issued",
      "observedGeneration": 2,
      "reason": "Issued",
      "status": "True",
      "type": "Ready"
    }
    
    • Se actualiza el secreto:
    kubectl get secret web-tls -n istio-system -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout | grep Issuer
    

    El resultado es similar al siguiente:

            Issuer: CN = external-ca
    

Transición a un certificado BYO con el modo ACME

En esta sección, se proporcionan una serie de pasos para realizar la transición a un certificado propio con el modo ACME.

Crea un CertificateIssuer con la configuración de ACME

  1. Crea un recurso CertificateIssuer con la configuración de ACME y guárdalo como un archivo YAML, como acme-issuer.yaml.

    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateIssuer
    metadata:
      name: ACME_ISSUER_NAME
      namespace: pki-system
    spec:
         acmeConfig:
           rootCACertificate: ROOT_CA_CERTIFICATE
           acme:
             server: ACME_SERVER_URL
             caBundle: CA_BUNDLE
             privateKeySecretRef:
               name: PRIVATE_KEY_SECRET_NAME
    

    Reemplaza las siguientes variables:

    • ACME_ISSUER_NAME: Es el nombre de la entidad emisora de ACME.
    • ROOT_CA_CERTIFICATE: Son los datos de la CA raíz de los certificados emitidos por el servidor de ACME.
    • ACME_SERVER_URL: Es la URL para acceder al extremo del directorio del servidor de ACME.
    • CA_BUNDLE: Es el paquete codificado en Base64 de AC de PEM que valida la cadena de certificados que presenta el servidor de ACME.
    • PRIVATE_KEY_SECRET_NAME: Es el nombre del secreto que contiene la clave privada de la cuenta de ACME.

    Para usar una clave privada de cuenta de ACME existente, asegúrate de que el secreto que la contiene use el nombre PRIVATE_KEY_SECRET_NAME dentro del mismo espacio de nombres que la entidad emisora de ACME. Si no proporcionas este secreto, se generará automáticamente uno nuevo con el mismo nombre para almacenar la clave privada de la cuenta de ACME.

  2. Aplica el recurso personalizado a tu zona de Distributed Cloud:

    kubectl apply -f acme-issuer.yaml --kubeconfig MANAGEMENT_API_SERVER
    
  3. Verifica que la nueva entidad emisora esté lista:

    kubectl --kubeconfig MANAGEMENT_API_SERVER -n pki-system get certificateissuer.pki.security.gdc.goog/ACME_ISSUER_NAME -ojson | jq -r ' .status.conditions[] | select( .type as $id | "Ready" | index($id))'
    

    Verás un resultado similar al siguiente:

    {
      "lastTransitionTime": "2024-05-01T18:32:17Z",
      "message": "",
      "observedGeneration": 1,
      "reason": "ACMEClientReady",
      "status": "True",
      "type": "Ready"
    }
    

Reemisión del certificado

Para cambiar la entidad emisora predeterminada a la nueva entidad emisora de ACME, consulta Cómo cambiar la entidad emisora de certificados predeterminada.

Para volver a emitir certificados de inmediato con la nueva entidad emisora predeterminada, consulta Cómo volver a emitir certificados web de la PKI de forma manual.