QnA

[QnA] XSUAA Scope가 Role Collection에 안 묶이는 이유 — 완전 해결 가이드

▶ YouTube에서 보기

[QnA] XSUAA Scope가 Role Collection에 안 묶이는 이유 — 완전 해결 가이드

Moderator · 2026. 4. 24. · 조회 6

[QnA] XSUAA Scope가 Role Collection에 안 묶이는 이유 — 완전 해결 가이드

📖 개요 및 학습 목표

SAP BTP에서 애플리케이션 보안을 설정할 때 가장 흔히 마주치는 문제: "xs-security.json에 scope를 정의했는데 왜 Role Collection에 안 보이지?" 이 글에서는 XSUAA(Authorization and Trust Management Service)의 Scope → Role Template → Role Collection 3단계 구조를 명확히 이해하고, 실제로 발생하는 401/403 에러를 체계적으로 해결하는 방법을 다룹니다.

이 글을 읽으면 다음을 할 수 있습니다:

  • ✅ Scope, Role Template, Role Collection의 관계를 명확히 이해하고 설명
  • ✅ xs-security.json을 올바르게 작성하고 XSUAA 인스턴스에 반영
  • ✅ 401/403 에러 발생 시 5가지 체크리스트로 원인을 빠르게 파악
  • ✅ CAP 프로젝트에서 @requires 어노테이션으로 역할 기반 접근 제어 구현
  • ✅ 멀티테넌트 환경에서의 신뢰 구성 문제 해결

대상 독자: BTP Cloud Foundry에 앱을 배포한 경험이 있고, 인증/인가 설정에서 막힌 중급 개발자

📚 선수 지식

  • SAP BTP Cloud Foundry 환경에서 앱 배포 경험 (cf push)
  • OAuth 2.0 기본 개념 — Access Token, Grant Type
  • JSON 파일 편집 및 CF CLI 기본 명령어
  • CAP(Cloud Application Programming) 기초 (선택사항이나 코드 예제에 포함)

🔧 환경 / 버전 / 준비물

  • SAP BTP: Cloud Foundry Runtime (Trial 계정 가능)
  • XSUAA Service: application 플랜 (단일 앱) 또는 broker 플랜 (재사용 서비스)
  • CF CLI: v8 이상 (cf version으로 확인)
  • CAP: @sap/cds 8.x (2024년 이후 릴리스, 선택)
  • 도구: BTP Cockpit 접근 권한, VS Code 또는 터미널

권장: BTP Trial에서 먼저 테스트한 후 프로덕션에 적용하세요.

이 글에서 다루는 것

💡 핵심 개념

XSUAA의 권한 구조를 도서관 출입 시스템에 비유하면 이해가 쉽습니다:

  • Scope = 개별 권한 카드 — "열람실 출입", "대출 가능", "서고 접근" 같은 최소 단위의 권한입니다. xs-security.json에서 정의하며, 앱 코드에서 직접 체크하는 대상입니다. 예: $XSAPPNAME.Read, $XSAPPNAME.Admin
  • Role Template = 권한 묶음 카드 — 여러 Scope를 하나로 묶은 것입니다. "일반 이용자" 카드에는 "열람실 출입 + 대출 가능"이 포함됩니다. 역시 xs-security.json에서 정의합니다.
  • Role Collection = 직원 배지 — BTP Cockpit에서 생성하고, 사용자에게 직접 할당하는 것입니다. Role Template을 Role Collection에 추가하고, Role Collection을 사용자에게 할당합니다.
# XSUAA 권한 흐름 구조
xs-security.json (개발자가 정의)
  └─ scopes: ["Read", "Write", "Admin"]    ← 최소 단위 권한
  └─ role-templates:                         ← Scope 묶음
       ├─ "Viewer"  → [Read]
       └─ "Manager" → [Read, Write, Admin]

BTP Cockpit (관리자가 설정)
  └─ Role Collections:                      ← 사용자에게 할당
       ├─ "AppViewers"  → Viewer Role Template
       └─ "AppManagers" → Manager Role Template
       └─ 사용자 할당: user@company.com → "AppManagers"

