LabHub

블로그

은행에서 플랫폼 엔지니어링 하기 — Backstage와 거버넌스의 결혼

한국어English日本語

들어가며

금융사에서 마이크로서비스 하나를 새로 만들려면 무엇이 필요할까요? 코드를 작성하는 시간은 하루면 충분할지 모릅니다. 그러나 현실은 이렇습니다. Git 저장소 생성 신청서 결재, 빌드 파이프라인 등록 요청, 방화벽 오픈 신청(왕복 며칠), DB 계정 발급 신청, 보안성 검토 접수, 자산 목록 등재, 모니터링 등록 요청. 각 단계마다 담당 부서가 다르고, 결재선이 다르고, 처리 기한이 다릅니다. 합치면 3주에서 한 달. 개발자는 그동안 코드를 짜는 대신 신청서를 씁니다.

흥미로운 점은, 이 절차들 하나하나는 모두 합리적 이유가 있다는 것입니다. 전자금융감독규정의 접근 통제, 정보보호 정책의 보안성 검토, 자산 관리 의무, 변경 통제. 문제는 절차의 존재가 아니라 절차가 사람의 손으로, 직렬로, 문서로 수행된다는 데 있습니다.

플랫폼 엔지니어링은 이 지점을 공략합니다. 절차를 없애는 것이 아니라, 절차를 코드에 내장해서 자동으로 수행되고 자동으로 증적이 남게 만드는 것. 이 글은 Backstage를 중심으로 금융사 내부 개발자 플랫폼(IDP)을 설계·운영하는 방법을 다룹니다. 이 글은 기술 관점의 정리이며, 개별 기관의 규제 적용은 준법감시 조직의 판단을 따라야 합니다.

금융권에서 플랫폼 엔지니어링의 가치 — 표준화는 곧 컴플라이언스 자동화

일반 기업에서 플랫폼 엔지니어링의 가치는 주로 "개발자 경험 개선"과 "인지 부하 감소"로 설명됩니다. 금융권에서는 여기에 결정적인 세 번째 가치가 추가됩니다.

표준화된 골든 패스는 그 자체로 컴플라이언스 자동화 장치입니다.

보안팀·감사팀 관점에서 보면, 점검 대상이 "서비스 300개의 제각각인 구성"에서 "템플릿 5개와 파이프라인 1개"로 줄어드는 것입니다. 점검 비용이 한 자릿수로 줄고, 점검의 신뢰도는 올라갑니다. 이것이 금융권 플랫폼 엔지니어링의 영업 논리이고, 경영진과 보안 조직을 설득하는 언어입니다.

[기존]  서비스마다 다른 구성
  점검 = 서비스 수 x 점검 항목 수  (수작업, 누락 가능)

[IDP]   골든 패스로 수렴
  점검 = 템플릿 수 x 점검 항목 수  (코드 리뷰로 대체 가능)
  + 템플릿 위반 탐지 자동화 (정책 엔진)

골든 패스에 규제 요건 내장하기 — Backstage 템플릿

Backstage Scaffolder 템플릿은 골든 패스의 입구입니다. 핵심은 보안·감사 요건을 선택지가 아니라 기본값으로 넣는 것입니다. 개발자가 의식하지 않아도 보안 스캔, 감사 로깅, 암호화 설정이 켜진 상태로 서비스가 태어나게 합니다.

# template.yaml — 금융 규제 요건이 내장된 신규 서비스 템플릿
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: secure-spring-service
  title: Spring Boot 서비스 (보안 기본값 내장)
  description: 보안 스캔, 감사 로깅, 암호화가 기본 활성화된 표준 서비스
  tags:
    - recommended
    - java
    - compliance-ready
