Back to blog
AWSBest PracticesCloud SecurityDatabasesNetworking

Fixing Redshift Clusters Still Running on EC2-Classic

Learn why a Redshift cluster on deprecated EC2-Classic networking is a risk and how to migrate it into a VPC with snapshots, CLI steps, and policy-as-code.

TL;DR

This check flags Redshift clusters still running on EC2-Classic networking, a retired AWS network model with no VPC isolation, security groups, or modern access controls. Migrate the cluster into a VPC by snapshotting it and restoring into a VPC subnet group.

EC2-Classic was AWS's original flat network model, where every instance and managed resource lived in a single shared network space alongside other tenants. AWS has been winding it down for years, and full retirement landed in 2022. If a Redshift cluster still reports EC2-Classic networking, it is either a very old cluster or one that was restored from an ancient snapshot. Either way, it is running outside a VPC, which means it lacks the isolation and control that everything else in your account depends on.

The redshift_classic check looks at each Redshift cluster and verifies whether it has a VpcId associated with it. A cluster with no VPC is an EC2-Classic cluster, and that is what gets flagged.


What this check detects

The check inspects the network placement of every Redshift cluster in the account and region. AWS describes a cluster's networking through its ClusterSubnetGroupName and VpcId fields. When a cluster runs in EC2-Classic, it has no cluster subnet group and no associated VPC.

You can see this yourself with the AWS CLI:

aws redshift describe-clusters \
  --query 'Clusters[*].{Name:ClusterIdentifier,Vpc:VpcId,SubnetGroup:ClusterSubnetGroupName}' \
  --output table

Any cluster where the Vpc column is empty is running on EC2-Classic and will be flagged.

Note: EC2-Classic clusters cannot be created anymore. If you see one, it predates 2013 era account defaults or was restored from a snapshot taken on a Classic cluster. AWS forces VPC placement for all new clusters.


Why it matters

EC2-Classic was deprecated for good reasons, and a Redshift cluster running there carries every one of those drawbacks in a database that often holds your most sensitive analytical data.

  • No VPC isolation. In a VPC you control routing, subnets, and which CIDR ranges can reach the cluster. On EC2-Classic, your cluster lives in a shared address space with weaker boundaries.
  • No security groups in the modern sense. EC2-Classic uses cluster security groups, a separate and far more limited construct than VPC security groups. You lose granular ingress and egress rules.
  • No private connectivity. Features like VPC endpoints, enhanced VPC routing, PrivateLink, and routing Redshift traffic over a private network are unavailable. Data movement to and from S3 may traverse paths you cannot lock down.
  • No modern features. Many newer Redshift capabilities assume VPC placement. Running on Classic blocks you from a long list of improvements and increasingly leaves you on unsupported configurations.
  • Compliance gaps. Frameworks like PCI DSS, HIPAA, and SOC 2 expect documented network segmentation. An EC2-Classic database is hard to justify to an auditor.

Danger: AWS has already retired EC2-Classic. A cluster still on it is on borrowed time. If AWS forces a migration on its own schedule, or the underlying support disappears, you could face an unplanned outage with no warning window. Migrate on your terms, not theirs.


How to fix it

You cannot flip a Redshift cluster from EC2-Classic to VPC in place. The supported path is to take a snapshot, then restore that snapshot into a VPC. Plan for a maintenance window because the new cluster gets a new endpoint, and clients need to be repointed.

Step 1: Create the VPC networking prerequisites

You need a VPC, at least one subnet (ideally across multiple Availability Zones for resilience), and a Redshift cluster subnet group that ties those subnets together.

# Create a cluster subnet group spanning two private subnets
aws redshift create-cluster-subnet-group \
  --cluster-subnet-group-name analytics-subnet-group \
  --description "Subnet group for analytics Redshift cluster" \
  --subnet-ids subnet-0abc123def456 subnet-0def456abc789

Step 2: Create a VPC security group for the cluster

aws ec2 create-security-group \
  --group-name redshift-analytics-sg \
  --description "Ingress control for analytics Redshift cluster" \
  --vpc-id vpc-0aa11bb22cc33

# Allow Redshift port only from your application subnet CIDR
aws ec2 authorize-security-group-ingress \
  --group-id sg-0redshift1234 \
  --protocol tcp \
  --port 5439 \
  --cidr 10.0.10.0/24

Step 3: Snapshot the existing EC2-Classic cluster

Warning: Snapshotting and restoring a large cluster takes time and storage. Snapshot storage beyond your free allowance is billed, and the restored cluster runs in parallel with the old one until you decommission it, so you pay for both during the cutover.

