Como configurar um proxy do Pub/Sub para clientes de dispositivos móveis no GKE


Neste tutorial, mostramos como publicar mensagens de aplicativos para dispositivos móveis ou do cliente no Pub/Sub usando um proxy que processa a lógica de autenticação e autorização em vez das credenciais do lado do cliente.

Mesmo que você autentique mensagens do cliente no Pub/Sub usando o Identity and Access Management (IAM), essas credenciais de longa duração nunca expiram. Em aplicativos do lado do cliente, essas credenciais podem ser descobertas por meio de técnicas como descompilação de aplicativos e engenharia reversa.

Em vez disso, é possível descarregar a autenticação e a lógica de autorização para um proxy que executa as seguintes tarefas:

  • Autentica solicitações recebidas para validar o usuário.
  • Encaminha solicitações para o Pub/Sub junto com as permissões apropriadas do IAM.

Neste tutorial, mostramos como implementar um proxy do Pub/Sub no Google Kubernetes Engine (GKE). Este tutorial é destinado a desenvolvedores de aplicativos e arquitetos de sistemas que definem e implementam o design para aplicativos móveis ou do lado do cliente. Para isso, presumimos que você entenda os conceitos fundamentais do Kubernetes (em inglês) e esteja familiarizado com o Cloud Endpoints.

Fluxo de solicitação para este tutorial

Para entender como o Pub/Sub se encaixa em um pipeline de streaming, considere uma análise de fluxo de cliques. Nesse caso de uso, convém entender como os usuários interagem com seu aplicativo para dispositivos móveis. Para receber esses insights, você captura a atividade do usuário em tempo real. O diagrama a seguir mostra o fluxo de dados.

O proxy do Pub/Sub recebe mensagens do cliente antes da agregação dos dados.

Os dados capturados pelo aplicativo são enviados ao Pub/Sub por meio de um proxy. O Pub/Sub pode ter assinantes downstream, como o Dataflow ou o Dataproc, que agregam os dados para você realizar análises significativas.

O diagrama a seguir mostra uma visualização detalhada do fluxo de solicitação que este tutorial segue.

Como os componentes do pipeline interagem em uma solicitação do usuário.

As próximas seções explicam como os vários componentes deste diagrama interagem.

Autenticação do usuário

Os aplicativos para dispositivos móveis podem usar vários métodos para autenticar usuários. O fluxo de autenticação é específico para seu aplicativo. Neste tutorial, mostramos uma dessas soluções para autenticar usuários. Uma implementação desta solução acompanha este tutorial.

Solicitações do app cliente para o proxy do Pub/Sub

O back-end do aplicativo gera um token de autenticação de curta duração que o cliente armazena localmente (por exemplo, usando o sistema Android Keystore ou os serviços do conjunto de chaves do iOS, link em inglês). Neste tutorial, usamos tokens de código do OpenID Connect (OIDC), link em inglês, para autenticar o app cliente. O Google emite e assina o token de código OIDC.

O aplicativo do lado do cliente envia uma solicitação ao proxy do Pub/Sub usando o token de código OIDC. O proxy do Pub/Sub valida o token e encaminha a solicitação para o Pub/Sub com as credenciais apropriadas do IAM.

Como publicar mensagens

Depois que o aplicativo cliente for autenticado, o proxy do Pub/Sub enviará uma solicitação de publicação para o Pub/Sub. Com o IAM, o Pub/Sub ajuda a garantir que o autor da chamada (o proxy do Pub/Sub) tenha as permissões certas para enviar solicitações de publicação. Neste tutorial, o proxy do Pub/Sub usa a conta de serviço padrão do Compute Engine para autenticar com o Pub/Sub. A conta de serviço padrão do Compute Engine tem o editor Papel de IAM (roles/editor), que fornece acesso de editor ao proxy do Pub/Sub.

