Milvus 행 수준 RBAC로 세분화된 액세스 제어 활성화
현대 데이터 시스템에서 액세스 제어가 중요한 이유
액세스 제어는 현대 데이터 관리, 특히 기업에서 가장 시급한 과제 중 하나입니다. 조직이 성장함에 따라, 특히 여러 부서와 역할이 있는 환경에서는 강력한 보안과 원활한 액세스가 모두 중요합니다. 액세스 제어가 특히 중요한 두 가지 예를 살펴보겠습니다.
의료: 개인정보 보호와 협업의 균형
의료 분야에서 조직은 환자의 개인정보를 보호하는 동시에 의료 전문가 간의 협업을 촉진해야 합니다. 정확한 진단과 치료 계획을 세우기 위해 환자의 의료 기록에 대한 전체 액세스가 필요한 의사를 상상해 보세요. 하지만 그 의사는 자신이 치료하지 않는 환자의 기록에는 액세스할 수 없어야 합니다. 이러한 요구를 충족하려면 세분화된 액세스 제어가 필수적이며, 이를 통해 권한이 부여된 의료진만 민감한 환자 데이터를 볼 수 있도록 보장할 수 있습니다. 이러한 수준의 제어는 조직이 HIPAA와 같은 엄격한 규정을 준수하는 동시에 개인정보를 보호하는 데 도움이 됩니다.
금융: 민감한 데이터 보호
금융 업계도 액세스 제어와 관련해 유사한 과제에 직면해 있습니다. 은행과 금융 기관은 계좌 세부 정보, 거래 내역, 신용 점수 등 방대한 양의 민감한 데이터를 처리합니다. 이러한 데이터는 사기 탐지, 리스크 분석, 개인화된 고객 경험을 위해 종종 벡터로 변환되어 Milvus와 같은 벡터 데이터베이스에 저장됩니다. 적절한 액세스 제어가 없으면 민감한 데이터가 권한이 없는 당사자에게 노출되어 중대한 재정적 및 법적 결과로 이어질 수 있습니다.
행 수준 권한과 같은 세분화된 제어를 통해 기관은 특정 사용자에 대한 액세스를 제한할 수 있습니다. 예를 들어, 고객 관리자는 자신의 고객 계좌 데이터에만 액세스할 수 있습니다. 리스크 관리 팀에 필요한 더 광범위한 액세스조차도 오용을 방지하기 위해 신중하게 모니터링하고 제한할 수 있습니다.
Milvus 행 수준 RBAC: 세분화된 액세스 제어 솔루션
역할 기반 액세스 제어(RBAC)는 조직 내 사용자의 역할에 따라 리소스에 대한 액세스가 부여되는 보안 모델입니다. 역할은 권한을 정의하고, 사용자는 해당 권한을 상속받아 액세스 권한을 안전하고 효율적으로 관리할 수 있도록 합니다.
Milvus는 확장성을 위해 구축된 오픈 소스 고성능 벡터 데이터베이스입니다. 검색 증강 생성(RAG), 시맨틱 검색 엔진, 추천 시스템, 챗봇과 같은 모델 AI 애플리케이션 구축에 적합합니다. Milvus는 비트맵 인덱싱을 사용하여 행 수준 액세스 제어를 가능하게 하는 권한 모델을 기반으로 세분화된 RBAC 솔루션을 제공합니다. 이 기능을 통해 사용자 역할 및 권한에 따라 특정 Milvus 리소스와 권한에 대한 액세스를 제어할 수 있습니다. 현재 Milvus RBAC는 Python과 Java에서만 사용할 수 있습니다.
Milvus RBAC는 여러 가지 장점을 제공합니다.
속도와 효율성: 대규모 데이터셋에서 권한을 빠르게 쿼리할 수 있습니다.
유연성: 역할과 책임이 변화함에 따라 적응하여 권한이 최신 상태로 유지되도록 보장합니다.
RBAC 기본 사항
역할과 권한
역할: 시스템에서 사용자의 역할을 나타내며, 각 역할에는 특정 권한 집합이 할당됩니다.
권한: Milvus 내 데이터 연결(테이블)의 개별 행에 대한 액세스 권한을 지정하며, 특정 데이터를 읽기, 쓰기 또는 삭제할 수 있는 권한 등이 포함됩니다.
비트맵 인덱스 구축
비트맵 인덱스는 이 액세스 제어 메커니즘의 기반입니다.
각 역할은 액세스할 수 있는 행을 나타내는 비트맵과 연결됩니다.
비트맵의 길이는 연결의 행 수와 일치합니다.
한 위치의 1은 해당 역할이 그 행에 액세스할 수 있음을 의미합니다.
0은 액세스 권한이 없음을 의미합니다.
비트맵 인덱스 사용
권한 부여: 역할에 행에 대한 액세스 권한을 부여하려면 역할의 비트맵에서 해당 비트를 1로 설정합니다.
권한 확인: 역할이 특정 행에 액세스할 수 있는지 확인하려면 비트맵에서 해당 비트가 1인지 확인하기만 하면 됩니다.
엔터프라이즈 지식을 저장하는 연결(테이블)인 Collection A가 있다고 가정해 보겠습니다. 각 행은 doc_id와 그와 연결된 지식 베이스인 kb_id로 식별되는 콘텐츠를 나타냅니다.
| 행 ID | PK | 데이터 | doc_id | kb_id | 역할 |
|---|---|---|---|---|---|
| 1 | 0 | Data A | 1 | 1 | role1 |
| 2 | 1 | Data B | 1 | 1 | role1 |
| 3 | 2 | Data C | 2 | 1 | role1 |
| 4 | 3 | Data D | 2 | 1 | role1 |
| 5 | 4 | Data E | 3 | 2 | role2 |
역할은 다음과 같이 정의됩니다:
Role 1: 행 1, 2, 3, 4에 액세스할 수 있습니다(
kb_id = 1).Role 2: 행 5에 액세스할 수 있습니다(
kb_id = 2).
쿼리 작업
사용자가 데이터를 쿼리할 때, 해당 사용자의 역할 비트맵은 쿼리 조건과 결합되어 액세스 권한이 있는 행을 필터링합니다. 예를 들어 Role 1을 가진 사용자가 "모든 데이터"를 쿼리하면, 해당 비트맵 11110은 행 1–4(Data A, Data B, Data C, Data D)를 반환합니다.
권한 업데이트
역할에 대한 액세스를 추가하거나 제거하려면 역할의 비트맵에서 해당 비트를 업데이트하기만 하면 됩니다. 예를 들어 비트를 1로 설정하면 액세스가 부여되고, 0으로 설정하면 철회됩니다.
장점 및 고려 사항
효율성: 비트맵 작업은 빠르며 대규모 데이터셋의 권한 관리에 적합합니다.
낮은 저장소 오버헤드: 비트맵은 수백만 개의 행이 있는 데이터셋에서도 최소한의 저장소만 사용합니다.
유연성: 비트맵 인덱스는 복잡한 쿼리 조건과 조합을 지원하므로 다양한 사용 사례에 매우 유연하게 적용할 수 있습니다.
Milvus 행 수준 RBAC 시연
이 섹션에서는 Milvus가 대기업의 다양한 지식 베이스에 대한 액세스를 관리하는 방법을 시연합니다.
사용 사례: 여러 지식 베이스를 갖춘 엔터프라이즈 RAG
대기업에서는 서로 다른 부서가 Milvus 기반의 RAG 애플리케이션을 위해 공개용 지식 베이스와 기밀 지식 베이스 등 별도의 지식 베이스를 유지하는 경우가 많습니다. 이러한 지식 베이스 전반에서 권한을 효과적으로 관리하기 위해, 엔터티 또는 문서를 기반으로 역할 기반 액세스 제어(RBAC)를 구현합니다. 예를 들어 슈퍼 관리자 역할(admin)이 액세스를 감독하고, CEO, finance, sales, developer와 같은 특정 비즈니스 단위에 대한 추가 역할이 각각 서로 다른 데이터 집합에 액세스할 수 있습니다.
그림: 대기업의 다양한 역할에 대한 액세스 제어
권한 열 정의
액세스를 관리하기 위해 Milvus 내의 배열 열에 권한 데이터를 저장합니다. 이 열은 어떤 역할이 어떤 데이터 행에 액세스할 수 있는지를 정의합니다. 이 권한 열의 field_name은 사용자 지정할 수 있으며, 배열의 크기는 사용자의 필요에 따라 조정할 수 있습니다. 그런 다음 이 열에 대해 BITMAP 인덱스가 생성되어 권한 확인을 효율적으로 만듭니다.
아래는 이 설정을 코드로 수행하는 방법입니다:
# 1. Set up a Milvus client
client = MilvusClient(
uri=CLUSTER_ENDPOINT
)
# 2. Create a collection
schema = MilvusClient.create_schema(
auto_id=False,
enable_dynamic_field=False,
)
# 3. define schema
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="data", datatype=DataType.VARCHAR, max_length=100)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=128)
# 4. add security column
schema.add_field(field_name="security_group", datatype=DataType.ARRAY,
element_type=DataType.VARCHAR, max_capacity=10, max_length=100)
index_params = MilvusClient.prepare_index_params()
index_params.add_index(
field_name="vector",
index_type="IVF_FLAT",
metric_type="L2",
params={"nlist": 1024}
)
# 5. create bitmap index for security column
index_params.add_index(field_name="security_group",
index_type="BITMAP")
# 6. create collection
client.create_collection(
collection_name="test_collection",
schema=schema,
index_params=index_params
)
쓰기 권한
새 데이터를 삽입할 때 각 행에 액세스할 수 있는 역할을 지정하여 권한을 할당합니다. 이는 해당 역할을 security_group 열에 작성하여 수행할 수 있습니다.
작동 방식의 예는 다음과 같습니다:
data =[]
data.append({
"id": random.randint(0, 100000),
"vector": [ random.uniform(-1, 1) for _ in range(128) ],
"data": "data" + str(random.randint(0,100000)),
# ceo role can read
"security_group": ["ceo"]
})
data.append({
"id": random.randint(0, 100000),
"vector": [ random.uniform(-1, 1) for _ in range(128) ],
"data": "data" + str(random.randint(0,100000)),
# finance role can read
"security_group": ["finance"]
})
data.append({
"id": random.randint(0, 100000),
"vector": [ random.uniform(-1, 1) for _ in range(128) ],
"data": "data" + str(random.randint(0,100000)),
# both sales and developer can read
"security_group": ["sales", "finance"]
})
res = client.insert(collection_name="test_collection", data=data)
쿼리 권한
검색 또는 쿼리 작업을 수행할 때, 사용자의 특정 역할이 액세스할 수 있는 데이터만 결과에 표시되도록 제한하는 것이 중요합니다. 사용자의 허용된 역할 범위를 벗어난 데이터는 쿼리 결과에서 숨겨집니다. 이를 수행하는 방법은 다음과 같습니다:
역할 권한 기반 데이터 쿼리
아래 예시에서는 array_contains() 함수를 사용하여 역할별 권한에 따라 데이터를 필터링합니다. 각 쿼리는 지정된 역할이 볼 수 있도록 승인된 데이터만 검색합니다.
res = client.query(
collection_name="test_collection",
# Query data visible only to the CEO role
filter='array_contains(security_group, "ceo")',
output_fields=["id", "data", "security_group"],
)
print("ceo role read:")
print(res)
res = client.query(
collection_name="test_collection",
# Query data visible only to the Sales role
filter='array_contains(security_group, "sales")',
output_fields=["id", "data", "security_group"],
)
print("sales role read:")
print(res)
res = client.query(
collection_name="test_collection",
# Query data visible only to the Developer role
filter='array_contains(security_group, "develop")',
output_fields=["id", "data", "security_group"],
)
print("developer role read:")
print(res)
res = client.query(
collection_name="test_collection",
# Query data visible to either the Developer or CEO roles
filter='array_contains_any(security_group, ["develop", "ceo"])',
output_fields=["id", "data", "security_group"],
)
print("developer or ceo role read:")
print(res)
출력은 다음과 같은 예시 형태가 됩니다:
ceo role read:
data: [
"{'security_group': ['ceo'], 'id': 3443, 'data': 'data35077'}",
"{'security_group': ['ceo'], 'id': 12181, 'data': 'data99090'}",
"{'security_group': ['ceo'], 'id': 16551, 'data': 'data74619'}",
"{'security_group': ['ceo'], 'id': 24466, 'data': 'data1373'}", ...
sales role read:
data: [
"{'data': 'data75305', 'security_group': ['sales'], 'id': 9122}",
"{'data': 'data61054', 'security_group': ['sales'], 'id': 20087}",
"{'data': 'data47948', 'security_group': ['sales', 'develop'], 'id': 21726}",
"{'data': 'data8596', 'security_group': ['sales'], 'id': 40090}", ...
developer role read:
data: [
"{'data': 'data1515', 'security_group': ['develop'], 'id': 6429}",
"{'data': 'data47031', 'security_group': ['develop'], 'id': 10953}",
"{'data': 'data47948', 'security_group': ['sales', 'develop'], 'id': 21726}",
"{'data': 'data86894', 'security_group': ['develop'], 'id': 56980}"], ...
developer or ceo role read:
data: [
"{'data': 'data35077', 'security_group': ['ceo'], 'id': 3443}",
"{'data': 'data1515', 'security_group': ['develop'], 'id': 6429}",
"{'data': 'data47031', 'security_group': ['develop'], 'id': 10953}",
"{'data': 'data99090', 'security_group': ['ceo'], 'id': 12181}", ...
이 접근 방식은 각 역할이 볼 권한이 있는 데이터만 정확히 보도록 보장하는 동시에, 권한이 없는 데이터는 숨깁니다. 또한 security_group 배열에 여러 역할을 쌓을 수 있어 유연하고 효율적인 권한 관리가 가능합니다.
역할 기반 액세스가 포함된 사용자 지정 필터
일부 경우, 사용자는 데이터를 쿼리할 때 사용자 지정 필터를 적용해야 할 수 있습니다. 이러한 필터는 검색을 구체화하기 위해 역할 기반 액세스와 결합될 수 있습니다. 사용자 지정 필터 조건과 함께 역할 기반 액세스 제어를 적용하면, 사용자가 역할과 특정 쿼리 기준 모두에 따라 볼 수 있도록 허용된 데이터만 검색하도록 보장할 수 있습니다.
예:
res = client.query(
collection_name="test_collection",
# Sales role queries data with the filter "pk in [1, 3, 5]"
filter='pk in [1, 3, 5] && array_contains(security_group, "sales")',
output_fields=["id", "data", "security_group"],
)
res = client.query(
collection_name="test_collection",
# Developer role queries data with the filter "pk > 10"
filter='pk > 10 && array_contains(security_group, "develop")',
output_fields=["id", "data", "security_group"],
)
이 예시에서 쿼리는 역할 기반 권한을 확인할 뿐만 아니라, 특정 기준에 따라 결과를 좁히기 위해 추가 필터(예: pk in [1, 3, 5] 또는 pk > 10)도 적용합니다. 이러한 유연성 덕분에 사용자는 데이터 액세스를 엄격하게 제어하면서도 매우 정밀한 쿼리를 작성할 수 있습니다.
권한 업데이트
권한을 변경해야 할 때가 있습니다—특정 데이터 행에 대해 특정 역할에 액세스 권한을 부여하거나, 해당 액세스 권한을 제거하는 경우입니다. Milvus는 upsert API를 통해 이 과정을 쉽게 만들어 주며, 이 API를 사용하면 데이터 행과 연결된 권한을 업데이트할 수 있습니다.
이 API를 사용하여 특정 행의 권한을 수정하는 방법을 살펴보겠습니다.
예시: 데이터 행의 권한 업데이트
행의 권한을 업데이트하려면 security_group 필드를 조정하기만 하면 됩니다. 이 예시에서는 이전에 "finance" 역할만 접근할 수 있었던 행에 "sales" 역할을 추가합니다.
upsert_row_update = {
"id": 101,
"vector": upsert_vector,
"data": upsert_data,
# update role
"security_group": ["finance", "sales"]
}
res = client.upsert(
collection_name="test_collection",
data=upsert_row_update)
결과:
upsert 전에는 pk = 101인 행이 다음과 같았습니다:
pk = 101:
data: [" {'id': 101,
'data': 'data63309',
'vector': [0.38069534, 0.15088418, -0.6266929, -0.6038463, 0.2516377...],
'security_group': ['finance'],"]
업서트 후 data: ["{'id': 101, 'data': 'data63309', 'vector': [0.38069534, 0.15088418, -0.6266929, -0.6038463, 0.2516377...], 'security_group': ['finance', 'sales']}"]
`security_group` 배열 컬럼과 비트맵 인덱스 필터링을 사용함으로써, 쿼리 중 권한을 효과적으로 관리할 수 있도록 행 수준 읽기 액세스 제어를 위한 견고한 기반을 마련했습니다. 이 방법은 강력한 성능과 액세스 권한에 대한 세밀한 제어를 제공합니다. 그러나 관리자가 데이터를 삽입하거나 업데이트할 때 권한을 신중하게 관리하고, 테이블을 생성할 때 잘 설계된 권한 전략을 보장해야 하므로 보다 직접적인 접근 방식이 필요합니다.
## 결론
세밀한 액세스 제어를 구현하는 것은 현대 데이터 관리의 핵심 구성 요소이며, 특히 의료 및 금융처럼 민감한 정보를 다루는 산업에서 중요합니다. [Milvus](https://milvus.io/)는 데이터 액세스를 정밀하고 효율적으로 관리하기 위한 강력한 솔루션인 행 수준 RBAC(Role-Based Access Control)를 제공합니다.
이 접근 방식은 보안을 강화할 뿐만 아니라 변화하는 비즈니스 요구 사항에 대한 유연성도 제공하여, 역할과 책임이 변경됨에 따라 액세스 정책이 적응할 수 있도록 보장합니다. 강력한 도구와 유연한 권한 모델을 갖춘 Milvus는 조직이 규제 요구 사항을 충족하면서 적절한 사람들에게 원활한 액세스를 제공하는, 매우 안전하고 확장 가능한 데이터 시스템을 만들 수 있도록 지원합니다.
더욱 동적인 권한 관리와 상속을 위해, Milvus의 완전 관리형 서비스인 [Zilliz Cloud](https://zilliz.com/cloud)는 훨씬 더 세밀한 권한 기능을 제공합니다. 이러한 향상된 기능은 관리 효율성을 개선할 뿐만 아니라 더 큰 유연성을 제공하여, 더 다양한 비즈니스 요구 사항을 보다 쉽게 충족할 수 있게 합니다. Zilliz Cloud RBAC에 대한 자세한 내용은 해당 [문서](https://docs.zilliz.com/docs/access-control)를 확인하세요.
## 추가 자료
- [벡터 데이터베이스란 무엇이며 어떻게 작동하나요? ](https://zilliz.com/learn/what-is-vector-database)
- [Milvus로 AI 앱 구축: 튜토리얼 및 노트북](https://zilliz.com/learn/milvus-notebooks)
- [GenAI 앱을 위한 최고 성능의 AI 모델 | Zilliz](https://zilliz.com/ai-models)
- [생성형 AI 리소스 허브 | Zilliz](https://zilliz.com/learn/generative-ai)
- [데이터 보호: 벡터 데이터베이스 시스템의 보안 및 개인정보 보호](https://zilliz.com/learn/safeguarding-data-security-and-privacy-in-vector-database-systems)
- [Open Source Milvus에서 Zilliz Cloud로 마이그레이션해야 하는 5가지 주요 이유](https://zilliz.com/blog/top-5-reasons-to-migrate-milvus-to-zilliz-cloud)
계속 읽기

Smarter Autoscaling in Zilliz Cloud: Always Optimized for Every Workload
With the latest upgrade, Zilliz Cloud introduces smarter autoscaling—a fully automated, more streamlined, elastic resource management system.

The Great AI Agent Protocol Race: Function Calling vs. MCP vs. A2A
Compare Function Calling, MCP, and A2A protocols for AI agents. Learn which standard best fits your development needs and future-proof your applications.

Building RAG Pipelines for Real-Time Data with Cloudera and Milvus
explore how Cloudera can be integrated with Milvus to effectively implement some of the key functionalities of RAG pipelines.



