From 59f7065cc2a57a25746d7175a0a0f8c9f67ccc9a Mon Sep 17 00:00:00 2001 From: Marius Kimmina <38843153+mariuskimmina@users.noreply.github.com> Date: Mon, 2 Oct 2023 05:17:58 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20AWS=20VPC=20subnet=20resource?= =?UTF-8?q?=20(#1827)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marius Kimmina --- providers/aws/resources/aws.lr | 14 +++ providers/aws/resources/aws.lr.go | 124 +++++++++++++++++++ providers/aws/resources/aws.lr.manifest.yaml | 13 ++ providers/aws/resources/aws_vpc.go | 42 +++++++ providers/aws/resources/shared.go | 1 + 5 files changed, 194 insertions(+) diff --git a/providers/aws/resources/aws.lr b/providers/aws/resources/aws.lr index a16ab84bdf..0772aa33b3 100644 --- a/providers/aws/resources/aws.lr +++ b/providers/aws/resources/aws.lr @@ -50,6 +50,8 @@ private aws.vpc @defaults("arn isDefault") { flowLogs() []aws.vpc.flowlog // List of route tables for the VPC routeTables() []aws.vpc.routetable + // List of subnets for the VPC + subnets() []aws.vpc.subnet // Tags on the VPC tags map[string]string } @@ -62,6 +64,18 @@ private aws.vpc.routetable @defaults("id") { routes []dict } +// Amazon Virtual Private Cloud (VPC) Subnet +private aws.vpc.subnet @defaults("arn") { + // ARN of the subnet + arn string + // Unique ID of the subnet + id string + // A list of CIDR descriptions + cidrs string + // Indicates whether instances launched in this subnet receive a public IPv4 address + mapPublicIpOnLaunch bool +} + // Amazon Virtual Private Cloud (VPC) Flow Log private aws.vpc.flowlog @defaults("id region status") { // Unique ID of the flow log diff --git a/providers/aws/resources/aws.lr.go b/providers/aws/resources/aws.lr.go index dba7cf286f..12da59428c 100644 --- a/providers/aws/resources/aws.lr.go +++ b/providers/aws/resources/aws.lr.go @@ -38,6 +38,10 @@ func init() { // to override args, implement: initAwsVpcRoutetable(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) Create: createAwsVpcRoutetable, }, + "aws.vpc.subnet": { + // to override args, implement: initAwsVpcSubnet(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) + Create: createAwsVpcSubnet, + }, "aws.vpc.flowlog": { // to override args, implement: initAwsVpcFlowlog(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) Create: createAwsVpcFlowlog, @@ -606,6 +610,9 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "aws.vpc.routeTables": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlAwsVpc).GetRouteTables()).ToDataRes(types.Array(types.Resource("aws.vpc.routetable"))) }, + "aws.vpc.subnets": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsVpc).GetSubnets()).ToDataRes(types.Array(types.Resource("aws.vpc.subnet"))) + }, "aws.vpc.tags": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlAwsVpc).GetTags()).ToDataRes(types.Map(types.String, types.String)) }, @@ -615,6 +622,18 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "aws.vpc.routetable.routes": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlAwsVpcRoutetable).GetRoutes()).ToDataRes(types.Array(types.Dict)) }, + "aws.vpc.subnet.arn": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsVpcSubnet).GetArn()).ToDataRes(types.String) + }, + "aws.vpc.subnet.id": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsVpcSubnet).GetId()).ToDataRes(types.String) + }, + "aws.vpc.subnet.cidrs": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsVpcSubnet).GetCidrs()).ToDataRes(types.String) + }, + "aws.vpc.subnet.mapPublicIpOnLaunch": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlAwsVpcSubnet).GetMapPublicIpOnLaunch()).ToDataRes(types.Bool) + }, "aws.vpc.flowlog.id": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlAwsVpcFlowlog).GetId()).ToDataRes(types.String) }, @@ -2645,6 +2664,10 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlAwsVpc).RouteTables, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) return }, + "aws.vpc.subnets": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsVpc).Subnets, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, "aws.vpc.tags": func(r plugin.Resource, v *llx.RawData) (ok bool) { r.(*mqlAwsVpc).Tags, ok = plugin.RawToTValue[map[string]interface{}](v.Value, v.Error) return @@ -2661,6 +2684,26 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlAwsVpcRoutetable).Routes, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) return }, + "aws.vpc.subnet.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsVpcSubnet).__id, ok = v.Value.(string) + return + }, + "aws.vpc.subnet.arn": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsVpcSubnet).Arn, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "aws.vpc.subnet.id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsVpcSubnet).Id, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "aws.vpc.subnet.cidrs": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsVpcSubnet).Cidrs, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "aws.vpc.subnet.mapPublicIpOnLaunch": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlAwsVpcSubnet).MapPublicIpOnLaunch, ok = plugin.RawToTValue[bool](v.Value, v.Error) + return + }, "aws.vpc.flowlog.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { r.(*mqlAwsVpcFlowlog).__id, ok = v.Value.(string) return @@ -5928,6 +5971,7 @@ type mqlAwsVpc struct { Region plugin.TValue[string] FlowLogs plugin.TValue[[]interface{}] RouteTables plugin.TValue[[]interface{}] + Subnets plugin.TValue[[]interface{}] Tags plugin.TValue[map[string]interface{}] } @@ -6020,6 +6064,22 @@ func (c *mqlAwsVpc) GetRouteTables() *plugin.TValue[[]interface{}] { }) } +func (c *mqlAwsVpc) GetSubnets() *plugin.TValue[[]interface{}] { + return plugin.GetOrCompute[[]interface{}](&c.Subnets, func() ([]interface{}, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("aws.vpc", c.__id, "subnets") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.([]interface{}), nil + } + } + + return c.subnets() + }) +} + func (c *mqlAwsVpc) GetTags() *plugin.TValue[map[string]interface{}] { return &c.Tags } @@ -6073,6 +6133,70 @@ func (c *mqlAwsVpcRoutetable) GetRoutes() *plugin.TValue[[]interface{}] { return &c.Routes } +// mqlAwsVpcSubnet for the aws.vpc.subnet resource +type mqlAwsVpcSubnet struct { + MqlRuntime *plugin.Runtime + __id string + // optional: if you define mqlAwsVpcSubnetInternal it will be used here + Arn plugin.TValue[string] + Id plugin.TValue[string] + Cidrs plugin.TValue[string] + MapPublicIpOnLaunch plugin.TValue[bool] +} + +// createAwsVpcSubnet creates a new instance of this resource +func createAwsVpcSubnet(runtime *plugin.Runtime, args map[string]*llx.RawData) (plugin.Resource, error) { + res := &mqlAwsVpcSubnet{ + MqlRuntime: runtime, + } + + err := SetAllData(res, args) + if err != nil { + return res, err + } + + if res.__id == "" { + res.__id, err = res.id() + if err != nil { + return nil, err + } + } + + if runtime.HasRecording { + args, err = runtime.ResourceFromRecording("aws.vpc.subnet", res.__id) + if err != nil || args == nil { + return res, err + } + return res, SetAllData(res, args) + } + + return res, nil +} + +func (c *mqlAwsVpcSubnet) MqlName() string { + return "aws.vpc.subnet" +} + +func (c *mqlAwsVpcSubnet) MqlID() string { + return c.__id +} + +func (c *mqlAwsVpcSubnet) GetArn() *plugin.TValue[string] { + return &c.Arn +} + +func (c *mqlAwsVpcSubnet) GetId() *plugin.TValue[string] { + return &c.Id +} + +func (c *mqlAwsVpcSubnet) GetCidrs() *plugin.TValue[string] { + return &c.Cidrs +} + +func (c *mqlAwsVpcSubnet) GetMapPublicIpOnLaunch() *plugin.TValue[bool] { + return &c.MapPublicIpOnLaunch +} + // mqlAwsVpcFlowlog for the aws.vpc.flowlog resource type mqlAwsVpcFlowlog struct { MqlRuntime *plugin.Runtime diff --git a/providers/aws/resources/aws.lr.manifest.yaml b/providers/aws/resources/aws.lr.manifest.yaml index 4743fa5de0..1d12ab79e9 100755 --- a/providers/aws/resources/aws.lr.manifest.yaml +++ b/providers/aws/resources/aws.lr.manifest.yaml @@ -2169,6 +2169,8 @@ resources: region: {} routeTables: {} state: {} + subnets: + min_mondoo_version: 9.0.0 tags: {} is_private: true min_mondoo_version: 5.15.0 @@ -2196,3 +2198,14 @@ resources: platform: name: - aws + aws.vpc.subnet: + fields: + arn: {} + cidrs: {} + id: {} + mapPublicIpOnLaunch: {} + is_private: true + min_mondoo_version: 9.0.0 + platform: + name: + - aws diff --git a/providers/aws/resources/aws_vpc.go b/providers/aws/resources/aws_vpc.go index 29aeb31d83..602316a7d7 100644 --- a/providers/aws/resources/aws_vpc.go +++ b/providers/aws/resources/aws_vpc.go @@ -180,6 +180,48 @@ func (a *mqlAwsVpc) routeTables() ([]interface{}, error) { return res, nil } +func (a *mqlAwsVpcSubnet) id() (string, error) { + return a.Arn.Data, nil +} + +func (a *mqlAwsVpc) subnets() ([]interface{}, error) { + conn := a.MqlRuntime.Connection.(*connection.AwsConnection) + vpcVal := a.Id.Data + + svc := conn.Ec2(a.Region.Data) + ctx := context.Background() + res := []interface{}{} + + nextToken := aws.String("no_token_to_start_with") + filterName := "vpc-id" + params := &ec2.DescribeSubnetsInput{Filters: []vpctypes.Filter{{Name: &filterName, Values: []string{vpcVal}}}} + for nextToken != nil { + subnets, err := svc.DescribeSubnets(ctx, params) + if err != nil { + return nil, err + } + nextToken = subnets.NextToken + if subnets.NextToken != nil { + params.NextToken = nextToken + } + + for _, subnet := range subnets.Subnets { + subnetResource, err := CreateResource(a.MqlRuntime, "aws.vpc.subnet", + map[string]*llx.RawData{ + "arn": llx.StringData(fmt.Sprintf(subnetArnPattern, a.Region.Data, conn.AccountId(), convert.ToString(subnet.SubnetId))), + "id": llx.StringData(convert.ToString(subnet.SubnetId)), + "cidrs": llx.StringData(*subnet.CidrBlock), + "mapPublicIpOnLaunch": llx.BoolData(*subnet.MapPublicIpOnLaunch), + }) + if err != nil { + return nil, err + } + res = append(res, subnetResource) + } + } + return res, nil +} + func initAwsVpc(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) { if len(args) > 2 { return args, nil, nil diff --git a/providers/aws/resources/shared.go b/providers/aws/resources/shared.go index cdba6cd0ec..7d3c7d2ebf 100644 --- a/providers/aws/resources/shared.go +++ b/providers/aws/resources/shared.go @@ -36,6 +36,7 @@ const ( networkAclArnPattern = "arn:aws:ec2:%s:%s:network-acl/%s" imageArnPattern = "arn:aws:ec2:%s:%s:image/%s" keypairArnPattern = "arn:aws:ec2:%s:%s:keypair/%s" + subnetArnPattern = "arn:aws:ec2:%s:%s:subnet/%s" s3ArnPattern = "arn:aws:s3:::%s" dynamoTableArnPattern = "arn:aws:dynamodb:%s:%s:table/%s" limitsArn = "arn:aws:dynamodb:%s:%s"