HomeArtigo
Yggdrasil: Escalando a Autorização no iFood com Cedar e uma Arquitetura Stateless
SEGURANÇA20 fev.

Yggdrasil: Escalando a Autorização no iFood com Cedar e uma Arquitetura Stateless

Em um ecossistema de microsserviços tão dinâmico e complexo como o do iFood, garantir que as pessoas e os sistemas tenham o acesso adequado aos recursos corretos é um desafio constante. Historicamente, na maioria dos casos, a lógica de autorização é implementada de forma descentralizada e inconsistente dentro de cada aplicação, tornando-se uma fonte de vulnerabilidades de segurança, débitos técnicos e dificuldades de auditoria. Para endereçar esses desafios, o time de Tecnologia do iFood desenvolveu o Yggdrasil, nossa plataforma de authorization-as-a-service.

O Yggdrasil centraliza e padroniza o controle de acesso, tornando a autorização mais escalável, auditável e reutilizável em toda a companhia. Inspirado no AWS Verified Permissions, um serviço de autorização totalmente gerenciado que permite armazenar, gerenciar e avaliar permissões de acesso granulares, o Yggdrasil utiliza a mesma linguagem de política open source, o AWS Cedar, para definir políticas. Porém, o Yggdrasil oferece integração nativa com o ecossistema do iFood, dando suporte a diversos provedores de identidade, auditoria e observabilidade.

Neste artigo, vamos explorar os conceitos por trás do Yggdrasil, desde o modelo de controle de acesso baseado em atributos, conhecido como ABAC, até a escolha por uma arquitetura stateless com Cedar, mas principalmente como essa plataforma está transformando a maneira como lidamos com autorização no iFood.

O que é ABAC (Attribute-Based Access Control)?

É comum que muitos sistemas de autorização utilizem o modelo RBAC (Role-Based Access Control), na qual as permissões são concedidas com base em papéis predefinidos, como “administrador” ou “visualizador”. Embora simples de entender, o RBAC pode se tornar rígido e levar a uma explosão de papéis à medida que as regras de negócio se tornam mais complexas.

O Yggdrasil adota uma abordagem mais flexível e granular: o ABAC (Attribute-Based Access Control). Em vez de papéis estáticos, o ABAC toma decisões de acesso com base em atributos. Esses atributos podem ser associados a qualquer elemento da requisição:

  • Principal: Atributos do usuário ou sistema que solicita o acesso (ex: cargo, time, localização);
  • Recurso: Atributos do objeto que está sendo acessado (ex: tipo de documento, tag de privacidade, centro de custo);
  • Ação: A operação que o principal deseja realizar (ex: ler, escrever, apagar);
  • Contexto: Atributos do ambiente no momento da requisição (ex: horário, endereço de IP);

Essa flexibilidade permite a criação de políticas de acesso muito mais ricas e dinâmicas, que refletem com mais fidelidade as regras de negócio. Por exemplo, uma política ABAC poderia expressar uma regra como: “Permitir que gerentes do time de finanças aprovem despesas acima de R$5.000, somente durante o horário comercial”.

Stateful vs. Stateless: A escolha pelo Cedar

Uma das decisões arquiteturais mais importantes ao desenhar uma plataforma de autorização é optar por uma abordagem stateful (com estado) ou stateless (sem estado). A principal diferença entre elas é origem dos atributos das entidades (perfis do usuário, tags do recurso, dados do ambiente): no modelo stateful, a maioria desses atributos é armazenado pela plataforma de autorização, enquanto no modelo stateless essa responsabilidade é da aplicação cliente, que envia os atributos na chamada feita para o Yggdrasil.

Soluções stateful, como o Zanzibar do Google, mantém um banco de dados massivo e centralizado com todos os relacionamentos de acesso (ex: “usuário X é membro do grupo Y”) e diversos outros atributos. Essa abordagem é poderosa, mas introduz uma complexidade operacional significativa, exigindo ingestão de dados assíncrona, manutenção de ETLs e um potencial ponto único de falha.

