Kiểm soát quyền truy cập dịch vụ SaaS bằng cách sử dụng Amazon Verified Permissions với per-tenant policy store

Tác giả Manuel Heinkel và Alex Pulver |  ngày 13 tháng 2 năm 2024 || trong Advanced (300), Amazon Verified Permissions, Best Practices, SaaS, Security, Identity, & Compliance, Technical How-to | Permalink |  Comments |  Share

Kiểm soát quyền truy cập là điều cần thiết đối với các ứng dụng dạng Software As A Service (SaaS) đa khách hàng. Các nhà phát triển SaaS phải quản lý quyền, phân quyền chi tiết và cô lập(isolation).

Trong bài viết này, chúng tôi sẽ trình bày cách bạn có thể sử dụng Amazon Verified Permissions để kiểm soát quyền truy cập trong một ứng dụng multi-tenant document management SaaS bằng cách sử dụng phương pháp per-tenant policy store. Chúng tôi cũng đề cập đến việc cách thực thi ranh giới các khách hàng.

Chúng tôi thường thấy có các nhu cầu kiểm soát truy cập sau đây trong các ứng dụng multi-tenant SaaS:

  • Các nhà phát triển ứng dụng cần xác định các policy áp dụng cho tất cả khách hàng.
  • Khách hàng cần kiểm soát ai có thể truy cập tài nguyên của họ.
  • Quản trị viên của khách hàng cần quản lý tất cả tài nguyên cho mỗi khách hàng.

Thêm vào đó, các nhà cung cấp phần mềm độc lập (ISV) thực thi tenant isolation để ngăn một khách hàng truy cập vào tài nguyên của khách hàng khác. Việc phân ranh giới khách hàng là điều bắt buộc đối với các doanh nghiệp SaaS và là một trong những chủ đề nền tảng đối với các nhà cung cấp SaaS.

Verified Permissions là một dịch vụ quản lý quyền và phân quyền chi tiết, có thể mở rộng, giúp bạn xây dựng và hiện đại hóa các ứng dụng mà không cần phải triển khai logic phân quyền trong mã nguồn của ứng dụng bạn.

Verified Permissions sử dụng ngôn ngữ Cedar để xác định các policies . Một Cedar policy  là một tuyên bố xác định những nguyên tắc nào được phép tường minh hoặc bị cấm  để thực hiện một hành động trên một tài nguyên. Tập hợp các policies xác định các quy tắc phân quyền cho ứng dụng của bạn. Verified Permissions lưu trữ các policies trong policy store. Mỗi policy store là một container chứa các policies và templates. Bạn có thể tìm hiểu thêm về các policies của Cedar từ bài viết Using Open Source Cedar to Write and Enforce Custom Authorization Policies.

Trước Verified Permissions, bạn phải thực thi logic phân quyền trong mã ứng dụng của mình. Bây giờ, chúng tôi sẽ chỉ cho bạn cách Verified Permissions giúp giảm bớt undifferentiated heavy lifting thông qua một ứng dụng mẫu.

Ứng dụng quản lý tài liệu đa người dùng dựa trên mô hình SaaS

Ứng dụng cho phép thêm, chia sẻ, truy cập và quản lý tài liệu. Nó yêu cầu các điều khiển truy cập sau:

  • Các nhà phát triển ứng dụng có thể xác định các policy áp dụng cho tất cả khách hàng.
  • Khách hàng có thể kiểm soát ai có thể truy cập tài liệu của họ.
  • Quản trị viên của khách hàng có thể quản lý tất cả tài liệu cho khách hàng.

Hãy bắt đầu bằng cách mô tả kiến trúc ứng dụng và sau đó đi sâu hơn vào thiết kế chi tiết.

Tổng quan về kiến trúc ứng dụng

Có hai cách tiếp cận để thiết kế nhiều khách hàng trong Verified Permissions: một single shared policy store và một per-tenant policy store. Bạn có thể tìm hiểu và chọn lựa, hướng dẫn cho những phương pháp này trong Verified Permissions user guide.

Đối với ví dụ về ứng dụng quản lý tài liệu SaaS, chúng tôi đã quyết định sử dụng phương pháp per-tenant policy store vì những lý do sau:

  • Cách ly policy đối với khách hàng sẽ tốn ít công sức
  • Có khả năng tùy chỉnh các mẫu và lược đồ cho mỗi khách hàng
  • Quá trình Off-boarding khách hàng ít tốn công sức
  • Hạn ngạch tài nguyên lưu trữ policy cho mỗi khách hàng