spec:
  owner: platform-team
  type: service

  parameters:
    - title: 서비스 기본 정보
      required:
        - serviceName
        - ownerGroup
        - dataClassification
      properties:
        serviceName:
          title: 서비스 이름
          type: string
          pattern: '^[a-z0-9-]+$'
        ownerGroup:
          title: 소유 조직 (인사 시스템 부서 코드와 연동)
          type: string
          ui:field: OwnerPicker
        dataClassification:
          title: 데이터 등급 (자산 관리 보고에 사용)
          type: string
          enum:
            - public
            - internal
            - personal-credit    # 개인신용정보 — 추가 통제 자동 적용
          default: internal

  steps:
    # 1) 스켈레톤 생성 — 보안 설정이 이미 포함된 코드베이스
    - id: fetch
      name: 표준 스켈레톤 생성
      action: fetch:template
      input:
        url: ./skeleton
        values:
          serviceName: ${{ parameters.serviceName }}
          owner: ${{ parameters.ownerGroup }}
          dataClass: ${{ parameters.dataClassification }}

    # 2) 데이터 등급이 personal-credit이면 암호화 모듈 강제 주입
    - id: inject-crypto
      name: 필드 암호화 모듈 주입
      if: ${{ parameters.dataClassification === 'personal-credit' }}
      action: fetch:template
      input:
        url: ./addons/field-encryption
        targetPath: ./src

    # 3) 사내 Git 생성 + 브랜치 보호 + CODEOWNERS 자동 설정
    - id: publish
      name: 저장소 생성
      action: publish:gitlab
      input:
        repoUrl: gitlab.bank.internal?owner=${{ parameters.ownerGroup }}&repo=${{ parameters.serviceName }}
        defaultBranch: main
        protectDefaultBranch: true

    # 4) 보안 파이프라인 등록 (SAST + SCA + 이미지 스캔 + 서명)
    - id: pipeline
      name: 표준 파이프라인 연결
      action: bank:pipeline:register
      input:
        repo: ${{ steps.publish.output.repoContentsUrl }}
        stages: ['sast', 'sca', 'image-scan', 'cosign-sign']

    # 5) 전자결재 기안 — 신규 자산 등재 승인 (커스텀 액션, 아래 절 참고)
    - id: approval
      name: 자산 등재 결재 상신
      action: bank:approval:submit
      input:
        docType: NEW_SERVICE_REGISTRATION
        serviceName: ${{ parameters.serviceName }}
        dataClass: ${{ parameters.dataClassification }}
        requester: ${{ user.entity.metadata.name }}

    # 6) 카탈로그 등록 — 자산 목록 의무의 자동 충족
    - id: register
      name: 카탈로그 등록
      action: catalog:register
      input:
        repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
        catalogInfoPath: '/catalog-info.yaml'

스켈레톤 쪽에도 규제 요건이 코드로 들어갑니다. 감사 로깅(누가·언제·무엇을)이 켜진 로백 설정, TLS 강제, 시크릿은 외부 볼트 참조만 허용하는 설정, 표준 헬스체크와 메트릭 엔드포인트가 기본 포함됩니다. 개발자가 "보안 요건을 공부해서 적용"하는 것이 아니라, "기본값을 굳이 끄지 않는 한 준수 상태"가 되는 구조입니다.

승인 워크플로 통합 — 전자결재와 Scaffolder의 연결

금융사의 모든 행위에는 결재가 따라옵니다. IDP가 결재를 우회하면 도입이 거부되고, 결재를 수동으로 남겨 두면 자동화의 의미가 없습니다. 답은 Scaffolder 커스텀 액션으로 결재 시스템을 호출하고, 승인 완료를 기다렸다가 다음 단계를 진행하는 것입니다.

// plugins/scaffolder-backend-module-bank/src/actions/submitApproval.ts
// 개념 코드: 전자결재 시스템 연동 커스텀 액션
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';

