Em ambientes GitOps, o repositório Git serve como a única fonte confiável para a configuração do sistema, incluindo objetos Kubernetes e informações sensíveis. Esta abordagem exige atenção especial à segurança, especialmente quando o repositório contém dados confidenciais como:
- Credenciais para acesso a registros de imagens Docker
- Informações de conexão com bancos de dados externos
- Dados de acesso a middleware como filas de mensagens
- Chaves de API de serviços terceirizados, incluindo provedores de nuvem
Neste artigo, exploraremos métodos para criptografar informações sensíveis no repositório Git, elevando o nível de segurança do seu fluxo GitOps. Antes de começar, certifique-se de ter o ArgoCD instalado em um cluster Kind local e clone o repositório de exemplo para seu próprio Git.
2. Estratégias de Gerenciamento de Segredos em GitOps
No ecossistema GitOps, três soluções se destacam para o gerenciamento de segredos:
- Sealed-Secrets: Oferece excelente usabilidade e alta atividade na comunidade, integrando-se naturalmente com fluxos GitOps.
- External-Secrets: Requer serviços externos de gerenciamento de chaves como AWS Secrets Manager, Google Secrets Manager ou Azure Key Vault.
- Vault: Ferramenta de gerenciamento de segredos da HashiCorp que exige configuração adicional e plugins para integração com ArgoCD.
Focaremos em Sealed-Secrets devido à sua simplicidade e integração direta. Esta solução utiliza algoritmos de criptografia assimétrica para proteger objetos Secret, permitindo armazenamento seguro no Git enquanto mantém a capacidade de descriptografia automática dentro do cluster.
3. Instalação do Sealed-Secrets
A integração do Sealed-Secrets com GitOps envolve dois componentes: uma ferramenta CLI local e um controlador executando no cluster.
3.1 Instalação da Ferramenta CLI kubeseal
A ferramenta kubeseal permite interagir com o serviço Sealed-Secrets e criptografar informações sensíveis. Para instalação no MacOS:
$ brew install kubeseal
Para sistemas Linux ou Windows, baixe o executável diretamente:
wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.19.5/kubeseal-0.19.5-linux-amd64.tar.gz
tar zxvf kubeseal-0.19.5-linux-amd64.tar.gz
chmod 755 kubeseal
mv kubeseal /usr/local/bin/
3.2 Instalação do Controlador
O controlador Sealed-Secrets é responsável pela descriptografia das informações e geração de objetos Secret nativos do Kubernetes. Recomendamos a instalação via Helm:
$ helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
$ helm install sealed-secrets -n kube-system --set-string fullnameOverride=sealed-secrets-controller sealed-secrets/sealed-secrets
$ kubectl wait deployment -n kube-system sealed-secrets-controller --for condition=Available=True --timeout=300s
4. Exemplo Prático de Aplicação
Para demonstrar o uso do Sealed-Secrets, criamos um Deployment que utiliza dois tipos de segredos: credenciais para pull de imagens e um Secret Kubernetes para variáveis de ambiente:
apiVersion: apps/v1
kind: Deployment
metadata:
name: aplicacao-exemplo
spec:
......
spec:
imagePullSecrets:
- name: registry-credentials
containers:
- name: aplicacao-exemplo
image: ghcr.io/usuario/aplicacao-exemplo:latest
ports:
- containerPort: 8080
name: http
env:
- name: SENHA_APLICACAO
valueFrom:
secretKeyRef:
key: password
name: segredo-aplicacao
A imagem de exemplo está em um registro privado no GitHub Packages (ghcr.io), exigindo credenciais para acesso. O Deployment também referencia um Secret chamado segredo-aplicacao para injetar uma variável de ambiente.
4.1 Configuração da Aplicação ArgoCD
Para integrar o Sealed-Secrets com GitOps, primeiro configure uma aplicação ArgoCD. Após clonar o repositório de exemplo e enviá-lo para seu Git, modifique o arquivo sealed-secret/application.yaml:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: demo-spring
spec:
project: default
source:
# Substitua pela URL do seu repositório Git
repoURL: https://github.com/seu-usuario/exemplo-kubernetes.git
Aplique a configuração no cluster:
$ cd sealed-secret
$ kubectl apply -f application.yaml
No console ArgoCD, você verá a aplicação, mas os Pods falharão com ImagePullBackOff devido à ausência das credenciais de registro.
4.2 Criação de Segredos Criptografados
Vamos criptografar os dois tipos de segredos necessários para nossa aplicação.
4.2.1 Credencial para Registro de Imagens
O arquivo sealed-secret/image-pull-secret.yaml contém o Secret original:
kind: Secret
type: kubernetes.io/dockerconfigjson
apiVersion: v1
metadata:
name: registry-credentials
data:
.dockerconfigjson: eyJhdXRocyI6eyJnaGNyLmlvIjp7InVzZXJuYW1lIjoibXl1c2VyIiwicGFzc3dvcmQiOiJnaHBfN3FrVkZhY1Y5Z3djRUVNUmNWd2VxTGdHT1Z1V081M3J1T2x2IiwiYXV0aCI6ImJIbDZhR0Z1WnpFNU9UazZaMmh3WHpkeGExWkdZV05XT1dkM1kwVkZVVkpqVm5kbGNVeG5SMDlXZHZUE05UTnlkVTlzZGc9PSJ9fX0=
Criptografe este Secret usando o kubeseal:
kubeseal -f image-pull-secret.yaml -w manifest/image-pull-sealed-secret.yaml --scope cluster-wide
O comando gera um objeto SealedSecret no arquivo manifest/image-pull-sealed-secret.yaml:
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
annotations:
sealedsecrets.bitnami.com/cluster-wide: "true"
creationTimestamp: null
name: registry-credentials
spec:
encryptedData:
.dockerconfigjson: AgBgEUOxC1i2AuZJ2LzPiSfYblycy71NGv1SapA46ugFlWyKRaUg+WQGDHr6W6m+/8mBPvDuKh40xrszBEeaN212qNbbyb87tb1fZ8v9g7DmcsYp5I3VBSQ+9sljoXlf8XmTyGnohl6ZV5i79muSzhmJhNJAofOGVX4O52RvGjP8P9LvLYS7rlV/Nv49F5tnJqaEtZbYlxpQ5WggFFyOZ+LSaR/wkS0anOW/k6ZU/KHWijnvBKl/YRBbXsPHnyJpkFmGhN8hvZkaUZYpRZ+mbkdYMPw6HAgUMiyMWnbbzRBheJmiFafKV9RRfqfZoTaHubLIXdpFRrHdRS6SojYUuJFrVTM9xXRdpadC9T0cRCwvKGGGRVbNosOWhPtB2DkwzptQOL+6KMAlBHFrOKdkVULKVveJV269X85NcQDH40ZZMuCTMPIItC8hs6pqOheQ0SvaYrVri1GkEXovUYbNArhnUPnUuUf/zMTbQ5sYOGb20ST1HbBJqiTvIn54N22tg0ANhTaRSuQoW7yxd7ZGno2xNiyoIYk/6r7m3rRUtmBXR8+VD1bmuandH+Bpb4rnYDmZUSEFuhXm/d/szgoaE+s6b/RHhml7WsaPXQEmOInaoe3WvwZvTa9htLKJq2XzHkPMHa5H4vPZ4+1MyM13o1R8GLYuwI5gFqsyDfnLRQ2bXMbAwiSFkhQ947RpXHmG0Y29opLeNnjDt93gGFfo20wIYwl5YhOALpV3K5vKL1gAmRq1urAtDGSnCZkrMQKbEtQUKPJrzgmftAanzScKyVrFkQ8lG7CBv9xt42acvYJL0gIyVUKdXFay6qN4/GyYx4lQvLYOAMctkafluI2EZQweasetM8g2js+uAUJn1+WtUqtE2Tljd+avc7sJwWpEZfpW2BpcXAOGC4pLxLVKjm8EKLTru4vi5TOF0bfOvZJGBnEFuZQMYpme
template:
metadata:
annotations:
sealedsecrets.bitnami.com/cluster-wide: "true"
creationTimestamp: null
name: registry-credentials
type: kubernetes.io/dockerconfigjson
4.2.2 Secret para Variáveis de Ambiente
O arquivo sealed-secret/sample-secret.yaml contém o Secret para variáveis de ambiente:
apiVersion: v1
kind: Secret
metadata:
name: segredo-aplicacao
data:
password: YWRtaW4K
Criptografe este Secret:
kubeseal -f sample-secret.yaml -w manifest/sample-sealed-secret.yaml --scope cluster-wide
4.3 Envio para o Repositório Git
Envie os segredos criptografados para seu repositório Git:
git add .
git commit -a -m 'Adicionando segredos criptografados'
git push origin main
No console ArgoCD, sincronize a aplicação clicando no botão "SYNC". O controlador Sealed-Secrets descriptografará os objetos SealedSecret e criará os Secrets correspondentes. A aplicação deve atingir o estado Healthy, com os Pods em execução.
4.4 Verificação dos Segredos
Para verificar se a variável de ambiente foi injetada corretamente, faça o port forwarding:
kubectl port-forward svc/aplicacao-exemplo 8081:8080 -n demo-secret
Em outro terminal, acesse o endpoint da aplicação:
$ curl http://localhost:8081/actuator/env/SENHA_APLICACAO
{"property":{"source":"systemEnvironment","value":"******"},"activeProfiles":[],"propertySources":[{"name":"server.ports"},{"name":"servletConfigInitParams"},{"name":"servletContextInitParams"},{"name":"systemProperties"},{"name":"systemEnvironment","property":{"value":"******","origin":"System Environment Property \"SENHA_APLICACAO\""}},{"name":"random"},{"name":"Config resource 'class path resource [application.yml]' via location 'optional:classpath:/'"},{"name":"Management Server"}]}
A resposta confirma que a variável de ambiente foi corretamente injetada a partir do Secret descriptografado.
5. Funcionamento do Sealed-Secrets
O Sealed-Secrets utiliza criptografia assimétrica para proteger os segredos. Quando o controlador é instalado, ele:
- Verifica se já existe um par de chaves RSA no cluster
- Se não existir, gera um novo par e o armazena em um Secret no namespace do controlador
- O kubeseal utiliza a chave pública para criptografar os Secrets
- O controlador usa a chave privada para descriptografar os SealedSecrets
Para visualizar o par de chaves:
$ kubectl get secret -n kube-system | grep sealed-secrets
$ kubectl get secret sealed-secrets-keyxxxxx -n kube-system -o yaml
6. Recomendações para Produção
Em ambientes de produção, é crucial fazer backup do par de chaves RSA. Se as chaves forem perdidas, os SealedSecrets existentes não poderão ser descriptografados.
Para backup:
kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml > backup-sealed-secret-rsa.yaml
Para restaurar em um novo cluster:
kubectl apply -f backup-sealed-secret-rsa.yaml
helm install sealed-secrets -n kube-system --set-string fullnameOverride=sealed-secrets-controller sealed-secrets/sealed-secrets
O controlador utilizará as chaves existentes em vez de gerar novas.
7. Conclusão
O Sealed-Secrets oferece uma solução elegante para gerenciar segredos em ambientes GitOps, permitindo armazenamento seguro no repositório Git enquento mantém a automação do fluxo. A ferramenta consiste em um componente CLI para criptografia e um controlador no cluster para descriptografia.
Em cenários com requisitos de segurança mais rigorosos ou integração com serviços de nuvem específicos, considere alternativas como External-Secrets. Para a maioria dos casos de uso, porém, o Sealed-Secrets oferece um equilíbrio ideal entre segurança e simplicidade operacional.
8. Exercício Prático
Para consolidar o conhecimento, tente o seguinte exercício:
- Crie um Secret diretamente no cluster:
echo -n admin | kubectl create secret generic meusegredo --dry-run=client --from-file=password=/dev/stdin -o yaml | kubectl apply -f - - Verifique os logs do controlador:
kubectl logs -l app.kubernetes.io/name=sealed-secrets -n kube-system - Analise o Secret criado:
kubectl get secret meusegredo -o yaml - Adicione a anotação
sealedsecrets.bitnami.com/managed: "true"ao Secret e reaplique - Observe se o comportamento do controlador muda após a anotação
Este exercício demonstra como o Sealed-Secrets interage com Secrets existentes no cluster.