Chúng tôi quyết định chấp nhận sự đánh đổi sau:

  • Nỗ lực cao trong việc thực thi quản lý policy toàn cầu (vì use-case của ứng dụng không yêu cầu thay đổi thường xuyên đối với các policy này)
  • Nỗ lực trung bình để triển khai luồng phân quyền (vì chúng tôi đã quyết định rằng trong ngữ cảnh này, các lý do trên sẽ lớn hơn việc triển khai ánh xạ từ ID khách hàng sang policy store ID)

Hình 1 thể hiện kiến trúc ứng dụng quản lý tài liệu SaaS. Để đơn giản, chúng tôi bỏ qua phần frontend và tập trung vào phần backend.

Hình 1: Kiến trúc ứng dụng quản lý tài liệu SaaS

  1. Tenant user đăng nhập vào identity provider, chẳng hạn như Amazon Cognito. Họ lấy một JSON Web Token (JWT) mà họ sử dụng cho các API requests. JWT chứa các yêu cầu như  user_id  để xác định tenant user và tenant_id để xác định user thuộc về tenant nào.
  2. Tenant user thực hiện các yêu cầu API bằng JWT tới ứng dụng.
  3. Amazon API Gateway sẽ xác minh tính hợp lệ của JWT với identity provider.
  4. Nếu JWT hợp lệ, API Gateway sẽ chuyển tiếp yêu cầu đến compute provider, trong trường hợp này là AWS Lambda để nó chạy logic nghiệp vụ.
  5. Lambda function sẽ giả định một  AWS Identity and Access Management (IAM) role với một IAM policy cho phép truy cập vào bảng Amazon DynamoDB để cung cấp ánh xạ tenant-to-policy-store. IAM policy sẽ giới hạn quyền truy cập sao cho Lambda function chỉ có thể truy cập dữ liệu hiện tại tenant_id.
  6. Lambda function sẽ tra cứu Verified Permissions policy_store_id cho request hiện tại. Để làm điều này, nó sẽ trích xuất tenant_id  từ JWT. Sau đó, function này sẽ truy xuất policy_store_id từ bảng ánh xạ tenant-to-policy-store.
  7. Lambda function đảm nhận một IAM role khác với IAM policy cho phép truy cập vào Verified Permissions policy store, bảng metadata tài liệu và kho tài liệu. IAM policy  sử dụng tenant_id và policy_store_id để giảm phạm vi truy cập.
  8. Lambda function nhận hoặc lưu trữ siêu tài liệu trong bảng DynamoDB. Function này sử dụng metadata cho các yêu cầu cấp quyền của Verified Permissions.
  9. Sử dụng thông tin từ bước 5 và 6, Lambda function gọi Verified Permissions để đưa ra quyết định cấp quyền hoặc tạo Cedar policies.
  10. Nếu được cấp quyền, ứng dụng có thể truy cập hoặc lưu trữ tài liệu.

Kiến trúc ứng dụng chuyên sâu

Bây giờ bạn đã biết kiến trúc cho từng use cases, hãy xem xét chúng chi tiết hơn và làm ngược lại từ trải nghiệm người dùng đến phần liên quan của kiến trúc ứng dụng. Kiến trúc tập trung vào quản lý quyền. Việc truy cập và lưu trữ tài liệu thực tế nằm ngoài phạm vi này.

Xác định các policies áp dụng cho tất cả khách hàng

Nhà phát triển ứng dụng phải xác định các policies chung bao gồm một bộ quyền truy cập cơ bản cho tất cả khách hàng. Chúng tôi sử dụng policies của Cedar để thực thi các quyền này.

Bởi vì chúng tôi đang sử dụng phương pháp per-tenant policy store nên quy trình giới thiệu khách hàng sẽ tạo các policies này cho từng khách hàng mới. Hiện tại, để cập nhật policies, quy trình triển khai phải áp dụng các thay đổi cho tất cả các cửa hàng policy store.

Phần “Add a document” và “Manage all the documents for a tenant” tiếp theo bao gồm các ví dụ về policies chung.

Đảm bảo rằng khách hàng không thể chỉnh sửa policies của khách hàng khác

Ứng dụng sử dụng IAM để tách biệt tài nguyên của khách hàng này với khách hàng khác. Bởi vì chúng tôi đang sử dụng cách tiếp cận policy store cho mỗi khách hàng  nên chúng tôi có thể sử dụng IAM để tách biệt một khách hàng policy store với một policy store khác.

Kiến trúc

