OpenID Connect: ủy quyền các ứng dụng nội bộ từ tùy chỉnh sang tiêu chuẩn

Vài tháng trước, tôi đã triển khai máy chủ OpenID Connect để quản lý quyền truy cập cho hàng trăm ứng dụng nội bộ của chúng tôi. Từ những phát triển của riêng chúng tôi, thuận tiện ở quy mô nhỏ hơn, chúng tôi đã chuyển sang một tiêu chuẩn được chấp nhận rộng rãi. Truy cập thông qua dịch vụ trung tâm giúp đơn giản hóa đáng kể các hoạt động đơn điệu, giảm chi phí thực hiện ủy quyền, cho phép bạn tìm thấy nhiều giải pháp làm sẵn và không phải vắt óc khi phát triển những giải pháp mới. Trong bài viết này, tôi sẽ nói về quá trình chuyển đổi này và những khó khăn mà chúng tôi đã vượt qua.

OpenID Connect: ủy quyền các ứng dụng nội bộ từ tùy chỉnh sang tiêu chuẩn

Cách đây đã lâu... Tất cả đã bắt đầu như thế nào

Vài năm trước, khi có quá nhiều ứng dụng nội bộ để kiểm soát thủ công, chúng tôi đã viết một ứng dụng để kiểm soát truy cập trong công ty. Đó là một ứng dụng Rails đơn giản kết nối với cơ sở dữ liệu chứa thông tin về nhân viên, nơi quyền truy cập vào các chức năng khác nhau được định cấu hình. Đồng thời, chúng tôi đã đưa ra SSO đầu tiên, dựa trên việc xác minh mã thông báo từ phía máy khách và máy chủ ủy quyền, mã thông báo được truyền ở dạng mã hóa với một số tham số và được xác minh trên máy chủ ủy quyền. Đây không phải là tùy chọn thuận tiện nhất vì mỗi ứng dụng nội bộ phải mô tả một lớp logic đáng kể và cơ sở dữ liệu của nhân viên được đồng bộ hóa hoàn toàn với máy chủ ủy quyền.

Sau một thời gian, chúng tôi quyết định đơn giản hóa nhiệm vụ ủy quyền tập trung. SSO đã được chuyển sang bộ cân bằng. Với sự trợ giúp của OpenResty, một mẫu đã được thêm vào Lua để kiểm tra mã thông báo, biết ứng dụng nào sẽ được yêu cầu và có thể kiểm tra xem có quyền truy cập ở đó hay không. Cách tiếp cận này đã đơn giản hóa rất nhiều nhiệm vụ kiểm soát quyền truy cập vào các ứng dụng nội bộ - trong mã của từng ứng dụng, không còn cần thiết phải mô tả logic bổ sung. Do đó, chúng tôi đã đóng lưu lượng bên ngoài và bản thân ứng dụng không biết gì về ủy quyền.

Tuy nhiên, một vấn đề vẫn chưa được giải quyết. Còn những ứng dụng cần thông tin về nhân viên thì sao? Có thể viết API cho dịch vụ ủy quyền, nhưng sau đó bạn sẽ phải thêm logic bổ sung cho từng ứng dụng như vậy. Ngoài ra, chúng tôi muốn loại bỏ sự phụ thuộc vào một trong những ứng dụng tự viết của chúng tôi, ứng dụng này sau này sẽ được dịch sang OpenSource, trên máy chủ ủy quyền nội bộ của chúng tôi. Chúng ta sẽ nói về nó vào lúc khác. Giải pháp cho cả hai vấn đề là OAuth.

theo tiêu chuẩn chung

OAuth là một tiêu chuẩn ủy quyền dễ hiểu, được chấp nhận rộng rãi, nhưng vì chỉ chức năng của nó là không đủ nên họ đã ngay lập tức bắt đầu xem xét OpenID Connect (OIDC). Bản thân OIDC là triển khai thứ ba của tiêu chuẩn xác thực mở, đã được đưa vào một tiện ích bổ sung qua giao thức OAuth 2.0 (một giao thức ủy quyền mở). Giải pháp này giải quyết vấn đề thiếu dữ liệu về người dùng cuối và cũng có thể thay đổi nhà cung cấp ủy quyền.

