ゼロから使いこなす IAM(InterSystems API Manager)

この記事には、IAM の基本概念を学習するための、教材、例、演習が含まれます。
すべてのリソースはこちらの git から入手できます: https://github.com/grongierisc/iam-training
ソリューションは training ブランチにあります。
この記事では、次の点について説明します。
- 1. 入門
- 2. インストール
- 3. その 1: サービス/ルート
- 4. その 2: プラグインの使用
- 5. その 3: 独自認証の追加
- 6. 演習: レート制限
- 7. 開発者ポータル
- 8. 開発者ポータル(その 2): 認証
- 9. 安全な管理ポータル
- 10. プラグイン
- 11. CI/CD
1. 入門

1.1. IAM とは?
IAM は、InterSystems API Manager の略で、Kong Enterprise Edition が土台となっています。
このため、Kong Open Source エディションの他に、次の機能にアクセスすることができます。
- 管理者ポータル
- 開発者ポータル
- 高度プラグイン
- Oauth2
- キャッシング
- ...

1.2. API 管理とは?
API 管理は、Web アプリケーションプログラミングインターフェース(API)の作成と公開、その使用ポリシーの適用、アクセスの制御、サブスクライバーコミュニティの育成、使用統計の収集と分析、およびパフォーマンスのレポート作成を行うプロセスです。 API 管理コンポーネントは、開発者とサブスクライバーのコミュニティをサポートする仕組みとツールをもたらします。

1.3. IAM ポータル
Kong と IAM は第一に API として設計されています。つまり、Kong/IAM で行われることすべては Rest 呼び出しまたは管理者ポータルで行えるということです。
この記事の中では、すべての例や演習は次のようにして提示されています。
| IAM ポータル | Rest API |
|---|---|
![]() |
![]() |
1.4. このトレーニングの流れ
この記事では、IAM を IRIS Rest API のプロキシとして使用することを狙いとしています。
この Rest API の定義は、次の場所にあります。
http://localhost:52773/swagger-ui/index.html#/
または次の場所にあります。
https://github.com/grongierisc/iam-training/blob/training/misc/spec.yml
この記事は main ブランチから始めてください。
記事の最後に到達すると、training ブランチと同じ結果が得られるはずです。
2. インストール

2.1. インストールには何が必要?
- Git
- Docker(Windows をお使いの方は、Docker インストールで「Linux コンテナ」が使用されるように設定してください)。
- Docker Compose
- Visual Studio Code と InterSystems ObjectScript VSCode 拡張機能
- InterSystems IRIS IAM 対応のライセンスファイル
- IAM Docker イメージ
2.2. IAM と IRIS の連携の仕組み
Kong/IAM の起動時に、コンテナは curl 呼び出しによって、Kong/IAM のライセンスをチェックします。
この呼び出しのエンドポイントは、IRIS コンテナの Rest API です。
参考: Kong ライセンスは IRIS のライセンスに組み込まれています。

