はじめに
この記事は SAP Advent Calendar 2024 の12月4日分の記事として執筆しています。
Authorization Management Service (AMS)とは、Cloud Identity Servicesの中にある、エンドユーザのアプリケーション利用権限を管理するためのコンポーネントです。「認証・認可」の認可の部分を担います。
出典:Authorization Management Service in SAP Cloud Identity Service
SAP BlogやCAPのドキュメントでは、SAP BTPは認可の管理をXSUAAからAMSへ移行しつつあると述べられています。BTPでのアプリケーション開発や権限管理を行うにあたっては、気になる情報です。そこでこの記事では、AMSを利用した権限管理の概要と、CAPでAMSを利用した権限管理をする方法について紹介します。
AMSを利用した権限管理の仕組み
アクセス権限の管理にポリシーを利用する
AMSでは、ポリシーを利用してアプリケーションへのアクセス権限を管理します。ポリシーとは、ユーザがリソースに対して特定のアクションを実行する権限があるかどうかを決定するためのルールのセットです。ポリシーをユーザに割り当てることで、ユーザはポリシーで許可された権限を持つようになります。
ポリシーの例(Authorization Management Service in SAP Cloud Identity Serviceより抜粋)
既存の複数のポリシーをまとめたポリシーを作成することもできます。
ポリシー = グループとなる
SAP Cloud Identity Serviceでは、デフォルトではポリシーを利用した権限管理は有効化されていません。テナントの設定で有効化する必要があります(参考:Configure Authorizations Based on Policies)。
ポリシーを有効化することにより、定義されたポリシーがグループとして表示されるようになります。ユーザにグループを割り当てることで、ポリシーも自動的に割り当たることになります。
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
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"でデータを表示することができました。
3. デプロイのための設定
Cloud Foundryにデプロイするための設定を行います。
3.1. ias-config.jsonを追加
プロジェクトのルートにias-config.json
ファイルを追加します。<unique-id>
には、Cloud Identity Services上でアプリケーションを識別するための一意なIDを指定します。
{
"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]/auth
にias
を指定します。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
ファイルで各ルートに指定されたauthenticationType
をxsuaa
から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
で定義されたもの
登録されたポリシーにユーザを割り当てることにより、サービスを利用する権限が割り当たります。チュートリアルではさらに、SAP Build Work Zoneからサービスを利用できるようにするための設定などが続きます。
権限管理の流れはどのように変わるのか
XSUAAを利用した方法とAMSを利用した方法とで、アプリケーション(CAP)の権限定義からユーザへ割り当てるまでの流れがどのように変わるのかを比較してみました。
XSUAAを使用する場合はアプリケーション、BTPコックピット、Cloud Identity Servicesの3か所での作業があります。これに対し、AMSを使用する場合はアプリケーションとCloud Identity Servicesの2か所で済むことがわかります。
おわりに
AMSを利用した権限管理はまだ登場したばかりのため、開発時とデプロイ後に多くのマニュアル設定が必要です。現時点ではAMSの利用はかなりハードルが高い(というか無理)です。この点は、おそらく来年にはcds add
コマンドやプラグインなどが追加されて、使いやすくなると考えられます。
そのうえで、AMSを使うメリットはXSUAAを上回るのでしょうか。確かに「ロールコレクションとグループのマッピング」という、BTPコックピットで行っていた作業は不要になるものの、Cloud Identity Services側でユーザに多くのグループ(ポリシー)の割り当てが必要になる可能性があります(「ポリシーがたくさんある場合は?」参照)。
個人的にはまだAMSに懐疑的なのですが、SAPはそちらに向かうといっているので、来年ドキュメントがもう少し充実したら改めてチャレンジしたいです。