Skip to content

Instantly share code, notes, and snippets.

@prasanthj
Forked from stavxyz/publicSubnets.go
Last active December 17, 2019 00:01
Show Gist options
  • Save prasanthj/8eed4896ef943a93fdbba2757af71d8a to your computer and use it in GitHub Desktop.
Save prasanthj/8eed4896ef943a93fdbba2757af71d8a to your computer and use it in GitHub Desktop.
finding public subnets in go
package main
import (
"fmt"
"sort"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
"github.com/racker/janus-passport/server/log"
)
func explicitPublicAssocations(svc ec2iface.EC2API, vpcFilter *ec2.Filter) ([]*ec2.RouteTableAssociation, error) {
var assocations []*ec2.RouteTableAssociation
filters := []*ec2.Filter{
vpcFilter,
&ec2.Filter{
Name: aws.String("route.destination-cidr-block"),
Values: []*string{aws.String("0.0.0.0/0")},
},
&ec2.Filter{
Name: aws.String("route.gateway-id"),
Values: []*string{aws.String("igw-*")},
},
}
params := &ec2.DescribeRouteTablesInput{}
params = params.SetFilters(filters)
// If a subnet is not explicitly associated with any route table,
// it is implicitly associated with the main route table.
// This command does not return the subnet ID for implicit associations.
tables, err := svc.DescribeRouteTables(params)
if err != nil {
return nil, err
}
for _, table := range tables.RouteTables {
log.Info(fmt.Sprintf("Found %d public assocations", len(table.Associations)))
assocations = append(assocations, table.Associations...)
}
return assocations, nil
}
// find the subnets that are not explicitly associated with any route table
// **assuming the Main route table is internet enabled**
func implicitMainSubnets(svc ec2iface.EC2API, vpcFilter *ec2.Filter) ([]*ec2.Subnet, error) {
// 1. list available subnets in this vpc
// 2. call describe route tables with each subnet
// 3. return the subnets that return zero assocations
filters := []*ec2.Filter{
vpcFilter,
&ec2.Filter{
Name: aws.String("state"),
Values: []*string{aws.String("available")},
},
}
params := &ec2.DescribeSubnetsInput{}
params = params.SetFilters(filters)
allSubnets, err := svc.DescribeSubnets(params)
if err != nil {
return nil, err
}
var subnets []*ec2.Subnet
for _, subnet := range allSubnets.Subnets {
filters := []*ec2.Filter{
vpcFilter,
&ec2.Filter{
Name: aws.String("association.subnet-id"),
Values: []*string{aws.String(*subnet.SubnetId)},
},
}
// If a subnet is not explicitly associated with any route table,
// it is implicitly associated with the main route table.
// This command does not return the subnet ID for implicit associations.
//
// NB: If this chunk of logic gets moved out of this function,
// Calling DescribeRouteTables with an _invalid_ subnet-id
// in the filter will *also* return an empty array for RouteTables
// i.e. DescribeRouteTables will not validate your subnet id
// if that is used in the filter. No danger here in its initial form
// but if the subnet id used is not guaranteed to be legit, we
// might end up thinking a bogus subnet ID is implicitly associated
// with the Main route table, since the return value looks the same.
params := &ec2.DescribeRouteTablesInput{}
params = params.SetFilters(filters)
tables, err := svc.DescribeRouteTables(params)
if err != nil {
return nil, err
}
if len(tables.RouteTables) == 0 {
// this subnet is implicitly associated with Main
log.Info("Found subnet implicitly associated with Main route table: ", subnet)
subnets = append(subnets, subnet)
}
}
return subnets, nil
}
func discoverPublicSubnets(svc ec2iface.EC2API) ([]*string, error) {
var subnetIDs []*string
vpcFilter := &ec2.Filter{
Name: aws.String("vpc-id"),
Values: []*string{aws.String("vpc-38fa1a5c"), aws.String("vpc-a93675cc"), aws.String("vpc-7efb0b1a")},
}
publicAssocations, err := explicitPublicAssocations(svc, vpcFilter)
if err != nil {
return nil, err
}
// Determine whether the Main route table is public
// If the main route table is not internet enabled
// it does not matter if there are implicit assocations
// To determine implicit associations, see which subnets have no
// explicit route table associations
// List subnets
mainAssocPublicIndex := sort.Search(
len(publicAssocations),
func(i int) bool { return *publicAssocations[i].Main == true },
)
if mainAssocPublicIndex < len(publicAssocations) {
// lookup implicit assocations
subnets, err := implicitMainSubnets(svc, vpcFilter)
if err != nil {
return nil, err
}
for _, subnet := range subnets {
subnetIDs = append(subnetIDs, subnet.SubnetId)
}
}
for _, assoc := range publicAssocations {
subnetIDs = append(subnetIDs, assoc.SubnetId)
}
return subnetIDs, nil
}
func main() {
log.Info("Hello")
sess, err := session.NewSession(&aws.Config{
Region: aws.String("us-west-2"),
})
if err != nil {
panic(err)
}
ec2svc := ec2.New(sess)
subnets, err := discoverPublicSubnets(ec2svc)
if err != nil {
panic(err)
}
log.Info("Subnets --> ", subnets)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment