1
1
""" GC01 - Check Federated Users MFA
2
2
https://canada-ca.github.io/cloud-guardrails/EN/01_Protect-Root-Account.html
3
3
"""
4
+
4
5
import json
5
6
import logging
6
7
@@ -43,10 +44,7 @@ def get_assume_role_credentials(role_arn):
43
44
"""
44
45
sts_client = boto3 .client ("sts" )
45
46
try :
46
- assume_role_response = sts_client .assume_role (
47
- RoleArn = role_arn ,
48
- RoleSessionName = "configLambdaExecution"
49
- )
47
+ assume_role_response = sts_client .assume_role (RoleArn = role_arn , RoleSessionName = "configLambdaExecution" )
50
48
return assume_role_response ["Credentials" ]
51
49
except botocore .exceptions .ClientError as ex :
52
50
# Scrub error message for any internal account info leaks
@@ -73,6 +71,7 @@ def evaluate_parameters(rule_parameters):
73
71
"""
74
72
return rule_parameters
75
73
74
+
76
75
# This generate an evaluation for config
77
76
def build_evaluation (
78
77
resource_id ,
@@ -96,12 +95,28 @@ def build_evaluation(
96
95
eval_cc ["ComplianceResourceType" ] = resource_type
97
96
eval_cc ["ComplianceResourceId" ] = resource_id
98
97
eval_cc ["ComplianceType" ] = compliance_type
99
- eval_cc ["OrderingTimestamp" ] = str (
100
- json .loads (event ["invokingEvent" ])["notificationCreationTime" ]
101
- )
98
+ eval_cc ["OrderingTimestamp" ] = str (json .loads (event ["invokingEvent" ])["notificationCreationTime" ])
102
99
return eval_cc
103
100
104
101
102
+ def account_has_federated_users (iam_client ) -> bool :
103
+ response = iam_client .list_open_id_connect_providers ()
104
+ if not response :
105
+ raise Exception ("Request to list OIDC providers returned an invalid response" )
106
+ providers = response .get ("OpenIDConnectProviderList" , [])
107
+ if providers :
108
+ return True
109
+
110
+ response = iam_client .list_saml_providers ()
111
+ if not response :
112
+ raise Exception ("Request to list SAML providers returned an invalid response" )
113
+ providers = response .get ("SAMLProviderList" , [])
114
+ if providers :
115
+ return True
116
+
117
+ return False
118
+
119
+
105
120
def lambda_handler (event , context ):
106
121
"""This function is the main entry point for Lambda.
107
122
Keyword arguments:
@@ -110,7 +125,6 @@ def lambda_handler(event, context):
110
125
"""
111
126
logger .debug ("Received event: %s" , event )
112
127
113
- global AWS_CONFIG_CLIENT
114
128
global AWS_ACCOUNT_ID
115
129
global EXECUTION_ROLE_NAME
116
130
global AUDIT_ACCOUNT_ID
@@ -138,22 +152,17 @@ def lambda_handler(event, context):
138
152
else :
139
153
AUDIT_ACCOUNT_ID = ""
140
154
141
- AWS_CONFIG_CLIENT = get_client ("config" , event )
142
-
143
- # is this a scheduled invokation?
144
- if is_scheduled_notification (invoking_event ["messageType" ]):
145
- # yes, proceed
146
- # Update AWS Config with the evaluation result
147
- evaluations = [
148
- build_evaluation (
149
- AWS_ACCOUNT_ID ,
150
- "COMPLIANT" ,
151
- event ,
152
- DEFAULT_RESOURCE_TYPE ,
153
- "Dependent on the compliance of Federated IdP"
154
- )
155
- ]
156
- AWS_CONFIG_CLIENT .put_evaluations (
157
- Evaluations = evaluations ,
158
- ResultToken = event ["resultToken" ]
159
- )
155
+ if not is_scheduled_notification (invoking_event ["messageType" ]):
156
+ return
157
+
158
+ aws_config_client = get_client ("config" , event )
159
+ aws_iam_client = get_client ("iam" , event )
160
+
161
+ annotation = (
162
+ "Dependent on the compliance of the Federated IdP."
163
+ if account_has_federated_users (aws_iam_client )
164
+ else "No federated IdP found."
165
+ )
166
+
167
+ evaluations = [build_evaluation (AWS_ACCOUNT_ID , "COMPLIANT" , event , DEFAULT_RESOURCE_TYPE , annotation )]
168
+ aws_config_client .put_evaluations (Evaluations = evaluations , ResultToken = event ["resultToken" ])
0 commit comments