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

Backstage 위협 모델

원문 보기 위키 갱신

이 위협 모델은 운영자, 개발자, 보안 연구자를 위한 Backstage의 핵심 보안 고려 사항을 개괄적으로 설명해요. 이는 살아 있는 문서이며 Backstage 프로젝트와 함께 관련이 있는 내용으로 진화하고 확장될 거예요.

출처: 문서

본문

이 위협 모델은 운영자, 개발자, 보안 연구자를 위한 Backstage의 핵심 보안 고려 사항을 개괄적으로 설명해요. 이는 살아 있는 문서이며 Backstage 프로젝트와 함께 관련이 있는 내용으로 진화하고 확장될 거예요.

보안 취약점 신고와 수정된 보안 결함에 대한 권고(advisory)에 대한 자세한 내용은 Backstage GitHub 저장소의 Security Policy와 Advisories를 참고하세요.

신뢰 모델

Backstage 신뢰 모델은 신뢰 수준이 다른 세 그룹으로 나뉘어요.

내부 사용자(internal user)는 일반적으로 특정 Backstage 배포의 조직에 속하는 인증된 사용자예요. 이 사용자들은 Backstage의 가용성을 훼손하지 않을 것으로 기대되는 수준으로 신뢰되지만, 데이터 기밀성이나 무결성을 훼손하지 않을 것이라고는 신뢰되지 않아요.

운영자(operator)는 Backstage 인스턴스를 구성하고 유지 관리하는 책임을 가진 사용자예요. 운영자는 시스템과 데이터베이스를 운영하므로 호스트 시스템에 대한 루트 접근 권한을 가지기 때문에 완전히 신뢰돼요. Backstage 도입자는 이 그룹의 접근을 제한하거나 관찰하기 위한 추가 조치를 취할 수 있지만, 이는 현재 Backstage 범위 밖이에요.

빌더(builder)는 내부 또는 외부 코드 기여자이며 운영자와 비슷한 수준의 접근 권한을 갖게 돼요. Backstage 플러그인을 설치할 때는 외부 소스의 다른 패키지를 살피듯이 살펴야 해요. 공급망 공격의 영향을, 예를 들어 배포를 서로 다른 플러그인을 가진 별도의 서비스로 나눠 제한하는 것은 가능하지만, Backstage 프로젝트 자체는 이런 종류의 공격을 방지하거나 어떤 식으로든 플러그인의 접근을 샌드박스하거나 제한하는 것을 목표로 하지 않아요.

외부 사용자(external user)는 다른 세 그룹에 속하지 않는 사용자예요. 예를 들어 조직 밖의 악의적인 행위자예요. Backstage의 보안 모델은 현재 이 그룹이 Backstage에 직접 접근하지 않는다고 가정하며, 그렇게 되도록 보장하는 것은 각 Backstage 도입자의 책임이에요.

운영자 책임

정보

이 섹션은 backend system과 최소 Backstage 릴리스 버전 1.24를 사용한다고 가정해요. 그 이전에는 Backstage에 무단 접근에 대한 내장 보호 기능이 없었고, 보호된 환경에 배포해야 했어요.

Backstage는 주로 공개 인터넷에 노출되기보다는 보호된 환경에 배포되도록 설계돼요. 기밀성과 무결성 관점에서 Backstage는 데이터에 대한 무단 접근으로부터 보호하고 데이터가 변조되지 않도록 보장하도록 설계됐어요. 그러나 Backstage는 서비스 거부 공격에 대한 기본적인 보호 이상을 제공하지 않으며, Backstage 배포를 그러한 공격으로부터 보호하는 것은 운영자의 책임이에요. Backstage 배포를 무단 접근으로부터 보호하는 일반적이고 권장되는 방법은 AWS의 ALB, GCP의 IAP, Cloudflare Access 같은 인증 프록시 뒤에 배포하는 것이에요.

Backstage에 로그인한 사용자는 일반적으로 모든 정보와 액션에 대한 완전한 접근 권한을 가져요. 더 세밀한 제어가 필요하다면 권한 시스템을 활성화하고 필요에 따라 접근을 제한하도록 구성해야 해요.

운영자는 구성 파일의 무결성을 보호할 책임이 있어요. 그렇지 않으면 취약한 구성을 도입할 수 있고, Backstage와 관련된 구성된 시크릿의 기밀성도 보호해야 해요. 이 시크릿에는 보통 서드파티 시스템에 대한 인증 세부 정보가 포함되기 때문이에요.