Hình 2: Tenant isolation

  1. Tenant user gọi đến API endpoint bằng JWT hợp lệ.
  2. Lambda function sử dụng  AWS Security Token Service (AWS STS)  để đảm nhận IAM role với IAM policy cho phép truy cập vào bảng DynamoDB ánh xạ tenant-to-policy-store. IAM policy chỉ cho phép truy cập vào bảng và các mục thuộc về khách hàng yêu cầu. Khi function đảm nhận vai trò này, nó sử dụng tenant_id để truy cập vào các mục có partition key khớp với tenant_id. Xem bài viết này trên blog  How to implement SaaS tenant isolation with ABAC and AWS IAM để biết ví dụ về các policies đó.
  3. Lambda function sử dụng tenant_id của người dùng để lấy Verified Permissions policy_store_id.
  4. Lambda function sử dụng cơ chế tương tự như trong bước 2 để đảm nhận vai trò IAM khác bằng cách sử dụng tenant_id và policy_store_id, chỉ cho phép truy cập vào tenant policy store.
  5. Lambda function truy cập vào tenant policy store.

Thêm một tài liệu

Khi người dùng truy cập ứng dụng lần đầu tiên, họ không có bất kỳ tài liệu nào. Để thêm một tài liệu, giao diện người dùng gọi đến POST /documents endpoint và cung cấp document_name trong request’s body.

Cedar policy

Chúng tôi cần một policy chung cho phép mọi người dùng khách hàng thêm tài liệu mới. Quá trình tạo khách hàng sẽ tạo policy này trong policy store của khách hàng.

permit (    

  principal,

  action == DocumentsAPI::Action::”addDocument”,

  resource

);

Policy này cho phép bất kỳ người đứng đầu nào thêm một tài liệu. Bởi vì chúng ta đang sử dụng phương pháp per-tenant policy store nên không cần phải giới hạn người đó cho một khách hàng cụ thể.

Kiến trúc

Hình 3: Thêm tài liệu

  1. Tenant user gọi đến POST /documents  endpoint để thêm một tài liệu.
  2. Lambda function sử dụng tenant_id của người dùng để lấy Verified Permissions policy_store_id.
  3. Lambda function gọi Verified Permissions policy store để kiểm tra xem người dùng khách hàng  có được phép thêm tài liệu hay không.
  4. Sau khi cấp quyền thành công, Lambda function sẽ thêm một tài liệu mới vào cơ sở dữ liệu metadata của tài liệu và tải tài liệu lên kho lưu trữ tài liệu.

Cấu trúc cơ sở dữ liệu được mô tả trong bảng sau:

tenant_id (Partition key): Stringdocument_id (Sort key): Stringdocument_name: Stringdocument_owner: String
<TENANT_ID><DOCUMENT_ID><DOCUMENT_NAME><USER_ID>
  • tenant_id:  tenant_id từ JWT claims.
  • document_id: Mã định danh ngẫu nhiên cho tài liệu, do ứng dụng tạo.
  • document_name: Tên của tài liệu được cung cấp cùng với yêu cầu API.
  • document_owner: Người dùng đã tạo tài liệu. Giá trị user_id từ JWT claims.

Chia sẻ một tài liệu với người dùng khác của khách hàng 

Sau khi tenant user đã tạo một hoặc nhiều tài liệu, họ có thể muốn chia sẻ chúng với những người dùng khác của cùng khách hàng. Để chia sẻ tài liệu, tại giao diện người dùng gọi POST /shares endpoint và cung cấp document_id của tài liệu mà người dùng muốn chia sẻ và user_id của người dùng nhận.

Cedar policy

Chúng tôi cần document owner policy chung cho phép document owner quản lý tài liệu, bao gồm cả việc chia sẻ. Quá trình tạo khách hàng sẽ tạo policy này trong policy store của khách hàng.

permit (    

  principal,

  action,

  resource

) when {

  resource.owner == principal && 

  resource.type == “document”

};

Policy cho phép người dùng thực hiện các hành động trên các tài nguyên có sẵn (tài liệu) khi người dùng là chủ sở hữu tài liệu. Policy này cho phép hành động shareDocument mà chúng tôi mô tả tiếp theo để chia sẻ một tài liệu.

Chúng tôi cũng cần chia sẻ policy cho phép người dùng truy cập tài liệu. Ứng dụng tạo ra các policies này cho mỗi hành động chia sẻ thành công. Chúng tôi khuyên bạn nên sử dụng các policy templates  để xác định share policy. Các policy templates cho phép một policy được xác định một lần và sau đó được đính kèm với nhiều nguyên tắc và tài nguyên. Các policies sử dụng policy templates được gọi là template-linked policies. Các cập nhật cho policy templates được phản ánh trên các nguyên tắc và tài nguyên sử dụng mẫu. Quá trình tạo khách hàng sẽ tạo share policy template trong policy store của khách hàng.

