Autenticação de usuário com o Identity-Aware Proxy

1. Introdução

Muitas vezes, é preciso autenticar os usuários do seu app da Web, e isso costuma exigir uma programação especial dele. Para os apps do Google Cloud Platform, você pode transferir essa responsabilidade para o serviço Identity-Aware Proxy. Se você só precisar restringir o acesso a usuários selecionados, não precisará fazer mudanças no aplicativo. Quando é preciso saber a identidade do usuário para manter as preferências dele no servidor, por exemplo, o Identity-Aware Proxy pode fazer isso para você com pouco código no aplicativo.

O que é o Identity-Aware Proxy?

O Identity-Aware Proxy (IAP) é um serviço do Google Cloud Platform que intercepta solicitações da Web enviadas ao aplicativo, autentica o autor delas por meio do serviço de identidade do Google e só permite a transmissão quando elas vêm de um usuário autorizado. Além disso, o IAP pode modificar o cabeçalho das solicitações para incluir informações sobre o usuário autenticado.

Neste codelab, você vai aprender a criar seu próprio aplicativo, restringir o acesso a ele e receber a identidade do usuário do IAP.

O que você criará

Neste codelab, você vai criar um aplicativo da Web mínimo com o Google App Engine e conhecer várias maneiras de usar o Identity-Aware Proxy para restringir o acesso ao aplicativo e fornecer informações de identidade do usuário a ele. Esse app vai:

  • Exibir uma página inicial.
  • Acessar informações de identidade do usuário transmitidas pelo IAP
  • Usar a verificação criptográfica para evitar o spoofing dessas informações

O que você vai aprender

  • Como escrever e implantar um aplicativo simples do App Engine usando Python 3.7
  • Como ativar e desativar o IAP para restringir o acesso ao aplicativo
  • Como transferir informações de identidade do usuário do IAP para o aplicativo
  • Como verificar criptograficamente as informações do IAP para se proteger contra spoofing

O que é necessário

  • Um navegador da Web moderno, como o Chrome.
  • Conhecimento básico da linguagem de programação Python

Este codelab é focado no Google App Engine e no IAP. Conceitos e blocos de códigos sem relevância não serão abordados. Eles são incluídos somente para você copiar e colar.

2. Etapas da configuração

Você vai trabalhar no ambiente de linha de comando do Cloud Shell. Comece abrindo esse ambiente e buscando o exemplo de código.

Iniciar o console e o Cloud Shell

Na parte superior esquerda da página do laboratório, clique no botão "Abrir Console do Google". Faça login com o nome de usuário e a senha mostrados abaixo desse botão.

Todos os comandos deste codelab serão executados em um Cloud Shell para o projeto criado e aberto para você. Abra o Cloud Shell clicando no ícone "Ativar o Cloud Shell" no lado direito do cabeçalho da página do console. Na metade inferior da página, você pode inserir e executar comandos.Eles podem ser executados no seu PC, mas primeiro é necessário instalar e configurar o software de desenvolvimento necessário. O Cloud Shell já tem todas as ferramentas de software necessárias.

Baixar o código

Clique na área da linha de comando no Cloud Shell para digitar os comandos. Busque o código no GitHub e mude para a pasta de código:

git clone https://github.com/googlecodelabs/user-authentication-with-iap.git
cd user-authentication-with-iap

Essa pasta contém uma subpasta para cada etapa do codelab. Acesse cada pasta no momento correspondente.

3. Etapa 1: implante o aplicativo e proteja-o com o IAP

Este é um aplicativo padrão do App Engine escrito em Python 3.7 que mostra uma página inicial com a mensagem "Hello, World". Vamos implantá-lo, testá-lo e restringir o acesso a ele usando o IAP.

Analisar o código do aplicativo

Mude da pasta principal do projeto para a subpasta 1-HelloWorld, que contém o código desta etapa.

cd 1-HelloWorld

O código do aplicativo está no arquivo main.py. Ele usa o framework da Web Flask (página em inglês) para responder a solicitações da Web com o conteúdo de um modelo. O arquivo desse modelo está em templates/index.html e contém apenas HTML simples para esta etapa. Um segundo arquivo de modelo em templates/privacy.html inclui um exemplo básico de política de privacidade.

Há dois outros arquivos: requirements.txt lista todas as bibliotecas Python não padrão que o aplicativo usa, e app.yaml informa ao Google Cloud Platform que esse é um aplicativo do App Engine escrito em Python 3.7.

Você pode listar cada arquivo no shell usando o comando cat. Por exemplo:

cat main.py

Outra opção é abrir o editor de código do Cloud Shell clicando no ícone de lápis no canto superior direito da janela do Cloud Shell e verificar o código.

