본문 바로가기
WIKI 기술 지식 베이스

스캐폴더 작업, 매개변수, 단계, 액션 인가하기

원문 보기 위키 갱신

스캐폴더 플러그인은 Backstage 권한 프레임워크와 통합되어, 템플릿을 실행하는 사용자에 따라 템플릿의 특정 매개변수와 단계에 대한 접근을 제어할 수 있게 합니다. 또한 스캐폴더 작업에 대한 접근도 제어할 수 있게 해 줍니다.

출처: 문서

본문

스캐폴더 플러그인은 Backstage 권한 프레임워크와 통합되어, 템플릿을 실행하는 사용자에 따라 템플릿의 특정 매개변수와 단계에 대한 접근을 제어할 수 있게 합니다. 또한 스캐폴더 작업에 대한 접근도 제어할 수 있게 해 줍니다.

팁

다음 예시를 더 잘 이해하려면 진행하기 전에 Writing a permission policy 문서를 검토하세요.

인라인 템플릿 드라이 런 인가

templateDryRunPermission 권한은 인라인 소프트웨어 템플릿 드라이 런을 제출할 수 있는 사람을 제어합니다. 그것은 /v2/dry-run 엔드포인트와 scaffolder:dry-run-template 백엔드 액션 모두에 적용됩니다.

선택된 사용자나 서비스만 인라인 템플릿을 제출할 수 있어야 할 때 이 권한을 사용하세요. 직접 드라이 런 요청은 또한 taskCreatePermission을 요구하며, 백엔드 액션은 호출자의 자격 증명으로 같은 엔드포인트를 호출합니다. actionExecutePermission 권한은 여전히 드라이 런이 실행하는 각 액션을 인가합니다.

예를 들어, 다음 정책은 사용자 alice만 인라인 템플릿 드라이 런을 제출하도록 허용합니다.

packages/backend/src/plugins/permission.ts

import { templateDryRunPermission } from '@backstage/plugin-scaffolder-common/alpha';import {  AuthorizeResult,  isPermission,  PolicyDecision,} from '@backstage/plugin-permission-common';import {  PermissionPolicy,  PolicyQuery,  PolicyQueryUser,} from '@backstage/plugin-permission-node';class ExamplePermissionPolicy implements PermissionPolicy {  async handle(    request: PolicyQuery,    user?: PolicyQueryUser,  ): Promise<PolicyDecision> {    if (isPermission(request.permission, templateDryRunPermission)) {      return {        result:          user?.info.userEntityRef === 'user:default/alice'            ? AuthorizeResult.ALLOW            : AuthorizeResult.DENY,      };    }    return { result: AuthorizeResult.ALLOW };  }}

매개변수와 단계 인가

특정 매개변수나 단계에 권한이 필요하다고 표시하려면, 매개변수 또는 단계에 하나 이상의 태그와 함께 backstage:permissions 속성을 추가하세요. 예를 들어:

apiVersion: scaffolder.backstage.io/v1beta3kind: Templatemetadata:  name: my_custom_templatespec:  type: service  parameters:    - title: Provide some simple information      properties:        title:          title: Title          type: string    - title: Extra information      properties:        description:          title: Description          type: string      backstage:permissions:        tags:          - secret  steps:    - id: step1      name: First log      action: debug:log      input:        message: hello    - id: step2      name: Log message      action: debug:log      input:        message: hello      backstage:permissions:        tags:          - secret

이 예시에서 description 매개변수와 step2 단계는 secret 태그로 표시됩니다.

템플릿을 실행하는 사용자에 따라 매개변수와 단계를 조건부로 인가하려면, 스캐폴더 플러그인이 제공하는 templateParameterReadPermission과 templateStepReadPermission 권한을 대상으로 권한 정책을 편집하세요. 예를 들어:

packages/backend/src/plugins/permission.ts

import {  templateParameterReadPermission,  templateStepReadPermission,} from '@backstage/plugin-scaffolder-common/alpha';import {  createScaffolderActionConditionalDecision,  scaffolderTemplateConditions,} from '@backstage/plugin-scaffolder-backend/alpha';class ExamplePermissionPolicy implements PermissionPolicy {  async handle(    request: PolicyQuery,    user?: PolicyQueryUser,  ): Promise<PolicyDecision> {    if (      isPermission(request.permission, templateParameterReadPermission) ||      isPermission(request.permission, templateStepReadPermission)    ) {      if (user?.info.userEntityRef === 'user:default/bob')        return createScaffolderTemplateConditionalDecision(request.permission, {          not: scaffolderTemplateConditions.hasTag({ tag: 'secret' }),        });    }    return {      result: AuthorizeResult.ALLOW,    };  }}

이 예시에서 사용자 bob는 secret 태그로 표시된 매개변수나 단계를 읽을 권한이 없습니다.

이 기능을 우리의 위협 모델에서 권장하는 대로 카탈로그에서 템플릿 수집을 제한하는 것과 결합하면, 특정 액션을 제한하는 견고한 시스템을 만들 수 있습니다.

액션 인가

매개변수와 단계와 유사하게, 스캐폴더 플러그인은 특정 액션에 대한 접근을 제한하는 권한을 노출합니다. 템플릿을 보호하고 싶다면 유용할 수 있습니다.

특정 액션에 대한 접근을 제한하려면 권한 정책을 다음과 같이 수정할 수 있습니다.

packages/backend/src/plugins/permission.ts

