From daa299c7a67cc6f064b5181ba5bd27ba91053d6a Mon Sep 17 00:00:00 2001 From: Nacho Rivera <59198746+n4ch04@users.noreply.github.com> Date: Thu, 17 Nov 2022 12:56:36 +0100 Subject: [PATCH] feat(): Sagemaker service and checks (#1490) Co-authored-by: sergargar --- providers/aws/services/sagemaker/__init__.py | 0 .../aws/services/sagemaker/check_extra7103 | 47 ---- .../aws/services/sagemaker/check_extra7104 | 47 ---- .../aws/services/sagemaker/check_extra7105 | 47 ---- .../aws/services/sagemaker/check_extra7106 | 47 ---- .../aws/services/sagemaker/check_extra7107 | 47 ---- .../aws/services/sagemaker/check_extra7108 | 47 ---- .../aws/services/sagemaker/check_extra7109 | 47 ---- .../aws/services/sagemaker/check_extra7110 | 47 ---- .../aws/services/sagemaker/check_extra7111 | 47 ---- .../aws/services/sagemaker/check_extra7112 | 47 ---- .../services/sagemaker/sagemaker_client.py | 4 + .../__init__.py | 0 ...ls_network_isolation_enabled.metadata.json | 35 +++ ...emaker_models_network_isolation_enabled.py | 21 ++ ...r_models_network_isolation_enabled_test.py | 83 +++++++ .../__init__.py | 0 ...dels_vpc_settings_configured.metadata.json | 35 +++ ...agemaker_models_vpc_settings_configured.py | 23 ++ ...ker_models_vpc_settings_configured_test.py | 82 +++++++ .../__init__.py | 0 ..._instance_encryption_enabled.metadata.json | 35 +++ ...er_notebook_instance_encryption_enabled.py | 21 ++ ...tebook_instance_encryption_enabled_test.py | 82 +++++++ .../__init__.py | 0 ...nstance_root_access_disabled.metadata.json | 35 +++ ..._notebook_instance_root_access_disabled.py | 21 ++ ...book_instance_root_access_disabled_test.py | 81 +++++++ .../__init__.py | 0 ...ance_vpc_settings_configured.metadata.json | 35 +++ ...tebook_instance_vpc_settings_configured.py | 23 ++ ...k_instance_vpc_settings_configured_test.py | 83 +++++++ .../__init__.py | 0 ...t_internet_access_configured.metadata.json | 35 +++ ...thout_direct_internet_access_configured.py | 21 ++ ..._direct_internet_access_configured_test.py | 91 ++++++++ .../services/sagemaker/sagemaker_service.py | 203 ++++++++++++++++++ .../sagemaker/sagemaker_service_test.py | 194 +++++++++++++++++ .../__init__.py | 0 ...container_encryption_enabled.metadata.json | 35 +++ ..._jobs_intercontainer_encryption_enabled.py | 21 ++ ..._intercontainer_encryption_enabled_test.py | 84 ++++++++ .../__init__.py | 0 ...bs_network_isolation_enabled.metadata.json | 35 +++ ...training_jobs_network_isolation_enabled.py | 21 ++ ...ing_jobs_network_isolation_enabled_test.py | 82 +++++++ .../__init__.py | 0 ...nd_output_encryption_enabled.metadata.json | 35 +++ ...bs_volume_and_output_encryption_enabled.py | 23 ++ ...lume_and_output_encryption_enabled_test.py | 82 +++++++ .../__init__.py | 0 ...jobs_vpc_settings_configured.metadata.json | 35 +++ ...r_training_jobs_vpc_settings_configured.py | 21 ++ ...ining_jobs_vpc_settings_configured_test.py | 88 ++++++++ 54 files changed, 1805 insertions(+), 470 deletions(-) create mode 100644 providers/aws/services/sagemaker/__init__.py delete mode 100644 providers/aws/services/sagemaker/check_extra7103 delete mode 100644 providers/aws/services/sagemaker/check_extra7104 delete mode 100644 providers/aws/services/sagemaker/check_extra7105 delete mode 100644 providers/aws/services/sagemaker/check_extra7106 delete mode 100644 providers/aws/services/sagemaker/check_extra7107 delete mode 100644 providers/aws/services/sagemaker/check_extra7108 delete mode 100644 providers/aws/services/sagemaker/check_extra7109 delete mode 100644 providers/aws/services/sagemaker/check_extra7110 delete mode 100644 providers/aws/services/sagemaker/check_extra7111 delete mode 100644 providers/aws/services/sagemaker/check_extra7112 create mode 100644 providers/aws/services/sagemaker/sagemaker_client.py create mode 100644 providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/__init__.py create mode 100644 providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/sagemaker_models_network_isolation_enabled.metadata.json create mode 100644 providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/sagemaker_models_network_isolation_enabled.py create mode 100644 providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/sagemaker_models_network_isolation_enabled_test.py create mode 100644 providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/__init__.py create mode 100644 providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/sagemaker_models_vpc_settings_configured.metadata.json create mode 100644 providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/sagemaker_models_vpc_settings_configured.py create mode 100644 providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/sagemaker_models_vpc_settings_configured_test.py create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/__init__.py create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/sagemaker_notebook_instance_encryption_enabled.metadata.json create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/sagemaker_notebook_instance_encryption_enabled.py create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/sagemaker_notebook_instance_encryption_enabled_test.py create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/__init__.py create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/sagemaker_notebook_instance_root_access_disabled.metadata.json create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/sagemaker_notebook_instance_root_access_disabled.py create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/sagemaker_notebook_instance_root_access_disabled_test.py create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/__init__.py create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/sagemaker_notebook_instance_vpc_settings_configured.metadata.json create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/sagemaker_notebook_instance_vpc_settings_configured.py create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/sagemaker_notebook_instance_vpc_settings_configured_test.py create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/__init__.py create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/sagemaker_notebook_instance_without_direct_internet_access_configured.metadata.json create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/sagemaker_notebook_instance_without_direct_internet_access_configured.py create mode 100644 providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/sagemaker_notebook_instance_without_direct_internet_access_configured_test.py create mode 100644 providers/aws/services/sagemaker/sagemaker_service.py create mode 100644 providers/aws/services/sagemaker/sagemaker_service_test.py create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/__init__.py create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/sagemaker_training_jobs_intercontainer_encryption_enabled.metadata.json create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/sagemaker_training_jobs_intercontainer_encryption_enabled.py create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/sagemaker_training_jobs_intercontainer_encryption_enabled_test.py create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/__init__.py create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/sagemaker_training_jobs_network_isolation_enabled.metadata.json create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/sagemaker_training_jobs_network_isolation_enabled.py create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/sagemaker_training_jobs_network_isolation_enabled_test.py create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/__init__.py create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/sagemaker_training_jobs_volume_and_output_encryption_enabled.metadata.json create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/sagemaker_training_jobs_volume_and_output_encryption_enabled.py create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/sagemaker_training_jobs_volume_and_output_encryption_enabled_test.py create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/__init__.py create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/sagemaker_training_jobs_vpc_settings_configured.metadata.json create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/sagemaker_training_jobs_vpc_settings_configured.py create mode 100644 providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/sagemaker_training_jobs_vpc_settings_configured_test.py diff --git a/providers/aws/services/sagemaker/__init__.py b/providers/aws/services/sagemaker/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/sagemaker/check_extra7103 b/providers/aws/services/sagemaker/check_extra7103 deleted file mode 100644 index 33f4fd87..00000000 --- a/providers/aws/services/sagemaker/check_extra7103 +++ /dev/null @@ -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 -} diff --git a/providers/aws/services/sagemaker/check_extra7104 b/providers/aws/services/sagemaker/check_extra7104 deleted file mode 100644 index 7677db48..00000000 --- a/providers/aws/services/sagemaker/check_extra7104 +++ /dev/null @@ -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 -} diff --git a/providers/aws/services/sagemaker/check_extra7105 b/providers/aws/services/sagemaker/check_extra7105 deleted file mode 100644 index cbff235d..00000000 --- a/providers/aws/services/sagemaker/check_extra7105 +++ /dev/null @@ -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 -} diff --git a/providers/aws/services/sagemaker/check_extra7106 b/providers/aws/services/sagemaker/check_extra7106 deleted file mode 100644 index be3d5d7f..00000000 --- a/providers/aws/services/sagemaker/check_extra7106 +++ /dev/null @@ -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 -} diff --git a/providers/aws/services/sagemaker/check_extra7107 b/providers/aws/services/sagemaker/check_extra7107 deleted file mode 100644 index 19ad16f5..00000000 --- a/providers/aws/services/sagemaker/check_extra7107 +++ /dev/null @@ -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 -} diff --git a/providers/aws/services/sagemaker/check_extra7108 b/providers/aws/services/sagemaker/check_extra7108 deleted file mode 100644 index 5f4311f5..00000000 --- a/providers/aws/services/sagemaker/check_extra7108 +++ /dev/null @@ -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 -} diff --git a/providers/aws/services/sagemaker/check_extra7109 b/providers/aws/services/sagemaker/check_extra7109 deleted file mode 100644 index 55c66afc..00000000 --- a/providers/aws/services/sagemaker/check_extra7109 +++ /dev/null @@ -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 -} diff --git a/providers/aws/services/sagemaker/check_extra7110 b/providers/aws/services/sagemaker/check_extra7110 deleted file mode 100644 index 9d4d8d0f..00000000 --- a/providers/aws/services/sagemaker/check_extra7110 +++ /dev/null @@ -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 -} diff --git a/providers/aws/services/sagemaker/check_extra7111 b/providers/aws/services/sagemaker/check_extra7111 deleted file mode 100644 index 2e632f21..00000000 --- a/providers/aws/services/sagemaker/check_extra7111 +++ /dev/null @@ -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 -} diff --git a/providers/aws/services/sagemaker/check_extra7112 b/providers/aws/services/sagemaker/check_extra7112 deleted file mode 100644 index 78ae27ad..00000000 --- a/providers/aws/services/sagemaker/check_extra7112 +++ /dev/null @@ -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 -} diff --git a/providers/aws/services/sagemaker/sagemaker_client.py b/providers/aws/services/sagemaker/sagemaker_client.py new file mode 100644 index 00000000..395d7b3f --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_client.py @@ -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) diff --git a/providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/__init__.py b/providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/sagemaker_models_network_isolation_enabled.metadata.json b/providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/sagemaker_models_network_isolation_enabled.metadata.json new file mode 100644 index 00000000..e3e3a804 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/sagemaker_models_network_isolation_enabled.metadata.json @@ -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": [] + } diff --git a/providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/sagemaker_models_network_isolation_enabled.py b/providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/sagemaker_models_network_isolation_enabled.py new file mode 100644 index 00000000..af6b4722 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/sagemaker_models_network_isolation_enabled.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/sagemaker_models_network_isolation_enabled_test.py b/providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/sagemaker_models_network_isolation_enabled_test.py new file mode 100644 index 00000000..e8bb645a --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_models_network_isolation_enabled/sagemaker_models_network_isolation_enabled_test.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/__init__.py b/providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/sagemaker_models_vpc_settings_configured.metadata.json b/providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/sagemaker_models_vpc_settings_configured.metadata.json new file mode 100644 index 00000000..07bb1085 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/sagemaker_models_vpc_settings_configured.metadata.json @@ -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": [] + } diff --git a/providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/sagemaker_models_vpc_settings_configured.py b/providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/sagemaker_models_vpc_settings_configured.py new file mode 100644 index 00000000..93beaa37 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/sagemaker_models_vpc_settings_configured.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/sagemaker_models_vpc_settings_configured_test.py b/providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/sagemaker_models_vpc_settings_configured_test.py new file mode 100644 index 00000000..293c3a1b --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_models_vpc_settings_configured/sagemaker_models_vpc_settings_configured_test.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/__init__.py b/providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/sagemaker_notebook_instance_encryption_enabled.metadata.json b/providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/sagemaker_notebook_instance_encryption_enabled.metadata.json new file mode 100644 index 00000000..3d146192 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/sagemaker_notebook_instance_encryption_enabled.metadata.json @@ -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": [] + } diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/sagemaker_notebook_instance_encryption_enabled.py b/providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/sagemaker_notebook_instance_encryption_enabled.py new file mode 100644 index 00000000..c3c7b63b --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/sagemaker_notebook_instance_encryption_enabled.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/sagemaker_notebook_instance_encryption_enabled_test.py b/providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/sagemaker_notebook_instance_encryption_enabled_test.py new file mode 100644 index 00000000..01bfccfb --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_notebook_instance_encryption_enabled/sagemaker_notebook_instance_encryption_enabled_test.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/__init__.py b/providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/sagemaker_notebook_instance_root_access_disabled.metadata.json b/providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/sagemaker_notebook_instance_root_access_disabled.metadata.json new file mode 100644 index 00000000..726bf706 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/sagemaker_notebook_instance_root_access_disabled.metadata.json @@ -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": [] + } diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/sagemaker_notebook_instance_root_access_disabled.py b/providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/sagemaker_notebook_instance_root_access_disabled.py new file mode 100644 index 00000000..a41d4c6c --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/sagemaker_notebook_instance_root_access_disabled.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/sagemaker_notebook_instance_root_access_disabled_test.py b/providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/sagemaker_notebook_instance_root_access_disabled_test.py new file mode 100644 index 00000000..e44cfcef --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_notebook_instance_root_access_disabled/sagemaker_notebook_instance_root_access_disabled_test.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/__init__.py b/providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/sagemaker_notebook_instance_vpc_settings_configured.metadata.json b/providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/sagemaker_notebook_instance_vpc_settings_configured.metadata.json new file mode 100644 index 00000000..0e20b6f7 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/sagemaker_notebook_instance_vpc_settings_configured.metadata.json @@ -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": [] + } diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/sagemaker_notebook_instance_vpc_settings_configured.py b/providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/sagemaker_notebook_instance_vpc_settings_configured.py new file mode 100644 index 00000000..ad33584e --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/sagemaker_notebook_instance_vpc_settings_configured.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/sagemaker_notebook_instance_vpc_settings_configured_test.py b/providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/sagemaker_notebook_instance_vpc_settings_configured_test.py new file mode 100644 index 00000000..ca2a0244 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_notebook_instance_vpc_settings_configured/sagemaker_notebook_instance_vpc_settings_configured_test.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/__init__.py b/providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/sagemaker_notebook_instance_without_direct_internet_access_configured.metadata.json b/providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/sagemaker_notebook_instance_without_direct_internet_access_configured.metadata.json new file mode 100644 index 00000000..6d7d4ec0 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/sagemaker_notebook_instance_without_direct_internet_access_configured.metadata.json @@ -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": [] + } diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/sagemaker_notebook_instance_without_direct_internet_access_configured.py b/providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/sagemaker_notebook_instance_without_direct_internet_access_configured.py new file mode 100644 index 00000000..880e40be --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/sagemaker_notebook_instance_without_direct_internet_access_configured.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/sagemaker_notebook_instance_without_direct_internet_access_configured_test.py b/providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/sagemaker_notebook_instance_without_direct_internet_access_configured_test.py new file mode 100644 index 00000000..383cef31 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_notebook_instance_without_direct_internet_access_configured/sagemaker_notebook_instance_without_direct_internet_access_configured_test.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_service.py b/providers/aws/services/sagemaker/sagemaker_service.py new file mode 100644 index 00000000..3aa16be6 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_service.py @@ -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] = [] diff --git a/providers/aws/services/sagemaker/sagemaker_service_test.py b/providers/aws/services/sagemaker/sagemaker_service_test.py new file mode 100644 index 00000000..f0b231f9 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_service_test.py @@ -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] diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/__init__.py b/providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/sagemaker_training_jobs_intercontainer_encryption_enabled.metadata.json b/providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/sagemaker_training_jobs_intercontainer_encryption_enabled.metadata.json new file mode 100644 index 00000000..3d25efdf --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/sagemaker_training_jobs_intercontainer_encryption_enabled.metadata.json @@ -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": [] + } diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/sagemaker_training_jobs_intercontainer_encryption_enabled.py b/providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/sagemaker_training_jobs_intercontainer_encryption_enabled.py new file mode 100644 index 00000000..caeb4d2a --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/sagemaker_training_jobs_intercontainer_encryption_enabled.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/sagemaker_training_jobs_intercontainer_encryption_enabled_test.py b/providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/sagemaker_training_jobs_intercontainer_encryption_enabled_test.py new file mode 100644 index 00000000..27d3d4e2 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_training_jobs_intercontainer_encryption_enabled/sagemaker_training_jobs_intercontainer_encryption_enabled_test.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/__init__.py b/providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/sagemaker_training_jobs_network_isolation_enabled.metadata.json b/providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/sagemaker_training_jobs_network_isolation_enabled.metadata.json new file mode 100644 index 00000000..2f011ed5 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/sagemaker_training_jobs_network_isolation_enabled.metadata.json @@ -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": [] + } diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/sagemaker_training_jobs_network_isolation_enabled.py b/providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/sagemaker_training_jobs_network_isolation_enabled.py new file mode 100644 index 00000000..c26ea22b --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/sagemaker_training_jobs_network_isolation_enabled.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/sagemaker_training_jobs_network_isolation_enabled_test.py b/providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/sagemaker_training_jobs_network_isolation_enabled_test.py new file mode 100644 index 00000000..c5272dc5 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_training_jobs_network_isolation_enabled/sagemaker_training_jobs_network_isolation_enabled_test.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/__init__.py b/providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/sagemaker_training_jobs_volume_and_output_encryption_enabled.metadata.json b/providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/sagemaker_training_jobs_volume_and_output_encryption_enabled.metadata.json new file mode 100644 index 00000000..bd62fb55 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/sagemaker_training_jobs_volume_and_output_encryption_enabled.metadata.json @@ -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": [] + } diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/sagemaker_training_jobs_volume_and_output_encryption_enabled.py b/providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/sagemaker_training_jobs_volume_and_output_encryption_enabled.py new file mode 100644 index 00000000..d6ab7e9e --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/sagemaker_training_jobs_volume_and_output_encryption_enabled.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/sagemaker_training_jobs_volume_and_output_encryption_enabled_test.py b/providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/sagemaker_training_jobs_volume_and_output_encryption_enabled_test.py new file mode 100644 index 00000000..43d1ac64 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_training_jobs_volume_and_output_encryption_enabled/sagemaker_training_jobs_volume_and_output_encryption_enabled_test.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/__init__.py b/providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/sagemaker_training_jobs_vpc_settings_configured.metadata.json b/providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/sagemaker_training_jobs_vpc_settings_configured.metadata.json new file mode 100644 index 00000000..f3928956 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/sagemaker_training_jobs_vpc_settings_configured.metadata.json @@ -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": [] + } diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/sagemaker_training_jobs_vpc_settings_configured.py b/providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/sagemaker_training_jobs_vpc_settings_configured.py new file mode 100644 index 00000000..6cf85182 --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/sagemaker_training_jobs_vpc_settings_configured.py @@ -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 diff --git a/providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/sagemaker_training_jobs_vpc_settings_configured_test.py b/providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/sagemaker_training_jobs_vpc_settings_configured_test.py new file mode 100644 index 00000000..f473909e --- /dev/null +++ b/providers/aws/services/sagemaker/sagemaker_training_jobs_vpc_settings_configured/sagemaker_training_jobs_vpc_settings_configured_test.py @@ -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