Tuy nhiên, chúng tôi đã không chọn một nhà cung cấp cụ thể và quyết định thêm tích hợp với OIDC cho máy chủ ủy quyền hiện có của chúng tôi. Có lợi cho quyết định này là thực tế là OIDC rất linh hoạt về mặt ủy quyền của người dùng cuối. Do đó, có thể triển khai hỗ trợ OIDC trên máy chủ ủy quyền hiện tại của bạn.

OpenID Connect: ủy quyền các ứng dụng nội bộ từ tùy chỉnh sang tiêu chuẩn

Cách triển khai máy chủ OIDC của riêng chúng tôi

1) Đưa dữ liệu về dạng mong muốn

Để tích hợp OIDC, cần phải đưa dữ liệu người dùng hiện tại về dạng có thể hiểu được theo tiêu chuẩn. Trong OIDC, điều này được gọi là Khiếu nại. Khiếu nại về cơ bản là các trường cuối cùng trong cơ sở dữ liệu người dùng (tên, email, điện thoại, v.v.). tồn tại danh sách tem tiêu chuẩnvà mọi thứ không có trong danh sách này đều được coi là tùy chỉnh. Do đó, điểm đầu tiên mà bạn cần chú ý nếu muốn chọn nhà cung cấp OIDC hiện có là khả năng tùy chỉnh thuận tiện của các thương hiệu mới.

Nhóm các dấu hiệu được kết hợp thành tập hợp con sau - Phạm vi. Trong quá trình ủy quyền, quyền truy cập không được yêu cầu đối với các thương hiệu cụ thể mà đối với phạm vi, ngay cả khi một số thương hiệu trong phạm vi không cần thiết.

2) Thực hiện các khoản tài trợ cần thiết

Phần tiếp theo của tích hợp OIDC là lựa chọn và triển khai các loại ủy quyền, được gọi là trợ cấp. Kịch bản tương tác tiếp theo giữa ứng dụng đã chọn và máy chủ ủy quyền sẽ phụ thuộc vào cấp được chọn. Một sơ đồ mẫu để chọn khoản tài trợ phù hợp được thể hiện trong hình bên dưới.

OpenID Connect: ủy quyền các ứng dụng nội bộ từ tùy chỉnh sang tiêu chuẩn

Đối với ứng dụng đầu tiên của chúng tôi, chúng tôi đã sử dụng cấp phổ biến nhất, Mã ủy quyền. Sự khác biệt của nó so với những cái khác là nó có ba bước, tức là. đang trải qua thử nghiệm bổ sung. Đầu tiên, người dùng đưa ra yêu cầu cấp quyền, nhận mã thông báo - Mã ủy quyền, sau đó với mã thông báo này, như thể với một vé đi du lịch, yêu cầu mã thông báo truy cập. Tất cả tương tác chính của tập lệnh ủy quyền này dựa trên chuyển hướng giữa ứng dụng và máy chủ ủy quyền. Bạn có thể đọc thêm về khoản tài trợ này đây.

