mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +00:00
feat(): Sagemaker service and checks (#1490)
Co-authored-by: sergargar <sergio@verica.io>
This commit is contained in:
0
providers/aws/services/sagemaker/__init__.py
Normal file
0
providers/aws/services/sagemaker/__init__.py
Normal file
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2020) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
CHECK_ID_extra7103="7.103"
|
||||
CHECK_TITLE_extra7103="[extra7103] Check if Amazon SageMaker Notebook instances have root access disabled"
|
||||
CHECK_SCORED_extra7103="NOT_SCORED"
|
||||
CHECK_CIS_LEVEL_extra7103="EXTRA"
|
||||
CHECK_ASFF_RESOURCE_TYPE_extra7103="AwsSageMakerNotebookInstance"
|
||||
CHECK_ALTERNATE_check7103="extra7103"
|
||||
CHECK_SEVERITY_extra7103="Medium"
|
||||
CHECK_SERVICENAME_extra7103="sagemaker"
|
||||
CHECK_RISK_extra7103='Users with root access have administrator privileges; users can access and edit all files on a notebook instance with root access enabled.'
|
||||
CHECK_REMEDIATION_extra7103='set the RootAccess field to Disabled. You can also disable root access for users when you create or update a notebook instance in the Amazon SageMaker console.'
|
||||
CHECK_DOC_extra7103='https://docs.aws.amazon.com/sagemaker/latest/dg/nbi-root-access.html'
|
||||
CHECK_CAF_EPIC_extra7103='IAM'
|
||||
|
||||
extra7103(){
|
||||
for regx in ${REGIONS}; do
|
||||
LIST_SM_NB_INSTANCES=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-notebook-instances --query 'NotebookInstances[*].NotebookInstanceName' --output text 2>&1)
|
||||
if [[ $(echo "$LIST_SM_NB_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
|
||||
textInfo "$regx: Access Denied trying to list notebook instances" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $LIST_SM_NB_INSTANCES ]];then
|
||||
for nb_instance in $LIST_SM_NB_INSTANCES; do
|
||||
SM_NB_ROOTACCESS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-notebook-instance --notebook-instance-name $nb_instance --query 'RootAccess' --output text)
|
||||
if [[ "${SM_NB_ROOTACCESS}" == "Enabled" ]]; then
|
||||
textFail "${regx}: Sagemaker Notebook instance $nb_instance has root access enabled" "${regx}" "$nb_instance"
|
||||
else
|
||||
textPass "${regx}: Sagemaker Notebook instance $nb_instance has root access disabled" "${regx}" "$nb_instance"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "${regx}: No Sagemaker Notebook instances found" "${regx}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2020) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
CHECK_ID_extra7104="7.104"
|
||||
CHECK_TITLE_extra7104="[extra7104] Check if Amazon SageMaker Notebook instances have VPC settings configured"
|
||||
CHECK_SCORED_extra7104="NOT_SCORED"
|
||||
CHECK_CIS_LEVEL_extra7104="EXTRA"
|
||||
CHECK_ASFF_RESOURCE_TYPE_extra7104="AwsSageMakerNotebookInstance"
|
||||
CHECK_ALTERNATE_check7104="extra7104"
|
||||
CHECK_SEVERITY_extra7104="Medium"
|
||||
CHECK_SERVICENAME_extra7104="sagemaker"
|
||||
CHECK_RISK_extra7104='This could provide an avenue for unauthorized access to your data.'
|
||||
CHECK_REMEDIATION_extra7104='Restrict which traffic can access by launching Studio in a Virtual Private Cloud (VPC) of your choosing.'
|
||||
CHECK_DOC_extra7104='https://docs.aws.amazon.com/sagemaker/latest/dg/studio-notebooks-and-internet-access.html'
|
||||
CHECK_CAF_EPIC_extra7104='Infrastructure Security'
|
||||
|
||||
extra7104(){
|
||||
for regx in ${REGIONS}; do
|
||||
LIST_SM_NB_INSTANCES=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-notebook-instances --query 'NotebookInstances[*].NotebookInstanceName' --output text 2>&1)
|
||||
if [[ $(echo "$LIST_SM_NB_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
|
||||
textInfo "$regx: Access Denied trying to list notebook instances" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $LIST_SM_NB_INSTANCES ]];then
|
||||
for nb_instance in $LIST_SM_NB_INSTANCES; do
|
||||
SM_NB_SUBNETID=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-notebook-instance --notebook-instance-name $nb_instance --query 'SubnetId' --output text)
|
||||
if [[ "${SM_NB_SUBNETID}" == "None" ]]; then
|
||||
textFail "${regx}: Sagemaker Notebook instance $nb_instance has VPC settings disabled" "${regx}" "$nb_instance"
|
||||
else
|
||||
textPass "${regx}: Sagemaker Notebook instance $nb_instance is in a VPC" "${regx}" "$nb_instance"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "${regx}: No Sagemaker Notebook instances found" "${regx}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2020) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
CHECK_ID_extra7105="7.105"
|
||||
CHECK_TITLE_extra7105="[extra7105] Check if Amazon SageMaker Models have network isolation enabled"
|
||||
CHECK_SCORED_extra7105="NOT_SCORED"
|
||||
CHECK_CIS_LEVEL_extra7105="EXTRA"
|
||||
CHECK_ASFF_RESOURCE_TYPE_extra7105="AwsSageMakerModel"
|
||||
CHECK_ALTERNATE_check7105="extra7105"
|
||||
CHECK_SEVERITY_extra7105="Medium"
|
||||
CHECK_SERVICENAME_extra7105="sagemaker"
|
||||
CHECK_RISK_extra7105='This could provide an avenue for unauthorized access to your data.'
|
||||
CHECK_REMEDIATION_extra7105='Restrict which traffic can access by launching Studio in a Virtual Private Cloud (VPC) of your choosing.'
|
||||
CHECK_DOC_extra7105='https://docs.aws.amazon.com/sagemaker/latest/dg/studio-notebooks-and-internet-access.html'
|
||||
CHECK_CAF_EPIC_extra7105='Infrastructure Security'
|
||||
|
||||
extra7105(){
|
||||
for regx in ${REGIONS}; do
|
||||
LIST_SM_NB_MODELS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-models --query 'Models[*].ModelName' --output text 2>&1)
|
||||
if [[ $(echo "$LIST_SM_NB_MODELS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
|
||||
textInfo "$regx: Access Denied trying to list models" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $LIST_SM_NB_MODELS ]];then
|
||||
for nb_model_name in $LIST_SM_NB_MODELS; do
|
||||
SM_NB_NETWORKISOLATION=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-model --model-name $nb_model_name --query 'EnableNetworkIsolation' --output text)
|
||||
if [[ $SM_NB_NETWORKISOLATION == False ]]; then
|
||||
textFail "${regx}: SageMaker Model $nb_model_name has network isolation disabled" "${regx}" "$nb_model_name"
|
||||
else
|
||||
textPass "${regx}: SageMaker Model $nb_model_name has network isolation enabled" "${regx}" "$nb_model_name"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "${regx}: No Sagemaker Models found" "${regx}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2020) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
CHECK_ID_extra7106="7.106"
|
||||
CHECK_TITLE_extra7106="[extra7106] Check if Amazon SageMaker Models have VPC settings configured"
|
||||
CHECK_SCORED_extra7106="NOT_SCORED"
|
||||
CHECK_CIS_LEVEL_extra7106="EXTRA"
|
||||
CHECK_ASFF_RESOURCE_TYPE_extra7106="AwsSageMakerModel"
|
||||
CHECK_ALTERNATE_check7106="extra7106"
|
||||
CHECK_SEVERITY_extra7106="Medium"
|
||||
CHECK_SERVICENAME_extra7106="sagemaker"
|
||||
CHECK_RISK_extra7106='This could provide an avenue for unauthorized access to your data.'
|
||||
CHECK_REMEDIATION_extra7106='Restrict which traffic can access by launching Studio in a Virtual Private Cloud (VPC) of your choosing.'
|
||||
CHECK_DOC_extra7106='https://docs.aws.amazon.com/sagemaker/latest/dg/studio-notebooks-and-internet-access.html'
|
||||
CHECK_CAF_EPIC_extra7106='Infrastructure Security'
|
||||
|
||||
extra7106(){
|
||||
for regx in ${REGIONS}; do
|
||||
LIST_SM_NB_MODELS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-models --query 'Models[*].ModelName' --output text 2>&1)
|
||||
if [[ $(echo "$LIST_SM_NB_MODELS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
|
||||
textInfo "$regx: Access Denied trying to list models" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $LIST_SM_NB_MODELS ]];then
|
||||
for nb_model_name in $LIST_SM_NB_MODELS; do
|
||||
SM_NB_VPCCONFIG=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-model --model-name $nb_model_name --query 'VpcConfig.Subnets' --output text)
|
||||
if [[ $SM_NB_VPCCONFIG == "None" ]]; then
|
||||
textFail "${regx}: Amazon SageMaker Model $nb_model_name has VPC settings disabled" "${regx}" "$nb_model_name"
|
||||
else
|
||||
textPass "${regx}: Amazon SageMaker Model $nb_model_name has VPC settings enabled" "${regx}" "$nb_model_name"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "${regx}: No Sagemaker Models found" "${regx}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2020) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
CHECK_ID_extra7107="7.107"
|
||||
CHECK_TITLE_extra7107="[extra7107] Check if Amazon SageMaker Training jobs have intercontainer encryption enabled"
|
||||
CHECK_SCORED_extra7107="NOT_SCORED"
|
||||
CHECK_CIS_LEVEL_extra7107="EXTRA"
|
||||
CHECK_ASFF_RESOURCE_TYPE_extra7107="AwsSageMakerNotebookInstance"
|
||||
CHECK_ALTERNATE_check7107="extra7107"
|
||||
CHECK_SEVERITY_extra7107="Medium"
|
||||
CHECK_SERVICENAME_extra7107="sagemaker"
|
||||
CHECK_RISK_extra7107='If not restricted unintended access could happen.'
|
||||
CHECK_REMEDIATION_extra7107='Internetwork communications support TLS 1.2 encryption between all components and clients.'
|
||||
CHECK_DOC_extra7107='https://docs.aws.amazon.com/sagemaker/latest/dg/interface-vpc-endpoint.html'
|
||||
CHECK_CAF_EPIC_extra7107='Data Protection'
|
||||
|
||||
extra7107(){
|
||||
for regx in ${REGIONS}; do
|
||||
LIST_SM_NB_JOBS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-training-jobs --query 'TrainingJobSummaries[*].TrainingJobName' --output text 2>&1)
|
||||
if [[ $(echo "$LIST_SM_NB_JOBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
|
||||
textInfo "$regx: Access Denied trying to list training jobs" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $LIST_SM_NB_JOBS ]];then
|
||||
for nb_job_name in $LIST_SM_NB_JOBS; do
|
||||
SM_NB_INTERCONTAINERENCRYPTION=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-training-job --training-job-name $nb_job_name --query 'EnableInterContainerTrafficEncryption' --output text)
|
||||
if [[ $SM_NB_INTERCONTAINERENCRYPTION == "False" ]]; then
|
||||
textFail "${regx}: SageMaker Training job $nb_job_name has intercontainer encryption disabled" "${regx}" "$nb_job_name"
|
||||
else
|
||||
textPass "${regx}: SageMaker Training jobs $nb_job_name has intercontainer encryption enabled" "${regx}" "$nb_job_name"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "${regx}: No Sagemaker Training found" "${regx}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2020) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
CHECK_ID_extra7108="7.108"
|
||||
CHECK_TITLE_extra7108="[extra7108] Check if Amazon SageMaker Training jobs have volume and output with KMS encryption enabled"
|
||||
CHECK_SCORED_extra7108="NOT_SCORED"
|
||||
CHECK_CIS_LEVEL_extra7108="EXTRA"
|
||||
CHECK_ASFF_RESOURCE_TYPE_extra7108="AwsSageMakerNotebookInstance"
|
||||
CHECK_ALTERNATE_check7108="extra7108"
|
||||
CHECK_SEVERITY_extra7108="Medium"
|
||||
CHECK_SERVICENAME_extra7108="sagemaker"
|
||||
CHECK_RISK_extra7108='Data exfiltration could happen if information is not protected. KMS keys provide additional security level to IAM policies.'
|
||||
CHECK_REMEDIATION_extra7108='Specify AWS KMS keys to use for input and output from S3 and EBS.'
|
||||
CHECK_DOC_extra7108='https://docs.aws.amazon.com/sagemaker/latest/dg/key-management.html'
|
||||
CHECK_CAF_EPIC_extra7108='Data Protection'
|
||||
|
||||
extra7108(){
|
||||
for regx in ${REGIONS}; do
|
||||
LIST_SM_NB_JOBS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-training-jobs --query 'TrainingJobSummaries[*].TrainingJobName' --output text 2>&1)
|
||||
if [[ $(echo "$LIST_SM_NB_JOBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
|
||||
textInfo "$regx: Access Denied trying to list training jobs" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $LIST_SM_NB_JOBS ]];then
|
||||
for nb_job_name in $LIST_SM_NB_JOBS; do
|
||||
SM_JOB_KMSENCRYPTION=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-training-job --training-job-name $nb_job_name --query 'ResourceConfig.VolumeKmsKeyId' --output text)
|
||||
if [[ "${SM_JOB_KMSENCRYPTION}" == "None" ]];then
|
||||
textFail "${regx}: Sagemaker Trainings job $nb_job_name has KMS encryption disabled" "${regx}" "$nb_job_name"
|
||||
else
|
||||
textPass "${regx}: Sagemaker Trainings job $nb_job_name has KSM encryption enabled" "${regx}" "$nb_job_name"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "${regx}: No Sagemaker Trainings jobs found" "${regx}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2020) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
CHECK_ID_extra7109="7.109"
|
||||
CHECK_TITLE_extra7109="[extra7109] Check if Amazon SageMaker Training jobs have network isolation enabled"
|
||||
CHECK_SCORED_extra7109="NOT_SCORED"
|
||||
CHECK_CIS_LEVEL_extra7109="EXTRA"
|
||||
CHECK_ASFF_RESOURCE_TYPE_extra7109="AwsSageMakerNotebookInstance"
|
||||
CHECK_ALTERNATE_check7109="extra7109"
|
||||
CHECK_SEVERITY_extra7109="Medium"
|
||||
CHECK_SERVICENAME_extra7109="sagemaker"
|
||||
CHECK_RISK_extra7109='This could provide an avenue for unauthorized access to your data.'
|
||||
CHECK_REMEDIATION_extra7109='Restrict which traffic can access by launching Studio in a Virtual Private Cloud (VPC) of your choosing.'
|
||||
CHECK_DOC_extra7109='https://docs.aws.amazon.com/sagemaker/latest/dg/interface-vpc-endpoint.html'
|
||||
CHECK_CAF_EPIC_extra7109='Infrastructure Security'
|
||||
|
||||
extra7109(){
|
||||
for regx in ${REGIONS}; do
|
||||
LIST_SM_NB_JOBS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-training-jobs --query 'TrainingJobSummaries[*].TrainingJobName' --output text 2>&1)
|
||||
if [[ $(echo "$LIST_SM_NB_JOBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
|
||||
textInfo "$regx: Access Denied trying to list training jobs" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $LIST_SM_NB_JOBS ]];then
|
||||
for nb_job_name in $LIST_SM_NB_JOBS; do
|
||||
SM_NB_NETWORKISOLATION=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-training-job --training-job-name $nb_job_name --query 'EnableNetworkIsolation' --output text)
|
||||
if [[ $SM_NB_NETWORKISOLATION == False ]]; then
|
||||
textFail "${regx}: Sagemaker Training job $nb_job_name has network isolation disabled" "${regx}" "$nb_job_name"
|
||||
else
|
||||
textPass "${regx}: Sagemaker Training job $nb_job_name has network isolation enabled" "${regx}" "$nb_job_name"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "${regx}: No Sagemaker Trainings jobs found" "${regx}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2020) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
CHECK_ID_extra7110="7.110"
|
||||
CHECK_TITLE_extra7110="[extra7110] Check if Amazon SageMaker Training job have VPC settings configured."
|
||||
CHECK_SCORED_extra7110="NOT_SCORED"
|
||||
CHECK_CIS_LEVEL_extra7110="EXTRA"
|
||||
CHECK_ASFF_RESOURCE_TYPE_extra7110="AwsSageMakerNotebookInstance"
|
||||
CHECK_ALTERNATE_check7110="extra7110"
|
||||
CHECK_SEVERITY_extra7110="Medium"
|
||||
CHECK_SERVICENAME_extra7110="sagemaker"
|
||||
CHECK_RISK_extra7110='This could provide an avenue for unauthorized access to your data.'
|
||||
CHECK_REMEDIATION_extra7110='Restrict which traffic can access by launching Studio in a Virtual Private Cloud (VPC) of your choosing.'
|
||||
CHECK_DOC_extra7110='https://docs.aws.amazon.com/sagemaker/latest/dg/interface-vpc-endpoint.html'
|
||||
CHECK_CAF_EPIC_extra7110='Infrastructure Security'
|
||||
|
||||
extra7110(){
|
||||
for regx in ${REGIONS}; do
|
||||
LIST_SM_NB_JOBS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-training-jobs --query 'TrainingJobSummaries[*].TrainingJobName' --output text 2>&1)
|
||||
if [[ $(echo "$LIST_SM_NB_JOBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
|
||||
textInfo "$regx: Access Denied trying to list training jobs" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $LIST_SM_NB_JOBS ]];then
|
||||
for nb_job_name in $LIST_SM_NB_JOBS; do
|
||||
SM_NB_SUBNETS=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-training-job --training-job-name $nb_job_name --query 'VpcConfig.Subnets' --output text)
|
||||
if [[ $SM_NB_SUBNETS == "None" ]]; then
|
||||
textFail "${regx}: Sagemaker Training job $nb_job_name has VPC settings for the training job volume and output disabled" "${regx}" "$nb_job_name"
|
||||
else
|
||||
textPass "${regx}: Sagemaker Training job $nb_job_name has VPC settings for the training job volume and output enabled" "${regx}" "$nb_job_name"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "${regx}: No Sagemaker Trainings jobs found" "${regx}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2020) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
CHECK_ID_extra7111="7.111"
|
||||
CHECK_TITLE_extra7111="[extra7111] Check if Amazon SageMaker Notebook instances have direct internet access"
|
||||
CHECK_SCORED_extra7111="NOT_SCORED"
|
||||
CHECK_CIS_LEVEL_extra7111="EXTRA"
|
||||
CHECK_ASFF_RESOURCE_TYPE_extra7111="AwsSageMakerNotebookInstance"
|
||||
CHECK_ALTERNATE_check7111="extra7111"
|
||||
CHECK_SEVERITY_extra7111="Medium"
|
||||
CHECK_SERVICENAME_extra7111="sagemaker"
|
||||
CHECK_RISK_extra7111='This could provide an avenue for unauthorized access to your data.'
|
||||
CHECK_REMEDIATION_extra7111='Restrict which traffic can access by launching Studio in a Virtual Private Cloud (VPC) of your choosing.'
|
||||
CHECK_DOC_extra7111='https://docs.aws.amazon.com/sagemaker/latest/dg/interface-vpc-endpoint.html'
|
||||
CHECK_CAF_EPIC_extra7111='Infrastructure Security'
|
||||
|
||||
extra7111(){
|
||||
for regx in ${REGIONS}; do
|
||||
LIST_SM_NB_INSTANCES=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-notebook-instances --query 'NotebookInstances[*].NotebookInstanceName' --output text 2>&1)
|
||||
if [[ $(echo "$LIST_SM_NB_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
|
||||
textInfo "$regx: Access Denied trying to list notebook instances" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $LIST_SM_NB_INSTANCES ]];then
|
||||
for nb_instance in $LIST_SM_NB_INSTANCES; do
|
||||
SM_NB_DIRECTINET=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-notebook-instance --notebook-instance-name $nb_instance --query 'DirectInternetAccess' --output text)
|
||||
if [[ "${SM_NB_DIRECTINET}" == "Enabled" ]]; then
|
||||
textFail "${regx}: Sagemaker Notebook instance $nb_instance has direct internet access enabled" "${regx}" "$nb_instance"
|
||||
else
|
||||
textPass "${regx}: Sagemaker Notebook instance $nb_instance has direct internet access disabled" "${regx}" "$nb_instance"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "${regx}: No Sagemaker Notebook instances found" "${regx}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2020) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
CHECK_ID_extra7112="7.112"
|
||||
CHECK_TITLE_extra7112="[extra7112] Check if Amazon SageMaker Notebook instances have data encryption enabled"
|
||||
CHECK_SCORED_extra7112="NOT_SCORED"
|
||||
CHECK_CIS_LEVEL_extra7112="EXTRA"
|
||||
CHECK_ASFF_RESOURCE_TYPE_extra7112="AwsSageMakerNotebookInstance"
|
||||
CHECK_ALTERNATE_check7112="extra7112"
|
||||
CHECK_SEVERITY_extra7112="Medium"
|
||||
CHECK_SERVICENAME_extra7112="sagemaker"
|
||||
CHECK_RISK_extra7112='Data exfiltration could happen if information is not protected. KMS keys provide additional security level to IAM policies.'
|
||||
CHECK_REMEDIATION_extra7112='Specify AWS KMS keys to use for input and output from S3 and EBS.'
|
||||
CHECK_DOC_extra7112='https://docs.aws.amazon.com/sagemaker/latest/dg/key-management.html'
|
||||
CHECK_CAF_EPIC_extra7112='Data Protection'
|
||||
|
||||
extra7112(){
|
||||
for regx in ${REGIONS}; do
|
||||
LIST_SM_NB_INSTANCES=$($AWSCLI $PROFILE_OPT --region $regx sagemaker list-notebook-instances --query 'NotebookInstances[*].NotebookInstanceName' --output text 2>&1)
|
||||
if [[ $(echo "$LIST_SM_NB_INSTANCES" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
|
||||
textInfo "$regx: Access Denied trying to list notebook instances" "$regx"
|
||||
continue
|
||||
fi
|
||||
if [[ $LIST_SM_NB_INSTANCES ]];then
|
||||
for nb_instance in $LIST_SM_NB_INSTANCES; do
|
||||
SM_NB_KMSKEY=$($AWSCLI $PROFILE_OPT --region $regx sagemaker describe-notebook-instance --notebook-instance-name $nb_instance --query 'KmsKeyId' --output text)
|
||||
if [[ "${SM_NB_KMSKEY}" == "None" ]]; then
|
||||
textFail "${regx}: Sagemaker Notebook instance $nb_instance has data encryption disabled" "${regx}" "$nb_instance"
|
||||
else
|
||||
textPass "${regx}: Sagemaker Notebook instance $nb_instance has data encryption enabled" "${regx}" "$nb_instance"
|
||||
fi
|
||||
done
|
||||
else
|
||||
textInfo "${regx}: No Sagemaker Notebook instances found" "${regx}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
4
providers/aws/services/sagemaker/sagemaker_client.py
Normal file
4
providers/aws/services/sagemaker/sagemaker_client.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from providers.aws.lib.audit_info.audit_info import current_audit_info
|
||||
from providers.aws.services.sagemaker.sagemaker_service import SageMaker
|
||||
|
||||
sagemaker_client = SageMaker(current_audit_info)
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "sagemaker_models_network_isolation_enabled",
|
||||
"CheckTitle": "Check if Amazon SageMaker Models have network isolation enabled",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sagemaker",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:aws:sagemaker:region:account-id:model",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsSageMakerModel",
|
||||
"Description": "Check if Amazon SageMaker Models have network isolation enabled",
|
||||
"Risk": "This could provide an avenue for unauthorized access to your data.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/sagemaker/latest/dg/studio-notebooks-and-internet-access.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Restrict which traffic can access by launching Studio in a Virtual Private Cloud (VPC) of your choosing.",
|
||||
"Url": "https://docs.aws.amazon.com/sagemaker/latest/dg/studio-notebooks-and-internet-access.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.sagemaker.sagemaker_client import sagemaker_client
|
||||
|
||||
|
||||
class sagemaker_models_network_isolation_enabled(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for model in sagemaker_client.sagemaker_models:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = model.region
|
||||
report.resource_id = model.name
|
||||
report.resource_arn = model.arn
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Sagemaker notebook instance {model.name} has network isolation enabled"
|
||||
if not model.network_isolation:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Sagemaker notebook instance {model.name} has network isolation disabled"
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,83 @@
|
||||
from re import search
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from providers.aws.services.sagemaker.sagemaker_service import Model
|
||||
|
||||
AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
test_notebook_instance = "test-notebook-instance"
|
||||
notebook_instance_arn = f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:notebook-instance/{test_notebook_instance}"
|
||||
subnet_id = "subnet-" + str(uuid4())
|
||||
|
||||
|
||||
class Test_sagemaker_models_network_isolation_enabled:
|
||||
def test_no_models(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_models = []
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_models_network_isolation_enabled.sagemaker_models_network_isolation_enabled import (
|
||||
sagemaker_models_network_isolation_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_models_network_isolation_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_network_isolation_enabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_models = []
|
||||
sagemaker_client.sagemaker_models.append(
|
||||
Model(
|
||||
name=test_notebook_instance,
|
||||
arn=notebook_instance_arn,
|
||||
region=AWS_REGION,
|
||||
network_isolation=True,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_models_network_isolation_enabled.sagemaker_models_network_isolation_enabled import (
|
||||
sagemaker_models_network_isolation_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_models_network_isolation_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search("has network isolation enabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_notebook_instance
|
||||
assert result[0].resource_arn == notebook_instance_arn
|
||||
|
||||
def test_instance_network_isolation_disabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_models = []
|
||||
sagemaker_client.sagemaker_models.append(
|
||||
Model(
|
||||
name=test_notebook_instance,
|
||||
arn=notebook_instance_arn,
|
||||
region=AWS_REGION,
|
||||
network_isolation=False,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_models_network_isolation_enabled.sagemaker_models_network_isolation_enabled import (
|
||||
sagemaker_models_network_isolation_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_models_network_isolation_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert search("has network isolation disabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_notebook_instance
|
||||
assert result[0].resource_arn == notebook_instance_arn
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "sagemaker_models_vpc_settings_configured",
|
||||
"CheckTitle": "Check if Amazon SageMaker Models have VPC settings configured",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sagemaker",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:aws:sagemaker:region:account-id:model",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsSageMakerModel",
|
||||
"Description": "Check if Amazon SageMaker Models have VPC settings configured",
|
||||
"Risk": "This could provide an avenue for unauthorized access to your data.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/sagemaker/latest/dg/studio-notebooks-and-internet-access.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Restrict which traffic can access by launching Studio in a Virtual Private Cloud (VPC) of your choosing.",
|
||||
"Url": "https://docs.aws.amazon.com/sagemaker/latest/dg/studio-notebooks-and-internet-access.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.sagemaker.sagemaker_client import sagemaker_client
|
||||
|
||||
|
||||
class sagemaker_models_vpc_settings_configured(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for model in sagemaker_client.sagemaker_models:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = model.region
|
||||
report.resource_id = model.name
|
||||
report.resource_arn = model.arn
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Sagemaker notebook instance {model.name} has VPC settings enabled"
|
||||
)
|
||||
if not model.vpc_config_subnets:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Sagemaker notebook instance {model.name} has VPC settings disabled"
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,82 @@
|
||||
from re import search
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from providers.aws.services.sagemaker.sagemaker_service import Model
|
||||
|
||||
AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
test_notebook_instance = "test-notebook-instance"
|
||||
notebook_instance_arn = f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:notebook-instance/{test_notebook_instance}"
|
||||
subnet_id = "subnet-" + str(uuid4())
|
||||
|
||||
|
||||
class Test_sagemaker_models_vpc_settings_configured:
|
||||
def test_no_models(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_models = []
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_models_vpc_settings_configured.sagemaker_models_vpc_settings_configured import (
|
||||
sagemaker_models_vpc_settings_configured,
|
||||
)
|
||||
|
||||
check = sagemaker_models_vpc_settings_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_vpc_settings_configured(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_models = []
|
||||
sagemaker_client.sagemaker_models.append(
|
||||
Model(
|
||||
name=test_notebook_instance,
|
||||
arn=notebook_instance_arn,
|
||||
region=AWS_REGION,
|
||||
vpc_config_subnets=[subnet_id],
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_models_vpc_settings_configured.sagemaker_models_vpc_settings_configured import (
|
||||
sagemaker_models_vpc_settings_configured,
|
||||
)
|
||||
|
||||
check = sagemaker_models_vpc_settings_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search("has VPC settings enabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_notebook_instance
|
||||
assert result[0].resource_arn == notebook_instance_arn
|
||||
|
||||
def test_instance_vpc_settings_not_configured(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_models = []
|
||||
sagemaker_client.sagemaker_models.append(
|
||||
Model(
|
||||
name=test_notebook_instance,
|
||||
arn=notebook_instance_arn,
|
||||
region=AWS_REGION,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_models_vpc_settings_configured.sagemaker_models_vpc_settings_configured import (
|
||||
sagemaker_models_vpc_settings_configured,
|
||||
)
|
||||
|
||||
check = sagemaker_models_vpc_settings_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert search("has VPC settings disabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_notebook_instance
|
||||
assert result[0].resource_arn == notebook_instance_arn
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "sagemaker_notebook_instance_encryption_enabled",
|
||||
"CheckTitle": "Check if Amazon SageMaker Notebook instances have data encryption enabled",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sagemaker",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:aws:sagemaker:region:account-id:notebook-instance",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsSageMakerNotebookInstance",
|
||||
"Description": "Check if Amazon SageMaker Notebook instances have data encryption enabled",
|
||||
"Risk": "Data exfiltration could happen if information is not protected. KMS keys provide additional security level to IAM policies.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/sagemaker/latest/dg/key-management.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/SageMaker/notebook-data-encrypted.html",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/SageMaker/notebook-data-encrypted.html",
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/bc_aws_general_40#fix---buildtime"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Specify AWS KMS keys to use for input and output from S3 and EBS.",
|
||||
"Url": "https://docs.aws.amazon.com/sagemaker/latest/dg/key-management.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.sagemaker.sagemaker_client import sagemaker_client
|
||||
|
||||
|
||||
class sagemaker_notebook_instance_encryption_enabled(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for notebook_instance in sagemaker_client.sagemaker_notebook_instances:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = notebook_instance.region
|
||||
report.resource_id = notebook_instance.name
|
||||
report.resource_arn = notebook_instance.arn
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Sagemaker notebook instance {notebook_instance.name} has data encryption enabled"
|
||||
if not notebook_instance.kms_key_id:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Sagemaker notebook instance {notebook_instance.name} has data encryption disabled"
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,82 @@
|
||||
from re import search
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from providers.aws.services.sagemaker.sagemaker_service import NotebookInstance
|
||||
|
||||
AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
test_notebook_instance = "test-notebook-instance"
|
||||
notebook_instance_arn = f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:notebook-instance/{test_notebook_instance}"
|
||||
kms_key = str(uuid4())
|
||||
|
||||
|
||||
class Test_sagemaker_notebook_instance_encryption_enabled:
|
||||
def test_no_instances(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_notebook_instances = []
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_notebook_instance_encryption_enabled.sagemaker_notebook_instance_encryption_enabled import (
|
||||
sagemaker_notebook_instance_encryption_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_notebook_instance_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_with_kms_key(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_notebook_instances = []
|
||||
sagemaker_client.sagemaker_notebook_instances.append(
|
||||
NotebookInstance(
|
||||
name=test_notebook_instance,
|
||||
arn=notebook_instance_arn,
|
||||
region=AWS_REGION,
|
||||
kms_key_id=kms_key,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_notebook_instance_encryption_enabled.sagemaker_notebook_instance_encryption_enabled import (
|
||||
sagemaker_notebook_instance_encryption_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_notebook_instance_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search("has data encryption enabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_notebook_instance
|
||||
assert result[0].resource_arn == notebook_instance_arn
|
||||
|
||||
def test_instance_no_kms_key(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_notebook_instances = []
|
||||
sagemaker_client.sagemaker_notebook_instances.append(
|
||||
NotebookInstance(
|
||||
name=test_notebook_instance,
|
||||
arn=notebook_instance_arn,
|
||||
region=AWS_REGION,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_notebook_instance_encryption_enabled.sagemaker_notebook_instance_encryption_enabled import (
|
||||
sagemaker_notebook_instance_encryption_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_notebook_instance_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert search("has data encryption disabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_notebook_instance
|
||||
assert result[0].resource_arn == notebook_instance_arn
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "sagemaker_notebook_instance_root_access_disabled",
|
||||
"CheckTitle": "Check if Amazon SageMaker Notebook instances have root access disabled",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sagemaker",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:aws:sagemaker:region:account-id:notebook-instance",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsSageMakerNotebookInstance",
|
||||
"Description": "Check if Amazon SageMaker Notebook instances have root access disabled",
|
||||
"Risk": "Users with root access have administrator privileges; users can access and edit all files on a notebook instance with root access enabled",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/sagemaker/latest/dg/nbi-root-access.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Set the RootAccess field to Disabled. You can also disable root access for users when you create or update a notebook instance in the Amazon SageMaker console.",
|
||||
"Url": "https://docs.aws.amazon.com/sagemaker/latest/dg/nbi-root-access.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.sagemaker.sagemaker_client import sagemaker_client
|
||||
|
||||
|
||||
class sagemaker_notebook_instance_root_access_disabled(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for notebook_instance in sagemaker_client.sagemaker_notebook_instances:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = notebook_instance.region
|
||||
report.resource_id = notebook_instance.name
|
||||
report.resource_arn = notebook_instance.arn
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Sagemaker notebook instance {notebook_instance.name} has root access disabled"
|
||||
if notebook_instance.root_access:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Sagemaker notebook instance {notebook_instance.name} has root access enabled"
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,81 @@
|
||||
from re import search
|
||||
from unittest import mock
|
||||
|
||||
from providers.aws.services.sagemaker.sagemaker_service import NotebookInstance
|
||||
|
||||
AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
test_notebook_instance = "test-notebook-instance"
|
||||
notebook_instance_arn = f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:notebook-instance/{test_notebook_instance}"
|
||||
|
||||
|
||||
class Test_sagemaker_notebook_instance_root_access_disabled:
|
||||
def test_no_instances(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_notebook_instances = []
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_notebook_instance_root_access_disabled.sagemaker_notebook_instance_root_access_disabled import (
|
||||
sagemaker_notebook_instance_root_access_disabled,
|
||||
)
|
||||
|
||||
check = sagemaker_notebook_instance_root_access_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_root_access_disabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_notebook_instances = []
|
||||
sagemaker_client.sagemaker_notebook_instances.append(
|
||||
NotebookInstance(
|
||||
name=test_notebook_instance,
|
||||
arn=notebook_instance_arn,
|
||||
region=AWS_REGION,
|
||||
root_access=False,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_notebook_instance_root_access_disabled.sagemaker_notebook_instance_root_access_disabled import (
|
||||
sagemaker_notebook_instance_root_access_disabled,
|
||||
)
|
||||
|
||||
check = sagemaker_notebook_instance_root_access_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search("has root access disabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_notebook_instance
|
||||
assert result[0].resource_arn == notebook_instance_arn
|
||||
|
||||
def test_instance_root_access_enabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_notebook_instances = []
|
||||
sagemaker_client.sagemaker_notebook_instances.append(
|
||||
NotebookInstance(
|
||||
name=test_notebook_instance,
|
||||
arn=notebook_instance_arn,
|
||||
region=AWS_REGION,
|
||||
root_access=True,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_notebook_instance_root_access_disabled.sagemaker_notebook_instance_root_access_disabled import (
|
||||
sagemaker_notebook_instance_root_access_disabled,
|
||||
)
|
||||
|
||||
check = sagemaker_notebook_instance_root_access_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert search("has root access enabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_notebook_instance
|
||||
assert result[0].resource_arn == notebook_instance_arn
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "sagemaker_notebook_instance_vpc_settings_configured",
|
||||
"CheckTitle": "Check if Amazon SageMaker Notebook instances have VPC settings configured",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sagemaker",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:aws:sagemaker:region:account-id:notebook-instance",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsSageMakerNotebookInstance",
|
||||
"Description": "Check if Amazon SageMaker Notebook instances have VPC settings configured",
|
||||
"Risk": "This could provide an avenue for unauthorized access to your data.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/sagemaker/latest/dg/studio-notebooks-and-internet-access.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/SageMaker/notebook-instance-in-vpc.html",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/SageMaker/notebook-instance-in-vpc.html",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Restrict which traffic can access by launching Studio in a Virtual Private Cloud (VPC) of your choosing..",
|
||||
"Url": "https://docs.aws.amazon.com/sagemaker/latest/dg/studio-notebooks-and-internet-access.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.sagemaker.sagemaker_client import sagemaker_client
|
||||
|
||||
|
||||
class sagemaker_notebook_instance_vpc_settings_configured(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for notebook_instance in sagemaker_client.sagemaker_notebook_instances:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = notebook_instance.region
|
||||
report.resource_id = notebook_instance.name
|
||||
report.resource_arn = notebook_instance.arn
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Sagemaker notebook instance {notebook_instance.name} is in a VPC"
|
||||
)
|
||||
if not notebook_instance.subnet_id:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Sagemaker notebook instance {notebook_instance.name} has VPC settings disabled"
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,83 @@
|
||||
from re import search
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from providers.aws.services.sagemaker.sagemaker_service import NotebookInstance
|
||||
|
||||
AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
test_notebook_instance = "test-notebook-instance"
|
||||
notebook_instance_arn = f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:notebook-instance/{test_notebook_instance}"
|
||||
subnet_id = "subnet-" + str(uuid4())
|
||||
|
||||
|
||||
class Test_sagemaker_notebook_instance_vpc_settings_configured:
|
||||
def test_no_instances(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_notebook_instances = []
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_notebook_instance_vpc_settings_configured.sagemaker_notebook_instance_vpc_settings_configured import (
|
||||
sagemaker_notebook_instance_vpc_settings_configured,
|
||||
)
|
||||
|
||||
check = sagemaker_notebook_instance_vpc_settings_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_vpc_settings_configured(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_notebook_instances = []
|
||||
sagemaker_client.sagemaker_notebook_instances.append(
|
||||
NotebookInstance(
|
||||
name=test_notebook_instance,
|
||||
arn=notebook_instance_arn,
|
||||
region=AWS_REGION,
|
||||
subnet_id=subnet_id,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_notebook_instance_vpc_settings_configured.sagemaker_notebook_instance_vpc_settings_configured import (
|
||||
sagemaker_notebook_instance_vpc_settings_configured,
|
||||
)
|
||||
|
||||
check = sagemaker_notebook_instance_vpc_settings_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search("is in a VPC", result[0].status_extended)
|
||||
assert result[0].resource_id == test_notebook_instance
|
||||
assert result[0].resource_arn == notebook_instance_arn
|
||||
|
||||
def test_instance_vpc_settings_not_configured(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_notebook_instances = []
|
||||
sagemaker_client.sagemaker_notebook_instances.append(
|
||||
NotebookInstance(
|
||||
name=test_notebook_instance,
|
||||
arn=notebook_instance_arn,
|
||||
region=AWS_REGION,
|
||||
root_access=True,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_notebook_instance_vpc_settings_configured.sagemaker_notebook_instance_vpc_settings_configured import (
|
||||
sagemaker_notebook_instance_vpc_settings_configured,
|
||||
)
|
||||
|
||||
check = sagemaker_notebook_instance_vpc_settings_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert search("has VPC settings disabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_notebook_instance
|
||||
assert result[0].resource_arn == notebook_instance_arn
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "sagemaker_notebook_instance_without_direct_internet_access_configured",
|
||||
"CheckTitle": "Check if Amazon SageMaker Notebook instances have direct internet access",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sagemaker",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:aws:sagemaker:region:account-id:notebook-instance",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsSageMakerNotebookInstance",
|
||||
"Description": "Check if Amazon SageMaker Notebook instances have direct internet access",
|
||||
"Risk": "This could provide an avenue for unauthorized access to your data.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/sagemaker/latest/dg/interface-vpc-endpoint.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/SageMaker/notebook-direct-internet-access.html",
|
||||
"NativeIaC": "",
|
||||
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/SageMaker/notebook-direct-internet-access.html",
|
||||
"Terraform": "https://docs.bridgecrew.io/docs/ensure-that-direct-internet-access-is-disabled-for-an-amazon-sagemaker-notebook-instance#fix---buildtime"
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Restrict which traffic can access by launching Studio in a Virtual Private Cloud (VPC) of your choosing.",
|
||||
"Url": "https://docs.aws.amazon.com/sagemaker/latest/dg/interface-vpc-endpoint.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.sagemaker.sagemaker_client import sagemaker_client
|
||||
|
||||
|
||||
class sagemaker_notebook_instance_without_direct_internet_access_configured(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for notebook_instance in sagemaker_client.sagemaker_notebook_instances:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = notebook_instance.region
|
||||
report.resource_id = notebook_instance.name
|
||||
report.resource_arn = notebook_instance.arn
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Sagemaker notebook instance {notebook_instance.name} has direct internet access disabled"
|
||||
if notebook_instance.direct_internet_access:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Sagemaker notebook instance {notebook_instance.name} has direct internet access enabled"
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,91 @@
|
||||
from re import search
|
||||
from unittest import mock
|
||||
|
||||
from providers.aws.services.sagemaker.sagemaker_service import NotebookInstance
|
||||
|
||||
AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
test_notebook_instance = "test-notebook-instance"
|
||||
notebook_instance_arn = f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:notebook-instance/{test_notebook_instance}"
|
||||
|
||||
|
||||
class Test_sagemaker_notebook_instance_without_direct_internet_access_configured:
|
||||
def test_no_instances(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_notebook_instances = []
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_notebook_instance_without_direct_internet_access_configured.sagemaker_notebook_instance_without_direct_internet_access_configured import (
|
||||
sagemaker_notebook_instance_without_direct_internet_access_configured,
|
||||
)
|
||||
|
||||
check = (
|
||||
sagemaker_notebook_instance_without_direct_internet_access_configured()
|
||||
)
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_direct_internet_disabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_notebook_instances = []
|
||||
sagemaker_client.sagemaker_notebook_instances.append(
|
||||
NotebookInstance(
|
||||
name=test_notebook_instance,
|
||||
arn=notebook_instance_arn,
|
||||
region=AWS_REGION,
|
||||
direct_internet_access=False,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_notebook_instance_without_direct_internet_access_configured.sagemaker_notebook_instance_without_direct_internet_access_configured import (
|
||||
sagemaker_notebook_instance_without_direct_internet_access_configured,
|
||||
)
|
||||
|
||||
check = (
|
||||
sagemaker_notebook_instance_without_direct_internet_access_configured()
|
||||
)
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search(
|
||||
"has direct internet access disabled", result[0].status_extended
|
||||
)
|
||||
assert result[0].resource_id == test_notebook_instance
|
||||
assert result[0].resource_arn == notebook_instance_arn
|
||||
|
||||
def test_instance_direct_internet_enabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_notebook_instances = []
|
||||
sagemaker_client.sagemaker_notebook_instances.append(
|
||||
NotebookInstance(
|
||||
name=test_notebook_instance,
|
||||
arn=notebook_instance_arn,
|
||||
region=AWS_REGION,
|
||||
direct_internet_access=True,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_notebook_instance_without_direct_internet_access_configured.sagemaker_notebook_instance_without_direct_internet_access_configured import (
|
||||
sagemaker_notebook_instance_without_direct_internet_access_configured,
|
||||
)
|
||||
|
||||
check = (
|
||||
sagemaker_notebook_instance_without_direct_internet_access_configured()
|
||||
)
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert search(
|
||||
"has direct internet access enabled", result[0].status_extended
|
||||
)
|
||||
assert result[0].resource_id == test_notebook_instance
|
||||
assert result[0].resource_arn == notebook_instance_arn
|
||||
203
providers/aws/services/sagemaker/sagemaker_service.py
Normal file
203
providers/aws/services/sagemaker/sagemaker_service.py
Normal file
@@ -0,0 +1,203 @@
|
||||
import threading
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from lib.logger import logger
|
||||
from providers.aws.aws_provider import generate_regional_clients
|
||||
|
||||
|
||||
################################ SageMaker
|
||||
class SageMaker:
|
||||
def __init__(self, audit_info):
|
||||
self.service = "sagemaker"
|
||||
self.session = audit_info.audit_session
|
||||
self.regional_clients = generate_regional_clients(self.service, audit_info)
|
||||
self.sagemaker_notebook_instances = []
|
||||
self.sagemaker_models = []
|
||||
self.sagemaker_training_jobs = []
|
||||
self.__threading_call__(self.__list_notebook_instances__)
|
||||
self.__threading_call__(self.__list_models__)
|
||||
self.__threading_call__(self.__list_training_jobs__)
|
||||
self.__describe_model__(self.regional_clients)
|
||||
self.__describe_notebook_instance__(self.regional_clients)
|
||||
self.__describe_training_job__(self.regional_clients)
|
||||
|
||||
def __get_session__(self):
|
||||
return self.session
|
||||
|
||||
def __threading_call__(self, call):
|
||||
threads = []
|
||||
for regional_client in self.regional_clients.values():
|
||||
threads.append(threading.Thread(target=call, args=(regional_client,)))
|
||||
for t in threads:
|
||||
t.start()
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
def __list_notebook_instances__(self, regional_client):
|
||||
logger.info("SageMaker - listing notebook instances...")
|
||||
try:
|
||||
list_notebook_instances_paginator = regional_client.get_paginator(
|
||||
"list_notebook_instances"
|
||||
)
|
||||
for page in list_notebook_instances_paginator.paginate():
|
||||
for notebook_instance in page["NotebookInstances"]:
|
||||
self.sagemaker_notebook_instances.append(
|
||||
NotebookInstance(
|
||||
name=notebook_instance["NotebookInstanceName"],
|
||||
region=regional_client.region,
|
||||
arn=notebook_instance["NotebookInstanceArn"],
|
||||
)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
def __list_models__(self, regional_client):
|
||||
logger.info("SageMaker - listing models...")
|
||||
try:
|
||||
list_models_paginator = regional_client.get_paginator("list_models")
|
||||
for page in list_models_paginator.paginate():
|
||||
for model in page["Models"]:
|
||||
self.sagemaker_models.append(
|
||||
Model(
|
||||
name=model["ModelName"],
|
||||
region=regional_client.region,
|
||||
arn=model["ModelArn"],
|
||||
)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
def __list_training_jobs__(self, regional_client):
|
||||
logger.info("SageMaker - listing training jobs...")
|
||||
try:
|
||||
list_training_jobs_paginator = regional_client.get_paginator(
|
||||
"list_training_jobs"
|
||||
)
|
||||
for page in list_training_jobs_paginator.paginate():
|
||||
for training_job in page["TrainingJobSummaries"]:
|
||||
self.sagemaker_training_jobs.append(
|
||||
TrainingJob(
|
||||
name=training_job["TrainingJobName"],
|
||||
region=regional_client.region,
|
||||
arn=training_job["TrainingJobArn"],
|
||||
)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
def __describe_notebook_instance__(self, regional_clients):
|
||||
logger.info("SageMaker - describing notebook instances...")
|
||||
try:
|
||||
for notebook_instance in self.sagemaker_notebook_instances:
|
||||
regional_client = regional_clients[notebook_instance.region]
|
||||
describe_notebook_instance = regional_client.describe_notebook_instance(
|
||||
NotebookInstanceName=notebook_instance.name
|
||||
)
|
||||
if (
|
||||
"RootAccess" in describe_notebook_instance
|
||||
and describe_notebook_instance["RootAccess"] == "Enabled"
|
||||
):
|
||||
notebook_instance.root_access = True
|
||||
if "SubnetId" in describe_notebook_instance:
|
||||
notebook_instance.subnet_id = describe_notebook_instance["SubnetId"]
|
||||
if (
|
||||
"DirectInternetAccess" in describe_notebook_instance
|
||||
and describe_notebook_instance["RootAccess"] == "Enabled"
|
||||
):
|
||||
notebook_instance.direct_internet_access = True
|
||||
if "KmsKeyId" in describe_notebook_instance:
|
||||
notebook_instance.kms_key_id = describe_notebook_instance[
|
||||
"KmsKeyId"
|
||||
]
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
def __describe_model__(self, regional_clients):
|
||||
logger.info("SageMaker - describing models...")
|
||||
try:
|
||||
for model in self.sagemaker_models:
|
||||
regional_client = regional_clients[model.region]
|
||||
describe_model = regional_client.describe_model(ModelName=model.name)
|
||||
if "EnableNetworkIsolation" in describe_model:
|
||||
model.network_isolation = describe_model["EnableNetworkIsolation"]
|
||||
if (
|
||||
"VpcConfig" in describe_model
|
||||
and "Subnets" in describe_model["VpcConfig"]
|
||||
):
|
||||
model.vpc_config_subnets = describe_model["VpcConfig"]["Subnets"]
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
def __describe_training_job__(self, regional_clients):
|
||||
logger.info("SageMaker - describing training jobs...")
|
||||
try:
|
||||
for training_job in self.sagemaker_training_jobs:
|
||||
regional_client = regional_clients[training_job.region]
|
||||
describe_training_job = regional_client.describe_training_job(
|
||||
TrainingJobName=training_job.name
|
||||
)
|
||||
if "EnableInterContainerTrafficEncryption" in describe_training_job:
|
||||
training_job.container_traffic_encryption = describe_training_job[
|
||||
"EnableInterContainerTrafficEncryption"
|
||||
]
|
||||
if (
|
||||
"ResourceConfig" in describe_training_job
|
||||
and "VolumeKmsKeyId" in describe_training_job["ResourceConfig"]
|
||||
):
|
||||
training_job.volume_kms_key_id = describe_training_job[
|
||||
"ResourceConfig"
|
||||
]["VolumeKmsKeyId"]
|
||||
if "EnableNetworkIsolation" in describe_training_job:
|
||||
training_job.network_isolation = describe_training_job[
|
||||
"EnableNetworkIsolation"
|
||||
]
|
||||
if (
|
||||
"VpcConfig" in describe_training_job
|
||||
and "Subnets" in describe_training_job["VpcConfig"]
|
||||
):
|
||||
training_job.vpc_config_subnets = describe_training_job[
|
||||
"VpcConfig"
|
||||
]["Subnets"]
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
|
||||
class NotebookInstance(BaseModel):
|
||||
name: str
|
||||
region: str
|
||||
arn: str
|
||||
root_access: bool = None
|
||||
subnet_id: str = None
|
||||
direct_internet_access: bool = None
|
||||
kms_key_id: str = None
|
||||
|
||||
|
||||
class Model(BaseModel):
|
||||
name: str
|
||||
region: str
|
||||
arn: str
|
||||
network_isolation: bool = None
|
||||
vpc_config_subnets: list[str] = []
|
||||
|
||||
|
||||
class TrainingJob(BaseModel):
|
||||
name: str
|
||||
region: str
|
||||
arn: str
|
||||
container_traffic_encryption: bool = None
|
||||
volume_kms_key_id: str = None
|
||||
network_isolation: bool = None
|
||||
vpc_config_subnets: list[str] = []
|
||||
194
providers/aws/services/sagemaker/sagemaker_service_test.py
Normal file
194
providers/aws/services/sagemaker/sagemaker_service_test.py
Normal file
@@ -0,0 +1,194 @@
|
||||
from unittest.mock import patch
|
||||
from uuid import uuid4
|
||||
|
||||
import botocore
|
||||
from boto3 import session
|
||||
|
||||
from providers.aws.lib.audit_info.models import AWS_Audit_Info
|
||||
from providers.aws.services.sagemaker.sagemaker_service import SageMaker
|
||||
|
||||
AWS_ACCOUNT_NUMBER = 123456789012
|
||||
AWS_REGION = "eu-west-1"
|
||||
|
||||
test_notebook_instance = "test-notebook-instance"
|
||||
notebook_instance_arn = f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:notebook-instance/{test_notebook_instance}"
|
||||
test_model = "test-model"
|
||||
test_arn_model = (
|
||||
f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:model/{test_model}"
|
||||
)
|
||||
test_training_job = "test-training-job"
|
||||
test_arn_training_job = (
|
||||
f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:training-job/{test_model}"
|
||||
)
|
||||
subnet_id = "subnet-" + str(uuid4())
|
||||
kms_key_id = str(uuid4())
|
||||
|
||||
make_api_call = botocore.client.BaseClient._make_api_call
|
||||
|
||||
|
||||
def mock_make_api_call(self, operation_name, kwarg):
|
||||
if operation_name == "ListNotebookInstances":
|
||||
return {
|
||||
"NotebookInstances": [
|
||||
{
|
||||
"NotebookInstanceName": test_notebook_instance,
|
||||
"NotebookInstanceArn": notebook_instance_arn,
|
||||
},
|
||||
]
|
||||
}
|
||||
if operation_name == "ListModels":
|
||||
return {
|
||||
"Models": [
|
||||
{
|
||||
"ModelName": test_model,
|
||||
"ModelArn": test_arn_model,
|
||||
},
|
||||
]
|
||||
}
|
||||
if operation_name == "ListTrainingJobs":
|
||||
return {
|
||||
"TrainingJobSummaries": [
|
||||
{
|
||||
"TrainingJobName": test_training_job,
|
||||
"TrainingJobArn": test_arn_training_job,
|
||||
},
|
||||
]
|
||||
}
|
||||
if operation_name == "DescribeNotebookInstance":
|
||||
return {
|
||||
"SubnetId": subnet_id,
|
||||
"KmsKeyId": kms_key_id,
|
||||
"DirectInternetAccess": "Enabled",
|
||||
"RootAccess": "Enabled",
|
||||
}
|
||||
if operation_name == "DescribeModel":
|
||||
return {
|
||||
"VpcConfig": {
|
||||
"Subnets": [
|
||||
subnet_id,
|
||||
]
|
||||
},
|
||||
"EnableNetworkIsolation": True,
|
||||
}
|
||||
if operation_name == "DescribeTrainingJob":
|
||||
return {
|
||||
"ResourceConfig": {
|
||||
"VolumeKmsKeyId": kms_key_id,
|
||||
},
|
||||
"VpcConfig": {
|
||||
"Subnets": [
|
||||
subnet_id,
|
||||
]
|
||||
},
|
||||
"EnableNetworkIsolation": True,
|
||||
"EnableInterContainerTrafficEncryption": True,
|
||||
}
|
||||
return make_api_call(self, operation_name, kwarg)
|
||||
|
||||
|
||||
def mock_generate_regional_clients(service, audit_info):
|
||||
regional_client = audit_info.audit_session.client(service, region_name=AWS_REGION)
|
||||
regional_client.region = AWS_REGION
|
||||
return {AWS_REGION: regional_client}
|
||||
|
||||
|
||||
@patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call)
|
||||
@patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.generate_regional_clients",
|
||||
new=mock_generate_regional_clients,
|
||||
)
|
||||
class Test_SageMaker_Service:
|
||||
# Mocked Audit Info
|
||||
def set_mocked_audit_info(self):
|
||||
audit_info = AWS_Audit_Info(
|
||||
original_session=None,
|
||||
audit_session=session.Session(
|
||||
profile_name=None,
|
||||
botocore_session=None,
|
||||
),
|
||||
audited_account=AWS_ACCOUNT_NUMBER,
|
||||
audited_user_id=None,
|
||||
audited_partition="aws",
|
||||
audited_identity_arn=None,
|
||||
profile=None,
|
||||
profile_region=None,
|
||||
credentials=None,
|
||||
assumed_role_info=None,
|
||||
audited_regions=None,
|
||||
organizations_metadata=None,
|
||||
)
|
||||
return audit_info
|
||||
|
||||
# Test SageMaker Service
|
||||
def test_service(self):
|
||||
audit_info = self.set_mocked_audit_info()
|
||||
sagemaker = SageMaker(audit_info)
|
||||
assert sagemaker.service == "sagemaker"
|
||||
|
||||
# Test SageMaker client
|
||||
def test_client(self):
|
||||
audit_info = self.set_mocked_audit_info()
|
||||
sagemaker = SageMaker(audit_info)
|
||||
for reg_client in sagemaker.regional_clients.values():
|
||||
assert reg_client.__class__.__name__ == "SageMaker"
|
||||
|
||||
# Test SageMaker session
|
||||
def test__get_session__(self):
|
||||
audit_info = self.set_mocked_audit_info()
|
||||
sagemaker = SageMaker(audit_info)
|
||||
assert sagemaker.session.__class__.__name__ == "Session"
|
||||
|
||||
# Test SageMaker list notebook instances
|
||||
def test_list_notebook_instances(self):
|
||||
audit_info = self.set_mocked_audit_info()
|
||||
sagemaker = SageMaker(audit_info)
|
||||
assert len(sagemaker.sagemaker_notebook_instances) == 1
|
||||
assert sagemaker.sagemaker_notebook_instances[0].name == test_notebook_instance
|
||||
assert sagemaker.sagemaker_notebook_instances[0].arn == notebook_instance_arn
|
||||
assert sagemaker.sagemaker_notebook_instances[0].region == AWS_REGION
|
||||
|
||||
# Test SageMaker list models
|
||||
def test_list_models(self):
|
||||
audit_info = self.set_mocked_audit_info()
|
||||
sagemaker = SageMaker(audit_info)
|
||||
assert len(sagemaker.sagemaker_models) == 1
|
||||
assert sagemaker.sagemaker_models[0].name == test_model
|
||||
assert sagemaker.sagemaker_models[0].arn == test_arn_model
|
||||
assert sagemaker.sagemaker_models[0].region == AWS_REGION
|
||||
|
||||
# Test SageMaker list training jobs
|
||||
def test_list_training_jobs(self):
|
||||
audit_info = self.set_mocked_audit_info()
|
||||
sagemaker = SageMaker(audit_info)
|
||||
assert len(sagemaker.sagemaker_training_jobs) == 1
|
||||
assert sagemaker.sagemaker_training_jobs[0].name == test_training_job
|
||||
assert sagemaker.sagemaker_training_jobs[0].arn == test_arn_training_job
|
||||
assert sagemaker.sagemaker_training_jobs[0].region == AWS_REGION
|
||||
|
||||
# Test SageMaker describe notebook instance
|
||||
def test_describe_notebook_instance(self):
|
||||
audit_info = self.set_mocked_audit_info()
|
||||
sagemaker = SageMaker(audit_info)
|
||||
assert len(sagemaker.sagemaker_notebook_instances) == 1
|
||||
assert sagemaker.sagemaker_notebook_instances[0].root_access
|
||||
assert sagemaker.sagemaker_notebook_instances[0].subnet_id == subnet_id
|
||||
assert sagemaker.sagemaker_notebook_instances[0].direct_internet_access
|
||||
assert sagemaker.sagemaker_notebook_instances[0].kms_key_id == kms_key_id
|
||||
|
||||
# Test SageMaker describe model
|
||||
def test_describe_model(self):
|
||||
audit_info = self.set_mocked_audit_info()
|
||||
sagemaker = SageMaker(audit_info)
|
||||
assert len(sagemaker.sagemaker_models) == 1
|
||||
assert sagemaker.sagemaker_models[0].network_isolation
|
||||
assert sagemaker.sagemaker_models[0].vpc_config_subnets == [subnet_id]
|
||||
|
||||
# Test SageMaker describe training jobs
|
||||
def test_describe_training_jobs(self):
|
||||
audit_info = self.set_mocked_audit_info()
|
||||
sagemaker = SageMaker(audit_info)
|
||||
assert len(sagemaker.sagemaker_training_jobs) == 1
|
||||
assert sagemaker.sagemaker_training_jobs[0].container_traffic_encryption
|
||||
assert sagemaker.sagemaker_training_jobs[0].network_isolation
|
||||
assert sagemaker.sagemaker_training_jobs[0].volume_kms_key_id == kms_key_id
|
||||
assert sagemaker.sagemaker_training_jobs[0].vpc_config_subnets == [subnet_id]
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "sagemaker_training_jobs_intercontainer_encryption_enabled",
|
||||
"CheckTitle": "Check if Amazon SageMaker Training jobs have intercontainer encryption enabled",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sagemaker",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:aws:sagemaker:region:account-id:training-job",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsSageMakerTrainingJob",
|
||||
"Description": "Check if Amazon SageMaker Training jobs have intercontainer encryption enabled",
|
||||
"Risk": "If not restricted unintended access could happen.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/sagemaker/latest/dg/interface-vpc-endpoint.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Internetwork communications support TLS 1.2 encryption between all components and clients.",
|
||||
"Url": "https://docs.aws.amazon.com/sagemaker/latest/dg/interface-vpc-endpoint.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.sagemaker.sagemaker_client import sagemaker_client
|
||||
|
||||
|
||||
class sagemaker_training_jobs_intercontainer_encryption_enabled(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for training_job in sagemaker_client.sagemaker_training_jobs:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = training_job.region
|
||||
report.resource_id = training_job.name
|
||||
report.resource_arn = training_job.arn
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Sagemaker training job {training_job.name} has intercontainer encryption enabled"
|
||||
if not training_job.container_traffic_encryption:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Sagemaker training job {training_job.name} has intercontainer encryption disabled"
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,84 @@
|
||||
from re import search
|
||||
from unittest import mock
|
||||
|
||||
from providers.aws.services.sagemaker.sagemaker_service import TrainingJob
|
||||
|
||||
AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
test_training_job = "test-training-job"
|
||||
training_job_arn = f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:training-job/{test_training_job}"
|
||||
|
||||
|
||||
class Test_sagemaker_training_jobs_intercontainer_encryption_enabled:
|
||||
def test_no_training_jobs(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_training_jobs = []
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_training_jobs_intercontainer_encryption_enabled.sagemaker_training_jobs_intercontainer_encryption_enabled import (
|
||||
sagemaker_training_jobs_intercontainer_encryption_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_training_jobs_intercontainer_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_traffic_encryption_enabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_training_jobs = []
|
||||
sagemaker_client.sagemaker_training_jobs.append(
|
||||
TrainingJob(
|
||||
name=test_training_job,
|
||||
arn=training_job_arn,
|
||||
region=AWS_REGION,
|
||||
container_traffic_encryption=True,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_training_jobs_intercontainer_encryption_enabled.sagemaker_training_jobs_intercontainer_encryption_enabled import (
|
||||
sagemaker_training_jobs_intercontainer_encryption_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_training_jobs_intercontainer_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search(
|
||||
"has intercontainer encryption enabled", result[0].status_extended
|
||||
)
|
||||
assert result[0].resource_id == test_training_job
|
||||
assert result[0].resource_arn == training_job_arn
|
||||
|
||||
def test_instance_traffic_encryption_disabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_training_jobs = []
|
||||
sagemaker_client.sagemaker_training_jobs.append(
|
||||
TrainingJob(
|
||||
name=test_training_job,
|
||||
arn=training_job_arn,
|
||||
region=AWS_REGION,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_training_jobs_intercontainer_encryption_enabled.sagemaker_training_jobs_intercontainer_encryption_enabled import (
|
||||
sagemaker_training_jobs_intercontainer_encryption_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_training_jobs_intercontainer_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert search(
|
||||
"has intercontainer encryption disabled", result[0].status_extended
|
||||
)
|
||||
assert result[0].resource_id == test_training_job
|
||||
assert result[0].resource_arn == training_job_arn
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "sagemaker_training_jobs_network_isolation_enabled",
|
||||
"CheckTitle": "Check if Amazon SageMaker Training jobs have network isolation enabled",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sagemaker",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:aws:sagemaker:region:account-id:training-job",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsSageMakerTrainingJob",
|
||||
"Description": "Check if Amazon SageMaker Training jobs have network isolation enabled",
|
||||
"Risk": "This could provide an avenue for unauthorized access to your data.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/sagemaker/latest/dg/interface-vpc-endpoint.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Restrict which traffic can access by launching Studio in a Virtual Private Cloud (VPC) of your choosing.",
|
||||
"Url": "https://docs.aws.amazon.com/sagemaker/latest/dg/interface-vpc-endpoint.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.sagemaker.sagemaker_client import sagemaker_client
|
||||
|
||||
|
||||
class sagemaker_training_jobs_network_isolation_enabled(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for training_job in sagemaker_client.sagemaker_training_jobs:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = training_job.region
|
||||
report.resource_id = training_job.name
|
||||
report.resource_arn = training_job.arn
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Sagemaker training job {training_job.name} has network isolation enabled"
|
||||
if not training_job.network_isolation:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Sagemaker training job {training_job.name} has network isolation disabled"
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,82 @@
|
||||
from re import search
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from providers.aws.services.sagemaker.sagemaker_service import TrainingJob
|
||||
|
||||
AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
test_training_job = "test-training-job"
|
||||
training_job_arn = f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:training-job/{test_training_job}"
|
||||
kms_key_id = str(uuid4())
|
||||
|
||||
|
||||
class Test_sagemaker_training_jobs_network_isolation_enabled:
|
||||
def test_no_training_jobs(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_training_jobs = []
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_training_jobs_network_isolation_enabled.sagemaker_training_jobs_network_isolation_enabled import (
|
||||
sagemaker_training_jobs_network_isolation_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_training_jobs_network_isolation_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_traffic_encryption_enabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_training_jobs = []
|
||||
sagemaker_client.sagemaker_training_jobs.append(
|
||||
TrainingJob(
|
||||
name=test_training_job,
|
||||
arn=training_job_arn,
|
||||
region=AWS_REGION,
|
||||
network_isolation=True,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_training_jobs_network_isolation_enabled.sagemaker_training_jobs_network_isolation_enabled import (
|
||||
sagemaker_training_jobs_network_isolation_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_training_jobs_network_isolation_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search("has network isolation enabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_training_job
|
||||
assert result[0].resource_arn == training_job_arn
|
||||
|
||||
def test_instance_traffic_encryption_disabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_training_jobs = []
|
||||
sagemaker_client.sagemaker_training_jobs.append(
|
||||
TrainingJob(
|
||||
name=test_training_job,
|
||||
arn=training_job_arn,
|
||||
region=AWS_REGION,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_training_jobs_network_isolation_enabled.sagemaker_training_jobs_network_isolation_enabled import (
|
||||
sagemaker_training_jobs_network_isolation_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_training_jobs_network_isolation_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert search("has network isolation disabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_training_job
|
||||
assert result[0].resource_arn == training_job_arn
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "sagemaker_training_jobs_volume_and_output_encryption_enabled",
|
||||
"CheckTitle": "Check if Amazon SageMaker Training jobs have volume and output with KMS encryption enabled",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sagemaker",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:aws:sagemaker:region:account-id:training-job",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsSageMakerTrainingJob",
|
||||
"Description": "Check if Amazon SageMaker Training jobs have volume and output with KMS encryption enabled",
|
||||
"Risk": "Data exfiltration could happen if information is not protected. KMS keys provide additional security level to IAM policies.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/sagemaker/latest/dg/key-management.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Specify AWS KMS keys to use for input and output from S3 and EBS.",
|
||||
"Url": "https://docs.aws.amazon.com/sagemaker/latest/dg/key-management.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.sagemaker.sagemaker_client import sagemaker_client
|
||||
|
||||
|
||||
class sagemaker_training_jobs_volume_and_output_encryption_enabled(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for training_job in sagemaker_client.sagemaker_training_jobs:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = training_job.region
|
||||
report.resource_id = training_job.name
|
||||
report.resource_arn = training_job.arn
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Sagemaker training job {training_job.name} has KMS encryption enabled"
|
||||
)
|
||||
if not training_job.volume_kms_key_id:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Sagemaker training job {training_job.name} has KMS encryption disabled"
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,82 @@
|
||||
from re import search
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from providers.aws.services.sagemaker.sagemaker_service import TrainingJob
|
||||
|
||||
AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
test_training_job = "test-training-job"
|
||||
training_job_arn = f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:training-job/{test_training_job}"
|
||||
kms_key_id = str(uuid4())
|
||||
|
||||
|
||||
class Test_sagemaker_training_jobs_volume_and_output_encryption_enabled:
|
||||
def test_no_training_jobs(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_training_jobs = []
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_training_jobs_volume_and_output_encryption_enabled.sagemaker_training_jobs_volume_and_output_encryption_enabled import (
|
||||
sagemaker_training_jobs_volume_and_output_encryption_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_training_jobs_volume_and_output_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_traffic_encryption_enabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_training_jobs = []
|
||||
sagemaker_client.sagemaker_training_jobs.append(
|
||||
TrainingJob(
|
||||
name=test_training_job,
|
||||
arn=training_job_arn,
|
||||
region=AWS_REGION,
|
||||
volume_kms_key_id=kms_key_id,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_training_jobs_volume_and_output_encryption_enabled.sagemaker_training_jobs_volume_and_output_encryption_enabled import (
|
||||
sagemaker_training_jobs_volume_and_output_encryption_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_training_jobs_volume_and_output_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search("has KMS encryption enabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_training_job
|
||||
assert result[0].resource_arn == training_job_arn
|
||||
|
||||
def test_instance_traffic_encryption_disabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_training_jobs = []
|
||||
sagemaker_client.sagemaker_training_jobs.append(
|
||||
TrainingJob(
|
||||
name=test_training_job,
|
||||
arn=training_job_arn,
|
||||
region=AWS_REGION,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_training_jobs_volume_and_output_encryption_enabled.sagemaker_training_jobs_volume_and_output_encryption_enabled import (
|
||||
sagemaker_training_jobs_volume_and_output_encryption_enabled,
|
||||
)
|
||||
|
||||
check = sagemaker_training_jobs_volume_and_output_encryption_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert search("has KMS encryption disabled", result[0].status_extended)
|
||||
assert result[0].resource_id == test_training_job
|
||||
assert result[0].resource_arn == training_job_arn
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "sagemaker_training_jobs_vpc_settings_configured",
|
||||
"CheckTitle": "Check if Amazon SageMaker Training job have VPC settings configured.",
|
||||
"CheckType": [],
|
||||
"ServiceName": "sagemaker",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:aws:sagemaker:region:account-id:training-job",
|
||||
"Severity": "medium",
|
||||
"ResourceType": "AwsSageMakerTrainingJob",
|
||||
"Description": "Check if Amazon SageMaker Training job have VPC settings configured.",
|
||||
"Risk": "This could provide an avenue for unauthorized access to your data.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/sagemaker/latest/dg/interface-vpc-endpoint.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Restrict which traffic can access by launching Studio in a Virtual Private Cloud (VPC) of your choosing.",
|
||||
"Url": "https://docs.aws.amazon.com/sagemaker/latest/dg/interface-vpc-endpoint.html"
|
||||
}
|
||||
},
|
||||
"Categories": [],
|
||||
"Tags": {
|
||||
"Tag1Key": "value",
|
||||
"Tag2Key": "value"
|
||||
},
|
||||
"DependsOn": [],
|
||||
"RelatedTo": [],
|
||||
"Notes": "",
|
||||
"Compliance": []
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
from lib.check.models import Check, Check_Report
|
||||
from providers.aws.services.sagemaker.sagemaker_client import sagemaker_client
|
||||
|
||||
|
||||
class sagemaker_training_jobs_vpc_settings_configured(Check):
|
||||
def execute(self):
|
||||
findings = []
|
||||
for training_job in sagemaker_client.sagemaker_training_jobs:
|
||||
report = Check_Report(self.metadata)
|
||||
report.region = training_job.region
|
||||
report.resource_id = training_job.name
|
||||
report.resource_arn = training_job.arn
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Sagemaker training job {training_job.name} has VPC settings for the training job volume and output enabled"
|
||||
if not training_job.vpc_config_subnets:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Sagemaker training job {training_job.name} has VPC settings for the training job volume and output disabled"
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
@@ -0,0 +1,88 @@
|
||||
from re import search
|
||||
from unittest import mock
|
||||
from uuid import uuid4
|
||||
|
||||
from providers.aws.services.sagemaker.sagemaker_service import TrainingJob
|
||||
|
||||
AWS_REGION = "eu-west-1"
|
||||
AWS_ACCOUNT_NUMBER = "123456789012"
|
||||
|
||||
test_training_job = "test-training-job"
|
||||
training_job_arn = f"arn:aws:sagemaker:{AWS_REGION}:{AWS_ACCOUNT_NUMBER}:training-job/{test_training_job}"
|
||||
subnet_id = "subnet-" + str(uuid4())
|
||||
|
||||
|
||||
class Test_sagemaker_training_jobs_vpc_settings_configured:
|
||||
def test_no_training_jobs(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_training_jobs = []
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_training_jobs_vpc_settings_configured.sagemaker_training_jobs_vpc_settings_configured import (
|
||||
sagemaker_training_jobs_vpc_settings_configured,
|
||||
)
|
||||
|
||||
check = sagemaker_training_jobs_vpc_settings_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_instance_traffic_encryption_enabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_training_jobs = []
|
||||
sagemaker_client.sagemaker_training_jobs.append(
|
||||
TrainingJob(
|
||||
name=test_training_job,
|
||||
arn=training_job_arn,
|
||||
region=AWS_REGION,
|
||||
vpc_config_subnets=[subnet_id],
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_training_jobs_vpc_settings_configured.sagemaker_training_jobs_vpc_settings_configured import (
|
||||
sagemaker_training_jobs_vpc_settings_configured,
|
||||
)
|
||||
|
||||
check = sagemaker_training_jobs_vpc_settings_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert search(
|
||||
"has VPC settings for the training job volume and output enabled",
|
||||
result[0].status_extended,
|
||||
)
|
||||
assert result[0].resource_id == test_training_job
|
||||
assert result[0].resource_arn == training_job_arn
|
||||
|
||||
def test_instance_traffic_encryption_disabled(self):
|
||||
sagemaker_client = mock.MagicMock
|
||||
sagemaker_client.sagemaker_training_jobs = []
|
||||
sagemaker_client.sagemaker_training_jobs.append(
|
||||
TrainingJob(
|
||||
name=test_training_job,
|
||||
arn=training_job_arn,
|
||||
region=AWS_REGION,
|
||||
)
|
||||
)
|
||||
with mock.patch(
|
||||
"providers.aws.services.sagemaker.sagemaker_service.SageMaker",
|
||||
sagemaker_client,
|
||||
):
|
||||
from providers.aws.services.sagemaker.sagemaker_training_jobs_vpc_settings_configured.sagemaker_training_jobs_vpc_settings_configured import (
|
||||
sagemaker_training_jobs_vpc_settings_configured,
|
||||
)
|
||||
|
||||
check = sagemaker_training_jobs_vpc_settings_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert search(
|
||||
"has VPC settings for the training job volume and output disabled",
|
||||
result[0].status_extended,
|
||||
)
|
||||
assert result[0].resource_id == test_training_job
|
||||
assert result[0].resource_arn == training_job_arn
|
||||
Reference in New Issue
Block a user