운영자는 궁극적으로 내부·외부 플러그인의 사용을 감사할 책임이 있어요. 플러그인은 호스트 시스템에서 실행되며 구성과 시크릿에 접근할 수 있기 때문이에요. NPM 같은 소스에서 플러그인을 설치할 때는 그 소스에서 설치하는 다른 패키지를 살피듯이 살펴야 해요.

운영자는 또한 Backstage 프로젝트의 해석된(resolved) NPM 의존성을 유지 관리할 책임이 있어요. 이는 yarn.lock이 취약점이 있는 패키지의 수정된 버전을, 그 수정 버전이 Backstage 패키지가 각각의 package.json 파일에서 요청하는 범위 안에 있을 때 받도록 보장하는 것을 포함해요. 이는 보통 자체 저장소에서 Dependabot, Snyk, 그리고/또는 Renovate 같은 자동화 도구를 사용해 이루어져요. Backstage 패키지가 요청하는 범위 안에 있는 수정 버전이 없거나, 전체 의존성을 다른 것으로 교체하는 것 같은 더 큰 작업이 필요할 때는, 메인테이너가 기여자와 협력해 기본 프로젝트에서 그 의존성 선언을 가능한 빨리 해결하려고 해요.

무단 접근에 대한 내장 보호는 기본적으로 프론트엔드 번들의 보호를 포함하지 않아요. 프론트엔드 번들은 프론트엔드 플러그인의 모든 코드와 축소된 코드, 그리고 이미지, 폰트 같은 다른 프론트엔드 리소스를 포함해요. 이것이 우려된다면 실험적인 공개 진입점(public entry point)을 사용해 두 개의 분리된 프론트엔드 빌드를 만들 수 있으며, 인증된 사용자만 전체 빌드에 접근할 수 있어요.

공통 백엔드 구성

중앙에서 구성되어 모든 Backstage 백엔드 플러그인이 사용할 수 있는 많은 공통 설비가 있어요. 예를 들어 SQL 데이터베이스에 접근을 제공하는 DatabaseService, 장기 실행 작업을 스케줄링하는 SchedulerService, 일반 로깅 설비인 LoggerService, 외부 소스에서 콘텐츠를 읽는 UrlReaderService가 있어요. 이 모든 것은 코드에서 직접 구성되거나 정적 구성의 backend 블록 안에서 구성돼요. 어떤 시크릿이든 기밀로 유지되고 악의적인 구성이 주입되지 않도록 적절한 주의를 기울여야 해요.

일반적인 Backstage 설정에서는 같은 호스트에서 실행되는 플러그인 사이에 경계가 없어요. 마찬가지로 같은 데이터베이스 접근을 공유하는 플러그인 사이에도 경계가 없어요. 다른 플러그인의 논리적 데이터베이스에 접근할 수 있는 호스트에서 실행 중인 플러그인은 그 플러그인에 대한 완전한 접근 권한을 가진 것으로 간주되어야 해요. 예를 들어 auth와 catalog 플러그인을 별도의 호스트에 별도의 구성과 자격 증명으로 배포하더라도, catalog 플러그인이 auth 플러그인의 논리적 데이터베이스에 접근할 수 있는 한 auth 플러그인에 대한 완전한 접근 권한을 가진 것으로 간주돼요. 두 플러그인 사이에 경계를 만드는 유일한 방법은 서로의 데이터베이스에 접근할 수 없도록 배포하는 것이에요. 이는 데이터베이스 설비뿐 아니라 캐시 같은 다른 공유 리소스에도 적용돼요.

UrlReaderService 설비는 안전한 Backstage 구성에 특히 관심이 있어요. 특히 backend.reading.allow 구성은 백엔드가 사용자를 대신해 콘텐츠를 읽을 수 있다고 신뢰하는 호스트를 나열해요. 이 목록이, 예를 들어 클라우드 제공자의 인스턴스 메타데이터 엔드포인트나 Backstage 인스턴스가 접근할 수 있는 민감한 정보를 담은 다른 엔드포인트에 대한 접근을 허용하지 않도록 하는 것이 매우 중요해요. 일반적으로 목록을 최소로 유지하고 필요한 엔드포인트에서만 읽도록 허용하는 것을 권장해요. 코드로 구현해야 하는 UrlReader 인터페이스의 사용자 지정 구현에도 같은 우려가 적용돼요.