O Yggdrasil optou por uma abordagem stateless com o AWS Cedar. O Cedar é uma linguagem e um motor de políticas de autorização open source que não depende de um estado centralizado. Em vez disso, a aplicação que solicita a autorização envia todos os dados relevantes, ou seja, as entidades e seus atributos, como parte da requisição. O motor do Cedar então avalia as políticas com base nesses dados para tomar uma decisão.

Essa arquitetura nos oferece um modelo operacional muito mais simples e resiliente, perfeitamente alinhado com a natureza distribuída dos nossos microsserviços.

Uma política em Cedar: exemplo prático

A linguagem Cedar é projetada para ser segura, rápida e fácil de aprender. Uma política em Cedar possui três itens principais: o efeito (permit ou forbid), o escopo (principal, ação e recurso) e as condições (cláusulas when e unless).

Vamos imaginar uma política para um sistema de gerenciamento de documentos. A regra é: “Permitir que qualquer usuário que pertença ao grupo ‘Auditores’ possa visualizar um documento, desde que o documento não seja privado.”

Em Cedar, essa política seria escrita da seguinte forma:

@id("auditor_leitura")
@cacheTTL("20m")
permit (
  principal in Group::"Auditores",
  action == Action::"visualizar",
  resource
)
when { !resource.private };
  • @id e @cacheTTL: anotações da política, elas adicionam metadados a decisão final. A anotação id é obrigatória no Yggdrasil.
  • permit: O efeito da política é de permissão.
  • principal in Group::”Auditores”: O escopo do principal define que ele deve ser membro do grupo Auditores.
  • action == Action::”visualizar”: A ação deve ser visualizar.
  • resource: O escopo do recurso é aberto, aplicando-se a qualquer recurso.
  • when { !resource.private }: A condição exige que o atributo private do recurso seja falso.

O Cedar opera com um princípio de deny-by-default. Se nenhuma política permit corresponder explicitamente à requisição, o acesso é negado. Isso torna o sistema inerentemente mais seguro e previsível.

Policy Store: a unidade básica de autorização

Uma Policy Store é, essencialmente, um contêiner que agrupa um conjunto de políticas e configurações associadas a um serviço ou domínio específico. Cada requisição de autorização ao Yggdrasil deve especificar qual policy store utilizar, e não qual política.

Essa abordagem traz duas vantagens cruciais:

  • Governança: visto que não é preciso alterar um cliente para habilitar ou desabilitar políticas, o onbording de atualizações é mais simples e garantimos que políticas de forbid serão sempre executadas.
  • Performance: Ao isolar as políticas por domínio, o motor de autorização só precisa avaliar um subconjunto relevante de regras, em vez de varrer todas as políticas existentes na organização.
  • Segurança e Isolamento: Isolar as políticas evita que uma regra de um time interfira acidentalmente no comportamento de outra. Como o Cedar é deny-by-default, garantir que apenas as políticas relevantes sejam avaliadas previne que uma política de permissão de outro contexto conceda acesso indevido.

Arquitetura do Yggdrasil

Para atender aos requisitos de alta performance e confiabilidade exigidos por um ambiente como o do iFood, o Yggdrasil foi projetado com uma arquitetura distribuída e resiliente. Em vez de um serviço centralizado que poderia se tornar um gargalo ou um ponto único de falha, o motor de autorização do Yggdrasil é distribuído e executado próximo às aplicações que o consomem.

Diagrama da arquitetura distribuída do Yggdrasil

