O blog da AWS

Controle de acesso SaaS usando Amazon Verified Permissions com um armazenamento de políticas por tenant

Escrito por Manuel Heinkel, arquiteto de soluções na AWS e Alex Pulver, Principal Solutions Architect na AWS.

O controle de acesso é essencial para aplicações de software como serviço (SaaS) multitenant. Os desenvolvedores de SaaS devem gerenciar permissões, autorização refinada e isolamento.

Neste post, demonstramos como você pode usar o Amazon Verified Permissions para controle de acesso em um aplicativo SaaS de gerenciamento de documentos multitenant usando uma abordagem de armazenamento de políticas por tenant. Também descrevemos como impor o limite do tenant.

Geralmente, vemos as seguintes necessidades de controle de acesso em aplicativos SaaS multitenant:

  • Os desenvolvedores da aplicaçãos precisam definir políticas que se apliquem a todos os tenants.
  • Os usuários dos tenants precisam controlar quem pode acessar seus recursos.
  • Os administradores de tenants precisam gerenciar todos os recursos de um tenant.

Além disso, fornecedores independentes de software (ISVs) implementam o isolamento de tenants para impedir que um tenant acesse os recursos de outro tenant. Impor limites aos tenants é fundamental para empresas de SaaS e é um dos tópicos fundamentais para provedores de SaaS.

O Amazon Verified Permissions é um serviço de autorização e gerenciamento de permissões escalável e refinado que ajuda você a criar e modernizar aplicativos sem precisar implementar a lógica de autorização no código do seu aplicativo.

As permissões são descritas em políticas na linguagem Cedar. Uma política Cedar é uma declaração que define quais principals estão explicitamente autorizadas, ou explicitamente proibidos, de realizar uma ação em um determinado recurso. O conjunto de políticas define as regras de autorização para sua aplicação. O Verified Permissions armazena as políticas em um repositório de políticas. Um repositório de políticas é um contêiner para políticas e templates. Você pode aprender mais sobre as políticas do Cedar na postagem Using Open Source Cedar to Write and Enforce Custom Authorization Policies.

Antes do Verified Permissions, você precisava implementar a lógica de autorização no código da sua aplicação. Agora, mostraremos como o Verified Permissions ajuda a remover esse trabalho em uma aplicação de exemplo.

Aplicação SaaS multitenant para gerenciamento de documentos

A aplicação permite adicionar, compartilhar, acessar e gerenciar documentos. Isso requer os seguintes controles de acesso:

  • Desenvolvedores da aplicação podem definir políticas que se aplicam a todos os tenants.
  • Usuários dos tenants podem controlar quem pode acessar seus documentos.
  • Administradores de tenants podem gerenciar todos os documentos de um tenant.

Vamos começar descrevendo a arquitetura da aplicação e depois nos aprofundando nos detalhes do design.

Visão geral da arquitetura da aplicação

Há duas abordagens para o design de vários tenants no Verified Permissions: um único repositório de políticas compartilhado e um armazenamento de políticas por tenant. Você pode aprender mais sobre considerações, trade-offs e guias para essas abordagens no guia do usuário do Verified Permissions.

Para o exemplo de aplicação SaaS de gerenciamento de documentos, decidimos usar a abordagem de armazenamento de políticas por tenant pelos seguintes motivos:

  • Isolamento de políticas de tenants com baixo esforço
  • A capacidade de personalizar modelos e esquemas por tenant
  • Off-boarding de tenants com baixo esforço
  • Cotas de recursos de armazenamento de políticas por tenant

Decidimos aceitar os seguintes trade-offs:

  • Grande esforço para implementar o gerenciamento global de políticas (porque o caso de uso da aplicação não exige mudanças frequentes nessas políticas)
  • Esforço médio para implementar o fluxo de autorização (porque decidimos que, nesse contexto, os motivos acima superam a implementação de um mapeamento do ID do tenant para o ID do repositório de políticas)

A Figura 1 mostra a arquitetura da aplicação SaaS de gerenciamento de documentos. Para simplificar, omitimos o frontend e nos concentramos no back-end.

Arquitetura da aplicação SaaS de gerenciamento de documentos