aws redshift create-cluster-snapshot \
  --snapshot-identifier classic-cluster-final-snapshot \
  --cluster-identifier legacy-analytics-cluster

Wait for the snapshot to reach the available state before restoring:

aws redshift describe-cluster-snapshots \
  --snapshot-identifier classic-cluster-final-snapshot \
  --query 'Snapshots[0].Status'

Step 4: Restore the snapshot into the VPC

aws redshift restore-from-cluster-snapshot \
  --cluster-identifier analytics-cluster-vpc \
  --snapshot-identifier classic-cluster-final-snapshot \
  --cluster-subnet-group-name analytics-subnet-group \
  --vpc-security-group-ids sg-0redshift1234 \
  --publicly-accessible false \
  --enhanced-vpc-routing

Tip: Set --enhanced-vpc-routing at restore time. It forces COPY and UNLOAD traffic between Redshift and S3 through your VPC, so you can govern that data movement with route tables, VPC endpoints, and security groups instead of letting it leave over the public AWS network.

Step 5: Cut over and verify

  1. Confirm the new cluster is available and note its new endpoint.
  2. Update connection strings in applications, BI tools, and ETL jobs to the new endpoint.
  3. Validate queries and row counts against the old cluster to confirm a clean restore.
  4. Verify VPC placement on the new cluster:
aws redshift describe-clusters \
  --cluster-identifier analytics-cluster-vpc \
  --query 'Clusters[0].{Vpc:VpcId,SubnetGroup:ClusterSubnetGroupName}'

Step 6: Decommission the old cluster

Danger: Deleting a cluster is irreversible. Only run this after you have validated the new cluster, repointed every client, and retained a final snapshot. The --final-cluster-snapshot-identifier flag gives you a recovery point.

aws redshift delete-cluster \
  --cluster-identifier legacy-analytics-cluster \
  --final-cluster-snapshot-identifier legacy-cluster-decommission-snapshot

How to prevent it from happening again

Since AWS already blocks new EC2-Classic clusters, prevention here is mostly about catching restores from old snapshots and enforcing VPC placement everywhere through code.

Define clusters in IaC with explicit VPC placement

Provision Redshift through Terraform or CloudFormation so the subnet group and security groups are always set. A Terraform example:

resource "aws_redshift_subnet_group" "analytics" {
  name       = "analytics-subnet-group"
  subnet_ids = [aws_subnet.private_a.id, aws_subnet.private_b.id]
}

resource "aws_redshift_cluster" "analytics" {
  cluster_identifier        = "analytics-cluster-vpc"
  node_type                 = "ra3.xlplus"
  cluster_subnet_group_name = aws_redshift_subnet_group.analytics.name
  vpc_security_group_ids    = [aws_security_group.redshift.id]
  publicly_accessible       = false
  enhanced_vpc_routing      = true
  encrypted                 = true
}

Gate it in CI/CD with policy-as-code

Use a tool like Checkov, tfsec, or OPA to fail any plan that creates a Redshift cluster without a subnet group. An example OPA/Rego rule:

package redshift.vpc

deny[msg] {
  resource := input.resource.aws_redshift_cluster[name]
  not resource.cluster_subnet_group_name
  msg := sprintf("Redshift cluster '%s' must specify a cluster_subnet_group_name", [name])
}

Tip: Add a continuous check that runs describe-clusters across all regions on a schedule and alerts on any cluster with an empty VpcId. Lensix runs the redshift_classic check automatically so a stray restore from a legacy snapshot surfaces immediately instead of lingering for months.


Best practices

  • Run every database in a VPC. Treat VPC placement as the floor, not a feature. Apply the same standard to RDS, ElastiCache, and any managed data service.
  • Keep clusters private. Set publicly_accessible = false and reach the cluster through private subnets, a bastion, or a VPN. There is rarely a good reason for a data warehouse to have a public endpoint.
  • Tighten security group ingress. Restrict port 5439 to specific application CIDRs or security groups, never 0.0.0.0/0.
  • Enable enhanced VPC routing so bulk data movement to and from S3 stays inside your network boundary where you can audit it.
  • Encrypt at rest and in transit. Turn on KMS encryption and require SSL connections.
  • Audit your snapshots. Old snapshots can carry forward legacy configurations. Periodically review and retire snapshots you no longer need so nobody restores an EC2-Classic cluster by accident.

An EC2-Classic Redshift cluster is a relic that AWS has already moved past. Migrating it into a VPC is a one-time effort that buys you isolation, modern security controls, and a configuration you can actually defend in an audit. Schedule the cutover, snapshot, restore into a VPC, and put a policy gate in place so it never reappears.