Objetivos

  • Crie um cluster do GKE para executar um proxy do Pub/Sub.
  • Crie um tópico do Pub/Sub.
  • Implante o proxy do Pub/Sub.
  • Configure o Endpoints para autenticar solicitações para o proxy do Pub/Sub.
  • Verifique se as mensagens foram publicadas no Pub/Sub.

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. No console do Google Cloud, acesse a página do seletor de projetos.

    Acessar o seletor de projetos

  2. Selecione ou crie um projeto do Google Cloud.

  3. Verifique se a cobrança está ativada para o seu projeto do Google Cloud.

  4. No Console do Google Cloud, ative o Cloud Shell.

    Ativar o Cloud Shell

    Na parte inferior do Console do Google Cloud, uma sessão do Cloud Shell é iniciada e exibe um prompt de linha de comando. O Cloud Shell é um ambiente shell com a CLI do Google Cloud já instalada e com valores já definidos para o projeto atual. A inicialização da sessão pode levar alguns segundos.

  5. Defina as variáveis de ambiente necessárias para este tutorial:
        export PROJECT=$(gcloud config get-value project)
        export REGION=us-central1
        export ZONE=${REGION}-b
        export CLUSTER=pubsub-proxy
        export TOPIC=proxy-test
        export SERVICE_ACCOUNT=publish-test
        export ENDPOINTS_SERVICE="pubtest.endpoints.${PROJECT}.cloud.goog"
        export GENERATE_TOKEN="https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts"
  6. Ative as APIs para Cloud Build, Compute Engine, Google Kubernetes Engine, Artifact Analysis, Container Registry, Endpoints, Service Management, Service Control e Pub/Sub:
        gcloud services enable \
            cloudbuild.googleapis.com \
            compute.googleapis.com \
            container.googleapis.com \
            containeranalysis.googleapis.com \
            containerregistry.googleapis.com \
            endpoints.googleapis.com \
            servicemanagement.googleapis.com \
            servicecontrol.googleapis.com \
            pubsub.googleapis.com

Como criar um tópico do Pub/Sub

  • No Cloud Shell, crie um tópico do Pub/Sub para o qual você publica mensagens:

    gcloud pubsub topics create $TOPIC
    

Como criar um cluster do GKE

  1. No Cloud Shell, crie um cluster do GKE:

    gcloud container clusters create $CLUSTER \
        --zone $ZONE \
        --scopes "https://www.googleapis.com/auth/cloud-platform"
    
  2. Receba credenciais para o cluster em execução:

    gcloud container clusters get-credentials $CLUSTER \
        --zone $ZONE \
        --project $PROJECT
    

Como criar uma imagem de contêiner

  1. No Cloud Shell, clone o repositório de código:

    git clone https://github.com/GoogleCloudPlatform/solutions-pubsub-proxy-rest
    
  2. Use o Cloud Build para criar uma imagem de contêiner a partir da origem e salve-a no Container Registry:

    cd solutions-pubsub-proxy-rest && \
        gcloud builds submit --tag gcr.io/$PROJECT/pubsub-proxy:v1
    

Como criar um endereço IP externo estático

  1. No Cloud Shell, crie um endereço IP externo estático que seja atribuído posteriormente ao balanceador de carga do proxy do Pub/Sub:

    gcloud compute addresses create service-ip --region $REGION
    
  2. Armazene o endereço IP estático em uma variável de ambiente, PROXY_IP:

    PROXY_IP=$(gcloud compute addresses describe service-ip \
        --region $REGION --format='value(address)')
    

Como implantar endpoints

O proxy do Pub/Sub usa o Endpoints para autenticar solicitações de usuários. O Endpoints usa o Extensible Service Proxy (ESP) para fornecer recursos de gerenciamento de API, como autenticação, monitoramento, rastreamento, e gerenciamento do ciclo de vida da API. Neste tutorial, usamos o Endpoints apenas para autenticar solicitações recebidas para o proxy do Pub/Sub.

