Pular para o conteúdo

Escopos e permissões

Credenciais por connector diz quais chaves criar. Esta página diz com que permissões criá-las.

São duas credenciais com naturezas diferentes: a API key não tem escopos, e a Application key tem.

Escopo Habilita Obrigatório?
nenhum metrics.* O Datadog não expõe um escopo de leitura de métricas: uma app key padrão já lê métricas.
logs_read_data + logs_read_index_data logs.* Se você usa logs
apm_read traces.*, topology.* (Software Catalog) Se você usa APM
monitors_read monitors.* Sempre (ver abaixo)
incident_read incidentes Se você usa incidentes
rum_apps_read rum.* Se você usa RUM
synthetics_read synthetics.* Se o Datadog serve synthetics
api_keys_read a higiene de chaves (security) Opcional, e sensível

Sem escopos. É usada apenas em /api/v1/validate, no health check.

Não é permissão, mas erra junto: se a sua organização é EU ou US3/US5/AP1, uma key válida responde 403 contra o site errado. Confira antes de investigar escopo.

Escopos de Access Policy. Só os dois primeiros são obrigatórios.

Escopo Habilita Obrigatório?
metrics:read Mimir: metrics.*, service graph, métricas de Faro e Synthetics Sim
logs:read Loki: logs.* Não; degrada op a op
traces:read Tempo: traces.* Não; degrada op a op
alerts:read + rules:read Alerting: monitors.* Não
stacks:read + stack-dashboards:read busca de dashboards no stack Não
Synthetic Monitoring synthetics.* via /api/v1/check/list Nome do escopo a confirmar na sua conta

O Mimir é o único obrigatório porque é a espinha: sem ele o connector não tem o que servir. Os demais degradam com erro acionável, não com falha de boot.

Uma policy IAM de leitura, servida como arquivo para você não precisar copiar da tela:

Terminal window
curl -O https://docs.rootpilot.sh/aws/rootpilot-edge-readonly.json
aws iam create-policy \
--policy-name RootPilotEdgeReadOnly \
--policy-document file://rootpilot-edge-readonly.json

Ela cobre o catálogo inteiro. Se você não usa uma capability, remova o Statement correspondente antes de criar. Os Sid existem para isso: cada um é um domínio removível.

O arquivo é o canônico; o bloco abaixo é a mesma coisa, e uma verificação no build falha se os dois divergirem.

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "IdentidadeEContexto",
"Effect": "Allow",
"Action": [
"sts:GetCallerIdentity",
"organizations:DescribeOrganization",
"organizations:ListAccounts"
],
"Resource": "*"
},
{
"Sid": "CustoEFinOps",
"Effect": "Allow",
"Action": [
"ce:GetCostAndUsage",
"ce:GetAnomalies",
"ce:GetReservationCoverage",
"ce:GetReservationPurchaseRecommendation",
"ce:GetSavingsPlansCoverage",
"ce:GetSavingsPlansPurchaseRecommendation",
"compute-optimizer:GetEnrollmentStatus",
"compute-optimizer:GetEC2InstanceRecommendations",
"compute-optimizer:GetEBSVolumeRecommendations",
"compute-optimizer:GetLambdaFunctionRecommendations",
"compute-optimizer:GetAutoScalingGroupRecommendations",
"compute-optimizer:GetRDSDatabaseRecommendations"
],
"Resource": "*"
},
{
"Sid": "Compute",
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeAddresses",
"ec2:DescribeNetworkInterfaces",
"ec2:DescribeSecurityGroups",
"ec2:DescribeSubnets",
"ec2:DescribeVpcs",
"ec2:DescribeVpcEndpoints",
"ec2:DescribeVpcPeeringConnections",
"ec2:DescribeRouteTables",
"ec2:DescribeInternetGateways",
"ec2:DescribeNatGateways",
"ec2:DescribeCustomerGateways",
"ec2:DescribeVpnConnections",
"ec2:DescribeVpnGateways",
"ec2:DescribeTransitGateways",
"ec2:DescribeTransitGatewayAttachments",
"ec2:DescribeManagedPrefixLists",
"ecs:ListClusters",
"eks:ListClusters",
"eks:DescribeCluster",
"eks:ListNodegroups",
"eks:DescribeNodegroup",
"ecr:DescribeRepositories",
"ecr:DescribeImages",
"lambda:ListFunctions",
"lambda:GetFunctionConfiguration",
"lambda:ListEventSourceMappings"
],
"Resource": "*"
},
{
"Sid": "BancosDeDados",
"Effect": "Allow",
"Action": [
"rds:DescribeDBInstances",
"rds:DescribeDBClusters",
"rds:DescribeDBSubnetGroups",
"rds:ListTagsForResource",
"dms:DescribeReplicationInstances",
"dms:DescribeReplicationTasks",
"es:ListDomainNames",
"es:DescribeDomains",
"elasticache:DescribeCacheClusters",
"elasticache:DescribeReplicationGroups",
"pi:DescribeDimensionKeys",
"pi:GetResourceMetrics"
],
"Resource": "*"
},
{
"Sid": "Rede",
"Effect": "Allow",
"Action": [
"elasticloadbalancing:DescribeLoadBalancers",
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:DescribeInstanceHealth",
"elasticloadbalancing:DescribeTags",
"route53:ListHostedZones",
"route53:GetHostedZone",
"route53:ListResourceRecordSets",
"sqs:ListQueues",
"sqs:GetQueueUrl",
"sqs:GetQueueAttributes"
],
"Resource": "*"
},
{
"Sid": "Observabilidade",
"Effect": "Allow",
"Action": [
"cloudwatch:GetMetricData",
"cloudwatch:DescribeAlarms",
"logs:DescribeLogGroups",
"logs:FilterLogEvents",
"logs:StartQuery",
"logs:GetQueryResults",
"application-signals:ListServices",
"application-signals:ListServiceLevelObjectives",
"application-signals:BatchGetServiceLevelObjectiveBudgetReport"
],
"Resource": "*"
},
{
"Sid": "AuditoriaEConsulta",
"Effect": "Allow",
"Action": [
"cloudtrail:LookupEvents",
"cloudtrail:ListEventDataStores",
"cloudtrail:StartQuery",
"cloudtrail:DescribeQuery",
"cloudtrail:GetQueryResults",
"athena:StartQueryExecution",
"athena:StopQueryExecution",
"athena:GetQueryExecution",
"athena:BatchGetQueryExecution",
"athena:GetQueryResults",
"athena:ListQueryExecutions"
],
"Resource": "*"
},
{
"Sid": "SegurancaIamSomenteLeitura",
"Effect": "Allow",
"Action": ["iam:ListUsers", "iam:ListAccessKeys", "iam:GetAccessKeyLastUsed"],
"Resource": "*"
}
]
}

