使用RAG实现数据访问授权的深度解析

本文详细介绍了如何为RAG架构实现强授权机制,通过Amazon S3 Access Grants与Bedrock知识库的集成,确保生成式AI应用仅返回用户有权访问的数据内容,解决了向量数据库权限同步和复杂身份权限管理的挑战。

使用RAG实现数据访问授权 | AWS安全博客

组织越来越多地使用大型语言模型(LLMs)通过生成式AI驱动的聊天机器人、虚拟助手和智能搜索功能来提供新型客户互动。为了增强这些互动,组织正在使用检索增强生成(RAG)来整合专有数据、行业特定知识和内部文档,以提供更准确、更具上下文相关性的响应。

RAG使用概述

RAG架构与搜索引擎有相似之处,但在数据访问方法上存在关键差异。搜索引擎提供信息源链接,要求用户基于其权限直接访问原始数据源。而RAG实现直接从LLM返回向量数据库结果,绕过了原始数据源的权限检查。

虽然元数据过滤可以帮助控制访问,但它面临两个关键挑战:首先,向量数据库仅定期同步,意味着源数据中的权限更改不会立即反映;其次,复杂的身份权限(主体可能属于数百个组)使得准确过滤结果变得困难。

解决方案概述:S3访问授权与Bedrock知识库

本示例展示了使用Amazon S3 Access Grants与Amazon Bedrock知识库的授权架构模式。组织内有多个团队(市场营销、销售、人力资源和IT),每个主体将有权访问其相应的项目或部门文件夹。

应用流程

  1. 用户使用其身份提供商(IdP)登录生成式AI应用
  2. 生成式AI应用与IAM Identity Center交换令牌并代表用户担任角色
  3. 生成式AI应用调用S3 Access Grants获取用户有权访问的授权列表
  4. 用户向生成式AI应用发送查询
  5. 生成式AI应用向知识库发送查询
  6. 生成式AI应用根据用户授权范围审查知识库返回的数据块
  7. 仅用户有权访问的范围才会传递给LLM生成响应

代码实现

步骤1:担任S3访问角色

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def assume_role(client_id, grant_type, client_assertion, role_arn, role_session_name, provider_arn):
    client_oidc = boto3.client('sso-oidc')
    client_sts = boto3.client('sts')
    
    token_response = client_oidc.create_token_with_iam(
        clientId=client_id,
        grantType=grant_type,
        assertion=client_assertion
    )
    
    id_token = jwt.decode(token_response['idToken'], options={'verify_signature': False})
    identity_context = id_token['sts:identity_context']
    
    temp_credentials = client_sts.assume_role(
        RoleArn=role_arn,
        RoleSessionName=role_session_name,
        ProvidedContexts=[{
            'ProviderArn': provider_arn,
            'ContextAssertion': identity_context
        }]
    )
    
    creds = temp_credentials['Credentials']
    return boto3.client(
        's3control',
        region_name='us-west-2',
        aws_access_key_id=creds['AccessKeyId'],
        aws_secret_access_key=creds['SecretAccessKey'],
        aws_session_token=creds['SessionToken']
    )

步骤2:获取调用者授权范围

1
2
3
4
5
6
7
8
def get_caller_grant_scopes(client, account):
    try:
        response = client.list_caller_access_grants(AccountId=account)
        scopes = [grant['GrantScope'].replace('*','') for grant in response['CallerAccessGrantsList']]
        return scopes
    except ClientError as e:
        print(f'Error: {e}')
        sys.exit(1)

步骤3:检查调用者授权范围

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
def check_grant_scopes(chunks, scopes):
    authorized = []
    not_authorized = []
    
    if not scopes:
        return [], chunks
    
    for chunk in chunks:
        location = chunk['location']
        authorized_scope = next((scope for scope in scopes if location.startswith(scope)), None)
        
        if authorized_scope:
            chunk['scope'] = authorized_scope
            authorized.append(chunk)
        else:
            not_authorized.append(chunk)
    
    return authorized, not_authorized

解决方案考虑因素

实施此RAG实现授权架构时,需要理解几个影响安全性、性能和可扩展性的关键考虑因素:

  • 此架构可用于您选择的数据源,前提是知识库返回数据源的URI,并且有API可以调用以验证主体有权访问的内容
  • S3 Access Grants提供主体访问数据源的授权,可以通过添加键/值标签或数据源对每个存储桶应用额外的访问控制策略
  • 授权范围列表可能会变得过时,需要决定刷新授权范围列表的频率
  • 根据主体有权访问的数据块和知识库返回的内容,在发送到LLM之前可能会丢弃某些数据块

结论

本文展示了为知识库返回结果提供强授权的架构模式,讲解了强授权的重要性以及如何使用Amazon S3 Access Grants实现授权,并通过代码示例演示了Amazon Bedrock知识库与S3 Access Grants的实际工作方式。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计