Workload Identity GKE — Service account k8s com permissões na GCP
O Workload Identity é um recurso do GKE (Google Kubernetes Engine) que nos permite linkar uma service account do Kubernetes com uma service account da GCP, fazendo assim, com que os Pods que utilizem esta service account, possam fazer ações permitidas na service account da GCP.
Por exemplo, temos um microserviço que faz operações em um Bucket. Então podemos criar uma service account na GCP com permissões para fazer ações em buckets, criar uma service account no Kubernetes, linkar as duas através do Workload Identity e a aplicação será automaticamente autenticada como a service account da GCP que definirmos.
Habilitando Workload Identity
Antes de começarmos a utilizar, precisamos habilitar esta funcionalidade no cluster:
Depois, precisamos habilitar o GKE Metadata Server nos node pools que possuem os worker nodes que queremos alocar os pods que irão usar a funcionalidade de Workload Identity.
Criando service account’s
Criamos uma service account na GCP, que terá as permissões que o nosso Pod irá utilizar. Então criamos a service account do Kubernetes que será linkada com esta criada na GCP:
kubectl create sa -n <namespace> workload-identity-test
Então rodamos comandos com gcloud no terminal, primeiro conectamos ao project na GCP que a service account que criamos está, e depois adicionamos a role de workloadIdentityUser na service da GCP para conseguirmos linkar as duas:
gcloud config set project <nome_projeto>
gcloud iam service-accounts add-iam-policy-binding \
<email_da_service_account_GCP> \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:production-261711.svc.id.goog[<namespace>/workload-identity-test]"
Possíveis erros:
Falta de permissão: Precisa mudar o project default do gcloud para o que você está tentando mexer: gcloud config set project <id_do_project>
gcloud crashed: Rodar gcloud components update
para atualizar as dependências.
Linkar service accounts
Agora para linkar as duas service accounts, adicionamos uma annotation na do Kubernetes (k edit sa -n <namespace> workload-identity-test
):
apiVersion: v1
kind: ServiceAccount
metadata:
# Adiciona esta annotation
annotations:
iam.gke.io/gcp-service-account: <email_service_account_GCP>
name: workload-identity-test
namespace: <namespace>
Para pegar achar o email da service account criada na GCP, basta ir até a service account:
Hands on
Criei um código de exemplo em NodeJS que é uma API com apenas uma rota que lista os buckets quando chamada. Para isto, eu uso a SDK da Google Cloud e a autenticação é esperada através de variáveis de ambiente.
O código está no meu Github:
https://github.com/ThiagoFelippi/workload-identity-example
Para subir no kubernetes, usei o private registry do Gitlab, e os seguintes manifestos:
apiVersion: apps/v1
kind: Deployment
metadata:
name: workload-identity-example
namespace: pocs
spec:
selector:
matchLabels:
app: workload-identity-example
template:
metadata:
labels:
app: workload-identity-example
spec:
imagePullSecrets:
- name: workload-identity-example
containers:
- name: workload-identity-example
image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
imagePullPolicy: IfNotPresent
envFrom:
- configMapRef:
name: workload-identity-example
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: workload-identity-example
namespace: pocs
spec:
type: ClusterIP
selector:
app: workload-identity-example
ports:
- port: 80
targetPort: 3000
Ao subir, podemos rodar um port-forward para não precisar expor a poc através de um ingress: k port-forward svc/workload-identity-example -n pocs 3001:80
Ao acessar a rota /buckets, temos o seguinte resultado:
E podemos ver os logs do container apontando que não estamos autenticados:
Agora vamos colocar a service account que criamos para gerenciar o Deployment e ver qual o resultado. Para isto, a única coisa que muda no deployment é adicionarmos o campo serviceAccoutName dentro de spec:
...
spec:
selector:
matchLabels:
app: workload-identity-example
template:
metadata:
labels:
app: workload-identity-example
spec:
serviceAccountName: workload-identity-test
...
E ao rodar a aplicação e entrar na rota /buckets de novo, conseguimos ver os buckets sendo listados:
Conclusões
Desta forma, aumentamos a segurança das nossas aplicações, não precisando expor dados sensíveis com a aplicação. Ensinarei em outros posts como usar isto na prática, com Helm Charts, por exemplo, com Vault, ArgoCD, etc.
Caso tenha alguma dúvida, deixe um comentário ou me chame no Linkedin: https://www.linkedin.com/in/thiago-crespo-felippi/