def __init__(self, session, account_id): self.session = session self.account_id = account_id self.iam = BotoFactory().get_capability(boto3.client, session, 'iam', account_id=account_id)
def get_all_cloudtrails_list(self, session, account_id): cloudtrail = BotoFactory().get_capability(boto3.client, session, 'cloudtrail', account_id) trails = cloudtrail.describe_trails( includeShadowTrails=True).get('trailList') return trails
def get_all_email_validated_certs(self): """returns an ARN list of all ACM certificates with email validation""" certificates = list() for r in self.regions: logging.info(f"Processing {self.account_id}:{r}") try: acm = BotoFactory().get_capability( boto3.client, self.session, 'acm', account_id=self.account_id, region=r, rolename='AxisCloudAdmin' ) pngt = acm.get_paginator('list_certificates') itr = pngt.paginate( CertificateStatuses=self.certificate_status ) for i in itr: for c in i.get('CertificateSummaryList'): result = ( acm.describe_certificate( CertificateArn=c.get('CertificateArn') ) ) validations_opts = result.get( 'Certificate').get( 'DomainValidationOptions') for v in validations_opts: if v.get('ValidationMethod') == 'EMAIL': certificates.append(c.get('CertificateArn')) except Exception as e: logging.error(f"{e} for {r}") logging.info(certificates) return certificates
def all_stacks_all_regions(self): regions = [ "eu-north-1", "ap-south-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-2", "ap-northeast-1", "sa-east-1", "ca-central-1", "ap-southeast-1", "ap-southeast-2", "eu-central-1", "us-east-1", "us-east-2", "us-west-1", "us-west-2" ] stacks_inventory = list() for r in regions: regional_cfn = BotoFactory().get_capability( boto3.client, self.session, 'cloudformation', account_id=self.account_id, region=r) pgnt = regional_cfn.get_paginator('list_stacks') itr = pgnt.paginate() for i in itr: for stack in i['StackSummaries']: log.info(f"{stack['StackId']}:{stack['StackStatus']}") stacks_inventory.append( f"{stack['StackId']}:{stack['StackStatus']}") log.info(stacks_inventory) return stacks_inventory
def __get_vpn_connections(self, region): ec2 = BotoFactory().get_capability(boto3.client, self.session, 'ec2', account_id=self.account_id, region=region) result = ec2.describe_vpn_connections().get('VpnConnections') return result
def delete_cloudtrail_name(self, session, account_id, region, ct_name): cloudtrail = BotoFactory().get_capability(boto3.client, session, 'cloudtrail', account_id) arn = f"arn:aws:cloudtrail:{region}:{account_id}:trail/{ct_name}" try: print(cloudtrail.delete_trail(Name=arn)) except Exception as e: logging.warning(e)
def __init__(self, session): if os.environ.get('OU_BLOCKLIST'): self.blocklist = os.environ.get('OU_BLOCKLIST').split(',') log.info(f"OU blocklist: {self.blocklist}") else: log.warn( "No OU_BLOCKLIST present in ENV, all OUs can be traversed") self.blocklist = set() self.org = BotoFactory().get_capability(boto3.client, session, 'organizations')
def fetch_role_arn(session, account_id, rolename): global arn_list iam = BotoFactory().get_capability( boto3.resource, session, 'iam', account_id=account_id ) try: role = iam.Role(rolename) print(role.arn) arn_list.append(role.arn) except iam.meta.client.exceptions.NoSuchEntityException as e: log.warn(f"not found in {account_id}, {e}")
def __get_subnets(self, region): ec2 = BotoFactory().get_capability(boto3.client, self.session, 'ec2', account_id=self.account_id, region=region) pgnt = ec2.get_paginator('describe_subnets') itr = pgnt.paginate() for i in itr: result = i.get('Subnets') logging.info(f"{self.account_id}:{region}:{result}") return result
def add_console_users_to_group(session, account_id, group_name): """ adds all users with password (login profile) active to a specified group """ users_w_pw = IAMOps().get_all_iam_users_with_pw(session, account_id) iam = BotoFactory().get_capability( boto3.client, session, 'iam', account_id=account_id ) for user in users_w_pw: iam.add_user_to_group( GroupName='RequireMFA', UserName=user ) log.info(f"Added {account_id}:{user} to {group_name}") print(f"Added {account_id}:{user} to {group_name}")
def get_active_accounts(session): """ Fetches all active account IDs from an Organization. To get accounts from an OU structure, refer to OrganizationsOps class instead, app/org_ops.py """ org = BotoFactory().get_capability( boto3.client, session, 'organizations', os.getenv('ORG_ACCOUNT'), os.getenv('DEFAULT_ROLE') ) accounts = dict() paginator = org.get_paginator('list_accounts') itr = paginator.paginate() for i in itr: for account in i['Accounts']: if account['Status'] == 'ACTIVE': accounts[account['Id']] = account return accounts
class OrganizationsOps(): def __init__(self, session): if os.environ.get('OU_BLOCKLIST'): self.blocklist = os.environ.get('OU_BLOCKLIST').split(',') log.info(f"OU blocklist: {self.blocklist}") else: log.warn( "No OU_BLOCKLIST present in ENV, all OUs can be traversed") self.blocklist = set() self.org = BotoFactory().get_capability(boto3.client, session, 'organizations') def get_all_children_ou(self, parent_ou): ous = set() log.info(f"Getting children OU for {parent_ou}") pgnt = self.org.get_paginator('list_organizational_units_for_parent') itr = pgnt.paginate(ParentId=parent_ou) for i in itr: for ou in i['OrganizationalUnits']: if ou['Id'] not in self.blocklist: ous.add(ou['Id']) if ous: for ou in ous.copy(): ous.update(self.get_all_children_ou(ou)) return ous def get_active_accounts_from_ous(self, ous): pngt = self.org.get_paginator('list_accounts_for_parent') accounts = list() for ou in ous: log.info(f"Getting accounts from {ou}") accounts.extend([ account['Id'] for account in pngt.paginate( ParentId=ou).build_full_result()['Accounts'] if account['Status'] == 'ACTIVE' ]) return accounts def get_accounts_from_root(self): root_ou = self.org.list_roots()['Roots'][0]['Id'] return self.get_active_accounts_from_ous( self.get_all_children_ou(root_ou))
def get_all_iam_users_with_pw(self): iam_resource = BotoFactory().get_capability(boto3.resource, self.session, 'iam', account_id=self.account_id) users = self.get_all_iam_users() iam_users_with_passwords = set() for user in users: lp = iam_resource.LoginProfile(user) try: lp.create_date iam_users_with_passwords.add( self.iam.get_user(UserName=user)['User']['UserName']) except self.iam.exceptions.NoSuchEntityException: pass return iam_users_with_passwords
def delete_role(self, rolename): try: # get all policies iam_r = BotoFactory().get_capability(boto3.resource, self.session, 'iam', self.account_id, os.getenv('DEFAULT_ROLE')) role = iam_r.Role(rolename) itr = role.policies.all() for i in itr: i.delete() # delete role response = role.delete() logging.info(json.dumps(response, indent=4, default=str)) except iam_r.meta.client.exceptions.NoSuchEntityException as e: logging.info(e) logging.info(f"{self.account_id}: role {rolename} doesn't exist")
def get_all_hosted_zones(session, account_id): """ get all HZ from a given account """ global hosted_zone_dict r53_client = BotoFactory().get_capability( boto3.client, session, 'route53', account_id=account_id ) hz = Route53Ops(client=r53_client).get_all_hosted_zones() log.info(f"{account_id}: {hz}") print(f"{account_id}: {hz}") if len(hz) > 0: hosted_zone_dict[account_id] = hz
class CFNOps(): def __init__(self, account_id): self.session = boto3.Session() self.account_id = account_id self.cfn = BotoFactory().get_capability(boto3.client, self.session, 'cloudformation', account_id) def check_if_stackset_present(self, account_id, stackname): paginator = self.cfn.get_paginator('list_stacks') itr = paginator.paginate() for i in itr: for stack in i['StackSummaries']: if stackname in stack['StackName'] \ and stack['StackStatus'] == 'CREATE_COMPLETE': return True return False def all_stacks_all_regions(self): regions = [ "eu-north-1", "ap-south-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-2", "ap-northeast-1", "sa-east-1", "ca-central-1", "ap-southeast-1", "ap-southeast-2", "eu-central-1", "us-east-1", "us-east-2", "us-west-1", "us-west-2" ] stacks_inventory = list() for r in regions: regional_cfn = BotoFactory().get_capability( boto3.client, self.session, 'cloudformation', account_id=self.account_id, region=r) pgnt = regional_cfn.get_paginator('list_stacks') itr = pgnt.paginate() for i in itr: for stack in i['StackSummaries']: log.info(f"{stack['StackId']}:{stack['StackStatus']}") stacks_inventory.append( f"{stack['StackId']}:{stack['StackStatus']}") log.info(stacks_inventory) return stacks_inventory
class IAMOps(): def __init__(self, session, account_id): self.session = session self.account_id = account_id self.iam = BotoFactory().get_capability(boto3.client, session, 'iam', account_id=account_id) def delete_role(self, rolename): try: # get all policies iam_r = BotoFactory().get_capability(boto3.resource, self.session, 'iam', self.account_id, os.getenv('DEFAULT_ROLE')) role = iam_r.Role(rolename) itr = role.policies.all() for i in itr: i.delete() # delete role response = role.delete() logging.info(json.dumps(response, indent=4, default=str)) except iam_r.meta.client.exceptions.NoSuchEntityException as e: logging.info(e) logging.info(f"{self.account_id}: role {rolename} doesn't exist") def remove_idp(self, idp_name): saml_arn = f"arn:aws:iam::{self.account_id}:saml-provider/{idp_name}" try: response = self.iam.delete_saml_provider(SAMLProviderArn=saml_arn) logging.info(json.dumps(response, indent=4, default=str)) except self.iam.exceptions.NoSuchEntityException: logging.info(f"{self.account_id}: IdP {idp_name} doesn't exist") def update_assume_role_policy(self, rolename, policy): """policy should be in dict-format to be translated to json""" try: return self.iam.update_assume_role_policy( RoleName=rolename, PolicyDocument=json.dumps(policy)) except Exception as e: logging.warning(e) def list_roles_with_trust(self, trusted_account): roles = list() pgn = self.iam.get_paginator('list_roles') itr = pgn.paginate() for i in itr: for r in i['Roles']: policy_doc = r['AssumeRolePolicyDocument'] if trusted_account in json.dumps(policy_doc): roles.append((r['Arn'])) print(roles) return roles def get_all_iam_users(self): users = set() pgnt = self.iam.get_paginator('list_users') itr = pgnt.paginate() for i in itr: for user in i['Users']: users.add(user['UserName']) return users def get_all_iam_users_with_pw(self): iam_resource = BotoFactory().get_capability(boto3.resource, self.session, 'iam', account_id=self.account_id) users = self.get_all_iam_users() iam_users_with_passwords = set() for user in users: lp = iam_resource.LoginProfile(user) try: lp.create_date iam_users_with_passwords.add( self.iam.get_user(UserName=user)['User']['UserName']) except self.iam.exceptions.NoSuchEntityException: pass return iam_users_with_passwords def compare_pw_policy(self, desired_pw_policy): """ Takes IAM current password policy and compares to the desired, return map with each discrepancy. desired_pw_policy is in DICT format, see boto3 documentation for all options. Example desired_pw_policy: { "MinimumPasswordLength": 16, "RequireSymbols": True, "RequireNumbers": True, "RequireUppercaseCharacters": True, "RequireLowercaseCharacters": True, "AllowUsersToChangePassword": True, "ExpirePasswords": True, "MaxPasswordAge": 90, "PasswordReusePrevention": 10, "HardExpiry": False } """ try: account_policy = self.iam.get_account_password_policy().get( 'PasswordPolicy') diff_items = { k: account_policy[k] for k in account_policy if k in desired_pw_policy and account_policy[k] != desired_pw_policy[k] } return diff_items except self.iam.exceptions.NoSuchEntityException as e: logging.warn(f"No password policy exists. {e}") return False def set_minimum_pw_policy(self, desired_pw_policy): """ Sets the minimum password policy in the IAM client's AWS account If there are stronger password requirements than those in the minimum one, the stronger requirement stays """ try: account_policy = self.iam.get_account_password_policy().get( 'PasswordPolicy') except self.iam.exceptions.NoSuchEntityException as e: logging.warn( f"{e}: No password policy exists, setting the desired policy") self.iam.update_account_password_policy(**desired_pw_policy) return self.iam.get_account_password_policy().get('PasswordPolicy') check_if_better = ['MinimumPasswordLength', 'PasswordReusePrevention'] for check in check_if_better: try: if account_policy[check] > desired_pw_policy[check]: desired_pw_policy[check] = account_policy[check] except KeyError: pass self.iam.update_account_password_policy(**desired_pw_policy) return (account_policy) def add_pw_parameter(self, key, value): """ pushes a specific password policy parameter to the IAM password policy, e.g. HardExpiry, MinimumPasswordLength... """ pw_pol = self.iam.get_account_password_policy()['PasswordPolicy'] try: pw_pol[key] except KeyError: pw_pol[key] = None if not pw_pol[key] == value: pw_pol[key] = value pw_pol.pop('ExpirePasswords') self.iam.update_account_password_policy(**pw_pol) return f"success" else: return f"already compliant"
def __init__(self, account_id): self.session = boto3.Session() self.account_id = account_id self.cfn = BotoFactory().get_capability(boto3.client, self.session, 'cloudformation', account_id)