def update_role_data(dynamo_table, account_number, role, current_policy, source='Scan', add_no_repo=True): """ Compare the current version of a policy for a role and what has been previously stored in Dynamo. - If current and new policy versions are different store the new version in Dynamo. Add any newly added permissions to temporary permission blacklist. Purge any old entries from permission blacklist. - Refresh the updated time on the role policy - If the role is completely new, store the first version in Dynamo - Updates the role with full history of policies, including current version Args: dynamo_table account_number role (Role): current role being updated current_policy (dict): representation of the current policy version source: Default 'Scan' but could be Repo, Rollback, etc Returns: None """ # policy_entry: source, discovered, policy stored_role = get_role_data(dynamo_table, role.role_id, fields=['OptOut', 'Policies']) if not stored_role: role_dict = store_initial_role_data(dynamo_table, role.arn, role.create_date, role.role_id, role.role_name, account_number, current_policy) role.set_attributes(role_dict) LOGGER.info('Added new role ({}): {}'.format(role.role_id, role.arn)) else: # is the policy list the same as the last we had? old_policy = stored_role['Policies'][-1]['Policy'] if current_policy != old_policy: add_new_policy_version(dynamo_table, role, current_policy, source) LOGGER.info( '{} has different inline policies than last time, adding to role store' .format(role.arn)) newly_added_permissions = find_newly_added_permissions( old_policy, current_policy) else: newly_added_permissions = set() if add_no_repo: update_no_repo_permissions(dynamo_table, role, newly_added_permissions) update_opt_out(dynamo_table, role) set_role_data(dynamo_table, role.role_id, {'Refreshed': datetime.datetime.utcnow().isoformat()}) role.policies = get_role_data(dynamo_table, role.role_id, fields=['Policies'])['Policies']
def update_role_data(dynamo_table, account_number, role, current_policy, current_managed_policy, source="Scan", add_no_repo=True, include_managed_policies=True): """ Compare the current version of a policy for a role and what has been previously stored in Dynamo. - If current and new policy versions are different store the new version in Dynamo. Add any newly added permissions to temporary permission blocklist. Purge any old entries from permission blocklist. - Refresh the updated time on the role policy - If the role is completely new, store the first version in Dynamo - Updates the role with full history of policies, including current version Args: dynamo_table account_number role (Role): current role being updated current_policy (dict): representation of the current policy version current_managed_policy (dict): representation of the current managed policy versions source: Default 'Scan' but could be Repo, Rollback, etc add_no_repo (bool) Returns: None """ # policy_entry: source, discovered, policy stored_role = get_role_data( dynamo_table, role.role_id, fields=["OptOut", "Policies", "ManagedPolicies", "Tags"]) if not stored_role: role_dict = store_initial_role_data( dynamo_table, role.arn, role.create_date, role.role_id, role.role_name, account_number, current_policy, current_managed_policy, role.tags, ) role_updates = Role.parse_obj(role_dict) update_dict = role_updates.dict(exclude_unset=True) role = role.copy(update=update_dict) LOGGER.info("Added new role ({}): {}".format(role.role_id, role.arn)) return role else: # is the policy list the same as the last we had? old_policy = stored_role["Policies"][-1]["Policy"] if current_policy != old_policy: add_new_policy_version(dynamo_table, role, current_policy, source) LOGGER.info( "{} has different inline policies than last time, adding to role store" .format(role.arn)) newly_added_permissions = find_newly_added_permissions( old_policy, current_policy) else: newly_added_permissions = set() # TODO Make this part of set_role_data instead to allow updating existing dynamo tables # TODO this code will not work with existing dynamo tables - because old roles won't have ManagedPolicies old_managed_policy = stored_role["ManagedPolicies"][-1]["Policy"] if current_managed_policy != old_managed_policy: add_new_managed_policy_version(dynamo_table, role, current_managed_policy, source) LOGGER.info( "{} has different managed policies than last time, adding to role store" .format(role.arn)) newly_added_managed_permissions = find_newly_added_permissions( old_managed_policy, current_managed_policy) else: newly_added_managed_permissions = set() # update tags if needed if role.tags != stored_role.get("Tags", []): set_role_data(dynamo_table, role.role_id, {"Tags": role.tags}) if add_no_repo: update_no_repo_permissions(dynamo_table, role, newly_added_permissions) if include_managed_policies: update_no_repo_permissions(dynamo_table, role, newly_added_managed_permissions) update_opt_out(dynamo_table, role) set_role_data( dynamo_table, role.role_id, {"Refreshed": datetime.datetime.utcnow().isoformat()}, ) # Update all data from Dynamo except CreateDate (it's in the wrong format) and DQ_by (we're going to recalc) current_role_data = get_role_data(dynamo_table, role.role_id) current_role_data.pop("CreateDate", None) current_role_data.pop("DisqualifiedBy", None) # Create an updated Role model to be returned to the caller role_updates = Role.parse_obj(current_role_data) update_dict = role_updates.dict(exclude_unset=True) role = role.copy(update=update_dict) return role