Skip to content

Commit

Permalink
New Resource: aws_api_gateway_rest_api_policy (#13619)
Browse files Browse the repository at this point in the history
* add api gateway rest api policy resource

* fix delete

* Update resource_aws_api_gateway_rest_api_policy_test.go

* lint

* sdk v2

* add logs for errors and use %w

* add logs for errors and use %w

* use tf 12 syntax for tests

* make policy checks more specific
  • Loading branch information
DrFaust92 authored Nov 17, 2020
1 parent c735aad commit f2904b2
Show file tree
Hide file tree
Showing 5 changed files with 418 additions and 0 deletions.
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ func Provider() *schema.Provider {
"aws_api_gateway_request_validator": resourceAwsApiGatewayRequestValidator(),
"aws_api_gateway_resource": resourceAwsApiGatewayResource(),
"aws_api_gateway_rest_api": resourceAwsApiGatewayRestApi(),
"aws_api_gateway_rest_api_policy": resourceAwsApiGatewayRestApiPolicy(),
"aws_api_gateway_stage": resourceAwsApiGatewayStage(),
"aws_api_gateway_usage_plan": resourceAwsApiGatewayUsagePlan(),
"aws_api_gateway_usage_plan_key": resourceAwsApiGatewayUsagePlanKey(),
Expand Down
1 change: 1 addition & 0 deletions aws/resource_aws_api_gateway_rest_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func resourceAwsApiGatewayRestApi() *schema.Resource {
"policy": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringIsJSON,
DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs,
},
Expand Down
129 changes: 129 additions & 0 deletions aws/resource_aws_api_gateway_rest_api_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package aws

import (
"fmt"
"log"
"strconv"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/apigateway"
"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"
)

func resourceAwsApiGatewayRestApiPolicy() *schema.Resource {
return &schema.Resource{
Create: resourceAwsApiGatewayRestApiPolicyPut,
Read: resourceAwsApiGatewayRestApiPolicyRead,
Update: resourceAwsApiGatewayRestApiPolicyPut,
Delete: resourceAwsApiGatewayRestApiPolicyDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"rest_api_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"policy": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringIsJSON,
DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs,
},
},
}
}

func resourceAwsApiGatewayRestApiPolicyPut(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).apigatewayconn

restApiId := d.Get("rest_api_id").(string)
log.Printf("[DEBUG] Setting API Gateway REST API Policy: %s", restApiId)

operations := make([]*apigateway.PatchOperation, 0)

operations = append(operations, &apigateway.PatchOperation{
Op: aws.String(apigateway.OpReplace),
Path: aws.String("/policy"),
Value: aws.String(d.Get("policy").(string)),
})

res, err := conn.UpdateRestApi(&apigateway.UpdateRestApiInput{
RestApiId: aws.String(restApiId),
PatchOperations: operations,
})

if err != nil {
return fmt.Errorf("error setting API Gateway REST API Policy %w", err)
}

log.Printf("[DEBUG] API Gateway REST API Policy Set: %s", restApiId)

d.SetId(aws.StringValue(res.Id))

return resourceAwsApiGatewayRestApiPolicyRead(d, meta)
}

func resourceAwsApiGatewayRestApiPolicyRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).apigatewayconn

log.Printf("[DEBUG] Reading API Gateway REST API Policy %s", d.Id())

api, err := conn.GetRestApi(&apigateway.GetRestApiInput{
RestApiId: aws.String(d.Id()),
})
if isAWSErr(err, apigateway.ErrCodeNotFoundException, "") {
log.Printf("[WARN] API Gateway REST API Policy (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}
if err != nil {
return fmt.Errorf("error reading API Gateway REST API Policy (%s): %w", d.Id(), err)
}

normalizedPolicy, err := structure.NormalizeJsonString(`"` + aws.StringValue(api.Policy) + `"`)
if err != nil {
return fmt.Errorf("error normalizing API Gateway REST API policy JSON: %w", err)
}
policy, err := strconv.Unquote(normalizedPolicy)
if err != nil {
return fmt.Errorf("error unescaping API Gateway REST API policy: %w", err)
}
d.Set("policy", policy)
d.Set("rest_api_id", api.Id)

return nil
}

func resourceAwsApiGatewayRestApiPolicyDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).apigatewayconn

restApiId := d.Get("rest_api_id").(string)
log.Printf("[DEBUG] Deleting API Gateway REST API Policy: %s", restApiId)

operations := make([]*apigateway.PatchOperation, 0)

operations = append(operations, &apigateway.PatchOperation{
Op: aws.String(apigateway.OpReplace),
Path: aws.String("/policy"),
Value: aws.String(""),
})

_, err := conn.UpdateRestApi(&apigateway.UpdateRestApiInput{
RestApiId: aws.String(restApiId),
PatchOperations: operations,
})

if err != nil {
return fmt.Errorf("error deleting API Gateway REST API policy: %w", err)
}

log.Printf("[DEBUG] API Gateway REST API Policy Deleted: %s", restApiId)

