Skip to main content

EC2 Security Group from Launch Wizard

Overview

This check identifies EC2 security groups whose names contain "launch-wizard," which indicates they were auto-generated by the EC2 Launch Wizard rather than created through controlled, baseline security practices.

When you launch an EC2 instance through the Console and click "Edit" on the security group settings, AWS automatically creates a security group named "launch-wizard-X" (where X is a number). These wizard-generated groups are intended for quick testing but often violate security best practices.

Risk

Wizard-generated security groups pose significant security risks:

  • Overly permissive rules: Launch-wizard groups typically include broad access rules such as 0.0.0.0/0 (anywhere) to administrative ports like SSH (22) or RDP (3389)
  • Port scanning exposure: Public access to admin ports makes instances easy targets for port scanning and brute-force attacks
  • Lateral movement: Once attackers gain entry, they can move laterally through your network
  • Data exfiltration: Broad egress rules can facilitate command-and-control communications
  • No change control: These groups bypass organizational security baselines and change control procedures

This check is rated Medium severity because it indicates a lack of security governance rather than a direct public exposure.

Remediation Steps

Prerequisites

  • AWS account access with permissions to modify EC2 security groups
  • Knowledge of which instances are using the launch-wizard security groups
  • A replacement security group that follows your organization's security baseline
Required IAM permissions

You will need the following permissions:

  • ec2:DescribeSecurityGroups - List and view security group details
  • ec2:DescribeSecurityGroupRules - View security group rules
  • ec2:DescribeInstances - See which instances use the security groups
  • ec2:ModifyInstanceAttribute - Change an instance's security groups
  • ec2:DeleteSecurityGroup - Remove the launch-wizard security group
  • ec2:CreateSecurityGroup - Create a replacement security group (if needed)
  • ec2:AuthorizeSecurityGroupIngress - Add inbound rules to new groups
  • ec2:AuthorizeSecurityGroupEgress - Add outbound rules to new groups

AWS Console Method

Step 1: Find launch-wizard security groups

  1. Sign in to the AWS Management Console
  2. Navigate to EC2 > Security Groups (under "Network & Security" in the left sidebar)
  3. Make sure you are in the correct region (e.g., us-east-1)
  4. In the search box, type launch-wizard to filter the list
  5. Note the security group IDs and which resources are using them

Step 2: Identify attached resources

Before deleting a security group, you need to know what's using it:

  1. Click on a launch-wizard security group
  2. Scroll down to the Associated resources section
  3. Note any instances, network interfaces, or other resources listed
  4. You must remove the security group from these resources before you can delete it

Step 3: Create a replacement security group (if needed)

If you don't have an existing security group that follows your security baseline:

  1. Click Create security group
  2. Enter a descriptive Name (e.g., web-server-sg or bastion-ssh-restricted)
  3. Enter a Description explaining its purpose
  4. Select the appropriate VPC
  5. Add Inbound rules following least-privilege principles:
    • Restrict source IPs to known ranges (avoid 0.0.0.0/0)
    • Only open required ports
    • For SSH, consider using AWS Systems Manager Session Manager instead
  6. Add Outbound rules as needed (default allows all outbound)
  7. Click Create security group

Step 4: Replace the security group on instances

  1. Navigate to EC2 > Instances
  2. Select an instance using the launch-wizard security group
  3. Click Actions > Security > Change security groups
  4. Remove the launch-wizard security group
  5. Add your baseline security group
  6. Click Save
  7. Repeat for all affected instances

Step 5: Delete the launch-wizard security group

Once no resources are attached:

  1. Navigate to EC2 > Security Groups
  2. Select the launch-wizard security group
  3. Click Actions > Delete security groups
  4. Confirm the deletion
AWS CLI (optional)

Find all launch-wizard security groups:

aws ec2 describe-security-groups \
--filters "Name=group-name,Values=*launch-wizard*" \
--query 'SecurityGroups[*].[GroupId,GroupName,VpcId]' \
--output table \
--region us-east-1

See what's using a security group:

aws ec2 describe-network-interfaces \
--filters "Name=group-id,Values=sg-0123456789abcdef0" \
--query 'NetworkInterfaces[*].[NetworkInterfaceId,Attachment.InstanceId,Description]' \
--output table \
--region us-east-1

Replace sg-0123456789abcdef0 with your security group ID.

Create a replacement security group:

aws ec2 create-security-group \
--group-name "web-server-sg" \
--description "Security group for web servers with restricted access" \
--vpc-id vpc-0123456789abcdef0 \
--region us-east-1

Add restricted SSH access (example: from a specific IP):

aws ec2 authorize-security-group-ingress \
--group-id sg-NEW_GROUP_ID \
--protocol tcp \
--port 22 \
--cidr 203.0.113.0/24 \
--region us-east-1

Replace 203.0.113.0/24 with your organization's IP range.

Update an instance to use the new security group:

aws ec2 modify-instance-attribute \
--instance-id i-0123456789abcdef0 \
--groups sg-NEW_GROUP_ID \
--region us-east-1

Delete the launch-wizard security group:

aws ec2 delete-security-group \
--group-id sg-0123456789abcdef0 \
--region us-east-1

This command will fail with DependencyViolation if the security group is still attached to any resources.

CloudFormation (optional)

Use CloudFormation to create properly configured security groups that follow your security baseline. This ensures all security groups are managed through infrastructure-as-code.

AWSTemplateFormatVersion: '2010-09-09'
Description: Baseline security groups to replace launch-wizard groups

Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: VPC where security groups will be created

AllowedSSHCidr:
Type: String
Description: CIDR block allowed for SSH access (e.g., your office IP range)
Default: 10.0.0.0/8
AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}/\d{1,2}$'