export const submitApprovalAction = () => {
  return createTemplateAction<{
    docType: string;
    serviceName: string;
    dataClass: string;
    requester: string;
  }>({
    id: 'bank:approval:submit',
    description: '전자결재 시스템에 기안을 상신하고 승인을 대기한다',
    schema: {
      input: {
        required: ['docType', 'serviceName', 'dataClass', 'requester'],
        type: 'object',
        properties: {
          docType: { type: 'string' },
          serviceName: { type: 'string' },
          dataClass: { type: 'string' },
          requester: { type: 'string' },
        },
      },
    },
    async handler(ctx) {
      const { docType, serviceName, dataClass, requester } = ctx.input;

      // 1) 결재 문서 생성 — 데이터 등급에 따라 결재선이 달라진다
      //    internal: 팀장 전결 / personal-credit: 팀장 + 정보보호 + CISO
      const approvalLine = dataClass === 'personal-credit'
        ? ['TEAM_LEAD', 'INFOSEC_REVIEW', 'CISO']
        : ['TEAM_LEAD'];

      const doc = await approvalClient.createDocument({
        type: docType,
        title: `신규 서비스 등재: ${serviceName}`,
        body: renderTemplate(docType, ctx.input),
        approvers: approvalLine,
        drafter: requester,
      });
      ctx.logger.info(`결재 상신 완료: ${doc.id}`);

      // 2) 승인 대기 — 폴링 (웹훅 수신이 가능하면 이벤트 기반으로)
      const result = await approvalClient.waitForCompletion(doc.id, {
        timeoutHours: 72,
        pollIntervalSec: 60,
      });

      if (result.status !== 'APPROVED') {
        throw new Error(`결재 반려: ${result.comment ?? '사유 미기재'}`);
      }

      // 3) 승인 증적을 출력으로 — 이후 단계와 카탈로그 주석에 기록
      ctx.output('approvalDocId', doc.id);
      ctx.output('approvedAt', result.completedAt);
      ctx.output('approvers', result.approverHistory);
    },
  });
};

설계 포인트는 다음과 같습니다.

카탈로그로 자산 관리 대응 — 시스템 목록, 소유자, 등급

전자금융기반시설 취약점 분석평가, 자산 실사, 감독 보고 — 모두 "시스템 목록과 소유자, 중요도"를 요구합니다. 엑셀로 관리되던 이 목록을 Backstage 카탈로그가 대체하면, 목록은 항상 최신이고(서비스 생성 시 자동 등재), 소유자는 항상 유효하며(인사연동 그룹), 등급은 정책 엔진이 참조하는 살아있는 데이터가 됩니다.

# catalog-info.yaml — 감독 보고 항목과 매핑되는 메타데이터
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: loan-application-api
  description: 대출 신청 접수 API
  annotations:
    bank.example.com/asset-id: "AST-2026-0142"        # 자산 관리 번호
    bank.example.com/approval-doc: "APR-2026-08731"   # 생성 승인 결재 문서
    bank.example.com/last-vuln-assessment: "2026-03"  # 최근 취약점 평가
  labels:
    bank.example.com/data-class: personal-credit
    bank.example.com/criticality: critical
    bank.example.com/dr-tier: tier-2
spec:
  type: service
  lifecycle: production
  owner: group:retail-lending-dev        # 인사 시스템 부서 코드와 동기화
  system: loan-origination
  dependsOn:
    - resource:loan-db
    - component:customer-master-api
감독·감사 요구 항목카탈로그 매핑산출 방법
정보자산 목록Component/Resource 엔티티 전체카탈로그 API로 일 단위 추출
자산별 책임자spec.owner (인사연동 그룹)그룹의 장을 책임자로 해석
시스템 중요도criticality 라벨중요도 평가 결과를 라벨로 기록
개인신용정보 처리 시스템data-class 라벨 필터라벨 쿼리 한 줄
시스템 간 연계 현황dependsOn 그래프의존성 그래프 내보내기
변경 승인 증적approval-doc 주석 + Git 이력결재 ID 역추적

분기마다 자산 실사 엑셀을 만들던 작업이 "카탈로그 API 호출 + 서식 변환" 배치 잡으로 바뀝니다. 더 중요한 것은 역방향 검증입니다. 클러스터에서 돌고 있는데 카탈로그에 없는 워크로드를 정책 엔진이 탐지하면, 그것이 곧 "미등재 자산 탐지" 통제가 됩니다.

폐쇄망에서의 IDP 운영 — 에어갭과 미러링

금융사 개발망은 인터넷이 막혀 있거나 프록시로 제한됩니다. Backstage와 그 생태계는 npm, 컨테이너 이미지, 플러그인 등 외부 의존성 덩어리이므로, 폐쇄망 운영을 위한 미러링 체계가 선행되어야 합니다.

