VPC Service Control의 Ingress/Egress Policies를 이용한 세분화된 BigQuery 접근 제어
구글 PS1팀 손지황
VPC Service Controls에 대하여
전통적인 보안 측면에서 Firewall은 TCP/IP, UDP 기반의 네트워크 통신에 대한 보안 기능을 제공하였습니다. 그리고 GCP 역시 Firewall 기능을 제공하고 있고, 올해 기능이 추가된 새로운 버전 런칭도 하였지만, VPC내 각종 Resource에 대한 API를 효율적으로 통제하고 보호하기에는 다른 성격의 보호 서비스가 필요합니다.
VPC Service Control은 GCP Resource에 대한 API 통신을 효율적으로 통제하기에 적합한 서비스로, GCP API 전용 방화벽으로 불러도 될만큼 API 통신을 쉽고 세밀하게 제어할 수 있습니다.
Perimeter로 불리는 보호 영역을 설정하고(어디서), 보호 대상 서비스 지정(무엇을), Perimeter를 기준으로 Ingress / Egress 정책을 설정하는것만으로(어떻게) GCP 내 Resource에 대해 효과적으로 보호 할 수 있습니다.
Perimeter의 통과 조건인 Ingress/Egress Policies
Access Level은 IP 기반, 지리적 위치 그리고 GCP 계정(User, Service Account) 등 각종 조건의 조합으로 구성되는 만큼 그 자체만으로도 훌륭한 설정이 가능합니다. 따라서 초기 VPC Service Control은 Perimeter와 Perimeter 간의 관계인 Bridge, 그리고 Perimeter 통과 조건에는 Access Level을 이용하여 구성하도록 설계되었습니다.
하지만 Perimeter 간의 관계를 설정할때 사용하였던 Bridge는 같은 ORG내에 있는 Project에만 설정이 가능하다는 제약이 있었고, 그래서 보조적으로 타 ORG에 있는 Project와 관계를 설정할때는 Ingress/Egress Policy를 통해 Project를 허용하는 설정을 해야만 설정이 가능하였습니다.
거기에 Perimeter를 보호하는데 있어 Access Level과 Bridge만으로는 기본적인 설계가 가능하지만 그 조합은 단순했고, 그보다 더 상세한 조건으로 허용 조건을 설정한다는것은 불가능하다는 문제가 있었습니다.
그래서 GCP는 Perimeter 통과 조건을 Ingress/Egress Policies를 기본 조건으로 변경하고, 기존의 Access Level 기반의 설정은 Optional 한 설정으로 변경하였습니다. 이것이 가능한것은 기존의 Access Level 설정 옵션은, 사실 Perimeter로 들어오는 Ingress API 요청에 대해 허용 Access Level을 설정함으로 Perimter를 보호했던거고, 이는 Ingress Policy에 Access Level에 대해 모든 것을 허용함과 같은 의미이기 때문입니다.
즉, 기존의 Access Level이 Optional로 변경되었지만, Ingres Policy 설정을 통해 동일한 효과를 가질 수 있으므로 특별한 경우가 아니면 사용할 일이 없게 되었으며, 이제 Ingress/Egress Policies를 통해 기존과 동일한 수준 또는 더 상세하게 통과 조건을 설정할 수 있게 된것입니다. 이를 이용해서 BigQuery의 데이터를 접근하는, 부여된 권한과 같은 조건에 따라 보호할 수 있습니다.
Ingress/Egress Policy
Ingress/Egress Policy는 Perimeter를 기준으로 방향에 따라 From/To 설정을 하게 됩니다. GCP에 대한 API는 어디서 어떤 형태로든 호출될 수 있으므로 그에 맞게 설정을 진행합니다.
Ingress Policy
Ingress Policy는 From에 Identity와 Source, To는 Project와 Service를 설정합니다.

