はじめに
IBM Cloud上のAPI Connectを試してみた時の作業ログです。
オンプレミスのサーバー上にREST APIでアクセスできるサービスがあってそれをAPI Connectで外部公開したい、というシナリオを想定します。
その場合、API Connect(IBM Cloud)とオンプレのサーバーをセキュアに接続する必要がありますが、そこを実現してくれるSecure Gatewayというサービスサービスがあります。今回はそのSecure Gatewayを使ってみます。
バックエンドのサービスはz/OS Connect(z/OS上のサービスを公開するためのコンポーネント)で公開されたCICSアプリケーションを想定します。
Secure Gateway Client用のマシンにはWindows10を使用します。
関連記事
IBM API Connect 関連メモ - (1)既存REST APIの取り込み
IBM API Connect 関連メモ - (2)API Connectツールキットを使用したNode.jsアプリ作成(Loopback)
IBM API Connect 関連メモ - (3)カタログ、開発者ポータルの構成
IBM API Connect 関連メモ - (4)各種APIの管理
IBM API Connect 関連メモ - (5)Secure Gateway経由でのz/OS Connectとの連携
IBM API Connect 関連メモ - (6)API Connect-z/OS Connect間TLS接続
IBM API Connect 関連メモ - (7)z/OS Connect 基本認証 + ID伝播
IBM API Connect 関連メモ - (8)z/OS Connect 連携におけるインターフェースの浄化
IBM API Connect 関連メモ - (9)z/OS Connect 連携まとめ
事前調査
IBM Cloud上のアプリケーション(今回の場合API Connectを想定)と、オンプレ上のリソース(今回の場合REST APIでアクセスできるサービスを想定)をつなために、IBM Cloud上にSecure Gateway Serviceを立てて、オンプレ環境とのつなぎとなるサーバーにSecure Gateway Clientを立て、論理的な接続経路を構成することになります。
「IBM Cloud => オンプレ」、「IBM Cloud <= オンプレ」の両方向の通信がサポートされますが、今回のケースでは前者の構成をとることになります。
バックエンド・サービス情報
オンプレ環境にバックエンドのサービスがあって、そのAPIをIBM Cloud上のAPI Connectで管理したいという前提です。
バックエンドのサービスの実装はなんでもよいのですが、ここでメインフレーム上のサービス(実体としてはCICSのアプリをz/OS Connect EEでREST APIで呼び出せるようにしたもの)を想定します。
このバックエンドのサービスを呼び出すためのエンドポイントは、"eplexa:30681"とします。
(例えば、オンプレ環境のネットワークからは、http://eplexa:30681/showroomdemo/v1/isecics/stock/CITR
というようなURLでアクセスできるものとします。)
このエンドポイントはあくまでオンプレのネットワーク上でのみ有効なものであり、インターネット向けに外部に公開しているものではない、というのが前提です。
Secure Gateway環境構築
Secure Gateway Serviceの追加
参考:ゲートウェイの追加
IBM CloudのカタログからSecure Gateway を選択
Cloud FoundryサービスにSecure Gatewayが作成されるのでこれをクリック
ゲートウェイ名の右の設定アイコンをクリックし、編集をクリックします
クライアントの追加
参考: クライアントの追加
上で作成したゲートウェイの管理画面から、クライアントの接続ボタンをクリックします。
WindowsマシンをSecure Gateway Clientとするので、Windowsのインストーラーをダウンロードします。
ダウンロードしたインストーラーを実行します。
参考: クライアントのインストール
※本当はここでACLファイルを作成してそのファイル名を指定する必要があったらしいのですが、最初不要かと思ってスルーしちゃってました。後述の「クライアントにACL設定追加」の節を参照のこと。
Windowsのサービスのウィンドウを開いて、IBM Cloude Secure Gateway Serviceが稼働していることを確認します。
また、サービスとして実行するのはよいですが、自動実行されるのは鬱陶しいので、手動実行に変えておきます。
Windowsのサービスが実行中になっていることを確認後、IBM CloudのSecure Gateway Serviceの画面を見ると、以下のようなアイコンが表示されて、クライアントとの接続がされたことが確認できます。
宛先の追加
参考: 宛先の追加
Secure Gateway Serviceの宛先タブから、+ボタンをクリック
Cloudアプリケーション(API Connect)とSecure Gateway Server間プロトコルはHTTPを選択して次へ
最初あまり考えずにHTTPにしてしまったが、後々APIConnect - z/OS Connect間をTLSとかで接続することを考えるとTCPでよい(後で修正)。
Secure Gateway Client - バックエンドサービス間の認証はNoneを選択して次へ
IPテーブルで接続できるIPを絞ったりすることができるようですが、ここでは一旦そのまま次へ
作成された宛先の設定アイコンをクリックすると、クラウド側のホスト:ポートなどが確認できます。
これで、ここに示されているホスト名:ポートにアクセスすると、宛先リソースにフォワードされるのかなと思ったのですが、リクエスト投げても繋がらない...
右上に赤い手のマークが出て、「ACLによりアクセスがブロックされています」と出てますが、これのせい?
補足: Secure Gatewayの位置づけについて
参考: Secure Gateway Service: FAQ
Secure Gateway Serviceは、OSIモデルの第4層にあたります。
上の記述にあるように、Secure GatewayはOSIモデルの第4層(トランスポート層)に相当します。TCP/UDPのレイヤーですね。つまり、SSHトンネリング等と同じような位置づけだと考えればよさそうです。
それなのに、上のプロトコルでTLSだとかHTTPだとかが選べるのでそれが何を意味するのか混乱したのですが、どうやら、クラウドアプリ - Secure Gateway Server 間、および、オンプレ上のSecure Gateway Client - バックエンドサーバー間をセキュアな構成にするっていうのができるっぽいです。
End to End (クラウドアプリ-バックエンドサーバー間)でセキュアな構成を考えて、Secure Gateway部分は単なる経路として扱うのであれば、とりあえずSecure Gatewayのレベルでのセキュリティは考えなくてもよいかと思います。
クライアントにACL設定追加 その1 / NG編
クライアントの追加のステップで、スルーしてしまっていたACLの設定を追加してみます。
クライアントには、<InstDir>\ibm\securegateway\client\secgw.cmd
を実行して起動されるツールがあるようなので使ってみます。こいつを実行すると...
なんかローカルでWebアプリ的なものが動いてブラウザが起動してきました。
アクセス制御リストを選択してみます。
ここの"アクセスを許可"の欄に、バックエンドサービスのホスト名:ポートを追加してみます。
反映の仕方がよく分からないので、Windowsのサービスを再起動してみました。
が、その後も状況は変わらず。
イマイチ反映方法が分からなかったのであきらめました。
クライアントにACL設定追加 その2 / OK編
上のやり方がNGだったので、別の方法を試します。
<InstDir>\ibm\securegateway\client\SampleACLFile.txt
というのが提供されていたので、これをACLFile.txtという名前でコピーして、以下のように編集します。
acl allow eplexa:30681
で構成ファイルが同ディレクトリのsecuregw_service.configに保持されているようなので、こいつを編集して上のACLFile.txtをACL_FILE=に指定します。
#Config file for Secure Gateway Client, to start as a Windows Service.
#PLEASE AVOID ANY RESIDUAL WHITE SPACES
#Enter the gateway ids separated by single spaces
GATEWAY_ID=xxxxx
#Enter the security tokens separated by --
SECTOKEN=xxxxxx
#Enter the ACL files separated by --
ACL_FILE=ACLFile.txt
# Enter the proxy info if you want to start the client with the proxy
PROXY=
#Enter the log levels separated by --
LOGLEVEL=INFO
#Enter if you want to use client UI (Y/N)
USE_UI=
#Enter the port for client UI
PORT=9003
#Enter the password for client UI
PWD=
#Enter the language for command line interface; acceptable values are en, de, es, fr, it, ja, ko, pt-BR, zh, zh-TW
LANGUAGE=ja
#Enter the startup options separated by single spaces, no "" is needed
#Accepted values are mentioned in this document
#https://cloud.ibm.com/docs/services/SecureGateway?topic=securegateway-client-interacting#startup-args
SECGW_ARGS=
これでSecure Gateway ClientのWindowsサービスを再起動してみます。
Secure Gatewayのクラウド側のホスト:ポートにアクセスしてみると、意図した通り、バックエンドサービスが呼び出せるようになりました!
API Connect からSecure Gateway経由でのバックエンド・サービス連携
さて、これでIBM Cloud上のAPI Connectから、Secure Gateway経由でオンプレ上のサービスにアクセスするパスは作れました。
いよいよ、バックエンドサービスのAPIをAPI Connectで管理できるようにしてみましょう。
バックエンドアクセス情報の整理
一旦、管理対象とするバックエンドサービスのAPIについて整理しておきます。
z/OS Connectは公開したAPI仕様をSwagger文書として生成してくれるので、これをAPI Connectに取り込めばよさそうです。
また、サービスのエンドポイントとしては実際にはeplexa:30681ですが、API Connectから見るとSecure Gatewayを介してのアクセスになりますので、Secure Gatewayが新たに生成したエンドポイントを使用することになります。
今回取り込むSwagger文書はこちらです。
{
"swagger" : "2.0",
"info" : {
"description" : "",
"version" : "1.0.0",
"title" : "cicsstockrestfulservice"
},
"host" : "localhost:8080",
"basePath" : "/showroomdemo/v1/isecics",
"schemes" : [ "https", "http" ],
"consumes" : [ "application/json" ],
"produces" : [ "application/json" ],
"paths" : {
"/order" : {
"post" : {
"tags" : [ "cicsstockrestfulservice" ],
"operationId" : "postCICSStockOrderService",
"parameters" : [ {
"in" : "body",
"name" : "postCICSStockOrderService_request",
"description" : "request body",
"required" : true,
"schema" : {
"$ref" : "#/definitions/postCICSStockOrderService_request"
}
} ],
"responses" : {
"400" : {
"description" : "Bad Request",
"schema" : {
"$ref" : "#/definitions/postCICSStockOrderService_response_400"
}
},
"200" : {
"description" : "OK",
"schema" : {
"$ref" : "#/definitions/postCICSStockOrderService_response_200"
}
}
}
}
},
"/stock/{groupCode}" : {
"get" : {
"tags" : [ "cicsstockrestfulservice" ],
"operationId" : "getCICSStockCheckService",
"parameters" : [ {
"name" : "groupCode",
"in" : "path",
"required" : true,
"type" : "string",
"maxLength" : 4
} ],
"responses" : {
"400" : {
"description" : "Bad Request",
"schema" : {
"$ref" : "#/definitions/getCICSStockCheckService_response_400"
}
},
"200" : {
"description" : "OK",
"schema" : {
"$ref" : "#/definitions/getCICSStockCheckService_response_200"
}
}
}
}
}
},
"definitions" : {
"getCICSStockCheckService_response_400" : {
"type" : "object",
"properties" : {
"stockCheck" : {
"type" : "object",
"properties" : {
"returnCode" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 99
},
"responseMessage" : {
"type" : "string",
"maxLength" : 80
}
}
}
}
},
"getCICSStockCheckService_response_200" : {
"type" : "object",
"properties" : {
"stockCheck" : {
"type" : "object",
"properties" : {
"returnCode" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 99
},
"responseMessage" : {
"type" : "string",
"maxLength" : 80
},
"itemList" : {
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"itemId" : {
"type" : "string",
"maxLength" : 8
},
"itemName" : {
"type" : "string",
"maxLength" : 66
},
"itemPrice" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 9999999
},
"stored" : {
"type" : "string",
"maxLength" : 1
},
"shipFrom" : {
"type" : "string",
"maxLength" : 64
}
}
},
"maxItems" : 6,
"minItems" : 6
}
}
}
}
},
"postCICSStockOrderService_request" : {
"type" : "object",
"properties" : {
"stockOrder" : {
"type" : "object",
"properties" : {
"orderList" : {
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"itemId" : {
"type" : "string",
"maxLength" : 8
},
"itemQuantity" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 9999999
}
}
},
"maxItems" : 6,
"minItems" : 6
}
}
}
}
},
"postCICSStockOrderService_response_400" : {
"type" : "object",
"properties" : {
"stockOrder" : {
"type" : "object",
"properties" : {
"returnCode" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 99
},
"responseMessage" : {
"type" : "string",
"maxLength" : 80
}
}
}
}
},
"postCICSStockOrderService_response_200" : {
"type" : "object",
"properties" : {
"stockOrder" : {
"type" : "object",
"properties" : {
"returnCode" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 99
},
"responseMessage" : {
"type" : "string",
"maxLength" : 80
},
"stockOfItemList" : {
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"itemId" : {
"type" : "string",
"maxLength" : 8
},
"stockYN" : {
"type" : "string",
"maxLength" : 1
},
"stockNum" : {
"type" : "integer",
"minimum" : 0,
"maximum" : 9999999
}
}
},
"maxItems" : 6,
"minItems" : 6
}
}
}
}
}
}
}
商品の在庫確認(参照系)とオーダー(更新系)の2種類のオペレーションがあります。
参照系のURL: GET http://eplexa:30681/showroomdemo/v1/isecics/stock/{groupCode}
更新系のURL: POST http://eplexa:30681/showroomdemo/v1/isecics/order
curlでの実行例
curl -X GET --header 'Accept: application/json' 'http://eplexa:30681/showroomdemo/v1/isecics/stock/CITR'`
curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{"stockOrder":{"orderList":[{"itemId":"CIWH0001","itemQuantity":1},{"itemId":"CIWH0002","itemQuantity":2}]}}' 'http://eplexa:30681/showroomdemo/v1/isecics/order'
API ConnectへSwagger文書の取り込み
ドラフト - API - 追加ボタン - ファイルまたはURLからAPIをインポートを選択して、上のSwaggerファイルを指定してインポートします。
"cicsstockrestfulservice 1.0.0"というAPIが作成されました。
アセンブリーの作成
操作切り替えをドラッグ&ドロップし、ケース0,1にそれぞれgetCICSStockCheckService, postCICSStockOrderServiceを割り当てます。
呼び出しをそれぞれ割り当て、タイトル、URL、メソッドを指定します。
それぞれ以下のように指定します。(URLはSecure Gatewayのホスト名:ポートを指定)
項目 | StockCheck | StockOrder |
---|---|---|
タイトル | invoke-stockCheck | invoke-stockOrder |
URL | http://xxxx.securegateway.appdomain.cloud:nnnnn/showroomdemo/v1/isecics/stock/$(request.parameters.groupCode) | http://xxxx.securegateway.appdomain.cloud:nnnnn/showroomdemo/v1/isecics/order |
HTTPメソッド | GET | POST |
最後に保存。
スキームの確認
取り込んだSwagger文書ではhttp,https両方有効になっていますが、API Connectではhttpは受け付けないようです。そのままの設定でAPIを公開しようとすると以下のように怒られることになるので、スキームの設定を変更します。
設計からスキームを選択し、httpのチェックをはずしておきます。
セキュリティー設定
以前実施した以下の手順に従って、APIキーを設定しておきます。
参考: セキュリティーの定義
製品の作成/公開
一応ダッシュボード - カタログ"Sandbox"を選択して製品のステータス見てみます。
公開済みになってます。
アセンブルからテスト
開発者ユーザーによるテスト
開発ユーザーでSandboxの開発者ポータルにログインし、API製品からcicsstockrestfulservice product 1.0.0を選択
サブスクライブ(配信登録)します
cicsstockrestfulserviceから、API呼び出しを試してみます。
クライアントID、シークレットは、この開発ユーザーがアプリケーションを作成した時に生成されたものを使用します。
参考: 開発者ポータルでのアプリケーション作成
操作の呼び出しをクリックして、正常応答が返ればOKです。
(汎用的なREST Clientからもリクエスト投げられるはず)
これで一通り、API Connect - Secure Gateway 経由でバックエンドのサービスを呼び出すところまで確認できました!