[인터넷 구간 — 반입 전용]
  registry.npmjs.org      ghcr.io / docker.io     plugin 저장소
        |                       |                       |
        v                       v                       v
  +---------------------------------------------------------+
  |  반입 게이트웨이 (주기 동기화 + 취약점 스캔 + 승인)          |
  +---------------------------------------------------------+
        |                       |
        v                       v
[내부망]
  Nexus/Verdaccio          Harbor
  (사내 npm 미러)           (사내 이미지 레지스트리)
        |                       |
        +----------+------------+
                   v
            Backstage 빌드/배포
            (yarn.lock의 resolved를 사내 미러 URL로 고정)

운영 노하우 몇 가지를 적어 둡니다.

셀프서비스의 경계 — 무엇은 자동, 무엇은 검토

"전부 셀프서비스"는 금융권에서 통하지 않고, "전부 결재"는 플랫폼의 존재 이유를 없앱니다. 경계는 위험 등급 매트릭스로 긋습니다.

작업위험 낮음 (자동 승인)위험 중간 (팀장 전결)위험 높음 (보안 검토 필수)
개발 환경 네임스페이스 생성O------
표준 템플릿 기반 신규 서비스O (internal 등급)O (대외 노출)O (개인신용정보 처리)
운영 배포 (표준 파이프라인)O (사전 승인된 변경 창구 내)O (창구 외 시간)---
방화벽 정책 추가---O (사내 구간, 표준 포트)O (대외 구간, 비표준)
DB 스키마 변경O (개발)O (운영, 비파괴)O (운영, 파괴적 변경)
시크릿 발급/회전O (자동 회전)---O (수동 예외 발급)
운영 데이터 조회 권한------O (시간 제한 + 사유 필수)

원칙은 세 가지입니다.

  1. 위험이 낮은 작업의 승인을 없애는 것이 아니라, 승인을 정책 통과로 대체합니다. "자동 승인"의 실체는 정책 엔진(쿼터, 등급, 템플릿 준수)의 기계 심사이며, 심사 결과가 증적으로 남습니다.
  2. 위험이 높은 작업은 사람의 검토를 유지하되, 검토에 필요한 정보를 플랫폼이 자동으로 첨부합니다. 보안팀이 받는 검토 요청에 데이터 등급, 의존성 그래프, 스캔 결과가 미리 붙어 있으면 검토 시간이 절반 이하로 줄어듭니다.
  3. 경계 자체를 코드로 관리합니다. 위 매트릭스를 YAML로 선언하고 결재선 라우팅이 이를 읽게 하면, 경계 조정도 PR과 결재로 추적됩니다.

성숙도 측정 — DORA에 규제 지표를 더한다

플랫폼의 성과는 측정해야 예산이 나옵니다. 금융권에서는 DORA 4지표에 규제 대응 지표를 더한 스코어카드를 권합니다.

분류지표도입 전 (예시)1년 후 목표
DORA배포 빈도월 1회주 2회 이상
DORA변경 리드타임3주2일
DORA변경 실패율18%8% 이하
DORA복구 시간 (MTTR)4시간30분
규제신규 서비스 보안 기본값 적용률측정 불가100% (템플릿 강제)
규제자산 목록 정합성 (실사 대비)약 70%99% 이상
규제취약점 조치 리드타임 (Critical)30일7일
규제미등재 자산 탐지 건수미탐지월간 0건 수렴
경험신규 서비스 셋업 소요15~20영업일1영업일
경험개발자 만족도 (분기 설문)---추세 상승

주의할 점은 지표를 평가 무기로 쓰지 않는 것입니다. 팀 간 순위표를 만드는 순간 지표는 조작되고, 플랫폼은 감시 도구로 인식되어 채택이 무너집니다. 지표는 플랫폼 자체의 개선과 경영 보고에만 사용한다는 원칙을 공개적으로 못 박아야 합니다.

문화 전환 — 보안팀을 플랫폼의 고객으로

금융사 플랫폼 엔지니어링의 성패는 기술보다 보안·감사 조직과의 관계에서 갈립니다. 흔한 실패는 플랫폼팀이 개발자만 고객으로 보고 보안팀을 "통과해야 할 관문"으로 취급하는 것입니다. 관문은 반드시 복수합니다.

발상을 바꿔 보안팀을 두 번째 고객으로 정의합니다.

사례 시나리오 — 3주가 1일이 되는 경로

가상의 시나리오로 전후를 비교합니다. 리테일 여신 팀이 대출 한도 조회 API를 신설하는 경우입니다.

[도입 전 — 21영업일]
D1~D3   : Git 저장소 신청서 작성, 결재 대기, 인프라팀 수동 생성
D4~D8   : 파이프라인 등록 요청, CI 담당자 큐 대기
D6~D10  : 방화벽 오픈 신청 (DB, 내부 API 2건) — 보안팀 검토 큐
D8~D12  : DB 계정 발급, 시크릿 수동 전달 (메신저로... 사고 위험)
D10~D15 : 보안성 검토 — 체크리스트 수작업 작성, 반려 1회
D15~D18 : 자산 목록 등재, 모니터링 등록 요청
D19~D21 : 운영 배포 결재, 첫 배포
개발자 체감: "코드보다 신청서를 더 많이 썼다"

[도입 후 — 1영업일]
09:00  Backstage 포털에서 secure-spring-service 템플릿 실행
       (서비스명, 소유 조직, 데이터 등급 = personal-credit 입력)
09:01  저장소·파이프라인·모니터링·카탈로그 자동 생성
       방화벽 표준 정책 자동 신청 (DB 1건은 표준 포트라 자동 승인)
09:02  데이터 등급이 personal-credit이므로 결재 자동 상신
       (팀장 + 정보보호 검토 — 스캔 결과와 의존성 그래프 자동 첨부)
14:30  정보보호팀 승인 (검토에 필요한 정보가 모두 첨부되어 있어 신속)
14:31  운영 네임스페이스 프로비저닝, 시크릿은 볼트 참조로 자동 주입
16:00  첫 운영 배포 완료 — 생성부터 배포까지 모든 증적이 자동 보존
개발자 체감: "오전에 만들고 오후에 배포했다"

핵심은 "결재가 사라진 것"이 아니라는 점입니다. 결재는 여전히 있습니다(정보보호팀 승인 14:30). 사라진 것은 신청서 작성, 큐 대기, 정보 재취합, 수동 등재 — 즉 결재 사이사이의 마찰입니다.

실패 패턴

흔한 실패를 미리 알아 두면 절반은 피할 수 있습니다.

도입 로드맵

단계기간(예시)핵심 산출물
0. 정렬1~2개월보안·준법 조직과 위험 등급 매트릭스 합의, 파일럿 팀 선정, 현행 리드타임 측정
1. 수직 슬라이스2~3개월템플릿 1개로 저장소~운영 배포까지 완전 자동화 (결재 연동 포함)
2. 카탈로그2개월기존 서비스 일괄 등재, 인사연동 소유자, 자산 보고 배치
3. 확산3~6개월템플릿 3~5종으로 확대, 파일럿 외 본부 온보딩, 폐쇄망 미러 안정화
4. 거버넌스 심화지속미등재 자산 탐지, 증적 자동 산출, 스코어카드 정례 보고

체크리스트

거버넌스

골든 패스

카탈로그

폐쇄망 운영

측정

마치며

은행에서 플랫폼 엔지니어링을 한다는 것은 결국 두 세계의 번역가가 되는 일입니다. 개발자에게는 "3주짜리 절차가 하루로 줄어드는 경험"으로, 보안팀에게는 "점검 대상이 300개에서 5개로 줄어드는 구조"로, 경영진에게는 "컴플라이언스 비용이 자동화로 전환되는 투자"로 — 같은 플랫폼이 세 가지 언어로 설명되어야 합니다.

Backstage와 거버넌스의 결혼은 비유가 아니라 구현 과제입니다. 템플릿에 규제 요건을 넣고, Scaffolder에 결재를 연결하고, 카탈로그를 자산 대장으로 만드는 일. 화려하지 않지만, 이 배관 작업이 끝난 조직에서는 규제 산업의 개발 속도에 대한 통념이 깨지는 것을 보게 됩니다.

참고 자료

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다