참고로 UrlReaderService 시스템은 서비스 컨텍스트로 작동하며 Backstage 권한 시스템이나 다른 외부 접근 제어 메커니즘과 통합되지 않아요. 이는 Backstage 인스턴스의 사용자가 개인이 접근해서는 안 되는 외부 콘텐츠를 읽을 수 있음을 의미해요. 예를 들어 catalog-info.yaml의 $text 자리 표시자는 사용자가 직접 접근할 수 없는 GitHub 저장소 같은 소스의 콘텐츠를 읽는 데 사용될 수 있어요. 이것이 우려된다면 카탈로그 자리 표시자 프로세서의 리졸버와 다른 플러그인의 유사한 기능을 비활성화하거나 교체하는 것을 권장해요.

인증

Backstage는 auth 플러그인을 통해 사용자 인증을 제공하며, 이는 주로 다양한 OAuth 2.0 제공자 통합을 위한 인가 서버 역할을 해요. 이 통합은 사용자를 Backstage에 로그인시키는 목적과 외부 리소스에 대한 위임 접근을 제공하는 목적을 모두 수행할 수 있으며, 모두 안전한 OAuth 2.0 인가 서버 구현의 공통적인 우려 사항을 따르게 돼요. 모든 auth 제공자 통합은 기본적으로 비활성화되어 있으며, 사용하려면 구성을 통해 활성화해야 해요. 각 Backstage 설치에서는 해당 인스턴스가 사용하는 최소한의 제공자 집합만 활성화하는 것을 권장해요.

auth 제공자를 사용해 사용자를 Backstage에 로그인시키려면 로그인 리졸버(sign-in resolver)로 구성해야 해요. 로그인 리졸버는 Backstage를 구성하는 데 민감한 부분이며, 항상 사용자 신원을 올바르게 해석하고 무단 사용자를 거부하는 것이 중요해요. 구성을 단순화할 수 있는 여러 내장 로그인 리졸버가 있거나, 코드로 자체 사용자 지정 로그인 리졸버를 구현할 수 있어요. 어느 쪽이든 이 리졸버가 사용자 신원을 올바르게 매핑하는 것이 매우 중요해요. 계정 탈취 위험을 피하기 위해 항상 필요한 최소한의 로그인 리졸버를 사용해야 해요.

Backstage는 AWS ALB 같은 인증 역방향 프록시를 통한 인증도 지원하며, 사용자 신원은 들어오는 프록시된 장식 요청에서 읽혀요. 다음 프록시 auth 제공자는 들어오는 요청의 서명을 검증하므로 사용자가 직접 접근해도 안전하게 배포할 수 있어요: awsAlb, cfAccess, gcpIap. oauth2Proxy 같은 제공자는 들어오는 요청을 검증하지 않으므로, 악의적인 내부 사용자가 위조된 신원 정보를 auth 백엔드에 공급하도록 스푸핑할 수 있어요. 따라서 oauth2Proxy 엔드포인트에 대한 접근을 제한하거나 다른 제공자를 사용하는 것을 강력히 권장해요.

로그인 리졸버로 로그인하는 과정의 일부로, 해석된 사용자 신원을 담은 Backstage Token이 발급돼요. 토큰은 비대칭 서명된 JSON Web Token이며, 공개 키는 토큰을 검증하려는 어떤 서비스든 사용할 수 있어요. 서명 키는 지속적으로 회전되며 각 Backstage 설치에 고유하므로, Backstage Token은 설치 간에 공유되지 않아요. 토큰은 사용자 신원과 소유권 정보에 대한 클레임을 담고 있어, 해당 사용자나 그룹이 소유한 Backstage 리소스를 결정하는 데 사용할 수 있어요. 이 토큰이 auth 플러그인 밖에서 위조될 수 없도록 하는 것이 중요하며, 예외는 같은 백엔드 서비스에 배포되거나 같은 데이터베이스를 공유하는 다른 플러그인이에요. 따라서 높은 보안 배포의 경우 auth 백엔드는 자체 데이터베이스를 가진 별도의 서비스에 배포해야 해요.

토큰은 Backstage 시스템 안에서 사용자의 신원을 증명하는 데 사용되며, Backstage 플러그인 전반에서 접근을 제어하는 데 사용돼요. 소유권 해석 로직이 Backstage 생태계 전체에서 일관되고 소유권 정보를 잘못 해석할 가능성이 없도록 하는 것이 중요해요.

