Integrar o Cloud Run e a federação de identidade da carga de trabalho


Saiba neste tutorial como usar a federação de identidade da carga de trabalho para autenticar cargas executadas fora do Google Cloud para que elas possam acessar microsserviços hospedados pelo Cloud Run. Este tutorial é destinado a administradores que querem integrar a federação de identidade da carga de trabalho ao provedor de identidade (IdP, na sigla em inglês) atual. A federação de identidade da carga de trabalho permite conectar cargas de trabalho externas a cargas executadas no Google Cloud. O Cloud Run permite executar microsserviços conteinerizados sem estado.

Confira instruções sobre como configurar o Jenkins como a carga de trabalho externa, o Keycloak como seu IdP, o Cloud Run e a federação de identidade da carga de trabalho. Ao fim deste tutorial, você vai saber como a federação de identidade da carga de trabalho permite autenticar seu aplicativo Jenkins com o Google Cloud usando a autenticação do OpenID Connect.

Autenticação de carga de trabalho externa usando a federação de identidade da carga de trabalho

A federação de identidade da carga de trabalho permite autenticar cargas de trabalho fora do Google Cloud sem usar uma chave da conta de serviço estática. Qualquer carga de trabalho externa que precise consumir serviços no Google Cloud pode se beneficiar desse recurso.

A federação de identidade da carga de trabalho permite que você use seu IdP para autenticar diretamente com o Google Cloud. Para autenticar, use o OpenID Connect. O Cloud Run aceita tokens do OpenID Connect enviados pelo IdP para autenticação.

O processo de autenticação ao usar a federação de identidade da carga de trabalho é o seguinte:

  1. Sua biblioteca de autenticação (AUTHN) envia uma solicitação do JSON Web Token (JWT) para o IdP.
  2. Seu IdP assina os JSON Web Tokens (JWT). A biblioteca AUTHN lê esses dados em uma variável.
  3. A biblioteca envia um comando POST para o serviço de token de segurança que inclui o token assinado.
  4. O serviço de token de segurança analisa o provedor do pool de identidade da carga de trabalho que você configurou para criar confiança e verifica a identidade na credencial.
  5. O serviço de token de segurança retorna um token federado.
  6. A biblioteca envia o token para o IAM.
  7. O IAM troca o token por um token do OpenID Connect de uma conta de serviço. Saiba mais em Como gerar tokens de ID do OpenID Connect.
  8. A biblioteca fornece o token do OpenID Connect para o Jenkins.
  9. O Jenkins usa esse token para fazer a autenticação no Cloud Run.

O diagrama a seguir mostra o fluxo de autenticação:

Fluxo de autenticação.

Objetivos

  • Configurar o Jenkins como carga de trabalho externa.
  • Configure o Keycloak como o IdP compatível com o OpenID Connect.
  • Conecte o Jenkins ao Keycloak.
  • Instale as bibliotecas de cliente do Cloud para receber o token JWT do Keycloak para o Google Cloud.
  • Conecte o Google Cloud ao Keycloak e ao Jenkins.
  • Receba do Keycloak o JWT para o usuário autenticado.

Embora este tutorial use o Keycloak, é possível usar qualquer provedor de identidade que ofereça suporte ao OpenID Connect, como GitLab, Okta ou OneLogin.

Custos

Neste documento, você usará os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem estar qualificados para uma avaliação gratuita.

Ao concluir as tarefas descritas neste documento, é possível evitar o faturamento contínuo excluindo os recursos criados. Saiba mais em Limpeza.

Antes de começar

  1. In the Google Cloud console, go to the project selector page.

    Go to project selector

  2. Select or create a Google Cloud project.

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Configure um microsserviço no Cloud Run. Saiba mais em Guia de início rápido: implantar um contêiner no Cloud Run.

Configurar o Jenkins

Conclua estas tarefas em um ambiente que não seja do Google Cloud, como seu ambiente local ou outra nuvem.

Se você já tiver um provedor de identidade com suporte ao OpenID Connect e uma carga de trabalho externa, pule esta etapa e acesse Como instalar bibliotecas de cliente do Cloud.