import { actionExecutePermission } from '@backstage/plugin-scaffolder-common/alpha';import {  createScaffolderActionConditionalDecision,  scaffolderActionConditions,} from '@backstage/plugin-scaffolder-backend/alpha';class ExamplePermissionPolicy implements PermissionPolicy {  async handle(    request: PolicyQuery,    user?: PolicyQueryUser,  ): Promise<PolicyDecision> {    if (isPermission(request.permission, actionExecutePermission)) {      if (user?.info.userEntityRef === 'user:default/alice') {        return createScaffolderActionConditionalDecision(request.permission, {          not: scaffolderActionConditions.hasActionId({            actionId: 'debug:log',          }),        });      }    }    return {      result: AuthorizeResult.ALLOW,    };  }}

이 권한 정책으로 사용자 alice는 debug:log 액션을 실행할 수 없습니다.

여러 규칙을 결합해 액션에 제공되는 입력을 제한할 수도 있습니다. 아래 예시에서 alice는 { "message": "not-this!" }를 액션 입력으로 전달할 때 debug:log를 실행할 수 없습니다.

packages/backend/src/plugins/permission.ts

import { actionExecutePermission } from '@backstage/plugin-scaffolder-common/alpha';import {  createScaffolderActionConditionalDecision,  scaffolderActionConditions,} from '@backstage/plugin-scaffolder-backend/alpha';class ExamplePermissionPolicy implements PermissionPolicy {  async handle(    request: PolicyQuery,    user?: PolicyQueryUser,  ): Promise<PolicyDecision> {    if (isPermission(request.permission, actionExecutePermission)) {      if (user?.info.userEntityRef === 'user:default/alice') {        return createScaffolderActionConditionalDecision(request.permission, {          not: {            allOf: [              scaffolderActionConditions.hasActionId({ actionId: 'debug:log' }),              scaffolderActionConditions.hasProperty({                key: 'message',                value: 'not-this!',              }),            ],          },        });      }    }    return {      result: AuthorizeResult.ALLOW,    };  }}

스캐폴더 작업 인가

스캐폴더 플러그인은 작업, 작업 로그, 작업 생성, 작업 취소에 대한 접근을 제한할 수 있는 권한도 노출합니다. 스캐폴더의 이러한 영역에 누가 접근할 수 있는지 제어하고 싶다면 유용할 수 있습니다. 작업에 대한 접근을 작업 작성자로만 제한하면서, 특정 사용자에게는 모든 작업을 볼 수 있는 권한을 부여하도록 정책을 구성할 수 있습니다.

이를 수행하는 간단한 예는 다음과 같습니다.

packages/src/backend/plugins/permissions.ts

import {  taskCancelPermission,  taskCreatePermission,  taskReadPermission,} from '@backstage/plugin-scaffolder-common/alpha';import {  AuthorizeResult,  isPermission,  PolicyDecision,} from '@backstage/plugin-permission-common';import {  PermissionPolicy,  PolicyQuery,  PolicyQueryUser,} from '@backstage/plugin-permission-node';import {  createScaffolderTaskConditionalDecision,  scaffolderTaskConditions,} from '@backstage/plugin-scaffolder-backend/alpha';class ExamplePermissionPolicy implements PermissionPolicy {  async handle(    request: PolicyQuery,    user?: PolicyQueryUser,  ): Promise<PolicyDecision> {    if (isPermission(request.permission, taskReadPermission)) {      // Allow alice to read any task      if (user?.info.userEntityRef === 'user:default/alice') {        return {          result: AuthorizeResult.ALLOW,        };      }      // Allow users to read tasks they created      return createScaffolderTaskConditionalDecision(        request.permission,        scaffolderTaskConditions.isTaskOwner({          createdBy: user?.info.userEntityRef ? [user?.info.userEntityRef] : [],        }),      );    }    if (isPermission(request.permission, taskCreatePermission)) {      const userArray = ['user:default/bob', 'user:default/alice'];      const allowed = userArray.some(        allowedUser => user?.info.userEntityRef === allowedUser,      );      if (allowed) {        return {          result: AuthorizeResult.ALLOW,        };      }      return {        result: AuthorizeResult.DENY,      };    }    if (isPermission(request.permission, taskCancelPermission)) {      // Allow bob to cancel only his tasks      if (user?.info.userEntityRef === 'user:default/bob') {        return createScaffolderTaskConditionalDecision(          request.permission,          scaffolderTaskConditions.isTaskOwner({            createdBy: user?.info.userEntityRef              ? [user?.info.userEntityRef]              : [],          }),        );      }      // Allow alice to cancel any task      if (user?.info.userEntityRef === 'user:default/alice') {        return {          result: AuthorizeResult.ALLOW,        };      }      return {        result: AuthorizeResult.DENY,      };    }    return {      result: AuthorizeResult.ALLOW,    };  }}

제공된 예시 권한 정책에서, 우리는 사용자 bob에게만 다음 액션/리소스를 수행/접근할 권한을 부여합니다.

  • bob이 만든 스캐폴더 작업과 그와 관련된 이벤트/로그를 읽기.
  • bob이 만든 진행 중인 스캐폴더 작업 취소.
  • 소프트웨어 템플릿 트리거(사실상 새 스캐폴더 작업 생성).

반면 사용자 alice에게는 다음이 부여됩니다.

  • 모든 스캐폴더 작업과 그와 관련된 이벤트/로그에 대한 읽기 접근.
  • 진행 중인 모든 스캐폴더 작업을 취소할 수 있는 능력.
  • 소프트웨어 템플릿을 트리거할 수 있는 능력.

다른 모든 사용자에게는 다음 액션/리소스를 수행/접근할 권한이 부여됩니다.

  • 사용자가 만든 스캐폴더 작업과 그와 관련된 이벤트/로그 읽기.

스캐폴더가 내보내는 규칙은 단순하지만, 그것들을 결합하면 더 복잡한 사용 사례를 달성하는 데 도움이 됩니다.

더 알아보기 (Learn more)