Por que Você Precisa de uma Camada de Busca Dedicada para Cognito
O Amazon Cognito é excelente para autenticação e gerenciamento básico de usuários. Mas quando sua equipe de suporte precisa encontrar um usuário com apenas parte do e-mail, um sobrenome e um nível de acesso específico entre milhares de contas, a API ListUsers padrão não dá conta.
O problema? A API do Cognito só suporta correspondência exata em atributos padrão e a paginação fica lenta em escala. Para cenários avançados — como busca fuzzy em atributos personalizados, segmentação em tempo real por grupos ou auditoria — você precisa de uma camada de busca dedicada.
Este guia mostra como construir uma arquitetura orientada a eventos que sincroniza automaticamente os dados de usuários do Cognito para o OpenSearch Serverless via DynamoDB Streams, garantindo buscas em milissegundos em qualquer escala.

Arquitetura: Dois Fluxos de Ingestão + Um Fluxo de Busca
A solução usa três serviços AWS em um pipeline serverless:
- Amazon DynamoDB como armazenamento de perfis
- AWS Lambda para transformação e ingestão de dados
- Amazon OpenSearch Serverless como índice de busca
Fluxo de Ingestão 1: Triggers do Cognito Lambda
Captura dados do usuário durante eventos de autenticação (cadastro e login).
# Trigger pós-confirmação do Cognito (Python)
import json
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('UserProfiles')
def lambda_handler(event, context):
# Extrai atributos do usuário do evento Cognito
user_attrs = event['request']['userAttributes']
user_id = event['userName']
# Cria registro inicial no DynamoDB
item = {
'userId': user_id,
'email': user_attrs.get('email', ''),
'name': user_attrs.get('name', ''),
'groups': [], # preenchido depois no trigger de geração de token
'lastLogin': None,
'createdAt': event['request']['userAttributes'].get('created_at', '')
}
table.put_item(Item=item)
return event
Fluxo de Ingestão 2: CloudTrail para Ações Administrativas
Ações administrativas (criar usuários via CLI, por exemplo) não disparam os triggers do Cognito. O CloudTrail + EventBridge preenche essa lacuna.
# Lambda consumidora de eventos CloudTrail (Python)
import json
import boto3
from datetime import datetime
cognito = boto3.client('cognito-idp')
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('UserProfiles')
def lambda_handler(event, context):
# Analisa evento CloudTrail para API admin do Cognito
detail = event['detail']
if detail['eventSource'] != 'cognito-idp.amazonaws.com':
return
user_pool_id = detail['requestParameters']['userPoolId']
username = detail['requestParameters']['username']
# Busca estado atual do usuário no Cognito
response = cognito.admin_get_user(
UserPoolId=user_pool_id,
Username=username
)
# Upsert no DynamoDB
item = {
'userId': username,
'email': next((a['Value'] for a in response['UserAttributes'] if a['Name'] == 'email'), ''),
'name': next((a['Value'] for a in response['UserAttributes'] if a['Name'] == 'name'), ''),
'lastModified': datetime.utcnow().isoformat()
}
table.put_item(Item=item)
return event
Fluxo de Busca: Consultando o Índice
# Lambda de busca (Python)
import json
import boto3
from opensearchpy import OpenSearch, RequestsHttpConnection
from requests_aws4auth import AWS4Auth
host = 'seu-endpoint-do-domínio-opensearch'
region = 'us-east-1'
service = 'aoss'
credentials = boto3.Session().get_credentials()
awsauth = AWS4Auth(credentials.access_key, credentials.secret_key,
region, service, session_token=credentials.token)
client = OpenSearch(
hosts=[{'host': host, 'port': 443}],
http_auth=awsauth,
use_ssl=True,
verify_certs=True,
connection_class=RequestsHttpConnection
)
def lambda_handler(event, context):
# Extrai parâmetros de busca do evento API Gateway
query = event.get('queryStringParameters', {})
search_term = query.get('q', '')
field = query.get('field', 'email') # padrão: e-mail
# Monta consulta OpenSearch com busca fuzzy
search_body = {
'query': {
'multi_match': {
'query': search_term,
'fields': [field, 'name^2', 'groups'],
'fuzziness': 'AUTO',
'operator': 'and'
}
},
'size': query.get('size', 20)
}
response = client.search(index='cognito-users', body=search_body)
# Formata resultados
results = []
for hit in response['hits']['hits']:
results.append(hit['_source'])
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps({'results': results, 'total': response['hits']['total']['value']})
}

Pontos de Atenção e Cuidados Essenciais
1. Timeout dos Triggers do Cognito
O Cognito impõe um limite de 5 segundos para funções trigger. Se você já tem outra lógica nesses triggers (claims personalizados, analytics), garanta que o tempo total de execução fique bem abaixo desse limite. Considere usar concorrência provisionada para evitar cold starts.
2. Consistência de Dados
Eventos do CloudTrail são entregues pelo menos uma vez, mas podem chegar fora de ordem. Use escritas condicionais no DynamoDB com um campo de versão para evitar que dados antigos sobrescrevam registros novos.
3. Custos do OpenSearch
O OpenSearch Serverless cobra por OCU (OpenSearch Capacity Units). Para volumes altos de escrita, considere fazer batch dos eventos do DynamoDB Streams para reduzir escritas no índice.
4. Segurança
- Use o Cognito Authorizer no API Gateway para validar tokens JWT antes de executar a busca.
- A Lambda de busca deve assumir uma role IAM somente leitura para o OpenSearch.
- Criptografe os dados do usuário em repouso tanto no DynamoDB quanto no OpenSearch.
Próximos Passos
- Implante o stack completo usando o repositório AWS CDK — ele inclui um frontend React e toda a infraestrutura.
- Integre com agentes de IA: Combine esta camada de busca com o Amazon Bedrock para criar um assistente conversacional de diretório de usuários. Para uma visão mais ampla sobre estratégias de dados unificados, veja este guia de migração de Oracle para PostgreSQL no Azure.
- Monitore a performance: Use métricas do CloudWatch para latência da Lambda, capacidade de leitura/escrita do DynamoDB e latência de consulta do OpenSearch para ajustar sua arquitetura.

Conclusão
Combinando triggers do Cognito Lambda, DynamoDB Streams e OpenSearch Serverless, você pode construir uma camada de busca de usuários em tempo real, escalável, que suporta busca fuzzy, filtros complexos e respostas em milissegundos — sem jobs manuais ou código de indexação personalizado.
Esse padrão permite que sua equipe de suporte encontre usuários em milhares de contas instantaneamente, que administradores segmentem usuários por grupo para campanhas direcionadas, e que times de compliance auditem atributos com filtros complexos.
Para um mergulho mais profundo em como as tendências de banco de dados estão evoluindo para dados unificados e agentes de IA, confira a análise sobre a visão de banco de dados da Microsoft para 2026.