Detalhes da arquitetura do Yggdrasil

  • Autorizador Local: Cada conta ou cluster que hospeda aplicações clientes possui sua própria instância do yggdrasil-authorizer. Isso garante baixa latência, pois a comunicação entre a aplicação e o autorizador ocorre localmente, sem a necessidade de chamadas de rede para fora do cluster.
  • Policy Stores em S3: As políticas de Cedar não são armazenadas dentro do autorizador. Em vez disso, elas são mantidas em um bucket S3 centralizado, que atua como a fonte da verdade. As instâncias locais do Yggdrasil atualizam periodicamente (a cada minuto) suas cópias locais das políticas a partir deste bucket, garantindo alta disponibilidade e consistência eventual.
  • Cache de Decisões: Cada autorizador utiliza um cache (Redis) para armazenar decisões de autorização já computadas. Isso melhora drasticamente a performance para requisições repetidas, um cenário comum em sistemas de alto volume.
  • Provedores de Identidade (OIDC): Quando uma requisição envolve a validação de um token de identidade (através da chamada IsAuthorizedWithToken), o Yggdrasil se comunica com os provedores de identidade configurados (como o Keycloak) para validar o token e extrair os claims (como papéis e outros atributos do principal) necessários para a avaliação da política.

Como o Yggdrasil Torna a Autorização Melhor

Ao adotar o Cedar e uma arquitetura de serviço centralizado, o Yggdrasil traz benefícios tangíveis em três áreas principais:

Escalabilidade

  • Motor Performático: O Cedar utiliza verificação formal, uma técnica de análise matemática, para garantir propriedades como a terminação. Isso prova que nenhuma política pode entrar em um loop infinito, assegurando que a avaliação seja sempre rápida e previsível.
  • Estratégias de Cache: O Yggdrasil implementa um cache de decisões de autorização. Uma vez que uma decisão de ALLOW é tomada, ela pode ser armazenada em cache por um tempo determinado (usando a anotação @cacheTTL na política), reduzindo drasticamente a latência para requisições idênticas subsequentes.

Auditabilidade

  • Logs de Auditoria: Todas as decisões de autorização (tanto permitidas quanto negadas) são registradas, criando uma trilha de auditoria completa e centralizada. Isso é fundamental para investigações de segurança, conformidade e para entender como os acessos estão sendo concedidos na prática.
  • Policy as Code: As políticas do Yggdrasil são gerenciadas como código em um repositório Git. Isso significa que toda alteração em uma política passa por um processo de revisão por pares (Merge Request), com versionamento e histórico. A validação das políticas é feita durante o pipeline de CI/CD, garantindo que apenas políticas sintaticamente corretas e seguras sejam implantadas em produção.

Reutilização

  • Compartilhamento de Conhecimento: Ao centralizar as políticas, criamos um repositório de conhecimento institucional. Times podem aprender com as políticas criadas por outros, evitando reinventar a roda e disseminando boas práticas de segurança em toda a organização.
  • Validação de Boas Práticas: O pipeline de validação não apenas verifica a sintaxe, mas também pode ser estendido para impor regras de negócio e boas práticas de segurança, garantindo um padrão de qualidade elevado e consistente.

Conclusão

O Yggdrasil representa um passo fundamental na maturidade da arquitetura de segurança do iFood. Ao externalizar e centralizar a autorização, estamos não apenas mitigando riscos de segurança, mas também empoderando nossos times de desenvolvimento para que possam focar no que fazem de melhor: criar produtos incríveis para nossos clientes, parceiros e entregadores.

A jornada está apenas começando. Temos planos para evoluir o Yggdrasil, adicionando mais fontes de identidade, refinando nossas ferramentas de desenvolvimento e explorando novos padrões de políticas. Acreditamos que, ao tratar a autorização como um serviço de primeira classe, estamos construindo uma base mais segura, escalável e resiliente para o futuro do iFood.

Compartilhe:
Caio Cavalcante

Caio Cavalcante

Security Engineer

Engenheiro de software e segurança no iFood. Gosta de ler, viajar e jogar jogos de tabuleiro.

Ir para a página do autor

Construa o futuro no iFood

Estamos sempre em busca de desenvolvedores, designers e cientistas de dados apaixonados para nos ajudar a revolucionar a experiência de entrega de alimentos. Junte-se à iFood Tech e faça parte da construção do futuro da tecnologia alimentar.

Conheça nossas CarreirasArrow Right