6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Authorization Management Service (AMS)を利用したCAPの権限管理

Last updated at Posted at 2024-12-03

はじめに

この記事は SAP Advent Calendar 2024 の12月4日分の記事として執筆しています。

Authorization Management Service (AMS)とは、Cloud Identity Servicesの中にある、エンドユーザのアプリケーション利用権限を管理するためのコンポーネントです。「認証・認可」の認可の部分を担います。

image.png
出典:Authorization Management Service in SAP Cloud Identity Service

SAP BlogCAPのドキュメントでは、SAP BTPは認可の管理をXSUAAからAMSへ移行しつつあると述べられています。BTPでのアプリケーション開発や権限管理を行うにあたっては、気になる情報です。そこでこの記事では、AMSを利用した権限管理の概要と、CAPでAMSを利用した権限管理をする方法について紹介します。

AMSを利用した権限管理の仕組み

アクセス権限の管理にポリシーを利用する

AMSでは、ポリシーを利用してアプリケーションへのアクセス権限を管理します。ポリシーとは、ユーザがリソースに対して特定のアクションを実行する権限があるかどうかを決定するためのルールのセットです。ポリシーをユーザに割り当てることで、ユーザはポリシーで許可された権限を持つようになります。

ポリシーの例(Authorization Management Service in SAP Cloud Identity Serviceより抜粋)
image.png

既存の複数のポリシーをまとめたポリシーを作成することもできます。
image.png

ポリシー = グループとなる

SAP Cloud Identity Serviceでは、デフォルトではポリシーを利用した権限管理は有効化されていません。テナントの設定で有効化する必要があります(参考:Configure Authorizations Based on Policies)。

image.png

ポリシーを有効化することにより、定義されたポリシーがグループとして表示されるようになります。ユーザにグループを割り当てることで、ポリシーも自動的に割り当たることになります。
image.png

ポリシーがたくさんある場合は?
複数のアプリケーションでそれぞれポリシーを定義している場合、個別のポリシー(グループ)をユーザに割り当てる必要があるのでしょうか。

ロールコレクションを使っている場合は、複数のロールコレクションを1つのグループにマッピングしておくことで、ユーザには1つのグループの割りてで済んでいました。同じようなことはポリシーでも実現できるでしょうか。

image.png

複数のポリシーをまとめたポリシーを作成することは可能です。ただ、アプリケーションをまたいでまとめることはできないので、ロールコレクションを使用した方法に比べて多くのポリシー(グループ)をユーザに割り当てる必要がありそうです。

image.png

CAPの権限管理もXSUAAからAMSに移行するらしい

CAPのドキュメントによると、新規に開発するアプリケーションでは、AMSの利用が推奨されるとのことです。

SAP BTPでは現在、XSUAAを用いた認可の管理を、AMSを統合したソリューションに置き換えつつあります。AMSはSAP Cloud Identity(SCI)に統合されており、認証、認可、ユーザーのプロビジョニングと管理を一元化して提供します。
新たに構築するアプリケーションでは、一般的にAMSの使用が推奨されます。

しかし、ドキュメントの中でAMSについて記述があるのはこの部分のみで(2024年11月現在)、具体的にどのように設定するかについては記載がありません。

チュートリアルがあった

以下にチュートリアルがあったので、実施してみました。しかし、ビルドでエラーになってしまいデプロイできていません。

発生したエラー
mbt buildを実行すると、以下のエラーが出ます。

TypeError [ERR_INVALID_ARG_TYPE]: The "paths[0]" argument must be of type string. Received undefined
    at Object.resolve (node:path:1101:7)
    at Object.to (/home/miyasuta/projects/incident-management-2411/node_modules/@sap/cds-dk/lib/build/plugin.js:136:37)
    at Object.compileCds (/home/miyasuta/projects/incident-management-2411/node_modules/@sap/ams-dev/src/cap/capAmsFlow.js:27:30)
    at async AmsBuildPlugin.build (/home/miyasuta/projects/incident-management-2411/node_modules/@sap/ams-dev/src/cap/AmsBuildPlugin.js:39:3)
    at async Promise.allSettled (index 0)
    at async BuildTaskEngine._executePipeline (/home/miyasuta/projects/incident-management-2411/node_modules/@sap/cds-dk/lib/build/buildTaskEngine.js:159:29)
    at async BuildTaskEngine._executeBuildTasks (/home/miyasuta/projects/incident-management-2411/node_modules/@sap/cds-dk/lib/build/buildTaskEngine.js:150:25)
    at async BuildTaskEngine.processTasks (/home/miyasuta/projects/incident-management-2411/node_modules/@sap/cds-dk/lib/build/buildTaskEngine.js:59:33)
    at async build (/home/miyasuta/projects/incident-management-2411/node_modules/@sap/cds-dk/lib/build/index.js:19:16)
    at async Object.build (/home/miyasuta/projects/incident-management-2411/node_modules/@sap/cds-dk/bin/build.js:171:5) {
  code: 'ERR_INVALID_ARG_TYPE'
}