흔한 오개념:

  • ❌ "Scope를 정의하면 자동으로 Role Collection이 생긴다" → ⭕ Scope → Role Template는 xs-security.json에서 정의하지만, Role Collection은 BTP Cockpit에서 별도로 생성하고 Role Template을 추가해야 합니다. 이 단계를 빠뜨리면 scope가 있어도 사용자에게 권한이 전달되지 않습니다.
  • ❌ "application 플랜과 broker 플랜은 같다" → ⭕ application 플랜은 단일 앱용, broker 플랜은 재사용 가능한 서비스용입니다. 잘못된 플랜을 선택하면 scope 매핑이 작동하지 않을 수 있습니다.

💻 실전 코드 — 3단계

1단계: xs-security.json 기본 설정

{
  "xsappname": "my-bookshop-app",
  "tenant-mode": "dedicated",
  "scopes": [
    {
      "name": "$XSAPPNAME.Read",
      "description": "Read books"
    },
    {
      "name": "$XSAPPNAME.Write",
      "description": "Create and update books"
    },
    {
      "name": "$XSAPPNAME.Admin",
      "description": "Full admin access"
    }
  ],
  "role-templates": [
    {
      "name": "Viewer",
      "description": "Read-only access",
      "scope-references": ["$XSAPPNAME.Read"]
    },
    {
      "name": "Manager",
      "description": "Read and write access",
      "scope-references": ["$XSAPPNAME.Read", "$XSAPPNAME.Write"]
    },
    {
      "name": "Administrator",
      "description": "Full access including admin",
      "scope-references": ["$XSAPPNAME.Read", "$XSAPPNAME.Write", "$XSAPPNAME.Admin"]
    }
  ],
  "role-collections": [
    {
      "name": "BookshopViewers",
      "description": "Bookshop read-only users",
      "role-template-references": [
        { "role-template-name": "Viewer", "service-instance-name": "my-bookshop-xsuaa" }
      ]
    },
    {
      "name": "BookshopManagers",
      "description": "Bookshop managers",
      "role-template-references": [
        { "role-template-name": "Manager", "service-instance-name": "my-bookshop-xsuaa" }
      ]
    }
  ]
}

실행: cf create-service xsuaa application my-bookshop-xsuaa -c xs-security.json

결과: BTP Cockpit → Security → Role Collections에서 "BookshopViewers"와 "BookshopManagers"가 생성되었는지 확인합니다.

2단계: CAP 프로젝트에서 역할 기반 접근 제어

// srv/cat-service.cds — @requires로 역할 기반 접근 제어
service CatalogService {
  @requires: 'authenticated-user'
  entity Books as projection on bookshop.Books;

  @requires: 'Manager'
  action submitOrder(book: Books:ID, quantity: Integer) returns { stock: Integer };

  @requires: 'Administrator'
  action deleteAllBooks();
}
// srv/cat-service.js — 핸들러에서 사용자 권한 확인
module.exports = class CatalogService extends cds.ApplicationService {
  async init() {
    this.before('submitOrder', (req) => {
      // req.user.is('Manager')로 역할 확인 가능
      if (!req.user.is('Manager')) {
        req.reject(403, 'Manager 역할이 필요합니다');
      }
      console.log(`주문 요청: user=${req.user.id}, roles=${JSON.stringify(req.user.roles)}`);
    });

    this.on('submitOrder', async (req) => {
      // 비즈니스 로직...
      const { book, quantity } = req.data;
      const db = await cds.connect.to('db');
      const { Books } = db.entities;
      const result = await db.run(
        UPDATE(Books).set({ stock: { '-=': quantity } }).where({ ID: book })
      );
      return { stock: result };
    });

    await super.init();
  }
};

3단계: CLI로 Role Collection 검증 및 사용자 할당

-- CF CLI로 XSUAA 인스턴스 확인
$ cf services | grep xsuaa
my-bookshop-xsuaa   xsuaa   application   create succeeded

-- Service Key 생성하여 XSUAA 설정 확인
$ cf create-service-key my-bookshop-xsuaa my-key
$ cf service-key my-bookshop-xsuaa my-key
-- 출력에서 clientid, clientsecret, url 확인