2.3. セットアップ
Git clone によって、次のリポジトリのクローンを作成します。
git clone https://github.com/grongierisc/iam-training
次のようにして、最初の Rest API を実行します。
docker-compose up
テストを行います。
http://localhost:52773/swagger-ui/index.html#/
ログイン/パスワード: SuperUser/SYS
2.4. IAM のインストール
2.4.1. Iris イメージ
まず、Community エディションをライセンスエディションに切り替える必要があります。
これを行うには、InterSystems Container Registry へのアクセスをセットアップして、アクセス制限付きの IRIS イメージをダウンロードする必要があります。
開発者コミュニティの「InterSystems Container Registry のご紹介」をご覧ください。
- WRC ログイン情報を使って https://containers.intersystems.com/ にログインし、トークンを取得します。
- コンピュータに Docker ログインをセットアップします。
docker login -u="user" -p="token" containers.intersystems.com
- InterSystems IRIS イメージを取得します。
docker pull containers.intersystems.com/intersystems/irishealth:2020.4.0.524.0
2.4.2. IAM イメージ
WRC Software Distribution を使用します。
- コンポーネント > ダウンロードに移動して IAM-1.5.0.9-4.tar.gz ファイルをダウンロードし、解凍(unzip & untar)してイメージを読み込みます。
docker load -i iam_image.tar
2.4.3. Docker ファイルを更新する
IRIS Community エディションをライセンスエディションに変更します。
- containers.intersystems.com/intersystems/irishealth:2020.4.0.524.0
- key フォルダにある iris.key を追加します。
dockerfile を編集して、その上に次の部分を追加します。
ARG IMAGE=containers.intersystems.com/intersystems/irishealth:2020.4.0.524.0
# 第 1 ステージ
FROM $IMAGE as iris-iam
COPY key/iris.key /usr/irissys/mgr/iris.key
COPY iris-iam.script /tmp/iris-iam.script
RUN iris start IRIS \
&& iris session IRIS < /tmp/iris-iam.script \
&& iris stop IRIS quietly
# 第 2 ステージ
FROM iris-iam
この部分では、マルチステージの dockerfile を作成します。
- 第 1 ステージでは、IRIS が IAM ライセンスを提供できるようにします。
- 第 2 ステージは、REST API ビルド用です。
新しい IRIS イメージを構築して IAM エンドポイントとユーザーを有効にする新しい iris-iam.script ファイルを作成します。
zn "%SYS"
write "Create web application ...",!
set webName = "/api/iam"
set webProperties("Enabled") = 1
set status = ##class(Security.Applications).Modify(webName, .webProperties)
write:'status $system.Status.DisplayError(status)
write "Web application "_webName_" was updated!",!
set userProperties("Enabled") = 1
set userName = "IAM"
Do ##class(Security.Users).Modify(userName,.userProperties)
write "User "_userName_" was updated!",!
halt
2.4.4. docker-compose を更新する
docker-compose ファイルを次のように更新します。
- db
- IAM の postgres データベース
- iam-migration
- データベースのブートストラップ
- iam
- 実際の IAM インスタンス
- 永続データ用のボリューム
次の部分を docker-compose ファイルの最後に追加します。
iam-migrations:
image: intersystems/iam:1.5.0.9-4
command: kong migrations bootstrap up
depends_on:
- db
environment:
KONG_DATABASE: postgres
KONG_PG_DATABASE: ${KONG_PG_DATABASE:-iam}
KONG_PG_HOST: db
KONG_PG_PASSWORD: ${KONG_PG_PASSWORD:-iam}
KONG_PG_USER: ${KONG_PG_USER:-iam}
KONG_CASSANDRA_CONTACT_POINTS: db
KONG_PLUGINS: bundled,jwt-crafter
ISC_IRIS_URL: IAM:${IRIS_PASSWORD}@iris:52773/api/iam/license
restart: on-failure
links:
- db:db
iam:
image: intersystems/iam:1.5.0.9-4
depends_on:
- db
environment:
KONG_ADMIN_ACCESS_LOG: /dev/stdout
KONG_ADMIN_ERROR_LOG: /dev/stderr
KONG_ADMIN_LISTEN: '0.0.0.0:8001'
KONG_ANONYMOUS_REPORTS: 'off'
KONG_CASSANDRA_CONTACT_POINTS: db
KONG_DATABASE: postgres
KONG_PG_DATABASE: ${KONG_PG_DATABASE:-iam}
KONG_PG_HOST: db
KONG_PG_PASSWORD: ${KONG_PG_PASSWORD:-iam}
KONG_PG_USER: ${KONG_PG_USER:-iam}
KONG_PROXY_ACCESS_LOG: /dev/stdout
KONG_PROXY_ERROR_LOG: /dev/stderr
KONG_PORTAL: 'on'
KONG_PORTAL_GUI_PROTOCOL: http
KONG_PORTAL_GUI_HOST: '127.0.0.1:8003'
KONG_ADMIN_GUI_URL: http://localhost:8002
KONG_PLUGINS: bundled
ISC_IRIS_URL: IAM:${IRIS_PASSWORD}@iris:52773/api/iam/license
volumes:
- ./iam:/iam
links:
- db:db
ports:
- target: 8000
published: 8000
protocol: tcp
- target: 8001
published: 8001
protocol: tcp
- target: 8002
published: 8002
protocol: tcp
- target: 8003
published: 8003
protocol: tcp
- target: 8004
published: 8004
protocol: tcp
- target: 8443
published: 8443
protocol: tcp
- target: 8444
published: 8444
protocol: tcp
- target: 8445
published: 8445
protocol: tcp
restart: on-failure
db:
image: postgres:9.6
environment:
POSTGRES_DB: ${KONG_PG_DATABASE:-iam}
POSTGRES_PASSWORD: ${KONG_PG_PASSWORD:-iam}
POSTGRES_USER: ${KONG_PG_USER:-iam}
volumes:
- 'pgdata:/var/lib/postgresql/data'
healthcheck:
test: ["CMD", "pg_isready", "-U", "${KONG_PG_USER:-iam}"]
interval: 30s
timeout: 30s
retries: 3
restart: on-failure
stdin_open: true
tty: true
volumes:
pgdata:
ルートフォルダに .env ファイルを追加します。
IRIS_PASSWORD=SYS
ちなみに、Kong ポートの定義は次のようになっています。
| ポート | プロトコル | 説明 |
|---|---|---|
| :8000 | HTTP | コンシューマからの HTTP 着信トラフィックを取り、上流のサービスに転送します。 |
| :8443 | HTTPS | コンシューマからの HTTPS 着信トラフィックを取り、上流のサービスに転送します。 |
| :8001 | HTTP | 管理 API。 HTTP によるコマンドラインからの呼び出しをリスンします。 |
| :8444 | HTTPS | 管理 API。 HTTPS によるコマンドラインからの呼び出しをリスンします。 |
| :8002 | HTTP | Kong Manager(GUI)。 HTTP トラフィックをリスンします。 |
| :8445 | HTTPS | Kong Manager(GUI)。 HTTPS トラフィックをリスンします。 |
| :8003 | HTTP | 開発者ポータル。 開発者ポータルが有効になっていることを前提に、HTTP トラフィックをリスンします。 |
| :8446 | HTTPS | 開発者ポータル。 開発者ポータルが有効になっていることを前提に、HTTPS トラフィックをリスンします。 |
| :8004 | HTTP | HTTP による開発者ポータルの /files トラフィック。開発者ポータルが有効になっていることが前提です。 |
| :8447 | HTTPS | HTTPS による開発者ポータルの /files トラフィック。開発者ポータルが有効になっていることが前提です。 |
2.4.5. オプション: .env として IRIS_PASSWORD を追加する
使いやすいよう(またセキュリティの理由により)、IRIS dockerfile の .env ファイルを使用できます。
使用するには、docker-compose の iris サービスの部分を次のように編集します。
build:
context: .
dockerfile: dockerfile
args:
- IRIS_PASSWORD=${IRIS_PASSWORD}
そして、dockerfile を編集します(ビルドの第 2 または第 1 ステージ)。
ARG IRIS_PASSWORD
RUN echo "${IRIS_PASSWORD}" > /tmp/password.txt && /usr/irissys/dev/Container/changePassword.sh /tmp/password.txt
2.4.6. テスト
docker-compose -f "docker-compose.yml" up -d --build
3. その 1: サービス/ルート

