ABAP

Authority-Check 그만 — CDS는 DCL로 접근제어 #shorts #SAP #ABAP

▶ YouTube에서 보기

개요와 이 글에서 다룰 범위

CDS(Core Data Services) 기반 애플리케이션에서 데이터 노출은 뷰 정의만으로 끝나지 않습니다. 어떤 사용자가 어떤 로우(row)를 조회할 수 있는지, 어떤 조직·회사코드·판매조직에 속한 데이터만 볼 수 있는지 결정하는 계층이 필요합니다. 이 계층이 바로 DCL(Data Control Language)입니다. 이 글에서는 SAP S/4HANA 및 ABAP Platform 상에서 CDS View Entity에 접근 제어를 선언형으로 부여하는 방법을 처음부터 프로덕션 수준까지 다룹니다.

  • DCL(Data Control Language)의 목적과 CDS 계층 구조 이해
  • Authorization Object와 PFCG Role 매핑 원리 파악
  • 기본 @AccessControl.authorizationCheck 선언부터 상속(inherit), Full Access 케이스까지 실전 적용
  • DCL 성능 이슈, 테스트 시나리오, 디버깅 방법 익히기

사전에 알아두면 좋은 것

이 글은 CDS View Entity의 기본 문법(define view entity, association, annotation)을 이미 사용해본 개발자를 대상으로 합니다. ABAP Authorization Object의 기본 개념(SU21, PFCG), 그리고 트랜잭션 SU53로 권한 오류를 확인해본 경험이 있으면 이해가 훨씬 빠릅니다. 추가로 ADT(ABAP Development Tools) 환경에서 CDS 오브젝트를 편집할 수 있어야 합니다.

환경과 버전 정보

DCL은 ABAP 릴리스 및 CDS 문법에 따라 지원 범위가 다릅니다. 아래 조합을 권장합니다.

  • 플랫폼: SAP S/4HANA 2022 이상 또는 ABAP Platform 2023 이상 (온프레미스), SAP BTP ABAP Environment(Steampunk) 최신 릴리스
  • CDS 문법: View Entity(define view entity) 기반 — 기존 define view도 DCL 지원되지만 View Entity가 권장 형태
  • 개발 도구: Eclipse + ADT 3.30 이상, ABAP 프로젝트 연결
  • 권한 오브젝트: SU21에서 사전 생성된 Authorization Object (예: Z_SORG, V_VBAK_VKO 등)
  • 테스트 계정: PFCG로 서로 다른 권한값이 부여된 최소 2개 이상의 테스트 사용자

DCL 소스는 CDS Data Definition과 별도의 오브젝트로 존재하며, 트랜스포트 시 함께 이동해야 합니다. 트랜스포트 요청에는 DDLS(Data Definition), DCLS(Data Control) 두 오브젝트 타입이 같이 포함되어야 런타임에서 정상 동작합니다.

DCL의 동작 원리와 핵심 개념

DCL을 이해하는 가장 쉬운 비유는 "출입증 검사대"입니다. CDS View Entity는 회사의 사무 공간(데이터 집합)이고, 사용자는 방문객, PFCG Role의 권한값은 방문객이 들고 있는 출입증에 인쇄된 층/부서 번호에 해당합니다. DCL은 검사대에서 "이 방문객의 출입증에 적힌 층 정보와 지금 들어가려는 방의 층 정보가 일치하는가?"를 자동으로 검사하는 룰셋입니다.

기술적으로는 다음 흐름이 됩니다.

  1. CDS View Entity에 @AccessControl.authorizationCheck: #CHECK 어노테이션을 부여
  2. 동일 이름의 DCL 소스(확장자 .asaccess)를 작성해 define role 블록으로 필터 조건을 선언
  3. 런타임에 CDS를 SELECT하면 ABAP 커널이 사용자 세션의 권한값을 조회해 WHERE 조건을 자동으로 주입
  4. 사용자는 자신이 접근 가능한 로우만 반환받음 (권한 없는 로우는 존재하지 않는 것처럼 필터링됨)

DCL의 대표적인 룰 유형은 세 가지입니다.

  • aspect pfcg_auth: PFCG Role에 부여된 Authorization Object 값과 CDS 컬럼을 매핑
  • inherit: 상위 CDS View에 정의된 DCL 규칙을 재사용 (association 경유 필터 상속)
  • Full Access / Bypass: 특정 조건 하에서 검사 없이 전체 접근 허용 (예: 배치 사용자)

주의할 점은 DCL이 선언형(declarative)이라는 사실입니다. ABAP 코드에서 AUTHORITY-CHECK를 명령형으로 부르지 않아도 SQL 레벨에서 필터가 걸립니다. 이는 성능/보안 측면에서 큰 장점이지만, "왜 조회 결과가 비어 있지?"라는 디버깅 상황에서 개발자가 DCL의 존재를 잊고 헤매는 원인이 되기도 합니다.

