From e2a8fa87383d0a7b57f493b090c8940dfb0dd254 Mon Sep 17 00:00:00 2001
From: Nacho Rivera <59198746+n4ch04@users.noreply.github.com>
Date: Tue, 18 Oct 2022 13:23:50 +0200
Subject: [PATCH] feat(iam_check_saml_providers_sts): Check and test (#1413)
---
providers/aws/services/iam/check_extra733 | 37 ------------
.../iam_check_saml_providers_sts/__init__.py | 0
...iam_check_saml_providers_sts.metadata.json | 35 +++++++++++
.../iam_check_saml_providers_sts.py | 18 ++++++
.../iam_check_saml_providers_sts_test.py | 58 +++++++++++++++++++
providers/aws/services/iam/iam_service.py | 11 ++++
.../aws/services/iam/iam_service_test.py | 44 ++++++++++++++
7 files changed, 166 insertions(+), 37 deletions(-)
delete mode 100644 providers/aws/services/iam/check_extra733
create mode 100644 providers/aws/services/iam/iam_check_saml_providers_sts/__init__.py
create mode 100644 providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts.metadata.json
create mode 100644 providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts.py
create mode 100644 providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts_test.py
diff --git a/providers/aws/services/iam/check_extra733 b/providers/aws/services/iam/check_extra733
deleted file mode 100644
index 4359bddb..00000000
--- a/providers/aws/services/iam/check_extra733
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env bash
-
-# Prowler - the handy cloud security tool (copyright 2018) 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_extra733="7.33"
-CHECK_TITLE_extra733="[extra733] Check if there are SAML Providers then STS can be used"
-CHECK_SCORED_extra733="NOT_SCORED"
-CHECK_CIS_LEVEL_extra733="EXTRA"
-CHECK_SEVERITY_extra733="Low"
-CHECK_ALTERNATE_check733="extra733"
-CHECK_ASFF_COMPLIANCE_TYPE_extra733="ens-op.acc.1.aws.iam.1"
-CHECK_SERVICENAME_extra733="iam"
-CHECK_RISK_extra733='Without SAML provider users with AWS CLI or AWS API access can use IAM static credentials. SAML helps users to assume role by default each time they authenticate.'
-CHECK_REMEDIATION_extra733='Enable SAML provider and use temporary credentials. You can use temporary security credentials to make programmatic requests for AWS resources using the AWS CLI or AWS API (using the AWS SDKs ). The temporary credentials provide the same permissions that you have with use long-term security credentials such as IAM user credentials. In case of not having SAML provider capabilities prevent usage of long-lived credentials.'
-CHECK_DOC_extra733='https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithSAML.html'
-CHECK_CAF_EPIC_extra733='IAM'
-
-extra733(){
- LIST_SAML_PROV=$($AWSCLI iam list-saml-providers $PROFILE_OPT --query 'SAMLProviderList[*].Arn' --output text |grep -v ^None)
- if [[ $LIST_SAML_PROV ]]; then
- for provider in $LIST_SAML_PROV; do
- PROVIDER_NAME=$(echo $provider| cut -d/ -f2)
- textInfo "$REGION: SAML Provider $PROVIDER_NAME has been found" "$REGION" "$PROVIDER_NAME"
- done
- else
- textFail "$REGION: No SAML Provider found. Add one and use STS" "$REGION" "$PROVIDER_NAME"
- fi
-}
diff --git a/providers/aws/services/iam/iam_check_saml_providers_sts/__init__.py b/providers/aws/services/iam/iam_check_saml_providers_sts/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts.metadata.json b/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts.metadata.json
new file mode 100644
index 00000000..de824c89
--- /dev/null
+++ b/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts.metadata.json
@@ -0,0 +1,35 @@
+{
+ "Provider": "aws",
+ "CheckID": "iam-check-saml-providers-sts",
+ "CheckTitle": "Check if there are SAML Providers then STS can be used",
+ "CheckType": ["Software and Configuration Checks", "Industry and Regulatory Standards" ,"CIS AWS Foundations Benchmark"],
+ "ServiceName": "iam",
+ "SubServiceName": "",
+ "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
+ "Severity": "low",
+ "ResourceType": "Other",
+ "Description": "Check if there are SAML Providers then STS can be used",
+ "Risk": "Without SAML provider users with AWS CLI or AWS API access can use IAM static credentials. SAML helps users to assume role by default each time they authenticate.",
+ "RelatedUrl": "",
+ "Remediation": {
+ "Code": {
+ "CLI": "",
+ "NativeIaC": "",
+ "Other": "",
+ "Terraform": ""
+ },
+ "Recommendation": {
+ "Text": "Enable SAML provider and use temporary credentials. You can use temporary security credentials to make programmatic requests for AWS resources using the AWS CLI or AWS API (using the AWS SDKs ). The temporary credentials provide the same permissions that you have with use long-term security credentials such as IAM user credentials. In case of not having SAML provider capabilities prevent usage of long-lived credentials.",
+ "Url": "https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithSAML.html"
+ }
+ },
+ "Categories": [],
+ "Tags": {
+ "Tag1Key": "value",
+ "Tag2Key": "value"
+ },
+ "DependsOn": [],
+ "RelatedTo": [],
+ "Notes": "",
+ "Compliance": []
+ }
diff --git a/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts.py b/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts.py
new file mode 100644
index 00000000..b8603938
--- /dev/null
+++ b/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts.py
@@ -0,0 +1,18 @@
+from lib.check.models import Check, Check_Report
+from providers.aws.services.iam.iam_client import iam_client
+
+
+class iam_check_saml_providers_sts(Check):
+ def execute(self) -> Check_Report:
+ findings = []
+ for provider in iam_client.saml_providers:
+ report = Check_Report(self.metadata)
+ provider_name = provider["Arn"].split("/")[1]
+ report.resource_id = provider_name
+ report.resource_arn = provider["Arn"]
+ report.region = iam_client.region
+ report.status = "PASS"
+ report.status_extended = f"SAML Provider {provider_name} has been found"
+ findings.append(report)
+
+ return findings
diff --git a/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts_test.py b/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts_test.py
new file mode 100644
index 00000000..88bd94c0
--- /dev/null
+++ b/providers/aws/services/iam/iam_check_saml_providers_sts/iam_check_saml_providers_sts_test.py
@@ -0,0 +1,58 @@
+from unittest import mock
+
+from boto3 import client
+from moto import mock_iam
+
+
+class Test_iam_check_saml_providers_sts:
+ @mock_iam
+ def test_iam_check_saml_providers_sts(self):
+ iam_client = client("iam")
+ xml_template = r"""
+
+
+
+
+
+MIICYDCCAgqgAwIBAgICBoowDQYJKoZIhvcNAQEEBQAwgZIxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
+EwpDYWxpZm9ybmlhMRQwEgYDVQQHEwtTYW50YSBDbGFyYTEeMBwGA1UEChMVU3VuIE1pY3Jvc3lz
+dGVtcyBJbmMuMRowGAYDVQQLExFJZGVudGl0eSBTZXJ2aWNlczEcMBoGA1UEAxMTQ2VydGlmaWNh
+dGUgTWFuYWdlcjAeFw0wNjExMDIxOTExMzRaFw0xMDA3MjkxOTExMzRaMDcxEjAQBgNVBAoTCXNp
+cm9lLmNvbTEhMB8GA1UEAxMYbG9hZGJhbGFuY2VyLTkuc2lyb2UuY29tMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCjOwa5qoaUuVnknqf5pdgAJSEoWlvx/jnUYbkSDpXLzraEiy2UhvwpoBgB
+EeTSUaPPBvboCItchakPI6Z/aFdH3Wmjuij9XD8r1C+q//7sUO0IGn0ORycddHhoo0aSdnnxGf9V
+tREaqKm9dJ7Yn7kQHjo2eryMgYxtr/Z5Il5F+wIDAQABo2AwXjARBglghkgBhvhCAQEEBAMCBkAw
+DgYDVR0PAQH/BAQDAgTwMB8GA1UdIwQYMBaAFDugITflTCfsWyNLTXDl7cMDUKuuMBgGA1UdEQQR
+MA+BDW1hbGxhQHN1bi5jb20wDQYJKoZIhvcNAQEEBQADQQB/6DOB6sRqCZu2OenM9eQR0gube85e
+nTTxU4a7x1naFxzYXK1iQ1vMARKMjDb19QEJIEJKZlDK4uS7yMlf1nFS
+
+
+
+
+"""
+ saml_provider_name = "test"
+ iam_client.create_saml_provider(
+ SAMLMetadataDocument=xml_template, Name=saml_provider_name
+ )
+
+ from providers.aws.lib.audit_info.audit_info import current_audit_info
+ from providers.aws.services.iam.iam_service import IAM
+
+ with mock.patch(
+ "providers.aws.services.iam.iam_check_saml_providers_sts.iam_check_saml_providers_sts.iam_client",
+ new=IAM(current_audit_info),
+ ):
+ # Test Check
+ from providers.aws.services.iam.iam_check_saml_providers_sts.iam_check_saml_providers_sts import (
+ iam_check_saml_providers_sts,
+ )
+
+ check = iam_check_saml_providers_sts()
+ result = check.execute()
+ assert result[0].status == "PASS"
diff --git a/providers/aws/services/iam/iam_service.py b/providers/aws/services/iam/iam_service.py
index 504a77cf..9707dbc1 100644
--- a/providers/aws/services/iam/iam_service.py
+++ b/providers/aws/services/iam/iam_service.py
@@ -25,6 +25,7 @@ class IAM:
self.__list_attached_group_policies__()
self.__list_mfa_devices__()
self.password_policy = self.__get_password_policy__()
+ self.saml_providers = self.__list_saml_providers__()
def __get_client__(self):
return self.client
@@ -237,6 +238,16 @@ class IAM:
except Exception as error:
logger.error(f"{self.region} -- {error.__class__.__name__}: {error}")
+ def __list_saml_providers__(self):
+ try:
+ saml_providers = self.client.list_saml_providers()["SAMLProviderList"]
+
+ except Exception as error:
+ logger.error(f"{self.region} -- {error.__class__.__name__}: {error}")
+
+ finally:
+ return saml_providers
+
@dataclass
class MFADevice:
diff --git a/providers/aws/services/iam/iam_service_test.py b/providers/aws/services/iam/iam_service_test.py
index cf303748..cf8b3bf0 100644
--- a/providers/aws/services/iam/iam_service_test.py
+++ b/providers/aws/services/iam/iam_service_test.py
@@ -374,3 +374,47 @@ class Test_IAM_Service:
assert (
iam.groups[0].attached_policies[0]["PolicyArn"] == policy["Policy"]["Arn"]
)
+
+ # Test IAM List SAML Providers
+ @mock_iam
+ def test__list_saml_providers__(self):
+ iam_client = client("iam")
+ xml_template = r"""
+
+
+
+
+
+MIICYDCCAgqgAwIBAgICBoowDQYJKoZIhvcNAQEEBQAwgZIxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
+EwpDYWxpZm9ybmlhMRQwEgYDVQQHEwtTYW50YSBDbGFyYTEeMBwGA1UEChMVU3VuIE1pY3Jvc3lz
+dGVtcyBJbmMuMRowGAYDVQQLExFJZGVudGl0eSBTZXJ2aWNlczEcMBoGA1UEAxMTQ2VydGlmaWNh
+dGUgTWFuYWdlcjAeFw0wNjExMDIxOTExMzRaFw0xMDA3MjkxOTExMzRaMDcxEjAQBgNVBAoTCXNp
+cm9lLmNvbTEhMB8GA1UEAxMYbG9hZGJhbGFuY2VyLTkuc2lyb2UuY29tMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCjOwa5qoaUuVnknqf5pdgAJSEoWlvx/jnUYbkSDpXLzraEiy2UhvwpoBgB
+EeTSUaPPBvboCItchakPI6Z/aFdH3Wmjuij9XD8r1C+q//7sUO0IGn0ORycddHhoo0aSdnnxGf9V
+tREaqKm9dJ7Yn7kQHjo2eryMgYxtr/Z5Il5F+wIDAQABo2AwXjARBglghkgBhvhCAQEEBAMCBkAw
+DgYDVR0PAQH/BAQDAgTwMB8GA1UdIwQYMBaAFDugITflTCfsWyNLTXDl7cMDUKuuMBgGA1UdEQQR
+MA+BDW1hbGxhQHN1bi5jb20wDQYJKoZIhvcNAQEEBQADQQB/6DOB6sRqCZu2OenM9eQR0gube85e
+nTTxU4a7x1naFxzYXK1iQ1vMARKMjDb19QEJIEJKZlDK4uS7yMlf1nFS
+
+
+
+
+"""
+ saml_provider_name = "test"
+ iam_client.create_saml_provider(
+ SAMLMetadataDocument=xml_template, Name=saml_provider_name
+ )
+
+ # IAM client for this test class
+ audit_info = self.set_mocked_audit_info()
+ iam = IAM(audit_info)
+
+ assert len(iam.saml_providers) == 1
+ assert iam.saml_providers[0]["Arn"].split("/")[1] == saml_provider_name