사용자 토큰의 클레임 중 하나는 User Identity Proof 또는 uip예요. 이는 오프라인 토큰 변환을 허용하는 토큰의 추가 서명이에요. 원래 서명을 uip로 대체하면 토큰은 여전히 사용자 신원의 증명이지만 더 이상 완전한 접근 토큰으로 작동하지 않으며 대부분의 플러그인 엔드포인트에서 거부돼요. 플러그인은 필요할 때 이 제한된 토큰의 사용을 명시적으로 허용할 수 있지만, 이는 완전한 토큰을 사용할 수 없을 때 필요할 때만, 이상적으로는 읽기 전용 접근에만 사용해야 해요. 제한된 사용자 토큰의 사용 사례에는 정적 애셋의 쿠키 인증, 데이터베이스에 사용자 신원 증명 저장 등이 있어요.

백엔드 플러그인 간의 통신은 사용자 인증과 비슷한 인증 방식을 사용해요. 각 백엔드 플러그인은 토큰 서명에 사용하는 자체 키 집합을 생성·게시하고, 공개 키는 검증을 위해 다른 모든 플러그인과 공유돼요. 각 플러그인의 게시된 JWKS의 예상 위치는 백엔드의 DiscoveryService 구현에 의해 결정되므로, 그 서비스의 어떤 사용자 지정 구현이든 사용자 입력에 주의하는 것이 매우 중요해요. 각 플러그인이 서명한 토큰에는 소스와 대상 플러그인 ID가 모두 포함되므로, 토큰을 재사용해 다른 플러그인에 접근할 수 없어요.

백엔드 플러그인 간 호출에서 사용자 신원을 전달할 때는 uip가 있는 제한된 사용자 토큰만 사용되며, 이를 호출 플러그인이 서명한 새 서비스 토큰으로 감싸요. 이는 수신 플러그인이 사용자 신원을 신뢰할 수 있지만, 인가된 플러그인을 제외하고는 사용자를 대신해 추가 호출을 할 수 없음을 의미해요. 다른 플러그인의 제한된 사용자 토큰을 받아들이는 엔드포인트는 예외이며, 가능하면 받아들이지 않는 것이 좋은 이유이기도 해요.

카탈로그

운영자는 사용자가 정의할 수 있는 허용된 엔티티 종류를 제한하도록 카탈로그 규칙을 구성해야 해요. 일반적으로 User, Group, Template 엔티티의 정의를 제한해 내부 사용자가 추가 항목을 등록하지 못하게 하는 것이 좋아요. Template 엔티티는 백엔드 호스트에서 실행되는 액션을 정의하며, 목표는 입력과 무관하게 이 액션이 안전하도록 하는 것이지만 여전히 더 민감한 컨텍스트이므로 추가 검사로 보호하는 것을 권장해요. 카탈로그에서 조직 데이터로 User와 Group 엔티티를 인제스해 그것에 의존한다면 그 엔티티 등록을 허용하지 않는 것이 매우 중요해요. 그렇게 하면 사용자를 사칭하고 그룹 구성원 정보를 혼란시킬 수 있는 가능성이 생길 수 있어요. 조직 데이터는 항상 정적으로 구성된 카탈로그 위치나 신뢰된 소스에서 읽는 엔티티 제공자를 사용해 인제스해야 해요. 엔티티 제공자가 직접 내보내는 엔티티는 항상 신뢰되며 규칙이 적용되지 않지만, 그 체인 아래에서 생성되는 엔티티는 여전히 규칙의 대상이 돼요.

카탈로그는 기본 설정에서 리소스 고갈 공격으로부터 보호하는 것을 목표로 하지 않아요. 내부 사용자가 많은 양의 엔티티를 등록하지 못하게 해야 한다면 엔티티 등록을 비활성화하고 엔티티를 발견하는 다른 접근 방식을 사용하는 것을 권장해요. 리소스 고갈 공격을 완화하는 한 가지 방법은 카탈로그가 감사 추적이 있는 신뢰된 SCM 소스에서만 읽도록 허용하는 것이에요. 카탈로그는 현재 엔티티 계층 깊이와 엔티티 크기에 대한 제한이 없으며, 이는 미래에 해결하고 싶어 해요.

기본적으로 모든 내부 사용자는 엔티티를 생성·삭제할 수 있어요. 이것이 조직의 요구에 맞지 않는다면 권한 시스템을 활성화하고 구성해 이 작업을 제한하는 것을 권장해요.

Scaffolder

기본적으로 스캐폴딩 작업은 템플릿에 정의된 액션을 포함해 호스트 머신에서 직접 실행돼요. Scaffolder 템플릿은 더 민감한 영역으로 간주되므로 템플릿 생성·갱신에 대한 접근을 신뢰된 당사자로 제어하는 것을 권장해요. 템플릿 실행은 입력과 무관하게 안전하도록 의도되지만, 여전히 이 추가 보호 계층을 권장해요. 문자열 템플릿은 Nunjitsu의 폐쇄 인터프리터가 평가하며, 이는 템플릿이 주변 Node.js 프로세스에 접근하는 것을 방지해요.