1. athena:StartQueryExecution e cloudtrail:StartQuery parecem escrita, e não são. É assim que se roda uma consulta de leitura nesses serviços: a ação cria uma execução, não altera dado. O handler valida o SQL antes: DDL e DML são rejeitados. Se a sua revisão de segurança barrar Start* por reflexo, é esse o argumento.

2. Athena precisa de S3, e não está acima. Os resultados vão para um bucket, e sem s3:GetObject/s3:PutObject/s3:ListBucket no bucket de resultados a consulta falha. Dependendo do seu catálogo, também glue:GetTable/GetDatabase/GetPartitions. Ficou de fora de propósito: o ARN é seu, e um curinga aqui seria pior que uma omissão explícita.

3. DocumentDB usa o namespace rds:. Não existe docdb:, e procurar por ele sem achar leva a conceder demais.

4. Três prefixos não batem com o nome do serviço: CloudWatch Logs é logs:, Cost Explorer é ce:, OpenSearch é es:.

5. Nada de embed do QuickSight. O connector tem código para GenerateEmbedUrlFor* e GetDashboardEmbedUrl, mas essas quatro ops foram deferidas por postura e não estão no catálogo: o enforcement as recusa antes de chegar ao connector. Conceder essas permissões seria privilégio que nada consegue exercer. Se você usa a capability bi, adicione só as ações quicksight:Describe*, List* e Search*.

Para quê Como Permissão
Ler as suas fontes RUNNER_AWS_CRED_MODE: static (chaves) ou chain (IRSA, instance profile) A policy acima
Ler os seus segredos RUNNER_SECRET_STORE_MODE=aws secretsmanager:GetSecretValue, escopado ao prefixo dos seus segredos

A segunda deve ser apertada ao ARN, não *:

