はじめに
今回はz/OS Connect周りの話が中心です。
このシリーズでは、バックエンドのサービスを提供するコンポーネントとしてオンプレ上(メインフレーム上)のz/OS Connectを想定しています。
バックエンドのサービスにアクセスする際に"基本認証"を行わせるケースを試してみます。
"基本認証"は、ユーザーID/パスワードで認証することになりますが、そのユーザー情報をどこに保持しておくか(ユーザーレジストリーとして何を使用するか)、というのは以下のような選択肢があります。
(1) server.xml上にユーザー情報を保持する (基本ユーザーレジストリー)
(2) RACF上のユーザー情報を使用する (SAFユーザーレジストリー)
(3) LDAP上のユーザー情報を使用する (LADPユーザーレジストリー)
ここでは、まず前段として、z/OS Connectの設定方法として(1), (2)のケースを試してみます。
その後z/OS Connectで認証されたユーザーIDをCICSへ伝播させてみます。
最終的にはそれをAPI Connectからアクセスしてみます。
※Angelプロセスの構成や、APIの登録などは実施済みの想定です。ここではセキュリティの設定のみにフォーカスしています。
関連記事
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 連携まとめ
全体像
ここで取り上げているのはz/OS Connectの認証、および、バックエンド(CICS)へのID伝播についての構成です。
(1)基本ユーザーレジストリーを使用した基本認証
これはserver.xml上にユーザー情報を保持しておく方法です。主に開発環境での使用が想定される機能です。
セキュリティ要件の高くないケースや手っ取り早く認証の仕組みを使いたい場合に使えます。
(基本ユーザーレジストリーを使用する場合、後述のバックエンドへのID伝播は行えません。)
基本ユーザーレジストリーの構成
ユーザーID、パスワードなどの情報をserver.xml上に定義します。
...
<basicRegistry id="basic" realm="customRealm">
<user name="FRED" password="{xor}GQ0aGw=="/>
<user name="CICS004" password="{xor}HBYcDG9vaw=="/>
<group name="DemoAdmin">
<member name="FRED" />
<member name="CICS004" />
</group>
</basicRegistry>
...
ここではFRED, CICS004という2つのユーザーを定義しています。(グループも定義していますがここでは細かなアクセス制御は触れないのであまり意味はありません。)
z/OS Connectの導入ディレクトリのwlp/binにあるsecurityUtilityというコマンドを使うとパスワードの文字列を暗号化することができます。
例えば、パスワードに"FRED"という文字列を使いたい場合には以下のように実行します。
[CICS004@EPLEX1:/V1R11/usr/lpp/IBM/zosconnect/v3r0/wlp/bin] ./securityUtility encode FRED
{xor}GQ0aGw==
これで返された結果をserver.xml上のpasswordの値として指定します。
※暗号化せずに平文でそのままパスワードをserver.xmlに指定することも可能です。
基本認証の構成
参考: 基本ユーザー・レジストリーを使用した基本認証の構成方法
適切なレベルでrequireAuthをtrueに設定します。ここではz/OS Connect全体に有効化したいので、zosconnect_zosConnectManager
要素で指定しています。
また、<webAppSecurity allowFailOverToBasicAuth="true"/>
を指定します。
...
<zosconnect_zosConnectManager
...
requireAuth="true"/>
...
<webAppSecurity allowFailOverToBasicAuth="true"/>
...
アクセス許可設定
参考: 基本ユーザー・レジストリーを使用して zosConnectAccess ロールを構成する方法
ここでは認証の仕組みの構成だけしたいのですが、最低限の認可の設定(アクセス制御)は実施しないといけないようです。認証されたユーザーがz/OS Connectにアクセスできるようにするための許可設定を行います。
(詳細なアクセス制御も行えますが、ここでは触れません。)
...
<authorization-roles id="zos.connect.access.roles">
<security-role name="zosConnectAccess">
<special-subject type="ALL_AUTHENTICATED_USERS"/>
</security-role>
</authorization-roles>
...
簡易テスト
上の設定でz/OS Connectを再起動後、z/OS Connectで公開されているREST APIを叩いてみます。
(単純にGETできるAPIで確認)
基本認証のユーザーID/パスワード指定方法はテストの仕方によって様々なので、以下いくつかのパターンでやってみます。
Chrome
サービスのURLにアクセスするとユーザーID, パスワードが聞かれるのでserver.xmlに設定した情報を入力します。
REST APIテストツール
Chromeプラグインの、Talend API Testerを使ってリクエスト投げてみます。
REST APIとして投げる場合は、Basic認証のユーザーID,パスワードは、HTTPのヘッダー情報にAuthorizationという項目を追加して、そこにBasic User:Password
という形で指定します。この時、User:Password
部分はBase64 Encodeしたものを指定します。こんな感じになります=>Basic RlJFRDpGUkVE
(FRED:FREDをエンコードしたもの)。
Base64 Encodeは以下のようなサイトでサクッとできます。
https://www.base64encode.org/
CURL
CURLコマンドだとこんな感じで確認できます。
user01@DESKTOP-U7UON7M:~$ curl -v -u FRED:FRED http://eplex1:30682/showroomdemo/v1/isecics/stock/CITR
* Trying xx.xx.xx.xx...
* TCP_NODELAY set
* Connected to eplex1 (xx.xx.xx.xx) port 30682 (#0)
* Server auth using Basic with user 'FRED'
> GET /showroomdemo/v1/isecics/stock/CITR HTTP/1.1
> Host: eplex1:30682
> Authorization: Basic RlJFRDpGUkVE
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Servlet/3.1
< Content-Type: application/json; charset=UTF-8
< Content-Language: en-US
< Content-Length: 1253
< Set-Cookie: LtpaToken2=9BYRcpuOGH3GmBvfGjOHbnYcqSLZpY728c6UcWuVuOhVwtmTerEYRPSHX55ynC5e2ytSw3IkGca/R0a590bA9gFwH2VK4OIyGrLBbkz+2/D0DwU4dx7JSLW1FX4oHQiez1jzkwR9bYwokVUaIAhDZgtUa6uEaTsHoH9E2Yu1JX+yh4iLB/pr2OjKd7kbL/nUVr58YPfxeBS+FY4Ls5B+MAY5cmv8+OANymZBGoBhdIcmkmUPl+9Cf11ta3l5x8kBkWetxYEUM7/mOZl4/lXk5yvxwtGasfJf3lY4XNSJTZ3+Rd9kkOQXKMB4hDZFdZDB; Path=/; HttpOnly
< Date: Fri, 10 Jul 2020 09:36:41 GMT
< Expires: Thu, 01 Dec 1994 16:00:00 GMT
< Cache-Control: no-cache="set-cookie, set-cookie2"
<
* Connection #0 to host eplex1 left intact
{"stockCheck":{"returnCode":0,"itemList":[{"itemId":"CITR0001","shipFrom":"\u5317\u6d77\u9053\u672d\u5e4c\u90e8\u54c1\u30bb\u30f3\u30bf\u30fc","itemName":"\uff90\uff7c\uff6d\uff9b\uff9dPILOTSPORT4","stored":"Y","itemPrice":100000},{"itemId":"CITR0002","shipFrom":"\u9752\u68ee\u770c\u9752\u68ee\u30d1\u30fc\u30c4\u30bb\u30f3\u30bf\u30fc","itemName":"\uff90\uff7c\uff6d\uff9b\uff9dPRIMACY4","stored":"Y","itemPrice":80000},{"itemId":"CITR0003","shipFrom":"\u79cb\u7530\u770c\u79cb\u7530\u90e8\u54c1\u30bb\u30f3\u30bf\u30fc","itemName":"\uff90\uff7c\uff6d\uff9b\uff9dENERGY SAVER","stored":"Y","itemPrice":90000},{"itemId":"CITR0004","shipFrom":"\u5ca9\u624b\u770c\u76db\u5ca1\u90e8\u54c1\u30bb\u30f3\u30bf\u30fc","itemName":"\uff90\uff7c\uff6d\uff9b\uff9dCROSSCLIMATE SERIES","stored":"Y","itemPrice":70000},{"itemId":"CITR0005","shipFrom":"\u5c71\u5f62\u770c\u5c71\u5f62\u30d1\u30fc\u30c4\u30bb\u30f3\u30bf\u30fc","itemName":"\uff90\uff7c\uff6d\uff9b\uff9dX-ICE XI3","stored":"Y","itemPrice":60000},{"itemId":"CITR0006","shipFrom":"\u5bae\u57ce\u770c\u4ed9\u53f0\u6771\u5317\u30d1\u30fc\u30c4\u30bb\u30f3\u30bf\u30fc","itemName":"\uff8c\uff9e\uff98\uff7c\uff9e\uff72\uff7cREGNO GR-XII","stored":"Y","itemPrice":40000}],"responseMessage":"Items found."}}
(2)SAFユーザーレジストリーを使用した基本認証
RACFユーザーで認証させるための構成です。
SAFレジストリーの有効化
参考: SAF ユーザー・レジストリーをアクティブにして構成する方法
RACF操作
非認証ユーザーIDというのを作っておく必要があるらしい。認証が完了していない状態で使われるデフォルトのユーザーみたいなものでしょうか。
[CICS004@EPLEX1:/u/cics004/RACF/APIC] tsocmd "ADDUSER WSGUEST3 DFLTGRP(WSGUESTG) OWNER(SYS1) OMVS(HOME(/u/wsguest3) PROGRAM(/bin/sh)) NAME('Unauthenticated User') NOPASSWORD NOOIDCARD RESTRICTED"
ADDUSER WSGUEST3 DFLTGRP(WSGUESTG) OWNER(SYS1) OMVS(HOME(/u/wsguest3) PROGRAM(/bin/sh)) NAME('Unauthenticated User') NOPASSWORD NOOIDCARD RESTRICTED
[CICS004@EPLEX1:/u/cics004/RACF/APIC] tsocmd "PERMIT BBGZDFLT CLASS(APPL) ID(WSGUEST3) ACCESS(READ)"
PERMIT BBGZDFLT CLASS(APPL) ID(WSGUEST3) ACCESS(READ)
次に、実際に認証に使用するユーザーをつくってみます。"ZCON01"というユーザーを作ります。
[CICS004@EPLEX1:/u/cics004/RACF/APIC] tsocmd "ADDUSER ZCON01 DFLTGRP(WSGUESTG) OWNER(SYS1) OMVS(UID(0) SHARED HOME(/u/zcon01) PROGRAM(/bin/sh)) NAME('zcon user') PASSWORD(PSWD)"
ADDUSER ZCON01 DFLTGRP(WSGUESTG) OWNER(SYS1) OMVS(UID(0) SHARED HOME(/u/zcon01) PROGRAM(/bin/sh)) NAME('zcon user') PASSWORD(PSWD)
[CICS004@EPLEX1:/u/cics004/RACF/APIC] tsocmd "PERMIT BBGZDFLT CLASS(APPL) ID(ZCON01) ACCESS(READ)"
PERMIT BBGZDFLT CLASS(APPL) ID(ZCON01) ACCESS(READ)
USS上にHOMEディレクトリ(/u/zcon01)を作成して、パスワードを変更しておきます。
[CICS004@EPLEX1:/u] mkdir zcon01
[CICS004@EPLEX1:/u] tsocmd "ALTUSER ZCON01 PASSWORD(xxx) NOEXPIRED"
ALTUSER ZCON01 PASSWORD(xxx) NOEXPIRED
server.xml編集
RACFをユーザーレジストリとして使用するための宣言を行います。
<feature>zosSecurity-1.0</feature>
を追加し、safCredentials要素を追加します。
SAFをレジストリとして使うために <safRegistry/>
を追加します。
また、<safCredentials>
を追加します。profilePrefixはデフォルトのBBGZDFLTをそのまま使います。非認証ユーザーIDは上で作成したWSGUEST3を使用するので、unauthenticatedUserにWSGUEST3を指定します。
...
<featureManager>
<feature>zosconnect:zosConnect-2.0</feature>
<feature>zosconnect:zosConnectCommands-1.0</feature>
<feature>zosconnect:cicsService-1.0</feature>
<feature>imsmobile:imsmobile-2.0</feature>
<feature>jms-2.0</feature>
<feature>mqzosconnect:zosConnectMQ-2.0</feature>
<feature>wmqJmsClient-2.0</feature>
<feature>zosTransaction-1.0</feature>
<feature>zosSecurity-1.0</feature>
</featureManager>
...
<safRegistry/>
<safCredentials
profilePrefix="BBGZDFLT"
unauthenticatedUser="WSGUEST3"/>
...
SAFレジストリーを使用した基本認証の構成
参考:SAF ユーザー・レジストリーを使用した基本認証の構成方法
server.xml編集
適切なレベルでrequireAuthをtrueに設定します。ここではz/OS Connect全体に有効化したいので、zosconnect_zosConnectManager
要素で指定しています。
また、<webAppSecurity allowFailOverToBasicAuth="true"/>
を指定します。
...
<zosconnect_zosConnectManager
...
requireAuth="true"/>
...
<webAppSecurity allowFailOverToBasicAuth="true"/>
...
アクセス許可設定
参考: SAF ユーザー・レジストリーを使用して zosConnectAccess ロールを構成する方法
ここでは認証の仕組みの構成だけしたいのですが、最低限の認可の設定(アクセス制御)は実施しないといけないようです。認証されたユーザーがz/OS Connectにアクセスできるようにするための許可設定をRACFで行います。
(詳細なアクセス制御は"Authorization Interceptor"という機能を使って行えますが、ここでは触れません。)
EJBROLEクラスに"BBGZDFLT.zos.connect.access.roles.zosConnectAccess"プロファイルを作成します。
(既に作成されていたのでここでは割愛)
ZCON01ユーザーにこのプロファイルのREAD権限を付与します。
[CICS004@EPLEX1:/u/cics004/RACF/APIC] tsocmd "PERMIT BBGZDFLT.zos.connect.access.roles.zosConnectAccess CLASS(EJBROLE) ID(ZCON01) ACCESS(READ)"
PERMIT BBGZDFLT.zos.connect.access.roles.zosConnectAccess CLASS(EJBROLE) ID(ZCON01) ACCESS(READ)
ICH06011I RACLISTED PROFILES FOR EJBROLE WILL NOT REFLECT THE UPDATE(S) UNTIL A SETROPTS REFRESH IS ISSUED
[CICS004@EPLEX1:/u/cics004/RACF/APIC] tsocmd "SETROPTS RACLIST(EJBROLE) REFRESH"
SETROPTS RACLIST(EJBROLE) REFRESH
簡易テスト
上の設定でz/OS Connectを再起動後、z/OS Connectで公開されているREST APIを叩いてみます。
(単純にGETできるAPIで確認)
確認方法は(1)の例と同じです。
Chromeからz/OS Connectが提供するサービスのURLにアクセスすると、ユーザーIDパスワードを聞かれるので、RACFで定義されたユーザーZCON01とパスワードを指定します。
(2)' SAF Basic認証 + TLSサーバー認証(HTTPS)
SAF Basic認証と、前回実施したAPI Connect - z/OS Connect間TLS接続とを組み合わせて構成してみます。
TLS(サーバー認証+クライアント認証) + Basic認証 という構成がいけるかなと思いましたが、クライアントの認証をTLSフローの中でクライアント証明書で実施するのと、ユーザーID/パスワードでの認証を2つ行わせるのはどうやらNGのようでした。普通に2つの構成組み合わせればできるかと思ったのですが、エラーでうまく認証通りませんでした...。
なので、ここではTLSはサーバー認証のみとし、通信は暗号化した上でユーザーID/パスワードでの基本認証を行わせるという構成でやってみます。(Basic認証だけだとユーザーID/パスワードが平文で流れてしまいますがTLS(HTTPS)を併用することで暗号化されるのでセキュリティー・レベルが上がります。)
実際の構成は、上の(2)と前回のTLSサーバー認証のみの構成を組み合わせればよいだけです。
構成
詳細は、既出の記述をなぞっていただければよいですが、server.xmlとしてはこんな感じになります。
...
<featureManager>
<feature>zosconnect:zosConnect-2.0</feature>
<feature>zosconnect:zosConnectCommands-1.0</feature>
<feature>zosconnect:cicsService-1.0</feature>
<feature>imsmobile:imsmobile-2.0</feature>
<feature>jms-2.0</feature>
<feature>mqzosconnect:zosConnectMQ-2.0</feature>
<feature>wmqJmsClient-2.0</feature>
<feature>zosTransaction-1.0</feature>
<feature>zosSecurity-1.0</feature>
</featureManager>
...
<zosconnect_zosConnectManager setUTF8ResponseEncoding="true"
requireSecure="true"
requireAuth="true"/>
...
<safRegistry/>
<safCredentials
profilePrefix="BBGZDFLT"
unauthenticatedUser="WSGUEST3"/>
<safAuthorization id="saf-authorization"/>
<webAppSecurity allowFailOverToBasicAuth="true"/>
<ssl id="defaultSSLConfig"
keyStoreRef="defaultKeyStore"
clientAuthentication="false" />
<keyStore id="defaultKeyStore"
fileBased="false"
location="safkeyring:///Keyring.ZOSCONN"
password="password"
readOnly="true"
type="JCERACFKS" />
...
簡易テスト
サーバー証明書に署名しているCA証明書を登録済みの環境からテストすれば、あとはユーザーID/パスワードををRACF登録済みのものにすればOK
API Connectからのアクセス
このSAF Basic認証 + TLSサーバー認証(HTTPS) の構成で、API Connectから接続してみます。
API ConnectではアセンブリのInvokeの所で、Basic認証用のユーザーID/パスワードを指定できるので、そこにRACF登録のユーザー(ZCON01)を設定します。
今回、ユーザーIDとパスワードはAPI Connectのアセンブル上にベタで持たせている状態ですが、とりあえずこれでAPI Connect - z/OS Connect間を基本認証(+TLS)で接続することができました。
CICSへのID伝播
上の構成をさらに拡張して、z/OS Connectで認証されたユーザーをCICSまで伝播させてみます(接続プロトコルはIPICを使用)。
つまり、以下のような流れを実装してみます。
API Connectからバックエンドのサービスにアクセスする際に基本認証の仕組みでユーザーID
パスワードを指定します(HTTPヘッダー情報にユーザーID/パスワードを指定)。
このユーザーID,パスワードはz/OS上のRACFで管理されている想定です。
リクエストを受け取ったz/OS Connectは送られてきたユーザーID/パスワードをRACFを使って認証します。
認証がOKだったらリクエストに応じたバックエンドのCICSのサービスを呼び出すことになりますが、この時認証したユーザーをCICSにも伝播させて、そのユーザーIDの元でCICSトランザクションを実行します。
CICS接続についてID伝播を行う場合、接続の単位で固定でユーザーIDを指定する方法(リンク・レベル・セキュリティー)と、リクエスト単位でユーザーIDを伝播させる方法(ユーザー・セキュリティ)がありますが、ここでは後者のリクエスト単位でユーザーIDを伝播させる方法について記載します。ユーザーIDをCICSに伝播させる場合、SAFレジストリー(RACF)、もしくはLDAPレジストリーを使用した認証をする必要があります。server.xml内にユーザーIDを保持する基本レジストリーはID伝播には使用できません。
構成変更
SAF Basic認証 + TLSサーバー認証(HTTPS) の構成はされている前提で、z/OS Connectで認証されたユーザーをCICSに伝播させるために必要な追加構成について記載します。
参考: 配布 ID 伝搬の構成
CICS側
SIT
...
SEC=YES
...
SEC=YESを指定する必要があります。その他必要に応じてXTRANなどを設定してください。
TCPIPSERVICE定義
OBJECT CHARACTERISTICS CICS RELEASE = 0710
CEDA View TCpipservice( IPICTCP )
TCpipservice : IPICTCP
GROup : DEMOGRP2
DEScription :
Urm : DFHISAIP
POrtnumber : 54722 1-65535
STatus : Open Open | Closed
PROtocol : IPic Http | Eci | User | IPic
TRansaction : CISS
Backlog : 00000 0-32767
TSqprefix :
Host : ANY
(Mixed Case) :
Ipaddress : ANY
SPeciftcps :
SOcketclose : No No | 0-240000 (HHMMSS)
MAXPersist : No No | 0-65535
MAXDatalen : 3-524288
SECURITY
SSl : No Yes | No | Clientauth | Attlsaware
CErtificate :
(Mixed Case)
PRIvacy : Notsupported | Required | Supported
CIphers :
(Mixed Case)
AUthenticate : No | Basic | Certificate | AUTORegister
| AUTOMatic
Realm :
(Mixed Case)
ATtachsec : Local | Verify
DNS CONNECTION BALANCING
DNsgroup :
GRPcritical : No No | Yes
DEFINITION SIGNATURE
DEFinetime : 07/13/20 17:02:55
...
これは特にこれまでの定義と同様です。CICSがz/OS Connectからの接続をListenするポート番号などを指定します。
IPCONN定義
OBJECT CHARACTERISTICS CICS RELEASE = 0710
CEDA View Ipconn( IPICTCP )
Ipconn : IPICTCP
Group : DEMOGRP2
DEScription :
IPIC CONNECTION IDENTIFIERS
APplid : ZC30DM02
Networkid : TSCNET1
HOst :
(Mixed Case) :
Port : No No | 1-65535
Tcpipservice : IPICTCP
HA : No No | Yes
IPIC CONNECTION PROPERTIES
Receivecount : 001 1-999
SENdcount : 000 0-999
Queuelimit : No No | 0-9999
MAxqtime : No No | 0-9999
OPERATIONAL PROPERTIES
AUtoconnect : No No | Yes
INservice : Yes Yes | No
SECURITY
SSl : No No | Yes
CErtificate : (Mixed Case)
CIphers :
(Mixed Case)
Linkauth : Secuser Secuser | Certuser
SECurityname :
Userauth : Identify Local | Identify | Verify | Defaultuser
IDprop : Notallowed Notallowed | Optional | Required
RECOVERY
Xlnaction : Keep Keep | Force
MIRROR TASK PROPERTIES
MIrrorlife : Request Request | Task | Uow
DEFINITION SIGNATURE
DEFinetime : 07/13/20 17:47:21
...
ポイント
- APPLID: z/OS Connectの値と合わせる(zosConnectApplid)
- NETWORKID: z/OS Connectの値と合わせる(zosConnectNetworkid)
- TCPIPSERVICE: 上で定義したTCPIPSERVICE名
- USERAUTH: Identifyを指定
z/OS Connect (server.xml)側
<zosconnect_zosConnectManager setUTF8ResponseEncoding="true" requireSecure="true" requireAuth="true"/>
...
<safCredentials
profilePrefix="BBGZDFLT"
unauthenticatedUser="WSGUEST3"
mapDistributedIdentities="true" />
...
<zosconnect_cicsIpicConnection id="CT54DMA1" host="xx.xx.xx.xx" port="54722"
zosConnectApplid="ZC30DM02" zosConnectNetworkid="TSCNET1"/>
safCredentialsで、mapDistributedIdentities="true"を指定します。
また、zosconnect_cicsIpicConnectionで、IPCONN定義で指定したAPPLID, NETWORKIDの値に合わせて、zosConnectApplid, zosConnectNetworkidを指定します。
以上で設定変更は終了なので、CICSリージョン、z/OS Connectをそれぞれ再起動します。
API Connectからの接続確認
API Connect側は前回と特に変更はありません。アセンブルでRACFのユーザーID(ZCON01),パスワードを指定している状態です。
ユーザーIDがCICSまで伝播しているかどうかを確認するために、CICS端末に接続してCSMIトランザクションをCEDXでデバッグするようにしておきます。
その状態で、API Connectのアセンブルからテストを実施します。
EDFでCICSトランザクションが稼働した状態でフックされますので、別のCICS端末からCEMT INQ TASKを実行してみます。
CSMIトランザクションの状況を見ると、API Connect側で指定したRACFユーザー"ZCON01"の権限で実行されていることが確認できました。
すなわち、API Connectで指定したユーザーがz/OS Connectで認証され、それがCICSまで伝播されたことが確認できました。