Emitir certificados que atestam a identidade de terceiros

Este tutorial demonstra como emitir certificados que atestam uma identidade de terceiros usando reflexão de identidade e pools de identidade de carga de trabalho.

É possível usar a reflexão de identidade para criar certificados que correspondam à identidade verificada de um solicitante de certificado. Usando a reflexão de identidade, é possível limitar um solicitante de certificado sem privilégios para solicitar apenas certificados com um nome alternativo do assunto (SAN, na sigla em inglês) correspondente à identidade na credencial.

Objetivos

Este tutorial fornece informações sobre como usar o serviço de AC com pools de identidade de carga de trabalho para federar uma identidade de terceiros e receber um certificado que atesta essa identidade.

Antes de começar

Antes de começar, entenda os seguintes conceitos:

  • Pools de identidade da carga de trabalho: permitem gerenciar provedores de identidade de terceiros. Para mais informações, consulte Gerenciar provedores e pools de identidade da carga de trabalho.
  • Federação de identidade da carga de trabalho: a federação de identidade da carga de trabalho aproveita os pools de identidade da carga de trabalho para conceder acesso a identidades de terceiros aos serviços do Google Cloud. Para mais informações, consulte Federação de identidade da carga de trabalho.
  • Serviço de token de segurança (STS, na sigla em inglês): permite trocar credenciais de terceiros por tokens próprios (do Google Cloud). Para mais informações, consulte Serviço de token de segurança.
  • Reflexão de identidade: o recurso de reflexão de identidade permite que a identidade verificada de um solicitante de certificado seja encaminhada ao certificado solicitado. Para mais informações, consulte Reflexão de identidade.

Verifique se você tem os seguintes papéis do IAM:

  • Para gerenciar autoridades certificadoras (ACs) e pools de ACs e solicitar certificados, você precisa ter a função de gerente de operação de serviço de AC (privateca.caManager). Para mais informações sobre os papéis do IAM para o serviço de CA, consulte Controle de acesso com o IAM.
  • Para gerenciar provedores e pools de identidade da carga de trabalho, você precisa ter o papel de administrador do pool de Identidade da carga de trabalho (iam.workloadIdentityPoolAdmin).
  • Para criar uma conta de serviço, você precisa ter o papel de administrador da conta de serviço (iam.serviceAccountAdmin).

Para saber mais sobre a concessão de papéis do IAM, consulte Gerenciar o acesso a projetos, pastas e organizações. É possível conceder as funções do IAM necessárias a uma Conta do Google, uma conta de serviço, um Grupo do Google, uma conta do Google Workspace ou um domínio do Cloud Identity.

Configurar um pool de identidade e um provedor da carga de trabalho

Este tutorial explica como usar um provedor do Google OpenID Connect (OIDC) com uma conta de serviço para atuar como uma identidade de terceiros. O provedor OIDC das Contas do Google atua como um provedor de identidade (IDP) terceirizado, e a conta de serviço do Google Cloud é um exemplo de identidade de terceiros atribuída por esse IDP.

Os pools de identidade de carga de trabalho oferecem suporte a vários provedores de identidade, incluindo o Microsoft Azure/Active Directory local, a AWS e os provedores de identidade baseados em SAML.

Para configurar um pool de identidades e um provedor de carga de trabalho, faça o seguinte: 1. Para representar um conjunto confiável de identidades federadas, crie um pool de identidade da carga de trabalho:

```
gcloud iam workload-identity-pools create IDENTITY_POOL_ID --location global --display-name "tutorial-wip"
```

Replace the following:

- <var>IDENTITY_POOL_ID</var>: The unique identifier of the new workload
  identity pool.
  1. Crie um provedor de pool de identidade da carga de trabalho para o provedor de identidade de terceiros:

    gcloud iam workload-identity-pools providers create-oidc PROVIDER_ID --location global --workload-identity-pool IDENTITY_POOL_ID --display-name "tutorial-oidc" --attribute-mapping "google.subject=assertion.sub" --issuer-uri="https://accounts.google.com"
    

    Substitua:

    • PROVIDER_ID: o identificador exclusivo do provedor de identidade que você quer criar no pool de identidades da carga de trabalho.

    É possível personalizar as seguintes flags para seu caso de uso:

    • attribute-mapping: essa flag define o mapeamento entre as declarações de terceiros para a declaração principal do Google, google.subject. google.subject é um mapeamento obrigatório que pode ser definido para qualquer declaração ou combinação de declarações usando uma expressão de CEL. Para mais informações, consulte Definir um mapeamento e uma condição de atributo.
    • issuer-uri: para provedores OIDC, essa flag é um endpoint acessível publicamente que o Google procura para verificar tokens de terceiros. Para mais informações, consulte Como preparar um provedor de identidade externo.

    Para mais informações sobre como configurar um provedor de identidade de carga de trabalho, consulte Como configurar a federação de identidade de carga de trabalho.