Kong/IAM の連携の仕組みを覚えていますか?

ここでは、次の項目を構築します。
- サービス
- crud API 用
- ルート
- このサービスにアクセスするためのルート
3.1. サービスを作成する
| IAM ポータル | Rest API | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
これで、開発者ポータルの認証が有効になりました。
8.2. アクセスを制限する
デフォルトでは、認証されていないユーザーがすべてにアクセスできるようになっています。
ロールを作成することで、アクセスを制限することができます。
例として、CRUD API ドキュメントへのアクセスを制限してみましょう。
8.2.1. ロールを作成する
| IAM ポータル | Rest API | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
- 自動認証を再利用します。
| IAM ポータル | Rest API | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
これで完了です。 jwt-crafter の実際の使用は次のようになります。
テストしよう!
10.2. 新しいプラグインを作成するこれは lua を学習する場所ではありませんが、IAM を素早く再起動して新しい開発をテストする方法などのヒントをいくつか紹介します。 10.2.1. ファイル構造
表記法により、Kong プラグインには kong-plugin のプレフィックスを付ける必要があります。 この例では、プラグインの名前を helloworld とします。 次の 3 つのファイルは必須ファイルです。
10.2.1.1. handler.luaplugins インターフェースでは、handler.lua ファイル内の次のいずれかのメソッドをオーバーライドして、Kong の実行ライフサイクルのさまざまなエントリポイントにカスタムロジックを実装できます。
|
10.2.1.1.1. 例
local BasePlugin = require "kong.plugins.base_plugin"
local HelloWorldHandler = BasePlugin:extend()
function HelloWorldHandler:new()
HelloWorldHandler.super.new(self, "helloworld")
end
function HelloWorldHandler:access(conf)
HelloWorldHandler.super.access(self)
if conf.say_hello then
ngx.log(ngx.ERR, "============ Hello World! ============")
ngx.header["Hello-World"] = "Hello World!!!"
else
ngx.log(ngx.ERR, "============ Bye World! ============")
ngx.header["Hello-World"] = "Bye World!!!"
end
end
return HelloWorldHandler
10.2.1.2. schema.lua
ポータルで表示される構成ファイルです。
return {
no_consumer = true,
fields = {
say_hello = { type = "boolean", default = true },
say_hello_body = { type = "boolean", default = true }
}
}
10.2.1.3. *.rockspec
package = "kong-plugin-helloworld" -- hint: rename, must match the info in the filename of this rockspec!
-- as a convention; stick to the prefix: `kong-plugin-`
version = "0.1.0-1" -- hint: renumber, must match the info in the filename of this rockspec!
-- The version '0.1.0' is the source code version, the trailing '1' is the version of this rockspec.
-- whenever the source version changes, the rockspec should be reset to 1. The rockspec version is only
-- updated (incremented) when this file changes, but the source remains the same.
-- TODO: This is the name to set in the Kong configuration `plugins` setting.
-- Here we extract it from the package name.
local pluginName = package:match("^kong%-plugin%-(.+)$") -- "myPlugin"
supported_platforms = {"linux", "macosx"}
source = {
url = "https://github.com/grongierisc/iam-training",
branch = "master",
-- tag = "0.1.0"
-- hint: "tag" could be used to match tag in the repository
}
description = {
summary = "This a demo helloworld for Kong plugin",
homepage = "https://github.com/grongierisc/iam-training",
license = "Apache 2.0"
}
dependencies = {
"lua >= 5.1"
-- other dependencies should appear here
}
build = {
type = "builtin",
modules = {
["kong.plugins."..pluginName..".handler"] = "kong/plugins/"..pluginName.."/handler.lua",
["kong.plugins."..pluginName..".schema"] = "kong/plugins/"..pluginName.."/schema.lua",
}
}
10.2.2. 構築
ここでは、次の章と同じことを行います: 11.1.1. コミュニティプラグインで新しい Kong/IAM docker イメージを構築する
ただし、このプラグインに適応させています。
Dockerfile :
FROM intersystems/iam:1.5.0.9-4
USER root
COPY ./plugins /custom/plugins
RUN cd /custom/plugins/kong-plugin-jwt-crafter && luarocks make
RUN cd /custom/plugins/kong-plugin-helloworld && luarocks make
#USER kong #Stay with root use, we will see why later
環境変数でプラグインを有効にします。
KONG_PLUGINS: 'bundled,jwt-crafter,helloworld'
これで新しい IAM イメージをビルドします。
docker-compose build iam
そして docker-compose を起動してテストします。
10.2.3. ヒント
IAM コンテナを「デバッグモード」で実行し、コンテナの停止/再開を簡単に行えるようにするには、dockerfile を変更して、プラグインの追加/削除など行います。
iam サービスを次のようにして停止できます。
docker-compose stop iam
そして、シェルを使用して実行モードで起動します。
docker-compose run -p 8000:8000 -p 8001:8001 -p 8002:8002 iam sh
コンテナでは次のように行います。
./docker-entrypoint.sh kong
コーディングをお楽しみください :)
11. CI/CD

