<h2>Introdução ao Secrets Manager e KMS na AWS</h2>
<p>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.</p>
<h2>Fundamentos: Secrets Manager vs Variáveis de Ambiente</h2>
<h3>Por que não usar variáveis de ambiente simples?</h3>
<p>A maioria dos desenvolvedores inicia armazenando credenciais em arquivos <code>.env</code> 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.</p>
<h3>Arquitetura básica</h3>
<p>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.</p>
<h2>Implementação Prática: Armazenando e Recuperando Segredos</h2>
<h3>Criando um segredo com Boto3</h3>
<pre><code class="language-python">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']}")</code></pre>
<h3>Recuperando o segredo na aplicação</h3>
<pre><code class="language-python">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'
)</code></pre>
<h3>Rotação automática de senhas</h3>
<p>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:</p>
<pre><code class="language-python">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}</code></pre>
<h2>KMS: Controle Fino de Criptografia</h2>
<h3>Políticas de chave para acesso mínimo</h3>
<p>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:</p>
<pre><code class="language-json">{
"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"
}
}
}</code></pre>
<h3>Auditoria com CloudTrail</h3>
<p>Todo acesso ao KMS é registrado no CloudTrail. Configure alertas para descriptografias anormais usando CloudWatch:</p>
<pre><code class="language-python">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']
)</code></pre>
<h2>Conclusão</h2>
<p>Aprendemos que <strong>Secrets Manager centraliza o armazenamento de credenciais com rotação automática</strong>, eliminando segredos em código. <strong>KMS fornece criptografia com controle granular</strong>, garantindo que apenas as aplicações certas acessem os segredos corretos. Por fim, <strong>auditoria através do CloudTrail transforma segurança reativa em proativa</strong>, detectando acessos anormais antes que se tornem incidentes. Implementar essa arquitetura desde o início economiza resgates de segurança no futuro.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://docs.aws.amazon.com/secretsmanager/" target="_blank" rel="noopener noreferrer">AWS Secrets Manager Documentation</a></li>
<li><a href="https://docs.aws.amazon.com/kms/latest/developerguide/best-practices.html" target="_blank" rel="noopener noreferrer">AWS KMS Best Practices</a></li>
<li><a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/secretsmanager.html" target="_blank" rel="noopener noreferrer">Boto3 SecretsManager API Reference</a></li>
<li><a href="https://docs.aws.amazon.com/security/" target="_blank" rel="noopener noreferrer">AWS Security Best Practices Guide</a></li>
<li><a href="https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" target="_blank" rel="noopener noreferrer">OWASP Secrets Management Cheat Sheet</a></li>
</ul>