Beanstalk-Reporter: Aggregating Information for AWS Resources
I recently wrote a tool that aggregates information for resources linked to AWS Elastic Beanstalk deployments for easier security monitoring and auditing. You may find the source {here}.
What is Elastic Beanstalk?
Elastic Beanstalk is a service that allows rapid application deployment on AWS infrastructure. Details such as instance provisioning, VPC and subnet set-up, routing, security groups, auto-scaling and load balancing, among others are all managed by AWS under the hood. The user is primarily responsible for providing the application code and tweaking simple stack parameters. The infrastructure provisioned initially can of course be modified at a later point through the Beanstalk service (simple tuning) or through the relevant service (in-depth control). It is crucial that security configuration is monitored and validated on the underlying infrastructure to ensure security and compliance.
The Problem
The configuration tab in the AWS console for a Beanstalk environment shows plain-text ARNs/IDs for linked resources such as load balancers, VPCs, auto-scaling groups, instances and so on, however, does not directly link to them. Viewing the configuration for these items via console involves navigating to those specific services and then filtering by the ARN/ID.
The AWS CLI approach via: aws elasticbeanstalk describe-environment-resources --environment-name <name>
, is more of the same - listing ARNs and IDs of linked resources, albeit in a standardized JSON format. Individual resources may be described via their own family of commands, for example: aws ec2 describe-instance --instance-ids <id>
, which provides verbose output - only a subset of which may be relevant to security engineers.
The Solution
This tool:
- Takes in a CLI profile name and a Beanstalk environment name.
- Enumerates linked resources such as load balancers, autoscaling groups and instances, their network configuration and security-group rules.
- Includes security-oriented information in a standardized JSON structure.
- Pretty-prints to standard output.
Most of the items correspond to security controls, however, you may choose to extend the script to include additional information from the AWS API response.
Ideas for Extensions
- Apart from ad-hoc use, this tool may be used in a loop, iterating over all Beanstalk environments in your account to maintain a repository and continuously monitor infrastructure configuration. Data can be pushed to logging tools that ingest JSON natively such as Elasticsearch and alerts may be set up to track deviation from baseline.
- A simple front-end to visualize this information on a web page or PDF report as an end result for security assessments.
Usage
python3 beanstalk_reporter.py --profile <aws_cli_profile_name> --env <beanstalk_env_name>
Demo
Sample Output
{
"LoadBalancers": {
"Details": {
"DNSName": "awseb-AWSEB-1UVPUXSO6KOIE-1718280053.ap-south-1.elb.amazonaws.com",
"LoadBalancerName": "awseb-AWSEB-1UVPUXSO6KOIE",
"AvailabilityZones": [
{
"ZoneName": "ap-south-1b",
"SubnetId": "subnet-28a3cf64"
},
{
"ZoneName": "ap-south-1a",
"SubnetId": "subnet-7ba79813"
}
],
"SecurityGroups": [
"sg-0306ad9cbb3900202"
],
"VpcId": "vpc-c0adbba8"
},
"Attributes": {
"access_logs.s3.enabled": "false",
"access_logs.s3.bucket": "",
"access_logs.s3.prefix": "",
"idle_timeout.timeout_seconds": "60",
"deletion_protection.enabled": "false",
"routing.http2.enabled": "true",
"routing.http.drop_invalid_header_fields.enabled": "false",
"routing.http.xff_client_port.enabled": "false",
"routing.http.desync_mitigation_mode": "defensive",
"waf.fail_open.enabled": "false",
"routing.http.x_amzn_tls_version_and_cipher_suite.enabled": "false"
},
"Listeners": [
{
"Protocol": "HTTP",
"Port": 80,
"TargetGroupStickiness": false
}
],
"SecurityGroups": [
{
"GroupId": "sg-0306ad9cbb3900202",
"Description": "Load Balancer Security Group",
"InboundRules": [
{
"IpProtocol": "tcp",
"ToPort": 80,
"From": "0.0.0.0/0"
}
],
"OutboundRules": [
{
"IpProtocol": "tcp",
"ToPort": 80,
"To": "0.0.0.0/0"
}
]
}
]
},
"AutoScalingGroups": {
"AutoScalingGroupName": "awseb-e-nqr3wfc2ss-stack-AWSEBAutoScalingGroup-1EWYSNAEDH40D",
"AvailabilityZones": [
"ap-south-1b",
"ap-south-1a"
],
"DesiredCapacity": 2,
"MaxSize": 2,
"MinSize": 2,
"NewInstancesProtectedFromScaleIn": false,
"Instances": [
{
"InstanceId": "i-00431322e2b12a257",
"AvailabilityZone": "ap-south-1b",
"HealthStatus": "Healthy"
},
{
"InstanceId": "i-0dc3bbfd97c783eb6",
"AvailabilityZone": "ap-south-1a",
"HealthStatus": "Healthy"
}
]
},
"Instances": [
{
"InstanceId": "i-00431322e2b12a257",
"InstanceType": "t2.micro",
"ImageId": "ami-0e932ae268855ee62",
"PlatformDetails": "Linux/UNIX",
"AvailabilityZone": "ap-south-1b",
"InstanceRole": "arn:aws:iam::153316549657:instance-profile/aws-elasticbeanstalk-ec2-role",
"Monitoring": "disabled",
"NetworkInterfaces": [
{
"PrivateIPAddress": "172.31.2.132",
"PrivateDnsName": "ip-172-31-2-132.ap-south-1.compute.internal",
"PublicIpAddress": "15.207.110.197",
"PublicDnsName": "ec2-15-207-110-197.ap-south-1.compute.amazonaws.com",
"MacAddress": "0a:09:71:b7:3b:2a",
"IPv6Address": []
}
],
"SecurityGroups": [
{
"GroupId": "sg-080a3f187c29db02a",
"Description": "VPC Security Group",
"InboundRules": [
{
"IpProtocol": "tcp",
"ToPort": 80,
"From": "sg-0306ad9cbb3900202"
}
],
"OutboundRules": [
{
"IpProtocol": "ALL TRAFFIC",
"ToPort": "ALL PORTS",
"To": "0.0.0.0/0"
}
]
}
]
},
{
"InstanceId": "i-0dc3bbfd97c783eb6",
"InstanceType": "t2.micro",
"ImageId": "ami-0e932ae268855ee62",
"PlatformDetails": "Linux/UNIX",
"AvailabilityZone": "ap-south-1a",
"InstanceRole": "arn:aws:iam::153316549657:instance-profile/aws-elasticbeanstalk-ec2-role",
"Monitoring": "disabled",
"NetworkInterfaces": [
{
"PrivateIPAddress": "172.31.39.85",
"PrivateDnsName": "ip-172-31-39-85.ap-south-1.compute.internal",
"PublicIpAddress": "65.0.85.185",
"PublicDnsName": "ec2-65-0-85-185.ap-south-1.compute.amazonaws.com",
"MacAddress": "02:e3:eb:e7:16:c8",
"IPv6Address": []
}
],
"SecurityGroups": [
{
"GroupId": "sg-080a3f187c29db02a",
"Description": "VPC Security Group",
"InboundRules": [
{
"IpProtocol": "tcp",
"ToPort": 80,
"From": "sg-0306ad9cbb3900202"
}
],
"OutboundRules": [
{
"IpProtocol": "ALL TRAFFIC",
"ToPort": "ALL PORTS",
"To": "0.0.0.0/0"
}
]
}
]
}
]
}