KonnectのDev Portalのアクセス制限をAPIを使って設定する

Konnectの機能の1つである開発者向けAPIポータル（[Dev Portal](https://docs.konghq.com/konnect/dev-portal/)）は、APIサービスを登録することで検索、アクセス、利用が簡単に出来るようになるAPI管理のためのWebサイトである。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/be328820-a749-4f4e-5f70-53a20e9382a9.png)
（上図はDevPortalの一例：[API Developer Portal](https://konghq.com/products/kong-konnect/features/developer-portal)より引用）

このDev Portalの概念や基本的な使い方については以前[こちら](https://qiita.com/ipppppei/items/cdd1f4dd6be82bf76943)で紹介した。
このPortalの利用時、利用者が増えてAPIも増えてくると以下のようなことがしたくなってくると思う。
- API仕様の公開範囲を絞りたい
- 読み取り専用のユーザと編集権限を持つユーザを分けたい

今回はこれを実現するためのRBACの仕様とOIDC利用時の設定方法を確認する。
そのまま試してもつまらないので、今回は設定を基本APIベースで行う。
なお、連携に使うOIDCはAzureのEntra IDとする。

## 前提知識
### API Product
API Productの概念については以前書いた[こちらの記事](https://qiita.com/ipppppei/items/cdd1f4dd6be82bf76943)にまとめているので、ここでは説明は省略する。

### DevPortalのアクセス制限
DevPortalのアクセス制限にはロールベースでのアクセス制限（RBAC: Role Base Access Control)が[用意されている](https://docs.konghq.com/konnect/dev-portal/access-and-approval/manage-teams/)。

'24/10時点で用意されているロールは以下となる。
|ロール名|概要|
|---|---|
|API Viewer|API Productのドキュメントへの読み取りのみ可能|
|API Consumer|フル権限|

この権限はAPI Productごとに設定可能なため、例えば
- 顧客の機密情報を扱うAPIサービスへのアクセスは限られたユーザしか許可しない
- パートナー企業には更に読み取り権限のみしか付加しない

みたいな使い方が出来るようになる。

## ユースケースの検証
### 前提
ここでは以下のようなユースケースで権限設定出来るか確認する。
- API Catalog内のAPIは以下3つ
  - 社内イントラ向けAPI(Intra API)
  - 法人事業向けAPI(Corporate API)
  - 顧客情報管理API(Customer API)
- Dev Portalにアクセスできるのは以下の3種類のユーザ
  - 社内の一般ユーザ
  - 開発チーム（プロパー）
  - 開発チーム全般
- 各種ユーザがアクセスできるAPI Catalogは以下の通り
  
||Intra API|Corporate API|Customer API|
|---|---|---|---|
|一般ユーザ|読取のみ|NG|NG|
|開発チーム（プロパー）|読取のみ|フル|フル|
|開発チーム全般|読取のみ|読取のみ|NG|

図に表すと以下のような感じになる。
![20240924145122.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/59ee1475-0ed9-cbca-9e14-6a050e7673e2.png)

上記のDev Portalの権限設定をRBACとOIDC連携を使って実現する。

### 検証の流れ
以下の手順で検証する
1. Dev Portalの作成
2. API Productの登録
3. Dev PortalへのOIDCの設定
4. Dev PortalのRBACの有効化と動作確認

最初はBuilt-inユーザを作成して設定を進め、後からOIDCを有効化する。

### Dev Portalの作成
ここはAPIではなくUIで作成する（忘れてただけでAPIでも作成可能）。
Dev Portalの作成の前に、動作確認時にアプリの作成で使うAuth Strategyを作成する。
Dev Portalの`Application Auth`から`+ Create New Auth Strategy`を選択する。
![20240924180245.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/79de9d4b-880b-57f8-e7e0-9251c78d7738.png)

ここでは以下で作成する。
- Name: `apikey`
- Display Name: `apikey`
- Auth Type: `Key-Auth`
- Key Names: `apikey`

次にDev Portalの作成に移る。
左サイドバーの`Dev Portal`をクリックし、`+ Dev Portal`から作成する。
ここでは以下の設定値で作成する。
- `Name`: default-dev-portal
- Dev Portal Settingsは以下を利用
  - `Private Portal`
  - `Auto Approve Developers`
  - `Auto Approve Applications`
  - Default Application Auth Strategy: `apikey` (先ほど作成したもの)

Auto Approveは検証の手間を省くために設定した。
RBACについては後から有効化する。

作成したDev Portalをクリックし、Dev Portalにアクセスする。
すると以下の画面になるため、一番下の`Sing UP →`をクリックして初期ユーザを登録する。
![20240922170610.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/55d0f02b-05b6-34cf-88b3-b6f71d1871aa.png)

以下のような認証メールが届くので、`Confirm your email`をクリックし、パスワードを設定すればアカウントが有効化される。
![20240922170752.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/e29849a5-3617-c98c-17f3-687beac27e04.png)

登録したアカウントでログインすると、以下のようにProductに何もない画面が表示される。
![20240922171020.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/1a1a5f29-fbef-a1aa-c029-859dc0705544.png)

### API Productの登録
ここからAPIをメインに使って設定作業を行う。
まずは[こちらのドキュメント](https://docs.konghq.com/konnect/api-products/productize-service/)に従ってAPIを使ってKonnectにAPI Productを作成する。
最初にKonnectのPAT(Personal Access Token)を環境変数に設定する。
```sh
export KONNECT_TOKEN=kpat_ER1WQxxxx
```
Dev PortalのIDを取得する。
ここではDev Portalの名前を`default-dev-portal`としている。
```sh
PORTAL_ID=$(curl -X GET -s \
    https://us.api.konghq.com/v2/portals \
    -H "Authorization: Bearer $KONNECT_TOKEN" \
    | jq -r '.data[] | select(.name == "default-dev-portal") | .id')
```

最初にユースケースに出てきた3つのAPIのうち、Intra APIを作成する。
以下を実行するとAPI Productが作成できる。
```sh
curl -X POST \
    https://us.api.konghq.com/v2/api-products \
    -H "Authorization: Bearer $KONNECT_TOKEN" \
    -H 'Content-Type: application/json' \
    -d '{
    "name": "IntraAPI",
    "portal_ids": ["'"$PORTAL_ID"'"]
    }'
```
次にAPI Productに紐づくバージョンを作成する。
作成したAPI ProductのIDを取得する。
```sh
PRODUCT_ID=$(curl -X GET -s \
  https://us.api.konghq.com/v2/api-products \
  -H "Authorization: Bearer $KONNECT_TOKEN" \
   | jq -r '.data[] | select(.name == "IntraAPI") | .id')
```
取得したIDを含めたAPIのエンドポイントにリクエストを送り、API Productのバージョンを作成して公開する。
```sh
curl -X POST \
    https://us.api.konghq.com/v2/api-products/${PRODUCT_ID}/product-versions \
    -H "Authorization: Bearer $KONNECT_TOKEN" \
    -H 'Content-Type: application/json' \
    -d '{
    "name": "v1",
    "publish_status": "published"
    }'
```
`"publish_status"`に`"published"`を指定することで作成と同時に公開できる。
なお、ここでPortalへの公開設定もあわせて出来そうなのだが、実際は出来ない（後述）。

次に作成したバージョンにDocumentとOpenAPISpecification(API Spec)を登録する。
登録に用いるそれぞれのファイルを作成する（内容は適当）。
```md:md-IntraAPI.md
cat <<EOF > ./md-IntraAPI.md
## Intra API
This documentation shows how to use Intra API.
EOF
```
```yaml:oas-IntraAPI.yaml
cat <<EOF > ./oas-IntraAPI.yaml
openapi: 3.0.0
info:
  title: Intra API
  version: "0.1"
paths:
  /get:
    get:
      operationId: /get
      responses:
        "200":
          description: "get: response 200"
  /post:
    post:
      operationId: /post
      responses:
        "200":
          description: "post: response 200"
servers:
  - url: https://httpbin.org
EOF
```
先にドキュメントから登録する。
[APIの仕様](https://docs.konghq.com/konnect/api/api-products/latest/#/API%20Product%20Documentation/create-api-product-document)を見ると以下のようにMarkdownはBase64でエンコードしたものを設定するようになっている。
```json
{
  "slug": "api-product-document",
  "status": "published",
  "title": "API Product Document",
  "content": "IyBBUEkgUHJvZHVjdCBEb2N1bWVudCBIZWFkZXIKQVBJIHByb2R1Y3QgZG9jdW1lbnQgY29udGVudA=="
}
```
なので上記を真似て以下のようにデータ部を設定して登録する。
```sh
CONTENT=$(base64 -w0 md-IntraAPI.md)
curl -X POST \
    https://us.api.konghq.com/v2/api-products/${PRODUCT_ID}/documents \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $KONNECT_TOKEN" \
    -d '{
    "slug": "api-product-document",
    "status": "published",
    "title": "API Product Document for Intra API",
    "content": "'"$CONTENT"'",
    "metadata": {
      "author": "John Doe"
    }
    }'
```
登録が完了すると以下のようにKonnectのUIから確認できる。
![20240919170210.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/ce47e2b5-932b-e28a-41d3-083e20264930.png)

次に[こちらのAPI仕様](https://docs.konghq.com/konnect/api/api-products/latest/#/API%20Product%20Version%20Specification/create-api-product-version-spec)に従ってAPI Specも登録する。
YAMLの内容はドキュメントと同じようにBase64でエンコードする必要がある。
```sh
{
  "name": "oas.yaml",
  "content": "TXkgWUFNTCBvciBKU09OIGZvcm1hdHRlZCBPQVMgY29udGVudA=="
}
```
そのため以下のようにBase64化する。
```sh
CONTENT=$(base64 -w0 oas-IntraAPI.yaml)
```
また、ドキュメントはAPI Productと紐づくが、API SpecはAPI Productのバージョンと紐づくため、バージョンのIDを取得してAPIのエンドポイントにIDを含むようにして実行する必要がある。
そのため以下でバージョンのIDを取得する。
```sh
VERSION_ID=$(curl -X GET -s \
    https://us.api.konghq.com/v2/api-products/${PRODUCT_ID}/product-versions \
    -H "Authorization: Bearer $KONNECT_TOKEN" \
    | jq -r '.data[] | select(.name == "v1") | .id')
```
バージョンを環境変数に設定後、以下でAPI Specを登録する。
```sh
curl -X POST \
    https://us.api.konghq.com/v2/api-products/${PRODUCT_ID}/product-versions/${VERSION_ID}/specifications \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $KONNECT_TOKEN" \
    -d '{
    "name": "oas-IntraAPI.yaml",
    "content": "'"$CONTENT"'"
    }'
```
登録後、以下のようにKonnect上で確認できる。
![20240919173059.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/d6e017ba-174c-1e5d-bbeb-12d539031af8.png)

最後にバージョンをDev Portalに公開する。
UIだとこの辺の部分。
![20241010102457.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/f016e203-c338-1290-0a6b-cb8f4246eca0.png)

公開にはDev Portal作成前に作成したAuth StrategyのIDが必要となるので、このIDを取得する。
```sh
AUTH_STRATEGY_ID=$(curl -X GET -s \
    https://us.api.konghq.com/v2/application-auth-strategies \
    -H "Authorization: Bearer $KONNECT_TOKEN" \
    | jq -r '.data[] | select(.name == "apikey") | .id')
```
次にバージョンをDev Portalに公開するのだが、このエンドポイントが何故かPortal側のエンドポイントになってるので注意。
（API Productのエンドポイントからでも作れそうだが、実際に試すと`"property portals should not exist"`とエラーになる）
エンドポイントの仕様は[こちら](https://docs.konghq.com/konnect/api/portal-management/latest/#/Portal%20Product%20Versions/create-portal-product-version)にあるので、これに従って以下のような感じで作成する。
```sh
curl -X PATCH \
      https://us.api.konghq.com/v2/portals/${PORTAL_ID}/product-versions/${VERSION_ID} \
      -H "Authorization: Bearer $KONNECT_TOKEN" \
      -H 'Content-Type: application/json' \
      -d '{
          "publish_status": "published",
          "deprecated": false,
          "application_registration_enabled": true,
          "auto_approve_registration": true,
          "auth_strategy_ids": [
            "'"$AUTH_STRATEGY_ID"'"
           ]
      }'
```
これまでの手順でリソース自体は作成されているので、`PATCH`を使って変更する形で設定する。
以上でAPI Productの作成手順は終了となる。

同じ要領でCorporate APIとCustomer APIも作成する。
コマンドを1つ1つ実行するのが面倒な人は以下にスクリプトを用意したので必要に応じて使うとよい。

<details><summary>作成用スクリプト（クリックすると展開）：</summary><div>

```sh:create_api_product.sh
#!/bin/bash

API_LIST=("IntraAPI" "CorporateAPI" "CustomerAPI")

AUTH_STRATEGY_NAME=apikey

KONNECT_TOKEN==kpat_ER1WQ0rnLX82VJxxx

#alias base64='/opt/homebrew/bin/gbase64'
if [ -z "$KONNECT_TOKEN" ]; then
    echo "Failed to set KONNECT_TOKEN"
    exit 1
fi


create_api_product() {
  API_NAME=$1
  if [ -z "$API_NAME" ]; then
    echo "API_NAME is empty."
    return 1
  fi
  # Get the portal ID for "default-dev-portal"
  PORTAL_ID=$(curl -X GET -s \
      https://us.api.konghq.com/v2/portals \
      -H "Authorization: Bearer $KONNECT_TOKEN" \
      | jq -r '.data[] | select(.name == "default-dev-portal") | .id')

  # Create API Product
  curl -X POST \
      https://us.api.konghq.com/v2/api-products \
      -H "Authorization: Bearer $KONNECT_TOKEN" \
      -H 'Content-Type: application/json' \
      -d '{
      "name": "'"$API_NAME"'",
      "portal_ids": ["'"$PORTAL_ID"'"]
      }'

  # Get the newly created Product ID
  PRODUCT_ID=$(curl -X GET -s \
    https://us.api.konghq.com/v2/api-products \
    -H "Authorization: Bearer $KONNECT_TOKEN" \
     | jq -r '.data[] | select(.name == "'"$API_NAME"'") | .id')

  # Create the API product version
  curl -X POST \
      https://us.api.konghq.com/v2/api-products/${PRODUCT_ID}/product-versions \
      -H "Authorization: Bearer $KONNECT_TOKEN" \
      -H 'Content-Type: application/json' \
      -d '{
      "name": "v1",
      "publish_status": "published"
      }'

  # Create Markdown document for the API
  cat <<EOF > ./md-${API_NAME}.md
## ${API_NAME}
This documentation shows how to use ${API_NAME}.
EOF

  # Create OpenAPI specification file
  cat <<EOF > ./oas-${API_NAME}.yaml
openapi: 3.0.0
info:
  title: ${API_NAME}
  version: "0.1"
paths:
  /get:
    get:
      operationId: /get
      responses:
        "200":
          description: "get: response 200"
  /post:
    post:
      operationId: /post
      responses:
        "200":
          description: "post: response 200"
servers:
  - url: https://httpbin.org
EOF

  # Encode and publish the markdown document
  CONTENT=$(gbase64 -w0 md-${API_NAME}.md)
  curl -X POST \
      https://us.api.konghq.com/v2/api-products/${PRODUCT_ID}/documents \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $KONNECT_TOKEN" \
      -d '{
      "slug": "api-product-document",
      "status": "published",
      "title": "API Product Document for '"$API_NAME"'",
      "content": "'"$CONTENT"'",
      "metadata": {
        "author": "John Doe"
      }
      }'

  # Encode and upload the OpenAPI specification
  CONTENT=$(gbase64 -w0 oas-${API_NAME}.yaml)
  VERSION_ID=$(curl -X GET -s \
      https://us.api.konghq.com/v2/api-products/${PRODUCT_ID}/product-versions \
      -H "Authorization: Bearer $KONNECT_TOKEN" \
      | jq -r '.data[] | select(.name == "v1") | .id')

  curl -X POST \
      https://us.api.konghq.com/v2/api-products/${PRODUCT_ID}/product-versions/${VERSION_ID}/specifications \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $KONNECT_TOKEN" \
      -d '{
      "name": "oas-'"$API_NAME"'.yaml",
      "content": "'"$CONTENT"'"
      }'

  # Get the Auth Strategy ID
  AUTH_STRATEGY_ID=$(curl -X GET -s \
      https://us.api.konghq.com/v2/application-auth-strategies \
      -H "Authorization: Bearer $KONNECT_TOKEN" \
      | jq -r '.data[] | select(.name == "'"$AUTH_STRATEGY_NAME"'") | .id')

  # Publish to Dev Portal
  curl -X PATCH \
      https://us.api.konghq.com/v2/portals/${PORTAL_ID}/product-versions/${VERSION_ID} \
      -H "Authorization: Bearer $KONNECT_TOKEN" \
      -H 'Content-Type: application/json' \
      -d '{
          "publish_status": "published",
          "deprecated": false,
          "application_registration_enabled": true,
          "auto_approve_registration": true,
          "auth_strategy_ids": [
            "'"$AUTH_STRATEGY_ID"'"
           ]
      }'

  echo "API Product ${API_NAME} has been created and published."
}


for CREATE_APINAME in "${API_LIST[@]}"; do
    create_api_product "$CREATE_APINAME"
done

exit 0
```
</div></details>

作成後、Dev Portalにログインすると以下のように3つのAPI Productが表示される。
<img alt"picture 5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/938b790a-8113-7cf7-006c-3b145c3c6c7d.png" width=500 />

まだRBACを設定していないので、Dev Portalにアクセス出来る人は全員API Productが全て表示される状態となる。

### Dev PortalへのOIDCの設定
ここでは[Team](https://docs.konghq.com/konnect/org-management/teams-and-roles/)を作成し、EntraIDのロールとマッピングさせて自動的にKonnectのロールが割り当たるようにする。


公式の[この辺りのドキュメント](https://docs.konghq.com/konnect/dev-portal/access-and-approval/manage-teams/#create-developer-teams)を参照してTeamを作成する。
ここでは[API仕様](https://docs.konghq.com/konnect/api/portal-management/latest/#/Portal%20Teams/create-portal-team)を参考に以下のスクリプトを実行してまとめて3チーム作成した。
```sh:create_team.sh
#!/bin/bash
KONNECT_TOKEN==kpat_ER1WQ0rnLX82VJxxx

if [ -z "$KONNECT_TOKEN" ]; then
    echo "Failed to set KONNECT_TOKEN"
    exit 1
fi 

PORTAL_ID=$(curl -X GET -s \
    https://us.api.konghq.com/v2/portals \
    -H "Authorization: Bearer $KONNECT_TOKEN" \
    | jq -r '.data[] | select(.name == "default-dev-portal") | .id')

create_team(){
  TEAM=$1
  DESCRIPTION=$2
  curl -X POST \
    https://us.api.konghq.com/v2/portals/${PORTAL_ID}/teams \
    -H "Authorization: Bearer $KONNECT_TOKEN" \
    -H 'Content-Type: application/json' \
    -d '{
     "name": "'"$TEAM"'",
     "description": "'"$DESCRIPTION"'"
     }'
}

create_team "All User" "Default team"
create_team "All Developer" "Default Developer team"
create_team "Proper Developer" "Proper Developer team"
```
作成後は以下のような感じでKonnectから確認できる。なおRBACを有効化していないので警告が出る。
![20240924151222.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/0eee6850-b90a-2d66-81a6-f227f58781d9.png)

次にTeamにどのAPI Productに対し、どのような権限を持つかを設定する。
ロールは以下のように追加する。
|Team|Product|Role|
|---|---|---|
|All User|IntraAPI|API Viewer|
|Proper Developer|IntraAPI|API Viewer|
||CorporateAPI|API Consumer|
||CustomerAPI|API Consumer|
|All Developer|IntraAPI|API Viewer|
||CorporateAPI|API Viewer|

これを行うためのAPI仕様は[こちら](https://docs.konghq.com/konnect/api/portal-management/latest/#/Portal%20Team%20Membership/add-developer-to-portal-team)となる。
パスは`/v2/portals/${PORTAL_ID}/teams/${TEAM_ID}/assigned-roles `となり、Dev PortalのIDとTeamのIDが必要となっている。
また、ボディは以下のようになる。
```json
       "role_name": "'"$ROLE_NAME"'",
       "entity_type_name": "Services",
       "entity_region":"us",
       "entity_id": "'"$PRODUCT_ID"'"
```
元のAPI仕様だと読み取りづらいのだが、以下のようになる。
- `role_name`: ロール名。`API Viewer`か`API Consumer`を指定する
- `entity_type_name`: 恐らく`Services`で固定
- `entity_region`: 利用するリージョンを指定
- `entity_id`: API ProductのIDを指定。全てのAPI Productに対してロールを当てる場合は`"*"`を指定。

これを実行するスクリプトは以下となる。
<details><summary>ロール割当用スクリプト（クリックすると展開）：</summary><div>

```sh:add_role.sh
#!/bin/bash
KONNECT_TOKEN==kpat_ER1WQ0rnLX82VJxxx

set -x

PORTAL_ID=$(curl -X GET -s \
    https://us.api.konghq.com/v2/portals \
    -H "Authorization: Bearer $KONNECT_TOKEN" \
    | jq -r '.data[] | select(.name == "default-dev-portal") | .id')


assign_role()
{
    TEAM_NAME=$1
    API_NAME=$2
    ROLE_NAME=$3

    TEAM_ID=$(curl -s -X GET \
        https://us.api.konghq.com/v2/portals/${PORTAL_ID}/teams \
        -H "Authorization: Bearer $KONNECT_TOKEN" \
        | jq -r --arg team_name "$TEAM_NAME" '.data[] | select(.name == $team_name) | .id')

    PRODUCT_ID=$(curl -X GET -s \
      https://us.api.konghq.com/v2/api-products \
      -H "Authorization: Bearer $KONNECT_TOKEN" \
       | jq -r '.data[] | select(.name == "'"$API_NAME"'") | .id')

    curl -X POST \
      https://us.api.konghq.com/v2/portals/${PORTAL_ID}/teams/${TEAM_ID}/assigned-roles \
      -H "Authorization: Bearer $KONNECT_TOKEN" \
      -H 'Content-Type: application/json' \
      -d '{
       "role_name": "'"$ROLE_NAME"'",
       "entity_type_name": "Services",
       "entity_region":"us",
       "entity_id": "'"$PRODUCT_ID"'"
       }'
}

assign_role "All User" "IntraAPI" "API Viewer"

assign_role "Proper Developer" "IntraAPI" "API Viewer"
assign_role "Proper Developer" "CorporateAPI" "API Consumer"
assign_role "Proper Developer" "CustomerAPI" "API Consumer"

assign_role "All Developer" "IntraAPI" "API Viewer"
assign_role "All Developer" "CorporateAPI" "API Viewer"
```
</div></details>


実行後、KonnectのUIからロールがアサインされたことが確認できる。
![20241009104544.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/20ffe35e-e664-079e-dc4c-94e7d7eb1ee5.png)

次にDev PortalとOIDCを連携させる。
OIDCとの連携手順は[こちら](https://qiita.com/ipppppei/items/7da1349bb50532b94f54)で書いた手順をそのまま使って連携するため、ここでは手順の紹介は省略する。
ただし、今回はEntra IDのロールを使ってマッピングを行うため、KonnectのClaim MappingsのGroupsは`roles`に変更する。
![20240924164305.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/8827ccbc-047f-cd52-ca15-1f825cc6927f.png)

設定後、Entra ID側でアプリロールを作成する。
OIDC連携手順実施時に作成したアプリの`アプリの登録`->`アプリロール`->`アプリロールの作成`から以下のような感じでそれぞれのロールを作成する。
![20240924152418.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/5dbd1cad-b9f7-55fe-fe5d-890c2be73d20.png)

`値`の欄は空白は設定できないので、名前の空白を詰めたものを設定している。
作成後のロール一覧は以下のような感じになる。
![20240924164821.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/65b02b65-77c2-3405-2e2b-900693f88765.png)

Entra IDのユーザとロールの割り当ては動作検証時に行うため、ここでは一旦スキップする。

最後に作成したロールとKonnect上のTeamをマッピングする。
Dev Portal選択後、`Settings`->`Team Mappings`を選択し、`IdP Mapping Enabled`にチェックを入れて先ほど設定したロールの`値`をGroup Nameに埋めていく。
![20240924152906.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/e84daeb4-0cb4-9ad1-860f-7e740c4937d5.png)
以上でOIDC連携の設定は完了となる。

### Dev PortalのRBACの有効化と動作確認

RBACの有効化に移る。
Dev Portal選択後、`Settings`->`General`を選択し、Portal RBACの項目の右のEnabledを有効化するとTeamで設定したRBACが有効化される。
この状態でアクセスすると、まだログインアカウントはどのTeamにも属していないためProductは表示されない。
![20240924165719.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/27eea6db-78ff-0e53-a080-c8c6117e70c5.png)  

次にアカウントをどこかのTeamに属させてみる。
Entra IDのエンタープライズアプリケーションから`ユーザとグループ`で対象アカウントのチェックボックスを選択後、`割り当ての編集`からロールを割り当てる。
![20240924152734.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/105769e1-e25b-8f45-e415-532077ce21b1.png)

ここでは`All Developer`に変更してみる。
ロールを割り当て後、Dev Portalにログインすると以下のようにCustomer APIを除くAPI Productが表示される。
![20240924173146.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/b825949d-1c33-0cda-5cc2-f69200d629c3.png)
また、アカウントをクリックして`My Apps`からアプリケーションを作成しようとしても、アプリケーションを作成することが出来ない。
![20241010130553.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/b80cc03d-6166-fe12-4912-9b3e5e19a2e2.png)

権限としては読み取り権限しか設定していないので、意図した通りの挙動となっている。
なお、KonnectからDevelopersを確認すると、ログインしたユーザが登録されている事が分かる。
OIDCとRBACを連携させた場合はKonnect側でのユーザ作成は不要となる。

次にProper Developerにロールを変更して再度ログインしてみる。
先ほど同様にEntra IDでロールを変更後、Dev Portalをログアウトして再度ログインする。
![20240924174800.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/80778ec5-2592-e5c9-3067-75056aaddd06.png)
今度は全てのAPI Productが表示された。
またアプリケーションも作成可能となっている。
![20241010130702.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/faf3d597-c42b-d970-77d7-fe74c4153999.png)
念の為作成してみる。
![20241010130732.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/ac91ab8c-5b4e-f581-31ce-bb87d7982bd4.png)
そのまま生成すると無事生成でき、My Appからは以下のような感じで確認できるようになる。
![20241010130810.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/9d1f184b-6e28-0353-1836-f541c92ff66c.png)

## 所感
権限分離については用意されているロールは少ないものの、世の中によくあるユースケースはカバーできるようになっており、使い勝手は悪くないと思う。
OIDCとの連携も簡単であった。
一方で、APIの設定が非常に苦労した（一度挫折して記事化を断念したくらい）。
Konnectのドキュメントでこのあたりの記載はほとんどなく、[APIの仕様書](https://docs.konghq.com/api/)もKonnectの機能ごとに分かれていて、UIのどの操作がどのAPIに対応するのかを追うのが非常に難しい。
またAPIの仕様書の記載も不十分だったりミスがあったりと、一筋縄では行かなかった。
初めてAPIによる自動化を試す人は自力でトライするのもいいが、有識者などに相談するのもありかと思う。
もしくはKonnectの[Terraform Provider](https://registry.terraform.io/providers/kong/konnect/latest/docs)を使うとかも良さそう。