{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:REGIAO:CONTA:secret:rootpilot/*"
}

O sso:GetRoleCredentials e sso:ListAccountRoles que aparecem no código são do caminho de desenvolvimento com aws sso login. Não conceda em produção.

Aqui a permissão tem duas camadas, e conceder só a primeira é o erro mais comum.

Camada 1, IAM: eks:DescribeCluster (já na policy acima), para descobrir endpoint e CA do cluster.

Camada 2, RBAC dentro do cluster. O connector gera um token no estilo aws eks get-token e fala com o API server. Uma identidade IAM sem binding no cluster recebe 401/403 do Kubernetes, não da AWS, e o erro não menciona IAM, o que manda a investigação para o lado errado.

O connector lê apenas isto:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: rootpilot-read
rules:
- apiGroups: [""]
resources: ["pods", "services", "endpoints"]
verbs: ["get", "list"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list"]

Ligue-o à identidade IAM do runner com uma EKS access entry (ou uma entrada no aws-auth, em clusters mais antigos) e um ClusterRoleBinding.

Sem EKS_CLUSTER no ambiente, o health check responde skipped: no cluster configured, que não é erro de permissão, mas se parece com um.

Papéis no projeto. O roles/viewer cobre a maior parte; estes são os que costumam faltar:

Papel Habilita
roles/viewer Compute, GKE, Cloud SQL, Run, Functions, DNS, Artifact Registry, Firestore, Redis
roles/monitoring.viewer metrics.*
roles/logging.viewer logs.*
roles/cloudasset.viewer inventário de assets
roles/recommender.viewer recomendações
roles/securitycenter.findingsViewer security.*
roles/billing.viewer no billing account custo. Note que é no billing account, não no projeto
roles/bigquery.dataViewer + roles/bigquery.jobUser ler o GCP_BILLING_EXPORT_TABLE
roles/iam.securityReviewer leitura de IAM

O custo é o que mais dá trabalho: precisa do papel no billing account e de acesso BigQuery à tabela de export. Sem GCP_BILLING_EXPORT_TABLE, a op falha de forma explícita.

Com RUNNER_GCP_CRED_MODE=chain, esses papéis vão na GSA de Workload Identity e nenhuma chave circula.

Token fine-grained (recomendado):

Permissão Nível Para quê
Metadata Read Obrigatória. Base de todas as outras
Contents Read Commits, conteúdo, refs, tags, comparação, busca de código
Pull requests Read PRs, arquivos de PR, PRs associados a um commit
Actions Read Runs de workflow
Checks Read Checks de um ref
Administration Read Apenas proteção de branch (ver abaixo)
Dependabot alerts Read Alertas de segurança

Token clássico, se preferir: repo + read:org + security_events.

Nenhuma dessas permissões é de escrita. O connector não tem uma única chamada mutante. Veja Modelo de segurança.

Escopos de bot token:

Escopo Para quê
channels:read, groups:read listar conversas
channels:history, groups:history ler histórico
chat:write chat.postMessage, op de escrita
channels:manage chat.createChannel, op de escrita
Plataforma O que a credencial precisa Notas
Checkly Leitura de checks e resultados (/checks, /check-results/{id}) CHECKLY_ACCOUNT_ID é obrigatório na prática para token de usuário; sem ele, 401 sem explicação
Vercel Leitura de deployments e projetos (/v6/deployments, /v9/projects) Token read-only escopado ao time; VERCEL_TEAM_ID obrigatório para token de time, senão 403 mudo
Amplitude Chave de API + secret com acesso às APIs de Dashboard/Export Cobre /events/segmentation, /funnels, /dashboards, /charts. Leitura
SonarQube Token de usuário com Browse nos projetos analisados /api/issues/search, /api/measures/component, /api/qualitygates/project_status, /api/hotspots/search
Jira Browse projects, mais Create issues, Add comments e Transition issues As três únicas escritas de ticket do catálogo. Sem elas, só leitura funciona
Cloudflare Zone:Read + DNS:Read Escope às zonas necessárias, não à conta inteira
Azion Token com leitura de workspace (applications, connectors, workloads) e das APIs GraphQL de métricas e eventos Os POST do connector são transporte de query GraphQL, não mutations
MongoDB Usuário com read nos bancos consultados O MONGO_URI embute a credencial; use usuário dedicado somente-leitura

Antes de uma auditoria, confira contra a árvore em vez de confiar na página:

Terminal window
# Comandos AWS efetivamente usados, agrupados por serviço
grep -rhoE "\bnew [A-Z][A-Za-z0-9]+Command\b" packages/connectors/src | sort -u
# Endpoints REST de um connector
grep -ohE "'/[a-zA-Z0-9/_.{}-]+'" packages/connectors/src/sonarqube.ts | sort -u
# O que está de fato exposto (o enforcement recusa o resto)
grep -oE "'[a-z]+\.[a-zA-Z]+'" apps/runner/src/connectors/manifests/real.ts | sort -u

A última linha é a que importa para menor privilégio: permissão para uma op que não está no catálogo é privilégio que nada consegue exercer. Foi assim que os embed do QuickSight saíram desta página.