Figura 1: Arquitetura da aplicação SaaS de gerenciamento de documentos

  1. Um usuário do tenant faz login em um provedor de identidade, como o Amazon Cognito. Ele recebe um JSON Web Token (JWT), que é utilizado para solicitações de API. O JWT contém declarações como o user_id, que identifica o usuário do tenant, e o tenant_id, que
    define a qual tenant o usuário pertence.
  2. O usuário do tenant faz solicitações de API com o JWT para a aplicação.
  3. O Amazon API Gateway verifica a validade do JWT com o provedor de identidade.
  4. Se o JWT for válido, o API Gateway encaminha a solicitação para processamento, neste caso a uma função do AWS Lambda, que executa a lógica de negócio.
  5. A função Lambda assume uma role do AWS Identity and Access Management (IAM) com uma política do IAM que permite acesso à tabela do Amazon DynamoDB que, por sua vez, fornece o mapeamento de tenant para o armazenamento das políticas. A política do IAM define o escopo do acesso de forma que a função Lambda só possa acessar dados do tenant_id atual.
  6. A função Lambda pesquisa no Verified Permissions com o policy_store_id da solicitação atual. Para fazer isso, ele extrai o tenant_id do JWT. Em seguida, a função recupera o policy_store_id da tabela de mapeamento do tenant para o repositório de políticas.
  7. A função Lambda assume outra role do IAM com uma política do IAM que permite acesso ao armazenamento de políticas do Verified Permissions, à tabela de metadados do documento e ao armazenamento de documentos. A política do IAM usa tenant_id e policy_store_id para granular o acesso.
  8. A função Lambda obtém ou armazena metadados de documentos em uma tabela do DynamoDB. A função usa os metadados para solicitações de autorização de permissões verificadas.
  9. Usando as informações das etapas 5 e 6, a função Lambda chama o Verified Permissions para tomar uma decisão de autorização ou criar políticas Cedar.
  10. Se autorizado, a aplicação pode então acessar ou armazenar um documento.

Aprofundamento da arquitetura da aplicação

Agora que você conhece a arquitetura dos casos de uso, vamos analisá-los com mais detalhes e retroceder, desde a experiência do usuário até a parte relacionada da arquitetura da aplicação. A arquitetura se concentra no gerenciamento de permissões. Acessar e armazenar o documento real está fora do escopo.

Defina políticas que se apliquem a todos os tenants

O desenvolvedor da aplicação deve definir políticas globais que incluam um conjunto básico de permissões de acesso para todos os tenants. Usamos as políticas do Cedar para implementar essas permissões.

Como estamos usando uma abordagem de armazenamento de políticas por tenant, o processo de onboarding de tenants deve criar essas políticas para cada novo tenant. Atualmente, para atualizar as políticas, o pipeline de implantação deve aplicar as alterações em todos os repositórios de políticas.

As seções “Adicionar um documento” e “Gerenciar todos os documentos para um tenant” a seguir incluem exemplos de políticas globais.

Certifique-se de que um tenant não possa editar as políticas de outro tenant

A aplicação usa o IAM para isolar os recursos de um tenant do outro. Como estamos usando uma abordagem de armazenamento de políticas por tenant, podemos usar o IAM para isolar um armazenamento de políticas de tenant do outro.

Arquitetura

Isolamento de tenants

Figura 2: Isolamento de tenants

  1. Um usuário do tenant chama um endpoint de API usando um JWT válido.
  2. A função Lambda usa o AWS Security Token Service (AWS STS) para assumir uma role do IAM com uma política do IAM que permite acesso à tabela do DynamoDB de mapeamento do tenant para o armazenamento de políticas. A política do IAM só permite acesso à tabela e às entradas que pertencem ao tenant solicitante. Quando a função assume a role, ela usa o tenant_id para definir o escopo do acesso aos itens cuja chave de partição corresponde ao tenant_id. Consulte a postagem de blog Como implementar o isolamento de tenants de SaaS com o ABAC e o AWS IAM para ver exemplos dessas políticas.
  3. A função Lambda usa o tenant_id do usuário para obter o policy_store_id a ser usado no Verified Permissions.
  4. A função Lambda usa o mesmo mecanismo da etapa 2 para assumir uma role diferente do IAM usando tenant_id e policy_store_id, que só permitem acesso ao armazenamento de políticas do tenant.
  5. A função Lambda acessa o repositório de políticas do tenant.

Adicionar um documento