Para simular uma carga de trabalho externa, use uma VM com o Jenkins instalado nela. É possível executar o Jenkins como uma imagem Docker ou fazer a instalação diretamente no servidor. As etapas a seguir mostram como fazer a instalação diretamente no servidor.

  1. Escolha uma VM e abra uma linha de comando.
  2. Instale o Java:

    $ sudo apt update
    $ sudo apt install openjdk-11-jre
    $ java -version
    
  3. Instale o Jenkins:

    curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo tee \
    /usr/share/keyrings/jenkins-keyring.asc > /dev/null
    echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
    https://pkg.jenkins.io/debian-stable binary/ | sudo tee \
    /etc/apt/sources.list.d/jenkins.list > /dev/null
    sudo apt-get update
    sudo apt-get install jenkins
    
  4. Verifique se é possível acessar o servidor Jenkins na porta 8080. Se você estiver usando uma VM protegida por um firewall, verifique se as portas apropriadas estão abertas.

  5. Busque a senha de administrador e configure o Jenkins. Consulte instruções em Assistente de configuração pós-instalação.

  6. Siga estas etapas para configurar o SSL:

    1. Se você tem um provedor de domínio, pode usar a autoridade certificadora (CA) para solicitar um certificado assinado. Você também pode receber um certificado assinado gratuito com duração de 90 dias em zerossl.com.
    2. Faça o download do arquivo ZIP do certificado e transfira esse arquivo para o servidor que está executando o Jenkins:

      scp -i CERTFILE.pem -r CERTFILE.zip VM_FQDN:/home/USERNAME
      

      Substitua:

      • CERTFILE pelo nome do arquivo de certificado que inclui a chave pública.
      • VM_FQDN pelo FQDN do servidor fora do Google Cloud.
      • USERNAME pelo seu nome de usuário.
    3. Renomeie os arquivos e gere um arquivo .pkcs12 que o Jenkins pode usar:

      openssl rsa -in KEYFILE.com.key -out KEYFILE.com.key

      Substitua KEYFILE pelo nome do arquivo de certificado.

  7. Atualize o arquivo /etc/sysconfig/jenkins:

    1. Abra o arquivo em um editor de texto:

      vi /etc/sysconfig/jenkins
      
    2. Defina JENKINS_PORT como -1.

    3. Defina JENKINS_HTTPS_PORT como 8443.

    4. Na parte inferior do arquivo, adicione os seguintes argumentos:

      JENKINS_ARGS="--httpsCertificate=/var/lib/jenkins/.ssl/CERTFILE.crt --httpsPrivateKeys=/var/lib/jenkins/.ssl/KEYFILE.pkcs1.key"

      Substitua:

      • CERTFILE pelo nome do arquivo de certificado usando o formato .crt.
      • KEYFILE pelo nome de arquivo da chave PKCS.
  8. Reinicie o servidor Jenkins.

  9. Verifique se a porta 8443 está aberta no firewall e acesse o Jenkins na porta 8443.

  10. Instale um plug-in do Jenkins exigido para integrar o Keycloak ao Jenkins. Você pode escolher uma das seguintes opções:

    Para instalar o plug-in, proceda da seguinte maneira:

    1. No painel do Jenkins, acesse Manage Jenkins > Manage Plugins.
    2. Selecione Available e pesquise o plug-in que você quer. A captura de tela a seguir mostra o Plugin Manager com a guia Available selecionada.

      Gerenciador de plug-ins do Jenkins.

    3. Instale o plug-in.

Configurar o Keycloak