Não é preciso alterar nenhum arquivo nesta etapa.

Faça a implantação no App Engine

Agora implante o app no ambiente padrão do App Engine para Python 3.7.

gcloud app deploy

Talvez seja necessário escolher uma região para a implantação. Selecione uma opção perto de você que mostre "supports standard", indicando que é compatível com o padrão. Quando for perguntado se você quer continuar, digite Y para sim.

Em alguns minutos, a implantação será concluída e você vai receber uma mensagem informando que pode conferir o aplicativo com gcloud app browse. Insira este comando. Se uma nova guia não abrir no navegador, clique no link exibido para abri-lo em uma nova guia ou copie o URL em uma guia aberta manualmente, se necessário. Como esta é a primeira vez que o app é executado, levará alguns segundos para ele aparecer enquanto uma instância de nuvem é iniciada. Em seguida, você verá a janela a seguir.

1c1c0b166c6023e.png

É possível abrir o mesmo URL em qualquer computador conectado à Internet para ver essa página da Web. O acesso ainda não está restrito.

Restringir o acesso com o IAP

Na janela do console do Cloud, clique no ícone de menu no canto superior esquerdo da página, clique em "Segurança" e em "Identity-Aware Proxy".

Como esta é a primeira vez que você ativou uma opção de autenticação para este projeto, vai aparecer uma mensagem informando que é necessário configurar a tela de permissão OAuth antes de usar o IAP.

Clique no botão "CONFIGURAR TELA DE CONSENTIMENTO". Uma nova guia será aberta para configurar a tela de permissão.

Preencha os espaços obrigatórios com os valores corretos:

Nome do aplicativo

Exemplo do IAP

E-mail para suporte

Seu endereço de e-mail. Ele pode já estar preenchido.

Domínio autorizado

a parte do URL do aplicativo referente ao nome do host, por exemplo, iap-example-999999.appspot.com. Ela está na barra de endereço da página da Web "Hello World" que foi aberta. Não inclua https:// do início nem / do fim do URL.Pressione Enter após preencher o valor.

Link da página inicial do aplicativo

o URL usado para visualizar o app

Link da Política de Privacidade do aplicativo

o link da página de privacidade no app, igual ao da página inicial com /privacy adicionado ao final

Clique em Salvar. Será solicitado que você crie credenciais. Você não precisa fazer isso neste codelab. Basta fechar esta guia do navegador.

Volte e atualize a página do Identity-Aware Proxy. Agora você vai ver uma lista de recursos que podem ser protegidos.Clique no botão na coluna IAP localizada na linha do app do App Engine para ativar o IAP.

Você verá os nomes de domínio que serão protegidos pelo IAP. Clique em ATIVAR.

Agora abra uma guia do navegador e navegue até o URL do seu app. A tela "Fazer login com o Google" será aberta para você acessar o app.

Faça login com uma conta do Google ou do G Suite. Você verá uma tela negando seu acesso.

Você protegeu o aplicativo com o IAP, mas ainda não informou ao serviço quais contas têm permissão.

Volte à página do Identity-Aware Proxy do console, marque a caixa de seleção ao lado do aplicativo do App Engine e veja a barra lateral à direita da página.

Cada endereço de e-mail, endereço do Grupo do Google ou nome de domínio do G Suite com permissão de acesso precisa ser adicionado como um membro. Clique em ADICIONAR MEMBRO. Insira seu endereço de e-mail e escolha o papel "Usuário do app da Web protegido pelo Cloud IAP/IAP" para atribuir a esse endereço. Você pode inserir mais endereços ou domínios do G Suite da mesma maneira.

Clique em "Salvar". A mensagem "Política atualizada" aparecerá na parte inferior da janela.

Navegue de volta para o aplicativo e recarregue a página. Agora você verá o aplicativo da Web, porque já fez login com um usuário autorizado. No entanto, a página "Você não tem acesso" ainda pode ser exibida, porque o IAP pode não verificar novamente a autorização. Nesse caso, siga estas etapas:

  • Abra o navegador da Web no endereço da página inicial com /_gcp_iap/clear_login_cookie adicionado ao final do URL, como em https://iap-example-999999.appspot.com/_gcp_iap/clear_login_cookie.
  • Você verá uma nova tela "Fazer login com o Google", com sua conta já preenchida. Não clique na conta. Em vez disso, clique em "Usar outra conta" e insira novamente suas credenciais.
  • Isso fará com que o IAP verifique novamente o acesso, e você verá a tela inicial do aplicativo.

Se você tiver acesso a outro navegador ou puder usar o modo de navegação anônima e tiver outra conta válida do Gmail ou G Suite, use isso para navegar até a página do aplicativo e fazer login com a outra conta. Como ela não foi autorizada, você verá a tela "You Don't Have Access" em vez do aplicativo.