Scaffolder는 종종 GitHub 조직에서 저장소를 만드는 것 같은 높은 권한을 가져요. 따라서 운영자는 사용자 입력이 일반적으로 사용자 정의이므로 리소스를 악의적으로 또는 실수로 삭제하거나 수정할 수 있는, 기존 리소스를 삭제하거나 갱신하는 Scaffolder Template에 주의해야 해요.

Scaffolder 서비스가 가지는 접근을 줄일 수 있는 한 가지 전략은 액션 실행 시 사용자 자격 증명에 의존하는 것이에요. 예를 들어 GitHub App 통합을 읽기 전용 권한으로 구성하고, 별도의 사용자 OAuth 토큰으로 저장소를 만들 수 있어요. 이는 우선 사용자가 저장소를 만들 수 있는 접근 권한을 가져야 해요.

운영자는 다른 플러그인 패키지처럼 설치된 스캐폴딩 액션을 감사해야 해요. 일부 액션은 더 완화된 환경을 위해 의도되었을 수 있으므로, 설치된 액션이 자체 보안 요구 사항과 부합하는지 검증하는 것도 중요해요.

기본적으로 모든 내부 사용자는 스캐폴더에서 템플릿을 실행할 수 있어요. 이것이 조직의 요구에 맞지 않는다면 권한 시스템을 활성화하고 구성해 이 작업을 제한하는 것을 권장해요.

TechDocs

TechDocs의 백엔드는 크게 두 가지 방식으로 구성할 수 있어요. 기본값은 techdocs.builder가 local로 설정된 경우로, 문서가 요청 시 생성되어 TechDocs 백엔드에 의해 로컬로 저장돼요. techdocs.builder가 external로 설정된 경우는 문서가 외부 프로세스(예: CI/CD 파이프라인)에 의해 생성되고 구성된 외부 스토리지 제공자에서 단순히 읽는다고 가정해요.

문서가 로컬로 생성될 때는 생성된 애셋이 저장되는 위치에서 파일 시스템 권한의 안전한 구성을 보장할 책임이 통합자에게 있어요. 문서가 외부에서 생성될 때는 문서를 생성하는 외부 프로세스, 문서 애셋이 게시되는 스토리지 제공자, TechDocs 백엔드 사이의 접근 제어와 권한 부여를 보장할 책임이 통합자에게 있어요.

백엔드 구성과 무관하게 TechDocs 프론트엔드는 문서 사이트의 생성된 HTML을 신뢰하지 않으며, 사용자에게 콘텐츠를 렌더링하기 전에 엄격한 살균(sanitization) 프로세스를 적용해요.

기본적으로 모든 TechDocs 문서는 모든 Backstage 사용자에게 보여요. 카탈로그에 대한 보기 권한을 구성해 TechDocs 사이트에 대한 접근을 제한할 수 있어요.

프록시

프록시 백엔드는 프론트엔드 플러그인이 Backstage 프론트엔드에서 직접 트래픽을 받도록 설정되지 않을 수 있는 원격 서비스에 접근하기 위한 유틸리티로 작동해요. 일반적인 이유는 업스트림 서비스가 적절한 CORS 헤더를 제공하지 않거나 콘텐츠를 HTTPS로 서빙하지 않는 경우예요.

프록시 항목은 정적 구성을 통해 구성돼요. 각 항목은 마운트 경로와 업스트림 대상이 있으며, 허용된 메서드를 제한하거나 추가 헤더를 주입하는 것 같은 다른 옵션도 지원해요. 업스트림 서비스에 인증 헤더를 주입하는 것은 자격 증명으로 요청을 장식하는 위험한 방식이므로 피하는 것을 권장해요. Backstage 배포에 접근할 수 있는 사람은 누구나 주입된 자격 증명을 사용해 업스트림 서비스에 요청할 수 있어요. 대신 개별 요청을 안전한 방식으로 업스트림 서비스에 전달하는 백엔드 플러그인을 만드는 것을 권장해요. 업스트림 요청에 자격 증명을 주입하게 된다면 민감한 정보나 액션을 노출하지 않는지 확인하세요. 또한 사용할 수 있는 메서드를 제한하는 allowedMethods 옵션을 사용하고 최소 요구 인가 범위의 토큰을 사용하는 등 접근을 최대한 제한해야 해요.

더 알아보기 (Learn more)