Neste tutorial, o Keycloak gerencia usuários, grupos e papéis. O Keycloak usa realms para gerenciar usuários.

  1. Na VM em execução fora do Google Cloud, instale o servidor do Keycloak. Para este tutorial, recomendamos instalar o Keycloak usando um contêiner do Docker.

  2. Abra o Admin Console do Keycloak.

  3. Acesse Realm settings.

  4. Na guia General, verifique se os campos estão definidos da seguinte maneira:

    • Ativado: ON
    • Acesso gerenciado pelo usuário: OFF
    • Endpoints: Configuração do endpoint do OpenID e Metadados do provedor de identidade SAML 2.0

    A captura de tela abaixo mostra os campos que você precisa configurar.

    Configurações gerais do Keycloak.

  5. Crie um cliente para que você tenha uma entidade que possa solicitar o Keycloak para autenticar um usuário. Muitas vezes, os clientes são aplicativos e serviços que usam o Keycloak para fornecer uma solução de Logon único (SSO, na sigla em inglês).

    1. No Admin Console do Keycloak, clique em Clients > Create.
    2. Digite o seguinte:

      • ID do cliente: jenkins
      • Protocolo do cliente: openid-connect
      • URL raiz: http://JENKINS_IP_ADDRESS:8080, em que JENKINS_IP_ADDRESS é o endereço IP do servidor Jenkins.

      A captura de tela abaixo mostra os campos que você precisa configurar.

      Adicionar cliente no Keycloak.

    3. Clique em Salvar.

  6. Na guia Installation, verifique se o formato do token é Keycloak OIDC JSON. Faça uma cópia desse token, porque ele será necessário para concluir a configuração do Jenkins.

  7. Para criar um grupo de teste, faça o seguinte:

    1. No Admin Console do Keycloak, clique em Groups > New.
    2. Digite um nome para o grupo e clique em Save.
    3. Crie mais um grupo de teste. É possível atribuir papéis aos grupos, mas isso não é necessário neste tutorial.
  8. Para criar um usuário de teste para adicionar ao grupo, faça o seguinte:

    1. No Admin Console do Keycloak, clique em Manage user > Add users.
    2. Preencha as informações do usuário e clique em Save.

      A captura de tela abaixo mostra exemplos de informações de uma conta de usuário.

      Adicionar usuário no Keycloak.

    3. Clique na guia Credentials e verifique se Temporary está definido como Off.

    4. Redefina a senha.

      Você vai usar essa conta depois no JWT para autenticação.

      A captura de tela a seguir mostra a guia Credentials com os campos que você precisa configurar.

      Alterar senha no Keycloak.

    5. Clique na guia Groups e selecione um dos grupos que você criou.

    6. Clique em Participar.

    7. Repita esta etapa criando mais usuários de teste.

Configurar o Jenkins para OpenID Connect

Saiba nesta seção como configurar o plug-in do OpenID Connect para o Jenkins.

  1. No servidor Jenkins, acesse Manage Jenkins > Configure Global Security.
  2. Em "Security Realm", selecione Keycloak Authentication Plugin. Clique em Salvar.

  3. Clique em Configure System.

  4. Nas configurações Global Keycloak, copie o JSON de instalação do Keycloak que você criou em Configure Keycloak. Se você precisar recuperar os dados JSON, faça o seguinte:

    1. No Admin Console do Keycloak, acesse Clients.

    2. Clique no nome do cliente.

    3. Na guia Installation, clique em Format Option e selecione Keycloak OIDC JSON.

    Confira a seguir um exemplo de JSON do Keycloak:

    {
        "realm":"master"
        "auth-server-url":"AUTHSERVERURL"
        "ssl-required":"none"
        "resource":"jenkins"
        "public-client":true
        "confidential-port":0
    }
    

    O AUTHSERVERURL é o URL do servidor de autenticação.

  5. Para salvar a configuração do OIDC, clique em Salvar.

O Jenkins agora pode redirecionar para o Keycloak a fim de receber informações do usuário.

Instalar bibliotecas de cliente do Cloud