Neste tutorial, você implantará o ESP como um arquivo secundário (em inglês) com o proxy do Pub/Sub. O ESP intercepta e autentica solicitações recebidas antes de encaminhá-las ao proxy do Pub/Sub.

  1. No Cloud Shell, substitua o marcador [PROJECT_ID] pelo código do projeto do Google Cloud no arquivo openapi.yaml:

    sed -i -e "s/\[PROJECT_ID\]/$PROJECT/g" openapi.yaml
    
  2. No arquivo de manifesto da OpenAPI, substitua o marcador [IP_ADDRESS] pelo valor de PROXY_IP:

    sed -i -e "s/\[IP_ADDRESS\]/$PROXY_IP/g" openapi.yaml
    
  3. Implante a definição de serviço da OpenAPI no Endpoints:

    gcloud endpoints services deploy openapi.yaml
    

    O comando anterior cria o seguinte:

    • Um serviço gerenciado com o nome que você especificou no campo de host do arquivo openapi.yaml (pubtest.endpoints.project-id.cloud.goog), em que project-id é o ID do projeto do Google Cloud.
    • Um registro A DNS que usa o nome do serviço e o mapeamento do endereço IP do balanceador de carga do proxy do Pub/Sub definido na extensão x-google-endpoints no arquivo openapi.yaml.

    Durante a implantação, você vê um aviso que pode ser ignorado porque este tutorial usa tokens de código OIDC para autenticação em vez de chaves de API.

    WARNING: openapi.yaml: Operation 'post' in path '/publish': Operation does
    not require an API key; callers may invoke the method without specifying an
    associated API-consuming project. To enable API key all the
    SecurityRequirement Objects
    (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object)
    inside security definition must reference at least one SecurityDefinition
    of type : 'apiKey'.
    
  4. Verifique se o serviço está implantado corretamente:

    gcloud endpoints services describe ${ENDPOINTS_SERVICE}
    

    A saída será assim:

    [...]
    producerProjectId: project-id
    serviceConfig:
      documentation:
        summary: Pub/Sub proxy exposed as an Endpoint API
    [...]
      name: pubtest.endpoints.project-id.cloud.goog
      title: PubSub Proxy
      usage: {}
    serviceName: pubtest.endpoints.project-id.cloud.goog
    

    Na saída:

    • project-id: o ID do seu projeto do Google Cloud.

