func isSubnetPublic(rt []*ec2.RouteTable, subnetID string) (bool, error) {
	var subnetTable *ec2.RouteTable
	for _, table := range rt {
		for _, assoc := range table.Associations {
			if aws.StringValue(assoc.SubnetId) == subnetID {
				subnetTable = table
				break
			}
		}
	}
	if subnetTable == nil {
		for _, table := range rt {
			for _, assoc := range table.Associations {
				if aws.BoolValue(assoc.Main) {
					subnetTable = table
					break
				}
			}
		}
	}
	if subnetTable == nil {
		return false, fmt.Errorf("could not locate routing table for subnet %q", subnetID)
	}
	for _, route := range subnetTable.Routes {
		if strings.HasPrefix(aws.StringValue(route.GatewayId), "igw") {
			return true, nil
		}
	}
	return false, nil
}
Copied from Kubernete's https://github.com/kubernetes/kubernetes/blob/master/pkg/cloudprovider/providers/aws/aws.go
package aws
import (
	"fmt"
	"strings"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
	log "github.com/sirupsen/logrus"
)
const (
	defaultClusterID           = "unknown-cluster"
	kubernetesClusterLegacyTag = "KubernetesCluster"
	clusterIDTag               = "ClusterID"  
	clusterIDTagPrefix         = "kubernetes.io/cluster/"
	resourceLifecycleOwned     = "owned"
	kubernetesCreatorTag       = "kubernetes:application"
	autoScalingGroupNameTag    = "aws:autoscaling:groupName"
	runningState               = 16  
	stoppedState               = 80  
	elbRoleTagName             = "kubernetes.io/role/elb"
	internalELBRoleTagName     = "kubernetes.io/role/internal-elb"
	kubernetesNodeRoleTag      = "k8s.io/role/node"
)
type securityGroupDetails struct {
	name string
	id   string
}
type instanceDetails struct {
	id      string
	ip      string
	vpcID   string
	tags    map[string]string
	running bool
}
func (id *instanceDetails) clusterID() string {
	for name, value := range id.tags {
		if strings.HasPrefix(name, clusterIDTagPrefix) && value == resourceLifecycleOwned {
			return strings.TrimPrefix(name, clusterIDTagPrefix)
		}
	}
	for name, value := range id.tags {
		if name == kubernetesClusterLegacyTag {
			return value
		}
	}
	return defaultClusterID
}
type subnetDetails struct {
	id               string
	availabilityZone string
	tags             map[string]string
	public           bool
}
func (sd *subnetDetails) String() string {
	return fmt.Sprintf("%s (%s) @ %s (public: %t)", sd.Name(), sd.id, sd.availabilityZone, sd.public)
}
func (sd *subnetDetails) Name() string {
	if n, err := getNameTag(sd.tags); err == nil {
		return n
	}
	return "unknown-subnet"
}
func getAutoScalingGroupName(instanceTags map[string]string) (string, error) {
	if len(instanceTags) < 1 {
		return "", ErrMissingAutoScalingGroupTag
	}
	asg, has := instanceTags[autoScalingGroupNameTag]
	if !has || asg == "" {
		return "", ErrMissingAutoScalingGroupTag
	}
	return asg, nil
}
func getInstanceDetails(ec2Service ec2iface.EC2API, instanceID string) (*instanceDetails, error) {
	params := &ec2.DescribeInstancesInput{
		Filters: []*ec2.Filter{
			{
				Name: aws.String("instance-id"),
				Values: []*string{
					aws.String(instanceID),
				},
			},
		},
	}
	resp, err := ec2Service.DescribeInstances(params)
	if err != nil || resp == nil {
		return nil, fmt.Errorf("unable to get details for instance %q: %v", instanceID, err)
	}
	i, err := findFirstRunningInstance(resp)
	if err != nil {
		return nil, fmt.Errorf("unable to find instance %q: %v", instanceID, err)
	}
	return &instanceDetails{
		id:      aws.StringValue(i.InstanceId),
		ip:      aws.StringValue(i.PrivateIpAddress),
		vpcID:   aws.StringValue(i.VpcId),
		tags:    convertEc2Tags(i.Tags),
		running: aws.Int64Value(i.State.Code)&0xff == runningState,
	}, nil
}
func getInstancesDetailsWithFilters(ec2Service ec2iface.EC2API, filters []*ec2.Filter) (map[string]*instanceDetails, error) {
	params := &ec2.DescribeInstancesInput{
		Filters: filters,
	}
	result := make(map[string]*instanceDetails)
	err := ec2Service.DescribeInstancesPages(params, func(resp *ec2.DescribeInstancesOutput, lastPage bool) bool {
		for _, reservation := range resp.Reservations {
			for _, instance := range reservation.Instances {
				result[aws.StringValue(instance.InstanceId)] = &instanceDetails{
					id:      aws.StringValue(instance.InstanceId),
					ip:      aws.StringValue(instance.PrivateIpAddress),
					vpcID:   aws.StringValue(instance.VpcId),
					tags:    convertEc2Tags(instance.Tags),
					running: aws.Int64Value(instance.State.Code)&0xff == runningState,
				}
			}
		}
		return true
	})
	if err != nil {
		return nil, fmt.Errorf("failed getting instance list from EC2: %v", err)
	}
	return result, nil
}
func findFirstRunningInstance(resp *ec2.DescribeInstancesOutput) (*ec2.Instance, error) {
	for _, reservation := range resp.Reservations {
		for _, instance := range reservation.Instances {
			if aws.Int64Value(instance.State.Code)&0xff == runningState {
				return instance, nil
			}
		}
	}
	return nil, ErrNoRunningInstances
}
func getSubnets(svc ec2iface.EC2API, vpcID, clusterID string) ([]*subnetDetails, error) {
	params := &ec2.DescribeSubnetsInput{
		Filters: []*ec2.Filter{
			{
				Name: aws.String("vpc-id"),
				Values: []*string{
					aws.String(vpcID),
				},
			},
		},
	}
	resp, err := svc.DescribeSubnets(params)
	if err != nil {
		return nil, err
	}
	log.Debug("aws.getRouteTables")
	rt, err := getRouteTables(svc, vpcID)
	if err != nil {
		return nil, err
	}
	retAll := make([]*subnetDetails, len(resp.Subnets))
	retFiltered := make([]*subnetDetails, 0)
	for i, sn := range resp.Subnets {
		az := aws.StringValue(sn.AvailabilityZone)
		subnetID := aws.StringValue(sn.SubnetId)
		isPublic, err := isSubnetPublic(rt, subnetID)
		if err != nil {
			return nil, err
		}
		tags := convertEc2Tags(sn.Tags)
		retAll[i] = &subnetDetails{
			id:               subnetID,
			availabilityZone: az,
			public:           isPublic,
			tags:             tags,
		}
		if _, ok := tags[clusterIDTagPrefix+clusterID]; ok {
			retFiltered = append(retFiltered, &subnetDetails{
				id:               subnetID,
				availabilityZone: az,
				public:           isPublic,
				tags:             tags,
			})
		}
	}
	if len(retFiltered) == 0 {
		log.Warn("No tagged subnets found; considering all subnets. This is likely to be an error in future versions.")
		return retAll, nil
	}
	return retFiltered, nil
}
func convertEc2Tags(instanceTags []*ec2.Tag) map[string]string {
	tags := make(map[string]string, len(instanceTags))
	for _, tagDescription := range instanceTags {
		tags[aws.StringValue(tagDescription.Key)] = aws.StringValue(tagDescription.Value)
	}
	return tags
}
func getRouteTables(svc ec2iface.EC2API, vpcID string) ([]*ec2.RouteTable, error) {
	params := &ec2.DescribeRouteTablesInput{
		Filters: []*ec2.Filter{
			{
				Name: aws.String("vpc-id"),
				Values: []*string{
					aws.String(vpcID),
				},
			},
		},
	}
	resp, err := svc.DescribeRouteTables(params)
	if err != nil {
		return nil, err
	}
	return resp.RouteTables, nil
}