使用IAM Policy指定IP范围以限制用户对Bedrock服务的调用

一、背景

由于中美贸易战纠纷,一些高科技领域存在黑名单,禁止中国(含香港)地区的用户使用美国开发商的技术和服务。在这种政策要求下,作为业界最前沿的领先的2个大语言模型的供应商 OpenAI(ChatGPT)和 Anthropic(Claude)均宣布不向中国地区用户提供服务。同时,AWS Bedrock上的Claude模型,也需要遵循监管规则,即模型使用者必须是海外用户,包括AWS账户注册的联络地址、账单地址都必须在海外,这些地址不能是中国大陆、也不能是香港,但可以是新加坡。如果是存在Partner代付的场景,Partner也必须满足以上标准。

在以上背景下,海外应用使用Anthropic Claude模型是完全合规的,即模型使用者是在海外,应用代码部署位置也是在海外,处理的信息也是海外用户信息。虽然如此,由于大部分互联网公司的开发团队在国内,开发者经常会在本机使用国内网络直接调用Bedrock上的Claude服务进行开发测试。这种情况下,调用Bedrock Claude服务的来源IP依然是中国地区的IP,此时可能会存在不合规的情况。这种不合规场景有可能会导致账号异常。

为了避免这种不合规场景,可找到调用Bedrock服务的AKSK所对应的IAM User,在这个IAM User上增加对应的IAM Policy,以白名单方式只允许海外特定IP的请求,并拒绝来自其他地区(含中国区)的请求,避免不合规的调用。

二、IAM Policy配置

找到调用Bedrock服务的AKSK所对应的IAM User,查看现有的Policy哪一条是为Bedrock进行赋权的,找到这条规则,在下方增加Condition这一段信息,并且可配置CIDR的地址段来设置允许访问的访问。

在以下配置样例中,只有白名单授权的CIDR可以访问Bedrock,其他来源IP地址会被拒绝。在实际生产环境中,可以把这个IP地址范围替换为海外的应用系统实际部署的出口地址。例如生产环境的VPC出口是NAT Gateway,那么可以把策略中的IP地址改成NAT Gateway的EIP地址。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "bedrock:InvokeModel",
                "bedrock:InvokeModelWithResponseStream"
            ],
            "Resource": "arn:aws:bedrock:*::foundation-model/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "13.230.101.201/32",
                        "13.230.101.202/32"
                    ]
                }
            }
        }
    ]
}

修改IAM Policy并且Attach到IAM User后,保存配置即可立刻生效。由于规则立刻生效,建议修改现有生产环境前,现在测试环境进行充分测试,以免规则配置错误,造成所有应用都无法连接Bedrock服务。尤其是不要对IP地址写*规则,这样可能会导致所有IAM User对应的AKSK都不能连接,造成重大故障。因此编写规则一定按照如下的Policy例子,分别配置ActionResourceCondition几个字短,不要草率的用*通配符导致误拦截。

三、测试代码

编写如下Python代码测试。为了方便测试IAM Policy是否生效,可以在代码中直接显式的指定使用某个特定IAM User的AKSK,这样可直接测试新编写的IAM Policy是否生效。测试通过后,建议还是通过配置文件来指定AKSK,而不是在程序中硬编码。

import boto3
import json

region_name = 'us-west-2'
model_id = 'anthropic.claude-3-haiku-20240307-v1:0'

message_text = "Write an email from Bob, Customer Service Manager, to the customer \"John Doe\" who provided negative feedback on the service provided by our customer support engineer. Limit to 100 words."
system_prompt = [
        { "text": "Please respond to all requests in the style of a professional service desk." }
    ]

#session = boto3.Session(region_name=region_name)
session = boto3.Session(
    aws_access_key_id='xxxxxxxxxxxxxxxx',
    aws_secret_access_key='xxxxxxxxxxxx',
    region_name='us-west-2'
    )
bedrock = session.client(service_name="bedrock-runtime")

message_list = []
initial_message = {
    "role": "user",
    "content": [
        { "text": message_text } 
    ],
}
message_list.append(initial_message)

response = bedrock.converse(
    modelId = model_id,
    system = system_prompt ,
    messages = message_list ,
    inferenceConfig={
        "maxTokens": 2000,
        "temperature": 0
    },
)

# Only get content from response
response_message = response['output']['message']['content'][0]['text']
print(response_message)

# Print token usage
print("\n\n--- Token usage ---")
print("Usage:", json.dumps(response['usage'], indent=4))

运行以上代码。当运行代码的客户端出口公网地址不是IAM Policy中授权的地址,就会获得如下错误:

botocore.errorfactory.AccessDeniedException: An error occurred (AccessDeniedException) when calling the Converse operation: User: arn
:aws:iam::123456789012:user/bedrock-api is not authorized to perform: bedrock:InvokeModel on resource: arn:aws:bedrock:
us-west-2::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0 because no identity-based policy allows the bedrock:InvokeModel
 action

这表示当前IAM Policy没有正确的权限,拒绝了Bedrock调用。

由此规则配置完成。