-- 토큰 발급 테스트 (Client Credentials)
$ curl -X POST "{xsuaa-url}/oauth/token"   -H "Content-Type: application/x-www-form-urlencoded"   -d "grant_type=client_credentials&client_id={clientid}&client_secret={clientsecret}"
-- 응답의 scope 필드에서 할당된 scope 목록 확인

-- Role Collection에 사용자 할당 (BTP Cockpit 또는 CLI)
$ cf curl "/sap/rest/authorization/v2/rolecollections/BookshopManagers/users"   -X PUT -d '{"username":"user@company.com","origin":"sap.default"}'

⚠️ 흔한 실수 / 트러블슈팅

Q1: xs-security.json을 수정했는데 변경사항이 반영 안 돼요

  • 증상: 새 scope를 추가했는데 Role Template에 나타나지 않음
  • 원인: XSUAA 서비스 인스턴스를 업데이트하지 않음
  • 해결: cf update-service my-bookshop-xsuaa -c xs-security.json 실행. 단순히 파일만 수정하면 반영되지 않으며, 반드시 cf update-service 명령으로 인스턴스를 갱신해야 합니다.

Q2: 403 Forbidden — "Insufficient scope"

  • 증상: 로그인은 되지만 API 호출 시 403 반환
  • 원인 체크리스트: 1) Role Collection에 Role Template이 추가되었는지 확인 2) Role Collection에 사용자가 할당되었는지 확인 3) xs-security.json의 xsappname과 실제 서비스 인스턴스 이름이 일치하는지 확인 4) $XSAPPNAME 접두사가 scope-references에 올바르게 사용되었는지 확인 5) 토큰을 재발급 받았는지 확인 (캐시된 토큰에는 새 scope가 없음)
  • 해결: 위 5가지를 순서대로 점검하세요. 대부분 2번(사용자 미할당) 또는 5번(캐시 토큰) 문제입니다.

Q3: 멀티테넌트 환경에서 "token audience invalid"

  • 증상: subscriber 테넌트에서 토큰 검증 실패
  • 원인: xs-security.json에서 tenant-mode가 "shared"로 설정되어야 하는데 "dedicated"로 되어있거나, allowedproviders가 누락됨
  • 해결: "tenant-mode": "shared"로 변경하고, subscriber 서브어카운트가 provider의 XSUAA를 신뢰하도록 Trust Configuration을 설정하세요.

Q4: Role Collection이 BTP Cockpit에 안 보여요

  • 증상: xs-security.json에 role-collections를 정의했는데 Cockpit에 없음
  • 원인: role-collections 섹션은 서비스 인스턴스 생성 시에만 적용됩니다. 이미 존재하는 인스턴스에 cf update-service하면 role-collections는 무시될 수 있습니다.
  • 해결: Cockpit에서 수동으로 Role Collection을 생성하고 Role Template을 추가하세요. 또는 인스턴스를 삭제 후 재생성합니다 (주의: 기존 바인딩이 끊어짐).

🚀 다음 단계 / 관련 주제

  • IAS(Identity Authentication Service) 연동 — XSUAA 대신 또는 함께 IAS를 사용하는 하이브리드 인증 설정
  • Attribute-Based Access Control — Scope 외에 사용자 속성(조직, 지역 등)으로 세밀한 권한 제어
  • Principal Propagation — On-Premise 시스템으로 사용자 토큰을 전달하는 SSO 구성
  • CAP @restrict 심화 — CDS 레벨에서 행 단위 권한 제어 (where 절 기반)
  • App Router 설정 — 프론트엔드 라우팅 + XSUAA 토큰 관리 패턴

자세한 내용은 본문에서

📚 참고 자료


⚠️ 비공식 콘텐츠 안내

본 게시글은 btpstacks.com의 독립 학습 콘텐츠이며 SAP SE와 무관합니다. 공식 문서는 help.sap.com을 참고하세요.

SAP, ABAP, SAP BTP, SAPUI5, SAP Fiori는 독일 및 기타 국가에서 SAP SE의 상표 또는 등록상표입니다.

댓글 0

아직 댓글이 없습니다.