New
Join our webinar! Building a customizable and extensible cloud asset inventory at scale
AWS
Tutorials

Exploring AWS EC2 Security Groups - Best Practices and Query Examples

Jonathan Sarig

Jonathan Sarig

AWS Security groups are a critical part of managing access to your AWS resources. However, working with the deeply nested JSON data in AWS security groups can be challenging, especially for non-technical users. This blog post will guide you through the aws_ec2_security_groups table, helping you understand its structure and providing example queries to make the most of your data.
To begin, you first need to sync your AWS security groups using CloudQuery's AWS Source Plugin to any destination available in our destination plugins. In the query examples below, we’ll use the PostgreSQL Destination Plugin.
To get started, download the CloudQuery CLI, and set up your CloudQuery configuration file by following the AWS Source Plugin documentation. When writing your CloudQuery AWS configuration, make sure that you add aws_ec2_security_groups to the list of tables being synced.
You can start exploring the data from your accounts AWS EC2 security groups using these examples of views and checks created by the CloudQuery AWS Compliance Package. One of these is the security groups ingress rules:
select
  account_id,
  region,
  group_name,
  arn,
  group_id AS id,
  vpc_id,
  (i->>'FromPort')::integer AS from_port,
  (i->>'ToPort')::integer AS to_port,
  i->>'IpProtocol' AS ip_protocol,
  ip_ranges->>'CidrIp' AS ip,
  ip6_ranges->>'CidrIpv6' AS ip6
from aws_ec2_security_groups, JSONB_ARRAY_ELEMENTS(aws_ec2_security_groups.ip_permissions) AS i
LEFT JOIN JSONB_ARRAY_ELEMENTS(i->'IpRanges') AS ip_ranges ON true
LEFT JOIN JSONB_ARRAY_ELEMENTS(i->'Ipv6Ranges') AS ip6_ranges ON true
This SQL query retrieves detailed information about AWS EC2 security groups, including their account ID, region, group name, ARN (Amazon Resource Name), VPC ID, and various security rule details. It specifically extracts and converts JSON data within the security group’s ip_permissions field to get the port ranges (FromPort and ToPort), the IP protocol (IpProtocol), and both IPv4 (CidrIp) and IPv6 (CidrIpv6) address ranges. The query uses JSON functions to handle the complex nested data structures and joins them to get a comprehensive view of each security group’s rules.
Similarly, we can extract the data for outbound ports and IPs affected by the group:
SELECT
  account_id,
  region,
  group_name,
  arn,
  group_id AS id,
  vpc_id,
  (i->>'FromPort')::integer AS from_port,
      (i->>'ToPort')::integer AS to_port,
      i->>'IpProtocol' AS ip_protocol,
  ip_ranges->>'CidrIp' AS ip,
  ip6_ranges->>'CidrIpv6' AS ip6
FROM aws_ec2_security_groups, JSONB_ARRAY_ELEMENTS(aws_ec2_security_groups.ip_permissions_egress) AS i
  LEFT JOIN JSONB_ARRAY_ELEMENTS(i->'IpRanges') AS ip_ranges ON true
  LEFT JOIN JSONB_ARRAY_ELEMENTS(i->'Ipv6Ranges') AS ip6_ranges ON true
This SQL query retrieves specific details from AWS EC2 security groups, focusing on outbound (egress) permissions. It selects the account ID, region, group name, ARN (Amazon Resource Name), group ID (renamed to id), and VPC ID. Additionally, it extracts and converts JSON data within the ip_permissions_egress field to retrieve and display the port ranges (FromPort and ToPort), IP protocol (IpProtocol), and both IPv4 (CidrIp) and IPv6 (CidrIpv6) address ranges. The query uses JSON functions to handle these nested data structures and join them to produce a comprehensive set of egress rules for each security group.
The complex JSON columns being flattened are:
While these objects are complex, these queries highlight the important properties you need to look at to understand what the security group affects.
To further understand these columns, you need to look at the check VPC default security groups should not allow inbound or outbound traffic from AWS CIS 3.0.
SELECT
  account_id,
  arn,
  CASE WHEN
      group_name='default'
      AND (jsonb_array_length(ip_permissions) > 0
      OR jsonb_array_length(ip_permissions_egress) > 0)
      THEN 'fail'
      ELSE 'pass'
  END AS status
