Segurança em GitOps: Soluções para Armazenamento de Segredos

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:

  1. Verifica se já existe um par de chaves RSA no cluster
  2. Se não existir, gera um novo par e o armazena em um Secret no namespace do controlador
  3. O kubeseal utiliza a chave pública para criptografar os Secrets
  4. 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:

  1. 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 -
  2. Verifique os logs do controlador: kubectl logs -l app.kubernetes.io/name=sealed-secrets -n kube-system
  3. Analise o Secret criado: kubectl get secret meusegredo -o yaml
  4. Adicione a anotação sealedsecrets.bitnami.com/managed: "true" ao Secret e reaplique
  5. 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.

Tags: GitOps kubernetes ArgoCD sealed-secrets Secret-Management

Publicado em 9-28 05:30