Quando um usuário acessa a aplicação pela primeira vez, ele não possui nenhum documento. Para adicionar um documento, o frontend chama o endpoint POST /documents e fornece um document_name no corpo da solicitação.

Política Cedar

permit (    
  principal,
  action == DocumentsAPI::Action::"addDocument",
  resource
);

Essa política permite que qualquer principal adicione um documento. Como estamos usando uma abordagem de armazenamento de políticas por tenant, não há necessidade de definir o escopo do principal para um tenant.

Arquitetura

Adicionando um documento

Figura 3: Adicionando um documento

  1. Um usuário do tenant chama o endpoint POST /documents para adicionar um documento.
  2. A função Lambda usa o tenant_id do usuário para obter o policy_store_id a ser usado no Verified Permissions.
  3. A função Lambda chama o repositório de políticas do Verified Permissions para verificar se o usuário do tenant está autorizado a adicionar um documento.
  4. Após a autorização bem-sucedida, a função Lambda adiciona um novo documento ao banco de dados de metadados do documento e carrega o documento no armazenamento de documentos.

A estrutura do banco de dados é descrita na tabela a seguir:

tenant_id (chave de partição):

String

document_id (Chave de classificação):

String

document_name:

String

document_owner:

String

<TENANT_ID> <DOCUMENT_ID> <DOCUMENT_NAME> <USER_ID>
  • tenant_id: O tenant_id das declarações do JWT.
  • document_id: um identificador aleatório para o documento, criado pela aplicação.
  • document_name: o nome do documento fornecido com a solicitação da API.
  • document_owner: o usuário que criou o documento. O valor é o user_id das declarações do JWT.

Compartilhar um documento com outro usuário de um tenant

Depois que um usuário do tenant criar um ou mais documentos, talvez ele queira compartilhá-los com outros usuários do mesmo tenant. Para compartilhar um documento, o frontend chama o endpoint POST /shares e fornece o document_id do documento que o usuário deseja compartilhar e o user_id do usuário receptor.

Política Cedar

Precisamos de uma política global do proprietário do documento que permita que o proprietário do documento gerencie o documento, incluindo o compartilhamento. O processo de onboarding do tenant cria essa política no repositório de políticas do tenant.

permit (    
  principal,
  action,
  resource
) when {
  resource.owner == principal && 
  resource.type == "document"
};

A política permite que os principals executem ações nos recursos disponíveis (o documento) quando o principal é o proprietário do documento. Essa política permite que a ação ShareDocument, que descreveremos a seguir, compartilhe um documento.

Também precisamos de uma política de compartilhamento que permita que o usuário receptor acesse o documento. A aplicação cria essas políticas para cada ação de compartilhamento bem-sucedida. Recomendamos que você use templates de políticas para definir a política de compartilhamento. Os templates de política permitem que uma política seja definida uma vez e depois anexada a vários principals e recursos. As políticas que usam um template de política são chamadas de políticas vinculadas a templates. As atualizações do modelo de política são refletidas nos principals e recursos que usam o modelo. O processo de onboarding do tenant cria o template de política de compartilhamento no repositório de políticas do tenant.

Definimos o template de política de compartilhamento da seguinte forma:

permit (    
  principal == ?principal,  
  action == DocumentsAPI::Action::"accessDocument",
  resource == ?resource 
);

Veja a seguir um exemplo de uma política vinculada a um template usando o template de política de compartilhamento:

permit (    
  principal == DocumentsAPI::User::"<user_id>",
  action == DocumentsAPI::Action::"accessDocument",
  resource == DocumentsAPI::Document::"<document_id>" 
);

A política inclui o user_id do usuário receptor (principal) e o document_id do documento (recurso).

Arquitetura

Compartilhamento de um documento