Para enviar um JWT do Keycloak para o Google Cloud, é preciso instalar as bibliotecas de cliente do Cloud no servidor Jenkins. Neste tutorial, usamos o Python para interagir com o Google Cloud usando o SDK.

  1. No servidor Jenkins, instale o Python. As etapas a seguir mostram como instalar o Python3:

    sudo apt update
    sudo apt install software-properties-common
    sudo add-apt-repository ppa:deadsnakes/ppa
    sudo apt update
    sudo apt install python3.8
    
  2. Instale o pip3 para fazer o download e importar as bibliotecas de cliente do Cloud:

    pip3 –version
    sudo apt update
    sudo apt install python3-pip
    pip3 –version
    
  3. Instale as bibliotecas de cliente do Cloud para Python usando o pip3:

    pip3 install –upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
    

    Por exemplo:

    pip3 install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
    Collecting google-api-python-client
        Downloading google_api_python_client-2.42.0-py2.py3-none-any.whl (8.3 MB)
            USERNAME | 8.3 MB 19.9 MB/s
    Collecting google-auth-httplib2
        Downloading google_auth_httplib2-0.1.0-py2.py3-none-any.whl (9.3 MB)
    Collecting google-auth-oauthlib
    Downloading google_auth_oauthlib-0.5.1-py2.py3-non-any.whl (19 KB)
    

    Substitua USERNAME pelo seu nome de usuário.

  4. Instale a Google Cloud CLI no servidor Jenkins. Consulte instruções em Guia de início rápido: como instalar a CLI gcloud.

Configurar o ambiente do Google Cloud

Conheça nesta seção as etapas necessárias para garantir que o ambiente do Google Cloud que hospeda o contêiner sem servidor possa se conectar com o Jenkins e o Keycloak.

  1. No Google Cloud, crie uma conta de serviço para que o microsserviço no Cloud Run possa acessar as permissões associadas a ela. Por exemplo, para criar uma conta de serviço usando a gcloud CLI, faça o seguinte:

    gcloud iam service-accounts create cloudrun-oidc \
      –-description="cloud run oidc sa"  \
      –-display-name="cloudrun-oidc"
    

    Por padrão, o Cloud Run cria uma conta de serviço padrão para você. No entanto, usar a conta de serviço padrão não é uma prática recomendada de segurança porque tem um vasto conjunto de permissões. Portanto, recomendamos criar uma conta de serviço separada para seu microsserviço. Saiba como criar uma conta de serviço para o Cloud Run em Criar e gerenciar contas de serviço.

  2. Crie um pool de identidade da carga de trabalho. Para criar um pool usando a CLI gcloud, execute o seguinte:

    gcloud iam workload-identity-pools create cloudrun-oidc-pool \
      --location="global" \
      —-description="cloudrun-oidc" \
      —-display-name="cloudrun-oidc"
    
  3. Crie um provedor de pool de identidade da carga de trabalho para o OpenID Connect:

    gcloud iam workload-identity-pools providers create-oidc cloud-run-provider \
      --workload-identity-pool="cloudrun-oidc-pool" \
      --issuer-uri="VAR_LINK_TO_ENDPOINT" \
      --location="global" \
      --attribute-mapping ="google.subject=assertion.sub,attribute.isadmin-assertion.isadmin,attribute.aud=assertion.aud" \
      --attribute-condition="attribute.isadmin=='true'"
    

    Substitua VAR_LINK_TO_ENDPOINT por uma variável que contenha o link para o endpoint OIDC do Keycloak. Para encontrar esse link, no Admin Console do Keycloak, na janela Realm, clique na guia General. O endpoint precisa ser HTTPS, ou seja, é preciso configurar o servidor do Keycloak com HTTPS.