Identity:
‘Any Identity’, ‘Any User Account’, ‘Any Service Account’를 통해 각각 제한 없음, 모든 유저, 모든 서비스 어카운트에 대해 지정을 할 수 있습니다. 또 ‘Selected identities’를 통해 직접 허용할 유저와 서비스 어카운트 각각을 입력할 수 있습니다.
GCP에 접근하는 환경이 다수의 유저만 접근할 경우 Any User Account를 선택할 수 있지만, 일부 유저만 사용하는 환경이라면 Selected identities를 통해 제한을 하는것이 보안을 위한 선택입니다.
다만, 보안을 위해 Any를 선택할 수 없고, Selected identities를 통해 입력할 유저가 많다면 Any Identity를 선택하고, 다음 Source에 적절한 Access Level을 지정합니다. Policy에 다수의 유저가 입력되면 스트링 형태로 표현되므로 관리의 어려움이 있습니다. 이럴때는 Access Level을 통해 User, User + IP Range 형태로 제한을 거는것이 더 효율적입니다.
Source:
API가 호출되는 위치 입니다. ‘All Sources’, ‘Access Level’, ‘Projects’, ‘VPC Networks’를 선택할 수 있으며, 보통 ‘Projects’ 또는 ‘Access Level’로 설정을 하게 됩니다. Project간 API 통신에는 Projects를 선택하게 되고, 앞서 이야기한것처럼 Identity로 설정하기 어려운 경우 Access Level을 통해 제한을 걸 수 있습니다.
Project:
‘All projects’, ‘Selected projects’를 선택할 수 있습니다. 보통 All projects로 Perimeter에 설정된 Project 모두에 대해 공통 설정을 하는것이 일반적이나, Perimeter에 Project가 복수로 설정된 경우 Selected projects를 선택해 각각에 대해 설정할 수 있습니다.
Service:
Policy의 가장 중요한 설정입니다. 어떠한 Service(Resource) API를 허용할지 선택할 수 있습니다. ‘All services’ 또는 ‘Selected services’를 선택할 수 있습니다.
‘All services’를 선택할 경우 Perimeter로 보호받는 모든 서비스에 대한 API가 허용됩니다. 하지만 VPC SC의 보다 상세한 설정을 위해서는 ‘Selected services’를 선택하고, 허용할 API와 Method를 제한하게 됩니다.
Method는 각 API에서 호출하는 Method이며, GCP는 보통 각 리소스에 대해 CRUD Method를 각각 제공하므로 이를 통해 API에 대한 상세한 제어가 가능합니다.
Egress Policy
Egress Policy는 From에 Identity, To는 GCP냐 외부 리소스냐에 따라 달라지는데, 보통 GCP에 대한 통신을 보호하므로 GCP 기준으로 Project와 Services를 설정하게 됩니다.

Identity, Project, Services는 Ingress와 동일한 방식으로 옵션을 설정 하게 됩니다.
BigQuery에서 Query 수행
VPC Service Control을 사용해 BigQuery Data를 보호하기 위해서는 BigQuery에서 Query를 수행 시 어떠한 API 동작이 수행되는지 이해할 필요가 있습니다. 이는 Query 내용과 실행 위치에 따라 다양한 조합으로 수행이 되는데, 특정 케이스에 대한 이해가 있으면 다른 케이스에 대한 동작을 예상해볼 수 있습니다.
다음은 특정 프로젝트(Src Prj.)에서 다른 프로젝트(Tgt Prj.)에 있는 BQ Data에 대한 Select Query를 실행했을때 프로젝트 간 발생하는 내부 호출에 대한 흐름입니다.

위 그림을 순서대로 살펴보면
- 사용자는 Source Project의 GCP Console에에서 Select Query를 실행합니다. 이때 데이터를 조회하는 대상은 Target Project의 BQ에 저장된 데이터 입니다.
이때 사용자는 GCP Console에서 `Run Query`를 클릭 했을 뿐이지만 실제로는 사용자 위치에서 Source Project로 Query 실행을 한것에 대한 API Method가 내부적으로 생성됩니다.(Source Project의 Perimeter 통과) - Source Project는 Target Project로 GCP 내부적인 BigQuery API 호출을 생성합니다. 이 때 사용하는 Method는 BigQuery Job을 생성하는 bigquery.jobs.create와 실제 데이터를 요청하는 bigquery.tables.getData 입니다.
- GCP는 사용자가 실제 Target Project에 접근이 가능한지 확인하기 위한것으로 추정되는 API 호출을 하나 더 생성합니다. 이는 사용자 위치에서 직접 Target Project로 2번과 동일한 API Method를 호출함으로 알 수 있습니다.
※ 만약 최초 호출이 사용자가 아닌 Source Project의 VPC 내에서 이루어졌다면, 다른 흐름이 나타날것입니다. - Target Project에서 데이터를 가져오는 BigQuery Job 수행이 완료되면, 반대로 Source Project에 BigQuery Job을 생성하는 요청을 하게 됩니다.
- 확보된 데이터가 Source Project의 GCP Console에서 표시됩니다.
위 케이스를 보면 BigQuery에서 Query를 수행 시 내부적으로 API 통신이 이루어지고 있음을 알 수 있습니다. 따라서 상황별 호출되는 API Method를 알고 있으면 BigQuery를 효율적으로 보호할 수 있습니다.
BigQuery에서 Project간 단방향 조회 설정
GCP를 이용해 구축한 시스템은 초기에는 VPC SC의 기본적인 기능만으로도 BigQuery의 Data를 안전하게 보호할 수 있습니다. 하지만 시스템이 확장되면서 GCP 내외적으로 데이터에 접근하는 다양한 케이스가 있고, 케이스별로 제약조건이 상이할 수 있습니다. 경우에 따라 기존 Bridge로는 커버가 안되는 상황이 발생하게 되는데, VPC SC 에서 Policy를 사용하면 이런 상황에 적절한 설정으로 BigQuery 데이터를 계속 보호할 수 있습니다. 그리고 이런 케이스 중 하나가 바로 BigQuery 단방향 조회 케이스 입니다.
케이스 시나리오
프로젝트 A와 B가 있고, A에서 B로 데이터 조회 쿼리를 날릴 수 있지만, B에서 A로는 차단해야하는 경우가 있다고 가정합니다.