DCL은 명령형 AUTHORITY-CHECK를 완전히 대체하지는 않습니다. RAP 액션·함수 실행 권한처럼 로우 필터가 아닌 "동작 실행 권한"은 여전히 명령형 체크 또는 Behavior Definition의 authorization 파트에서 처리해야 합니다.

실전 예제 1단계: 판매조직 기준 기본 필터

영업 문서 헤더를 조회하는 CDS View Entity가 있다고 가정합시다. 판매조직(VKORG) 값에 따라 사용자가 조회 가능한 로우가 달라져야 합니다. 먼저 Data Definition을 정의합니다.

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Header - DCL Enabled'
define view entity ZC_SalesOrderHeader
  as select from vbak
{
  key vbeln          as SalesOrderId,
      vkorg          as SalesOrganization,
      vtweg          as DistributionChannel,
      spart          as Division,
      auart          as OrderType,
      kunnr          as SoldToParty,
      erdat          as CreatedOn,
      netwr          as NetAmount,
      waerk          as Currency
}

그리고 같은 이름의 DCL 소스를 생성합니다. ADT에서 New > Other ABAP Repository Object > Access Control으로 만들 수 있습니다.

@EndUserText.label: 'DCL for Sales Order Header'
@MappingRole: true
define role ZC_SalesOrderHeader {
  grant select on ZC_SalesOrderHeader
    where (SalesOrganization) =
          aspect pfcg_auth ( V_VBAK_VKO,
                             VKORG,
                             ACTVT = '03' );
}

이 룰은 다음을 의미합니다. "사용자 세션에 부여된 V_VBAK_VKO 권한 오브젝트의 VKORG 값과 CDS의 SalesOrganization 컬럼 값이 일치하고, 활동(ACTVT)이 03(조회)일 때만 SELECT를 허용한다." PFCG Role에서 사용자 A에게 VKORG=1000만 허용했다면, ZC_SalesOrderHeader에서 SELECT할 때 자동으로 WHERE VKORG = '1000'이 SQL에 추가됩니다.

실전 예제 2단계: 상속과 다중 조건 결합

실무에서는 단일 조건으로 끝나는 경우가 드뭅니다. 예컨대 영업 문서 항목(Item)을 조회하는 뷰가 있고, 이 뷰는 헤더 뷰와 association으로 연결되어 있다면 항목 뷰에서 다시 DCL을 처음부터 쓸 필요가 없습니다. inherit로 상속받는 편이 훨씬 안전하고 유지보수가 쉽습니다.

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Item - Composite View'
define view entity ZC_SalesOrderItem
  as select from vbap
  association [1..1] to ZC_SalesOrderHeader as _Header
    on $projection.SalesOrderId = _Header.SalesOrderId
{
  key vbeln     as SalesOrderId,
  key posnr     as ItemNumber,
      matnr     as MaterialId,
      werks     as Plant,
      kwmeng    as OrderQuantity,
      netwr     as ItemNetAmount,
      _Header
}

이제 항목 뷰의 DCL을 상속 기반으로 작성합니다.

@EndUserText.label: 'DCL for Sales Order Item (inherited)'
@MappingRole: true
define role ZC_SalesOrderItem {
  grant select on ZC_SalesOrderItem
    where inheriting conditions from entity _Header;
}

이 방식은 헤더 뷰에서 이미 정의한 판매조직 필터가 항목 뷰에도 자동으로 적용되므로, 헤더 룰이 변경되면 항목 뷰가 별도 수정 없이 따라 변경됩니다. 규모가 큰 프로젝트에서 DCL 룰 중복을 없애는 핵심 패턴입니다.

추가 조건이 필요할 땐 and로 조합할 수 있습니다. 예를 들어 공장(Plant) 별 추가 제한이 필요한 경우입니다.

@EndUserText.label: 'DCL with combined filter'
@MappingRole: true
define role ZC_SalesOrderItem {
  grant select on ZC_SalesOrderItem
    where inheriting conditions from entity _Header
      and (Plant) = aspect pfcg_auth ( M_MATE_WRK,
                                       WERKS,
                                       ACTVT = '03' );
}

운영 중에는 어떤 사용자가 어떤 룰로 필터링되고 있는지 감사(audit) 요구가 자주 발생합니다. 이때는 애플리케이션 로그(SLG1)에 별도로 접근 이력을 기록하도록 RAP Behavior Implementation에 훅을 추가하는 편이 좋습니다. DCL 자체가 로그를 남기지는 않기 때문입니다.

실전 예제 3단계: 프로덕션 고려사항과 예외 처리

실서비스에 배포하려면 세 가지를 반드시 챙겨야 합니다.

