diff --git a/roles/aws/aws_admin_tools/defaults/main.yml b/roles/aws/aws_admin_tools/defaults/main.yml index ab8a82f0a..b6e1561c6 100644 --- a/roles/aws/aws_admin_tools/defaults/main.yml +++ b/roles/aws/aws_admin_tools/defaults/main.yml @@ -14,8 +14,13 @@ aws_admin_tools: policies: [] - name: "change_asg_scaling" type: POST - policies: - - arn:aws:iam::aws:policy/AmazonEC2FullAccess + policies: [] + inline_policies: + name: "change_asg_scaling" + resource: "*" + action: + - "autoscaling:DescribePolicies" + - "autoscaling:PutScalingPolicy" - name: "get_list_of_ec2" type: GET policies: [] @@ -41,3 +46,14 @@ aws_admin_tools: resource: "*" action: - "wafv2:UpdateIPSet" + - name: "get_acl_list" + type: GET + policies: [] + inline_policies: + name: "get_acl_list" + resource: "*" + action: + - "wafv2:ListResourcesForWebACL" + - "wafv2:ListWebACLs" + - "wafv2:GetWebACL" + - "cloudfront:ListDistributionsByWebACLId" diff --git a/roles/aws/aws_admin_tools/templates/api_get_acl_list.py.j2 b/roles/aws/aws_admin_tools/templates/api_get_acl_list.py.j2 new file mode 100644 index 000000000..6271f2acf --- /dev/null +++ b/roles/aws/aws_admin_tools/templates/api_get_acl_list.py.j2 @@ -0,0 +1,63 @@ +import json +import boto3 + +waf_regional = boto3.client("wafv2", region_name="{{ _aws_region }}") +waf_cf = boto3.client("wafv2", region_name="us-east-1") +cf_client = boto3.client('cloudfront', region_name="us-east-1") + +def get_rules(waf_client, acl_name, acl_id, scope): + rule_details = waf_client.get_web_acl(Name=acl_name, Scope=scope, Id=acl_id) + return [ + { + 'Name': rule['Name'], + 'Priority': rule['Priority'] + } + for rule in rule_details['WebACL']['Rules'] + ] + +def get_cf_associations(cf_client, web_acl_arn): + dist_list = cf_client.list_distributions_by_web_acl_id(WebACLId=web_acl_arn) + return [item['DomainName'] for item in dist_list.get('DistributionList', {}).get('Items', [])] + +def get_regional_associations(waf_client, web_acl_arn): + associations = [] + for res_type in ['APPLICATION_LOAD_BALANCER', 'API_GATEWAY']: + res_list = waf_client.list_resources_for_web_acl(WebACLArn=web_acl_arn, ResourceType=res_type) + if res_list.get('ResourceArns'): + associations.append({res_type: res_list['ResourceArns']}) + return associations + +def get_web_acls(waf_client, scope, include_cf_associations=False, cf_client=None): + response = waf_client.list_web_acls(Scope=scope) + web_acls = [] + + for acl in response['WebACLs']: + rules = get_rules(waf_client, acl['Name'], acl['Id'], scope) + associations = ( + get_cf_associations(cf_client, acl['ARN']) if include_cf_associations + else get_regional_associations(waf_client, acl['ARN']) + ) + web_acls.append({ + 'Name': acl['Name'], + 'Id': acl['Id'], + 'Rules': rules, + 'Association': associations + }) + return web_acls + +def lambda_handler(event, context): + # CloudFront ACLs (Global Scope) + cf_acls = get_web_acls(waf_cf, scope='CLOUDFRONT', include_cf_associations=True, cf_client=cf_client) + + # Regional ACLs (EU-West-1) + regional_acls = get_web_acls(waf_regional, scope='REGIONAL') + + return { + 'statusCode': 200, + 'ACLs': { + 'CloudFront': cf_acls, + 'Regional': { + "{{ _aws_region }}": regional_acls + } + } + } diff --git a/roles/aws/aws_admin_tools/templates/api_get_list_of_ec2.py.j2 b/roles/aws/aws_admin_tools/templates/api_get_list_of_ec2.py.j2 index c777c9e29..a3af97ec6 100644 --- a/roles/aws/aws_admin_tools/templates/api_get_list_of_ec2.py.j2 +++ b/roles/aws/aws_admin_tools/templates/api_get_list_of_ec2.py.j2 @@ -5,66 +5,44 @@ import boto3 ec2_cli = boto3.client("ec2", region_name="{{ _aws_region }}") def lambda_handler(event, context): - - print("Gathering instance details.") - ec2_instances=ec2_cli.describe_instances() - - instance_exist = False - Ec2_info_list=[] - - for reservation in ec2_instances["Reservations"]: - for instance in reservation["Instances"]: - pub_ip = "" - priv_ip = "" - inst_name = "" - eip_list=[] - priv_eip=[] - pub_eip=[] - - if "PublicIpAddress" in instance: - pub_ip = instance['PublicIpAddress'] - else: - pub_ip = "-" - if "PrivateIpAddress" in instance: - priv_ip = instance['PrivateIpAddress'] - else: - priv_ip = "-" - - if "Tags" in instance: - for name in instance['Tags']: - if name['Key'] == 'Name': - inst_name = name['Value'] - - eip_list = ec2_cli.describe_addresses( - Filters=[ - { - 'Name': 'tag:Name', - 'Values': [inst_name] - } - ] - ) - for eip in eip_list['Addresses']: - if "PublicIp" in eip: - pub_eip.append(eip['PublicIp']) - if "PrivateIpAddress" in eip: - priv_eip.append(eip['PrivateIpAddress']) - else: - inst_name = "-" - - new_dict={ - 'EC2 name': inst_name, - 'State': instance['State'], - 'Public IP': pub_ip, - 'Private IP': priv_ip, - 'Instance type': instance['InstanceType'], - 'EIP': { - 'public': pub_eip, - 'private': priv_eip - } - } - Ec2_info_list.append(new_dict) - - return { - 'statusCode': 200, - 'EC2 info': Ec2_info_list - } + print("Gathering instance details.") + + # Describe instances and addresses once + instances_response = ec2_cli.describe_instances() + addresses_response = ec2_cli.describe_addresses() + + # Preprocess EIPs for quick lookup by tag:Name + eip_map = {} + for eip in addresses_response.get('Addresses', []): + name_tag = next((tag['Value'] for tag in eip.get('Tags', []) if tag['Key'] == 'Name'), None) + if name_tag: + eip_map.setdefault(name_tag, {'Public': [], 'Private': []}) + if 'PublicIp' in eip: + eip_map[name_tag]['Public'].append(eip['PublicIp']) + if 'PrivateIpAddress' in eip: + eip_map[name_tag]['Private'].append(eip['PrivateIpAddress']) + + ec2_info_list = [] + + for reservation in instances_response.get("Reservations", []): + for instance in reservation.get("Instances", []): + inst_name = "-" + if "Tags" in instance: + for tag in instance["Tags"]: + if tag["Key"] == "Name": + inst_name = tag["Value"] + break + + ec2_info_list.append({ + "EC2Name": inst_name, + "State": instance.get("State", {}), + "PublicIP": instance.get("PublicIpAddress", "-"), + "PrivateIP": instance.get("PrivateIpAddress", "-"), + "InstanceType": instance.get("InstanceType", "-"), + "EIP": eip_map.get(inst_name, {"Public": [], "Private": []}) + }) + + return { + "statusCode": 200, + "EC2Info": ec2_info_list + }