Skip to content

Commit

Permalink
Add aws_route53_vpc_association_authorization table (#2199)
Browse files Browse the repository at this point in the history
  • Loading branch information
jramosf authored Jun 10, 2024
1 parent 0a68935 commit 240e9f1
Show file tree
Hide file tree
Showing 10 changed files with 361 additions and 1 deletion.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"hosted_zone_id": "{{output.resource_hosted_zone_id.value}}",
"akas": "{{output.resource_aka.value}}"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
select hosted_zone_id, akas
from aws_route53_vpc_association_authorization
where hosted_zone_id = '{{output.resource_hosted_zone_id.value}}'
and vpc_id = '{{output.resource_vpc_alternate_id.value}}'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
select hosted_zone_id
from aws_route53_vpc_association_authorization
where hosted_zone_id = 'UNKNOWN_ZONE_ID'
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
104 changes: 104 additions & 0 deletions aws-test/tests/aws_route53_vpc_association_authorization/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@


variable "resource_name" {
type = string
default = "turbot-test-20200125-create-update"
description = "Name of the resource used throughout the test."
}

variable "aws_profile" {
type = string
default = "default"
description = "AWS credentials profile used for the test. Default is to use the default profile."
}

variable "aws_region" {
type = string
default = "us-east-1"
description = "AWS region used for the test. Does not work with default region in config, so must be defined here."
}

variable "aws_region_alternate" {
type = string
default = "us-east-2"
description = "Alternate AWS region used for tests that require two regions (e.g. DynamoDB global tables)."
}

provider "aws" {
profile = var.aws_profile
region = var.aws_region
}

provider "aws" {
alias = "alternate"
profile = var.aws_profile
region = var.aws_region_alternate
}

data "aws_canonical_user_id" "current_user" {}
data "aws_partition" "current" {}
data "aws_caller_identity" "current" {}
data "aws_region" "primary" {}
data "aws_region" "alternate" {
provider = aws.alternate
}

data "null_data_source" "resource" {
inputs = {
scope = "arn:${data.aws_partition.current.partition}:::${data.aws_caller_identity.current.account_id}"
}
}

resource "aws_vpc" "main" {
cidr_block = "10.6.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
}

resource "aws_vpc" "alternate" {
provider = aws.alternate

cidr_block = "10.7.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
}

resource "aws_route53_zone" "main" {
name = "example.com"

vpc {
vpc_id = aws_vpc.main.id
}

# Prevent the deletion of associated VPCs after
# the initial creation. See documentation on
# aws_route53_zone_association for details
lifecycle {
ignore_changes = [vpc]
}
}

resource "aws_route53_vpc_association_authorization" "resource" {
vpc_id = aws_vpc.alternate.id
zone_id = aws_route53_zone.main.id
}

output "resource_hosted_zone_id" {
value = aws_route53_zone.zone_id
}

output "resource_vpc_alternate_id" {
value = aws_vpc.alternate.id
}

output "resource_aka" {
value = "${aws_route53_zone.main.zone_id}:${aws_vpc.alternate.id}"
}

output "account_id" {
value = data.aws_caller_identity.current.account_id
}

output "aws_partition" {
value = data.aws_partition.current.partition
}
3 changes: 2 additions & 1 deletion aws/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ func Plugin(ctx context.Context) *plugin.Plugin {
"aws_iot_fleet_metric": tableAwsIoTFleetMetric(ctx),
"aws_iot_thing": tableAwsIoTThing(ctx),
"aws_iot_thing_group": tableAwsIoTThingGroup(ctx),
"aws_iot_thing_type": tableAwsIoTThingType(ctx),
"aws_iot_thing_type": tableAwsIoTThingType(ctx),
"aws_kinesis_consumer": tableAwsKinesisConsumer(ctx),
"aws_kinesis_firehose_delivery_stream": tableAwsKinesisFirehoseDeliveryStream(ctx),
"aws_kinesis_stream": tableAwsKinesisStream(ctx),
Expand Down Expand Up @@ -439,6 +439,7 @@ func Plugin(ctx context.Context) *plugin.Plugin {
"aws_route53_resolver_rule": tableAwsRoute53ResolverRule(ctx),
"aws_route53_traffic_policy": tableAwsRoute53TrafficPolicy(ctx),
"aws_route53_traffic_policy_instance": tableAwsRoute53TrafficPolicyInstance(ctx),
"aws_route53_vpc_association_authorization": tableAwsRoute53VPCAssociationAuthorization(ctx),
"aws_route53_zone": tableAwsRoute53Zone(ctx),
"aws_s3_access_point": tableAwsS3AccessPoint(ctx),
"aws_s3_account_settings": tableAwsS3AccountSettings(ctx),
Expand Down
143 changes: 143 additions & 0 deletions aws/table_aws_route53_vpc_association_authorization.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package aws

import (
"context"
"fmt"
"strings"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/route53"

"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform"
)

func tableAwsRoute53VPCAssociationAuthorization(_ context.Context) *plugin.Table {
return &plugin.Table{
Name: "aws_route53_vpc_association_authorization",
Description: "AWS Route53 VPC Association Authorization",
List: &plugin.ListConfig{
ParentHydrate: listHostedZones,
Hydrate: listVPCAssociationAuthorization,
IgnoreConfig: &plugin.IgnoreConfig{
ShouldIgnoreErrorFunc: shouldIgnoreErrors([]string{"NoSuchHostedZone"}),
},
KeyColumns: []*plugin.KeyColumn{
{
Name: "hosted_zone_id",
Require: plugin.Optional,
},
},
Tags: map[string]string{"service": "route53", "action": "ListVPCAssociationAuthorizations"},
},
Columns: awsGlobalRegionColumns([]*plugin.Column{
{
Name: "hosted_zone_id",
Description: "The ID of the hosted zone for which you want a list of VPCs that can be associated with the hosted zone.",
Type: proto.ColumnType_STRING,
},
{
Name: "vpc_id",
Description: "(Private hosted zones only) The ID of an Amazon VPC.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("VPCId"),
},
{
Name: "vpc_region",
Description: "(Private hosted zones only) The region that an Amazon VPC was created in.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("VPCRegion"),
},

// Steampipe standard columns
{
Name: "title",
Description: resourceInterfaceDescription("title"),
Type: proto.ColumnType_STRING,
Transform: transform.From(authorizationTitle).Transform(transform.ToString),
},
}),
}
}

type VPCAssociationAuthorizationResult struct {
HostedZoneId *string
VPCId *string
VPCRegion *string
}

//// LIST FUNCTION
func listVPCAssociationAuthorization(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {

// Create session
svc, err := Route53Client(ctx, d)
if err != nil {
plugin.Logger(ctx).Error("aws_route53_zone_vpc_association_authorization.listVPCAssociationAuthorization", "client_error", err)
return nil, err
}

var hostedZoneId = d.EqualsQualString("hosted_zone_id")

// Try to use ParentHydrate if no explicit value in quals
if hostedZoneId == "" {
zone := h.Item.(HostedZoneResult)
if zone.Id == nil {
return nil, nil
}
hostedZoneId = strings.Split(*zone.Id, "/")[2]
}

// https://docs.aws.amazon.com/Route53/latest/APIReference/API_ListVPCAssociationAuthorizations.html#API_ListVPCAssociationAuthorizations_RequestSyntax
// Max 50 per page as per aws api docs
maxItems := int32(50)
if d.QueryContext.Limit != nil {
limit := int32(*d.QueryContext.Limit)
if limit < maxItems {
maxItems = int32(limit)
}
}

input := &route53.ListVPCAssociationAuthorizationsInput{
HostedZoneId: aws.String(hostedZoneId),
MaxResults: aws.Int32(maxItems),
}

for {
result, err := svc.ListVPCAssociationAuthorizations(ctx, input)
if err != nil {
plugin.Logger(ctx).Error("aws_route53_zone_vpc_association_authorization.listVPCAssociationAuthorization", "api_error", err)
return nil, err
}

for _, vpc := range result.VPCs {
vpcRegion := string(vpc.VPCRegion)
d.StreamListItem(ctx, &VPCAssociationAuthorizationResult{
HostedZoneId: &hostedZoneId,
VPCId: vpc.VPCId,
VPCRegion: &vpcRegion,
})

// context cancelled
if d.RowsRemaining(ctx) == 0 {
return nil, nil
}
}

if result.NextToken == nil {
break
}
input.NextToken = result.NextToken
}
return nil, nil
}

// TRANSFORM FUNCTIONS
func authorizationTitle(ctx context.Context, d *transform.TransformData) (interface{}, error) {
result := d.HydrateItem.(*VPCAssociationAuthorizationResult)

// same format as terraform builtin IDs "HOSTED_ZONE_ID:VPC_ID"
// https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_vpc_association_authorization#import
akas := fmt.Sprintf("%s:%s", *result.HostedZoneId, *result.VPCId)
return akas, nil
}
97 changes: 97 additions & 0 deletions docs/tables/aws_route53_vpc_association_authorization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
title: "Steampipe Table: aws_route53_vpc_association_authorization - Query AWS Route53 for other-account VPCs."
description: "Gets a list of the VPCs that were created by other accounts and that can be associated with a specified hosted zone because you've submitted one or more `CreateVPCAssociationAuthorization` requests."
---

# Table: aws_route53_vpc_association_authorization - Query AWS Route53 for other-account VPCs using SQL

Amazon Route 53 is a highly available and scalable Domain Name System (DNS) web service.

## Table Usage Guide

The `aws_route53_vpc_association_authorization` table in Steampipe provides you with information VPCs in other AWS accounts that are authorized to be associated with a specified `hosted_zone_id`.

## Examples

### Basic info
Check which other-account VPCs are authorized

```sql+postgres
select
hosted_zone_id,
vpc_id,
vpc_region
from
aws_route53_vpc_association_authorization
where
hosted_zone_id = 'Z3M3LMPEXAMPLE';
```

```sql+sqlite
select
hosted_zone_id,
vpc_id,
vpc_region
from
aws_route53_vpc_association_authorization
where
hosted_zone_id = 'Z3M3LMPEXAMPLE';
```

### Sort VPCs descending by region name

```sql+postgres
select
hosted_zone_id,
vpc_id,
vpc_region
from
aws_route53_vpc_association_authorization
where
hosted_zone_id = 'Z3M3LMPEXAMPLE'
order by
vpc_region desc;
```

```sql+sqlite
select
hosted_zone_id,
vpc_id,
vpc_region
from
aws_route53_vpc_association_authorization
where
hosted_zone_id = 'Z3M3LMPEXAMPLE'
order by
vpc_region desc;
```

### Retrieve VPC Association Authorizations for available Hosted Zones

You can combine multiple tables to query or get fields such as the zone domain name (something the AWS API does not provide by default).

```sql+postgres
select
auth.hosted_zone_id,
z.name,
auth.vpc_id,
auth.vpc_region
from
aws_route53_vpc_association_authorization auth
inner join
aws_route53_zone z on auth.hosted_zone_id = z.id
where z.name = 'mycooldomain.xyz';
```

```sql+sqlite
select
auth.hosted_zone_id,
z.name,
auth.vpc_id,
auth.vpc_region
from
aws_route53_vpc_association_authorization auth
inner join
aws_route53_zone z on auth.hosted_zone_id = z.id
where z.name = 'mycooldomain.xyz';
```

0 comments on commit 240e9f1

Please sign in to comment.