Figura 4: Compartilhamento de um documento

  1. Um usuário do tenant chama o endpoint POST /shares para compartilhar um documento.
  2. A função Lambda usa o tenant_id do usuário para obter o policy_store_id a ser utilizado no Verified Permissions e os IDs do modelo de política para cada ação da tabela do DynamoDB que armazena o mapeamento do tenant no repositório de políticas. Nesse caso, a função precisa usar o share_policy_template_id.
  3. A função consulta a tabela de metadados do documento do DynamoDB para recuperar o atributo document_owner do documento que o usuário deseja compartilhar.
  4. A função Lambda chama o Verified Permissions para verificar se o usuário está autorizado a compartilhar o documento. O contexto da solicitação usa o user_id das declarações do JWT como entidade, shareDocument como ação e document_id como recurso. A entidade do documento inclui o atributo document_owner, que veio da tabela de metadados do documento do DynamoDB.
  5. Se o usuário estiver autorizado a compartilhar o recurso, a função criará uma nova política de compartilhamento vinculada ao modelo no repositório de políticas do tenant. Essa política inclui o user_id do usuário receptor como entidade e o document_id como recurso.

Acesse um documento compartilhado

Depois que um documento é compartilhado, o usuário receptor deseja acessá-lo. Para acessar o documento, o frontend chama o endpoint GET /documents e fornece o document_id do documento que o usuário deseja acessar.

Política Cedar

Conforme mostrado na seção anterior, durante o processo de compartilhamento, a aplicação cria uma política de compartilhamento vinculada a um template que permite que o usuário receptor acesse o documento. O Verified Permissions avalia essa política quando o usuário tenta acessar o documento.

Arquitetura

Acessando um documento compartilhado

Figura 5: Acessando um documento compartilhado

  1. Um usuário do tenant chama o endpoint GET /documents para acessar o documento.
  2. A função Lambda usa o tenant_id do usuário para obter o policy_store_id a ser usado no Verified Permissions.
  3. A função Lambda chama o Verified Permissions para verificar se o usuário está autorizado a acessar o documento. O contexto da solicitação usa o user_id das declarações do JWT como principal, o AccessDocument como a ação e o document_id como o recurso.

Gerencie todos os documentos de um tenant

Quando um cliente realiza o onboarding em uma aplicação SaaS, a aplicação cria o usuário administrador do tenant. O administrador do tenant deve ter permissões para realizar todas as ações em todos os documentos do tenant.

Política Cedar

Precisamos de uma política global que permita que os administradores de tenants gerenciem todos os documentos. O processo de onboarding do tenant cria essa política no repositório de políticas do tenant.

permit (    
  principal in DocumentsAPI::Group::"<admin_group_id>”,
  action,
  resource
);

Essa política permite que cada membro do grupo <admin_group_id> execute qualquer ação em qualquer documento.

Arquitetura

Gerenciando documentos

Figura 6: Gerenciando documentos

  1. O administrador tenant chama o endpoint POST /documents para gerenciar um documento.
  2. A função Lambda usa o tenant_id do usuário para obter o policy_store_id que será usado no Verified Permissions.
  3. A função Lambda chama o Verified Permissions para verificar se o usuário está autorizado a gerenciar o documento.

Conclusão

Nesta postagem, mostramos como o Amazon Verified Permissions ajuda a implementar decisões de autorização refinadas em uma aplicação SaaS multitenant. Você viu como aplicar a abordagem de armazenamento de políticas por tenant à arquitetura da aplicação. Consulte o guia do usuário do Verified Permissions para saber como escolher entre usar um repositório de políticas por tenant ou um repositório de políticas compartilhado. Para saber mais, visite a documentação e o workshop do Amazon Verified Permissions.

Sobre os Autores

Manuel Heinkel é arquiteto de soluções na AWS e trabalha com empresas de software na Alemanha para criar aplicações inovadoras e seguros na nuvem. Ele apoia os clientes na solução de desafios de negócios e na obtenção do sucesso com a AWS. Manuel tem um histórico de aprofundamento em tópicos de segurança e SaaS. Fora do trabalho, ele gosta de passar tempo com sua família e explorar as montanhas.
Alex Pulver é um Principal Solutions Architect na AWS. Ele trabalha com clientes para ajudar a projetar processos e soluções para suas necessidades comerciais. Suas áreas de interesse atuais são engenharia de produto, experiência do desenvolvedor e estratégia de plataforma. Ele é o criador do Application Design Framework, que visa alinhar negócios e tecnologia, reduzir o retrabalho e permitir a arquitetura evolutiva.

Este conteúdo foi traduzido para Português do blog original em inglês (link aqui).

Tradutor: Cesar Augusto Kuehl, arquiteto de soluções – AWS Brasil

Revisor: José Augusto Ferronato, arquiteto de soluções – AWS Brasil