첫째, Full Access가 필요한 배치/서비스 사용자 처리. 야간 배치 잡이나 인터페이스 계정은 특정 조직에 묶이지 않고 전체 데이터를 처리해야 하는 경우가 많습니다. 이때는 별도의 권한값(예: VKORG = '*')을 PFCG에서 부여하고, DCL에서는 그대로 aspect pfcg_auth가 처리하도록 두면 됩니다. 매핑 어스펙트는 별표(*) 마스터 값에 대해 조건을 생성하지 않으므로 자동으로 Full Access가 됩니다.

둘째, DCL을 완전히 우회해야 하는 특수 케이스. 예를 들어 통계 집계용 CDS View에서 라인 단위 필터를 걸면 합계가 왜곡되는 경우가 있습니다. 이때는 View 자체에 @AccessControl.authorizationCheck: #NOT_REQUIRED를 부여하되, 상위 소비 서비스에서 별도 권한 체크를 걸어야 합니다. 이 선택은 반드시 보안 검토를 거쳐야 합니다.

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Aggregated KPI View - guarded at service level'
define view entity ZC_SalesKpiAggregate
  as select from ZC_SalesOrderItem
{
  key SalesOrganization,
      sum(ItemNetAmount) as TotalNetAmount
}
group by SalesOrganization

셋째, 성능 최적화. DCL은 SQL WHERE 절을 자동 주입하므로 그 자체로 인덱스 활용에 큰 영향을 줍니다. 다음 원칙을 지키는 편이 안전합니다.

  • 필터 컬럼(VKORG, WERKS 등)에 인덱스가 존재하는지 DB에서 확인
  • 깊은 association을 통해 여러 단계 inheriting하지 않기 — 조인 폭발 위험
  • 대량 조회 API의 경우 DCL 적용 여부에 따른 쿼리 플랜을 ST05로 측정
  • 가능하면 CDS 뷰 계층을 얕게 유지하고, 최상위 소비 뷰에만 DCL 부여

테스트는 다음 시나리오를 최소 커버해야 합니다.

  1. 권한이 하나의 조직값(VKORG=1000)만 부여된 사용자 — 해당 조직 로우만 반환되는지
  2. 다중 값(VKORG=1000, 2000)이 부여된 사용자 — OR 조건으로 합쳐지는지
  3. 권한 오브젝트가 아예 없는 사용자 — 빈 결과 반환되는지
  4. 별표(*) 권한이 부여된 어드민 — 전체 조회 가능한지

자주 만나는 문제와 해결

Q1. DCL을 적용했는데 결과가 계속 비어 있습니다. 가장 흔한 원인은 PFCG Role에 해당 Authorization Object 값이 부여되지 않았거나, 사용자 마스터에 Role이 할당됐지만 User Comparison(사용자 비교)이 실행되지 않아 권한 프로파일이 세션에 반영되지 않은 경우입니다. SU53으로 마지막 실패한 체크를 확인하고, PFCG의 User 탭에서 사용자 비교 상태를 확인하세요.

Q2. 개발 시스템에서는 잘 되는데 QA에서 필터가 안 걸립니다. DCLS 오브젝트가 트랜스포트에 포함되지 않았거나, 대상 시스템에서 DCL 소스가 Inactive 상태로 임포트된 경우입니다. SE80 또는 ADT에서 오브젝트 활성 상태를 확인하고, @AccessControl.authorizationCheck 어노테이션이 실제로 #CHECK로 활성화됐는지 재확인합니다.

Q3. CDS View 두 개를 UNION으로 합쳤더니 DCL이 이상하게 동작합니다. UNION 브랜치별로 DCL이 각각 적용되며, 각 브랜치에 대해 grant select를 명시적으로 작성해야 합니다. 하나만 정의하고 나머지를 잊는 실수가 잦으므로 UNION 뷰의 DCL은 브랜치 수만큼 룰 블록이 있는지 리뷰 시 반드시 체크리스트에 넣습니다.

디버깅 팁 하나 더 — ADT에서 CDS View를 열고 Data Preview 상단의 "Access Control" 토글을 끄고 켜서 필터 유무별 결과를 비교하면 어떤 로우가 DCL에 의해 걸러졌는지 즉시 확인할 수 있습니다. 개발 계정에는 해당 토글 권한이 일반적으로 부여됩니다.

확장해서 살펴볼 만한 주제

DCL을 기본기로 익혔다면 다음 주제로 넘어가는 것을 권장합니다. RAP(RESTful ABAP Programming) Behavior Definition의 authorization master/authorization instance 문법은 Create/Update/Delete 액션 단위 권한 제어에 필요합니다. 또한 SAP Gateway와 OData 노출 시 DCL이 서비스 계층까지 자동 전파되는 방식, 그리고 계산 뷰(Calculation View)와 DCL의 상호작용도 흥미로운 주제입니다. BTP ABAP Environment에서는 IAM(Identity Access Management) 앱을 통해 PFCG 대신 Business Catalog/Role 개념이 사용되므로 대응 문법도 함께 학습해두면 좋습니다.

더 읽어볼 자료

댓글 0

아직 댓글이 없습니다.