Introdução ao Secrets Manager e KMS na AWS
Gerenciar segredos em aplicações modernas é uma tarefa crítica que frequentemente é negligenciada. Credenciais de banco de dados, chaves de API e tokens de autenticação comprometem toda a segurança da sua aplicação se vazados. O AWS Secrets Manager resolve esse problema fornecendo armazenamento centralizado e rotação automática de segredos, enquanto o KMS (Key Management Service) oferece criptografia de ponta a ponta. Neste artigo, aprenderemos como integrar essas duas ferramentas em projetos reais, eliminando a prática perigosa de armazenar credenciais em código ou arquivos de configuração.
Fundamentos: Secrets Manager vs Variáveis de Ambiente
Por que não usar variáveis de ambiente simples?
A maioria dos desenvolvedores inicia armazenando credenciais em arquivos .env ou variáveis de ambiente. Isso funciona localmente, mas é um risco em produção: logs podem expor valores, repositórios Git podem conter histórico, e não há rotação automática. O Secrets Manager resolve isso oferecendo um vault seguro com auditoria integrada, rotação automática de senhas e integração nativa com serviços AWS.
Arquitetura básica
O KMS criptografa cada segredo armazenado no Secrets Manager usando chaves gerenciadas. Você define políticas de acesso granulares: apenas sua aplicação pode descriptografar o segredo específico que precisa. Essa separação entre o que está armazenado (Secrets Manager) e como é protegido (KMS) fornece defesa em profundidade.
Implementação Prática: Armazenando e Recuperando Segredos
Criando um segredo com Boto3
import boto3
import json
# Cliente do Secrets Manager
client = boto3.client('secretsmanager', region_name='us-east-1')
# Criar um novo segredo
secret_data = {
'username': 'admin_user',
'password': 'SuperSecurePassword123!',
'host': 'db.example.com'
}
response = client.create_secret(
Name='prod/database/credentials',
Description='Credenciais do banco de dados PostgreSQL',
SecretString=json.dumps(secret_data),
KmsKeyId='arn:aws:kms:us-east-1:123456789:key/12345678-1234-1234-1234-123456789012'
)
print(f"Segredo criado: {response['ARN']}")
Recuperando o segredo na aplicação
import boto3
import json
from functools import lru_cache
class SecretsManager:
def __init__(self):
self.client = boto3.client('secretsmanager', region_name='us-east-1')
self._cache = {}
@lru_cache(maxsize=10)
def get_secret(self, secret_name):
"""Recupera e cacheia o segredo por 1 hora em produção"""
try:
response = self.client.get_secret_value(SecretId=secret_name)
if 'SecretString' in response:
return json.loads(response['SecretString'])
else:
return response['SecretBinary']
except self.client.exceptions.ResourceNotFoundException:
raise ValueError(f"Segredo '{secret_name}' não encontrado")
except Exception as e:
raise RuntimeError(f"Erro ao recuperar segredo: {str(e)}")
# Uso na aplicação
secrets_manager = SecretsManager()
db_creds = secrets_manager.get_secret('prod/database/credentials')
# Conectar ao banco de dados com as credenciais
db_connection = psycopg2.connect(
host=db_creds['host'],
user=db_creds['username'],
password=db_creds['password'],
database='production'
)
Rotação automática de senhas
O Secrets Manager pode rotacionar automaticamente senhas do RDS sem intervenção manual. Configure uma função Lambda que altera a senha no banco de dados:
import boto3
import pymysql
import json
secrets_client = boto3.client('secretsmanager')
def lambda_handler(event, context):
secret_id = event['SecretId']
token = event['ClientRequestToken']
step = event['Step']
# Recuperar o segredo atual
secret_response = secrets_client.get_secret_value(SecretId=secret_id)
current_secret = json.loads(secret_response['SecretString'])
if step == 'createSecret':
# Gerar nova senha
new_password = secrets_client.get_random_password(
PasswordLength=32,
ExcludeCharacters='/@"\'\\;'
)['RandomPassword']
# Armazenar nova versão pendente
secrets_client.put_secret_value(
SecretId=secret_id,
ClientRequestToken=token,
SecretString=json.dumps({
**current_secret,
'password': new_password
}),
VersionStages=['AWSPENDING']
)
elif step == 'setSecret':
# Aplicar nova senha no banco de dados
connection = pymysql.connect(
host=current_secret['host'],
user=current_secret['username'],
password=current_secret['password'],
database='mysql'
)
cursor = connection.cursor()
new_creds = json.loads(
secrets_client.get_secret_value(
SecretId=secret_id,
VersionId=token,
VersionStage='AWSPENDING'
)['SecretString']
)
cursor.execute(
f"ALTER USER '{new_creds['username']}'@'%' IDENTIFIED BY '{new_creds['password']}'"
)
connection.commit()
cursor.close()
connection.close()
elif step == 'finishSecret':
# Marcar versão como AWSCURRENT
secrets_client.update_secret_version_stage(
SecretId=secret_id,
VersionStage='AWSCURRENT',
MoveToVersionId=token,
RemoveFromVersionId=secret_response['VersionId']
)
return {'statusCode': 200}
KMS: Controle Fino de Criptografia
Políticas de chave para acesso mínimo
O KMS oferece criptografia gerenciada, mas o poder real está nas políticas. Uma aplicação EC2 só deve conseguir usar a chave KMS necessária, não todas:
{
"Sid": "AllowEC2ToDecryptDatabaseSecrets",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/EC2-ApplicationRole"
},
"Action": [
"kms:Decrypt",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": "secretsmanager.us-east-1.amazonaws.com"
}
}
}
Auditoria com CloudTrail
Todo acesso ao KMS é registrado no CloudTrail. Configure alertas para descriptografias anormais usando CloudWatch:
import boto3
cloudwatch = boto3.client('cloudwatch')
cloudwatch.put_metric_alarm(
AlarmName='UnusualKMSDecryptions',
MetricName='UserErrorCount',
Namespace='AWS/KMS',
Statistic='Sum',
Period=300,
EvaluationPeriods=1,
Threshold=10,
ComparisonOperator='GreaterThanThreshold',
AlarmActions=['arn:aws:sns:us-east-1:123456789012:SecurityAlerts']
)
Conclusão
Aprendemos que Secrets Manager centraliza o armazenamento de credenciais com rotação automática, eliminando segredos em código. KMS fornece criptografia com controle granular, garantindo que apenas as aplicações certas acessem os segredos corretos. Por fim, auditoria através do CloudTrail transforma segurança reativa em proativa, detectando acessos anormais antes que se tornem incidentes. Implementar essa arquitetura desde o início economiza resgates de segurança no futuro.