Criar um pool de ACs e uma AC emissora

Esta seção explica como criar um pool de AC e adicionar uma AC raiz a ele. É possível usar esse pool de ACs para emitir certificados refletidos de identidade. Se você quiser usar um pool de AC e uma AC, pule esta seção.

Em vez de uma AC raiz, você também pode criar uma AC subordinada. Criar uma AC raiz ajuda a encurtar o procedimento.

  1. Crie um pool de ACs no nível de DevOps:

    gcloud privateca pools create CA_POOL_ID --location LOCATION --tier devops
    

    Substitua:

    • CA_POOL_ID: o ID do pool de ACs do serviço de AC que emite certificados.
    • LOCATION: o local do pool de ACs.

    Para mais informações sobre como criar pools de ACs, consulte Criar um pool de ACs.

  2. Crie uma CA raiz:

    gcloud privateca roots create CA_ID --pool CA_POOL_ID  --location LOCATION --subject "CN=test,O=test-org"
    

    Substitua:

    • CA_ID: o ID da autoridade certificadora que emite certificados.
    • CA_POOL_ID: o ID do pool de ACs do serviço de AC que emite certificados.
    • LOCATION: o local do pool de ACs.

    Para mais informações sobre como criar uma AC raiz, consulte Criar uma AC raiz.

  3. Ative as identidades federadas do pool de Identidade da carga de trabalho para emitir certificados do pool de ACs. A reflexão de identidade exige o papel do IAM de requerente do certificado da carga de trabalho de CA (roles/privateca.workloadCertificateRequester) para os requerentes de CreateCertificate.

    É possível representar os participantes do pool de identidades da carga de trabalho em várias granularidades, variando de um único sujeito a todas as identidades no pool em todos os provedores. Para mais informações, consulte os principais ou conjuntos de principais disponíveis (use a guia Google Cloud CLI) para se adequar melhor ao seu caso de uso.

    gcloud privateca pools add-iam-policy-binding CA_POOL_ID --location LOCATION --role roles/privateca.workloadCertificateRequester --member "principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/IDENTITY_POOL_ID/*"
    

    Substitua:

    • PROJECT_NUMBER: o número do projeto em que você criou o pool de Identidade da carga de trabalho.

Criar uma conta de serviço que represente uma identidade de terceiros

O procedimento a seguir pressupõe que uma conta de serviço represente uma terceira parte. Esta seção mostra como usar o endpoint do IAM GenerateIdToken para extrair uma identidade de terceiros na forma de um token OIDC. Dependendo do caso de uso, talvez seja necessário seguir etapas diferentes para receber o token de identidade de terceiros escolhido.

gcloud iam service-accounts create SERVICE_ACCOUNT

Substitua:

  • SERVICE_ACCOUNT: o ID da conta de serviço que representa a identidade de terceiros.

Emitir um certificado que ateste a identidade de terceiros

Antes de começar, verifique se você tem o papel do IAM de Criador do token da conta de serviço (roles/iam.serviceAccountTokenCreator). Você precisa desse papel do IAM para chamar a API GenerateIdToken.

