Infra Operator - Arquitetura e Design
Introdução
Este documento explica a arquitetura do infra-operator, um Operator Kubernetes que provisiona recursos AWS usando o padrão de Custom Resources (CRs). O operator foi desenvolvido seguindo as melhores práticas da comunidade Kubernetes e utiliza AWS SDK Go v2 para interação direta com os serviços AWS.
Visão Geral da Arquitetura
Componentes Principais
1. Custom Resource Definitions (CRDs)
CRDs definem a estrutura dos recursos customizados que o operator gerencia.
AWSProvider CRD
Propósito: Centralizar credenciais e configurações AWS.
Campos principais:
region: Região AWS (obrigatório)roleARN: ARN do papel IAM para IRSAaccessKeyIDRef/secretAccessKeyRef: Referências a Secrets para credenciais estáticasdefaultTags: Tags aplicadas a todos os recursos
Status:
ready: Indica se as credenciais são válidasaccountID: ID da conta AWScallerIdentity: ARN da identidade autenticadaconditions: Condições de status
Arquivo: api/v1alpha1/awsprovider_types.go
S3Bucket CRD
Propósito: Gerenciar buckets S3 com configuração completa.
Campos principais:
providerRef: Referência ao AWSProviderbucketName: Nome do bucket (globalmente único)versioning: Configuração de versionamentoencryption: Configuração de criptografialifecycleRules: Regras de ciclo de vidacorsRules: Configuração CORSpublicAccessBlock: Bloqueio de acesso públicodeletionPolicy: Política de deleção (Delete, Retain, Orphan)
Status:
ready: Bucket criado e configuradoarn: ARN do bucketregion: Região onde o bucket existebucketDomainName: Nome de domínio do bucket
Arquivo: api/v1alpha1/s3bucket_types.go
2. Controllers (Reconcilers)
Controllers implementam a lógica de reconciliação - eles observam o estado desejado (spec) e o estado atual, e trabalham para convergir o estado atual ao desejado.
AWSProvider Controller
Responsabilidades:
- Validar credenciais AWS usando STS GetCallerIdentity
- Construir configuração AWS (aws.Config) baseada na spec
- Atualizar status com informações da conta
- Revalidar credenciais periodicamente (a cada 5 minutos)
Fluxo de reconciliação:
Arquivo: controllers/awsprovider_controller.go
S3Bucket Controller
Responsabilidades:
- Criar bucket S3 se não existir
- Configurar versionamento, criptografia, lifecycle, CORS, tags
- Configurar bloqueio de acesso público
- Gerenciar ciclo de vida (criação, atualização, deleção)
- Implementar finalizers para cleanup controlado
Fluxo de reconciliação:
Arquivo: controllers/s3bucket_controller.go
3. AWS Helper Package
Funções auxiliares para interação com AWS.
Funções principais:
GetAWSConfigFromProvider(): Obtém aws.Config a partir do AWSProvider CRbuildAWSConfig(): Constrói configuração AWS com credenciaisgetSecretValue(): Lê valores de Kubernetes Secrets
Arquivo: pkg/aws/provider.go
Padrões de Design Implementados
1. Reconciliation Loop
O padrão fundamental dos Operators Kubernetes. O controller observa o estado desejado (CR spec) e trabalha continuamente para fazer o estado atual convergir ao desejado.
Características:
- Idempotente: Múltiplas execuções produzem o mesmo resultado
- Edge-triggered e Level-triggered: Reage a mudanças e também verifica estado periodicamente
- Tratamento de erros: Retorna erro para requeue automático
2. Finalizers
Mecanismo para executar cleanup antes de deletar um CR.
Implementação no S3Bucket:
const s3BucketFinalizer = "aws-infra-operator.runner.codes/s3bucket-finalizer"
// Ao criar/atualizar:
if !controllerutil.ContainsFinalizer(bucket, s3BucketFinalizer) {
controllerutil.AddFinalizer(bucket, s3BucketFinalizer)
r.Update(ctx, bucket)
}
// Ao deletar:
if !bucket.ObjectMeta.DeletionTimestamp.IsZero() {
if controllerutil.ContainsFinalizer(bucket, s3BucketFinalizer) {
// Executar cleanup
r.deleteBucket(ctx, s3Client, bucket)
// Remover finalizer
controllerutil.RemoveFinalizer(bucket, s3BucketFinalizer)
r.Update(ctx, bucket)
}
}
3. Status Conditions
Seguindo o padrão Kubernetes de conditions para reportar estado.
Estrutura:
type Condition struct {
Type string // "Ready"
Status string // "True", "False", "Unknown"
LastTransitionTime metav1.Time
Reason string // "BucketReady", "CreationFailed"
Message string // Descrição detalhada
}
4. Provider Pattern
Separação de credenciais (AWSProvider) dos recursos (S3Bucket, RDS, etc).
Vantagens:
- Reutilização de credenciais entre múltiplos recursos
- Validação centralizada de autenticação
- Suporte para múltiplos providers (multi-conta, multi-região)
- Rotação de credenciais facilitada
5. Deletion Policies
Política flexível para controlar o que acontece com recursos AWS quando o CR é deletado.
Opções:
- Delete: Remove recurso AWS (padrão)
- Retain: Mantém recurso AWS, remove apenas o CR
- Orphan: Desacopla do operator mas mantém tudo
Fluxo de Dados
Criação de um S3Bucket
Autenticação IRSA
Estrutura de Arquivos
infra-operator/
│
├── api/v1alpha1/ # Definições de API (CRDs)
│ ├── groupversion_info.go # Registro do grupo de API
│ ├── awsprovider_types.go # Struct do CRD AWSProvider
│ ├── s3bucket_types.go # Struct do CRD S3Bucket
│ ├── rdsinstance_types.go # Struct do CRD RDS (controller pendente)
│ ├── ec2instance_types.go # Struct do CRD EC2 (controller pendente)
│ └── sqsqueue_types.go # Struct do CRD SQS (controller pendente)
│
├── controllers/ # Lógica de Reconciliação
│ ├── awsprovider_controller.go # Valida credenciais AWS
│ └── s3bucket_controller.go # Gerencia buckets S3
│
├── pkg/ # Bibliotecas Compartilhadas
│ └── aws/
│ └── provider.go # Funções auxiliares para config AWS
│
├── config/ # Manifestos Kubernetes
│ ├── crd/bases/ # Manifestos YAML dos CRDs
│ ├── rbac/ # RBAC (ServiceAccount, Role, Binding)
│ ├── manager/ # Deployment e Namespace
│ └── samples/ # CRs de exemplo
│
├── docs/ # Documentação
│ ├── ARCHITECTURE.md # Este arquivo
│ └── DEPLOYMENT_GUIDE.md # Guia de deployment
│
├── main.go # Ponto de entrada do operator
├── Dockerfile # Build da imagem de container
├── Makefile # Automação de build
├── go.mod # Definição do módulo Go
├── CLAUDE.md # Documentação técnica completa
└── README.md # Documentação voltada ao usuário
Decisões Arquiteturais
Por que Go SDK v2 ao invés de ACK?
Decisão: Usar AWS SDK for Go v2 diretamente.
Alternativa considerada: AWS Controllers for Kubernetes (ACK)
Razões:
-
Controle Total:
- Lógica de reconciliação customizada
- Validações específicas do negócio
- Tratamento de erros customizado
-
Simplicidade no Deployment:
- Operator único para todos os serviços
- Sem necessidade de instalar múltiplos controllers ACK
- Menor overhead de recursos
-
Aprendizado:
- Melhor entendimento dos padrões de operators
- Conhecimento profundo das APIs AWS
- Flexibilidade para implementar recursos customizados
-
Dependências:
- Menos dependências externas
- Updates de SDK mais simples
- Sem dependência do roadmap ACK
Trade-offs:
- Mais código para manter
- Necessidade de implementar recursos manualmente (paginação, retries)
- Responsabilidade de acompanhar mudanças nas APIs AWS
Por que Provider Pattern?
Decisão: Separar credenciais (AWSProvider) dos recursos (S3, RDS, etc).
Razões:
- Reuso: Um AWSProvider pode ser usado por múltiplos recursos
- Segurança: Credenciais isoladas em recurso específico
- Multi-tenancy: Diferentes namespaces podem ter diferentes providers
- Multi-conta: Suporta acesso a múltiplas contas AWS
- Rotação: Facilita rotação de credenciais
Alternativa: Credenciais diretas em cada recurso (muito repetitivo e inseguro)
Por que Deletion Policies?
Decisão: Permitir que usuários escolham o que acontece ao deletar um CR.
Razões:
- Segurança: Evitar deleção acidental de dados importantes
- Flexibilidade: Diferentes casos de uso (dev vs prod)
- Compliance: Algumas regulamentações exigem retenção de dados
- Migração: Facilita migração para outras ferramentas
Políticas implementadas:
Delete: Remove recurso AWS (padrão para ambientes efêmeros)Retain: Mantém recurso AWS (padrão para produção)Orphan: Desacopla mas mantém tudo
Concorrência e Thread Safety
Controller Runtime
Controller-runtime gerencia concorrência automaticamente:
- Work Queue: Serializa eventos de reconciliação
- Max Concurrent Reconciles: Configurável (padrão: 1)
- Retry Backoff: Backoff exponencial para erros
Estado Compartilhado
Sem estado compartilhado entre reconciliações:
- Cada reconciliação busca estado atual do Kubernetes
- Sem cache compartilhado entre reconciles
- Estado persistido apenas nos CRs
Rate Limiting
AWS SDK:
- Implementa retry automático com backoff exponencial
- Respeita limites de taxa da AWS
- Usa context.Context para timeout
Kubernetes Client:
- Rate limiting configurável
- Padrão: 5 QPS, burst 10
Performance e Escalabilidade
Otimizações Implementadas
-
Smart Requeue:
- Recursos ready: requeue a cada 5 minutos
- Recursos com erro: requeue a cada 1 minuto
- Mudanças imediatas: requeue imediato
-
Minimizar Chamadas de API:
- HeadBucket antes de GetBucket (mais barato)
- Aplicar configurações apenas se mudaram
- Batch updates quando possível
-
Status Subresource:
- Updates de status não triggam nova reconciliação
- Reduz reconciliações desnecessárias
Limites Atuais
-
Região Única por Provider: Um AWSProvider = uma região
- Workaround: Criar múltiplos AWSProviders
-
Sem Paginação: Não lista grandes quantidades de recursos
- Impacto: Limitado para operators que gerenciam recursos
-
Processamento Sequencial: Um recurso por vez
- Impacto: Escalabilidade limitada para muitos recursos
Melhorias Futuras
- Metrics: Métricas Prometheus para observabilidade
- Webhooks: Validação e defaults em admission
- Caching: Cache de informações AWS para reduzir chamadas de API
- Parallel Reconciliation: MaxConcurrentReconciles > 1
- Health Checks: Health checks detalhados para recursos AWS
Segurança
Princípios Implementados
-
Least Privilege:
- RBAC mínimo necessário
- Políticas IAM específicas por serviço
- Recursos namespaced quando possível
-
Gerenciamento de Secrets:
- Credenciais em Kubernetes Secrets
- IRSA preferido (sem credenciais de longa duração)
- Nunca logar credenciais
-
Container Security:
- Usuário não-root (UID 65532)
- Root filesystem somente-leitura
- Sem escalação privilegiada
- Imagem base distroless
-
Network Security:
- HTTPS para APIs AWS
- Validação de certificados
- Sem exposição de credenciais no status
Modelo de Ameaças
Ameaças consideradas:
- Vazamento de Credenciais: Mitigado com IRSA e Secrets
- Acesso Não Autorizado: Mitigado com RBAC
- Escalação de Privilégio: Mitigado com security context
- Ataques MITM: Mitigado com HTTPS
Observabilidade
Logging
Logging estruturado com controller-runtime:
- Contexto automático (namespace, name, kind)
- Níveis de log: info, error, debug
- Formato JSON (opcional)
Exemplo:
logger := log.FromContext(ctx)
logger.Info("Creating S3 bucket", "bucket", bucketName)
logger.Error(err, "Failed to create bucket")
Relatório de Status
Todos os CRs expõem:
status.ready: Booleano indicando se o recurso está prontostatus.conditions: Array de condições detalhadasstatus.lastSyncTime: Timestamp da última reconciliação
Health Checks
Endpoints disponíveis:
/healthz: Liveness probe/readyz: Readiness probe/metrics: Métricas Prometheus (futuro)
Estratégia de Testes
Níveis de Teste
-
Testes Unitários (futuro):
- Teste de lógica dos controllers
- Mock do AWS SDK
- Mock do cliente Kubernetes
-
Testes de Integração (futuro):
- Teste com envtest (fake API server)
- Teste de reconciliação completa
- Sem dependência real de AWS
-
Testes E2E (futuro):
- Teste em cluster real
- Teste com AWS real
- Validação de recursos criados
Metas de Cobertura de Testes
- Controllers: > 80% de cobertura
- AWS helpers: > 90% de cobertura
- E2E: Happy paths e principais casos de erro
Conclusão
O infra-operator foi arquitetado seguindo padrões estabelecidos pela comunidade Kubernetes, com foco em:
- Simplicidade: Fácil de entender e manter
- Extensibilidade: Fácil de adicionar novos recursos AWS
- Segurança: IRSA, RBAC, least privilege
- Confiabilidade: Finalizers, deletion policies, idempotência
- Observabilidade: Status conditions, logging estruturado
A arquitetura permite crescimento futuro com adição de novos serviços AWS, implementação de webhooks e melhorias de performance, mantendo uma fundação sólida e bem estruturada.