Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Open Policy Agentを用いたAPI Gatewayの認可制御 / Authori...

Rina Ueno
September 17, 2021

Open Policy Agentを用いたAPI Gatewayの認可制御 / Authorization in API Gateway using Open Policy Agent

Rina Ueno

September 17, 2021
Tweet

More Decks by Rina Ueno

Other Decks in Technology

Transcript

  1. © Hitachi, Ltd. 2021. All rights reserved. Open Policy Agentを⽤いたAPI

    Gatewayの認可制御/ Authorization in API Gateway using Open Policy Agent Hitachi OSS Tech Talk#1 2021.09.17 Hitachi, Ltd. R&D Group Rina Ueno
  2. © Hitachi, Ltd. 2021. All rights reserved. 認可制御へのOPAの適⽤ 本セッションはOPAのユースケースのうち、認可制御を⾏う 1

    6 © Hitachi, Ltd. 2021. All rights reserved. 2-1 OPAの主なユースケース Kubernetes CI/CD Authorization Service Mesh pAPI GWなどでの認可処理 pRBAC, ABAC, JWT(JSON Web Token) pPath, HTTP Method pService間 でのアクセス制御 pSource , Destination pJWT/x509 SVIDs pManifestの検査 pLabel pResource Requests/Limits p自動/継続的な検査 pDependency (Image, Package) pK8s Configs, Resources Check
  3. © Hitachi, Ltd. 2021. All rights reserved. 2 1. API

    Gatewayと認可制御 2. API GatewayへのOPA適⽤⽅式 3. API GatewayとOPA連携の実装例 4. OPAの注意点とその対策 ⽬次
  4. © Hitachi, Ltd. 2021. All rights reserved. APIアクセス制御にはセキュリティ機能のとして「認証」「認可」がある API Gatewayのアクセス制御

    4 ※ シングルサインオン(SSO)とは、1度システム利⽤開始のユーザー認証 (ログイン) を⾏う と、複数のシステムを利⽤開始する際に、都度認証を⾏う必要がない仕組み。 API Gateway アクセス アクセス Client API API API SSOサーバ ユーザID管理 エンドユーザ API管理、 アクセス制御 (認可を含む) ユーザは誰? APIへのアクセス権限はある?
  5. © Hitachi, Ltd. 2021. All rights reserved. API Gatewayで認可制御を⾏う上での課題 5

    認可処理の再利⽤性の向上 API API 認可処理や設定⽅法がAPI GatewayやSSOの機能のソ フトウェアの仕様に依存する。類似の処理でも使⽤するソフ トごとに個別で設計・設定する必要がある。 認可処理のテスト容易性の向上 API Gateway は⼀般に認可判定処理とアクセス制御の 処理が⼀連で⾏われるため、認可判定のみのテストが困 難。認可判定の単体テストのために実環境へのAPI Gatewayデプロイやダミーアクセス等が必要になる。 Log
  6. © Hitachi, Ltd. 2021. All rights reserved. Open Policy Agent

    (OPA) の活⽤ 6 • 軽量かつ汎⽤的なポリシーエンジン • ポリシーに反するデータを検出 • ポリシーはコード化してファイルに記述 • CNCF Graduated Project 開発時や運⽤時におけるルールを規定したもの Policy as Code
  7. © Hitachi, Ltd. 2021. All rights reserved. API GatewayでのOPA活⽤のメリット 8

    ポリシーロジックとビジネスロジックの分離 → 認可処理とAPI Gatewayの依存性を排除 再利⽤性 OPAで認可制御を共通化。 認可処理をコード化すれば、 類似案件に再利⽤しやすい。 テスト容易性 • 認可処理のみのテストが可能 • OPAは単体テスト機能を持ち、 テスト⾃動化もしやすい。 API Gateway Client API SSOサーバ 認証 アクセス制御 (認可を含む) OPA 認可 ポリシーロジック ビジネスロジック
  8. © Hitachi, Ltd. 2021. All rights reserved. Token Introspection型のOPA適⽤パターン 9

    Ø OAuth 2.0の Token Introspectionを⽤い て、SSOサーバにトークンの有効 性を検証させる⽅式 Ø 利点 • シンプルで実装しやすい • ⼀般でよく使われる ※ OAuth 2.0の署名検証を⽤いた「署名検証型のOPA連携パターン」も検討した。 API Gateway Resource Server A-3. トークンの要求 A-1. 認証(OIDC, SAML, etc.) A-4. トークン発⾏ (JWS, etc.) B-7. アクセス (A-1~A-4は初回のみ実施) • 属性の取得 : JWSのParse • アクセス可否の判定 : URL・属性から判定 (true/false) Client App. OPA REST Server mode B-6. アクセス制御 B-4. 認可判定 B-3. Token Introspection SSO B-1. アクセス (with JWS) B-5. 結果通知 (true/false) B-2. 認可依頼 (with JWS) A-2. 認証処理
  9. © Hitachi, Ltd. 2021. All rights reserved. • 銀⾏⼝座へのアクセスを模したサンプル •

    ClientごとにScopeを設定。ScopeとHTTP Methodを対応させてアクセス制御 SSO Server OPAによるAPI Gatewayアクセス制御のシナリオ例 11 Users Clients Scope 備考 john kakeibo account-read 家計簿アプリ atm account-read account-write ATMアプリ an_account Realm GET /bankaccount POST /bankaccount ※API GatewayやOPAは シナリオに直接関係しないため省略 銀⾏⼝座取引API 凡例 Access Denied Access Allowed <Scheme> { "id" : <filled automatically>, "update_time": <filled automatically>, "operation" : "[deposit|withdrawal]", "expense" : "", "memo" : "" } kakeibo atm john Users Clients scope: account–read が必要 scope: account–write が必要
  10. © Hitachi, Ltd. 2021. All rights reserved. システム構成 • Amazon

    API Gatewayを使⽤ • API Gatewayの認可処理はLambda Authorizerを⽤い、その内部でOPAを動作 12 クライアント 銀⾏⼝座取引API 認可処理 AWS EC2 Instance Keycloak® Subnet AWS Lambda Authorizer OPA Lib. Amazon API Gateway 7. アクセス 5. 認可判定 読み込み 4. Token Introspection Amazon VPC Endpoint 1. JWSトークン取得(ログイン処理) 2. アクセス (with JWS) 3. 認可依頼 (with JWS) 6. 結果通知 (true/false) AWS Lambda (BankApp) Amazon S3 Bucket policy.rego data.json AWS EC2 Instance Client App. 2. アクセス (with JWS)
  11. © Hitachi, Ltd. 2021. All rights reserved. OPAのポリシー 1/3 (ルール)

    13 package authz # What is this? # # Token Introspection方式でトークンの正当性をチェックし、 # その後、jwsトークン内のrolesとHTTP MethodsからRBACベースの認可判定を行う # 入出力のサンプルは末尾に記載 default allow = false default authenticate = false default authorize = false # アクセス制御を判断するメインの処理。 # authenticate == true && authorize == true が条件 allow { authenticate authorize } # 処理時間最適化のため、decodeは1回で済ませる params := get_cid_and_scopes(input.access_token) # token_intospectionを用いたトークン正当性チェックのルール # JWSのClient IDがdataで指定した値の場合、対応するClient Secretとともに token_introspectionを実行し、 # そのリクエストが成功し(200)、かつtokenがactiveであればtrue authenticate { some x params.client_id == data.clients[x].id client_secret := data.clients[x].secret keycloak_url := get_url(data.base_url, data.realm, data.introspect_format) result := token_introspection(input.access_token, keycloak_url, params.client_id, client_secret) result.status_code == 200 result.active == true } # JWS内のscopeとHTTP Methodを用いた認可チェックのルール # grants内に指定されたRole(account-read/account-write)があり、 # かつHTTP MethodがRoleに許可されたactionならばtrue authorize { some x params.scopes[_] == data.grants[x].role upper(input.method) == data.grants[x].action[_] }
  12. © Hitachi, Ltd. 2021. All rights reserved. OPAのポリシー 2/3 (関数)

    14 token_introspection( access_token, keycloak_url, client_id, client_secret, ) = {"status_code": status_code, "active": active} { # Keycloakにtoken introspectionを行う関数 # Keycloakの token/introspect にpostリクエストを投げ、ステータスコードとトークン 正当性を返す # # Args: # access_token (string): jwsのアクセストークン # keycloak_url (string): Token Introspectionを行うURL。realm情報が 埋め込まれているため注意 # client_id (string): クライアントの名前。今回はbank_app # client_secret (srting): クライアントのシークレット情報。詳しくはKeycloak のドキュメント参照 # # Returns: # object: 以下2種のデータを含む # status_code (int) : HTTPのstatus code。200が正常 # active (boolean) : トークン正当性 auth := base64.encode(concat(":", [client_id, client_secret])) body := urlquery.encode_object({ "token_type_hint": "access_token", "token": access_token, }) resp := http.send({ "method": "post", "url": keycloak_url, "raw_body": body, "headers": { "Content-Type": "application/x-www-form-urlencoded", "Authorization": concat(" ", ["Basic", auth]), }, }) status_code := resp.status_code active := resp.body.active }
  13. © Hitachi, Ltd. 2021. All rights reserved. OPAのポリシー 3/3 (関数)

    15 get_cid_and_scopes(access_token) = {"client_id": client_id, "scopes": scopes} { # JWSトークンをデコードし、client_idとscopesを抽出する関数 # # Args: # access_token (string): decode対象のjwsトークン # # Returns: # object: 以下2種のデータを含む # client_id (string) : JWSが指定するClient ID # scopes (list of strings) : JWSのトークン正当性 [_, payload, _] := io.jwt.decode(access_token) client_id := payload.azp scopes := split(payload.scope, " ") } get_url(base_url, realm, format) = url { # 引数を基にKeycloakのURLを生成する関数 # # Args: # base_url (string): プロトコルとドメインとポート番号。 http://example:8080 など # realm (string): Realm名 # format (string): URLの雛形。変数は%vで表現。 # # Returns: # string: KeycloakのURL url := sprintf(format, [base_url, realm]) } #--------------------------------------------- # 入力サンプル # { # "access_token": <トークン>, # "method": "get" # } # -------- # 出力サンプル(result[0].expressions[0].value.allowが判定結果) # { # <出力結果> # }
  14. © Hitachi, Ltd. 2021. All rights reserved. JSONファイルを⽤いた固有情報の分離 16 案件固有データ

    data.json { "base_url": "http://demo.ap-northeast-1.compute.internal:8080", "realm": "an_account", "introspect_format": "%v/auth/realms/%v/protocol/openid-connect/token/introspect", "clients": [ { "id": "kakeibo", "secret": "c109740e-4fe8-47be-82bf-5ad41c9f00a7" }, { "id": "atm", "secret": "0239a3e0-5b6f-462c-af8d-5cc128c4e78d" } ], "grants": [ { "role": "account-read", "action": [ "GET" ] }, { "role": "account-write", "action": [ "POST", "PUT" ] } ] } 案件ごとに異なる値はRegoファイル(ポリシー)から分離してJSONファイルに集約 →ポリシーの可搬性向上
  15. © Hitachi, Ltd. 2021. All rights reserved. OPAを⽤いた認可処理テストの実⾏例 17 「トークンとメソッドの記述」と、「OPAのREPLでテスト実⾏するコード」を作成

    ⼊⼒データ input.json { "access_token": <access token>, "method": "get" } ポリシー実⾏コード eval.sh #!/bin/bash opa eval --fail -i input.json -d policy.rego -d data.json "data.authz" ポリシー実⾏⽤のファイルディレクトリ $ tree . ├── data.json ├── eval.sh ├── input.json └── policy.rego
  16. © Hitachi, Ltd. 2021. All rights reserved. 注意点1 Rego ⾔語の学習容易化

    Rego ⾔語での特有な記述⽅法に慣れるまではポリシーの作成コストが⼤きい 20 • ⼀般的なユースケースについて作成 • 学習/作成時間の削減 コードのサンプルやガイドラインを作成 • 関数の説明⽂を記述 • ポリシーの処理の理解の容易化 Docstring ※1の記述 ※1 Docstring:Pythonのコメント表記⽅式 sample- policy- 1.rego sample- policy- 2.rego sample- policy- 3.rego OPA Repo. # JWSトークンをデコードし、client_idとscopesを抽出する関数 # # Args: # access_token (string): decode対象のjwsトークン # # Returns: # object: 以下2種のデータを含む # client_id (string) : JWSが指定するClient ID # scopes (list of strings) : JWSのトークン正当性
  17. © Hitachi, Ltd. 2021. All rights reserved. 注意点2 挙動や処理のトレースの容易化 OPAはルールの判定結果しか出⼒されず、出⼒を得るまでの挙動/処理を追いにくい

    trace関数を活⽤し、処理を追えるようにする 21 ※1 Explanationの出⼒⽅法の情報がなかったため、筆者が内容を調査して公式ドキュメントに記載(merge済) API Parameter Example CLI --explain opa eval --explain=notes --format=pretty 'trace("hello world")' HTTP explain=notes curl localhost:8181/v1/data/example/allow?explain=notes&pretty REPL notes n/a trace 関数 § ルールや関数内で処理途中の変数を出⼒するなど`printf`のように利⽤できる。引数は⼀つの⽂字列のみ。 § trace関数の処理結果の出⼒にはExplanationの出⼒を有効化する必要あり※1
  18. © Hitachi, Ltd. 2021. All rights reserved. 参考) Fregotを⽤いたOPAのデバッグ Fregotとは?

    § Fugue Rego Toolkit § Rego⾔語開発を⽀援するサードパーティーツール § CLIにて対話形式でのポリシーのステップイン実⾏ が可能(REPL機能; 右画像) 利点 § エラーメッセージが充実 注意点 § regoエンジンが古く、最近の関数には未対応 最終更新: 2021.4.8 § data.json(固有値記述ファイル)には未対応 22 fregotのHPより引⽤
  19. © Hitachi, Ltd. 2021. All rights reserved. まとめ 1. OPAを⽤いた認可制御を紹介

    ◇ メリットは「認可処理の再利⽤性・テスト容易性の向上」 ◇ API GatewayへのOPA適⽤は「Token Introspection⽅式」 2. Amazon API GatewayとOPA連携の実装例を紹介 3. 事業へOPA適⽤する際の注意点とその対策を紹介 ◇ 注意点「Rego ⾔語の学習容易化」のため、 サンプルコードやコーディングガイドラインを作成、Docstringに関数説明を記述 ◇ 注意点「デバッグの容易化」のため、trace関数を活⽤し処理を追跡 23
  20. © Hitachi, Ltd. 2021. All rights reserved. 商標 § Open

    Policy Agentは、 The Linux Foundationの⽶国またはその他の国における登録商標または 商標です。 § Keycloakは、Red Hat, Inc.の⽶国またはその他の国における登録商標または商標です。 § Fregotは、 Fugue, Inc.の⽶国またはその他の国における登録商標または商標です。 § Amazon Web Services, Amazon API Gateway, Amazon VPC, Amazon EC2, AWS Lambda, Amazon S3, AWS CloudFormation, Amazon Cognito, AWS IAM は、⽶国および/またはその他 の諸国における、Amazon.com, Inc. または その関連会社の商標です。 § その他記載の会社名、製品名、サービス名、その他固有名詞は、 それぞれの会社の商標または登録商標です § 本発表中の⽂章、図では、TM、🄬マークは表記しておりません。 24