4. Etapa 2: acessar as informações de identidade do usuário

Quando um aplicativo é protegido com o IAP, ele pode usar as informações de identidade transmitidas pelo IAP no cabeçalho das solicitações da Web. Nesta etapa, o aplicativo vai receber o endereço de e-mail do usuário que fez login e um ID de usuário único e permanente atribuído a ele pelo serviço de identidade do Google. Esses dados serão exibidos para o usuário na página inicial.

Esta é a etapa 2, e a última etapa terminou com o Cloud Shell aberto na pasta iap-codelab/1-HelloWorld. Abra a pasta desta etapa:

cd ~/iap-codelab/2-HelloUser

Implantar no App Engine

Como a implantação leva alguns minutos, comece implantando o app no ambiente padrão do App Engine para Python 3.7:

gcloud app deploy

Quando aparecer uma mensagem perguntando se você quer continuar, digite Y para sim. Em alguns minutos, a implantação será concluída. Enquanto você espera, analise os arquivos do aplicativo conforme descrito abaixo.

Quando a implantação estiver pronta, você verá uma mensagem informando que é possível ver o aplicativo com gcloud app browse. Insira este comando. Se uma nova guia não abrir no navegador, copie o link exibido e acesse-o em outra guia normalmente. Você vai ver uma página semelhante a esta:

5b5fb03111258cec.png

Talvez seja necessário aguardar alguns minutos para que a nova versão do aplicativo substitua a anterior. Se necessário, atualize a página para ver algo semelhante ao exemplo acima.

Analise os arquivos do aplicativo

Esta pasta contém o mesmo conjunto de arquivos visto na etapa 1, mas dois deles foram alterados: main.py e templates/index.html. O programa passou por mudanças para buscar as informações do usuário transmitidas pelo IAP no cabeçalho das solicitações, e o modelo agora exibe esses dados.

Existem duas linhas em main.py que buscam os dados de identidade transmitidos pelo IAP:

user_email = request.headers.get('X-Goog-Authenticated-User-Email')
user_id = request.headers.get('X-Goog-Authenticated-User-ID')

Os cabeçalhos X-Goog-Authenticated-User- são transmitidos pelo IAP, e os nomes são indiferentes a maiúsculas. Então, use só maiúsculas ou minúsculas, como preferir. Agora a instrução render_template inclui esses valores para eles serem exibidos:

page = render_template('index.html', email=user_email, id=user_id)

Coloque os nomes em chaves duplas para que o modelo index.html mostre esses valores:

Hello, {{ email }}! Your persistent ID is {{ id }}.

Os dados transmitidos têm o prefixo accounts.google.com:, que mostra a origem das informações. Se você quiser, o aplicativo poderá remover tudo até os dois pontos (inclusive esta pontuação) para exibir os valores brutos.

Desative o IAP

O que acontece com o aplicativo quando o IAP é desativado ou ignorado por outros aplicativos em execução no mesmo projeto na nuvem, por exemplo? Desative o IAP para saber.

Na janela do console do Cloud, clique no ícone de menu no canto superior esquerdo da página, clique em "Segurança" e em "Identity-Aware Proxy". Clique no botão ativar do IAP ao lado do app do App Engine para desativar o IAP.

Você verá um aviso de que isso permitirá que todos os usuários acessem o aplicativo.

Atualize a página da Web do aplicativo. Você verá a mesma página, mas sem informações do usuário:

17c850de95fea839.png

Como agora o aplicativo está desprotegido, um usuário pode enviar uma solicitação da Web que parece ter passado pelo IAP. Por exemplo, é possível executar o seguinte comando curl no Cloud Shell para fazer isso. Substitua <your-url-here> pelo URL correto do app:

curl -X GET <your-url-here> -H "X-Goog-Authenticated-User-Email: totally fake email"

A página da Web aparecerá na linha de comando e será semelhante ao exemplo a seguir:

<!doctype html>
<html>
<head>
  <title>IAP Hello User</title>
</head>
<body>
  <h1>Hello World</h1>

  <p>
    Hello, totally fake email! Your persistent ID is None.
  </p>

  <p>
    This is step 2 of the <em>User Authentication with IAP</em>
    codelab.
 </p>

</body>
</html>

Não há como o aplicativo saber que o IAP foi desativado ou ignorado. Para casos em que isso é um risco em potencial, a etapa 3 mostra uma solução.

5. Etapa 3: usar a verificação criptográfica