Chúng tôi xác định share policy template như sau:

permit (    

  principal == ?principal,  

  action == DocumentsAPI::Action::”accessDocument”,

  resource == ?resource 

);

Sau đây là ví dụ về template-linked policy sử dụng share policy template:

permit (    

  principal == DocumentsAPI::User::”<user_id>”,

  action == DocumentsAPI::Action::”accessDocument”,

  resource == DocumentsAPI::Document::”<document_id>” 

);

Policy này bao gồm user_id của người dùng nhận và document_id của tài liệu (tài nguyên).

Kiến trúc

Hình 4: Chia sẻ tài liệu

  1. Tenant user gọi đến POST /documents  endpoint để chia sẻ tài liệu.
  2. Lambda function sử dụng tenant_id của người dùng để lấy Verified Permissions policy_store_id và các ID của policy template cho mỗi hành động từ bảng DynamoDB lưu trữ khách hàng vào ánh xạ policy store. Trong trường hợp này, function cần sử dụng share_policy_template_id.
  3. Function truy vấn vào bảng DynamoDB metadata của tài liệu để truy xuất thuộc tính document_owner cho tài liệu mà người dùng muốn chia sẻ.
  4. Lambda function gọi Verified Permissions để kiểm tra xem người dùng có được phép chia sẻ tài liệu hay không. Yêu cầu này cần  sử dụng user_id từ JWT claims như principal, shareDocument làm hành động và document_id làm tài nguyên. Thực thể tài liệu bao gồm thuộc tính document_owner, thuộc tính này đến từ bảng DynamoDB siêu dữ liệu tài liệu.
  5. Nếu người dùng được phép chia sẻ tài nguyên, function sẽ tạo template-linked share policy mới trong tenant’s policy store. Policy này bao gồm user_id của người dùng nhận là người chính và document_id là tài nguyên.

Truy cập tài liệu được chia sẻ

Sau khi tài liệu được chia sẻ, người dùng được nhận muốn truy cập tài liệu đó. Để truy cập tài liệu, frontend gọi đến GET /documents  endpoint và cung cấp document_id của tài liệu mà người dùng muốn truy cập.

Cedar policy

Như đã trình bày trong phần trước, trong quá trình chia sẻ, ứng dụng sẽ tạo template-linked share policy cho phép người dùng được nhận truy cập vào tài liệu. Verified Permissions sẽ đánh giá policy này khi người dùng cố gắng truy cập tài liệu.

Kiến trúc

Hình 5: Truy cập tài liệu được chia sẻ

  1. Tenant user gọi đến GET /documents  enpoint để truy cập tài liệu.
  2. Lambda function sử dụng tenant_id của người dùng để lấy Verified Permissions policy_store_id
  3. Lambda function  gọi Verified Permissions để kiểm tra xem người dùng có được phép truy cập tài liệu hay không. Bối cảnh yêu cầu sử dụng user_id từ JWT claims như principal, accessDocument làm hành động và document_id làm tài nguyên.

Quản lý tất cả các tài liệu cho khách hàng

Khi khách hàng đăng ký ứng dụng SaaS, ứng dụng sẽ tạo người dùng quản trị viên của khách hàng. Quản trị viên này phải có quyền thực hiện mọi hành động trên tất cả tài liệu của khách hàng.

Cedar policy

Chúng tôi cần một policy chung cho phép quản trị viên quản lý tất cả tài liệu. Quá trình tạo khách hàng sẽ tạo chính sách này trong policy store của khách hàng.

Kiến trúc

Hình 6: Quản lý tài liệu

  1. Quản trị viên gọi đến  POST /documents  enpoint để quản lý tài liệu.
  2. Lambda function sử dụng tenant_id của người dùng để lấy Verified Permissions policy_store_id
  3. Lambda function gọi Verified Permissions để kiểm tra xem người dùng có được phép quản lý tài liệu hay không.

Phần kết luận

Trong bài viết này, chúng tôi đã giới thiệu cho bạn cách Amazon Verified Permissions giúp thực thi các quyết định cấp phép một cách chi tiết cho ứng dụng đa khách hàng SaaS. Bạn đã biết áp dụng cách tiếp cận per-tenant policy store vào kiến trúc ứng dụng. Xem user guide Verified Permissions để biết cách chọn giữa việc sử dụng per-tenant policy store hoặc shared policy store. Để tìm hiểu thêm, hãy truy cập documentationworkshop về Verified Permissions.

Toàn bộ bài viết gốc được chia sẻ tại đường dẫn sau:

SaaS access control using Amazon Verified Permissions with a per-tenant policy store