From e8436bd8304d99881f0ea0e642a141398c03c5e7 Mon Sep 17 00:00:00 2001 From: jtyers <40065647+jtyers@users.noreply.github.com> Date: Fri, 6 Nov 2020 15:32:34 +0000 Subject: [PATCH 1/3] Soft-code SAML providers and tolerate unknown ones when generating reports --- commands/weboftrust.py | 169 +++++++++++++++++++++++------------------ 1 file changed, 95 insertions(+), 74 deletions(-) diff --git a/commands/weboftrust.py b/commands/weboftrust.py index b823dc082..c7d472c19 100644 --- a/commands/weboftrust.py +++ b/commands/weboftrust.py @@ -16,6 +16,87 @@ # - How IAM admins are identified (need to leverage code from find_admins better) # - More services and their trust policies. +PROVIDERS = { + 'saml-provider/okta': { + 'node': Account( json_blob={"id": "okta", "name": "okta", "type": "Okta"}), + 'assumed': True, + }, + "saml-provider/onelogin": { + 'node': Account( + json_blob={ + "id": "onelogin", + "name": "onelogin", + "type": "Onelogin", + } + ), + 'assumed': True, + }, + "saml-provider/waad": { + 'node': Account( + json_blob={ + "id": "WAAD", + "name": "WAAD", + "type": "waad", + } + ), + 'assumed': True, + }, + "saml-provider/allcloud-sso": { + 'node': Account( + json_blob={ + "id": "AllCloud-SSO", + "name": "AllCloud-SSO", + "type": "AllCloud-SSO", + } + ), + 'assumed': True, + }, + "saml-provider/adfs": { + 'node': Account( + json_blob={"id": "adfs", "name": "adfs", "type": "ADFS"} + ), + 'assumed': True, + }, + "saml-provider/auth0": { + 'node': Account( + json_blob={"id": "auth0", "name": "auth0", "type": "auth0"} + ), + 'assumed': True, + }, + "saml-provider/google": { + 'node': Account( + json_blob={ + "id": "google", + "name": "google", + "type": "google", + } + ), + 'assumed': True, + }, + "saml-provider/gsuite": { + 'node': Account( + json_blob={ + "id": "gsuite", + "name": "gsuite", + "type": "gsuite", + } + ), + 'assumed': True, + }, + "cognito-identity.amazonaws.com": { + 'node': None, + }, + "www.amazon.com": { + 'node': Account( + json_blob={ + "id": "Amazon.com", + "name": "Amazon.com", + "type": "Amazon", + } + ), + }, +} + def get_regional_vpc_peerings(region): vpc_peerings = query_aws( @@ -193,81 +274,21 @@ def get_iam_trusts(account, nodes, connections, connections_to_get): try: saml_provider_arn = next(saml for saml in saml_providers if saml['Arn'] == federated_principal)['Arn'] - if 'saml-provider/okta' in saml_provider_arn.lower(): - node = Account( - json_blob={"id": "okta", "name": "okta", "type": "Okta"} - ) - assume_role_nodes.add(node) - elif "saml-provider/onelogin" in saml_provider_arn.lower(): - node = Account( - json_blob={ - "id": "onelogin", - "name": "onelogin", - "type": "Onelogin", - } - ) - assume_role_nodes.add(node) - elif "saml-provider/waad" in saml_provider_arn.lower(): - node = Account( - json_blob={ - "id": "WAAD", - "name": "WAAD", - "type": "waad", - } - ) - assume_role_nodes.add(node) - elif "saml-provider/allcloud-sso" in saml_provider_arn.lower(): - node = Account( - json_blob={ - "id": "AllCloud-SSO", - "name": "AllCloud-SSO", - "type": "AllCloud-SSO", - } - ) - assume_role_nodes.add(node) - elif "saml-provider/adfs" in saml_provider_arn.lower(): - node = Account( - json_blob={"id": "adfs", "name": "adfs", "type": "ADFS"} - ) - assume_role_nodes.add(node) - elif "saml-provider/auth0" in saml_provider_arn.lower(): - node = Account( - json_blob={"id": "auth0", "name": "auth0", "type": "auth0"} - ) - assume_role_nodes.add(node) - elif "saml-provider/google" in saml_provider_arn.lower(): - node = Account( - json_blob={ - "id": "google", - "name": "google", - "type": "google", - } - ) - assume_role_nodes.add(node) - elif "saml-provider/gsuite" in saml_provider_arn.lower(): - node = Account( - json_blob={ - "id": "gsuite", - "name": "gsuite", - "type": "gsuite", - } - ) + found = False + for k, v in PROVIDERS.items(): + if k in in saml_provider_arn.lower(): + found = True + if v.get('node') != None: + node = v['node'] + + if v.get('assumed'): + assume_role_nodes.add(node) + + break + + if not found: + node = Account( json_blob={"id": "unknown", "name": "saml-unknown", "type": "saml-unknown"}) assume_role_nodes.add(node) - elif "cognito-identity.amazonaws.com" in saml_provider_arn.lower(): - continue - elif "www.amazon.com" in saml_provider_arn.lower(): - node = Account( - json_blob={ - "id": "Amazon.com", - "name": "Amazon.com", - "type": "Amazon", - } - ) - continue - else: - raise Exception( - "Unknown federation provider: {}".format(saml_provider_arn.lower()) - ) except StopIteration: if "cognito-identity.amazonaws.com" in federated_principal.lower(): From d5e2b0020e5d237ddb00007770c10d843cc2f6a3 Mon Sep 17 00:00:00 2001 From: jtyers <40065647+jtyers@users.noreply.github.com> Date: Fri, 6 Nov 2020 16:05:08 +0000 Subject: [PATCH 2/3] fix typo --- commands/weboftrust.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/weboftrust.py b/commands/weboftrust.py index c7d472c19..7ca784e23 100644 --- a/commands/weboftrust.py +++ b/commands/weboftrust.py @@ -276,7 +276,7 @@ def get_iam_trusts(account, nodes, connections, connections_to_get): found = False for k, v in PROVIDERS.items(): - if k in in saml_provider_arn.lower(): + if k in saml_provider_arn.lower(): found = True if v.get('node') != None: node = v['node'] From aef0520af049c77b2bb0445846be5dd8030125ba Mon Sep 17 00:00:00 2001 From: jtyers <40065647+jtyers@users.noreply.github.com> Date: Fri, 6 Nov 2020 16:31:27 +0000 Subject: [PATCH 3/3] move to YAML-based config for providers --- commands/weboftrust.py | 94 +++--------------------------------------- saml_providers.yaml | 73 ++++++++++++++++++++++++++++++++ shared/common.py | 9 +++- 3 files changed, 87 insertions(+), 89 deletions(-) create mode 100644 saml_providers.yaml diff --git a/commands/weboftrust.py b/commands/weboftrust.py index 7ca784e23..f470cb850 100644 --- a/commands/weboftrust.py +++ b/commands/weboftrust.py @@ -5,7 +5,7 @@ import pyjq import urllib.parse -from shared.common import parse_arguments, make_list, query_aws, get_regions +from shared.common import parse_arguments, make_list, query_aws, get_regions, get_saml_providers __description__ = "Create Web Of Trust diagram for accounts" @@ -16,88 +16,6 @@ # - How IAM admins are identified (need to leverage code from find_admins better) # - More services and their trust policies. -PROVIDERS = { - 'saml-provider/okta': { - 'node': Account( json_blob={"id": "okta", "name": "okta", "type": "Okta"}), - 'assumed': True, - }, - "saml-provider/onelogin": { - 'node': Account( - json_blob={ - "id": "onelogin", - "name": "onelogin", - "type": "Onelogin", - } - ), - 'assumed': True, - }, - "saml-provider/waad": { - 'node': Account( - json_blob={ - "id": "WAAD", - "name": "WAAD", - "type": "waad", - } - ), - 'assumed': True, - }, - "saml-provider/allcloud-sso": { - 'node': Account( - json_blob={ - "id": "AllCloud-SSO", - "name": "AllCloud-SSO", - "type": "AllCloud-SSO", - } - ), - 'assumed': True, - }, - "saml-provider/adfs": { - 'node': Account( - json_blob={"id": "adfs", "name": "adfs", "type": "ADFS"} - ), - 'assumed': True, - }, - "saml-provider/auth0": { - 'node': Account( - json_blob={"id": "auth0", "name": "auth0", "type": "auth0"} - ), - 'assumed': True, - }, - "saml-provider/google": { - 'node': Account( - json_blob={ - "id": "google", - "name": "google", - "type": "google", - } - ), - 'assumed': True, - }, - "saml-provider/gsuite": { - 'node': Account( - json_blob={ - "id": "gsuite", - "name": "gsuite", - "type": "gsuite", - } - ), - 'assumed': True, - }, - "cognito-identity.amazonaws.com": { - 'node': None, - }, - "www.amazon.com": { - 'node': Account( - json_blob={ - "id": "Amazon.com", - "name": "Amazon.com", - "type": "Amazon", - } - ), - }, -} - - def get_regional_vpc_peerings(region): vpc_peerings = query_aws( region.account, "ec2-describe-vpc-peering-connections", region @@ -275,13 +193,13 @@ def get_iam_trusts(account, nodes, connections, connections_to_get): saml_provider_arn = next(saml for saml in saml_providers if saml['Arn'] == federated_principal)['Arn'] found = False - for k, v in PROVIDERS.items(): - if k in saml_provider_arn.lower(): + for p in get_saml_providers(): + if p['name'] in saml_provider_arn.lower(): found = True - if v.get('node') != None: - node = v['node'] + if p.get('node') != None: + node = Account(**p['node']) - if v.get('assumed'): + if p.get('assumed'): assume_role_nodes.add(node) break diff --git a/saml_providers.yaml b/saml_providers.yaml new file mode 100644 index 000000000..3d877b872 --- /dev/null +++ b/saml_providers.yaml @@ -0,0 +1,73 @@ +- name: saml-provider/okta + node: + json_blob: + id: okta + name: okta + type: Okta + assumed: true + +- name: saml-provider/onelogin + node: + json_blob: + id: onelogin + name: onelogin + type: Onelogin + assumed: true + +- name: saml-provider/waad + node: + json_blob: + id: WAAD + name: WAAD + type: waad + assumed: true + +- name: saml-provider/allcloud-sso + node: + json_blob: + id: AllCloud-SSO + name: AllCloud-SSO + type: AllCloud-SSO + assumed: true + +- name: saml-provider/adfs + node: + json_blob: + id: adfs + name: adfs + type: ADFS + assumed: true + +- name: saml-provider/auth0 + node: + json_blob: + id: auth0 + name: auth0 + type: auth0 + assumed: true + +- name: saml-provider/google + node: + json_blob: + id: google + name: google + type: google + assumed: true + +- name: saml-provider/gsuite + node: + json_blob: + id: gsuite + name: gsuite + type: gsuite + assumed: true + +- name: cognito-identity.amazonaws.com + node: null + +- name: www.amazon.com + node: + json_blob: + id: Amazon.com + name: Amazon.com + type: Amazon diff --git a/shared/common.py b/shared/common.py index e1a370825..c70451410 100644 --- a/shared/common.py +++ b/shared/common.py @@ -235,6 +235,13 @@ def parse_arguments(arguments, parser=None): return (args, accounts, config) +def get_saml_providers(): + """Returns support SAML providers""" + + with open("saml_providers.yaml", "r") as f: + return yaml.safe_load(f) + + def get_account_stats(account, all_resources=False): """Returns stats for an account""" @@ -399,4 +406,4 @@ def get_current_policy_doc(policy): for doc in policy["PolicyVersionList"]: if doc["IsDefaultVersion"]: return doc["Document"] - raise Exception("No default document version in policy {}".format(policy["Arn"])) \ No newline at end of file + raise Exception("No default document version in policy {}".format(policy["Arn"]))