Skip to content

Commit c39f6bc

Browse files
committed
Use secrets manager for api key
1 parent 74ca3b9 commit c39f6bc

File tree

4 files changed

+304
-11
lines changed

4 files changed

+304
-11
lines changed

deployment/BedrockProxy.template

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
Description: Bedrock Access Gateway - OpenAI-compatible RESTful APIs for Amazon Bedrock
2+
Parameters:
3+
ApiKeySecretArn:
4+
Type: String
5+
AllowedPattern: ^arn:aws:secretsmanager:.*$
6+
Description: The secret ARN in Secrets Manager used to store the API Key
7+
DefaultModelId:
8+
Type: String
9+
Default: anthropic.claude-3-sonnet-20240229-v1:0
10+
Description: The default model ID, please make sure the model ID is supported in the current region
11+
Resources:
12+
VPCB9E5F0B4:
13+
Type: AWS::EC2::VPC
14+
Properties:
15+
CidrBlock: 10.250.0.0/16
16+
EnableDnsHostnames: true
17+
EnableDnsSupport: true
18+
InstanceTenancy: default
19+
Tags:
20+
- Key: Name
21+
Value: BedrockProxy/VPC
22+
VPCPublicSubnet1SubnetB4246D30:
23+
Type: AWS::EC2::Subnet
24+
Properties:
25+
AvailabilityZone:
26+
Fn::Select:
27+
- 0
28+
- Fn::GetAZs: ""
29+
CidrBlock: 10.250.0.0/24
30+
MapPublicIpOnLaunch: true
31+
Tags:
32+
- Key: aws-cdk:subnet-name
33+
Value: Public
34+
- Key: aws-cdk:subnet-type
35+
Value: Public
36+
- Key: Name
37+
Value: BedrockProxy/VPC/PublicSubnet1
38+
VpcId:
39+
Ref: VPCB9E5F0B4
40+
VPCPublicSubnet1RouteTableFEE4B781:
41+
Type: AWS::EC2::RouteTable
42+
Properties:
43+
Tags:
44+
- Key: Name
45+
Value: BedrockProxy/VPC/PublicSubnet1
46+
VpcId:
47+
Ref: VPCB9E5F0B4
48+
VPCPublicSubnet1RouteTableAssociation0B0896DC:
49+
Type: AWS::EC2::SubnetRouteTableAssociation
50+
Properties:
51+
RouteTableId:
52+
Ref: VPCPublicSubnet1RouteTableFEE4B781
53+
SubnetId:
54+
Ref: VPCPublicSubnet1SubnetB4246D30
55+
VPCPublicSubnet1DefaultRoute91CEF279:
56+
Type: AWS::EC2::Route
57+
Properties:
58+
DestinationCidrBlock: 0.0.0.0/0
59+
GatewayId:
60+
Ref: VPCIGWB7E252D3
61+
RouteTableId:
62+
Ref: VPCPublicSubnet1RouteTableFEE4B781
63+
DependsOn:
64+
- VPCVPCGW99B986DC
65+
VPCPublicSubnet2Subnet74179F39:
66+
Type: AWS::EC2::Subnet
67+
Properties:
68+
AvailabilityZone:
69+
Fn::Select:
70+
- 1
71+
- Fn::GetAZs: ""
72+
CidrBlock: 10.250.1.0/24
73+
MapPublicIpOnLaunch: true
74+
Tags:
75+
- Key: aws-cdk:subnet-name
76+
Value: Public
77+
- Key: aws-cdk:subnet-type
78+
Value: Public
79+
- Key: Name
80+
Value: BedrockProxy/VPC/PublicSubnet2
81+
VpcId:
82+
Ref: VPCB9E5F0B4
83+
VPCPublicSubnet2RouteTable6F1A15F1:
84+
Type: AWS::EC2::RouteTable
85+
Properties:
86+
Tags:
87+
- Key: Name
88+
Value: BedrockProxy/VPC/PublicSubnet2
89+
VpcId:
90+
Ref: VPCB9E5F0B4
91+
VPCPublicSubnet2RouteTableAssociation5A808732:
92+
Type: AWS::EC2::SubnetRouteTableAssociation
93+
Properties:
94+
RouteTableId:
95+
Ref: VPCPublicSubnet2RouteTable6F1A15F1
96+
SubnetId:
97+
Ref: VPCPublicSubnet2Subnet74179F39
98+
VPCPublicSubnet2DefaultRouteB7481BBA:
99+
Type: AWS::EC2::Route
100+
Properties:
101+
DestinationCidrBlock: 0.0.0.0/0
102+
GatewayId:
103+
Ref: VPCIGWB7E252D3
104+
RouteTableId:
105+
Ref: VPCPublicSubnet2RouteTable6F1A15F1
106+
DependsOn:
107+
- VPCVPCGW99B986DC
108+
VPCIGWB7E252D3:
109+
Type: AWS::EC2::InternetGateway
110+
Properties:
111+
Tags:
112+
- Key: Name
113+
Value: BedrockProxy/VPC
114+
VPCVPCGW99B986DC:
115+
Type: AWS::EC2::VPCGatewayAttachment
116+
Properties:
117+
InternetGatewayId:
118+
Ref: VPCIGWB7E252D3
119+
VpcId:
120+
Ref: VPCB9E5F0B4
121+
ProxyApiHandlerServiceRoleBE71BFB1:
122+
Type: AWS::IAM::Role
123+
Properties:
124+
AssumeRolePolicyDocument:
125+
Statement:
126+
- Action: sts:AssumeRole
127+
Effect: Allow
128+
Principal:
129+
Service: lambda.amazonaws.com
130+
Version: "2012-10-17"
131+
ManagedPolicyArns:
132+
- Fn::Join:
133+
- ""
134+
- - "arn:"
135+
- Ref: AWS::Partition
136+
- :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
137+
ProxyApiHandlerServiceRoleDefaultPolicy86681202:
138+
Type: AWS::IAM::Policy
139+
Properties:
140+
PolicyDocument:
141+
Statement:
142+
- Action:
143+
- bedrock:ListFoundationModels
144+
- bedrock:ListInferenceProfiles
145+
Effect: Allow
146+
Resource: "*"
147+
- Action:
148+
- bedrock:InvokeModel
149+
- bedrock:InvokeModelWithResponseStream
150+
Effect: Allow
151+
Resource:
152+
- arn:aws:bedrock:*::foundation-model/*
153+
- arn:aws:bedrock:*:*:inference-profile/*
154+
- Action:
155+
- secretsmanager:GetSecretValue
156+
- secretsmanager:DescribeSecret
157+
Effect: Allow
158+
Resource:
159+
Ref: ApiKeySecretArn
160+
Version: "2012-10-17"
161+
PolicyName: ProxyApiHandlerServiceRoleDefaultPolicy86681202
162+
Roles:
163+
- Ref: ProxyApiHandlerServiceRoleBE71BFB1
164+
ProxyApiHandlerEC15A492:
165+
Type: AWS::Lambda::Function
166+
Properties:
167+
Architectures:
168+
- arm64
169+
Code:
170+
ImageUri:
171+
Fn::Join:
172+
- ""
173+
- - 366590864501.dkr.ecr.
174+
- Ref: AWS::Region
175+
- "."
176+
- Ref: AWS::URLSuffix
177+
- /bedrock-proxy-api:latest
178+
Description: Bedrock Proxy API Handler
179+
Environment:
180+
Variables:
181+
DEBUG: "false"
182+
API_KEY_SECRET_ARN:
183+
Ref: ApiKeySecretArn
184+
DEFAULT_MODEL:
185+
Ref: DefaultModelId
186+
DEFAULT_EMBEDDING_MODEL: cohere.embed-multilingual-v3
187+
ENABLE_CROSS_REGION_INFERENCE: "true"
188+
MemorySize: 1024
189+
PackageType: Image
190+
Role:
191+
Fn::GetAtt:
192+
- ProxyApiHandlerServiceRoleBE71BFB1
193+
- Arn
194+
Timeout: 600
195+
DependsOn:
196+
- ProxyApiHandlerServiceRoleDefaultPolicy86681202
197+
- ProxyApiHandlerServiceRoleBE71BFB1
198+
ProxyApiHandlerInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HYF6C33779:
199+
Type: AWS::Lambda::Permission
200+
Properties:
201+
Action: lambda:InvokeFunction
202+
FunctionName:
203+
Fn::GetAtt:
204+
- ProxyApiHandlerEC15A492
205+
- Arn
206+
Principal: elasticloadbalancing.amazonaws.com
207+
ProxyALB87756780:
208+
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
209+
Properties:
210+
LoadBalancerAttributes:
211+
- Key: deletion_protection.enabled
212+
Value: "false"
213+
Scheme: internet-facing
214+
SecurityGroups:
215+
- Fn::GetAtt:
216+
- ProxyALBSecurityGroup0D6CA3DA
217+
- GroupId
218+
Subnets:
219+
- Ref: VPCPublicSubnet1SubnetB4246D30
220+
- Ref: VPCPublicSubnet2Subnet74179F39
221+
Type: application
222+
DependsOn:
223+
- VPCPublicSubnet1DefaultRoute91CEF279
224+
- VPCPublicSubnet1RouteTableAssociation0B0896DC
225+
- VPCPublicSubnet2DefaultRouteB7481BBA
226+
- VPCPublicSubnet2RouteTableAssociation5A808732
227+
ProxyALBSecurityGroup0D6CA3DA:
228+
Type: AWS::EC2::SecurityGroup
229+
Properties:
230+
GroupDescription: Automatically created Security Group for ELB BedrockProxyALB1CE4CAD1
231+
SecurityGroupEgress:
232+
- CidrIp: 255.255.255.255/32
233+
Description: Disallow all traffic
234+
FromPort: 252
235+
IpProtocol: icmp
236+
ToPort: 86
237+
SecurityGroupIngress:
238+
- CidrIp: 0.0.0.0/0
239+
Description: Allow from anyone on port 80
240+
FromPort: 80
241+
IpProtocol: tcp
242+
ToPort: 80
243+
VpcId:
244+
Ref: VPCB9E5F0B4
245+
ProxyALBListener933E9515:
246+
Type: AWS::ElasticLoadBalancingV2::Listener
247+
Properties:
248+
DefaultActions:
249+
- TargetGroupArn:
250+
Ref: ProxyALBListenerTargetsGroup187739FA
251+
Type: forward
252+
LoadBalancerArn:
253+
Ref: ProxyALB87756780
254+
Port: 80
255+
Protocol: HTTP
256+
ProxyALBListenerTargetsGroup187739FA:
257+
Type: AWS::ElasticLoadBalancingV2::TargetGroup
258+
Properties:
259+
HealthCheckEnabled: false
260+
TargetType: lambda
261+
Targets:
262+
- Id:
263+
Fn::GetAtt:
264+
- ProxyApiHandlerEC15A492
265+
- Arn
266+
DependsOn:
267+
- ProxyApiHandlerInvoke2UTWxhlfyqbT5FTn5jvgbLgjFfJwzswGk55DU1HYF6C33779
268+
Outputs:
269+
APIBaseUrl:
270+
Description: Proxy API Base URL (OPENAI_API_BASE)
271+
Value:
272+
Fn::Join:
273+
- ""
274+
- - http://
275+
- Fn::GetAtt:
276+
- ProxyALB87756780
277+
- DNSName
278+
- /api/v1
279+

deployment/BedrockProxyFargate.template

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
Description: Bedrock Access Gateway - OpenAI-compatible RESTful APIs for Amazon Bedrock
2-
Transform: AWS::LanguageExtensions
32
Parameters:
43
ApiKeySecretArn:
54
Type: String
65
AllowedPattern: ^arn:aws:secretsmanager:.*$
76
Description: The secret ARN in Secrets Manager used to store the API Key
7+
DefaultModelId:
8+
Type: String
9+
Default: anthropic.claude-3-sonnet-20240229-v1:0
10+
Description: The default model ID, please make sure the model ID is supported in the current region
811
Resources:
912
VPCB9E5F0B4:
1013
Type: AWS::EC2::VPC
@@ -214,11 +217,7 @@ Resources:
214217
Value: "false"
215218
- Name: DEFAULT_MODEL
216219
Value:
217-
Fn::FindInMap:
218-
- ProxyRegionTable03E5BEB3
219-
- Ref: AWS::Region
220-
- model
221-
- DefaultValue: anthropic.claude-3-sonnet-20240229-v1:0
220+
Ref: DefaultModelId
222221
- Name: DEFAULT_EMBEDDING_MODEL
223222
Value: cohere.embed-multilingual-v3
224223
- Name: ENABLE_CROSS_REGION_INFERENCE
@@ -407,10 +406,6 @@ Resources:
407406
TargetType: ip
408407
VpcId:
409408
Ref: VPCB9E5F0B4
410-
Mappings:
411-
ProxyRegionTable03E5BEB3:
412-
us-east-1:
413-
model: anthropic.claude-3-sonnet-20240229-v1:0
414409
Outputs:
415410
APIBaseUrl:
416411
Description: Proxy API Base URL (OPENAI_API_BASE)

src/api/auth.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,41 @@
1+
import json
12
import os
23
from typing import Annotated
34

45
import boto3
6+
from botocore.exceptions import ClientError
57
from fastapi import Depends, HTTPException, status
68
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
79

810
from api.setting import DEFAULT_API_KEYS
911

1012
api_key_param = os.environ.get("API_KEY_PARAM_NAME")
13+
api_key_secret_arn = os.environ.get("API_KEY_SECRET_ARN")
1114
api_key_env = os.environ.get("API_KEY")
1215
if api_key_param:
16+
# For backward compatibility.
17+
# Please now use secrets manager instead.
1318
ssm = boto3.client("ssm")
1419
api_key = ssm.get_parameter(Name=api_key_param, WithDecryption=True)["Parameter"][
1520
"Value"
1621
]
22+
elif api_key_secret_arn:
23+
sm = boto3.client("secretsmanager")
24+
try:
25+
response = sm.get_secret_value(SecretId=api_key_secret_arn)
26+
if "SecretString" in response:
27+
secret = json.loads(response["SecretString"])
28+
api_key = secret["api_key"]
29+
except ClientError as e:
30+
raise RuntimeError(
31+
"Unable to retrieve API KEY, please ensure the secret ARN is correct"
32+
)
33+
except KeyError as e:
34+
raise RuntimeError('Please ensure the secret contains a "api_key" field')
1735
elif api_key_env:
1836
api_key = api_key_env
1937
else:
38+
# For local use only.
2039
api_key = DEFAULT_API_KEYS
2140

2241
security = HTTPBearer()

src/api/models/bedrock.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def list_bedrock_models() -> dict:
105105
status = model['modelLifecycle'].get('status', 'ACTIVE')
106106

107107
# currently, use this to filter out rerank models and legacy models
108-
if not stream_supported or status != "ACTIVE":
108+
if not stream_supported or status not in ["ACTIVE", "LEGACY"]:
109109
continue
110110

111111
inference_types = model.get('inferenceTypesSupported', [])

0 commit comments

Comments
 (0)