Autenticação no Google Cloud Platform usando gcloud e Java com SpringBoot
Existem diferentes maneiras de fazermos autenticação na plataforma do GCP — Google Cloud Platform e recuperar um Access Token para fazermos requisições autenticadas em API´s na plataforma. Resumidamente podemos recuperar um token executando os comandos o gcloud ou então programaticamente usando uma das inúmeras linguagens de programação suportadas pela plataforma e aqui nesse teste faremos isso usando Java.
Aqui abordaremos de maneira simples e resumida algumas maneiras de fazermos autenticação na plataforma e obtermos um token de acesso as API´s. Não temos como objetivo cobrir de maneira profunda o assunto de segurança, autenticação e autorização, para isso sugiro que consulte a documentação oficial do Google Cloud que é completa e repleta de exemplos na maioria das linguagens de programação.
Aqui você pode encontrar a documentação completa de autenticação.
Visão Geral
De maneira geral o controle de acesso na plataforma do Google Cloud contempla três principais pontos: Autenticação, Autorização e Auditoria.
Autenticação determina quem você é ao se conectar á plataforma.
Autorização determina o que você pode fazer na plataforma.
Auditoria registra todas as ações que foram feitas na plataforma.
Para fazermos a autenticação na plataforma basicamente temos duas principais maneiras sendo uma através de um usuário da plataforma que nos dá acesso ao console e outra seria tendo uma ‘service account’, esta mais usada para integrações entre sistemas e aplicações.
Usuário
Acessando com um usuário comum que tenha acesso ao Google Cloud Platform que você queira acessar (geralmente essa conta é o login do gmail) como mostra na imagem abaixo.
Cloud Shell
Uma vez conectados na plataforma, uma maneira bastante rápida de conseguirmos um token é usando o Cloud Shell e usando um comando do gcloud para isso.
O Cloud Shell é uma ferramenta muito útil que o Google providencia com acesso fácil e direto do console de administração do GCP. Ao acessar o Cloud shell o Google instância uma maquina virtual gratuita para utilização imediata com os recursos do gcloud funcionando sem a necessidade de instalar o Google Cloud SDK e com as principais ferramentas de linha de comando favoritas, como bash, sh, emacs e vim , as ferramentas de administrador, como cliente MySQL, Kubernetes e Docker, Java, Go, Python, Node.js, PHP, Ruby e Git todas já configuradas e prontas para uso, sem a necessidade de instalar a versão mais recente e todas as dependências delas. Basta se conectar ao Cloud Shell e pronto!
Aqui você encontra detalhes dessa ferramenta.
Clicando no botão do Cloud Shell (circulada) um shell será aberto na parte de baixo e nele vamos executando o seguinte comando:
gcloud auth application-default print-access-token
O resultado abaixo deve ser o retorno do comado. Este é seu token de acesso.
Google Cloud SDK
Uma outra maneira de conseguirmos um token de acesso é usando Google Cloud SDK pelo nosso shell em nossa maquina. Nesse caso vamos usar o Windows PowerShell.
Abra o PowerShell e inicie a conexão com o GCP executando o comando abaixo
gcloud init
Siga o passo a passo e informe a sua conta e o projeto que pretende se conectar.
Vamos aqui executar o mesmo comando do gcloud e teremos o mesmo resultado, um novo access token gerado.
gcloud auth application-default print-access-token
Service Account
Vamos criar uma service account para usa-la em nossos projetos/API´s. A service account é uma conta de acesso usada por aplicações para que as mesmas possam se conectar sistematicamente no GCP e assim conseguir se autenticar e gerar um token de acesso.
Para criar uma service account acesse o menu lateral esquerdo > IAM & Admin > Service Account
Na tela que foi aberta clique em + CREATE SERVICE ACCOUNT
Então você será direcionado para a tela de criação da Service Account. No campo “Service account name” vamos dar o nome dessa conta, preencha com “test-app” para fins de teste de artigo.
As boas praticas sugerem que tanto o nome quanto a descrição dessa conta sejam condizentes com o que de fato essa conta se destina.
Na próxima tela vamos atribuir as permissões para essa service account. Apenas para esse exemplo vamos colocar a Role de Project Owner.
As boas praticas de segurança indicam que o ideal é darmos o menor acesso possível(mais restrito) para que a conta tenha acesso estritamente ao que ela pode fazer. Conceder um acesso como o que estamos fazendo aqui para um Service Account em ambiente de produção é perigoso e NÃO RECOMENDADO.
Por fim ao voltarmos a tela que lista as Service Accounts teremos a nossa nova Service Account listada.
Criando uma Credencial
Agora que já criamos a nossa Service Account vamos criar uma credencial para essa conta.
No menu lateral esquerdo acesse: APIs & Services > Credentials.
Na tela de credenciais selecione a Service Account que você acabou de criar.
Clique em + CREATE KEY
Na caixa de opção escolha JSON e ao clicar em CREATE um arquivo .json vai ser baixado para seu computador.
No meu caso o arquivo com nome “services-exp-labs-272718–9ee5283d3edc.json” foi baixado para a pasta downloads com o conteúdo semelhante ao abaixo:
{
"type": "service_account",
"project_id": "services-1111111111",
"private_key_id": "sajdljasljdlkasjdlkajsljdlaksjdla",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEnIZc=\n-----END PRIVATE KEY-----\n",
"client_email": "test-app@services-exp-labs-11111.iam.gserviceaccount.com",
"client_id": "1111111111111111",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/test-app%40services-exp-labs-8.iam.gserviceaccount.com"}
O conteúdo do seu arquivo .json deve ser semelhante a esse (que foi propositalmente modificado por motivos de segurança)
Esse arquivo contem todas as credenciais para acessar remotamente seu ambiente no GCP. Tenha muito cuidado com esse arquivo e JAMAIS adicione ele em um repositório do git.
Escopo de Acesso
Os escopos de acesso definem os escopos padrão do OAuth para solicitações feitas por meio das bibliotecas de cliente e da gcloud. Consequentemente, eles podem limitar o acesso aos métodos de API ao autenticar por meio do OAuth.
Essa informação vai ser importante mais pra frente quando estivermos resgatando um token via código de programação pois teremos que declarar o escopo da chamada.
Uma Service Account é configurada automaticamente com os seguintes escopos:
- Acesso somente leitura ao Cloud Storage:
https://www.googleapis.com/auth/devstorage.read_only
- Acesso para gravar registros do Compute Engine:
https://www.googleapis.com/auth/logging.write
- Acesso de gravação para publicar dados de métrica nos projetos do Google Cloud:
https://www.googleapis.com/auth/monitoring.write
- Acesso somente leitura a recursos do Service Management necessários para o Google Cloud Endpoints(Alfa):
https://www.googleapis.com/auth/service.management.readonly
- Acesso de leitura/gravação a recursos do Service Control necessários para o Google Cloud Endpoints(Alfa):
https://www.googleapis.com/auth/servicecontrol
Obtendo o token com Java
Agora que já conseguimos pegar o token de algumas maneiras usando o comando do gcloud vamos ver uma maneira de obtermos esse token via linha de código Java sem termos que usar o gcloud.
Criando projeto — Java + SpringBoot
Vamos criar um projeto de testes usando Java + SpringBoot para entendermos como podemos fazer essa autenticação e pegar o Token programaticamente.
Acesse o site Spring initializr e configure como na imagem abaixo e vamos gerar um projeto de testes.
Depois de baixar o .zip descompacte ele em uma pasta e seu projeto springBoot básico esta pronto pra uso.
Todo esse código gerado aqui estará disponível no meu gitHub para que você possa clonar e rodar em sua maquina. Para isso execute o comando abaixo
git clone https://github.com/gcbrandao/gcp-auth.git
Primeiro passo para conseguirmos a autenticação é adicionarmos as dependências no arquivo pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency><dependency>
<groupId>com.google.cloud</groupId>
<artifactId>libraries-bom</artifactId>
<version>3.3.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement><dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gcp-starter</artifactId>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.30.7</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.9.0</version>
</dependency>
Usando uma service account para acessar a plataforma temos duas opções básicas de referenciar as credenciais baixadas no arquivo .json. Uma delas será definindo uma variável de ambiente apontando para o nosso arquivo e outra é apontando diretamente no código o arquivo sem a necessidade de uma variável de ambiente.
Variável de Ambiente
Uma maneira de fornecer as credenciais de autenticação ao código do nosso aplicativo de testes é definindo uma variável de ambiente com o nome GOOGLE_APPLICATION_CREDENTIALS.
Para definir a variável de ambiente execute o comando abaixo e substitua [PATH] pelo caminho de onde você salvou o arquivo JSON com a chave da conta de serviço e [FILE_NAME] pelo nome de arquivo. Essa variável só se aplica à sessão de shell atual. Dessa maneira, se você abrir uma nova sessão, precisará definir a variável novamente.
$env:GOOGLE_APPLICATION_CREDENTIALS="[PATH]"$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\[FILE_NAME].json"
Informando o Arquivo JSON no projeto
Uma outra maneira (e a qual eu prefiro) é informar o arquivo JSON de credencial diretamente nos arquivos de configuração do nosso projeto. Pra isso faremos os seguintes passos:
Mova o arquivo JSON para o diretório “/resouces “ do projeto
Agora vamos referenciar ele no “\resources\application.yml”
google:
cloud:
connection-timeout: 60000
read-timeout: 60000
security-key-file: services-exp-labs-272718-9ee5283d3edc.json
Agora vamos criar uma classe para lermos essas configurações
@Data
// lombok de getters e setters
@Component
@ComponentScan
@ConfigurationProperties(prefix = "google.cloud")
// config que aponta para leitura do nosso application.ymlpublic class GoogleCloudProperties {private int connectionTimeout = 60000;
private int readTimeout = 60000;
private String securityKeyFile;
private String projectId;
private String location;
}
Vamos criar uma classe chamada GCPAccessToken.java para interagirmos com as credenciais do GCP.
@Autowired
private GoogleCloudProperties cloudProperties;
// injetando a classe de configuraçãoprivate GoogleCredentials credential;/*
* Pega o token apontando para o arquivo JSON direto
*/public GoogleCredentials getCredentialDirectFile() throws IOException {String securityKeyFile = cloudProperties.getSecurityKeyFile();
// recuperando o arquivo json
credential = GoogleCredentials // objeto resposavel pelas credenciais
.fromStream(new ClassPathResource(securityKeyFile).getInputStream()) // recupera o arquivo JSON
.createScoped(Collections.singletonList("https://www.googleapis.com/auth/devstorage.read_only"));
// informa o escopo do acessocredential.refreshIfExpired();return credential;
// retorna o objeto GoogleCredentials com as credenciais nele
}
Test Case
Vamos criar um testCase para verificarmos se nosso código funciona mesmo e o token é resgatado.
Na pasta de testes de sua aplicação crie a seguinte classe de testes “GcpAuthApplicationTests.java” e vamos criar o seguinte conteúdo:
@SpringBootTest
@AutoConfigureMockMvc
class GcpAuthApplicationTests {@Autowired
GCPAccessToken gcpAccessToken;@Test
public void shoulReturnTokenFromDirectFile() throws IOException {GoogleCredentials credentialDirectFile = gcpAccessToken.getCredentialDirectFile();
// instanciando o GoogleCredentials e chamando nosso metodo que usa o JSON para se autenticarString accessToken = credentialDirectFile.getAccessToken().toString();
// Salvando o conteudo do AccessToken em uma StringSystem.out.printf("AccessToken: %s", accessToken);
// Imprime na tela o valor do Token
}
Nossa classe completa deve ficar semelhante a imagem abaixo:
Ao executarmos o nosso teste GcpAuthApplicationTests.java ,caso tenhamos feito tudo certo ate aqui, teremos o nosso token mostrado na tela.
Finalizamos aqui as maneiras que temos de autenticar e recuperar um token do ambiente do Google Cloud Platform.
Espero ter ajudado e obrigado pela leitura.