-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(stepfunctions-tasks): bedrock createModelCustomizationJob integration #31913
base: main
Are you sure you want to change the base?
Changes from 1 commit
a976a46
79dfc84
3798cb7
8a5d70d
bde1a4f
3aa76b6
dfa9f8c
8686dcc
e5d3e3f
e6d6e37
b661fad
b7a8345
548c706
0351161
a414a5a
c034b66
509203a
83bcf27
9568cba
a4831da
41a0b71
d591952
102067e
fb63238
41370b6
b91224a
f921e0e
caf77fd
5caff6f
3a65136
8b54f06
423dd4b
bd13141
3b035c0
e826b0f
3e141ab
90f4fca
58d8e7d
9368362
46af288
b02a71d
6fee400
293c392
67acafe
ea3c9af
a7aff64
c5fcd41
f33659a
8639c66
377e00c
f07163f
4ba01ba
fd5b087
18e8f23
4d79d75
51e8280
65a0dad
1c68985
22ab29d
066b0d5
7694a20
5647ea2
2ac1f5c
09240f4
3697bf6
c209f7f
baff6fc
ce714e8
684c475
8fa1b48
ac37e8d
0a05f2e
7493c0b
87f8370
068c110
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,10 +47,14 @@ export interface ITag { | |
export interface IBedrockCreateModelCustomizationJobVpcConfig { | ||
/** | ||
* VPC configuration security groups | ||
* | ||
* The maximum number of security groups is 5. | ||
*/ | ||
readonly securityGroups: ec2.ISecurityGroup[]; | ||
/** | ||
* VPC configuration subnets | ||
* | ||
* The maximum number of subnets is 16. | ||
*/ | ||
readonly subnets: ec2.ISubnet[]; | ||
} | ||
|
@@ -63,37 +67,48 @@ export interface BedrockCreateModelCustomizationJobProps extends sfn.TaskStateBa | |
* The base model. | ||
*/ | ||
readonly baseModel: bedrock.IModel; | ||
|
||
/** | ||
* A unique, case-sensitive identifier to ensure that the API request completes no more than one time. | ||
* If this token matches a previous request, Amazon Bedrock ignores the request, but does not return an error. | ||
* | ||
* The maximum length is 256 characters and it needs to satisfy the regular expression ^[a-zA-Z0-9](-*[a-zA-Z0-9])*$. | ||
* @see https://docs.aws.amazon.com/AWSEC2/latest/APIReference/Run_Instance_Idempotency.html | ||
* | ||
* @default - no client request token | ||
*/ | ||
readonly clientRequestToken?: string; | ||
|
||
/** | ||
* The customization type. | ||
* | ||
* @default FINE_TUNING | ||
*/ | ||
readonly customizationType?: CustomizationType; | ||
|
||
/** | ||
* The custom model is encrypted at rest using this key. | ||
* | ||
* @default - no encryption | ||
*/ | ||
readonly kmsKey?: kms.IKey; | ||
readonly customModelKmsKey?: kms.IKey; | ||
|
||
/** | ||
* A name for the resulting custom model. | ||
* | ||
* The maximum length is 63 characters and it needs to satisfy the regular expression ^([0-9a-zA-Z][_-]?)+$. | ||
*/ | ||
readonly customModelName: string; | ||
|
||
/** | ||
* Tags to attach to the resulting custom model. | ||
* | ||
* The maximum number of tags is 200. | ||
* | ||
* @default - no tags | ||
*/ | ||
readonly customModelTags?: ITag[]; | ||
|
||
/** | ||
* Parameters related to tuning the model. | ||
* | ||
|
@@ -102,44 +117,56 @@ export interface BedrockCreateModelCustomizationJobProps extends sfn.TaskStateBa | |
* @default - use default hyperparameters | ||
*/ | ||
readonly hyperParameters?: { [key: string]: string }; | ||
|
||
/** | ||
* A name for the fine-tuning job. | ||
* | ||
* The maximum length is 63 characters and it needs to satisfy the regular expression ^[a-zA-Z0-9](-*[a-zA-Z0-9\+\-\.])*$. | ||
*/ | ||
readonly jobName: string; | ||
|
||
/** | ||
* Tags to attach to the job. | ||
* The maximum number of tags is 200. | ||
* | ||
* @default - no tags | ||
*/ | ||
readonly jobTags?: ITag[]; | ||
|
||
/** | ||
* The S3 URI where the output data is stored. | ||
* | ||
* @see https://docs.aws.amazon.com/bedrock/latest/APIReference/API_OutputDataConfig.html | ||
*/ | ||
readonly outputDataS3Uri: string; | ||
|
||
/** | ||
* The IAM role that Amazon Bedrock can assume to perform tasks on your behalf. | ||
* | ||
* For example, during model training, Amazon Bedrock needs your permission to read input data from an S3 bucket, | ||
* write model artifacts to an S3 bucket. | ||
* To pass this role to Amazon Bedrock, the caller of this API must have the iam:PassRole permission. | ||
* | ||
* @default - use auto generated role | ||
*/ | ||
readonly role?: iam.IRole; | ||
|
||
/** | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While I like the simplified To avoid making breaking changes in the future in case new sub-properties are added, can we make a base interface |
||
* The S3 URI where the training data is stored. | ||
* | ||
* @see https://docs.aws.amazon.com/bedrock/latest/APIReference/API_TrainingDataConfig.html | ||
*/ | ||
readonly trainingDataS3Uri: string; | ||
|
||
/** | ||
* The S3 URI where the validation data is stored. | ||
* | ||
* The maximum number of validation data S3 URIs is 10. | ||
* | ||
* @see https://docs.aws.amazon.com/bedrock/latest/APIReference/API_Validator.html | ||
*/ | ||
readonly validationDataS3Uri: string[]; | ||
/** | ||
* The IAM role that Amazon Bedrock can assume to perform tasks on your behalf. | ||
* | ||
* For example, during model training, Amazon Bedrock needs your permission to read input data from an S3 bucket, | ||
* write model artifacts to an S3 bucket. | ||
* To pass this role to Amazon Bedrock, the caller of this API must have the iam:PassRole permission. | ||
* | ||
* @default - use auto generated role | ||
*/ | ||
readonly role?: iam.IRole; | ||
|
||
/** | ||
* Configuration parameters for the private Virtual Private Cloud (VPC) that contains the resources you are using for this job. | ||
* | ||
|
@@ -158,8 +185,8 @@ export class BedrockCreateModelCustomizationJob extends sfn.TaskStateBase { | |
sfn.IntegrationPattern.RUN_JOB, | ||
]; | ||
|
||
protected readonly taskMetrics: sfn.TaskMetricsConfig | undefined; | ||
protected readonly taskPolicies: iam.PolicyStatement[] | undefined; | ||
protected readonly taskMetrics?: sfn.TaskMetricsConfig; | ||
protected readonly taskPolicies?: iam.PolicyStatement[]; | ||
|
||
private readonly integrationPattern: sfn.IntegrationPattern; | ||
private _role: iam.IRole; | ||
|
@@ -193,6 +220,11 @@ export class BedrockCreateModelCustomizationJob extends sfn.TaskStateBase { | |
return this._role; | ||
} | ||
|
||
/** | ||
* Configure the IAM role for the bedrock create model customization job | ||
* | ||
* @see https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-code-samples.html | ||
*/ | ||
private renderBedrockCreateModelCustomizationJobRole(): iam.IRole { | ||
if (this.props.role) { | ||
return this.props.role; | ||
|
@@ -214,57 +246,57 @@ export class BedrockCreateModelCustomizationJob extends sfn.TaskStateBase { | |
], | ||
resources: ['*'], | ||
}), | ||
] : []), | ||
new iam.PolicyStatement({ | ||
actions: ['ec2:CreateNetworkInterface'], | ||
resources: [ | ||
stack.formatArn({ | ||
new iam.PolicyStatement({ | ||
actions: ['ec2:CreateNetworkInterface'], | ||
resources: [ | ||
stack.formatArn({ | ||
service: 'ec2', | ||
resource: 'network-interface', | ||
resourceName: '*', | ||
}), | ||
stack.formatArn({ | ||
service: 'ec2', | ||
resource: 'security-group', | ||
resourceName: '*', | ||
}), | ||
stack.formatArn({ | ||
service: 'ec2', | ||
resource: 'subnet', | ||
resourceName: '*', | ||
}), | ||
], | ||
}), | ||
new iam.PolicyStatement({ | ||
actions: ['ec2:CreateTags'], | ||
resources: [stack.formatArn({ | ||
service: 'ec2', | ||
resource: 'network-interface', | ||
resourceName: '*', | ||
}), | ||
stack.formatArn({ | ||
service: 'ec2', | ||
resource: 'security-group', | ||
resourceName: '*', | ||
}), | ||
stack.formatArn({ | ||
service: 'ec2', | ||
resource: 'subnet', | ||
resourceName: '*', | ||
}), | ||
], | ||
}), | ||
new iam.PolicyStatement({ | ||
actions: ['ec2:CreateTags'], | ||
resources: [stack.formatArn({ | ||
service: 'ec2', | ||
resource: 'network-interface', | ||
resourceName: '*', | ||
})], | ||
conditions: { | ||
StringEquals: { | ||
'ec2:CreateAction': 'CreateNetworkInterface', | ||
})], | ||
conditions: { | ||
StringEquals: { | ||
'ec2:CreateAction': 'CreateNetworkInterface', | ||
}, | ||
}, | ||
}, | ||
}), | ||
new iam.PolicyStatement({ | ||
actions: [ | ||
'ec2:CreateNetworkInterfacePermission', | ||
'ec2:DeleteNetworkInterface', | ||
'ec2:DeleteNetworkInterfacePermission', | ||
], | ||
resources: ['*'], | ||
conditions: { | ||
StringEquals: { | ||
'ec2:Subnet': [ | ||
...(this.props.vpcConfig | ||
? this.props.vpcConfig.subnets.map((subnet) => subnet.subnetId) | ||
: []), | ||
], | ||
}), | ||
new iam.PolicyStatement({ | ||
actions: [ | ||
'ec2:CreateNetworkInterfacePermission', | ||
'ec2:DeleteNetworkInterface', | ||
'ec2:DeleteNetworkInterfacePermission', | ||
], | ||
resources: ['*'], | ||
conditions: { | ||
StringEquals: { | ||
'ec2:Subnet': [ | ||
...(this.props.vpcConfig | ||
? this.props.vpcConfig.subnets.map((subnet) => subnet.subnetId) | ||
: []), | ||
], | ||
}, | ||
}, | ||
}, | ||
}), | ||
}), | ||
] : []), | ||
new iam.PolicyStatement({ | ||
actions: ['s3:GetObject'], | ||
resources: [ | ||
|
@@ -309,12 +341,12 @@ export class BedrockCreateModelCustomizationJob extends sfn.TaskStateBase { | |
actions: ['iam:PassRole'], | ||
resources: [this._role.roleArn], | ||
}), | ||
...(this.props.kmsKey | ||
...(this.props.customModelKmsKey | ||
? [ | ||
new iam.PolicyStatement({ | ||
// TODO - this should be more specific | ||
actions: ['kms:*'], | ||
resources: [this.props.kmsKey.keyArn], | ||
resources: [this.props.customModelKmsKey.keyArn], | ||
}), | ||
] | ||
: []), | ||
|
@@ -324,19 +356,19 @@ export class BedrockCreateModelCustomizationJob extends sfn.TaskStateBase { | |
|
||
private validateStringLength(name: string, min: number, max: number, value?: string): void { | ||
if (value !== undefined && !Token.isUnresolved(value) && (value.length < min || value.length > max)) { | ||
throw new Error(`${name} must be between ${min} and ${max} characters long`); | ||
throw new Error(`${name} must be between ${min} and ${max} characters long, got: ${value.length}`); | ||
} | ||
} | ||
|
||
private validatePattern(name: string, pattern: RegExp, value?: string): void { | ||
if (value !== undefined && !Token.isUnresolved(value) && !pattern.test(value)) { | ||
Check failure Code scanning / CodeQL Polynomial regular expression used on uncontrolled data High
This
regular expression Error loading related location Loading library input Error loading related location Loading |
||
throw new Error(`${name} must match the pattern ${pattern.toString()}`); | ||
throw new Error(`${name} must match the pattern ${pattern.toString()}, got: ${value}`); | ||
} | ||
} | ||
|
||
private validateArrayLength(name: string, min: number, max: number, value?: any[]): void { | ||
if (value !== undefined && (value.length < min || value.length > max)) { | ||
throw new Error(`${name} must be between ${min} and ${max} items long`); | ||
throw new Error(`${name} must be between ${min} and ${max} items long, got: ${value.length}`); | ||
} | ||
} | ||
|
||
|
@@ -370,7 +402,7 @@ export class BedrockCreateModelCustomizationJob extends sfn.TaskStateBase { | |
BaseModelIdentifier: this.props.baseModel.modelArn, | ||
ClientRequestToken: this.props.clientRequestToken, | ||
CustomizationType: this.props.customizationType, | ||
CustomModelKmsKeyId: this.props.kmsKey?.keyArn, | ||
CustomModelKmsKeyId: this.props.customModelKmsKey?.keyArn, | ||
CustomModelName: this.props.customModelName, | ||
CustomModelTags: this.props.customModelTags?.map((tag) => ({ Key: tag.key, Value: tag.value })), | ||
HyperParameters: this.props.hyperParameters, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from the linked docs,
By default, Amazon Bedrock encrypts custom models with AWS owned keys.
- can we specify that as the default here?