こんにちは。Red Hatでソリューションアーキテクトをしている杉本 拓です。
今回はクラウドネイティブなAPI管理ソリューションであるKuadrant に含まれている、APIをセキュアにするための新しいオープンソースプロジェクト Authorinoについて、Red Hat Developerのブログ記事 Authorino: Making open source, cloud-native API security simple and flexible の翻訳を通じて紹介をしたいと思います。
なお、赤帽エンジニアブログの別の記事において、このAuthorinoのサンプルアプリケーションの動かし方について紹介していますので、そちらもご覧いただければ幸いです。
Authorino: Making open source, cloud-native API security simple and flexible (クラウドネイティブなAPIセキュリティをシンプルかつ柔軟にするオープンソース)
Authorinoは、インターネットの利用がより安全にできるようにアプリケーションの改修を行う際、セキュリティのことを考慮されずに構築されたAPIに対して認証や認可を追加しなければならないという、常に発生する問題に対してソリューションを提供するものです。Authorinoを使用すれば、簡単でクラウドネイティブなやり方で、そのようなAPIを公開することができるようになります。APIを修正したり、作り直したりする必要はありません。Authorinoは外部の認可フィルタを備えた軽量なリバースプロキシ層で、KubernetesのAPI経由で全て設定が可能となっており、要件に応じて適切な認証・認可モデルを追加することができます。
この記事では、Authorinoの用途とメリットの概要、その基本的な仕組み、そしてユースケース例に基づく簡単なデモンストレーションを紹介します。
Authorinoのユースケース
Authorinoの使用頻度の高いシナリオを想像してみましょう。例えば自分がAPIの開発者であるとして、何か要件が明確になったり、面白そうな機能拡張の要望が新しく来たとします。あなたはホワイトボードのところに行き、サービスとAPIをベースにした素晴らしいソフトウェアのソリューションを思いつきます。あなたは自分のお気に入りの開発ツールを選び、プロジェクトにおいて重要な機能のコーディングに取りかかります。数時間から数日で、ベータ版を公開し、実際に使ってもらうことができるようになりました。あなたのソリューションは、機能的に豊富ではありませんが、求められていた機能には重点が置かれ、効率的に作られています。万事順調でした。ある現実的な要件、特にアクセスコントロールの要件が現れてくるまでは。
さて、あなたは微細なセキュリティに関する問いに対応しなくてはならなくなりました。誰がAPIにアクセスするのか? ユーザーのIDはどのように確認するのか? ユーザーはデータベースに格納すべきか? パーミッションについてはどうでしょうか? 認可のルールはどれくらいの頻度で変更されるのか? ロールベースのアクセスコントロール(RBAC)を実装すべきか? 読み取り専用アクセスを許可すべきでしょうか?
このように動的かつ複雑なこともある様々なポリシーを適用しなくてはならず、準拠すべき認証・認可の標準やプロトコルもあり、認可のシステムも複数あり、さらにはレガシーシステムとの連携も必要となってくるとなると、APIをセキュアにするということに対して、あっという間に途方に暮れてしまいます。
アクセス制御のルールをすべてAPIの実装コードに押し込むことは、設計上の重要な原則である「関心事の分離」に明らかに反することになります。もしそのようなことをしてしまうと、APIが本来持つべき機能、パフォーマンス、保守性、スケーラビリティなどに問題が生じることになるでしょう。if else文でソースコードが汚くなってしまうだけでなく、アクセス制御をソースコードに組み込んでしまうことにより、実装とライブラリや周辺テクノロジーとの結合度が強くなってしまい、コードの再利用性は確実に制限されてしまいます。
一方、市場にある特化型の個別ソリューションはあまり魅力的とは言えず、かと言って別途サーバを立ち上げ、複雑な設定ファイルを扱って...、というのもあまりいいとは思われません。
今時の開発者が望むのは、パフォーマンスに優れ、アプリケーションのコアな部分に集中できるような、特化型でいいソリューションです。また、彼らが望むのは既存のインフラや使い慣れている開発言語と技術要素を活かしつつ、習得が容易でデプロイや運用も簡単なソリューションでもあります。
Authorinoとは?
Authorinoは、APIを保護するためのKubernetesネイティブな外部認可サービスのオープンソース です。API設計のリバースプロキシパターンに基づいて構築され、APIのゼロトラストセキュリティをサポートします。Authorinoは、ネットワークのエッジやバックエンドサービス、コンテナ間のクラスタ内通信(内部プロキシ経由)、受信トラフィック(ingress ゲートウェイ経由)など、いろんな場所で動作します。
AuthorinoはEnvoyプロキシの上に構築され、gRPCプロトコルを使用してExternal Authorization (外部システムでの認証認可)を行います。そのプロキシ上で、AuthorinoはAPIへのリクエストに対して非常に高速にユーザIDの検証と認可ポリシーの適用を行うレイヤーとなり、これにより適切に認証および認可されない限り、トラフィックがサービスに到達するのを防ぎます。
Authorinoを使用することにより、APIキー、OpenID Connect(署名入りJSON Web トークン)、OAuth 2.0イントロスペクション、Kubernetes認証などを使用してAPIの公開と認証トークン/クレデンシャルの検証を行うことが可能です。またAuthorinoでは、シンプルなJSONパターンマッチングルール(JWTクレームチェックやHTTPリクエスト属性チェックなど)、複雑なOpen Policy Agent (OPA) Regoポリシー、Kubernetes SubjectAccessReview (Kubernetes RBAC)などの認可ポリシーによる、柔軟なアクセス制御が可能になります。業界標準やプロトコルの中から最適なものを選択し、それらを組み合わせて使用することができます。外部の認証サーバーやリソースデータのレジストリと接続したり、キャッシュを利用したり、デプロイメントのトポロジーにおいても集中型ゲートウェイやサイドカーなど様々な方式から選択が可能です。
Authorinoを使用するメリット
Authorinoは、現代のWebに関わる様々な認可の要件に対応することができます。以下はそのメリットの一部です:
汎用性: Authorinoにより、互換性の高いAPIセキュリティの実現が可能になります。Authorinoは何か特定の仕様を強制するものではなく、何かをするのに一つの方法しかできないということがないようにしています。そのため、APIキー、OAuth 2.0、OIDC、ネイティブなKubernetes認証トークン、Red Hat OpenShiftのユーザー認証、mTLS 等々、さまざまな認証モデルやプロトコルをサポートしています。API保護のニーズに最も適した方式を1つ選択することも、あるいは複数を組み合わせて別のIDソースと連携しながら、各ユーザーグループに対してアサーティブで適切な認可ポリシーを適用することができます。Authorinoには、Open Policy Agent (OPA)とJSONパターンマッチングに基づいてポリシーを評価する強力な仕組みが組み込まれており、エッジに格納されたユーザー情報、JWT、コンテキスト、あるいはその場で取得してキャッシュされた属性データに基づいたRBAC、UBAC、またはABACなど、あらゆる種類のアクセス制御の方式を実装するための認可ルールを記述することができます。AuthorinoはKubernetesのSubjectAccessReviewに基づく認可もサポートしています。
クリーン: Authorinoを使えば、開発者はAPIソリューションのコアな部分に集中でき、認証サーバーやIDプロバイダーとの統合、ユーザープロファイルの管理、複雑なアクセス制御システムのif else文の処理など、認証認可の処理に関わるオーバーヘッドをすべて強力なセキュリティエージェントに任せることができます。Envoyフィルターを使用したAPIへのアクセスにおいてリバースプロキシやゲートウェイのパターンを活用することで、AuthorinoはAPIのセキュリティを強化しつつ、ほとんどのユースケースでAPIのコードに変更を加える必要がありません。
Kubernetesネイティブ: AuthorinoはKubernetes上で動作するように設計されています。不親切な設定ファイルや標準化されていない管理用APIの代わりに、Kubernetesのカスタムリソースを通じてAuthorinoでサービスを保護することができるようになります。Authorinoのカスタムコントローラは、Kubernetesサーバー内のリソースの状態を監視し、信頼できる唯一のデータソースが確実なものであるとすることで、真のクラウドネイティブなユーザーエクスペリエンスを提供します。もちろん、コンテナオーケストレーションの環境で当然期待されるような、スケーリング、自動化、監視、監査も可能です。稼働しているAPIのセキュリティの状態を誰が変更できるのかに関しても、API開発者に直接責任を委ねるのか、あるいはDevOpsやSREを含めたより複雑なワークフローで処理するのか、KubernetesのRBACを利用した権限管理を行うことができます。
柔軟性: Authorinoは、APIのネットワークアーキテクチャに関しても何かを強制することはありません。むしろ1つのプロキシ構成で複数のAPIに対応する一般的なシングルゲートウェイのトポロジーに対応したり、集中型または完全分散型のAuthorinoサイドカーに接続する専用プロキシにすることもできます。Authorinoは柔軟で、完全にステートレスなアプリケーションであり、硬直的なアーキテクチャにならず、本質的なボトルネックも無いため、DevOpsチームはNorth-SouthあるいはEast-WestのAPIアクセスのいずれにも対応したスケーリングを自在に実現することができます。
効率性: APIセキュリティのスタックにはキャッシュのレイヤーが自動的に追加されます。OpenID ConnectやUser-Managed Access(UMA)の設定、JSON Web Key Set(JWKS)、コンパイル済みのOPAポリシーなど、さまざまなオプションが用意されています。今後、失効したアクセストークンの情報や、要求されたリソースデータのキャッシュ機能も追加される予定です。
シームレス: Authorinoはスタンドアローンで使用することもできますが、今後Red Hat 3scale API ManagementがKuadrant連携して利用することも可能になる予定です。Kuadrantは、Authorinoとの認証・認可をはじめ、流量制御、OASのサポート、カスタムの開発者ポータルなど、完全にクラウドネイティブなAPI管理を実現するものです。Kuadrantのデータプレーンにより、Kubernetesサービス、Ingressゲートウェイ、OpenShiftルート、Istio VirtualServicesやHTTPRoutesなどのネットワークリソースとAPI管理機能のオーケストレーションをシンプルかつまとまりのある形で行うことができ、高レベルのAPI仕様をAuthorinoカスタムリソースを含む低レベルのリソースに変換してくれます。
オープンソース: Authorinoは、Kubernetes、OpenShift、OAuth、OIDC、OPA、UMAなど、信頼性が高く、広く採用されているオープンソースの技術に基づいています。AuthorinoはGo言語で書かれており、Red Hatの支援を受けています。
Authorinoの仕組み
AuthorinoはEnvoy ProxyのExternal Authorizationを利用し、gRPCプロトコルを実装しています。まず最初にAPIの開発者がAPIを実装してデプロイし、Envoy ProxyのエンドポイントでそのAPIを公開します。プロキシは、External Authorizationフィルタとその呼び出し先であるAuthorinoサービスを設定する必要があります。開発者はAPIを公開するトポロジーに合わせてこの設定を手動で行うこともできますし、Kuadrantが提供する自動化機能を活用することもできます。APIに対する保護機能の追加とリクエストの受け付けの開始を効果的に行うためには、開発者はKubernetesのAuthConfig
カスタムリソース(CR)をクラスターに適用します。
AuthConfig
CRには、APIへのリクエストに適用されるID検証と認可のルールを記述します。ユーザークレデンシャルやアクセストークンを検証する際に信頼できるIDソースと認証方式をリストアップし、認証は、OIDCのJWT、OAuth 2.0 opaqueトークンイントロスペクション、Kubernetesのアクセストークンなどのプロトコルを使用して外部の認証サーバーやIdPで行うこともでき(アクセストークンの検証はリクエスト時にAuthorinoが行います)、あるいはAPIキー、mTLS、HMAC認証などの組み込みの方式を使用して行うことも可能です。
AuthConfig
CRでは、認可の形式を定義することも可能です。Authorinoの認可ポリシーは、単純なJSONパターンマッチングルール(JWTクレームチェックなど)として表現したり、インラインで記述されたり外部のポリシーレジストリから取得したOpen Policy Agent (OPA) Rego言語で定義したり、あるいはKubernetesのSubjectAccessReviewに基づく認可を使用することも可能です。
保護されたAPIを利用するユーザーは、有効なトークンまたはクレデンシャルを取得してAPIにアクセスし、指定された認証フィールド(HTTPのAuthorizationヘッダー、カスタムヘッダー、クエリー文字列のパラメーター、あるいはクッキーなど)にそれらのクレデンシャルを格納してリクエストを送信します。リクエストはEnvoy Proxyによってインターセプトされ、Envoy ProxyはAuthorinoとのgRPC接続を高速に行います。Authorinoは、ポリシーを適用するために有効なカスタムリソースを検索し、認証パイプラインをトリガーします。Authorinoは認証パイプラインを通じて、提供されたトークンまたはクレデンシャルが少なくとも1つの信頼できるIDソースに受け入れられているか、そしてすべての認可ポリシーでAPIで要求されたリソースに対するユーザーのアクセスが許可されているかどうかを検証します。図1はその基本的なフローを示しています。
認可ポリシーは、リクエストのコンテキストデータ(HTTPリクエストの属性など)、クレデンシャルから解決されたIDの属性(ユーザー情報、JWTクレームなど)、外部サービスから取得したメタデータなど、認証パイプラインを通じて収集されたあらゆる情報を利用することができます。
Authorinoはリクエストごとに認可JSONを生成し、それが実行時に認可ポリシーが評価される際のインプットとなります。ポリシーはRego言語で記述したり、組み込みのOPAモジュールで実行したり、SubjectAccessReviewを使用してKubernetesのRBACの評価を行ったり、あるいは "is equal to"、"matches a regex"、"include" などの演算子による単純なJSONパターンマッチングルールにすることも可能です。図2はリクエストを受け付けた際のAuthorinoの認証認可のパイプラインを示しています。
AuthorinoがユーザーのID検証に成功し、すべてのポリシーでユーザーのアクセスが許可された場合、Envoyはトラフィックを要求通りに保護されたAPIにリダイレクトします。そうでない場合は、要求された API に到達することはなく、適切な HTTP ステータス コードがユーザーに返されます。APIをリダイレクトする前に、AuthorinoはオプションでカスタムのHTTPヘッダーやEnvoy Dynamic Metadataをインジェクトしたり、トークン正規化およびエッジ認証の実装に使用できる署名付きOIDC準拠JWTであるFestival Wristbandトークンの発行を行うことも可能です。
ユースケース例
Authorinoは、APIを保護する機能をユースケースに応じて柔軟にパッケージングすることができるように設計されています。例えば、あるAPIに対してリクエストがあるとしましょう。異なる認証プロトコルで取得された異なるIDソースからのアクセストークンを受け入れて、すべてのケースをカバーするためにRegoで書かれた1つのOPAベースの認可ポリシーでアクセスを管理することを選択するかもしれません。あるいは他のプロジェクトにおいては、常に単一の信頼できるIDソースから発行されたアクセストークンを許可し、認可ポリシーを複数の単純なパターンマッチングルールに分割する方がいいかもしれません。Authorinoでは、このような様々なユースケースをすべて混在させたり組み合わせたりすることが可能です。
OIDC認証に基づいたAPI保護ポリシーで、さらにRBACとUBACのポリシールールを適用する場合、AuthorinoのAuthConfig
カスタムリソースの記述は以下のようになります。
apiVersion: apiVersion: authorino.kuadrant.io/v1beta1 kind: AuthConfig metadata: name: my-api-protection-1 spec: hosts: - my-api.io identity: - name: users oidc: issuer: http://my-trusted-idp.example.com authorization: - name: rbac when: - selector: auth.identity.roles operator: excl value: admin json: rules: - selector: auth.content.request.method operator: eq value: GET - name: ubac json: rules: - selector: auth.identity.email_verified operator: eq value: "true"
この例では、ユーザーがOIDCサーバーで認証し、保護されたAPIへのリクエストで取得したJWTを提示します。Authorinoは、OIDCの設定とJKWSを検索し、JWTを検証して2つの認可ポリシーを適用します。最初の認可ポリシーは、admin
ロールではないユーザーはAPIに対してGET
HTTPリクエストしか送信することができず、2つ目の認可ポリシーは、検証されていない電子メールアドレスを持つユーザーからのリクエストを禁止しています。
もう1つの例は、API対するリクエストを行ったのが、Kubernetesサーバーのクライアントとして認証されたユーザーの場合なのか、APIキー(各APIキーはKubernetes Secret
リソースとして保存されています)により認証されたユーザーの場合なのか、2つのパターンが考えられるAPIのケースです。認可の部分については、Regoで書かれた1つのポリシーで、Kubernetesで認証されたユーザーはAPIにフルアクセスできるのに対し、APIキーで認証されたユーザーはUTCの午前8時前にのみAPIにアクセスできるとしています。
apiVersion: apiVersion: authorino.kuadrant.io/v1beta1 kind: AuthConfig metadata: name: my-api-protection-2 spec: hosts: - my-other-api.io identity: - name: k8s-users kubernetes: {} - name: api-key-users apiKey: labelSelectors: audience: api-user credentials: in: custom_header keySelector: X-APIKEY authorization: - name: my-policy opa: inlineRego: | k8s_user { input.auth.identity.iss == "kubernetes.default.svc" } api_key_user { input.auth.identity.kind == "Secret" } before_8am { beginning_of_day := floor(time.now_ns()/86400000000000)*86400 (input.context.request.time.seconds - beginning_of_day) < (8*3600) } allow { k8s_user } allow { api_key_user; before_8am }
Authorinoについてもっと詳しく知るには
もし、この記事に興味を持っていただき、Authorinoについてもっと知りたいと思われたなら、GitHubのAuthorinoリポジトリをチェックしてみてください。様々なのユースケースに基づいた多くのユーザーガイドとチュートリアル、アーキテクチャとAuthorinoの動作に関する詳細な情報、ドキュメント化された全機能のリストなどの資料があります。
Authorinoは現在ベータ版であり、公式リリースはまもなく開始される予定です。Red Hatのいくつかのチームは、Authorinoの機能に関するユースケースを調査してきており、ソリューションの設計をしています。このプロジェクトに参加し貢献するのはとても刺激になることでしょう。
ぜひSlackのオープンチャンネルに参加してみてください: kuadrant.slack.com