FROM
  aws_ec2_security_groups
This SQL query checks AWS EC2 default security groups for any inbound or outbound rules. It selects the account ID and ARN, and marks the status as ‘fail’ if the default group has rules, otherwise ‘pass’. This helps ensure default groups comply with policy.
-- uses view aws_compliance__security_group_ingress_rules
WITH IndividualRuleStatus AS (
  SELECT
    account_id,
    id AS resource_id,
    CASE WHEN
      (ip = '0.0.0.0/0' OR ip = '::/0')
      AND ((from_port IS NULL AND to_port IS NULL) -- all ports
      OR 20  BETWEEN from_port AND to_port
      OR 21  BETWEEN from_port AND to_port
      OR 22  BETWEEN from_port AND to_port
      OR 23  BETWEEN from_port AND to_port
      OR 25  BETWEEN from_port AND to_port
      OR 110 BETWEEN from_port AND to_port
      OR 135 BETWEEN from_port AND to_port
      OR 143 BETWEEN from_port AND to_port
      OR 445 BETWEEN from_port AND to_port
      OR 143 BETWEEN from_port AND to_port
      OR 143 BETWEEN from_port AND to_port
      OR 300 BETWEEN from_port AND to_port
      OR 330 BETWEEN from_port AND to_port
      OR 338 BETWEEN from_port AND to_port
      OR 433 BETWEEN from_port AND to_port
      OR 500 BETWEEN from_port AND to_port
      OR 543 BETWEEN from_port AND to_port
      OR 550 BETWEEN from_port AND to_port
      OR 560 BETWEEN from_port AND to_port
      OR 808 BETWEEN from_port AND to_port
      OR 808 BETWEEN from_port AND to_port
      OR 888 BETWEEN from_port AND to_port
      OR 920 BETWEEN from_port AND to_port
      OR 930 BETWEEN from_port AND to_port)
      THEN 'fail'
      ELSE 'pass'
    END AS status
  FROM aws_compliance__security_group_ingress_rules
)

SELECT
  account_id,
  resource_id,
  CASE
    WHEN SUM(CASE WHEN status = 'fail' THEN 1 ELSE 0 END) > 0 THEN 'fail'
    ELSE 'pass'
  END as status
FROM IndividualRuleStatus
GROUP BY account_id, resource_id
This SQL query assesses AWS EC2 security group ingress rules for potential vulnerabilities. It first creates a temporary view (IndividualRuleStatus) that flags rules as ‘fail’ if they allow traffic from any IP (0.0.0.0/0 or ::/0) on critical ports. The final query then aggregates these results by account ID and resource ID, marking the security group as ‘fail’ if any rule is flagged, otherwise as ‘pass’. This helps in identifying security groups with potentially risky open access.
With these examples, you are ready to explore the security group data available from our AWS Source Plugin. By modifying these queries, you can gain insights into various aspects of your AWS security groups.
Ready to dive deeper into your AWS security group data? Try CloudQuery today and gain comprehensive insights into your AWS security configurations. Contact us or join our Community to connect with other users and our engineering team, and explore the full potential of CloudQuery.
Jonathan Sarig

Written by Jonathan Sarig

Jonathan is a software engineer at CloudQuery with a particular interest in machine learning. He primarily works in golang but also has experience in (and a passion for) Rust.

Turn cloud chaos into clarity

Find out how CloudQuery can help you get clarity from a chaotic cloud environment with a personalized conversation and demo.

Join our mailing list

Subscribe to our newsletter to make sure you don't miss any updates.

Legal

© 2024 CloudQuery, Inc. All rights reserved.

We use tracking cookies to understand how you use the product and help us improve it. Please accept cookies to help us improve. You can always opt out later via the link in the footer.