Para receber um certificado que atesta a identidade de terceiros, faça o seguinte:

  1. Receba um token de identidade de terceiros do provedor de identidade de terceiros.

    curl

    export ID_TOKEN=`curl -d '{"audience":"//iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/IDENTITY_POOL_ID/providers/PROVIDER_ID"}' -H 'Content-Type: application/json' -H "Authorization: Bearer $(gcloud auth print-access-token)" https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT@PROJECT_ID.iam.gserviceaccount.com:generateIdToken | python3 -c "import sys;import json;print(json.load(sys.stdin)['token'])"`
    

    Substitua:

    • PROJECT_ID: o ID do projeto do Google Cloud para o projeto em que você quer criar recursos.

    Bibliotecas de cliente

    .

    Para acessar o token de terceiros de maneira programática, é possível receber um token de uma credencial de origem de arquivo ou de URL. Para mais informações, consulte Como autenticar usando bibliotecas de cliente, a CLI gcloud ou o Terraform. Neste tutorial, seguimos um fluxo de trabalho de credenciais de origem de arquivo.

    Carregue a credencial em um caminho legível pelo solicitante do certificado:

    curl -d '{"audience":"//iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/IDENTITY_POOL_ID/providers/PROVIDER_ID"}' -H 'Content-Type: application/json' -H "Authorization: Bearer $(gcloud auth print-access-token)" https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT@PROJECT_ID.iam.gserviceaccount.com:generateIdToken | python3 -c "import sys;import json;       print(json.load(sys.stdin)['token']) > /tmp/oidc_token.txt
    

    Substitua:

    • PROJECT_ID: o ID do projeto em que você quer criar recursos.
  2. Troque o token de terceiros por um token OAuth federado usando o endpoint token do STS:

    curl

    export STS_TOKEN=`curl -L -X POST 'https://sts.googleapis.com/v1/token' -H 'Content-Type: application/json' \
    -d '{
        "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
        "audience": "//iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/IDENTITY_POOL_ID/providers/PROVIDER_ID",
        "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
        "scope": "https://www.googleapis.com/auth/cloud-platform",
        "subject_token": "'$ID_TOKEN'",
        "subject_token_type": "urn:ietf:params:oauth:token-type:jwt"
    }' | python3 -c "import sys;import json; print(json.load(sys.stdin)['access_token'])"`
    

    Bibliotecas de cliente

    1. Crie um arquivo de configuração de credencials chamado oidc_token.txt que o código de solicitação de certificado possa ler para realizar uma troca de token.
    gcloud iam workload-identity-pools create-cred-config projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/IDENTITY_POOL_ID --output-file=/tmp/cred_config.json --credential-source-file=/tmp/oidc_token.txt
    
    1. Leia o arquivo oidc_token.txt para definir o mecanismo de autorização na biblioteca do cliente:

    python

    import json
    
    from google.auth import identity_pool
    
    with open('/tmp/cred_config.json', 'r') as f:
      json_config_info = json.loads(f.read())
    credentials = identity_pool.Credentials.from_info(json_config_info)
    scoped_credentials = credentials.with_scopes(
        ['https://www.googleapis.com/auth/cloud-platform'])
    
  3. Faça uma solicitação ao serviço de autoridade certificadora com o modo de solicitação de assunto REFLECTED_SPIFFE:

    curl

    1. Opcional: se você não tiver um CSR, crie um executando o comando abaixo.

      export TUTORIAL_CSR=$(openssl req -newkey rsa:2048 -nodes -subj / -keyout tutorial_do_not_use.key)
      
    2. Solicite um certificado com a CSR, um período de validade e um modo de solicitação de assunto refletido:

      curl -H "Authorization: Bearer $(echo $STS_TOKEN)" https://privateca.googleapis.com/v1/projects/PROJECT_NUMBER/locations/LOCATION/caPools/CA_POOL_ID/certificates\?alt\=json  -X POST -H "Content-Type: application/json" -H 'Accept: application/json' --data '{"lifetime": "100s", "pemCsr": "'$TUTORIAL_CSR'", "subjectMode": "REFLECTED_SPIFFE"}'
      

    Bibliotecas de cliente

    Para encaminhar o token próprio para o serviço de AC, é necessário criar um cliente com credenciais. Em seguida, use esse cliente com credenciais para fazer solicitações de certificado:

    1. Inicie um cliente de serviço de AC com credenciais:

      python

      caServiceClient = privateca_v1.CertificateAuthorityServiceClient(credentials=scoped_credentials)
      
    2. Solicite um certificado.

      Python

      Para autenticar no serviço de CA, configure o Application Default Credentials. Para mais informações, consulte Configurar a autenticação para um ambiente de desenvolvimento local.

      import google.cloud.security.privateca_v1 as privateca_v1
      from google.protobuf import duration_pb2
      
      
      def create_certificate(
          project_id: str,
          location: str,
          ca_pool_name: str,
          ca_name: str,
          certificate_name: str,
          common_name: str,
          domain_name: str,
          certificate_lifetime: int,
          public_key_bytes: bytes,
      ) -> None:
          """
          Create a Certificate which is issued by the Certificate Authority present in the CA Pool.
          The key used to sign the certificate is created by the Cloud KMS.
      
          Args:
              project_id: project ID or project number of the Cloud project you want to use.
              location: location you want to use. For a list of locations, see: https://cloud.google.com/certificate-authority-service/docs/locations.
              ca_pool_name: set a unique name for the CA pool.
              ca_name: the name of the certificate authority which issues the certificate.
              certificate_name: set a unique name for the certificate.
              common_name: a title for your certificate.
              domain_name: fully qualified domain name for your certificate.
              certificate_lifetime: the validity of the certificate in seconds.
              public_key_bytes: public key used in signing the certificates.
          """
      
          caServiceClient = privateca_v1.CertificateAuthorityServiceClient()
      
          # The public key used to sign the certificate can be generated using any crypto library/framework.
          # Also you can use Cloud KMS to retrieve an already created public key.
          # For more info, see: https://cloud.google.com/kms/docs/retrieve-public-key.
      
          # Set the Public Key and its format.
          public_key = privateca_v1.PublicKey(
              key=public_key_bytes,
              format_=privateca_v1.PublicKey.KeyFormat.PEM,
          )
      
          subject_config = privateca_v1.CertificateConfig.SubjectConfig(
              subject=privateca_v1.Subject(common_name=common_name),
              subject_alt_name=privateca_v1.SubjectAltNames(dns_names=[domain_name]),
          )
      
          # Set the X.509 fields required for the certificate.
          x509_parameters = privateca_v1.X509Parameters(
              key_usage=privateca_v1.KeyUsage(
                  base_key_usage=privateca_v1.KeyUsage.KeyUsageOptions(
                      digital_signature=True,
                      key_encipherment=True,
                  ),
                  extended_key_usage=privateca_v1.KeyUsage.ExtendedKeyUsageOptions(
                      server_auth=True,
                      client_auth=True,
                  ),
              ),
          )
      
          # Create certificate.
          certificate = privateca_v1.Certificate(
              config=privateca_v1.CertificateConfig(
                  public_key=public_key,
                  subject_config=subject_config,
                  x509_config=x509_parameters,
              ),
              lifetime=duration_pb2.Duration(seconds=certificate_lifetime),
          )
      
          # Create the Certificate Request.
          request = privateca_v1.CreateCertificateRequest(
              parent=caServiceClient.ca_pool_path(project_id, location, ca_pool_name),
              certificate_id=certificate_name,
              certificate=certificate,
              issuing_certificate_authority_id=ca_name,
          )
          result = caServiceClient.create_certificate(request=request)
      
          print("Certificate creation result:", result)
      
      

    3. Verifique o certificado. O certificado precisa ter um assunto que contenha um único SAN de URI. O SAN que atesta uma identidade tem o seguinte formato:

      spiffe://IDENTITY_POOL_ID.PROJECT_NUMBER.global.workload.id.goog/subject/<oidc_subject_number>
      

      Substitua:

      • IDENTITY_POOL_ID: o identificador exclusivo do pool de identidade da carga de trabalho.
      • PROJECT_NUMBER: o número do projeto em que você criou o pool de Identidade da carga de trabalho.