return nil
}
218 changes: 218 additions & 0 deletions aws/resource_aws_api_gateway_rest_api_policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package aws

import (
"fmt"
"regexp"
"strconv"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/apigateway"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccAWSAPIGatewayRestApiPolicy_basic(t *testing.T) {
var v apigateway.RestApi
resourceName := "aws_api_gateway_rest_api_policy.test"
rName := acctest.RandomWithPrefix("tf-acc-test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSAPIGatewayRestApiPolicyDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSAPIGatewayRestApiPolicyConfig(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayRestApiPolicyExists(resourceName, &v),
resource.TestMatchResourceAttr(resourceName, "policy", regexp.MustCompile(`"Action":"execute-api:Invoke".+`)),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccAWSAPIGatewayRestApiPolicyConfigUpdated(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayRestApiPolicyExists(resourceName, &v),
resource.TestMatchResourceAttr(resourceName, "policy", regexp.MustCompile(`"aws:SourceIp":"123.123.123.123/32".+`))),
},
},
})
}

func TestAccAWSAPIGatewayRestApiPolicy_disappears(t *testing.T) {
var v apigateway.RestApi
resourceName := "aws_api_gateway_rest_api_policy.test"
rName := acctest.RandomWithPrefix("tf-acc-test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSAPIGatewayRestApiPolicyDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSAPIGatewayRestApiPolicyConfig(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayRestApiPolicyExists(resourceName, &v),
testAccCheckResourceDisappears(testAccProvider, resourceAwsApiGatewayRestApiPolicy(), resourceName),
),
ExpectNonEmptyPlan: true,
},
},
})
}

func TestAccAWSAPIGatewayRestApiPolicy_disappears_restApi(t *testing.T) {
var v apigateway.RestApi
resourceName := "aws_api_gateway_rest_api_policy.test"
rName := acctest.RandomWithPrefix("tf-acc-test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSAPIGatewayRestApiPolicyDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSAPIGatewayRestApiPolicyConfig(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayRestApiPolicyExists(resourceName, &v),
testAccCheckResourceDisappears(testAccProvider, resourceAwsApiGatewayRestApi(), "aws_api_gateway_rest_api.test"),
),
ExpectNonEmptyPlan: true,
},
},
})
}

func testAccCheckAWSAPIGatewayRestApiPolicyExists(n string, res *apigateway.RestApi) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}

if rs.Primary.ID == "" {
return fmt.Errorf("No API Gateway ID is set")
}

conn := testAccProvider.Meta().(*AWSClient).apigatewayconn

req := &apigateway.GetRestApiInput{
RestApiId: aws.String(rs.Primary.ID),
}
describe, err := conn.GetRestApi(req)
if err != nil {
return err
}

normalizedPolicy, err := structure.NormalizeJsonString(`"` + aws.StringValue(describe.Policy) + `"`)
if err != nil {
return fmt.Errorf("error normalizing API Gateway REST API policy JSON: %w", err)
}
policy, err := strconv.Unquote(normalizedPolicy)
if err != nil {
return fmt.Errorf("error unescaping API Gateway REST API policy: %w", err)
}

if aws.StringValue(describe.Id) != rs.Primary.ID &&
policy != rs.Primary.Attributes["policy"] {
return fmt.Errorf("API Gateway REST API Policy not found")
}

*res = *describe

return nil
}
}

func testAccCheckAWSAPIGatewayRestApiPolicyDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).apigatewayconn

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_api_gateway_rest_api_policy" {
continue
}

req := &apigateway.GetRestApisInput{}
describe, err := conn.GetRestApis(req)

if err == nil {
if len(describe.Items) != 0 &&
aws.StringValue(describe.Items[0].Id) == rs.Primary.ID &&
aws.StringValue(describe.Items[0].Policy) == "" {
return fmt.Errorf("API Gateway REST API Policy still exists")
}
}

return err
}

return nil
}

func testAccAWSAPIGatewayRestApiPolicyConfig(rName string) string {
return fmt.Sprintf(`
resource "aws_api_gateway_rest_api" "test" {
name = %[1]q
}
resource "aws_api_gateway_rest_api_policy" "test" {
rest_api_id = aws_api_gateway_rest_api.test.id
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "execute-api:Invoke",
"Resource": "${aws_api_gateway_rest_api.test.arn}"
}
]
}
EOF
}
`, rName)
}

func testAccAWSAPIGatewayRestApiPolicyConfigUpdated(rName string) string {
return fmt.Sprintf(`
resource "aws_api_gateway_rest_api" "test" {
name = %[1]q
}
resource "aws_api_gateway_rest_api_policy" "test" {
rest_api_id = aws_api_gateway_rest_api.test.id
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "execute-api:Invoke",
"Resource": "${aws_api_gateway_rest_api.test.arn}",
"Condition": {
"IpAddress": {
"aws:SourceIp": "123.123.123.123/32"
}
}
}
]
}
EOF
}
`, rName)
}
Loading

0 comments on commit f2904b2

Please sign in to comment.