この記事も残り少なくなりました。
最後に、DevOps/CI/CD について話しましょう。 この章は、IAM/Kong 向けの CI/CD を実装/スクリプト化する方法について、いくつかのアイデアを提供することを目的としています。
Kong は第一に API であるため、すべての Rest 呼び出しをスクリプト化して、各環境で実行させるという考え方です。
postman とその親友の newman(postman のコマンドラインバージョン)を使用すると、Rest 呼び出しのスクリプト化を最も簡単に行うことができます。
11.1. postman コレクションを作成する
postman が便利な理由の 1 つは、Rest 呼び出しの前後でスクリプトを実行できるところにあります。
ほとんどの場合、この機能を使用します。
11.1.1. IAM が起動しているか
最初のスクリプトでは、IAM が稼働しているかどうかを確認します。

var iam_url = pm.environment.get("iam_url");
var iam_config_port = pm.environment.get("iam_config_port");
var url = "http://" + iam_url + ":" + iam_config_port + "/";
SenReq(20);
async function SenReq(maxRequest) {
var next_request = "end request";
const result = await SendRequest(maxRequest);
console.log("result:",result);
if(result == -1)
{
console.error("IAM starting .... failed !!!!");
}
}
function SendRequest(maxRequest) {
return new Promise(resolve => {
pm.sendRequest(url,
function (err) {
if (err) {
if (maxRequest > 1) {
setTimeout(function () {}, 5000);
console.warn("IAM not started...retry..next retry in 5 sec");
SendRequest(maxRequest - 1);
} else {
console.error("IAM starting .... failed");
resolve(-1);
}
} else {
console.log("IAM starting .... ok");
resolve(1);
}
}
);
});
}
11.1.2. 古いデータを削除する
var iam_url=pm.environment.get("iam_url");
var iam_config_port=pm.environment.get("iam_config_port");
pm.sendRequest("http://"+iam_url+":"+iam_config_port+"/plugins", function (err, res) {
if (err) {
console.log("ERROR : ",err);
}
else {
var body_json=res.json();
if(body_json.data)
{
for( i=0; i < body_json.data.length; i++)
{
// Example with a full fledged SDK Request
route_id = body_json.data[i].id;
const delete_route = {
url: "http://"+iam_url+":"+iam_config_port+"/plugins/" + route_id,
method: 'DELETE',
};
pm.sendRequest(delete_route, function(err, res){
console.log(err ? err : res);
});
}
}
}
});
ルート、サービス、およびコンシューマでも同じように行ってください。
ルートのあるサービスは削除できないため、この実行順序は重要です。
11.1.3. サービス/ルートを作成する
ルートはサービスに依存しています。 この種のケースでは、postman の Test 関数を使用してデータを取得することができます。

| 画面 | スクリプト | |||||
|---|---|---|---|---|---|---|
|
|







































