def test__retrieve_noncompliant_checks(): # Arrange check_compliant = Check('TestService', '...', ComplianceStatus.Compliant) check_noncompliant = Check('IAM', 'No IAM users...', ComplianceStatus.NonCompliant) assessment = Assessment('playground-dev', '123456789098') assessment.add_check(check_compliant) assessment.add_check(check_noncompliant) # Act checks = assessment.non_compliant_checks() # handler(event, None) # Assert assert len(checks) == 1
def inventory_wide_open_s3_buckets(regions, session=boto3) -> Check: check = Check('S3', 'S3 bucket wide open for the world', ComplianceStatus.Compliant) client = session.client('s3') response = client.list_buckets() for bucket in response['Buckets']: bucket_name = bucket['Name'] try: response = client.get_bucket_policy_status(Bucket=bucket_name) except ClientError as e: # No bucket policy exist continue policy_status = response['PolicyStatus'] if policy_status['IsPublic']: response = client.get_bucket_policy(Bucket=bucket_name) policy_json = response['Policy'] policy = eval(policy_json) for statement in policy['Statement']: if 'Condition' not in statement: metadata = CheckMetadata('Bucket name', f'{bucket_name}') check.add_metadata(metadata) check.compliance_status = ComplianceStatus.NonCompliant break return check
def inventory_ec2_wide_open_security_groups(regions, session=boto3) -> Check: check = Check('EC2', 'Security Groups should not be wide open for the world', ComplianceStatus.Compliant) for region in regions: client = session.client('ec2', region) response = client.describe_security_groups() for security_group in response['SecurityGroups']: group_name = security_group['GroupName'] for ip_permission in security_group['IpPermissions']: ip_ranges = ip_permission['IpRanges'] for ip_range in ip_ranges: cidr_ip = ip_range['CidrIp'] if cidr_ip == '0.0.0.0/0': from_port = ip_permission['FromPort'] to_port = ip_permission['ToPort'] if from_port != 443 or to_port != 443: check_metadata_1 = CheckMetadata( 'Security group', f'{group_name} ({region})') check_metadata_2 = CheckMetadata( 'Port ranges', f'From port: {from_port} To port: {to_port}') check.add_metadata(check_metadata_1) check.add_metadata(check_metadata_2) check.compliance_status = ComplianceStatus.NonCompliant return check
def inventory_account_mfa_on_root_user(regions, session=boto3) -> Check: check = Check('Account', 'MFA should be enabled on root user', ComplianceStatus.Compliant) client = session.client('iam') response = client.get_account_summary() account_mfa_enabled = response['SummaryMap']['AccountMFAEnabled'] if not account_mfa_enabled: # print('$$$ MFA on ROOT is not enabled') check.compliance_status = ComplianceStatus.NonCompliant return check
def test__create_non_compliant_assessment(): # Arrange check = Check('IAM', 'No IAM users...', ComplianceStatus.NonCompliant) metadata = CheckMetadata(key='ResourceId', value='i-345bh34bjky56b34') check.add_metadata(metadata) assessment = Assessment('playground-dev', '123456789098') assessment.add_check(check) assessment_readable = str(assessment) print(assessment_readable) # Assert assert 'i-345bh34bjky56b34' in assessment_readable
def inventory_s3_as_static_website(regions, session=boto3) -> Check: check = Check('S3', 'S3 bucket should not be used for static hosting', ComplianceStatus.Compliant) client = session.client('s3') response = client.list_buckets() for bucket in response['Buckets']: bucket_name = bucket['Name'] try: response = client.get_bucket_website(Bucket=bucket_name) metadata = CheckMetadata('Bucket name', f'{bucket_name}') check.add_metadata(metadata) check.compliance_status = ComplianceStatus.NonCompliant except: pass return check
def inventory_wide_open_iam_role(regions, session=boto3) -> Check: check = Check('IAM', 'IAM Role wide open for the world', ComplianceStatus.Compliant) client = session.client('iam') response = client.list_roles() roles = response['Roles'] for role in roles: assume_role_policy_document = role['AssumeRolePolicyDocument'] role_name = role['RoleName'] statements = assume_role_policy_document['Statement'] for statement in statements: principal = statement['Principal'] if 'AWS' in principal: if principal['AWS'] == '*': metadata = CheckMetadata('Role', f'{role_name}') check.add_metadata(metadata) check.compliance_status = ComplianceStatus.NonCompliant return check
def inventory_wide_open_sns_topics(regions, session=boto3) -> Check: check = Check('SNS', 'SNS topic wide open for the world', ComplianceStatus.Compliant) for region in regions: client = session.client('sns', region) response = client.list_topics() # NextToken='string') topics = response['Topics'] for topic in topics: topic_arn = topic['TopicArn'] response = client.get_topic_attributes(TopicArn=topic_arn) attributes = response['Attributes'] policy_json = attributes['Policy'] policy = eval(policy_json) for statement in policy['Statement']: if statement['Principal'] == '*': metadata = CheckMetadata('SNS topic', f'{topic_arn} ({region})') check.add_metadata(metadata) check.compliance_status = ComplianceStatus.NonCompliant return check
def inventory_iam_users(regions, session=boto3) -> Check: check = Check('IAM', 'IAM User with old access keys (over 90 days)', ComplianceStatus.Compliant) client = session.client('iam') response = client.list_users() users = response['Users'] for user in users: user_name = user['UserName'] response = client.list_access_keys(UserName=user_name) for key in response['AccessKeyMetadata']: created = key['CreateDate'] access_key_id = key['AccessKeyId'] age = datetime.datetime.now(datetime.timezone.utc) - created if age.days > 90: check_metadata_1 = CheckMetadata( 'User name', f'{user_name} (Key Id: {access_key_id}, Key days of age: {age.days})' ) check.add_metadata(check_metadata_1) check.compliance_status = ComplianceStatus.NonCompliant return check
def inventory_cloudtrail_active(regions, session=boto3) -> Check: check = Check( 'CloudTrail', 'At least one active CloudTrail trail should be present in account', ComplianceStatus.Compliant) for region in regions: client = session.client('cloudtrail', region) response = client.list_trails() trails = response['Trails'] trail_on = False for trail in trails: trail_arn = trail['TrailARN'] response = client.get_trail_status(Name=trail_arn) is_logging = response['IsLogging'] if is_logging: trail_on = True if not trail_on: metadata = CheckMetadata('No active trail', f'{region}') check.add_metadata(metadata) check.compliance_status = ComplianceStatus.NonCompliant return check
def inventory_wide_open_sqs_queue(regions, session=boto3) -> Check: check = Check('SQS', 'SQS queue wide open for the world', ComplianceStatus.Compliant) for region in regions: client = session.client('sqs', region) response = client.list_queues() if 'QueueUrls' not in response: return check for queue_url in response['QueueUrls']: response_policy = client.get_queue_attributes( QueueUrl=queue_url, AttributeNames=['Policy']) policy_json = response_policy['Attributes']['Policy'] policy = eval(policy_json) for statement in policy['Statement']: if statement['Principal'] == '*': metadata = CheckMetadata('SQS queue', f'{queue_url} ({region})') check.add_metadata(metadata) check.compliance_status = ComplianceStatus.NonCompliant return check