-
-
Save prasanthj/8eed4896ef943a93fdbba2757af71d8a to your computer and use it in GitHub Desktop.
finding public subnets in go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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