Como implantar um proxy

  1. No Cloud Shell, gere um certificado SSL autoassinado para permitir conexões HTTPS com o proxy.

    openssl req -x509 -nodes -days 365 \
        -newkey rsa:2048 -keyout ./nginx.key \
        -out ./nginx.crt \
        -subj "/CN=${ENDPOINTS_SERVICE}"
    
  2. Crie uma chave secreta do Kubernetes usando o certificado SSL e a chave privada:

    kubectl create secret generic nginx-ssl \
        --from-file=./nginx.crt \
        --from-file=./nginx.key
    
  3. Substitua o marcador [PROJECT_ID] no arquivo de manifesto de implantação pelo ID do projeto do Google Cloud:

    sed -i -e "s/\[PROJECT_ID\]/$PROJECT/g" kube/deployment.yaml
    
  4. Substitua o marcador [IP_ADDRESS] no arquivo de manifesto de serviço pelo valor de PROXY_IP:

    sed -i -e "s/\[IP_ADDRESS\]/$PROXY_IP/g" kube/service.yaml
    
  5. Implante o proxy:

    kubectl apply -f kube/
    
  6. Verifique se a implantação foi bem-sucedida:

    kubectl rollout status deployment/pubsub-proxy
    

    A saída será assim:

    [...]
    deployment "pubsub-proxy" successfully rolled out
    
  7. Verifique se dois contêineres (ESP e proxy do Pub/Sub) estão em execução no pod:

    kubectl get pods $(kubectl get pod \
        -l app=pubsub-proxy \
        -o jsonpath="{.items[0].metadata.name}") \
        -o jsonpath={.spec.containers[*].name}
    

    A resposta será semelhante a:

    esp  pubsub-proxy
    
  8. Fique atento ao valor de EXTERNAL-IP para mudar de <pending> para o endereço IP externo estático que você criou anteriormente:

    kubectl get svc pubsub-proxy -w
    

    A saída será assim:

    NAME          TYPE          CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
    pubsub-proxy  LoadBalancer  10.7.247.212  <pending>     443:31104/TCP  6m32s
    pubsub-proxy  LoadBalancer  10.7.247.212  <PROXY_IP>    443:31104/TCP  6m5s
    

    Para parar de assistir, pressione CTRL+C.

    Depois que o proxy do Pub/Sub for implantado, ele será exposto em https://${ENDPOINTS_SERVICE}/publish. Pode levar alguns minutos para a nova configuração do DNS se propagar.

  9. Verifique a configuração do DNS:

    watch nslookup ${ENDPOINTS_SERVICE}
    

    A saída será assim:

    Server:   169.254.169.254
    Address:  169.254.169.254#53
    
    Non-authoritative answer:
    Name: pubtest.endpoints.project-id.cloud.goog
    Address: gke-load-balancer-ip
    

    Na saída:

    • gke-load-balancer-ip: o endereço IP do balanceador de carga do GKE (IP do proxy).

    Para parar de assistir, pressione CTRL+C.

Se alguma das etapas anteriores resultar em um erro, consulte as etapas de solução de problemas.

Como gerar um token de autenticação

O procedimento a seguir para gerar um token de autenticação é um exemplo. Para o ambiente de produção, é necessário que os usuários gerem os próprios tokens de autenticação. Por exemplo, é possível encontrar um código de amostra para receber um token de código OIDC de maneira programática na documentação do Identity-Aware Proxy.

Para gerar um token de autenticação, faça o seguinte:

  1. Crie uma conta de serviço do Google Cloud para a qual você gera um token de código OIDC:

    gcloud iam service-accounts create \
        $SERVICE_ACCOUNT \
        --display-name $SERVICE_ACCOUNT
    
  2. Consiga a identidade do e-mail da conta de serviço:

    SA_EMAIL=${SERVICE_ACCOUNT}@${PROJECT}.iam.gserviceaccount.com
    
  3. Conceda o papel Criador de token da conta de serviço (roles/iam.serviceAccountTokenCreator) do IAM para a conta de serviço:

    gcloud iam service-accounts add-iam-policy-binding $SA_EMAIL \
        --member user:$(gcloud config get-value account) \
        --role roles/iam.serviceAccountTokenCreator
    
  4. Usando a API de credenciais do IAM, gere um token de código OIDC.

    TOKEN=$(curl -s ${GENERATE_TOKEN}/${SA_EMAIL}:generateIdToken \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -d '{"audience": "'${ENDPOINTS_SERVICE}'", "includeEmail": "true"}' | jq -r ".token")
    

    O nome do serviço do Endpoints é especificado no campo audience. A declaração audience identifica o destinatário para o qual o token é destinado.

  5. Verifique se o token foi criado:

    echo $TOKEN
    

    O JSON Web Token (JWT) é semelhante ao seguinte:

    eyJhbGciOiJSUzI1NiIsImtpZCI6IjY4NjQyODlm[...].eyJhdWQiOiJwdWJ0ZXN0LmVuZHBvaW50cy52aXR
    hbC1vY3RhZ29uLTEwOTYxMi5jbG91ZC5nb[...].SjBI4TZjZAlYo6lFKkrvfAcVUp_AJzFKoSsjNbmD_n[...]
    

