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

Issue #6072 datasource/aws_iam_policy: lookup by name #6084

Merged
merged 10 commits into from
Apr 22, 2021
3 changes: 3 additions & 0 deletions .changelog/6084.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
data-source/aws_iam_policy: Add support for lookup by `arn`, `name`, and/or `path_prefix`
```
91 changes: 67 additions & 24 deletions aws/data_source_aws_iam_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package aws
import (
"fmt"
"net/url"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/finder"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)
Expand All @@ -20,23 +22,29 @@ func dataSourceAwsIAMPolicy() *schema.Resource {

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validateArn,
},
"name": {
"description": {
Type: schema.TypeString,
Computed: true,
},
"policy": {
"name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
},
"path": {
Type: schema.TypeString,
Computed: true,
},

"description": {
"path_prefix": {
Type: schema.TypeString,
Optional: true,
},
"policy": {
Type: schema.TypeString,
Computed: true,
},
Expand All @@ -54,16 +62,15 @@ func dataSourceAwsIAMPolicyRead(d *schema.ResourceData, meta interface{}) error
ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig

arn := d.Get("arn").(string)
name := d.Get("name").(string)
pathPrefix := d.Get("path_prefix").(string)

input := &iam.GetPolicyInput{
PolicyArn: aws.String(arn),
}
var results []*iam.Policy

// Handle IAM eventual consistency
var output *iam.GetPolicyOutput
err := resource.Retry(waiter.PropagationTimeout, func() *resource.RetryError {
var err error
output, err = conn.GetPolicy(input)
results, err = finder.Policies(conn, arn, name, pathPrefix)

if tfawserr.ErrCodeEquals(err, iam.ErrCodeNoSuchEntityException) {
return resource.RetryableError(err)
Expand All @@ -77,23 +84,27 @@ func dataSourceAwsIAMPolicyRead(d *schema.ResourceData, meta interface{}) error
})

if tfresource.TimedOut(err) {
output, err = conn.GetPolicy(input)
results, err = finder.Policies(conn, arn, name, pathPrefix)
}

if err != nil {
return fmt.Errorf("error reading IAM policy %s: %w", arn, err)
return fmt.Errorf("error reading IAM policy (%s): %w", PolicySearchDetails(arn, name, pathPrefix), err)
}

if output == nil || output.Policy == nil {
return fmt.Errorf("error reading IAM policy %s: empty output", arn)
if len(results) == 0 {
return fmt.Errorf("no IAM policy found matching criteria (%s); try different search", PolicySearchDetails(arn, name, pathPrefix))
}

policy := output.Policy
if len(results) > 1 {
return fmt.Errorf("multiple IAM policies found matching criteria (%s); try different search", PolicySearchDetails(arn, name, pathPrefix))
}

d.SetId(aws.StringValue(policy.Arn))
policy := results[0]
policyArn := aws.StringValue(policy.Arn)

d.Set("arn", policy.Arn)
d.Set("description", policy.Description)
d.SetId(policyArn)

d.Set("arn", policyArn)
d.Set("name", policy.PolicyName)
d.Set("path", policy.Path)
d.Set("policy_id", policy.PolicyId)
Expand All @@ -102,10 +113,26 @@ func dataSourceAwsIAMPolicyRead(d *schema.ResourceData, meta interface{}) error
return fmt.Errorf("error setting tags: %w", err)
}

// Retrieve policy
// Retrieve policy description
policyInput := &iam.GetPolicyInput{
PolicyArn: policy.Arn,
}

policyOutput, err := conn.GetPolicy(policyInput)

if err != nil {
return fmt.Errorf("error reading IAM policy (%s): %w", policyArn, err)
}

if policyOutput == nil || policyOutput.Policy == nil {
return fmt.Errorf("error reading IAM policy (%s): empty output", policyArn)
}

d.Set("description", policyOutput.Policy.Description)

// Retrieve policy
policyVersionInput := &iam.GetPolicyVersionInput{
PolicyArn: aws.String(arn),
PolicyArn: policy.Arn,
VersionId: policy.DefaultVersionId,
}

Expand All @@ -131,11 +158,11 @@ func dataSourceAwsIAMPolicyRead(d *schema.ResourceData, meta interface{}) error
}

if err != nil {
return fmt.Errorf("error reading IAM Policy (%s) version: %w", arn, err)
return fmt.Errorf("error reading IAM Policy (%s) version: %w", policyArn, err)
}

if policyVersionOutput == nil || policyVersionOutput.PolicyVersion == nil {
return fmt.Errorf("error reading IAM Policy (%s) version: empty output", arn)
return fmt.Errorf("error reading IAM Policy (%s) version: empty output", policyArn)
}

policyVersion := policyVersionOutput.PolicyVersion
Expand All @@ -144,11 +171,27 @@ func dataSourceAwsIAMPolicyRead(d *schema.ResourceData, meta interface{}) error
if policyVersion != nil {
policyDocument, err = url.QueryUnescape(aws.StringValue(policyVersion.Document))
if err != nil {
return fmt.Errorf("error parsing IAM Policy (%s) document: %w", arn, err)
return fmt.Errorf("error parsing IAM Policy (%s) document: %w", policyArn, err)
}
}

d.Set("policy", policyDocument)

return nil
}

// PolicySearchDetails returns the configured search criteria as a printable string
func PolicySearchDetails(arn, name, pathPrefix string) string {
var policyDetails []string
if arn != "" {
policyDetails = append(policyDetails, fmt.Sprintf("ARN: %s", arn))
}
if name != "" {
policyDetails = append(policyDetails, fmt.Sprintf("Name: %s", name))
}
if pathPrefix != "" {
policyDetails = append(policyDetails, fmt.Sprintf("PathPrefix: %s", pathPrefix))
}

return strings.Join(policyDetails, ", ")
}
Loading