cartography 0.102.0rc2__py3-none-any.whl → 0.103.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cartography might be problematic. Click here for more details.
- cartography/__main__.py +1 -2
- cartography/_version.py +2 -2
- cartography/cli.py +302 -253
- cartography/client/core/tx.py +39 -18
- cartography/config.py +4 -0
- cartography/driftdetect/__main__.py +1 -2
- cartography/driftdetect/add_shortcut.py +10 -2
- cartography/driftdetect/cli.py +71 -75
- cartography/driftdetect/detect_deviations.py +7 -3
- cartography/driftdetect/get_states.py +20 -8
- cartography/driftdetect/model.py +5 -5
- cartography/driftdetect/serializers.py +8 -6
- cartography/driftdetect/storage.py +2 -2
- cartography/graph/cleanupbuilder.py +35 -15
- cartography/graph/job.py +46 -17
- cartography/graph/querybuilder.py +165 -80
- cartography/graph/statement.py +35 -26
- cartography/intel/analysis.py +4 -1
- cartography/intel/aws/__init__.py +114 -55
- cartography/intel/aws/apigateway.py +134 -63
- cartography/intel/aws/cloudtrail.py +127 -0
- cartography/intel/aws/config.py +56 -20
- cartography/intel/aws/dynamodb.py +108 -40
- cartography/intel/aws/ec2/__init__.py +2 -2
- cartography/intel/aws/ec2/auto_scaling_groups.py +181 -78
- cartography/intel/aws/ec2/elastic_ip_addresses.py +41 -13
- cartography/intel/aws/ec2/images.py +49 -20
- cartography/intel/aws/ec2/instances.py +234 -136
- cartography/intel/aws/ec2/internet_gateways.py +40 -11
- cartography/intel/aws/ec2/key_pairs.py +44 -20
- cartography/intel/aws/ec2/launch_templates.py +101 -59
- cartography/intel/aws/ec2/load_balancer_v2s.py +104 -39
- cartography/intel/aws/ec2/load_balancers.py +82 -42
- cartography/intel/aws/ec2/network_acls.py +89 -65
- cartography/intel/aws/ec2/network_interfaces.py +146 -87
- cartography/intel/aws/ec2/reserved_instances.py +45 -16
- cartography/intel/aws/ec2/route_tables.py +138 -98
- cartography/intel/aws/ec2/security_groups.py +71 -21
- cartography/intel/aws/ec2/snapshots.py +61 -22
- cartography/intel/aws/ec2/subnets.py +54 -18
- cartography/intel/aws/ec2/tgw.py +100 -34
- cartography/intel/aws/ec2/util.py +1 -1
- cartography/intel/aws/ec2/volumes.py +69 -41
- cartography/intel/aws/ec2/vpc.py +37 -12
- cartography/intel/aws/ec2/vpc_peerings.py +83 -24
- cartography/intel/aws/ecr.py +88 -32
- cartography/intel/aws/ecs.py +83 -47
- cartography/intel/aws/eks.py +55 -29
- cartography/intel/aws/elasticache.py +42 -18
- cartography/intel/aws/elasticsearch.py +57 -20
- cartography/intel/aws/emr.py +61 -23
- cartography/intel/aws/iam.py +401 -145
- cartography/intel/aws/iam_instance_profiles.py +22 -22
- cartography/intel/aws/identitycenter.py +71 -37
- cartography/intel/aws/inspector.py +159 -89
- cartography/intel/aws/kms.py +92 -38
- cartography/intel/aws/lambda_function.py +103 -34
- cartography/intel/aws/organizations.py +30 -10
- cartography/intel/aws/permission_relationships.py +133 -51
- cartography/intel/aws/rds.py +249 -85
- cartography/intel/aws/redshift.py +107 -46
- cartography/intel/aws/resourcegroupstaggingapi.py +120 -66
- cartography/intel/aws/resources.py +53 -46
- cartography/intel/aws/route53.py +108 -61
- cartography/intel/aws/s3.py +168 -83
- cartography/intel/aws/s3accountpublicaccessblock.py +157 -0
- cartography/intel/aws/secretsmanager.py +24 -12
- cartography/intel/aws/securityhub.py +20 -9
- cartography/intel/aws/sns.py +166 -0
- cartography/intel/aws/sqs.py +60 -28
- cartography/intel/aws/ssm.py +70 -30
- cartography/intel/aws/util/arns.py +7 -7
- cartography/intel/aws/util/common.py +31 -4
- cartography/intel/azure/__init__.py +78 -19
- cartography/intel/azure/compute.py +101 -27
- cartography/intel/azure/cosmosdb.py +496 -170
- cartography/intel/azure/sql.py +296 -105
- cartography/intel/azure/storage.py +322 -113
- cartography/intel/azure/subscription.py +39 -23
- cartography/intel/azure/tenant.py +13 -4
- cartography/intel/azure/util/credentials.py +95 -55
- cartography/intel/bigfix/__init__.py +2 -2
- cartography/intel/bigfix/computers.py +93 -65
- cartography/intel/create_indexes.py +3 -2
- cartography/intel/crowdstrike/__init__.py +11 -9
- cartography/intel/crowdstrike/endpoints.py +5 -1
- cartography/intel/crowdstrike/spotlight.py +8 -3
- cartography/intel/cve/__init__.py +46 -13
- cartography/intel/cve/feed.py +48 -12
- cartography/intel/digitalocean/__init__.py +22 -13
- cartography/intel/digitalocean/compute.py +75 -108
- cartography/intel/digitalocean/management.py +44 -80
- cartography/intel/digitalocean/platform.py +48 -43
- cartography/intel/dns.py +36 -10
- cartography/intel/duo/__init__.py +21 -16
- cartography/intel/duo/api_host.py +14 -9
- cartography/intel/duo/endpoints.py +50 -45
- cartography/intel/duo/groups.py +18 -14
- cartography/intel/duo/phones.py +37 -34
- cartography/intel/duo/tokens.py +26 -23
- cartography/intel/duo/users.py +54 -50
- cartography/intel/duo/web_authn_credentials.py +30 -25
- cartography/intel/entra/__init__.py +25 -7
- cartography/intel/entra/ou.py +112 -0
- cartography/intel/entra/users.py +69 -63
- cartography/intel/gcp/__init__.py +185 -49
- cartography/intel/gcp/compute.py +418 -231
- cartography/intel/gcp/crm.py +96 -43
- cartography/intel/gcp/dns.py +60 -19
- cartography/intel/gcp/gke.py +72 -38
- cartography/intel/gcp/iam.py +61 -41
- cartography/intel/gcp/storage.py +84 -55
- cartography/intel/github/__init__.py +13 -11
- cartography/intel/github/repos.py +270 -137
- cartography/intel/github/teams.py +170 -88
- cartography/intel/github/users.py +70 -39
- cartography/intel/github/util.py +36 -34
- cartography/intel/gsuite/__init__.py +47 -26
- cartography/intel/gsuite/api.py +73 -30
- cartography/intel/jamf/__init__.py +19 -1
- cartography/intel/jamf/computers.py +30 -7
- cartography/intel/jamf/util.py +7 -2
- cartography/intel/kandji/__init__.py +6 -3
- cartography/intel/kandji/devices.py +14 -8
- cartography/intel/kubernetes/namespaces.py +7 -4
- cartography/intel/kubernetes/pods.py +7 -4
- cartography/intel/kubernetes/services.py +8 -4
- cartography/intel/lastpass/__init__.py +2 -2
- cartography/intel/lastpass/users.py +23 -12
- cartography/intel/oci/__init__.py +44 -11
- cartography/intel/oci/iam.py +134 -38
- cartography/intel/oci/organizations.py +13 -6
- cartography/intel/oci/utils.py +43 -20
- cartography/intel/okta/__init__.py +66 -15
- cartography/intel/okta/applications.py +42 -20
- cartography/intel/okta/awssaml.py +93 -33
- cartography/intel/okta/factors.py +16 -4
- cartography/intel/okta/groups.py +56 -29
- cartography/intel/okta/organization.py +5 -1
- cartography/intel/okta/origins.py +6 -2
- cartography/intel/okta/roles.py +15 -5
- cartography/intel/okta/users.py +20 -8
- cartography/intel/okta/utils.py +6 -4
- cartography/intel/pagerduty/__init__.py +8 -7
- cartography/intel/pagerduty/escalation_policies.py +18 -6
- cartography/intel/pagerduty/schedules.py +12 -4
- cartography/intel/pagerduty/services.py +11 -4
- cartography/intel/pagerduty/teams.py +8 -3
- cartography/intel/pagerduty/users.py +3 -1
- cartography/intel/pagerduty/vendors.py +3 -1
- cartography/intel/semgrep/__init__.py +24 -6
- cartography/intel/semgrep/dependencies.py +50 -28
- cartography/intel/semgrep/deployment.py +3 -1
- cartography/intel/semgrep/findings.py +42 -18
- cartography/intel/snipeit/__init__.py +17 -3
- cartography/intel/snipeit/asset.py +12 -6
- cartography/intel/snipeit/user.py +8 -5
- cartography/intel/snipeit/util.py +9 -4
- cartography/models/aws/apigateway.py +21 -17
- cartography/models/aws/apigatewaycertificate.py +28 -22
- cartography/models/aws/apigatewayresource.py +28 -20
- cartography/models/aws/apigatewaystage.py +33 -25
- cartography/models/aws/cloudtrail/__init__.py +0 -0
- cartography/models/aws/cloudtrail/trail.py +61 -0
- cartography/models/aws/dynamodb/gsi.py +30 -22
- cartography/models/aws/dynamodb/tables.py +25 -17
- cartography/models/aws/ec2/auto_scaling_groups.py +102 -82
- cartography/models/aws/ec2/images.py +36 -34
- cartography/models/aws/ec2/instances.py +51 -45
- cartography/models/aws/ec2/keypair.py +21 -16
- cartography/models/aws/ec2/keypair_instance.py +28 -21
- cartography/models/aws/ec2/launch_configurations.py +30 -26
- cartography/models/aws/ec2/launch_template_versions.py +48 -38
- cartography/models/aws/ec2/launch_templates.py +21 -17
- cartography/models/aws/ec2/load_balancer_listeners.py +27 -23
- cartography/models/aws/ec2/load_balancers.py +47 -37
- cartography/models/aws/ec2/network_acl_rules.py +38 -30
- cartography/models/aws/ec2/network_acls.py +38 -29
- cartography/models/aws/ec2/networkinterface_instance.py +52 -39
- cartography/models/aws/ec2/networkinterfaces.py +53 -37
- cartography/models/aws/ec2/privateip_networkinterface.py +32 -22
- cartography/models/aws/ec2/reservations.py +18 -14
- cartography/models/aws/ec2/route_table_associations.py +44 -34
- cartography/models/aws/ec2/route_tables.py +50 -43
- cartography/models/aws/ec2/routes.py +45 -37
- cartography/models/aws/ec2/securitygroup_instance.py +29 -20
- cartography/models/aws/ec2/securitygroup_networkinterface.py +24 -15
- cartography/models/aws/ec2/subnet_instance.py +24 -19
- cartography/models/aws/ec2/subnet_networkinterface.py +40 -31
- cartography/models/aws/ec2/volumes.py +47 -40
- cartography/models/aws/eks/clusters.py +23 -21
- cartography/models/aws/emr.py +32 -30
- cartography/models/aws/iam/instanceprofile.py +33 -24
- cartography/models/aws/identitycenter/awsidentitycenter.py +18 -14
- cartography/models/aws/identitycenter/awspermissionset.py +37 -29
- cartography/models/aws/identitycenter/awsssouser.py +23 -21
- cartography/models/aws/inspector/findings.py +77 -65
- cartography/models/aws/inspector/packages.py +35 -29
- cartography/models/aws/s3/__init__.py +0 -0
- cartography/models/aws/s3/account_public_access_block.py +51 -0
- cartography/models/aws/sns/__init__.py +0 -0
- cartography/models/aws/sns/topic.py +50 -0
- cartography/models/aws/ssm/instance_information.py +51 -39
- cartography/models/aws/ssm/instance_patch.py +32 -26
- cartography/models/bigfix/bigfix_computer.py +42 -38
- cartography/models/bigfix/bigfix_root.py +3 -3
- cartography/models/core/common.py +12 -10
- cartography/models/core/nodes.py +5 -2
- cartography/models/core/relationships.py +14 -6
- cartography/models/crowdstrike/hosts.py +37 -35
- cartography/models/cve/cve.py +34 -32
- cartography/models/cve/cve_feed.py +6 -6
- cartography/models/digitalocean/__init__.py +0 -0
- cartography/models/digitalocean/account.py +21 -0
- cartography/models/digitalocean/droplet.py +56 -0
- cartography/models/digitalocean/project.py +48 -0
- cartography/models/duo/api_host.py +3 -3
- cartography/models/duo/endpoint.py +43 -41
- cartography/models/duo/group.py +14 -14
- cartography/models/duo/phone.py +27 -27
- cartography/models/duo/token.py +16 -16
- cartography/models/duo/user.py +46 -44
- cartography/models/duo/web_authn_credential.py +27 -19
- cartography/models/entra/ou.py +48 -0
- cartography/models/entra/tenant.py +24 -18
- cartography/models/entra/user.py +64 -48
- cartography/models/gcp/iam.py +23 -23
- cartography/models/github/orgs.py +5 -4
- cartography/models/github/teams.py +37 -31
- cartography/models/github/users.py +34 -23
- cartography/models/kandji/device.py +22 -16
- cartography/models/kandji/tenant.py +6 -4
- cartography/models/lastpass/tenant.py +3 -3
- cartography/models/lastpass/user.py +32 -28
- cartography/models/semgrep/dependencies.py +36 -24
- cartography/models/semgrep/deployment.py +5 -5
- cartography/models/semgrep/findings.py +58 -42
- cartography/models/semgrep/locations.py +27 -21
- cartography/models/snipeit/asset.py +30 -21
- cartography/models/snipeit/tenant.py +6 -4
- cartography/models/snipeit/user.py +19 -12
- cartography/stats.py +3 -3
- cartography/sync.py +107 -31
- cartography/util.py +84 -62
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/METADATA +3 -14
- cartography-0.103.0rc1.dist-info/RECORD +396 -0
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/WHEEL +1 -1
- cartography-0.102.0rc2.dist-info/RECORD +0 -381
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/entry_points.txt +0 -0
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/licenses/LICENSE +0 -0
- {cartography-0.102.0rc2.dist-info → cartography-0.103.0rc1.dist-info}/top_level.txt +0 -0
cartography/intel/aws/iam.py
CHANGED
|
@@ -24,8 +24,8 @@ stat_handler = get_stats_client(__name__)
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class PolicyType(enum.Enum):
|
|
27
|
-
managed =
|
|
28
|
-
inline =
|
|
27
|
+
managed = "managed"
|
|
28
|
+
inline = "inline"
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def get_policy_name_from_arn(arn: str) -> str:
|
|
@@ -34,49 +34,66 @@ def get_policy_name_from_arn(arn: str) -> str:
|
|
|
34
34
|
|
|
35
35
|
@timeit
|
|
36
36
|
def get_group_policies(boto3_session: boto3.session.Session, group_name: str) -> Dict:
|
|
37
|
-
client = boto3_session.client(
|
|
38
|
-
paginator = client.get_paginator(
|
|
37
|
+
client = boto3_session.client("iam")
|
|
38
|
+
paginator = client.get_paginator("list_group_policies")
|
|
39
39
|
policy_names: List[Dict] = []
|
|
40
40
|
for page in paginator.paginate(GroupName=group_name):
|
|
41
|
-
policy_names.extend(page[
|
|
42
|
-
return {
|
|
41
|
+
policy_names.extend(page["PolicyNames"])
|
|
42
|
+
return {"PolicyNames": policy_names}
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
@timeit
|
|
46
46
|
def get_group_policy_info(
|
|
47
|
-
|
|
47
|
+
boto3_session: boto3.session.Session,
|
|
48
|
+
group_name: str,
|
|
49
|
+
policy_name: str,
|
|
48
50
|
) -> Any:
|
|
49
|
-
client = boto3_session.client(
|
|
51
|
+
client = boto3_session.client("iam")
|
|
50
52
|
return client.get_group_policy(GroupName=group_name, PolicyName=policy_name)
|
|
51
53
|
|
|
52
54
|
|
|
53
55
|
@timeit
|
|
54
|
-
def get_group_membership_data(
|
|
55
|
-
|
|
56
|
+
def get_group_membership_data(
|
|
57
|
+
boto3_session: boto3.session.Session,
|
|
58
|
+
group_name: str,
|
|
59
|
+
) -> Dict:
|
|
60
|
+
client = boto3_session.client("iam")
|
|
56
61
|
try:
|
|
57
62
|
memberships = client.get_group(GroupName=group_name)
|
|
58
63
|
return memberships
|
|
59
64
|
except client.exceptions.NoSuchEntityException:
|
|
60
65
|
# Avoid crashing the sync
|
|
61
|
-
logger.warning(
|
|
66
|
+
logger.warning(
|
|
67
|
+
"client.get_group(GroupName='%s') failed with NoSuchEntityException; skipping.",
|
|
68
|
+
group_name,
|
|
69
|
+
)
|
|
62
70
|
return {}
|
|
63
71
|
|
|
64
72
|
|
|
65
73
|
@timeit
|
|
66
|
-
def get_group_policy_data(
|
|
67
|
-
|
|
74
|
+
def get_group_policy_data(
|
|
75
|
+
boto3_session: boto3.session.Session,
|
|
76
|
+
group_list: List[Dict],
|
|
77
|
+
) -> Dict:
|
|
78
|
+
resource_client = boto3_session.resource("iam")
|
|
68
79
|
policies = {}
|
|
69
80
|
for group in group_list:
|
|
70
81
|
name = group["GroupName"]
|
|
71
82
|
arn = group["Arn"]
|
|
72
83
|
resource_group = resource_client.Group(name)
|
|
73
|
-
policies[arn] = policies[arn] = {
|
|
84
|
+
policies[arn] = policies[arn] = {
|
|
85
|
+
p.name: p.policy_document["Statement"]
|
|
86
|
+
for p in resource_group.policies.all()
|
|
87
|
+
}
|
|
74
88
|
return policies
|
|
75
89
|
|
|
76
90
|
|
|
77
91
|
@timeit
|
|
78
|
-
def get_group_managed_policy_data(
|
|
79
|
-
|
|
92
|
+
def get_group_managed_policy_data(
|
|
93
|
+
boto3_session: boto3.session.Session,
|
|
94
|
+
group_list: List[Dict],
|
|
95
|
+
) -> Dict:
|
|
96
|
+
resource_client = boto3_session.resource("iam")
|
|
80
97
|
policies = {}
|
|
81
98
|
for group in group_list:
|
|
82
99
|
name = group["GroupName"]
|
|
@@ -90,15 +107,21 @@ def get_group_managed_policy_data(boto3_session: boto3.session.Session, group_li
|
|
|
90
107
|
|
|
91
108
|
|
|
92
109
|
@timeit
|
|
93
|
-
def get_user_policy_data(
|
|
94
|
-
|
|
110
|
+
def get_user_policy_data(
|
|
111
|
+
boto3_session: boto3.session.Session,
|
|
112
|
+
user_list: List[Dict],
|
|
113
|
+
) -> Dict:
|
|
114
|
+
resource_client = boto3_session.resource("iam")
|
|
95
115
|
policies = {}
|
|
96
116
|
for user in user_list:
|
|
97
117
|
name = user["UserName"]
|
|
98
118
|
arn = user["Arn"]
|
|
99
119
|
resource_user = resource_client.User(name)
|
|
100
120
|
try:
|
|
101
|
-
policies[arn] = {
|
|
121
|
+
policies[arn] = {
|
|
122
|
+
p.name: p.policy_document["Statement"]
|
|
123
|
+
for p in resource_user.policies.all()
|
|
124
|
+
}
|
|
102
125
|
except resource_client.meta.client.exceptions.NoSuchEntityException:
|
|
103
126
|
logger.warning(
|
|
104
127
|
f"Could not get policies for user {name} due to NoSuchEntityException; skipping.",
|
|
@@ -107,8 +130,11 @@ def get_user_policy_data(boto3_session: boto3.session.Session, user_list: List[D
|
|
|
107
130
|
|
|
108
131
|
|
|
109
132
|
@timeit
|
|
110
|
-
def get_user_managed_policy_data(
|
|
111
|
-
|
|
133
|
+
def get_user_managed_policy_data(
|
|
134
|
+
boto3_session: boto3.session.Session,
|
|
135
|
+
user_list: List[Dict],
|
|
136
|
+
) -> Dict:
|
|
137
|
+
resource_client = boto3_session.resource("iam")
|
|
112
138
|
policies = {}
|
|
113
139
|
for user in user_list:
|
|
114
140
|
name = user["UserName"]
|
|
@@ -127,15 +153,21 @@ def get_user_managed_policy_data(boto3_session: boto3.session.Session, user_list
|
|
|
127
153
|
|
|
128
154
|
|
|
129
155
|
@timeit
|
|
130
|
-
def get_role_policy_data(
|
|
131
|
-
|
|
156
|
+
def get_role_policy_data(
|
|
157
|
+
boto3_session: boto3.session.Session,
|
|
158
|
+
role_list: List[Dict],
|
|
159
|
+
) -> Dict:
|
|
160
|
+
resource_client = boto3_session.resource("iam")
|
|
132
161
|
policies = {}
|
|
133
162
|
for role in role_list:
|
|
134
163
|
name = role["RoleName"]
|
|
135
164
|
arn = role["Arn"]
|
|
136
165
|
resource_role = resource_client.Role(name)
|
|
137
166
|
try:
|
|
138
|
-
policies[arn] = {
|
|
167
|
+
policies[arn] = {
|
|
168
|
+
p.name: p.policy_document["Statement"]
|
|
169
|
+
for p in resource_role.policies.all()
|
|
170
|
+
}
|
|
139
171
|
except resource_client.meta.client.exceptions.NoSuchEntityException:
|
|
140
172
|
logger.warning(
|
|
141
173
|
f"Could not get policies for role {name} due to NoSuchEntityException; skipping.",
|
|
@@ -144,8 +176,11 @@ def get_role_policy_data(boto3_session: boto3.session.Session, role_list: List[D
|
|
|
144
176
|
|
|
145
177
|
|
|
146
178
|
@timeit
|
|
147
|
-
def get_role_managed_policy_data(
|
|
148
|
-
|
|
179
|
+
def get_role_managed_policy_data(
|
|
180
|
+
boto3_session: boto3.session.Session,
|
|
181
|
+
role_list: List[Dict],
|
|
182
|
+
) -> Dict:
|
|
183
|
+
resource_client = boto3_session.resource("iam")
|
|
149
184
|
policies = {}
|
|
150
185
|
for role in role_list:
|
|
151
186
|
name = role["RoleName"]
|
|
@@ -165,8 +200,8 @@ def get_role_managed_policy_data(boto3_session: boto3.session.Session, role_list
|
|
|
165
200
|
|
|
166
201
|
@timeit
|
|
167
202
|
def get_role_tags(boto3_session: boto3.session.Session) -> List[Dict]:
|
|
168
|
-
role_list = get_role_list_data(boto3_session)[
|
|
169
|
-
resource_client = boto3_session.resource(
|
|
203
|
+
role_list = get_role_list_data(boto3_session)["Roles"]
|
|
204
|
+
resource_client = boto3_session.resource("iam")
|
|
170
205
|
role_tag_data: List[Dict] = []
|
|
171
206
|
for role in role_list:
|
|
172
207
|
name = role["RoleName"]
|
|
@@ -177,8 +212,8 @@ def get_role_tags(boto3_session: boto3.session.Session) -> List[Dict]:
|
|
|
177
212
|
continue
|
|
178
213
|
|
|
179
214
|
tag_data = {
|
|
180
|
-
|
|
181
|
-
|
|
215
|
+
"ResourceARN": role_arn,
|
|
216
|
+
"Tags": resource_role.tags,
|
|
182
217
|
}
|
|
183
218
|
role_tag_data.append(tag_data)
|
|
184
219
|
|
|
@@ -187,38 +222,41 @@ def get_role_tags(boto3_session: boto3.session.Session) -> List[Dict]:
|
|
|
187
222
|
|
|
188
223
|
@timeit
|
|
189
224
|
def get_user_list_data(boto3_session: boto3.session.Session) -> Dict:
|
|
190
|
-
client = boto3_session.client(
|
|
225
|
+
client = boto3_session.client("iam")
|
|
191
226
|
|
|
192
|
-
paginator = client.get_paginator(
|
|
227
|
+
paginator = client.get_paginator("list_users")
|
|
193
228
|
users: List[Dict] = []
|
|
194
229
|
for page in paginator.paginate():
|
|
195
|
-
users.extend(page[
|
|
196
|
-
return {
|
|
230
|
+
users.extend(page["Users"])
|
|
231
|
+
return {"Users": users}
|
|
197
232
|
|
|
198
233
|
|
|
199
234
|
@timeit
|
|
200
235
|
def get_group_list_data(boto3_session: boto3.session.Session) -> Dict:
|
|
201
|
-
client = boto3_session.client(
|
|
202
|
-
paginator = client.get_paginator(
|
|
236
|
+
client = boto3_session.client("iam")
|
|
237
|
+
paginator = client.get_paginator("list_groups")
|
|
203
238
|
groups: List[Dict] = []
|
|
204
239
|
for page in paginator.paginate():
|
|
205
|
-
groups.extend(page[
|
|
206
|
-
return {
|
|
240
|
+
groups.extend(page["Groups"])
|
|
241
|
+
return {"Groups": groups}
|
|
207
242
|
|
|
208
243
|
|
|
209
244
|
@timeit
|
|
210
245
|
def get_role_list_data(boto3_session: boto3.session.Session) -> Dict:
|
|
211
|
-
client = boto3_session.client(
|
|
212
|
-
paginator = client.get_paginator(
|
|
246
|
+
client = boto3_session.client("iam")
|
|
247
|
+
paginator = client.get_paginator("list_roles")
|
|
213
248
|
roles: List[Dict] = []
|
|
214
249
|
for page in paginator.paginate():
|
|
215
|
-
roles.extend(page[
|
|
216
|
-
return {
|
|
250
|
+
roles.extend(page["Roles"])
|
|
251
|
+
return {"Roles": roles}
|
|
217
252
|
|
|
218
253
|
|
|
219
254
|
@timeit
|
|
220
|
-
def get_account_access_key_data(
|
|
221
|
-
|
|
255
|
+
def get_account_access_key_data(
|
|
256
|
+
boto3_session: boto3.session.Session,
|
|
257
|
+
username: str,
|
|
258
|
+
) -> Dict:
|
|
259
|
+
client = boto3_session.client("iam")
|
|
222
260
|
# NOTE we can get away without using a paginator here because users are limited to two access keys
|
|
223
261
|
access_keys: Dict = {}
|
|
224
262
|
try:
|
|
@@ -228,22 +266,25 @@ def get_account_access_key_data(boto3_session: boto3.session.Session, username:
|
|
|
228
266
|
f"Could not get access key for user {username} due to NoSuchEntityException; skipping.",
|
|
229
267
|
)
|
|
230
268
|
return access_keys
|
|
231
|
-
for access_key in access_keys[
|
|
232
|
-
access_key_id = access_key[
|
|
269
|
+
for access_key in access_keys["AccessKeyMetadata"]:
|
|
270
|
+
access_key_id = access_key["AccessKeyId"]
|
|
233
271
|
last_used_info = client.get_access_key_last_used(
|
|
234
272
|
AccessKeyId=access_key_id,
|
|
235
|
-
)[
|
|
273
|
+
)["AccessKeyLastUsed"]
|
|
236
274
|
# only LastUsedDate may be null
|
|
237
275
|
# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iam/client/get_access_key_last_used.html
|
|
238
|
-
access_key[
|
|
239
|
-
access_key[
|
|
240
|
-
access_key[
|
|
276
|
+
access_key["LastUsedDate"] = last_used_info.get("LastUsedDate")
|
|
277
|
+
access_key["LastUsedService"] = last_used_info["ServiceName"]
|
|
278
|
+
access_key["LastUsedRegion"] = last_used_info["Region"]
|
|
241
279
|
return access_keys
|
|
242
280
|
|
|
243
281
|
|
|
244
282
|
@timeit
|
|
245
283
|
def load_users(
|
|
246
|
-
neo4j_session: neo4j.Session,
|
|
284
|
+
neo4j_session: neo4j.Session,
|
|
285
|
+
users: List[Dict],
|
|
286
|
+
current_aws_account_id: str,
|
|
287
|
+
aws_update_tag: int,
|
|
247
288
|
) -> None:
|
|
248
289
|
ingest_user = """
|
|
249
290
|
MERGE (unode:AWSUser{arn: $ARN})
|
|
@@ -274,7 +315,10 @@ def load_users(
|
|
|
274
315
|
|
|
275
316
|
@timeit
|
|
276
317
|
def load_groups(
|
|
277
|
-
neo4j_session: neo4j.Session,
|
|
318
|
+
neo4j_session: neo4j.Session,
|
|
319
|
+
groups: List[Dict],
|
|
320
|
+
current_aws_account_id: str,
|
|
321
|
+
aws_update_tag: int,
|
|
278
322
|
) -> None:
|
|
279
323
|
ingest_group = """
|
|
280
324
|
MERGE (gnode:AWSGroup{arn: $ARN})
|
|
@@ -317,7 +361,10 @@ def _parse_principal_entries(principal: Dict) -> List[Tuple[Any, Any]]:
|
|
|
317
361
|
|
|
318
362
|
@timeit
|
|
319
363
|
def load_roles(
|
|
320
|
-
neo4j_session: neo4j.Session,
|
|
364
|
+
neo4j_session: neo4j.Session,
|
|
365
|
+
roles: List[Dict],
|
|
366
|
+
current_aws_account_id: str,
|
|
367
|
+
aws_update_tag: int,
|
|
321
368
|
) -> None:
|
|
322
369
|
ingest_role = """
|
|
323
370
|
MERGE (rnode:AWSPrincipal{arn: $Arn})
|
|
@@ -387,7 +434,7 @@ def load_roles(
|
|
|
387
434
|
ingest_policy_statement,
|
|
388
435
|
SpnArn=principal_value,
|
|
389
436
|
SpnType=principal_type,
|
|
390
|
-
RoleArn=role[
|
|
437
|
+
RoleArn=role["Arn"],
|
|
391
438
|
aws_update_tag=aws_update_tag,
|
|
392
439
|
)
|
|
393
440
|
spn_arn = get_account_from_arn(principal_value)
|
|
@@ -401,7 +448,11 @@ def load_roles(
|
|
|
401
448
|
|
|
402
449
|
|
|
403
450
|
@timeit
|
|
404
|
-
def load_group_memberships(
|
|
451
|
+
def load_group_memberships(
|
|
452
|
+
neo4j_session: neo4j.Session,
|
|
453
|
+
group_memberships: Dict,
|
|
454
|
+
aws_update_tag: int,
|
|
455
|
+
) -> None:
|
|
405
456
|
ingest_membership = """
|
|
406
457
|
MATCH (group:AWSGroup{arn: $GroupArn})
|
|
407
458
|
WITH group
|
|
@@ -427,7 +478,10 @@ def load_group_memberships(neo4j_session: neo4j.Session, group_memberships: Dict
|
|
|
427
478
|
|
|
428
479
|
|
|
429
480
|
@timeit
|
|
430
|
-
def get_policies_for_principal(
|
|
481
|
+
def get_policies_for_principal(
|
|
482
|
+
neo4j_session: neo4j.Session,
|
|
483
|
+
principal_arn: str,
|
|
484
|
+
) -> Dict:
|
|
431
485
|
get_policy_query = """
|
|
432
486
|
MATCH
|
|
433
487
|
(principal:AWSPrincipal{arn:$Arn})-[:POLICY]->
|
|
@@ -447,12 +501,17 @@ def get_policies_for_principal(neo4j_session: neo4j.Session, principal_arn: str)
|
|
|
447
501
|
|
|
448
502
|
@timeit
|
|
449
503
|
def sync_assumerole_relationships(
|
|
450
|
-
neo4j_session: neo4j.Session,
|
|
504
|
+
neo4j_session: neo4j.Session,
|
|
505
|
+
current_aws_account_id: str,
|
|
506
|
+
aws_update_tag: int,
|
|
451
507
|
common_job_parameters: Dict,
|
|
452
508
|
) -> None:
|
|
453
509
|
# Must be called after load_role
|
|
454
510
|
# Computes and syncs the STS_ASSUME_ROLE allow relationship
|
|
455
|
-
logger.info(
|
|
511
|
+
logger.info(
|
|
512
|
+
"Syncing assume role mappings for account '%s'.",
|
|
513
|
+
current_aws_account_id,
|
|
514
|
+
)
|
|
456
515
|
query_potential_matches = """
|
|
457
516
|
MATCH (:AWSAccount{id:$AccountId})-[:RESOURCE]->(target:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(source:AWSPrincipal)
|
|
458
517
|
WHERE NOT source.arn ENDS WITH 'root'
|
|
@@ -487,14 +546,18 @@ def sync_assumerole_relationships(
|
|
|
487
546
|
aws_update_tag=aws_update_tag,
|
|
488
547
|
)
|
|
489
548
|
run_cleanup_job(
|
|
490
|
-
|
|
549
|
+
"aws_import_roles_policy_cleanup.json",
|
|
491
550
|
neo4j_session,
|
|
492
551
|
common_job_parameters,
|
|
493
552
|
)
|
|
494
553
|
|
|
495
554
|
|
|
496
555
|
@timeit
|
|
497
|
-
def load_user_access_keys(
|
|
556
|
+
def load_user_access_keys(
|
|
557
|
+
neo4j_session: neo4j.Session,
|
|
558
|
+
user_access_keys: Dict,
|
|
559
|
+
aws_update_tag: int,
|
|
560
|
+
) -> None:
|
|
498
561
|
# TODO change the node label to reflect that this is a user access key, not an account access key
|
|
499
562
|
ingest_account_key = """
|
|
500
563
|
MATCH (user:AWSUser{arn: $UserARN})
|
|
@@ -514,16 +577,16 @@ def load_user_access_keys(neo4j_session: neo4j.Session, user_access_keys: Dict,
|
|
|
514
577
|
|
|
515
578
|
for arn, access_keys in user_access_keys.items():
|
|
516
579
|
for key in access_keys["AccessKeyMetadata"]:
|
|
517
|
-
if key.get(
|
|
580
|
+
if key.get("AccessKeyId"):
|
|
518
581
|
neo4j_session.run(
|
|
519
582
|
ingest_account_key,
|
|
520
583
|
UserARN=arn,
|
|
521
|
-
AccessKeyId=key[
|
|
522
|
-
CreateDate=str(key[
|
|
523
|
-
Status=key[
|
|
524
|
-
LastUsedDate=key[
|
|
525
|
-
LastUsedService=key[
|
|
526
|
-
LastUsedRegion=key[
|
|
584
|
+
AccessKeyId=key["AccessKeyId"],
|
|
585
|
+
CreateDate=str(key["CreateDate"]),
|
|
586
|
+
Status=key["Status"],
|
|
587
|
+
LastUsedDate=key["LastUsedDate"],
|
|
588
|
+
LastUsedService=key["LastUsedService"],
|
|
589
|
+
LastUsedRegion=key["LastUsedRegion"],
|
|
527
590
|
aws_update_tag=aws_update_tag,
|
|
528
591
|
)
|
|
529
592
|
|
|
@@ -561,14 +624,23 @@ def _transform_policy_statements(statements: Any, policy_id: str) -> List[Dict]:
|
|
|
561
624
|
|
|
562
625
|
def transform_policy_data(policy_map: Dict, policy_type: str) -> None:
|
|
563
626
|
for principal_arn, policy_statement_map in policy_map.items():
|
|
564
|
-
logger.debug(
|
|
627
|
+
logger.debug(
|
|
628
|
+
f"Transforming IAM {policy_type} policies for principal {principal_arn}",
|
|
629
|
+
)
|
|
565
630
|
for policy_key, statements in policy_statement_map.items():
|
|
566
|
-
policy_id =
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
631
|
+
policy_id = (
|
|
632
|
+
transform_policy_id(
|
|
633
|
+
principal_arn,
|
|
634
|
+
policy_type,
|
|
635
|
+
policy_key,
|
|
636
|
+
)
|
|
637
|
+
if policy_type == PolicyType.inline.value
|
|
638
|
+
else policy_key
|
|
639
|
+
)
|
|
640
|
+
policy_statement_map[policy_key] = _transform_policy_statements(
|
|
641
|
+
statements,
|
|
642
|
+
policy_id,
|
|
643
|
+
)
|
|
572
644
|
|
|
573
645
|
|
|
574
646
|
def transform_policy_id(principal_arn: str, policy_type: str, name: str) -> str:
|
|
@@ -576,7 +648,11 @@ def transform_policy_id(principal_arn: str, policy_type: str, name: str) -> str:
|
|
|
576
648
|
|
|
577
649
|
|
|
578
650
|
def _load_policy_tx(
|
|
579
|
-
tx: neo4j.Transaction,
|
|
651
|
+
tx: neo4j.Transaction,
|
|
652
|
+
policy_id: str,
|
|
653
|
+
policy_name: str,
|
|
654
|
+
policy_type: str,
|
|
655
|
+
principal_arn: str,
|
|
580
656
|
aws_update_tag: int,
|
|
581
657
|
) -> None:
|
|
582
658
|
ingest_policy = """
|
|
@@ -603,15 +679,29 @@ def _load_policy_tx(
|
|
|
603
679
|
|
|
604
680
|
@timeit
|
|
605
681
|
def load_policy(
|
|
606
|
-
neo4j_session: neo4j.Session,
|
|
682
|
+
neo4j_session: neo4j.Session,
|
|
683
|
+
policy_id: str,
|
|
684
|
+
policy_name: str,
|
|
685
|
+
policy_type: str,
|
|
686
|
+
principal_arn: str,
|
|
607
687
|
aws_update_tag: int,
|
|
608
688
|
) -> None:
|
|
609
|
-
neo4j_session.write_transaction(
|
|
689
|
+
neo4j_session.write_transaction(
|
|
690
|
+
_load_policy_tx,
|
|
691
|
+
policy_id,
|
|
692
|
+
policy_name,
|
|
693
|
+
policy_type,
|
|
694
|
+
principal_arn,
|
|
695
|
+
aws_update_tag,
|
|
696
|
+
)
|
|
610
697
|
|
|
611
698
|
|
|
612
699
|
@timeit
|
|
613
700
|
def load_policy_statements(
|
|
614
|
-
neo4j_session: neo4j.Session,
|
|
701
|
+
neo4j_session: neo4j.Session,
|
|
702
|
+
policy_id: str,
|
|
703
|
+
policy_name: str,
|
|
704
|
+
statements: Any,
|
|
615
705
|
aws_update_tag: int,
|
|
616
706
|
) -> None:
|
|
617
707
|
ingest_policy_statement = """
|
|
@@ -643,143 +733,258 @@ def load_policy_statements(
|
|
|
643
733
|
|
|
644
734
|
@timeit
|
|
645
735
|
def load_policy_data(
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
736
|
+
neo4j_session: neo4j.Session,
|
|
737
|
+
principal_policy_map: Dict[str, Dict[str, Any]],
|
|
738
|
+
policy_type: str,
|
|
739
|
+
aws_update_tag: int,
|
|
650
740
|
) -> None:
|
|
651
741
|
for principal_arn, policy_statement_map in principal_policy_map.items():
|
|
652
742
|
logger.debug(f"Loading policies for principal {principal_arn}")
|
|
653
743
|
for policy_key, statements in policy_statement_map.items():
|
|
654
|
-
policy_name =
|
|
655
|
-
|
|
656
|
-
|
|
744
|
+
policy_name = (
|
|
745
|
+
policy_key
|
|
746
|
+
if policy_type == PolicyType.inline.value
|
|
747
|
+
else get_policy_name_from_arn(policy_key)
|
|
748
|
+
)
|
|
749
|
+
policy_id = (
|
|
750
|
+
transform_policy_id(
|
|
751
|
+
principal_arn,
|
|
752
|
+
policy_type,
|
|
753
|
+
policy_key,
|
|
754
|
+
)
|
|
755
|
+
if policy_type == PolicyType.inline.value
|
|
756
|
+
else policy_key
|
|
757
|
+
)
|
|
758
|
+
load_policy(
|
|
759
|
+
neo4j_session,
|
|
760
|
+
policy_id,
|
|
761
|
+
policy_name,
|
|
657
762
|
policy_type,
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
load_policy_statements(
|
|
763
|
+
principal_arn,
|
|
764
|
+
aws_update_tag,
|
|
765
|
+
)
|
|
766
|
+
load_policy_statements(
|
|
767
|
+
neo4j_session,
|
|
768
|
+
policy_id,
|
|
769
|
+
policy_name,
|
|
770
|
+
statements,
|
|
771
|
+
aws_update_tag,
|
|
772
|
+
)
|
|
662
773
|
|
|
663
774
|
|
|
664
775
|
@timeit
|
|
665
776
|
def sync_users(
|
|
666
|
-
neo4j_session: neo4j.Session,
|
|
667
|
-
|
|
777
|
+
neo4j_session: neo4j.Session,
|
|
778
|
+
boto3_session: boto3.session.Session,
|
|
779
|
+
current_aws_account_id: str,
|
|
780
|
+
aws_update_tag: int,
|
|
781
|
+
common_job_parameters: Dict,
|
|
668
782
|
) -> None:
|
|
669
783
|
logger.info("Syncing IAM users for account '%s'.", current_aws_account_id)
|
|
670
784
|
data = get_user_list_data(boto3_session)
|
|
671
|
-
load_users(neo4j_session, data[
|
|
785
|
+
load_users(neo4j_session, data["Users"], current_aws_account_id, aws_update_tag)
|
|
672
786
|
|
|
673
787
|
sync_user_inline_policies(boto3_session, data, neo4j_session, aws_update_tag)
|
|
674
788
|
|
|
675
789
|
sync_user_managed_policies(boto3_session, data, neo4j_session, aws_update_tag)
|
|
676
790
|
|
|
677
|
-
run_cleanup_job(
|
|
791
|
+
run_cleanup_job(
|
|
792
|
+
"aws_import_users_cleanup.json",
|
|
793
|
+
neo4j_session,
|
|
794
|
+
common_job_parameters,
|
|
795
|
+
)
|
|
678
796
|
|
|
679
797
|
|
|
680
798
|
@timeit
|
|
681
799
|
def sync_user_managed_policies(
|
|
682
|
-
boto3_session: boto3.session.Session,
|
|
800
|
+
boto3_session: boto3.session.Session,
|
|
801
|
+
data: Dict,
|
|
802
|
+
neo4j_session: neo4j.Session,
|
|
683
803
|
aws_update_tag: int,
|
|
684
804
|
) -> None:
|
|
685
|
-
managed_policy_data = get_user_managed_policy_data(boto3_session, data[
|
|
805
|
+
managed_policy_data = get_user_managed_policy_data(boto3_session, data["Users"])
|
|
686
806
|
transform_policy_data(managed_policy_data, PolicyType.managed.value)
|
|
687
|
-
load_policy_data(
|
|
807
|
+
load_policy_data(
|
|
808
|
+
neo4j_session,
|
|
809
|
+
managed_policy_data,
|
|
810
|
+
PolicyType.managed.value,
|
|
811
|
+
aws_update_tag,
|
|
812
|
+
)
|
|
688
813
|
|
|
689
814
|
|
|
690
815
|
@timeit
|
|
691
816
|
def sync_user_inline_policies(
|
|
692
|
-
boto3_session: boto3.session.Session,
|
|
817
|
+
boto3_session: boto3.session.Session,
|
|
818
|
+
data: Dict,
|
|
819
|
+
neo4j_session: neo4j.Session,
|
|
693
820
|
aws_update_tag: int,
|
|
694
821
|
) -> None:
|
|
695
|
-
policy_data = get_user_policy_data(boto3_session, data[
|
|
822
|
+
policy_data = get_user_policy_data(boto3_session, data["Users"])
|
|
696
823
|
transform_policy_data(policy_data, PolicyType.inline.value)
|
|
697
|
-
load_policy_data(
|
|
824
|
+
load_policy_data(
|
|
825
|
+
neo4j_session,
|
|
826
|
+
policy_data,
|
|
827
|
+
PolicyType.inline.value,
|
|
828
|
+
aws_update_tag,
|
|
829
|
+
)
|
|
698
830
|
|
|
699
831
|
|
|
700
832
|
@timeit
|
|
701
833
|
def sync_groups(
|
|
702
|
-
neo4j_session: neo4j.Session,
|
|
703
|
-
|
|
834
|
+
neo4j_session: neo4j.Session,
|
|
835
|
+
boto3_session: boto3.session.Session,
|
|
836
|
+
current_aws_account_id: str,
|
|
837
|
+
aws_update_tag: int,
|
|
838
|
+
common_job_parameters: Dict,
|
|
704
839
|
) -> None:
|
|
705
840
|
logger.info("Syncing IAM groups for account '%s'.", current_aws_account_id)
|
|
706
841
|
data = get_group_list_data(boto3_session)
|
|
707
|
-
load_groups(neo4j_session, data[
|
|
842
|
+
load_groups(neo4j_session, data["Groups"], current_aws_account_id, aws_update_tag)
|
|
708
843
|
|
|
709
844
|
sync_groups_inline_policies(boto3_session, data, neo4j_session, aws_update_tag)
|
|
710
845
|
|
|
711
846
|
sync_group_managed_policies(boto3_session, data, neo4j_session, aws_update_tag)
|
|
712
847
|
|
|
713
|
-
run_cleanup_job(
|
|
848
|
+
run_cleanup_job(
|
|
849
|
+
"aws_import_groups_cleanup.json",
|
|
850
|
+
neo4j_session,
|
|
851
|
+
common_job_parameters,
|
|
852
|
+
)
|
|
714
853
|
|
|
715
854
|
|
|
716
855
|
def sync_group_managed_policies(
|
|
717
|
-
boto3_session: boto3.session.Session,
|
|
856
|
+
boto3_session: boto3.session.Session,
|
|
857
|
+
data: Dict,
|
|
858
|
+
neo4j_session: neo4j.Session,
|
|
718
859
|
aws_update_tag: int,
|
|
719
860
|
) -> None:
|
|
720
861
|
managed_policy_data = get_group_managed_policy_data(boto3_session, data["Groups"])
|
|
721
862
|
transform_policy_data(managed_policy_data, PolicyType.managed.value)
|
|
722
|
-
load_policy_data(
|
|
863
|
+
load_policy_data(
|
|
864
|
+
neo4j_session,
|
|
865
|
+
managed_policy_data,
|
|
866
|
+
PolicyType.managed.value,
|
|
867
|
+
aws_update_tag,
|
|
868
|
+
)
|
|
723
869
|
|
|
724
870
|
|
|
725
871
|
def sync_groups_inline_policies(
|
|
726
|
-
boto3_session: boto3.session.Session,
|
|
872
|
+
boto3_session: boto3.session.Session,
|
|
873
|
+
data: Dict,
|
|
874
|
+
neo4j_session: neo4j.Session,
|
|
727
875
|
aws_update_tag: int,
|
|
728
876
|
) -> None:
|
|
729
877
|
policy_data = get_group_policy_data(boto3_session, data["Groups"])
|
|
730
878
|
transform_policy_data(policy_data, PolicyType.inline.value)
|
|
731
|
-
load_policy_data(
|
|
879
|
+
load_policy_data(
|
|
880
|
+
neo4j_session,
|
|
881
|
+
policy_data,
|
|
882
|
+
PolicyType.inline.value,
|
|
883
|
+
aws_update_tag,
|
|
884
|
+
)
|
|
732
885
|
|
|
733
886
|
|
|
734
887
|
@timeit
|
|
735
888
|
def sync_roles(
|
|
736
|
-
neo4j_session: neo4j.Session,
|
|
737
|
-
|
|
889
|
+
neo4j_session: neo4j.Session,
|
|
890
|
+
boto3_session: boto3.session.Session,
|
|
891
|
+
current_aws_account_id: str,
|
|
892
|
+
aws_update_tag: int,
|
|
893
|
+
common_job_parameters: Dict,
|
|
738
894
|
) -> None:
|
|
739
895
|
logger.info("Syncing IAM roles for account '%s'.", current_aws_account_id)
|
|
740
896
|
data = get_role_list_data(boto3_session)
|
|
741
|
-
load_roles(neo4j_session, data[
|
|
897
|
+
load_roles(neo4j_session, data["Roles"], current_aws_account_id, aws_update_tag)
|
|
742
898
|
|
|
743
|
-
sync_role_inline_policies(
|
|
899
|
+
sync_role_inline_policies(
|
|
900
|
+
current_aws_account_id,
|
|
901
|
+
boto3_session,
|
|
902
|
+
data,
|
|
903
|
+
neo4j_session,
|
|
904
|
+
aws_update_tag,
|
|
905
|
+
)
|
|
744
906
|
|
|
745
|
-
sync_role_managed_policies(
|
|
907
|
+
sync_role_managed_policies(
|
|
908
|
+
current_aws_account_id,
|
|
909
|
+
boto3_session,
|
|
910
|
+
data,
|
|
911
|
+
neo4j_session,
|
|
912
|
+
aws_update_tag,
|
|
913
|
+
)
|
|
746
914
|
|
|
747
|
-
run_cleanup_job(
|
|
915
|
+
run_cleanup_job(
|
|
916
|
+
"aws_import_roles_cleanup.json",
|
|
917
|
+
neo4j_session,
|
|
918
|
+
common_job_parameters,
|
|
919
|
+
)
|
|
748
920
|
|
|
749
921
|
|
|
750
922
|
def sync_role_managed_policies(
|
|
751
|
-
current_aws_account_id: str,
|
|
752
|
-
|
|
923
|
+
current_aws_account_id: str,
|
|
924
|
+
boto3_session: boto3.session.Session,
|
|
925
|
+
data: Dict,
|
|
926
|
+
neo4j_session: neo4j.Session,
|
|
927
|
+
aws_update_tag: int,
|
|
753
928
|
) -> None:
|
|
754
|
-
logger.info(
|
|
929
|
+
logger.info(
|
|
930
|
+
"Syncing IAM role managed policies for account '%s'.",
|
|
931
|
+
current_aws_account_id,
|
|
932
|
+
)
|
|
755
933
|
managed_policy_data = get_role_managed_policy_data(boto3_session, data["Roles"])
|
|
756
934
|
transform_policy_data(managed_policy_data, PolicyType.managed.value)
|
|
757
|
-
load_policy_data(
|
|
935
|
+
load_policy_data(
|
|
936
|
+
neo4j_session,
|
|
937
|
+
managed_policy_data,
|
|
938
|
+
PolicyType.managed.value,
|
|
939
|
+
aws_update_tag,
|
|
940
|
+
)
|
|
758
941
|
|
|
759
942
|
|
|
760
943
|
def sync_role_inline_policies(
|
|
761
|
-
current_aws_account_id: str,
|
|
762
|
-
|
|
944
|
+
current_aws_account_id: str,
|
|
945
|
+
boto3_session: boto3.session.Session,
|
|
946
|
+
data: Dict,
|
|
947
|
+
neo4j_session: neo4j.Session,
|
|
948
|
+
aws_update_tag: int,
|
|
763
949
|
) -> None:
|
|
764
|
-
logger.info(
|
|
950
|
+
logger.info(
|
|
951
|
+
"Syncing IAM role inline policies for account '%s'.",
|
|
952
|
+
current_aws_account_id,
|
|
953
|
+
)
|
|
765
954
|
inline_policy_data = get_role_policy_data(boto3_session, data["Roles"])
|
|
766
955
|
transform_policy_data(inline_policy_data, PolicyType.inline.value)
|
|
767
|
-
load_policy_data(
|
|
956
|
+
load_policy_data(
|
|
957
|
+
neo4j_session,
|
|
958
|
+
inline_policy_data,
|
|
959
|
+
PolicyType.inline.value,
|
|
960
|
+
aws_update_tag,
|
|
961
|
+
)
|
|
768
962
|
|
|
769
963
|
|
|
770
964
|
@timeit
|
|
771
965
|
def sync_group_memberships(
|
|
772
|
-
neo4j_session: neo4j.Session,
|
|
773
|
-
|
|
966
|
+
neo4j_session: neo4j.Session,
|
|
967
|
+
boto3_session: boto3.session.Session,
|
|
968
|
+
current_aws_account_id: str,
|
|
969
|
+
aws_update_tag: int,
|
|
970
|
+
common_job_parameters: Dict,
|
|
774
971
|
) -> None:
|
|
775
|
-
logger.info(
|
|
776
|
-
|
|
777
|
-
|
|
972
|
+
logger.info(
|
|
973
|
+
"Syncing IAM group membership for account '%s'.",
|
|
974
|
+
current_aws_account_id,
|
|
975
|
+
)
|
|
976
|
+
query = (
|
|
977
|
+
"MATCH (group:AWSGroup)<-[:RESOURCE]-(:AWSAccount{id: $AWS_ACCOUNT_ID}) "
|
|
978
|
+
"return group.name as name, group.arn as arn;"
|
|
979
|
+
)
|
|
778
980
|
groups = neo4j_session.run(query, AWS_ACCOUNT_ID=current_aws_account_id)
|
|
779
|
-
groups_membership = {
|
|
981
|
+
groups_membership = {
|
|
982
|
+
group["arn"]: get_group_membership_data(boto3_session, group["name"])
|
|
983
|
+
for group in groups
|
|
984
|
+
}
|
|
780
985
|
load_group_memberships(neo4j_session, groups_membership, aws_update_tag)
|
|
781
986
|
run_cleanup_job(
|
|
782
|
-
|
|
987
|
+
"aws_import_groups_membership_cleanup.json",
|
|
783
988
|
neo4j_session,
|
|
784
989
|
common_job_parameters,
|
|
785
990
|
)
|
|
@@ -787,19 +992,27 @@ def sync_group_memberships(
|
|
|
787
992
|
|
|
788
993
|
@timeit
|
|
789
994
|
def sync_user_access_keys(
|
|
790
|
-
neo4j_session: neo4j.Session,
|
|
791
|
-
|
|
995
|
+
neo4j_session: neo4j.Session,
|
|
996
|
+
boto3_session: boto3.session.Session,
|
|
997
|
+
current_aws_account_id: str,
|
|
998
|
+
aws_update_tag: int,
|
|
999
|
+
common_job_parameters: Dict,
|
|
792
1000
|
) -> None:
|
|
793
|
-
logger.info(
|
|
794
|
-
|
|
795
|
-
|
|
1001
|
+
logger.info(
|
|
1002
|
+
"Syncing IAM user access keys for account '%s'.",
|
|
1003
|
+
current_aws_account_id,
|
|
1004
|
+
)
|
|
1005
|
+
query = (
|
|
1006
|
+
"MATCH (user:AWSUser)<-[:RESOURCE]-(:AWSAccount{id: $AWS_ACCOUNT_ID}) "
|
|
1007
|
+
"RETURN user.name as name, user.arn as arn"
|
|
1008
|
+
)
|
|
796
1009
|
for user in neo4j_session.run(query, AWS_ACCOUNT_ID=current_aws_account_id):
|
|
797
1010
|
access_keys = get_account_access_key_data(boto3_session, user["name"])
|
|
798
1011
|
if access_keys:
|
|
799
1012
|
account_access_keys = {user["arn"]: access_keys}
|
|
800
1013
|
load_user_access_keys(neo4j_session, account_access_keys, aws_update_tag)
|
|
801
1014
|
run_cleanup_job(
|
|
802
|
-
|
|
1015
|
+
"aws_import_account_access_key_cleanup.json",
|
|
803
1016
|
neo4j_session,
|
|
804
1017
|
common_job_parameters,
|
|
805
1018
|
)
|
|
@@ -807,24 +1020,67 @@ def sync_user_access_keys(
|
|
|
807
1020
|
|
|
808
1021
|
@timeit
|
|
809
1022
|
def sync(
|
|
810
|
-
neo4j_session: neo4j.Session,
|
|
811
|
-
|
|
1023
|
+
neo4j_session: neo4j.Session,
|
|
1024
|
+
boto3_session: boto3.session.Session,
|
|
1025
|
+
regions: List[str],
|
|
1026
|
+
current_aws_account_id: str,
|
|
1027
|
+
update_tag: int,
|
|
1028
|
+
common_job_parameters: Dict,
|
|
812
1029
|
) -> None:
|
|
813
1030
|
logger.info("Syncing IAM for account '%s'.", current_aws_account_id)
|
|
814
1031
|
# This module only syncs IAM information that is in use.
|
|
815
1032
|
# As such only policies that are attached to a user, role or group are synced
|
|
816
|
-
sync_users(
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
1033
|
+
sync_users(
|
|
1034
|
+
neo4j_session,
|
|
1035
|
+
boto3_session,
|
|
1036
|
+
current_aws_account_id,
|
|
1037
|
+
update_tag,
|
|
1038
|
+
common_job_parameters,
|
|
1039
|
+
)
|
|
1040
|
+
sync_groups(
|
|
1041
|
+
neo4j_session,
|
|
1042
|
+
boto3_session,
|
|
1043
|
+
current_aws_account_id,
|
|
1044
|
+
update_tag,
|
|
1045
|
+
common_job_parameters,
|
|
1046
|
+
)
|
|
1047
|
+
sync_roles(
|
|
1048
|
+
neo4j_session,
|
|
1049
|
+
boto3_session,
|
|
1050
|
+
current_aws_account_id,
|
|
1051
|
+
update_tag,
|
|
1052
|
+
common_job_parameters,
|
|
1053
|
+
)
|
|
1054
|
+
sync_group_memberships(
|
|
1055
|
+
neo4j_session,
|
|
1056
|
+
boto3_session,
|
|
1057
|
+
current_aws_account_id,
|
|
1058
|
+
update_tag,
|
|
1059
|
+
common_job_parameters,
|
|
1060
|
+
)
|
|
1061
|
+
sync_assumerole_relationships(
|
|
1062
|
+
neo4j_session,
|
|
1063
|
+
current_aws_account_id,
|
|
1064
|
+
update_tag,
|
|
1065
|
+
common_job_parameters,
|
|
1066
|
+
)
|
|
1067
|
+
sync_user_access_keys(
|
|
1068
|
+
neo4j_session,
|
|
1069
|
+
boto3_session,
|
|
1070
|
+
current_aws_account_id,
|
|
1071
|
+
update_tag,
|
|
1072
|
+
common_job_parameters,
|
|
1073
|
+
)
|
|
1074
|
+
run_cleanup_job(
|
|
1075
|
+
"aws_import_principals_cleanup.json",
|
|
1076
|
+
neo4j_session,
|
|
1077
|
+
common_job_parameters,
|
|
1078
|
+
)
|
|
823
1079
|
merge_module_sync_metadata(
|
|
824
1080
|
neo4j_session,
|
|
825
|
-
group_type=
|
|
1081
|
+
group_type="AWSAccount",
|
|
826
1082
|
group_id=current_aws_account_id,
|
|
827
|
-
synced_type=
|
|
1083
|
+
synced_type="AWSPrincipal",
|
|
828
1084
|
update_tag=update_tag,
|
|
829
1085
|
stat_handler=stat_handler,
|
|
830
1086
|
)
|