同様のエラーがissueとして上がっていますが、未解決(というか、放置されている状態)です。

CAPでAMSを使うための手順

現状まだうまくいっていませんが、参考としてチュートリアルをベースにCAPでAMSを使うためにの手順について説明します。まだAMSが出始めということもありcds addコマンドなどで設定できず、全てマニュアルで設定する必要があります。これが大変でした。

前提とするCAPのサービス定義は以下のようになっています。

using { sap.capire.incidents as my } from '../db/schema';

/**
 * Service used by support personell, i.e. the incidents' 'processors'.
 */
service ProcessorService { 
    entity Incidents as projection on my.Incidents;

    @readonly
    entity Customers as projection on my.Customers;
}

annotate ProcessorService.Incidents with @odata.draft.enabled; 
annotate ProcessorService with @(requires: 'support');

/**
 * Service used by administrators to manage customers and incidents.
 */
service AdminService {
    entity Customers as projection on my.Customers;
    entity Incidents as projection on my.Incidents;
}

annotate AdminService with @(requires: 'admin');

1. dependencyの追加

以下のモジュールをインストールします。

npm install @sap/ams
npm install @sap/ams-dev --save-dev

@sap/amsはSAP Cloud Identity Services経由で認証されたユーザの権限チェックを行います。@sap/ams-devは開発時の権限チェック、およびdclという拡張子でポリシーを記述したファイルの生成を行います。

2. ローカル実行のための設定

ローカル実行時の権限チェックのため、以下の設定をpackage.json/cds/requires/[development]/authに追加します。

  "ams" : {
    "autoCompile" : true,
    "cache" : {
          "TTL" : 0
      }
    }

ローカル実行用のテストユーザをpackage.json/cds/requires/[development]/auth/usersに追加します。"policies": [...]でポリシーを指定するところが従来との違いです(ポリシーにはcap.のプリフィックスがつくことに注意)。

    "users": {
        "alice": {
          "policies" : [
              "cap.support"
          ]
        },
        "bob": {
        }
    }

ここまでで"cds"セクション全体は以下のようになります。