OAuth tuân thủ khái niệm rằng mã thông báo truy cập có được sau khi ủy quyền phải là tạm thời và nên thay đổi, tốt nhất là trung bình 10 phút một lần. Việc cấp Mã ủy quyền là xác minh ba bước thông qua các chuyển hướng, cứ sau 10 phút lại chuyển một bước như vậy, thẳng thắn mà nói, không phải là nhiệm vụ dễ chịu nhất đối với mắt. Để giải quyết vấn đề này, có một khoản trợ cấp khác - Mã thông báo làm mới, mà chúng tôi cũng đã sử dụng ở nước mình. Mọi thứ dễ dàng hơn ở đây. Trong quá trình xác minh từ một khoản trợ cấp khác, ngoài mã thông báo truy cập chính, một mã khác được cấp - Mã thông báo làm mới, chỉ có thể được sử dụng một lần và thời gian tồn tại của nó thường dài hơn nhiều. Với Mã thông báo làm mới này, khi TTL (Thời gian tồn tại) của mã thông báo truy cập chính kết thúc, yêu cầu mã thông báo truy cập mới sẽ đến điểm cuối của một khoản trợ cấp khác. Mã thông báo Làm mới đã sử dụng ngay lập tức được đặt lại về XNUMX. Quá trình kiểm tra này gồm hai bước và có thể được thực hiện ở chế độ nền mà người dùng không thể nhận thấy.

3) Thiết lập định dạng đầu ra dữ liệu tùy chỉnh

Sau khi các khoản trợ cấp đã chọn được triển khai, ủy quyền sẽ hoạt động, điều đáng nói là lấy dữ liệu về người dùng cuối. OIDC có một điểm cuối riêng cho việc này, nơi bạn có thể yêu cầu dữ liệu người dùng bằng mã thông báo truy cập hiện tại của mình và nếu nó được cập nhật. Và nếu dữ liệu của người dùng không thay đổi thường xuyên và bạn cần theo dõi dữ liệu hiện tại nhiều lần, thì bạn có thể tìm đến một giải pháp như mã thông báo JWT. Các mã thông báo này cũng được hỗ trợ bởi tiêu chuẩn. Bản thân mã thông báo JWT bao gồm ba phần: tiêu đề (thông tin về mã thông báo), tải trọng (bất kỳ dữ liệu cần thiết nào) và chữ ký (chữ ký, mã thông báo được ký bởi máy chủ và sau này bạn có thể kiểm tra nguồn chữ ký của nó).

Trong triển khai OIDC, mã thông báo JWT được gọi là id_token. Nó có thể được yêu cầu cùng với mã thông báo truy cập thông thường và tất cả những gì còn lại là xác minh chữ ký. Máy chủ ủy quyền có một điểm cuối riêng cho việc này với một loạt các khóa công khai ở định dạng J.W.K.. Và nói về điều này, điều đáng nói là có một điểm cuối khác, dựa trên tiêu chuẩn RFC5785 phản ánh cấu hình hiện tại của máy chủ OIDC. Nó chứa tất cả các địa chỉ điểm cuối (bao gồm địa chỉ của vòng khóa công khai được sử dụng để ký), các nhãn hiệu và phạm vi được hỗ trợ, các thuật toán mã hóa được sử dụng, các khoản trợ cấp được hỗ trợ, v.v.

Ví dụ trên Google:

{
 "issuer": "https://accounts.google.com",
 "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
 "device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
 "token_endpoint": "https://oauth2.googleapis.com/token",
 "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
 "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
 "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
 "response_types_supported": [
  "code",
  "token",
  "id_token",
  "code token",
  "code id_token",
  "token id_token",
  "code token id_token",
  "none"
 ],
 "subject_types_supported": [
  "public"
 ],
 "id_token_signing_alg_values_supported": [
  "RS256"
 ],
 "scopes_supported": [
  "openid",
  "email",
  "profile"
 ],
 "token_endpoint_auth_methods_supported": [
  "client_secret_post",
  "client_secret_basic"
 ],
 "claims_supported": [
  "aud",
  "email",
  "email_verified",
  "exp",
  "family_name",
  "given_name",
  "iat",
  "iss",
  "locale",
  "name",
  "picture",
  "sub"
 ],
 "code_challenge_methods_supported": [
  "plain",
  "S256"
 ],
 "grant_types_supported": [
  "authorization_code",
  "refresh_token",
  "urn:ietf:params:oauth:grant-type:device_code",
  "urn:ietf:params:oauth:grant-type:jwt-bearer"
 ]
}