Resources:
BastionSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: bastion-host-sg
GroupDescription: Security group for bastion hosts with restricted SSH access
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: !Ref AllowedSSHCidr
Description: SSH access from allowed CIDR range
Tags:
- Key: Name
Value: bastion-host-sg
- Key: ManagedBy
Value: CloudFormation

WebServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: web-server-sg
GroupDescription: Security group for web servers
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Description: HTTPS from anywhere
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
Description: HTTP from anywhere (redirect to HTTPS)
Tags:
- Key: Name
Value: web-server-sg
- Key: ManagedBy
Value: CloudFormation

InternalAppSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: internal-app-sg
GroupDescription: Security group for internal applications
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
SourceSecurityGroupId: !Ref BastionSecurityGroup
Description: SSH from bastion hosts only
Tags:
- Key: Name
Value: internal-app-sg
- Key: ManagedBy
Value: CloudFormation

Outputs:
BastionSecurityGroupId:
Description: Security group ID for bastion hosts
Value: !Ref BastionSecurityGroup
Export:
Name: !Sub '${AWS::StackName}-BastionSG'

WebServerSecurityGroupId:
Description: Security group ID for web servers
Value: !Ref WebServerSecurityGroup
Export:
Name: !Sub '${AWS::StackName}-WebServerSG'

InternalAppSecurityGroupId:
Description: Security group ID for internal applications
Value: !Ref InternalAppSecurityGroup
Export:
Name: !Sub '${AWS::StackName}-InternalAppSG'

Deploy the stack:

aws cloudformation create-stack \
--stack-name baseline-security-groups \
--template-body file://security-groups.yaml \
--parameters ParameterKey=VpcId,ParameterValue=vpc-0123456789abcdef0 \
ParameterKey=AllowedSSHCidr,ParameterValue=10.0.0.0/8 \
--region us-east-1
Terraform (optional)

Use Terraform to create and manage security groups that follow your security baseline.

provider "aws" {
region = "us-east-1"
}

variable "vpc_id" {
description = "VPC ID where security groups will be created"
type = string
}

variable "allowed_ssh_cidr" {
description = "CIDR block allowed for SSH access"
type = string
default = "10.0.0.0/8"
}

# Bastion host security group - restricted SSH access
resource "aws_security_group" "bastion" {
name = "bastion-host-sg"
description = "Security group for bastion hosts with restricted SSH access"
vpc_id = var.vpc_id

ingress {
description = "SSH from allowed CIDR range"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.allowed_ssh_cidr]
}

egress {
description = "Allow all outbound traffic"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

tags = {
Name = "bastion-host-sg"
ManagedBy = "Terraform"
}
}

# Web server security group
resource "aws_security_group" "web_server" {
name = "web-server-sg"
description = "Security group for web servers"
vpc_id = var.vpc_id

ingress {
description = "HTTPS from anywhere"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

ingress {
description = "HTTP from anywhere (redirect to HTTPS)"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

egress {
description = "Allow all outbound traffic"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

tags = {
Name = "web-server-sg"
ManagedBy = "Terraform"
}
}

# Internal application security group
resource "aws_security_group" "internal_app" {
name = "internal-app-sg"
description = "Security group for internal applications"
vpc_id = var.vpc_id

ingress {
description = "SSH from bastion hosts only"
from_port = 22
to_port = 22
protocol = "tcp"
security_groups = [aws_security_group.bastion.id]
}

egress {
description = "Allow all outbound traffic"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

tags = {
Name = "internal-app-sg"
ManagedBy = "Terraform"
}
}

output "bastion_security_group_id" {
description = "Security group ID for bastion hosts"
value = aws_security_group.bastion.id
}

output "web_server_security_group_id" {
description = "Security group ID for web servers"
value = aws_security_group.web_server.id
}

output "internal_app_security_group_id" {
description = "Security group ID for internal applications"
value = aws_security_group.internal_app.id
}

Apply the configuration:

terraform init
terraform plan -var="vpc_id=vpc-0123456789abcdef0"
terraform apply -var="vpc_id=vpc-0123456789abcdef0"

Verification

After completing the remediation:

  1. Go to EC2 > Security Groups in the AWS Console
  2. Search for launch-wizard - no results should appear
  3. Verify your instances are using the new baseline security groups
  4. Re-run the Prowler check to confirm the issue is resolved
CLI verification commands

Verify no launch-wizard security groups remain:

aws ec2 describe-security-groups \
--filters "Name=group-name,Values=*launch-wizard*" \
--query 'SecurityGroups[*].GroupId' \
--output text \
--region us-east-1

This command should return no results.

Verify an instance is using the correct security group:

aws ec2 describe-instances \
--instance-ids i-0123456789abcdef0 \
--query 'Reservations[0].Instances[0].SecurityGroups[*].[GroupId,GroupName]' \
--output table \
--region us-east-1

The output should show your baseline security groups, not any launch-wizard groups.

Additional Resources

Notes

  • Avoid 0.0.0.0/0 for admin ports: Never allow SSH (22), RDP (3389), or database ports from anywhere. Use specific IP ranges or security group references.
  • Use Session Manager instead of SSH: AWS Systems Manager Session Manager provides secure shell access without requiring inbound ports or SSH keys.
  • Implement change control: All security group changes should go through your organization's change management process and be tracked in version control.
  • Tag your security groups: Use consistent tagging to identify purpose, owner, and environment for each security group.
  • Regular audits: Periodically review all security groups to ensure they follow least-privilege principles and remove unused groups.
  • Use VPC Flow Logs: Enable VPC Flow Logs to monitor traffic and detect potential security issues.
  • Consider AWS Firewall Manager: For organizations with multiple accounts, use AWS Firewall Manager to centrally manage security groups across accounts.