이는 프로젝트 A는 모든 데이터를 저장하는 곳이고, B는 데이터가 생성되는 프로젝트라고 했을때, A는 조회를 위해 B에 접근을 해야하지만, B는 여러 프로젝트로부터 각종 데이터가 수집되는 A의 데이터에 접근해서는 안됩니다.
즉 프로젝트마다 가지고 있는 데이터의 중요도로 인해 조회 방향을 설정하는 케이스로, 이를 권한으로 제어할 수 있지만, 관리자나 상위 권한을 가진 사람은 어쩔 수 없이 두 프로젝트 모두 권한을 가지는 예외 상황이 발생할 수 있습니다. 따라서 보다 강화된 보안을 위해서는 불필요한 API Method를 차단함으로 혹시라도 잘못된 방향으로 데이터를 조회하는 상황을 원천적으로 차단할 수 있다는 장점을 가지게 됩니다.
VPC SC의 Policy 설정
이런 단방향 조회 설정의 열쇠는 Service 설정에 Method 입니다. Project A와 Project B에 설정된 각각의 Perimeter의 Ingress/Egress Policy 설정에 Method 조정을 통해 이를 구현합니다.
Project A에 대한 Perimeter의 Policy설정
Ingress Policy
From:
Identities:ANY_IDENTITY
Source > Projects =
Project A
To:
Projects =
Project B
Services =
Service name: bigquery.googleapis.com
Service methods:
bigquery.jobs.create
Egress Policy
From:
Identities:ANY_IDENTITY
To:
Projects =
Project B
Service =
Service name: bigquery.googleapis.com
Service methods:
허용할 BigQuery API의 Method 설정
허용할 Method는 케이스마다 차이가 있어 명확하게 정의하기가 어렵습니다. 다만, 기초적인 Select만 수행한다고 가정한다면, 다음과 같은 Method만 허용해도 문제는 없습니다.
BigQuery에서 Select 에 필요한 최소한의 Method
- bigquery.jobs.create
- bigquery.tables.get
- bigquery.tables.getData
Select에 필요한 권장 Method
- bigquery.jobs.create
- bigquery.datasets.get
- bigquery.tables.get
- bigquery.tables.getData
- bigquery.tables.getIamPolicy
- bigquery.tables.list
그 외 허용하는 수준에 따라 모든 Method를 열거나, 작업 범위에 따라 다음과 같은 Method를 선별하여 추가할 수 있습니다.
- BigQueryStorage.ReadRows
- BigQueryStorage.FinalizeStream
- BigQueryStorage.SplitReadStream
- BigQueryStorage.BatchCreateReadSessionStreams
- BigQueryStorage.CreateReadSession
- bigquery.routines.list
- bigquery.routines.get
- bigquery.models.list
- bigquery.models.getMetadata
- bigquery.datasets.get
- bigquery.jobs.create
- bigquery.tables.list
- bigquery.tables.update
- bigquery.tables.updateTag
- bigquery.tables.get
- bigquery.tables.getData
- bigquery.tables.getIamPolicy
- bigquery.tables.setCategory
지원되는 Method 목록은 다음 링크에서 확인할 수 있습니다.
Docs: Supported service method restrictions
Project B에 대한 Perimeter의 Policy설정
Ingress Policy
From:
Identities:ANY_IDENTITY
Source > Projects =
Project B
To:
Projects =
Project A
Services =
Service name: bigquery.googleapis.com
Service methods:
Project A의 Egress Policy에 허용한 Method와 동일
Egress Policy
From:
Identities:ANY_IDENTITY
To:
Projects =
Project A
Service =
Service name: bigquery.googleapis.com
Service methods:
bigquery.jobs.create
Project B는 A와 반대로 설정하게 됩니다. A의 Egress에서 허용한 Method가 B의 Ingress에 동일하게 설정되어야 합니다. 다만 BigQuery Job을 생성하는 Method의 경우 BigQuery 내부 구조상 두 프로젝트 모두 양방향으로 허용 되어야 합니다.
BigQuery 보안과 관련된 Method
BigQuery에는 자체적인 보안 기능으로 column-level security와 row-level security가 있습니다. 해당 기능이 설정된 데이터를 조회시 bigquery.tables.getData와 별도로 추가 method가 필요합니다.
Column-Level Security
BigQuey는 Policy Tag를 사용하여 개인 정보 등의 민감한 데이터를 별도의 권한으로 관리할 수 있습니다. 그리고 다른 프로젝트에서 이 Policy Tag를 설정하고, 데이터가 있는 프로젝트에서 이 Policy Tag를 가져다 쓴다고 하면 Fine-Grained Reader라는 권한이 필요하게 되는데, 실제 데이터 질의 시 권한 확인을 위한 별도의 API 호출을 하게 됩니다.