Do đó, bằng cách sử dụng id_token, bạn có thể chuyển tất cả các dấu hiệu cần thiết sang tải trọng của mã thông báo và không phải liên hệ với máy chủ ủy quyền mỗi lần để yêu cầu dữ liệu người dùng. Nhược điểm của phương pháp này là thay đổi dữ liệu người dùng từ máy chủ không đến ngay lập tức mà kèm theo mã thông báo truy cập mới.

Kết quả thực hiện

Vì vậy, sau khi triển khai máy chủ OIDC của riêng mình và định cấu hình các kết nối với nó ở phía ứng dụng, chúng tôi đã giải quyết được vấn đề truyền thông tin về người dùng.
Vì OIDC là một tiêu chuẩn mở nên chúng tôi có tùy chọn chọn nhà cung cấp hoặc triển khai máy chủ hiện có. Chúng tôi đã dùng thử Keycloak, nó rất thuận tiện để định cấu hình, sau khi thiết lập và thay đổi cấu hình kết nối ở phía ứng dụng, nó đã sẵn sàng hoạt động. Về phía ứng dụng, tất cả những gì còn lại là thay đổi cấu hình kết nối.

Nói về các giải pháp hiện có

Trong tổ chức của chúng tôi, với tư cách là máy chủ OIDC đầu tiên, chúng tôi đã lắp ráp triển khai của riêng mình và được bổ sung khi cần thiết. Sau khi xem xét chi tiết các giải pháp làm sẵn khác, chúng tôi có thể nói rằng đây là một điểm cần tranh luận. Có lợi cho quyết định triển khai máy chủ của riêng họ, các nhà cung cấp đã lo ngại về việc không có chức năng cần thiết, cũng như sự hiện diện của một hệ thống cũ trong đó có các ủy quyền tùy chỉnh khác nhau cho một số dịch vụ và khá nhiều dữ liệu về nhân viên đã được lưu trữ. Tuy nhiên, trong các triển khai làm sẵn, có những tiện lợi cho việc tích hợp. Ví dụ: Keycloak có hệ thống quản lý người dùng riêng và dữ liệu được lưu trữ trực tiếp trong đó và sẽ không khó để vượt qua người dùng của bạn ở đó. Để làm điều này, Keycloak có một API cho phép bạn thực hiện đầy đủ tất cả các hành động chuyển cần thiết.

Theo tôi, một ví dụ khác về việc triển khai được chứng nhận, thú vị là Ory Hydra. Nó thú vị bởi vì nó bao gồm các thành phần khác nhau. Để tích hợp, bạn sẽ cần liên kết dịch vụ quản lý người dùng của mình với dịch vụ ủy quyền của họ và mở rộng khi cần.

Keycloak và Ory Hydra không phải là giải pháp sẵn có duy nhất. Tốt nhất là chọn một triển khai được OpenID Foundation chứng nhận. Các giải pháp này thường có huy hiệu Chứng nhận OpenID.

OpenID Connect: ủy quyền các ứng dụng nội bộ từ tùy chỉnh sang tiêu chuẩn

Ngoài ra, đừng quên các nhà cung cấp trả phí hiện có nếu bạn không muốn giữ máy chủ OIDC của mình. Ngày nay có rất nhiều lựa chọn tốt.

những gì tiếp theo

Trong tương lai gần, chúng tôi sẽ đóng lưu lượng truy cập vào các dịch vụ nội bộ theo một cách khác. Chúng tôi dự định chuyển SSO hiện tại của mình trên bộ cân bằng bằng OpenResty sang proxy dựa trên OAuth. Ngoài ra còn có nhiều giải pháp làm sẵn ở đây, ví dụ:
github.com/bitly/oauth2_proxy
github.com/ory/oathkeeper
github.com/keycloak/keycloak-gatekeeper

Tài liệu bổ sung

jwt.io – dịch vụ tốt để xác thực mã thông báo JWT
openid.net/developers/certified - danh sách triển khai OIDC được chứng nhận

Nguồn: www.habr.com

Thêm một lời nhận xét