From 751985bd9555ce143db9a47873c96704d012b429 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Sat, 12 Feb 2022 15:51:12 +0200 Subject: [PATCH 1/2] policy --- .changelog/17039.txt | 3 + internal/provider/provider.go | 1 + internal/service/ec2/vpc_endpoint_policy.go | 141 ++++++++++++++++ .../service/ec2/vpc_endpoint_policy_test.go | 158 ++++++++++++++++++ .../docs/r/vpc_endpoint_policy.html.markdown | 69 ++++++++ 5 files changed, 372 insertions(+) create mode 100644 .changelog/17039.txt create mode 100644 internal/service/ec2/vpc_endpoint_policy.go create mode 100644 internal/service/ec2/vpc_endpoint_policy_test.go create mode 100644 website/docs/r/vpc_endpoint_policy.html.markdown diff --git a/.changelog/17039.txt b/.changelog/17039.txt new file mode 100644 index 00000000000..955cf01c3cc --- /dev/null +++ b/.changelog/17039.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +vpc_endpoint_policy +``` \ No newline at end of file diff --git a/internal/provider/provider.go b/internal/provider/provider.go index d3b00076b04..473b6b870b1 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1225,6 +1225,7 @@ func Provider() *schema.Provider { "aws_vpc_endpoint": ec2.ResourceVPCEndpoint(), "aws_vpc_endpoint_connection_accepter": ec2.ResourceVPCEndpointConnectionAccepter(), "aws_vpc_endpoint_connection_notification": ec2.ResourceVPCEndpointConnectionNotification(), + "aws_vpc_endpoint_policy": ec2.ResourceVPCEndpointPolicy(), "aws_vpc_endpoint_route_table_association": ec2.ResourceVPCEndpointRouteTableAssociation(), "aws_vpc_endpoint_service": ec2.ResourceVPCEndpointService(), "aws_vpc_endpoint_service_allowed_principal": ec2.ResourceVPCEndpointServiceAllowedPrincipal(), diff --git a/internal/service/ec2/vpc_endpoint_policy.go b/internal/service/ec2/vpc_endpoint_policy.go new file mode 100644 index 00000000000..98ba9948613 --- /dev/null +++ b/internal/service/ec2/vpc_endpoint_policy.go @@ -0,0 +1,141 @@ +package ec2 + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +func ResourceVPCEndpointPolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceVPCEndpointPolicyPut, + Update: resourceVPCEndpointPolicyPut, + Read: resourceVPCEndpointPolicyRead, + Delete: resourceVPCEndpointPolicyDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "policy": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs, + StateFunc: func(v interface{}) string { + json, _ := structure.NormalizeJsonString(v) + return json + }, + }, + "vpc_endpoint_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + } +} + +func resourceVPCEndpointPolicyPut(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).EC2Conn + + endpointID := d.Get("vpc_endpoint_id").(string) + req := &ec2.ModifyVpcEndpointInput{ + VpcEndpointId: aws.String(endpointID), + } + + policy, err := structure.NormalizeJsonString(d.Get("policy")) + if err != nil { + return fmt.Errorf("policy contains an invalid JSON: %w", err) + } + + if policy == "" { + req.ResetPolicy = aws.Bool(true) + } else { + req.PolicyDocument = aws.String(policy) + } + + log.Printf("[DEBUG] Updating VPC Endpoint Policy: %#v", req) + if _, err := conn.ModifyVpcEndpoint(req); err != nil { + return fmt.Errorf("Error updating VPC Endpoint Policy: %w", err) + } + d.SetId(endpointID) + + _, err = WaitVPCEndpointAvailable(conn, endpointID, d.Timeout(schema.TimeoutCreate)) + + if err != nil { + return fmt.Errorf("error waiting for VPC Endpoint (%s) to policy to set: %w", endpointID, err) + } + + return resourceVPCEndpointPolicyRead(d, meta) +} + +func resourceVPCEndpointPolicyRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).EC2Conn + + vpce, err := FindVPCEndpointByID(conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] VPC Endpoint Policy (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading VPC Endpoint Policy (%s): %w", d.Id(), err) + } + + d.Set("vpc_endpoint_id", d.Id()) + + policyToSet, err := verify.SecondJSONUnlessEquivalent(d.Get("policy").(string), aws.StringValue(vpce.PolicyDocument)) + + if err != nil { + return fmt.Errorf("while setting policy (%s), encountered: %w", policyToSet, err) + } + + policyToSet, err = structure.NormalizeJsonString(policyToSet) + + if err != nil { + return fmt.Errorf("policy (%s) is invalid JSON: %w", policyToSet, err) + } + + d.Set("policy", policyToSet) + return nil +} + +func resourceVPCEndpointPolicyDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).EC2Conn + + req := &ec2.ModifyVpcEndpointInput{ + VpcEndpointId: aws.String(d.Id()), + ResetPolicy: aws.Bool(true), + } + + log.Printf("[DEBUG] Resetting VPC Endpoint Policy: %#v", req) + if _, err := conn.ModifyVpcEndpoint(req); err != nil { + return fmt.Errorf("Error Resetting VPC Endpoint Policy: %w", err) + } + + _, err := WaitVPCEndpointAvailable(conn, d.Id(), d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return fmt.Errorf("error waiting for VPC Endpoint (%s) to be reset: %w", d.Id(), err) + } + + return nil +} diff --git a/internal/service/ec2/vpc_endpoint_policy_test.go b/internal/service/ec2/vpc_endpoint_policy_test.go new file mode 100644 index 00000000000..d80a8abf0fe --- /dev/null +++ b/internal/service/ec2/vpc_endpoint_policy_test.go @@ -0,0 +1,158 @@ +package ec2_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/ec2" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" +) + +func TestAccEC2VPCEndpointPolicy_basic(t *testing.T) { + var endpoint ec2.VpcEndpoint + + resourceName := "aws_vpc_endpoint_policy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckVpcEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVpcEndpointPolicyBasicConfig(rName, policy1), + Check: resource.ComposeTestCheckFunc( + testAccCheckVpcEndpointExists(resourceName, &endpoint), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccVpcEndpointPolicyBasicConfig(rName, policy2), + Check: resource.ComposeTestCheckFunc( + testAccCheckVpcEndpointExists(resourceName, &endpoint), + ), + }, + }, + }) +} + +func TestAccEC2VPCEndpointPolicy_disappears(t *testing.T) { + var endpoint ec2.VpcEndpoint + resourceName := "aws_vpc_endpoint_policy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckVpcEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVpcEndpointPolicyBasicConfig(rName, policy1), + Check: resource.ComposeTestCheckFunc( + testAccCheckVpcEndpointExists(resourceName, &endpoint), + acctest.CheckResourceDisappears(acctest.Provider, tfec2.ResourceVPCEndpointPolicy(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccEC2VPCEndpointPolicy_disappears_endpoint(t *testing.T) { + var endpoint ec2.VpcEndpoint + resourceName := "aws_vpc_endpoint_policy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckVpcEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVpcEndpointPolicyBasicConfig(rName, policy1), + Check: resource.ComposeTestCheckFunc( + testAccCheckVpcEndpointExists(resourceName, &endpoint), + acctest.CheckResourceDisappears(acctest.Provider, tfec2.ResourceVPCEndpoint(), "aws_vpc_endpoint.test"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +const policy1 = ` +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ReadOnly", + "Principal": "*", + "Action": [ + "dynamodb:DescribeTable", + "dynamodb:ListTables" + ], + "Effect": "Allow", + "Resource": "*" + } + ] +} +` + +const policy2 = ` +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowAll", + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Action": "*", + "Resource": "*" + } + ] +} +` + +func testAccVpcEndpointPolicyBasicConfig(rName, policy string) string { + return fmt.Sprintf(` +data "aws_vpc_endpoint_service" "test" { + service = "dynamodb" +} + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_vpc_endpoint" "test" { + service_name = data.aws_vpc_endpoint_service.test.service_name + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_vpc_endpoint_policy" "test" { + vpc_endpoint_id = aws_vpc_endpoint.test.id + policy = < Date: Wed, 23 Feb 2022 09:11:10 -0500 Subject: [PATCH 2/2] Update 17039.txt --- .changelog/17039.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changelog/17039.txt b/.changelog/17039.txt index 955cf01c3cc..3ffa2c63a05 100644 --- a/.changelog/17039.txt +++ b/.changelog/17039.txt @@ -1,3 +1,3 @@ ```release-note:new-resource -vpc_endpoint_policy -``` \ No newline at end of file +aws_vpc_endpoint_policy +```