-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
feat(sagemaker): add processing and transform job volume CMK checks #12802
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
8361581
e9e6540
91abda3
9c8960e
d768596
0f6ae12
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 |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| `sagemaker_processing_job_volume_encrypted_with_cmk` checks that every SageMaker processing job encrypts its ML storage volume with a customer-managed KMS key (`ProcessingResources.ClusterConfig.VolumeKmsKeyId`), and reports MANUAL when the job details cannot be described | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| `sagemaker_transform_job_volume_encrypted_with_cmk` checks that every SageMaker transform job encrypts its ML storage volume with a customer-managed KMS key (`TransformResources.VolumeKmsKeyId`), and reports MANUAL when the job details cannot be described | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| { | ||
| "Provider": "aws", | ||
| "CheckID": "sagemaker_processing_job_volume_encrypted_with_cmk", | ||
| "CheckTitle": "SageMaker processing job volumes use customer-managed KMS keys", | ||
| "CheckType": [ | ||
| "Software and Configuration Checks/AWS Security Best Practices", | ||
| "Effects/Data Exposure" | ||
| ], | ||
| "ServiceName": "sagemaker", | ||
| "SubServiceName": "", | ||
| "ResourceIdTemplate": "", | ||
| "Severity": "high", | ||
| "ResourceType": "Other", | ||
| "ResourceGroup": "ai_ml", | ||
| "Description": "**Amazon SageMaker processing jobs** are assessed for **at-rest encryption** of their attached ML storage volumes using a **customer-managed KMS key**. The finding reflects whether `ProcessingResources.ClusterConfig.VolumeKmsKeyId` is set on the job.", | ||
| "Risk": "A processing job without `VolumeKmsKeyId` falls back to an **AWS managed key**, which cannot carry a custom key policy and whose **rotation**, **access** and **lifecycle** are outside the account owner's control. Intermediate processing data on the volume then cannot be independently revoked, and grants to that data cannot be audited or restricted through a key policy.", | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| "RelatedUrl": "", | ||
| "AdditionalURLs": [ | ||
| "https://docs.aws.amazon.com/sagemaker/latest/dg/key-management.html", | ||
| "https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_DescribeProcessingJob.html", | ||
| "https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_ProcessingClusterConfig.html" | ||
| ], | ||
| "Remediation": { | ||
| "Code": { | ||
| "CLI": "aws sagemaker create-processing-job --processing-job-name <job_name> --role-arn <role_arn> --app-specification ImageUri=<image_uri> --processing-resources 'ClusterConfig={InstanceCount=1,InstanceType=ml.m5.xlarge,VolumeSizeInGB=30,VolumeKmsKeyId=<kms_key_id>}' --processing-output-config 'Outputs=[{OutputName=output-1,S3Output={S3Uri=s3://<bucket>/output,LocalPath=/opt/ml/processing/output,S3UploadMode=EndOfJob}}]' --processing-inputs '[{InputName=input-1,S3Input={S3Uri=s3://<bucket>/input,LocalPath=/opt/ml/processing/input,S3DataType=S3Prefix,S3InputMode=File}}]'", | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
| "NativeIaC": "```yaml\n# CloudFormation: SageMaker ProcessingJob with volume CMEK\nResources:\n <example_resource_name>:\n Type: AWS::SageMaker::ProcessingJob\n Properties:\n ProcessingJobName: <example_resource_name>\n RoleArn: <example_role_arn>\n AppSpecification:\n ImageUri: <example_ecr_image_uri>\n ProcessingResources:\n ClusterConfig:\n InstanceCount: 1\n InstanceType: ml.m5.xlarge\n VolumeSizeInGB: 30\n VolumeKmsKeyId: <example_kms_key_arn> # Critical: encrypts the processing EBS volume with a customer-managed key\n ProcessingOutputConfig:\n Outputs:\n - OutputName: output-1\n S3Output:\n S3Uri: s3://<example_bucket>/output\n LocalPath: /opt/ml/processing/output\n S3UploadMode: EndOfJob\n```", | ||
| "Other": "1. In the AWS console, go to SageMaker > Processing > Processing jobs\n2. Create a new processing job (existing jobs cannot change VolumeKmsKeyId)\n3. Under Resource configuration, set Volume encryption key to your customer-managed KMS key\n4. Complete required fields and create the job\n5. Verify DescribeProcessingJob shows ProcessingResources.ClusterConfig.VolumeKmsKeyId", | ||
| "Terraform": "```hcl\n# SageMaker Processing Job with volume CMEK\n# Note: aws_sagemaker_processing_job is not a first-class Terraform resource in all\n# providers; use the AWS CLI/SDK or CloudFormation equivalent with VolumeKmsKeyId set:\n# ProcessingResources.ClusterConfig.VolumeKmsKeyId = \"<example_kms_key_arn>\"\n```" | ||
| }, | ||
| "Recommendation": { | ||
| "Text": "Set `VolumeKmsKeyId` on every SageMaker processing job using a **customer-managed KMS key** with a least-privilege key policy and **rotation** enabled. Existing jobs cannot change the key; recreate non-compliant jobs.", | ||
| "Url": "https://hub.prowler.com/check/sagemaker_processing_job_volume_encrypted_with_cmk" | ||
| } | ||
| }, | ||
| "Categories": [ | ||
| "encryption", | ||
| "gen-ai" | ||
| ], | ||
| "DependsOn": [], | ||
| "RelatedTo": [ | ||
| "sagemaker_training_jobs_volume_and_output_encryption_enabled", | ||
| "sagemaker_transform_job_volume_encrypted_with_cmk" | ||
| ], | ||
| "Notes": "Reports MANUAL when DescribeProcessingJob fails so an unread job is never treated as compliant. VolumeKmsKeyId lives under ProcessingResources.ClusterConfig." | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| from prowler.lib.check.models import Check, Check_Report_AWS | ||
| from prowler.providers.aws.services.sagemaker.sagemaker_client import sagemaker_client | ||
|
|
||
|
|
||
| class sagemaker_processing_job_volume_encrypted_with_cmk(Check): | ||
| """Ensure SageMaker processing job volumes use a customer-managed KMS key. | ||
|
|
||
| Processing jobs write intermediate data to an attached ML storage volume. | ||
| When ``ProcessingResources.ClusterConfig.VolumeKmsKeyId`` is unset the | ||
| volume falls back to an AWS-managed key, which cannot carry a custom key | ||
| policy and whose rotation, access and lifecycle are outside the account | ||
| owner's control. | ||
|
Contributor
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. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Correct the fallback encryption description in both check docstrings. When 🤖 Prompt for AI Agents |
||
|
|
||
| - PASS: ``VolumeKmsKeyId`` is present on the processing job. | ||
| - FAIL: ``VolumeKmsKeyId`` is absent after a successful describe. | ||
| - MANUAL: ``DescribeProcessingJob`` failed, so encryption cannot be | ||
| determined either way. | ||
| """ | ||
|
|
||
| def execute(self) -> list[Check_Report_AWS]: | ||
| """Execute the SageMaker processing job volume CMK encryption check. | ||
|
|
||
| Returns: | ||
| One report per processing job in the inventory. | ||
| """ | ||
| findings = [] | ||
| for processing_job in sagemaker_client.sagemaker_processing_jobs: | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| report = Check_Report_AWS( | ||
| metadata=self.metadata(), resource=processing_job | ||
| ) | ||
| if processing_job.detail_fetch_error: | ||
| report.status = "MANUAL" | ||
| report.status_extended = ( | ||
| f"SageMaker processing job {processing_job.name} details could " | ||
| f"not be described ({processing_job.detail_fetch_error}); " | ||
| "volume encryption cannot be verified." | ||
| ) | ||
| elif processing_job.volume_kms_key_id: | ||
| report.status = "PASS" | ||
| report.status_extended = ( | ||
| f"SageMaker processing job {processing_job.name} encrypts its " | ||
| f"volume with the customer-managed KMS key " | ||
| f"{processing_job.volume_kms_key_id}." | ||
| ) | ||
| else: | ||
| report.status = "FAIL" | ||
| report.status_extended = ( | ||
| f"SageMaker processing job {processing_job.name} does not " | ||
| "encrypt its volume with a customer-managed KMS key." | ||
| ) | ||
| findings.append(report) | ||
| return findings | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| { | ||
| "Provider": "aws", | ||
| "CheckID": "sagemaker_transform_job_volume_encrypted_with_cmk", | ||
| "CheckTitle": "SageMaker transform job volumes use customer-managed KMS keys", | ||
| "CheckType": [ | ||
| "Software and Configuration Checks/AWS Security Best Practices", | ||
| "Effects/Data Exposure" | ||
| ], | ||
| "ServiceName": "sagemaker", | ||
| "SubServiceName": "", | ||
| "ResourceIdTemplate": "", | ||
| "Severity": "high", | ||
| "ResourceType": "Other", | ||
| "ResourceGroup": "ai_ml", | ||
| "Description": "**Amazon SageMaker transform jobs** are assessed for **at-rest encryption** of their attached ML storage volumes using a **customer-managed KMS key**. The finding reflects whether `TransformResources.VolumeKmsKeyId` is set on the job.", | ||
| "Risk": "A transform job without `VolumeKmsKeyId` falls back to an **AWS managed key**, which cannot carry a custom key policy and whose **rotation**, **access** and **lifecycle** are outside the account owner's control. Intermediate inference data on the volume then cannot be independently revoked, and grants to that data cannot be audited or restricted through a key policy.", | ||
| "RelatedUrl": "", | ||
| "AdditionalURLs": [ | ||
| "https://docs.aws.amazon.com/sagemaker/latest/dg/key-management.html", | ||
| "https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_DescribeTransformJob.html", | ||
| "https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_TransformResources.html" | ||
| ], | ||
| "Remediation": { | ||
| "Code": { | ||
| "CLI": "aws sagemaker create-transform-job --transform-job-name <job_name> --model-name <model_name> --transform-input 'DataSource={S3DataSource={S3DataType=S3Prefix,S3Uri=s3://<bucket>/input}},ContentType=text/csv' --transform-output 'S3OutputPath=s3://<bucket>/output' --transform-resources 'InstanceType=ml.m5.xlarge,InstanceCount=1,VolumeKmsKeyId=<kms_key_id>'", | ||
| "NativeIaC": "```yaml\n# CloudFormation: SageMaker TransformJob with volume CMEK\nResources:\n <example_resource_name>:\n Type: AWS::SageMaker::TransformJob\n Properties:\n TransformJobName: <example_resource_name>\n ModelName: <example_model_name>\n TransformInput:\n DataSource:\n S3DataSource:\n S3DataType: S3Prefix\n S3Uri: s3://<example_bucket>/input\n TransformOutput:\n S3OutputPath: s3://<example_bucket>/output\n TransformResources:\n InstanceType: ml.m5.xlarge\n InstanceCount: 1\n VolumeKmsKeyId: <example_kms_key_arn> # Critical: encrypts the transform EBS volume with a customer-managed key\n```", | ||
| "Other": "1. In the AWS console, go to SageMaker > Inference > Batch transform jobs\n2. Create a new transform job (existing jobs cannot change VolumeKmsKeyId)\n3. Under Resource configuration, set Volume encryption key to your customer-managed KMS key\n4. Complete required fields and create the job\n5. Verify DescribeTransformJob shows TransformResources.VolumeKmsKeyId", | ||
| "Terraform": "```hcl\n# SageMaker Transform Job with volume CMEK\n# Set TransformResources.VolumeKmsKeyId via the AWS CLI/SDK or CloudFormation:\n# VolumeKmsKeyId = \"<example_kms_key_arn>\"\n```" | ||
| }, | ||
| "Recommendation": { | ||
| "Text": "Set `VolumeKmsKeyId` on every SageMaker transform job using a **customer-managed KMS key** with a least-privilege key policy and **rotation** enabled. Existing jobs cannot change the key; recreate non-compliant jobs.", | ||
| "Url": "https://hub.prowler.com/check/sagemaker_transform_job_volume_encrypted_with_cmk" | ||
| } | ||
| }, | ||
| "Categories": [ | ||
| "encryption", | ||
| "gen-ai" | ||
| ], | ||
| "DependsOn": [], | ||
| "RelatedTo": [ | ||
| "sagemaker_training_jobs_volume_and_output_encryption_enabled", | ||
| "sagemaker_processing_job_volume_encrypted_with_cmk" | ||
| ], | ||
| "Notes": "Reports MANUAL when DescribeTransformJob fails so an unread job is never treated as compliant. VolumeKmsKeyId lives under TransformResources." | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.