Acessar o JWT para o usuário autenticado no Keycloak

  1. Na VM que executa o Keycloak, faça o download do token para um arquivo de texto. Por exemplo, no Linux, execute o seguinte:

    curl -L -X POST 'https://IP_FOR_KEYCLOAK:8080/auth/realms/master/protocol/openid-connect/token' -H 'Content-Type: application/x-www-form-urlencoded' \
      --data-urlencode 'client_id=jenks' \
      --data-urlencode 'grant_type=password' \
      --data-urlencode 'client_secret=CLIENT_SECRET \
      --data-urlencode 'scope=openid' \
      --data-urlencode 'username=USERNAME' \
      --data-urlencode 'password=PASSWORD' | grep access_token | cut -c18-1490 > token.txt
    

    Substitua:

    • IP_FOR_KEYCLOAK pelo endereço IP do servidor do Keycloak.
    • CLIENT_SECRET pela chave secreta do cliente do Keycloak.
    • USERNAME por um usuário do Keycloak.
    • PASSWORD pela senha do usuário do Keycloak.

    Esse comando inclui o ID, a chave secreta, o nome de usuário e a senha do cliente. Como prática recomendada de segurança, use variáveis de ambiente, e não a linha de comando, para mascarar esses valores. O exemplo de comando redireciona as credenciais para um arquivo chamado token.txt.

    Como opção, para automatizar essa etapa, você pode criar um script bash.

  2. Valide seu token em jwt.io.

  3. Na VM, crie o arquivo de credenciais:

    gcloud iam workload-identity-pools create-cred-config \
    projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/cloudrun-oidc-pool/providers/cloud-run/provider \
      --output-file=sts-creds.json \
      --credential-source-file=token.txt
    

    Saiba mais em gcloud iam workload-identity-pools create-cred-config.

    O arquivo de saída vai ficar assim:

    {
        "type": "external_account",
        "audience": "//iam.google.apis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/cloudrun-oidc-pool/subject/USER_EMAIL",
        "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
        "token_url": "https://sts.googleapis.com/v1/token",
        "credential_source": {
            "file" "token.txt" }
    }
    

    PROJECT_NUMBER é o número do projeto.

  4. Na VM, defina o arquivo sts.creds.json como uma variável para o ADC:

    export GOOGLE_APPLICATION_CREDENTIALS=/Users/USERNAME/sts-creds.json
    

    Substitua USERNAME pelo seu nome de usuário do UNIX.

    Antes do lançamento da federação de identidade da carga de trabalho, esse valor era a chave da conta de serviço. Com a federação de identidade da força de trabalho, esse valor é o arquivo de credenciais recém-criado.

  5. Crie uma vinculação de papel para o usuário representar a conta de serviço:

    gcloud iam service-accounts add-iam-policy-binding SERVICE_ACCOUNT \
        --role roles/iam.workloadIdentityUser \
        --member "principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/cloudrun-oidc-pool/subject/USER_EMAIL
    

    Substitua:

  6. Permita que a conta de serviço acesse o serviço do Cloud Run:

    gcloud run services add-iam-policy-binding SERVICE_NAME
      --member-"serviceAccount:SERVICE_ACCOUNT" \
      --role="roles/run.invoker"
    

    Substitua:

    • SERVICE_NAME pelo nome do microsserviço em execução no Cloud Run.

    • SERVICE_ACCOUNT pelo endereço de e-mail da conta de serviço do Cloud Run.

    Saiba mais em gcloud run services add-iam-policy-binding.

  7. Gere um token de ID:

    #!/usr/bin/python
    from google.auth import credentials
    from google.cloud import  iam_credentials_v1
    
    import google.auth
    import google.oauth2.credentials
    
    from google.auth.transport.requests import AuthorizedSession, Request
    
    url = "https://WORKLOAD_FQDN"
    aud = "https://WORKLOAD_FQDN"
    service_account = 'SERVICE_ACCOUNT'
    
    name = "projects/-/serviceAccounts/{}".format(service_account)
    id_token = client.generate_id_token(name=name,audience=aud, include_email=True)
    
    print(id_token.token)
    
    creds = google.oauth2.credentials.Credentials(id_token.token)
    authed_session = AuthorizedSession(creds)
    r = authed_session.get(url)
    print(r.status_code)
    print(r.text)
    

    Substitua:

    • WORKLOAD_FQDN pelo FQDN da carga de trabalho.

    • SERVICE_ACCOUNT pelo endereço de e-mail da conta de serviço do Cloud Run.

O token usado pode chamar a API Identity and Access Management, que vai fornecer o novo JWT necessário para invocar o serviço do Cloud Run.

É possível usar seu token em um pipeline do Jenkins para invocar o contêiner sem servidor que você está executando no Cloud Run. No entanto, essas etapas estão fora do escopo deste tutorial.

Limpar

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados neste tutorial, exclua o projeto.

Exclua o projeto

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

A seguir