feat(iam_check_saml_providers_sts): Check and test (#1413)

This commit is contained in:
Nacho Rivera
2022-10-18 13:23:50 +02:00
committed by GitHub
parent 1119ee54af
commit e2a8fa8738
7 changed files with 166 additions and 37 deletions

View File

@@ -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
}

View File

@@ -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": []
}

View File

@@ -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

View File

@@ -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"""<EntityDescriptor
xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
entityID="loadbalancer-9.siroe.com">
<SPSSODescriptor
AuthnRequestsSigned="false"
WantAssertionsSigned="false"
protocolSupportEnumeration=
"urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>
MIICYDCCAgqgAwIBAgICBoowDQYJKoZIhvcNAQEEBQAwgZIxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
EwpDYWxpZm9ybmlhMRQwEgYDVQQHEwtTYW50YSBDbGFyYTEeMBwGA1UEChMVU3VuIE1pY3Jvc3lz
dGVtcyBJbmMuMRowGAYDVQQLExFJZGVudGl0eSBTZXJ2aWNlczEcMBoGA1UEAxMTQ2VydGlmaWNh
dGUgTWFuYWdlcjAeFw0wNjExMDIxOTExMzRaFw0xMDA3MjkxOTExMzRaMDcxEjAQBgNVBAoTCXNp
cm9lLmNvbTEhMB8GA1UEAxMYbG9hZGJhbGFuY2VyLTkuc2lyb2UuY29tMIGfMA0GCSqGSIb3DQEB
AQUAA4GNADCBiQKBgQCjOwa5qoaUuVnknqf5pdgAJSEoWlvx/jnUYbkSDpXLzraEiy2UhvwpoBgB
EeTSUaPPBvboCItchakPI6Z/aFdH3Wmjuij9XD8r1C+q//7sUO0IGn0ORycddHhoo0aSdnnxGf9V
tREaqKm9dJ7Yn7kQHjo2eryMgYxtr/Z5Il5F+wIDAQABo2AwXjARBglghkgBhvhCAQEEBAMCBkAw
DgYDVR0PAQH/BAQDAgTwMB8GA1UdIwQYMBaAFDugITflTCfsWyNLTXDl7cMDUKuuMBgGA1UdEQQR
MA+BDW1hbGxhQHN1bi5jb20wDQYJKoZIhvcNAQEEBQADQQB/6DOB6sRqCZu2OenM9eQR0gube85e
nTTxU4a7x1naFxzYXK1iQ1vMARKMjDb19QEJIEJKZlDK4uS7yMlf1nFS
</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
</EntityDescriptor>"""
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"

View File

@@ -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:

View File

@@ -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"""<EntityDescriptor
xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
entityID="loadbalancer-9.siroe.com">
<SPSSODescriptor
AuthnRequestsSigned="false"
WantAssertionsSigned="false"
protocolSupportEnumeration=
"urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>
MIICYDCCAgqgAwIBAgICBoowDQYJKoZIhvcNAQEEBQAwgZIxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
EwpDYWxpZm9ybmlhMRQwEgYDVQQHEwtTYW50YSBDbGFyYTEeMBwGA1UEChMVU3VuIE1pY3Jvc3lz
dGVtcyBJbmMuMRowGAYDVQQLExFJZGVudGl0eSBTZXJ2aWNlczEcMBoGA1UEAxMTQ2VydGlmaWNh
dGUgTWFuYWdlcjAeFw0wNjExMDIxOTExMzRaFw0xMDA3MjkxOTExMzRaMDcxEjAQBgNVBAoTCXNp
cm9lLmNvbTEhMB8GA1UEAxMYbG9hZGJhbGFuY2VyLTkuc2lyb2UuY29tMIGfMA0GCSqGSIb3DQEB
AQUAA4GNADCBiQKBgQCjOwa5qoaUuVnknqf5pdgAJSEoWlvx/jnUYbkSDpXLzraEiy2UhvwpoBgB
EeTSUaPPBvboCItchakPI6Z/aFdH3Wmjuij9XD8r1C+q//7sUO0IGn0ORycddHhoo0aSdnnxGf9V
tREaqKm9dJ7Yn7kQHjo2eryMgYxtr/Z5Il5F+wIDAQABo2AwXjARBglghkgBhvhCAQEEBAMCBkAw
DgYDVR0PAQH/BAQDAgTwMB8GA1UdIwQYMBaAFDugITflTCfsWyNLTXDl7cMDUKuuMBgGA1UdEQQR
MA+BDW1hbGxhQHN1bi5jb20wDQYJKoZIhvcNAQEEBQADQQB/6DOB6sRqCZu2OenM9eQR0gube85e
nTTxU4a7x1naFxzYXK1iQ1vMARKMjDb19QEJIEJKZlDK4uS7yMlf1nFS
</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
</EntityDescriptor>"""
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