Quando há o risco de o IAP ser desativado ou ignorado, o aplicativo pode verificar se as informações de identidade recebidas são válidas. Para isso, ele usa um terceiro cabeçalho de solicitação da Web adicionado pelo IAP, chamado X-Goog-IAP-JWT-Assertion. O valor do cabeçalho é um objeto assinado criptograficamente que também contém os dados de identidade do usuário. O aplicativo pode verificar a assinatura digital e usar os dados transmitidos neste objeto para ter certeza de que ele foi transmitido pelo IAP sem alterações.

A verificação da assinatura digital requer várias etapas adicionais, como a busca pelo conjunto mais recente de chaves públicas do Google. Você decide se o aplicativo precisa dessas etapas a mais com base na confidencialidade dele e no risco de que alguém possa desativar ou ignorar o IAP.

Esta é a etapa 3, e a última etapa terminou com o Cloud Shell aberto na pasta iap-codelab/2-HelloUser. Abra a pasta desta etapa:

cd ~/iap-codelab/3-HelloVerifiedUser

Faça a implantação no App Engine

Implante o app no ambiente padrão do App Engine para Python 3.7:

gcloud app deploy

Quando aparecer uma mensagem perguntando se você quer continuar, digite Y para sim. Em alguns minutos, a implantação será concluída. Enquanto você espera, analise os arquivos do aplicativo conforme descrito abaixo.

Quando a implantação estiver pronta, você verá uma mensagem informando que é possível ver o aplicativo com gcloud app browse. Insira este comando. Se uma nova guia não abrir no navegador, copie o link exibido e acesse-o em outra guia normalmente.

Lembre-se de que você desativou o IAP na etapa 2. Por isso, nenhum dado do IAP está sendo fornecido ao aplicativo. Você vai ver uma página semelhante a esta:

8ef2abcc23d96958.png

Assim como antes, talvez seja preciso aguardar alguns minutos até que a versão mais recente da página apareça.

Como o IAP foi desativado, nenhuma informação do usuário está disponível. Agora, ative novamente o IAP.

Na janela do console do Cloud, clique no ícone de menu no canto superior esquerdo da página, clique em "Segurança" e em "Identity-Aware Proxy". Clique no botão ativar do IAP ao lado do app do App Engine para ativá-lo novamente.

Atualize a página. Ela será parecida com o exemplo a seguir:

3a4d93c11f228852.png

Observe que o endereço de e-mail indicado pelo método verificado não tem o prefixo accounts.google.com:.

Se o IAP estiver desativado ou for ignorado, não haverá dados verificados ou eles serão inválidos, porque eles só poderiam ter uma assinatura válida se fossem criados pelo proprietário das chaves privadas do Google.

Analise os arquivos do aplicativo

Esta pasta contém o mesmo conjunto de arquivos visto na etapa 2, com dois arquivos alterados e um novo. O novo arquivo é auth.py, que fornece um método user() para buscar e verificar as informações de identidade assinadas criptograficamente. Os itens alterados são main.py e templates/index.html, que agora usam os resultados desse método. Os cabeçalhos não verificados encontrados na etapa 2 também são mostrados para comparação.

A nova funcionalidade está principalmente na função user():

def user():
    assertion = request.headers.get('X-Goog-IAP-JWT-Assertion')
    if assertion is None:
        return None, None

    info = jwt.decode(
        assertion,
        keys(),
        algorithms=['ES256'],
        audience=audience()
    )

    return info['email'], info['sub']

O assertion corresponde aos dados assinados criptograficamente que foram transmitidos no cabeçalho da solicitação especificada. O código usa uma biblioteca para validar e decodificar esses dados. A validação usa as chaves públicas atribuídas pelo Google para verificar os dados que assina e saber para que público os dados foram preparados (basicamente, o projeto do Google Cloud que está sendo protegido). As funções auxiliares keys() e audience() coletam e retornam esses valores.

O objeto assinado tem dois dados de que precisamos: o endereço de e-mail verificado e o valor de ID exclusivo, indicados no campo padrão sub, de assinante.

Isso conclui a Etapa 3.

6. Resumo

Você implantou um aplicativo da Web do App Engine. Na etapa 1, você restringiu o acesso ao aplicativo somente aos usuários escolhidos. Na etapa 2, você buscou e exibiu a identidade dos usuários que o IAP permitiu acessar o aplicativo e viu como essas informações poderiam ser falsificadas se o IAP fosse desativado ou ignorado. Na etapa 3, você verificou as declarações assinadas criptograficamente da identidade do usuário, que não podem ser falsificadas.

7. Limpeza

Os únicos recursos do Google Cloud Platform usados neste codelab são instâncias do App Engine. Cada vez que você implanta o app, uma nova versão é criada e continua existindo até ser excluída. Saia do laboratório para excluir o projeto e todos os recursos dele.