1. Objetivo
Liberar acesso ao Amazon Athena via driver ODBC (Power BI, Excel, DBeaver, qualquer coisa que fale ODBC) a partir de máquinas fora da AWS, sem criar access key e sem depender de IAM Identity Center. A máquina do usuário troca um certificado X.509 por credenciais temporárias de 1 hora através do IAM Roles Anywhere. O signing helper fica rodando em segundo plano e mantém essas credenciais sempre renovadas num profile do arquivo credentials, que é de onde o driver lê.
Resultado esperado:
- Nenhuma access key fixa existe na conta para esse acesso.
- Cada usuário tem o próprio certificado, com validade curta (o tempo do projeto).
- A role só enxerga um workgroup do Athena e os dados que precisa.
- No CloudTrail dá para saber qual certificado fez cada consulta.
- Encerrar o acesso de todo mundo é um comando.
2. Por que não access key (e por que não Identity Center)
| Opção | Problema |
|---|---|
| Usuário IAM + access key | Credencial de longa duração parada num arquivo da máquina de alguém. Vaza, ninguém percebe, ninguém rotaciona. |
| IAM Identity Center | Ótimo quando existe. Mas nem sempre dá para usar: a organização pode ser só interna, o usuário pode ser de outra empresa, e o driver precisa de fluxo de navegador configurado. |
| Cognito + federação | Funciona, mas é muita peça para um acesso que vai durar semanas. |
| IAM Roles Anywhere | Credencial temporária, validade amarrada ao certificado, sem usuário IAM. O custo é gerenciar uma CA pequena. |
Esse cenário aparece muito em projeto de dashboard: o time do cliente precisa conectar o Power BI direto no Athena durante a construção, e depois o acesso acaba. Roles Anywhere encaixa bem nisso porque o próprio certificado já carrega a data de fim.
3. Arquitetura
Maquina do usuario (Windows) +--------------------------------------------------+ | Power BI / Excel | | | | | Driver ODBC Athena 2.x (Auth: IAM Profile) | | ^ le ~/.aws/credentials [athena-odbc] | | | | | aws_signing_helper.exe update (segundo plano) | | | assina com usuario.key + usuario.pem | +------|-------------------------------------------+ | HTTPS v IAM Roles Anywhere --valida contra--> Trust anchor (CA propria) | | credenciais temporarias (1h) v Athena (workgroup dedicado) --> Glue Data Catalog --> S3 (dados) / S3 (resultados) 4. Pré-requisitos
- [ ] Dados já catalogados no Glue e consultáveis pelo Athena
- [ ] OpenSSL na máquina onde a CA vai ficar (não na máquina do usuário)
- [ ] Driver ODBC do Athena versão 2.x na máquina do usuário
- [ ] AWS CLI v2 na sua máquina
export AWS_REGION="us-east-1" export ACCOUNT_ID="<ACCOUNT_ID>" export WORKGROUP="wg-dashboards" export BUCKET_DADOS="<BUCKET_DADOS>" export BUCKET_RESULTADOS="<BUCKET_RESULTADOS_ATHENA>" export GLUE_DB="<DATABASE_GLUE>" 5. Passo 1: Workgroup dedicado
Um workgroup só para esse acesso, com local de resultado forçado e limite de bytes escaneados por consulta. O limite evita que um SELECT * sem filtro numa tabela grande vire uma fatura surpresa.
aws athena create-work-group --name "$WORKGROUP" \ --configuration "ResultConfiguration={OutputLocation=s3://${BUCKET_RESULTADOS}/${WORKGROUP}/},EnforceWorkGroupConfiguration=true,PublishCloudWatchMetricsEnabled=true,BytesScannedCutoffPerQuery=10737418240" \ --description "Acesso ODBC externo via Roles Anywhere" 10737418240 é 10 GB por consulta. Ajuste ao tamanho dos seus dados.
Com EnforceWorkGroupConfiguration=true, o usuário não consegue mandar o resultado para outro bucket, mesmo que configure isso no driver.
6. Passo 2: CA e trust anchor
6.1 CA
mkdir -p ~/ca-rolesanywhere/{private,usuarios} && cd ~/ca-rolesanywhere chmod 700 private cat > ca.cnf <<'EOF' [ req ] distinguished_name = dn prompt = no x509_extensions = ext_ca [ dn ] CN = CA Acesso Athena O = <SUA_ORG> C = BR [ ext_ca ] basicConstraints = critical, CA:true keyUsage = critical, keyCertSign, cRLSign subjectKeyIdentifier = hash EOF openssl genrsa -out private/ca.key 4096 chmod 400 private/ca.key openssl req -new -x509 -days 1825 -config ca.cnf -key private/ca.key -out ca.pem 6.2 Trust anchor
jq -n --arg pem "$(cat ca.pem)" \ '{sourceType:"CERTIFICATE_BUNDLE", sourceData:{x509CertificateData:$pem}}' > source.json TA_ARN=$(aws rolesanywhere create-trust-anchor \ --name ta-athena-odbc \ --source file://source.json \ --enabled \ --query 'trustAnchor.trustAnchorArn' --output text) echo "$TA_ARN" Se a CA tiver custo de gestão que você não quer, a alternativa é o AWS Private CA como fonte do trust anchor. Funciona sem OpenSSL na emissão, mas tem custo mensal fixo. Para acesso de poucas semanas, a CA local resolve.
7. Passo 3: Role com trust policy restrita
O Roles Anywhere transforma o subject do certificado em session tags (x509Subject/CN, x509Subject/OU etc.). Isso permite que a trust policy aceite só certificados de um OU específico, mesmo que a CA emita certificados para outros fins.
trust-ra.json:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "rolesanywhere.amazonaws.com" }, "Action": ["sts:AssumeRole", "sts:TagSession", "sts:SetSourceIdentity"], "Condition": { "ArnEquals": { "aws:SourceArn": "arn:aws:rolesanywhere:us-east-1:<ACCOUNT_ID>:trust-anchor/<TRUST_ANCHOR_ID>" }, "StringEquals": { "aws:PrincipalTag/x509Subject/OU": "athena-odbc" } } } ] } Permissões (policy-athena.json). O que mais esquecem: o PutObject no bucket de resultados e o kms:Decrypt se os dados usam SSE-KMS.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AthenaWorkgroup", "Effect": "Allow", "Action": [ "athena:StartQueryExecution", "athena:StopQueryExecution", "athena:GetQueryExecution", "athena:GetQueryResults", "athena:GetQueryResultsStream", "athena:ListQueryExecutions", "athena:GetWorkGroup" ], "Resource": "arn:aws:athena:us-east-1:<ACCOUNT_ID>:workgroup/wg-dashboards" }, { "Sid": "AthenaMetadados", "Effect": "Allow", "Action": [ "athena:ListWorkGroups", "athena:ListDataCatalogs", "athena:GetDataCatalog", "athena:ListDatabases", "athena:GetDatabase", "athena:ListTableMetadata", "athena:GetTableMetadata" ], "Resource": "*" }, { "Sid": "Glue", "Effect": "Allow", "Action": [ "glue:GetDatabase", "glue:GetDatabases", "glue:GetTable", "glue:GetTables", "glue:GetPartition", "glue:GetPartitions", "glue:BatchGetPartition" ], "Resource": [ "arn:aws:glue:us-east-1:<ACCOUNT_ID>:catalog", "arn:aws:glue:us-east-1:<ACCOUNT_ID>:database/<DATABASE_GLUE>", "arn:aws:glue:us-east-1:<ACCOUNT_ID>:table/<DATABASE_GLUE>/*" ] }, { "Sid": "LeituraDados", "Effect": "Allow", "Action": ["s3:GetObject", "s3:ListBucket", "s3:GetBucketLocation"], "Resource": [ "arn:aws:s3:::<BUCKET_DADOS>", "arn:aws:s3:::<BUCKET_DADOS>/*" ] }, { "Sid": "Resultados", "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject", "s3:ListBucket", "s3:GetBucketLocation", "s3:AbortMultipartUpload", "s3:ListMultipartUploadParts" ], "Resource": [ "arn:aws:s3:::<BUCKET_RESULTADOS_ATHENA>", "arn:aws:s3:::<BUCKET_RESULTADOS_ATHENA>/wg-dashboards/*" ] } ] } Se os dados estão sob Lake Formation, a parte de S3 de dados sai e entra lakeformation:GetDataAccess mais o grant da role na tabela pelo Lake Formation. Sem o grant, o erro é Insufficient Lake Formation permission(s), mesmo com a policy IAM certa.
aws iam create-role --role-name ra-athena-odbc \ --assume-role-policy-document file://trust-ra.json \ --max-session-duration 3600 aws iam put-role-policy --role-name ra-athena-odbc \ --policy-name athena-wg-dashboards \ --policy-document file://policy-athena.json 8. Passo 4: Profile do Roles Anywhere
ROLE_ARN="arn:aws:iam::${ACCOUNT_ID}:role/ra-athena-odbc" PROFILE_ARN=$(aws rolesanywhere create-profile \ --name prof-athena-odbc \ --role-arns "$ROLE_ARN" \ --duration-seconds 3600 \ --enabled \ --query 'profile.profileArn' --output text) echo "$PROFILE_ARN" O profile também aceita --managed-policy-arns e --session-policy, que funcionam como teto em cima da role. Útil se a mesma role atende mais de um perfil de uso.
9. Passo 5: Emitir o certificado do usuário
A validade do certificado é o prazo do acesso. Projeto de 45 dias, certificado de 45 dias.
#!/usr/bin/env bash set -euo pipefail USUARIO="$1" # ex.: analista-01 DIAS="${2:-45}" cd ~/ca-rolesanywhere cat > "usuarios/${USUARIO}.ext" <<'EOF' basicConstraints = critical, CA:false keyUsage = critical, digitalSignature subjectKeyIdentifier = hash authorityKeyIdentifier = keyid EOF openssl genrsa -out "usuarios/${USUARIO}.key" 2048 openssl req -new -key "usuarios/${USUARIO}.key" \ -subj "/CN=${USUARIO}/OU=athena-odbc/O=<SUA_ORG>/C=BR" \ -out "usuarios/${USUARIO}.csr" openssl x509 -req -in "usuarios/${USUARIO}.csr" \ -CA ca.pem -CAkey private/ca.key -CAcreateserial \ -days "$DIAS" -sha256 -extfile "usuarios/${USUARIO}.ext" \ -out "usuarios/${USUARIO}.pem" rm -f "usuarios/${USUARIO}.csr" "usuarios/${USUARIO}.ext" openssl x509 -in "usuarios/${USUARIO}.pem" -noout -subject -serial -enddate Guarde numa planilha a relação serial, usuário, data de fim. O serial é o que aparece no CloudTrail.
O OU=athena-odbc é o que a trust policy do passo 3 exige. Certificado sem esse OU não assume a role, mesmo vindo da mesma CA.
10. Passo 6: Configurar a máquina do usuário (Windows)
10.1 Signing helper
Baixe o aws_signing_helper.exe da página de documentação do Roles Anywhere (seção "Obtaining temporary security credentials") e coloque em C:\aws\. Coloque o .pem e o .key em C:\aws\certs\ e restrinja a pasta ao próprio usuário:
New-Item -ItemType Directory -Force C:\aws\certs | Out-Null icacls C:\aws\certs /inheritance:r /grant:r "$($env:USERNAME):(OI)(CI)F" Teste o helper sozinho antes de mexer no ODBC. Se isso não devolver JSON com AccessKeyId, nada depois vai funcionar:
C:\aws\aws_signing_helper.exe credential-process ` --certificate C:\aws\certs\analista-01.pem ` --private-key C:\aws\certs\analista-01.key ` --trust-anchor-arn <TRUST_ANCHOR_ARN> ` --profile-arn <PROFILE_ARN> ` --role-arn <ROLE_ARN> 10.2 Manter as credenciais renovadas no credentials
Por que não credential_process no config: é o caminho mais comum com AWS CLI e SDKs, mas a documentação do IAM Profile do driver ODBC 2.x só cita credential_source (Ec2InstanceMetadata, EcsContainer, Environment) e plugin_name. Não dá para contar com credential_process ali. O que o driver garante é ler o profile do arquivo credentials e, nas versões mais novas, recarregar quando o arquivo muda.
Então o helper roda no modo update: ele escreve credenciais temporárias no profile athena-odbc do %USERPROFILE%\.aws\credentials e reescreve antes de expirar.
%USERPROFILE%\.aws\config:
[profile athena-odbc] region = us-east-1 Script C:\aws\athena-cred.ps1:
& C:\aws\aws_signing_helper.exe update ` --profile athena-odbc ` --certificate C:\aws\certs\analista-01.pem ` --private-key C:\aws\certs\analista-01.key ` --trust-anchor-arn <TRUST_ANCHOR_ARN> ` --profile-arn <PROFILE_ARN> ` --role-arn <ROLE_ARN> Para não depender de alguém lembrar de abrir, registre como tarefa agendada no logon do usuário:
$acao = New-ScheduledTaskAction -Execute "powershell.exe" ` -Argument "-NoProfile -WindowStyle Hidden -File C:\aws\athena-cred.ps1" $gatilho = New-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME Register-ScheduledTask -TaskName "athena-roles-anywhere" -Action $acao -Trigger $gatilho Start-ScheduledTask -TaskName "athena-roles-anywhere" Confira que o profile apareceu no %USERPROFILE%\.aws\credentials com aws_access_key_id, aws_secret_access_key e aws_session_token. Essas chaves são temporárias e valem 1 hora; o helper troca sozinho.
Se a máquina tiver AWS CLI:
aws sts get-caller-identity --profile athena-odbc O Arn volta como assumed-role/ra-athena-odbc/<SERIAL>.
Chave privada fora de arquivo. O signing helper também lê do repositório de certificados do Windows com
--cert-selector, no lugar de--certificatee--private-key. Se importar o.pfxmarcando a chave como não exportável, o arquivo.keydeixa de existir no disco. Vale para acesso mais longo. Para um acesso de semanas, a pasta com ACL resolve.
10.3 DSN ODBC
Abra o ODBC Data Sources (64-bit) (Power BI Desktop é 64 bits; usar o de 32 é o erro número um aqui) e crie um System DSN com o driver Amazon Athena ODBC (x64):
| Campo | Valor |
|---|---|
| Data Source Name | Athena-Dashboards |
| Region | us-east-1 |
| Catalog | AwsDataCatalog |
| Database | <DATABASE_GLUE> |
| Workgroup | wg-dashboards |
| S3 Output Location | em branco (o workgroup força) |
| Authentication Type | IAM Profile |
| AWS Profile | athena-odbc |
Clique em Test. Se der certo, no Power BI use Obter dados → ODBC → Athena-Dashboards.
Gateway on-premises do Power BI. O gateway roda como serviço (
PBIEgwService), não como o usuário logado. Ele não lê o%USERPROFILE%\.awsde ninguém. Nesse caso aponte oupdatepara um arquivo fixo com a variávelAWS_SHARED_CREDENTIALS_FILE=C:\aws\credentials(no ambiente da tarefa agendada e como variável de sistema), faça o mesmo comAWS_CONFIG_FILE=C:\aws\config, dê leitura na pasta para a conta do serviço e reinicie o gateway. Esse detalhe consome uma tarde se ninguém avisar.
11. Passo 7: Rastrear quem consultou o quê
Por padrão, o nome da sessão é o serial do certificado. No CloudTrail:
aws cloudtrail lookup-events \ --lookup-attributes AttributeKey=EventName,AttributeValue=StartQueryExecution \ --max-results 20 \ --query 'Events[].CloudTrailEvent' --output text \ | jq -r 'select(.userIdentity.arn | contains("ra-athena-odbc")) | [.eventTime, .userIdentity.arn, .sourceIPAddress] | @tsv' Cruzando o serial com a planilha do passo 5, você tem usuário, horário e IP de origem. O texto da consulta fica no histórico do workgroup (aws athena list-query-executions --work-group wg-dashboards).
Para ver o consumo do workgroup:
aws cloudwatch get-metric-statistics --namespace AWS/Athena \ --metric-name ProcessedBytes --dimensions Name=WorkGroup,Value=wg-dashboards \ --start-time "$(date -u -d '-7 days' +%FT%TZ)" --end-time "$(date -u +%FT%TZ)" \ --period 86400 --statistics Sum 12. Passo 8: Encerrar o acesso
Tem três níveis, do mais pontual ao mais amplo:
Um usuário só, antes do certificado vencer: gere uma CRL com o serial dele e importe no Roles Anywhere. Como a CA do passo 2 é simples (sem o banco do openssl ca), monte um índice mínimo só para gerar a CRL:
cd ~/ca-rolesanywhere SERIAL=$(openssl x509 -in usuarios/analista-01.pem -noout -serial | cut -d= -f2) REVOGADO_EM=$(date -u +%y%m%d%H%M%SZ) VENCE_EM=$(openssl x509 -in usuarios/analista-01.pem -noout -enddate | cut -d= -f2 \ | xargs -I{} date -u -d "{}" +%y%m%d%H%M%SZ) mkdir -p crl && touch crl/index.txt && echo 1000 > crl/crlnumber printf 'R\t%s\t%s\t%s\tunknown\t/CN=analista-01\n' "$VENCE_EM" "$REVOGADO_EM" "$SERIAL" >> crl/index.txt cat > crl.cnf <<'EOF' [ ca ] default_ca = ca_crl [ ca_crl ] database = crl/index.txt crlnumber = crl/crlnumber default_md = sha256 default_crl_days = 30 EOF openssl ca -config crl.cnf -gencrl -keyfile private/ca.key -cert ca.pem -out crl.pem openssl crl -in crl.pem -noout -text | grep -A1 "Serial Number" aws rolesanywhere import-crl --name crl-athena-odbc \ --trust-anchor-arn "$TA_ARN" \ --crl-data fileb://crl.pem --enabled Todo mundo, temporariamente:
aws rolesanywhere disable-profile --profile-id <PROFILE_ID> Fim do projeto:
aws rolesanywhere delete-profile --profile-id <PROFILE_ID> aws rolesanywhere delete-trust-anchor --trust-anchor-id <TRUST_ANCHOR_ID> aws iam delete-role-policy --role-name ra-athena-odbc --policy-name athena-wg-dashboards aws iam delete-role --role-name ra-athena-odbc Credenciais já emitidas continuam válidas até expirar (no máximo 1 hora, pela configuração do profile). Se precisar cortar na hora, use Revoke active sessions na role pelo console, que adiciona uma deny por aws:TokenIssueTime.
13. Troubleshooting
| Sintoma | Causa provável | Ação |
|---|---|---|
Helper retorna AccessDeniedException | OU do certificado não bate com a trust policy, ou trust anchor errado no ARN | openssl x509 -noout -subject e conferir aws:SourceArn |
| Helper retorna erro de assinatura | .pem e .key não são par | Comparar openssl x509 -noout -modulus e openssl rsa -noout -modulus |
| DSN testa ok, Power BI não lista tabelas | Falta glue:GetTables ou grant no Lake Formation | Policy do passo 3 |
Access denied when writing output | Falta PutObject no prefixo do workgroup | Policy de resultados |
| Funciona no Desktop, falha no gateway | Gateway roda como serviço | AWS_SHARED_CREDENTIALS_FILE e AWS_CONFIG_FILE de sistema |
| Funciona e para de funcionar depois de 1 hora | Helper update não está rodando | Tarefa agendada e Get-ScheduledTask athena-roles-anywhere |
Query exhausted resources ou corte por bytes | Limite do workgroup | Partições no filtro ou aumentar o limite |
| Driver não acha o profile | DSN de 32 bits ou profile com nome diferente | ODBC 64-bit, [profile athena-odbc] |
14. Referências
- IAM Roles Anywhere: https://docs.aws.amazon.com/rolesanywhere/latest/userguide/introduction.html
- Signing helper: https://docs.aws.amazon.com/rolesanywhere/latest/userguide/credential-helper.html
- Mapeamento de atributos do certificado: https://docs.aws.amazon.com/rolesanywhere/latest/userguide/attribute-mapping.html
- Athena ODBC 2.x, autenticação: https://docs.aws.amazon.com/athena/latest/ug/odbc-v2-driver-authentication-options.html
- Controle de custo por workgroup: https://docs.aws.amazon.com/athena/latest/ug/workgroups-setting-control-limits-cloudwatch.html