Limpar

Para evitar cobranças na sua conta do Google Cloud pelos recursos do serviço de CA criados seguindo este documento, execute as seguintes operações usando o Google Cloud CLI:

  1. Exclua a AC que você criou.

    1. Desative a AC:

      gcloud privateca roots disable CA_ID --pool CA_POOL_ID  --location LOCATION
      

      Substitua:

      • CA_ID: o identificador exclusivo da AC.
      • CA_POOL_ID: o identificador exclusivo do pool de ACs.
      • LOCATION: o local do pool de ACs.
    2. Exclua a AC:

      gcloud privateca roots delete CA_ID --pool CA_POOL_ID  --location LOCATION --ignore-active-certificates
      

      Substitua:

      • CA_ID: o identificador exclusivo da AC.
      • CA_POOL_ID: o identificador exclusivo do pool de ACs.
      • LOCATION: o local do pool de ACs.
  2. Exclua o pool de ACs que você criou.

    gcloud privateca pools delete CA_POOL_ID --location LOCATION
    

    Substitua:

    • CA_POOL_ID: o identificador exclusivo do pool de ACs.
    • LOCATION: o local do pool de ACs.

    Para mais informações sobre o comando gcloud privateca pools delete, consulte gcloud privateca pools delete.

  3. Exclua o pool de identidade da carga de trabalho que você criou:

    gcloud iam workload-identity-pools delete IDENTITY_POOL_ID --location global
    

    Substitua:

    • IDENTITY_POOL_ID: o identificador exclusivo do pool de identidade da carga de trabalho.
  4. Exclua a conta de serviço que você criou:

    gcloud iam service-accounts delete SERVICE_ACCOUNT@PROJECT_ID.iam.gserviceaccount.com
    

    Substitua:

    • SERVICE_ACCOUNT: o identificador exclusivo do pool de identidade da carga de trabalho.
    • PROJECT_ID: o projeto proprietário da conta de serviço.

O papel do IAM de solicitante de certificado da carga de trabalho de serviço de CA (privateca.workloadCertificateRequester) restringe o assunto do certificado emitido apenas à identidade do solicitante. Verifique se os usuários ou workloads que usam o recurso de reflexão de identidade recebem apenas o papel do IAM de solicitante de certificado da carga de trabalho do serviço de CA (privateca.workloadCertificateRequester). Para obedecer ao princípio de privilégio mínimo, você pode evitar conceder o papel de solicitante de certificado de serviço de CA (privateca.certificateRequester) do IAM.

A seguir