はじめに
API Connectのガバナンス・サービス機能を触ってみたので、概要と使用方法を備忘録として残しておきます。
公式ドキュメント:
https://www.ibm.com/docs/ja/api-connect/saas?topic=apis-configuring-governance-in-api-manager
ガバナンス機能とは?
IBM API Connectのアドオン機能で、API開発プロセスにおいて組織のガバナンス・ポリシーやベストプラクティスを検証・適用するためのサービスです。
事前に定義されたルールにAPIおよび製品ドキュメントが準拠しているかどうかをチェックすることが可能となります。
主な機能
-
カスタムルールセットの作成:
- Swagger(OpenAPI)、AsyncAPI、製品ドキュメントをチェックするためのルールをまとめたセットを作成
- 複数のルールセットを定義可能
-
バリデーションスキャン:
- カタログやスペースに対してスキャンを実行し、ポリシーやルールに準拠しているか確認
- API単位での検証のほか、カタログ内のAPIや製品を一括でスキャンすることも可能
ガバナンス機能の概要
-
目的:
- Swagger/OpenAPI/AsyncAPI、さらにProductドキュメントを、ルールセットに基づいて検証(lint)
- これにより、組織の設計基準・ベストプラクティス・セキュリティ方針に沿っているかをチェック可能
-
実装の中身:
- OpenAPIのリンティングツールであるSpectral をベースにしており、Spectralのコア関数のみ利用可能(カスタムJS関数は不可)
-
ルールセットの種類:
- Provider org ルールセット(組織カスタム、自分で作成可能)
- Global ルールセット(IBM/Spectral既定のルールセットで、編集不可)
この機能を使用するメリット
-
設計のばらつきを自動で検出:
- 命名・メタデータ不足・バージョニングの形式・セキュリティ定義の有無などを機械的に検知
- レビュー効率の向上
-
運用の前倒し品質保証:
- 公開前の強制バリデーション(10.0.10.0 Tech Preview)まで持っていくと、品質ゲートとして機能する(後述)
-
結果の可視化:
- 改善点が明確になり、チームで共通言語化
カスタムルールセットの作成
前提条件
-
管理サブシステムでガバナンスを有効化(管理者作業):
- 有効化されていると、API Manager左メニューに盾アイコン(Governance)が表示されます
-
ロール:
- ガバナンスの構成にはOrganization Administrator、Owner、または権限 Settings: Manage を持つカスタムロールが必要
ルールセットの作成方法
ルールセットの作成には以下の3つの方法があります。
- yamlを書いてインポートする方法
- GUI上で作成する方法
- CLIで追加する方法
今回はyamlのインポートとGUI上の作成の2つの方法で、以下の仕様を満たすルールセットを作成してみます。
ルールセットの仕様
- APIドキュメントをスキャンするルールセット
- 違反した場合は重大度
warn
で警告メッセージを表示 - ルールセットには以下の2つのルールが入っている
- ルール1: アセンブリーフローにGatewayScriptが含まれていなければ警告
- ルール2: アセンブリーフローにParseが含まれていなければ警告
API ConnectのガバナンスはSpectralのルールセット記法に準拠します(Given/Then で対象と検査を定義)。
方法1:yamlのインポート
テキストエディタで以下のようなスクリプトを作成します。
Spectralの記法については以下のリンクを参考にしています。
extends:
- "spectral:oas"
formats:
- oas3
rules:
require-gatewayscript-in-assembly:
description: "アセンブリーフローに少なくとも1つ 'gatewayscript' ポリシーが含まれていることを求めます。"
message: "アセンブリに 'gatewayscript' が見つかりません。少なくとも1つ追加してください。"
severity: warn
given: $.x-ibm-configuration.assembly.execute
then:
- function: schema
functionOptions:
schema:
type: array
contains:
type: object
required: ["gatewayscript"]
require-parse-in-assembly:
description: "アセンブリーフローに少なくとも1つ 'parse' ポリシーが含まれていることを求めます。"
message: "アセンブリに 'parse' が見つかりません。少なくとも1つ追加してください。"
severity: warn
given: $.x-ibm-configuration.assembly.execute
then:
- function: schema
functionOptions:
schema:
type: array
contains:
type: object
required: ["parse"]
- Given:JSONPathでどの部分を検査するか
- Then:どの関数でチェックするか(truthy/pattern/definedなどSpectralコア関数)
- severity:error / warn / info / hint /off
次に、API Connectにこのyamlをインポートします。画面左のメニューからガバナンスを選択します。
ルール・セットタブから追加をクリックし、インポートを選択します。
ルールセットのタイトルを設定します。
任意でこのルールセットの説明や、タグを設定することも可能です。
このルールセットは後ほどスキャンに使用するため、公開を選択します。
方法2:最初から作成
GUI上からルールセットを作成することも可能です。
API Connectの画面左のメニューからガバナンスを選択します。
ルール・セットタブから追加をクリックし、最初から作成を選択します。
ルールセットのタイトルを設定します。
任意でこのルールセットの説明や、タグを設定することも可能です。
重大度と、ルールセットの内容を記載します。
$.x-ibm-configuration.assembly.execute
- function: schema
functionOptions:
schema:
type: array
contains:
type: object
required: ["gatewayscript"]
こちらも方法1の内容と同一です。
$.x-ibm-configuration.assembly.execute
- function: schema
functionOptions:
schema:
type: array
contains:
type: object
required: ["parse"]
スキャン(検証)の実施
次に、上記の手順で作成したルールセットを使用して、スキャンを行います。
今回はスキャン対象のAPIとして、以下のリンクに記載のサンプルAPIを使用します。
https://github.com/ibm-apiconnect/sample-orders-api/blob/main/api/orders_api.yaml
openapi: 3.0.1
info:
title: Order
description: View and track your orders and deliveries.
termsOfService: https://github.com/ibm-apiconnect/sample-orders-api
contact:
name: IBM Corporation
url: https://www.ibm.com/products/api-connect
version: 2.0.0
x-ibm-name: ibm-sample-order-api
externalDocs:
description: "Github project for this API, containing source code and deployment\
\ pipeline"
url: https://github.com/ibm-apiconnect/sample-orders-api
servers:
- url: /order
security:
- clientID: []
paths:
/{orderNumber}:
get:
summary: Retrieve the details of your order.
parameters:
- name: orderNumber
in: path
description: Order number to lookup - you should find this in your confirmation
e-mail
required: true
schema:
type: string
responses:
"200":
description: Order found successfully
content:
application/json:
schema:
title: Order Details
type: object
properties:
order_number:
title: Order Number
type: string
example: ORD00989792
tracking_status:
title: Tracking Status
type: object
properties: {}
shipped_at:
title: Date Shipped
type: string
format: date-time
created_at:
title: Date Order Created
type: string
format: date-time
status:
title: Order Status
type: string
enum:
- SHIPPED
- PICKED
- PENDING
- DELIVERED
tracking_reference:
title: Tracking Reference
type: string
components:
securitySchemes:
clientID:
type: apiKey
name: X-IBM-Client-Id
in: header
x-ibm-configuration:
properties:
target-url:
value: "https://sample-api.us-east-a.apiconnect.automation.ibm.com/orders/order/{orderNumber}"
description: URL of the proxy policy
encoded: false
cors:
enabled: true
gateway: datapower-api-gateway
type: rest
phase: realized
enforced: true
testable: true
assembly:
execute:
- invoke:
title: order lookup
version: 2.0.0
verb: keep
target-url: $(target-url)
follow-redirects: false
timeout: 60
parameter-control:
type: blocklist
values: []
header-control:
type: blocklist
values: []
inject-proxy-headers: true
persistent-connection: true
backend-type: json
output: order
description: Retrieves order data from the fulfillment system using the key
of the provided order number.
- parse:
version: 2.1.0
title: parse response
parse-settings-reference:
default: apic-default-parsesettings
input: order
output: order
description: Parse the JSON from the order fulfillment system so that the
values can be used later in the flow.
- map:
version: 2.0.0
title: map input to lambda
inputs:
input:
schema:
type: object
properties:
delivery_method:
type: string
name: delivery_method
tracking_reference:
type: string
name: tracking_reference
variable: order.body
outputs:
output:
schema:
type: object
properties:
shipper:
type: string
name: shipper
reference:
type: string
name: reference
variable: message.body
content: application/json
actions:
- set: output.shipper
from: input.delivery_method
- set: output.reference
from: input.tracking_reference
- invoke:
version: 2.2.0
title: "lambda: track shipment"
backend-type: detect
header-control:
type: blocklist
values: []
parameter-control:
type: allowlist
values: []
http-version: HTTP/1.1
timeout: 60
verb: POST
chunked-uploads: true
persistent-connection: true
cache-response: protocol
cache-ttl: 900
stop-on-error: []
websocket-upgrade: false
target-url: https://plgej7e2skungmxzjakprvhe340qkrkl.lambda-url.us-east-1.on.aws/
output: tracking
graphql-send-type: detect
description: Call lambda function to look up the tracking for a parcel with
the associated shipping company.
- map:
version: 2.0.0
title: combine data for response
inputs:
tracking:
schema:
type: object
properties:
trackResponse:
type: object
name: trackResponse
properties:
shipment:
type: object
name: shipment
properties:
package:
type: object
name: package
properties:
activity:
type: array
name: activity
items:
type: object
properties:
status:
type: object
name: status
variable: tracking.body
order:
schema:
type: object
properties:
order_number:
type: string
name: order_number
created_at:
type: string
name: created_at
shipped_at:
type: string
name: shipped_at
status:
type: string
name: status
tracking_reference:
type: string
name: tracking_reference
variable: order.body
outputs:
output:
schema:
type: object
properties:
order_number:
type: string
name: order_number
status:
type: string
name: status
shipped_at:
type: string
name: shipped_at
tracking_reference:
type: string
name: tracking_reference
tracking_status:
type: object
name: tracking_status
created_at:
type: string
name: created_at
variable: message.body
actions:
- set: output.order_number
from: order.order_number
- set: output.tracking_status
from: tracking.trackResponse.shipment.package.activity.status
- set: output.shipped_at
from: order.shipped_at
- set: output.tracking_reference
from: order.tracking_reference
- set: output.status
from: order.status
- set: output.created_at
from: order.created_at
finally: []
activity-log:
enabled: true
success-content: activity
error-content: payload
x-original-swagger-version: "2.0"
このAPIのアセンブリーフローは以下のようになっています。
このアセンブリーフローにはparseが使用されていますが、gatewayscriptは使用されていません。
そのため、上記手順で公開したルールセットに含まれている以下の2つのルールのうち、ルール1のみが発火すれば想定通りの挙動となります。
- ルール1: アセンブリーフローにGatewayScriptが含まれていなければ警告
- ルール2: アセンブリーフローにParseが含まれていなければ警告
スキャンの実行はガバナンスのメニューから行うことも可能ですが、今回は左メニューの開発でAPIを開発した際にスキャンを実施するユースケースを想定します。
画面右上の妥当性検査をクリックし、ルール・セットを...
(ルール・セットを使用して API を検証)を選択します。
ルールセットとして、先ほど追加したsample-ruleset
を選択します。
APIルールセットにタグを付け、API側のtagsと一致させておくと、スキャン時に該当ルールセットが自動選択され時短になります。
特に、スキャンを行いたいルールセットが複数ある場合に便利です。
ルールセット内のルールが選択されているので、そのままValidateを選択します。
Validateを実行するとスキャンの結果が表示されます。
想定通り、gatewayscriptが存在しないことによる警告が表示されています。
Locationには、違反が検出されたパスが表示されています。ここから、どの箇所を修正すればよいかを確認可能です。
(今回の場合はフロー全体の中でGatewayScriptがないというエラーのためLocationの表示にはあまり意味がなさそうに見えますが、例えばフロー内のどこかのgatewayscriptの記述内容に違反がある、等のエラーの際に、Locationの表示から違反箇所が何番目のポリシーかをすぐに特定することができます。)
また、上記画面のダウンロードボタンをクリックすることで、エクスポートされたcsvファイルをダウンロードすることも可能です。
今回は1つのAPIに対してスキャンを実行しましたが、カタログ内のAPIに対して一括でスキャンを行うことも可能です。
Governance enforcement
バージョン10.0.10.0 では「Governance enforcement (Technology Preview)」として、カタログ公開前にAPI/Productを強制バリデーションする機能が追加されています。 
Enforcementを有効化している場合、ルールセットでerrorが検出された際にプロダクト公開可否の判定を設定可能です。
(例:設定がStrictの場合は、エラーがある限り公開不可など)
さらに詳しい情報をお探しの方へ
IBMの最新情報、イベント情報、さらに役立つ資料は、以下のIBM Communityでも発信・格納されています。
最新のトレンドや有益な情報をチェックするために、ぜひご覧ください!
-
WebSphere: IBM Community - WebSphere
WebSphere関連の最新情報やディスカッション、イベント情報、技術資料を公開中!
-
ELM (Engineering Lifecycle Management): IBM Community - ELM
ELMに関する最新のイベント情報、ナレッジ共有、便利なドキュメントをチェック!
-
Integration: IBM Community - Integration
Integrationに関する最新のイベント情報、ナレッジ共有、便利なドキュメントをチェック!