APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

Backstage のPermission Frameworkを理解する

はじめに

みなさん、 Backstage活用されていますか??
ご存知無い方のためにあらためて。BackstageはCNCFのプロジェクトの1つで、拡張性の高い開発者ポータルのOSSです。機能拡張などはPluginを追加導入することで実現します。

Backstageでは組織内で開発する様々なサービス、アプリケーション、インフラストラクチャリソースをソフトウェアカタログとして登録し、利用者間でそうした情報を共有したりすることができます。

このソフトウェアカタログですが、デフォルトではすべてのリソースが利用者全員参照・更新できるようになっています。

しかし、実際の開発チームにおいては、特定の開発チームやユーザーのみ更新可能にしたい、閲覧可能なユーザーを限定したいといった需要があるかと思います。

そうした要望に応えるためにBackstageではPermission Frameworkというものを用意しています。

今回はこのPermission Frameworkの基本について簡単にご紹介したいと思います。

Permission Frameworkの基礎

Permission Frameworkの動作説明

まずはじめにPermission Frameworkがどのように動作するかをご紹介します。

公式ドキュメントにも記載がありますが、以下のような構成になっています。

Permission Frameworkこの図の右の部分で、Permission機能を有効にしたPluginから呼び出され、その動作可否を「ALLOW」「DENY」「条件付き許可(CONDITIONAL)」のいずれかで決定します。

PluginからPermission Frameworkを呼び出される際に渡される情報は、Permission名やそのオプション情報、そして利用者のユーザー情報の3つになります。

Permission名

Permission名については具体的な例をみていただくとわかりやすいと思います。

ソフトウェアカタログの中の一番基本的な情報がcatalog entityです。また、そのカタログ情報の定義元URLを管理しているのがcatalog locationというものになります。

これらの情報の参照や更新の各動作に対してPermission名がつけられています。

Permission名の例

  • catalog.entity.read
  • catalog.entity.create
  • catalog.entity.delete
  • catalog.entity.update
  • catalog.location.read
  • catalog.location.create
  • catalog.location.delete

Permission名はPermission Frameworkを利用するPlugin(先程の図の中央の部分)で決定するもので、ここではCRUDの名称だけが定義されていますが、executeといったPermission名がつけられているものもあります。

Permission決定式

続いて実際のPermissionの決定についてです。

一般的には次の2通りがあります。

1つ目が、特定ユーザー・グループだったら無条件にALLOW/DENYとするものです。わかりやすい例で言えば管理者権限でしょうか。 ユーザーが管理者(ないしは管理者グループに属している場合)であれば、無条件にすべての動作を許可すると思います。 また、全ユーザーに対して catalog.entity.readは 許可するが、それ以外の場合は利用を拒否するといった指定もあると思います。

2つ目がアクセスしようとするリソースの内容によって決定するものです。 例えば、ユーザー(やグループ)がアクセス対象のカタログエンティティのオーナーであったら許可してよい、といった条件を指定するものです。

ここでポイントになるのがPermission Frameworkにはアクセス対象のリソースの具体的な内容は渡されないというところです。 このため、Permission Framework側は「こういう条件だったら許可してよいので、Plugin側でチェックするように」と条件式そのものをResponseとして返します。

Responseを受け取った呼び出し側のPluginでは、CONDITOINALの条件に合致しているかどうかをチェックしてALLOWかDENYかを最終的に決定します。

条件式に指定できる内容

条件式に指定できる内容は、Permission名同様Permission Frameworkを利用するPlugin(先程の図の中央の部分)で決定するものです。 たとえばさきほどのcatalog entityでは以下のような条件が用意されています。isEntityOwner が説明のところの「カタログエンティティのオーナーだったら」に該当する条件式です。

  • hasAnnotatons
  • hasLabel
  • hasMetadata
  • hasSpec
  • isEntityKind
  • isEntityOwner

Policyの指定方法

ALLOW/DENY/CONDITIONALを決定する指定をPolicyといいますが、実際どのように指定するかを見ていきたいと思います。

実は、Policyの指定についてはBackstage本体だけで実現する場合、かなり面倒です。というのもソースコードで記載しなければならないからです。

たとえば 「全ユーザー、catalog.entity.deleteはDENY、それ以外はALLOW」といった指定をする場合、以下のようなコードを記述して登録します。(公式ドキュメントはこちら

import { createRouter } from '@backstage/plugin-permission-backend';
import {
  AuthorizeResult,
  PolicyDecision,
} from '@backstage/plugin-permission-common';
import { PermissionPolicy } from '@backstage/plugin-permission-node';
import {
  PermissionPolicy,
  PolicyQuery,
} from '@backstage/plugin-permission-node';
import { Router } from 'express';
import { PluginEnvironment } from '../types';

class TestPermissionPolicy implements PermissionPolicy {
  async handle(): Promise<PolicyDecision> {
  async handle(request: PolicyQuery): Promise<PolicyDecision> {
    if (request.permission.name === 'catalog.entity.delete') {
      return {
        result: AuthorizeResult.DENY,
      };
    }

    return { result: AuthorizeResult.ALLOW };
  }
}

また、CONDITIONALな条件を指定する場合は以下のようなコードを記述します。

class TestPermissionPolicy implements PermissionPolicy {
  async handle(
    request: PolicyQuery,
    user?: PolicyQueryUser,
  ): Promise<PolicyDecision> {
    if (isResourcePermission(request.permission, 'catalog-entity')) {
      return createCatalogConditionalDecision(
        request.permission,
        {
          anyOf: [
            catalogConditions.isEntityOwner({
              claims: user?.info.ownershipEntityRefs ?? [],
            }),
            isInSystem({ systemRef: 'interviewing' }),
          ],
        },
      );
    }

    return { result: AuthorizeResult.ALLOW };
  }
}

これを組織に合わせて細かく実装するのは現実的ではないかもしれません。 しかし、Permission Frameworkを理解する際には、こうした実装が必要になるということを理解しておいてください。

もちろんこの部分をもう少し簡単に記述することも可能です。ただし、それはBackstage本体ではなく、3rd partyで用意している別のPluginを利用することになります。現在私自身が把握している範囲では3rd party pluginは3種類存在しています。そららのPluginを利用した場合のそれぞれ利点や課題といったものもあります。簡単にPolicyを記述する機能については現在評価を進めていますので別の機会にご紹介したいと思います。

また、実際にPolicyを定義しようとするとだんだんわかってくるのですが、組織の中でPolicyをどのように定義していけばよいかというのも結構悩みます。そうしたPolicyの定義のやり方については別の機会にご紹介させていただきます。

最後に

BackstageにおけるPermission Frameworkの基本動作をご紹介しました。また、基本的なPolicyの指定方法についてもご覧いただきました。 まずはこういった権限管理機構がある、ということをご認識いただければ幸いです。

最後に弊社ではBackstageの導入や運用をManagedで行うサービスを提供しています。今後は上記のようなPermission Frameworkも有効にし、Policyの定義方法のガイドなどもあわせて提供していきたいと考えておりますので、ご興味のある方はぜひご連絡ください。

techblog.ap-com.co.jp