diff --git a/README.md b/README.md index d6caada..de32308 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ Control | CSP/AWS | HOST/OS | App/DB | How is it implemented? - S3 Buckets - Glacier Vaults - EC2 Instances + - EC2 Internet Gateways - Amazon Machine Images (AMI) - EBS Volumes - Snapshots @@ -263,6 +264,7 @@ provider "aws" { | Images | ec2:DescribeImages | queries EC2 Images | | Volumes | ec2:DescribeVolumes | queries EC2 Volumes | | Snapshots | ec2:DescribeSnapshots | queries EC2 Snapshots | +| IGWs | ec2:DescribeInternetGatewaysPages | queries EC2 IGWs | | VPCs | ec2:DescribeVpcs | queries EC2 VPCs | | VpcPeers | ec2:DescribeVpcPeeringConnectionsPages | queries EC2 Vpc Peers | | Subnets | ec2:DescribeSubnets | queries EC2 Subnets | diff --git a/handler/helpers/ec2.go b/handler/helpers/ec2.go index 0346974..07dc950 100644 --- a/handler/helpers/ec2.go +++ b/handler/helpers/ec2.go @@ -134,6 +134,36 @@ func (svc *Ec2Svc) Subnets() ([]*ec2.Subnet, error) { return results, nil } +type Igw struct { + ID string + OwnerID string + VpcID string + Status string +} + +// Igws ... pages through DescribeInternetGatewaysPages and returns all VPC Internet Gateways +func (svc *Ec2Svc) Igws() ([]*Igw, error) { + var results []*Igw + err := svc.Client.DescribeInternetGatewaysPages(&ec2.DescribeInternetGatewaysInput{}, + func(page *ec2.DescribeInternetGatewaysOutput, lastPage bool) bool { + for _, igw := range page.InternetGateways { + for _, att := range igw.Attachments { + results = append(results, &Igw{ + ID: aws.StringValue(igw.InternetGatewayId), + OwnerID: aws.StringValue(igw.OwnerId), + VpcID: aws.StringValue(att.VpcId), + Status: aws.StringValue(att.State), + }) + } + } + return !lastPage + }) + if err != nil { + return nil, err + } + return results, nil +} + // SecurityGroups ... pages through DescribeSecurityGroupsPages and returns all SecurityGroups func (svc *Ec2Svc) SecurityGroups() ([]*ec2.SecurityGroup, error) { var results []*ec2.SecurityGroup diff --git a/handler/helpers/helpers.go b/handler/helpers/helpers.go index 478f75b..bf77a0b 100644 --- a/handler/helpers/helpers.go +++ b/handler/helpers/helpers.go @@ -319,6 +319,7 @@ const ( SheetImages = "Images" SheetVolumes = "Volumes" SheetSnapshots = "Snapshots" + SheetIgws = "IGWs" SheetVpcs = "VPCs" SheetVpcPeers = "VpcPeers" SheetSubnets = "Subnets" @@ -374,6 +375,8 @@ func TypeToSheet(items interface{}) (string, error) { sheet = SheetVolumes case *ec2.Snapshot: sheet = SheetSnapshots + case *ec2.InternetGateway: + sheet = SheetIgws case *ec2.Vpc: sheet = SheetVpcs case *ec2.Subnet: diff --git a/handler/inv/init.go b/handler/inv/init.go index 987a3a0..9fd685c 100644 --- a/handler/inv/init.go +++ b/handler/inv/init.go @@ -122,6 +122,16 @@ func init() { {FriendlyName: "StartTime", FieldName: "StartTime"}, }} }) + spreadsheet.RegisterSheet(helpers.SheetIgws, func() *spreadsheet.Sheet { + return &spreadsheet.Sheet{Name: "IGWs", Columns: []*spreadsheet.Column{ + {FriendlyName: "Account", FieldName: ""}, + {FriendlyName: "Region", FieldName: ""}, + {FriendlyName: "Id", FieldName: "ID"}, + {FriendlyName: "VpcId", FieldName: "VpcID"}, + {FriendlyName: "OwnerId", FieldName: "OwnerID"}, + {FriendlyName: "Status", FieldName: "Status"}, + }} + }) spreadsheet.RegisterSheet(helpers.SheetVpcs, func() *spreadsheet.Sheet { return &spreadsheet.Sheet{Name: "VPCs", Columns: []*spreadsheet.Column{ {FriendlyName: "Account", FieldName: ""}, diff --git a/handler/inv/inv.go b/handler/inv/inv.go index 967fcc5..1a03b73 100644 --- a/handler/inv/inv.go +++ b/handler/inv/inv.go @@ -82,6 +82,7 @@ var knownErrors = map[string]interface{}{ "AccessDeniedException": nil, "AuthorizationError": nil, "UnauthorizedOperation": nil, + "ThrottlingException": nil, } func isKnownError(err error) bool { @@ -157,6 +158,7 @@ func New() (*Inv, error) { helpers.SheetImages: inv.queryImages, helpers.SheetVolumes: inv.queryVolumes, helpers.SheetSnapshots: inv.querySnapshots, + helpers.SheetIgws: inv.queryIgws, helpers.SheetVpcs: inv.queryVpcs, helpers.SheetVpcPeers: inv.queryVpcPeers, helpers.SheetSubnets: inv.querySubnets, @@ -216,6 +218,7 @@ func (inv *Inv) Run(s *spreadsheet.Spreadsheet) error { // all sheets have been completed successfully func (inv *Inv) query(funcs map[string]queryFunc) { for name, fn := range funcs { + time.Sleep(3 * time.Second) // offset to avoid throttling inv.running = append(inv.running, name) go func(fn queryFunc, name string, out chan interface{}, errc chan error) { payloads, err := fn() @@ -608,6 +611,27 @@ func (inv *Inv) querySnapshots() ([]*spreadsheet.Payload, error) { }) } +// queryIgws ... queries Igws for all organization accounts and +// all sessions/regions in SessionMgr, pushes them onto a slice of interface +// then returns a slice of *spreadsheet.Payload +func (inv *Inv) queryIgws() ([]*spreadsheet.Payload, error) { + defer logDuration()() + return inv.walkSessions(func(account string, cred *credentials.Credentials, sess *session.Session) (*spreadsheet.Payload, error) { + svc := helpers.Ec2Svc{ + Client: ec2Creator(sess, &aws.Config{Credentials: cred}), + } + peers, err := svc.Igws() + if err != nil { + return nil, newQueryErrorf(err, "failed to get VpcPeers for account: %s, region: %s -> %v", account, *sess.Config.Region, err) + } + var items []interface{} + for _, v := range peers { + items = append(items, v) + } + return &spreadsheet.Payload{Static: []string{account, *sess.Config.Region}, Items: items}, nil + }) +} + // queryVpcs ... queries VPCs for all organization accounts and // all sessions/regions in SessionMgr, pushes them onto a slice of interface // then returns a slice of *spreadsheet.Payload