이때 사용하는 Method가 ‘fineGrainedGet’ 입니다. 이 Method 없이는 데이터 조회에 필요한 Method가 허용되고, 관련 IAM 권한이 있어도 절대 데이터에 접근할 수 없었습니다. Column-Level Security가 설정된 테이블에 접근할때는 다음 Method를 반드시 허용해 줘야합니다.
- datacatalog.categories.fineGrainedGet
Row-Level Security
최근까지 Row-Level Security가 적용된 테이블에 접근해야하는 경우, 해당 Method가 지원되지 않아 Policy를 All Method로 오픈하지 않고서는 설정이 불가능하였습니다. 하지만 이제 관련된 Method가 지원되어 Policy 설정으로도 Row-Level Security가 설정된 데이터에 대해서도 Method 제한과 동시에 접근이 가능해졌습니다.

Method에 `getFilteredData`를 허용함으로 Row-Level Security에 설정된 테이블도 정상적으로 제어가 가능해졌습니다. 따라서 Row-Level Security가 설정된 테이블의 데이터를 조회한다면 다음 Method를 반드시 허용해줘야 합니다.
- bigquery.rowAccessPolicies.getFilteredData
맺음말
기존 VPC Service Control의 경우 Bridge는 Perimeter와 Perimeter를 동등한 Level로 맞추기 때문에, 허용하고 싶지 않는 Service도 허용하게 된다거나, Access Level만으로는 데이터에 대한 Read 권한만 제공하고 싶지만 CRUD 모두를 허용하게 되는 등 의도하지 않은 과도한 허용을 할 수 밖에 없었습니다. 하지만 Ingress/Egress Policy를 사용하게 되면 다양한 상황에서 최소한의 Method만 허용하여, 서비스에 영향을 주지 않으면서 보안적으로 안전한 시스템 환경을 구성할 수 있습니다.
각 케이스에 맞는 Method만 허용한다는 작업은 BigQuery 기능 각각에 대해 내부 동작 방식을 알아야만 설정할 수 있으므로 사실 쉽지 않은 작업입니다. 다만 보안에 대한 의지를 가지고, 최소 허용 후 기능 동작 시 발생하는 에러 로그를 가지고 분석을 하게 되면 분명 필요한 Method를 확인할 수 있습니다. 앞서 이야기 했지만 권한으로만 제어를 하기에는 예외적인 상황이 발생할 수 있으며, 시간이 지남에 따라 점차 추가로 부여되는 권한들로부터 작업의 편의성과 보안을 모두 가질 수 없습니다. 따라서 VPC SC를 이용하여 원천적으로 접근을 통제하는 방법이 필연적으로 같이 수행되어야 하므로, 각 케이스에 맞는 설정으로 안정된 서비스와 보안 모두를 가지시길 바랍니다.