"cds": {
    "requires": {
      "[development]": {
        "auth": {
          "ams" : {
            "autoCompile" : true,
            "cache" : {
                  "TTL" : 0
            }
          },
          "kind": "mocked",
          "users": {
            "alice": {
              "policies" : [
                  "cap.support"
              ]
            },
            "bob": {
            }
          }
        }
      },
      "[production]": {
        "auth": "xsuaa",
        "db": "hana"
      }
    }

cds watchを実行すると、以下のフォルダが生成されます。

  • ams/dcl
  • gen/srv/ams/dcl

image.png

gen/srv/ams/dcl/cap/basePolicies.dclには、サービスに設定したアノテーションをもとに自動生成されたポリシーが設定されます。

// ----------------------------------------------------------------------------------
// Generated from a CAP model by the SAP AMS Dev Plugin (@sap/ams-dev)
// ----------------------------------------------------------------------------------

POLICY "support" {
    GRANT "support" ON $SCOPES;
}

POLICY "admin" {
    GRANT "admin" ON $SCOPES;
}

ams/dclは空です。ここには追加のポリシーを格納することができると思われます(チュートリアルでは使用していませんでした)。

ProcessorServiceに"alice"というユーザでログインすると、以下のエラーが出ました。supportのロールが割り当たっていないため権限がないとみなされています。

[cds] - Error: Forbidden
    at requires_check (/home/miyasuta/projects/incident-management-2411/node_modules/@sap/cds/lib/srv/protocols/http.js:54:32)
    at Layer.handle [as handle_request] (/home/miyasuta/projects/incident-management-2411/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/miyasuta/projects/incident-management-2411/node_modules/express/lib/router/index.js:328:13)
    at /home/miyasuta/projects/incident-management-2411/node_modules/express/lib/router/index.js:286:9
    at Function.process_params (/home/miyasuta/projects/incident-management-2411/node_modules/express/lib/router/index.js:346:12)
    at next (/home/miyasuta/projects/incident-management-2411/node_modules/express/lib/router/index.js:280:10)
    at http_log (/home/miyasuta/projects/incident-management-2411/node_modules/@sap/cds/lib/srv/protocols/http.js:42:59)
    at Layer.handle [as handle_request] (/home/miyasuta/projects/incident-management-2411/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/miyasuta/projects/incident-management-2411/node_modules/express/lib/router/index.js:328:13)
    at /home/miyasuta/projects/incident-management-2411/node_modules/express/lib/router/index.js:286:9 {
  code: 403,
  reason: "User 'alice' is lacking required roles: [support]",
  user: User {
    id: 'alice',
    tenant: 't1',
    roles: { admin: 1 },
    policies: [ 'cap.support' ],
    features: [ 'isbn' ],
    attr: {},
    tokenInfo: { getPayload: [Function: getPayload] }
  },
  required: [ 'support' ]

amsでの権限チェックになっているか怪しいですが、一旦package.jsonにsupportのロールも追加します。

          "users": {
            "alice": {
              "policies" : [
                  "cap.support"
              ],
              "roles": [
                "support"
              ]
            },
            "bob": {
            }
          }

その結果、"alice"でデータを表示することができました。
image.png

3. デプロイのための設定

Cloud Foundryにデプロイするための設定を行います。

3.1. ias-config.jsonを追加

プロジェクトのルートにias-config.jsonファイルを追加します。<unique-id>には、Cloud Identity Services上でアプリケーションを識別するための一意なIDを指定します。

ias-config.json
    {
      
        "authorization": {
          "enabled":true
        },
        "provided-apis": [
            {
              "name": "incidents-api",
              "description": "api exposed by incident mgmt app"
            }
          ],
        "display-name": "incident-ias-<unique-id>"
    }
3.2. production用のauth設定

package.json/cds/requires/[production]/authiasを指定します。XSUAAの代わりにIASで認証するということです。

  "cds": {
    "requires": {
      "[development]": {...},
      "[production]": {
        "auth": "ias",
        "db": "hana"
      }
    }
3.3. mta.yamlの設定

①XSUAAの代わりにIASを使う
resourcesセクションでxsuaaの代わりにidentity(IAS)のサービスを指定します。pathには3.1.で定義したias-config.jsonを指定します。

resources:
  - name: incident-management-auth
    parameters:
      path: ./ias-config.json
      service-plan: application
      service: identity
    type: org.cloudfoundry.managed-service

②サービスモジュールの設定
サービスモジュールに以下の設定を追加します。

- name: incident-management-srv
  type: nodejs
  path: gen/srv
  requires:
  - name: incident-management-db
  - name: incident-management-auth
  # 追加 -----------------------------------
    parameters:
      config:
         credential-type: "X509_GENERATED"
  properties:
    AMS_DCL_ROOT: ams/dcl
  #----------------------------------------  

③ams-policies-deployerを追加
ポリシーをデプロイするため、以下のモジュールを追加します。

- name: incident-management-ams-policies-deployer
  type: javascript.nodejs
  path: gen/policies
  parameters:
    buildpack: nodejs_buildpack
    no-route: true
    no-start: true
    tasks:
      - name: deploy-dcl
        command: npm start
        memory: 512M
  requires:
    - name: incident-management-auth
      parameters:
        config:
          credential-type: X509_GENERATED
          app-identifier: policy-deployer

④destination-contentの設定
UIを含んだプロジェクトの場合、destination-contentを以下のように調整します。

このチュートリアルはXSUAAベースでアプリケーションを作ってからAMS向けに調整するという手順のため、XSUAA絡みの設定が残っています。それを削除するステップです。

  • XSUAAのサービスインスタンスのバインディングを削除
  • XSUAAのためのdestinationを削除

最終的に、destination-contentの設定は以下のようになります。

- name: incident-management-destination-content
  type: com.sap.application.content
  requires:
    - name: incident-management-destination-service
      parameters:
        content-target: true
    - name: incident-management_html_repo_host
      parameters:
        service-key:
          name: incident-management_html_repo_host-key
    parameters:
      content:
        instance:
          destinations:
          - Name: incidents_incidents_management_html_repo_host
            ServiceInstanceName: incident-management-html5-app-host-service
            ServiceKeyName: incident-management_html_repo_host-key
            sap.cloud.service: incidents
          existing_destinations_policy: ignore
    build-parameters:
      no-source: true

⑤サービス宛先にパラメータを追加
resourcesセクションのdestinationサービスの定義の中にあるCAPのサービス宛先に、HTML5.IASDependencyName: incidents-apiというパラメータを追加します。incidents-apiというのは、ias-config.jsonの中でprovided-apis[0].nameに指定したのと同じ値です。

- name: incident-management-destination-service
  type: org.cloudfoundry.managed-service
  parameters:
    config:
      HTML5Runtime_enabled: true
      init_data:
        instance:
          destinations:
          - Authentication: NoAuthentication
            Name: ui5
            ProxyType: Internet
            Type: HTTP
            URL: https://ui5.sap.com
          - Authentication: NoAuthentication
            HTML5.IASDependencyName: incidents-api
            HTML5.DynamicDestination: true
            HTML5.ForwardAuthToken: true
            Name: incident-management-srv-api
            ProxyType: Internet
            Type: HTTP
            URL: ~{srv-api/srv-url}
          existing_destinations_policy: update
      version: 1.0.0
    service: destination
    service-name: incident-management-destination-service
    service-plan: lite
3.4. xs-app.jsonの設定

UIを含んだプロジェクトの場合、app/<appname>/xs-app.jsonファイルで各ルートに指定されたauthenticationTypexsuaaからiasに変更します。

   {
   "welcomeFile": "/index.html",
   "authenticationMethod": "route",
   "routes": [
     {
       "source": "^/odata/(.*)$",
       "target": "/odata/$1",
       "destination": "incident-management-srv-api",
       "authenticationType": "ias",
       "csrfProtection": false
     },
     {
       "source": "^/resources/(.*)$",
       "target": "/resources/$1",
       "authenticationType": "none",
       "destination": "ui5"
     },
     {
       "source": "^/test-resources/(.*)$",
       "target": "/test-resources/$1",
       "authenticationType": "none",
       "destination": "ui5"
     },
     {
       "source": "^(.*)$",
       "target": "$1",
       "service": "html5-apps-repo-rt",
       "authenticationType": "ias"
     }
   ]
 }

4. デプロイ後

現状ビルド・デプロイができていませんが、チュートリアルによれば、デプロイ後は以下の状態になります。

  • IASテナントにアプリケーションができる(下図の③)
  • アプリケーションのAuthorization Policiesタブにアップロードしたポリシーが登録されている(下図の④)…gen/srv/ams/dcl/cap/basePolicies.dclで定義されたもの
    image.png

登録されたポリシーにユーザを割り当てることにより、サービスを利用する権限が割り当たります。チュートリアルではさらに、SAP Build Work Zoneからサービスを利用できるようにするための設定などが続きます。

権限管理の流れはどのように変わるのか

XSUAAを利用した方法とAMSを利用した方法とで、アプリケーション(CAP)の権限定義からユーザへ割り当てるまでの流れがどのように変わるのかを比較してみました。

image.png

XSUAAを使用する場合はアプリケーション、BTPコックピット、Cloud Identity Servicesの3か所での作業があります。これに対し、AMSを使用する場合はアプリケーションとCloud Identity Servicesの2か所で済むことがわかります。

おわりに

AMSを利用した権限管理はまだ登場したばかりのため、開発時とデプロイ後に多くのマニュアル設定が必要です。現時点ではAMSの利用はかなりハードルが高い(というか無理)です。この点は、おそらく来年にはcds addコマンドやプラグインなどが追加されて、使いやすくなると考えられます。
そのうえで、AMSを使うメリットはXSUAAを上回るのでしょうか。確かに「ロールコレクションとグループのマッピング」という、BTPコックピットで行っていた作業は不要になるものの、Cloud Identity Services側でユーザに多くのグループ(ポリシー)の割り当てが必要になる可能性があります(「ポリシーがたくさんある場合は?」参照)。
個人的にはまだAMSに懐疑的なのですが、SAPはそちらに向かうといっているので、来年ドキュメントがもう少し充実したら改めてチャレンジしたいです。

参考

6
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?