Como chamar o Pub/Sub usando um proxy

  1. No Cloud Shell, publique uma mensagem de teste:

    curl -i -k -X POST https://${ENDPOINTS_SERVICE}/publish \
        -H "Authorization: Bearer $TOKEN" \
        -H "Content-Type: application/json" \
        -d '{"topic": "'$TOPIC'", "messages": [ {"attributes": {"key1": "value1", "key2" : "value2"}, "data": "test data"}]}'
    

    A saída será assim:

    HTTP/2 200
    server: nginx
    date: Sun, 02 Jun 2019 03:53:46 GMT
    ...
    
  2. Verifique se a mensagem foi publicada no tópico do Pub/Sub:

    kubectl logs -f --tail=5 deployment/pubsub-proxy -c pubsub-proxy
    

    Os registros de implantação do proxy do Pub/Sub exibem a mensagem Successfully published:

    2019-06-02 03:49:39.723:INFO:oejs.Server:main: Started @2554ms
    Jun 02, 2019 3:53:44 AM com.google.pubsub.proxy.publish.PublishMessage
    getPublisher
    INFO: Creating new publisher for: proxy-test
    Jun 02, 2019 3:53:47 AM
    com.google.pubsub.proxy.publish.PublishMessage$1 onSuccess
    INFO: Successfully published: 569006136173844
    

Como solucionar problemas

  1. No Cloud Shell, verifique o estado dos dois contêineres no pod proxy do Pub/Sub:

    kubectl describe pods $(kubectl get pod -l app=pubsub-proxy \
        -o jsonpath="{.items[0].metadata.name}")
    

    Na saída do registro, o status dos contêineres é Running:

    [...]
    Containers:
      esp:
    [...]
      State:  Running
        Started:  Fri, 21 Jun 2019 16:41:30 +0530
      Ready:  True
      Restart Count:  0
    [...]
      pubsub-proxy:
        State:  Running
          Started:  Fri, 21 Jun 2019 16:41:42 +0530
        Ready:  True
        Restart Count:  0
    [...]
    
  2. (Opcional) Verifique os registros do contêiner para ver se há outros erros. Por exemplo, para verificar os registros de proxy do Pub/Sub, execute o seguinte comando:

    kubectl logs -f --tail=10 deployment/pubsub-proxy -c pubsub-proxy
    

Para receber ajuda com a solução de problemas, consulte os seguintes documentos:

Limpeza

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados neste tutorial, exclua o projeto do Google Cloud criado para este tutorial ou exclua os recursos associados a ele.

Excluir o projeto do Google Cloud

A maneira mais fácil de eliminar o faturamento é excluir o projeto que você criou para o tutorial.

  1. No Console do Google Cloud, acesse a página Gerenciar recursos.

    Acessar "Gerenciar recursos"

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
  3. Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.

Excluir os recursos

Se você quiser manter o projeto do Google Cloud usado neste tutorial, exclua os recursos individuais:

  1. No Cloud Shell, exclua o cluster do GKE:

    gcloud container clusters delete $CLUSTER --zone $ZONE --async
    
  2. Exclua o código baixado, os artefatos e outras dependências:

    cd .. && rm -rf solutions-pubsub-proxy-rest
    
  3. Exclua a imagem no Container Registry:

    gcloud container images list-tags \
        gcr.io/$PROJECT/pubsub-proxy \
        --format 'value(digest)' | \
        xargs -I {} gcloud container images delete \
        --force-delete-tags --quiet \
        gcr.io/${PROJECT}/pubsub-proxy@sha256:{}
    
  4. Exclua o tópico Pub/Sub:

    gcloud pubsub topics delete $TOPIC
    
  5. Exclua a conta de serviço:

    gcloud iam service-accounts delete $SA_EMAIL
    
  6. Exclua o Endpoints:

    gcloud endpoints services delete ${ENDPOINTS_SERVICE}
    
  7. Exclua o endereço IP estático:

    gcloud compute addresses delete service-ip --region $REGION
    

A seguir