Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

apigateway/rest_api: Fix diffs from equivalent policies #22115

Merged
merged 6 commits into from
Dec 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changelog/22115.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:bug
resource/aws_api_gateway_rest_api_policy: Fix erroneous diffs in `policy` when no changes made or policies are equivalent
```

```release-note:bug
resource/aws_api_gateway_rest_api: Fix erroneous diffs in `policy` when no changes made or policies are equivalent
```
59 changes: 44 additions & 15 deletions internal/service/apigateway/rest_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/apigateway"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
awspolicy "github.com/hashicorp/awspolicyequivalence"
"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"
Expand Down Expand Up @@ -54,6 +55,10 @@ func ResourceRestAPI() *schema.Resource {
Computed: true,
ValidateFunc: validation.StringIsJSON,
DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs,
StateFunc: func(v interface{}) string {
json, _ := structure.NormalizeJsonString(v)
return json
},
},

"binary_media_types": {
Expand Down Expand Up @@ -176,7 +181,13 @@ func resourceRestAPICreate(d *schema.ResourceData, meta interface{}) error {
}

if v, ok := d.GetOk("policy"); ok {
params.Policy = aws.String(v.(string))
policy, err := structure.NormalizeJsonString(v.(string))

if err != nil {
return fmt.Errorf("policy (%s) is invalid JSON: %w", policy, err)
}

params.Policy = aws.String(policy)
}

if len(tags) > 0 {
Expand Down Expand Up @@ -308,12 +319,16 @@ func resourceRestAPICreate(d *schema.ResourceData, meta interface{}) error {
})
}

if v, ok := d.GetOk("policy"); ok && v.(string) != aws.StringValue(output.Policy) {
updateInput.PatchOperations = append(updateInput.PatchOperations, &apigateway.PatchOperation{
Op: aws.String(apigateway.OpReplace),
Path: aws.String("/policy"),
Value: aws.String(v.(string)),
})
if v, ok := d.GetOk("policy"); ok {
if equivalent, err := awspolicy.PoliciesAreEquivalent(v.(string), aws.StringValue(output.Policy)); err != nil || !equivalent {
ewbankkit marked this conversation as resolved.
Show resolved Hide resolved
policy, _ := structure.NormalizeJsonString(v.(string)) // validation covers error

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

if len(updateInput.PatchOperations) > 0 {
Expand Down Expand Up @@ -378,11 +393,19 @@ func resourceRestAPIRead(d *schema.ResourceData, meta interface{}) error {
if err != nil {
return fmt.Errorf("error normalizing policy JSON: %w", err)
}

policy, err := strconv.Unquote(normalized_policy)
if err != nil {
return fmt.Errorf("error unescaping policy: %s", err)
}
d.Set("policy", policy)

policyToSet, err := verify.SecondJSONUnlessEquivalent(d.Get("policy").(string), policy)

if err != nil {
return fmt.Errorf("while setting policy (%s), encountered: %w", policyToSet, err)
}

d.Set("policy", policyToSet)

d.Set("binary_media_types", api.BinaryMediaTypes)

Expand Down Expand Up @@ -467,10 +490,12 @@ func resourceRestAPIUpdateOperations(d *schema.ResourceData) []*apigateway.Patch
}

if d.HasChange("policy") {
policy, _ := structure.NormalizeJsonString(d.Get("policy").(string)) // validation covers error

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

Expand Down Expand Up @@ -675,12 +700,16 @@ func resourceRestAPIUpdate(d *schema.ResourceData, meta interface{}) error {
})
}

if v, ok := d.GetOk("policy"); ok && v.(string) != aws.StringValue(output.Policy) {
updateInput.PatchOperations = append(updateInput.PatchOperations, &apigateway.PatchOperation{
Op: aws.String(apigateway.OpReplace),
Path: aws.String("/policy"),
Value: aws.String(v.(string)),
})
if v, ok := d.GetOk("policy"); ok {
if equivalent, err := awspolicy.PoliciesAreEquivalent(v.(string), aws.StringValue(output.Policy)); err != nil || !equivalent {
ewbankkit marked this conversation as resolved.
Show resolved Hide resolved
policy, _ := structure.NormalizeJsonString(v.(string)) // validation covers error

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

if len(updateInput.PatchOperations) > 0 {
Expand Down
23 changes: 21 additions & 2 deletions internal/service/apigateway/rest_api_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ func ResourceRestAPIPolicy() *schema.Resource {
Required: true,
ValidateFunc: validation.StringIsJSON,
DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs,
StateFunc: func(v interface{}) string {
json, _ := structure.NormalizeJsonString(v)
return json
},
},
},
}
Expand All @@ -50,10 +54,16 @@ func resourceRestAPIPolicyPut(d *schema.ResourceData, meta interface{}) error {

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

policy, err := structure.NormalizeJsonString(d.Get("policy").(string))

if err != nil {
return fmt.Errorf("policy (%s) is invalid JSON: %w", policy, err)
}

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

res, err := conn.UpdateRestApi(&apigateway.UpdateRestApiInput{
Expand Down Expand Up @@ -93,11 +103,20 @@ func resourceRestAPIPolicyRead(d *schema.ResourceData, meta interface{}) error {
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)

policyToSet, err := verify.SecondJSONUnlessEquivalent(d.Get("policy").(string), policy)

if err != nil {
return fmt.Errorf("while setting policy (%s), encountered: %w", policyToSet, err)
}

d.Set("policy", policyToSet)

d.Set("rest_api_id", api.Id)

return nil
Expand Down
65 changes: 29 additions & 36 deletions internal/service/apigateway/rest_api_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ func TestAccAPIGatewayRestAPIPolicy_basic(t *testing.T) {
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"policy"},
},
{
Config: testAccRestAPIPolicyUpdatedConfig(rName),
Expand Down Expand Up @@ -171,21 +172,17 @@ resource "aws_api_gateway_rest_api" "test" {
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
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Deny"
Principal = {
AWS = "*"
}
Action = "execute-api:Invoke"
Resource = aws_api_gateway_rest_api.test.arn
}]
})
}
`, rName)
}
Expand All @@ -199,26 +196,22 @@ resource "aws_api_gateway_rest_api" "test" {
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"
policy = jsonencode({
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