diff --git a/aws/data_source_aws_iam_policy_document.go b/aws/data_source_aws_iam_policy_document.go index 2e0c6ff2c7e..8e9ce8cc8a8 100644 --- a/aws/data_source_aws_iam_policy_document.go +++ b/aws/data_source_aws_iam_policy_document.go @@ -85,6 +85,15 @@ func dataSourceAwsIamPolicyDocument() *schema.Resource { }, }, }, + "version": { + Type: schema.TypeString, + Optional: true, + Default: "2012-10-17", + ValidateFunc: validation.StringInSlice([]string{ + "2008-10-17", + "2012-10-17", + }, false), + }, "json": { Type: schema.TypeString, Computed: true, @@ -104,9 +113,9 @@ func dataSourceAwsIamPolicyDocumentRead(d *schema.ResourceData, meta interface{} } // process the current document - doc := &IAMPolicyDoc{} - - doc.Version = "2012-10-17" + doc := &IAMPolicyDoc{ + Version: d.Get("version").(string), + } if policyID, hasPolicyID := d.GetOk("policy_id"); hasPolicyID { doc.Id = policyID.(string) @@ -141,26 +150,46 @@ func dataSourceAwsIamPolicyDocumentRead(d *schema.ResourceData, meta interface{} } if resources := cfgStmt["resources"].(*schema.Set).List(); len(resources) > 0 { - stmt.Resources = dataSourceAwsIamPolicyDocumentReplaceVarsInList( - iamPolicyDecodeConfigStringList(resources), + var err error + stmt.Resources, err = dataSourceAwsIamPolicyDocumentReplaceVarsInList( + iamPolicyDecodeConfigStringList(resources), doc.Version, ) + if err != nil { + return fmt.Errorf("error reading resources: %s", err) + } } - if resources := cfgStmt["not_resources"].(*schema.Set).List(); len(resources) > 0 { - stmt.NotResources = dataSourceAwsIamPolicyDocumentReplaceVarsInList( - iamPolicyDecodeConfigStringList(resources), + if notResources := cfgStmt["not_resources"].(*schema.Set).List(); len(notResources) > 0 { + var err error + stmt.NotResources, err = dataSourceAwsIamPolicyDocumentReplaceVarsInList( + iamPolicyDecodeConfigStringList(notResources), doc.Version, ) + if err != nil { + return fmt.Errorf("error reading not_resources: %s", err) + } } if principals := cfgStmt["principals"].(*schema.Set).List(); len(principals) > 0 { - stmt.Principals = dataSourceAwsIamPolicyDocumentMakePrincipals(principals) + var err error + stmt.Principals, err = dataSourceAwsIamPolicyDocumentMakePrincipals(principals, doc.Version) + if err != nil { + return fmt.Errorf("error reading principals: %s", err) + } } - if principals := cfgStmt["not_principals"].(*schema.Set).List(); len(principals) > 0 { - stmt.NotPrincipals = dataSourceAwsIamPolicyDocumentMakePrincipals(principals) + if notPrincipals := cfgStmt["not_principals"].(*schema.Set).List(); len(notPrincipals) > 0 { + var err error + stmt.NotPrincipals, err = dataSourceAwsIamPolicyDocumentMakePrincipals(notPrincipals, doc.Version) + if err != nil { + return fmt.Errorf("error reading not_principals: %s", err) + } } if conditions := cfgStmt["condition"].(*schema.Set).List(); len(conditions) > 0 { - stmt.Conditions = dataSourceAwsIamPolicyDocumentMakeConditions(conditions) + var err error + stmt.Conditions, err = dataSourceAwsIamPolicyDocumentMakeConditions(conditions, doc.Version) + if err != nil { + return fmt.Errorf("error reading condition: %s", err) + } } stmts[i] = stmt @@ -196,52 +225,66 @@ func dataSourceAwsIamPolicyDocumentRead(d *schema.ResourceData, meta interface{} return nil } -func dataSourceAwsIamPolicyDocumentReplaceVarsInList(in interface{}) interface{} { +func dataSourceAwsIamPolicyDocumentReplaceVarsInList(in interface{}, version string) (interface{}, error) { switch v := in.(type) { case string: - return dataSourceAwsIamPolicyDocumentVarReplacer.Replace(v) + if version == "2008-10-17" && strings.Contains(v, "&{") { + return nil, fmt.Errorf("found &{ sequence in (%s), which is not supported in document version 2008-10-17", v) + } + return dataSourceAwsIamPolicyDocumentVarReplacer.Replace(v), nil case []string: out := make([]string, len(v)) for i, item := range v { + if version == "2008-10-17" && strings.Contains(item, "&{") { + return nil, fmt.Errorf("found &{ sequence in (%s), which is not supported in document version 2008-10-17", item) + } out[i] = dataSourceAwsIamPolicyDocumentVarReplacer.Replace(item) } - return out + return out, nil default: panic("dataSourceAwsIamPolicyDocumentReplaceVarsInList: input not string nor []string") } } -func dataSourceAwsIamPolicyDocumentMakeConditions(in []interface{}) IAMPolicyStatementConditionSet { +func dataSourceAwsIamPolicyDocumentMakeConditions(in []interface{}, version string) (IAMPolicyStatementConditionSet, error) { out := make([]IAMPolicyStatementCondition, len(in)) for i, itemI := range in { + var err error item := itemI.(map[string]interface{}) out[i] = IAMPolicyStatementCondition{ Test: item["test"].(string), Variable: item["variable"].(string), - Values: dataSourceAwsIamPolicyDocumentReplaceVarsInList( - iamPolicyDecodeConfigStringList( - item["values"].(*schema.Set).List(), - ), - ), + } + out[i].Values, err = dataSourceAwsIamPolicyDocumentReplaceVarsInList( + iamPolicyDecodeConfigStringList( + item["values"].(*schema.Set).List(), + ), version, + ) + if err != nil { + return nil, fmt.Errorf("error reading values: %s", err) } } - return IAMPolicyStatementConditionSet(out) + return IAMPolicyStatementConditionSet(out), nil } -func dataSourceAwsIamPolicyDocumentMakePrincipals(in []interface{}) IAMPolicyStatementPrincipalSet { +func dataSourceAwsIamPolicyDocumentMakePrincipals(in []interface{}, version string) (IAMPolicyStatementPrincipalSet, error) { out := make([]IAMPolicyStatementPrincipal, len(in)) for i, itemI := range in { + var err error item := itemI.(map[string]interface{}) out[i] = IAMPolicyStatementPrincipal{ Type: item["type"].(string), - Identifiers: dataSourceAwsIamPolicyDocumentReplaceVarsInList( - iamPolicyDecodeConfigStringList( - item["identifiers"].(*schema.Set).List(), - ), - ), + } + out[i].Identifiers, err = dataSourceAwsIamPolicyDocumentReplaceVarsInList( + iamPolicyDecodeConfigStringList( + item["identifiers"].(*schema.Set).List(), + ), version, + ) + if err != nil { + return nil, fmt.Errorf("error reading identifiers: %s", err) } } - return IAMPolicyStatementPrincipalSet(out) + return IAMPolicyStatementPrincipalSet(out), nil } func dataSourceAwsIamPolicyPrincipalSchema() *schema.Schema { diff --git a/aws/data_source_aws_iam_policy_document_test.go b/aws/data_source_aws_iam_policy_document_test.go index f68aca699a5..c882468e1f0 100644 --- a/aws/data_source_aws_iam_policy_document_test.go +++ b/aws/data_source_aws_iam_policy_document_test.go @@ -1,12 +1,10 @@ package aws import ( - "fmt" "regexp" "testing" "github.com/hashicorp/terraform/helper/resource" - "github.com/hashicorp/terraform/terraform" ) func TestAccAWSDataSourceIAMPolicyDocument_basic(t *testing.T) { @@ -20,7 +18,7 @@ func TestAccAWSDataSourceIAMPolicyDocument_basic(t *testing.T) { { Config: testAccAWSIAMPolicyDocumentConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckStateValue("data.aws_iam_policy_document.test", "json", + resource.TestCheckResourceAttr("data.aws_iam_policy_document.test", "json", testAccAWSIAMPolicyDocumentExpectedJSON, ), ), @@ -40,7 +38,7 @@ func TestAccAWSDataSourceIAMPolicyDocument_source(t *testing.T) { { Config: testAccAWSIAMPolicyDocumentSourceConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckStateValue("data.aws_iam_policy_document.test_source", "json", + resource.TestCheckResourceAttr("data.aws_iam_policy_document.test_source", "json", testAccAWSIAMPolicyDocumentSourceExpectedJSON, ), ), @@ -48,7 +46,7 @@ func TestAccAWSDataSourceIAMPolicyDocument_source(t *testing.T) { { Config: testAccAWSIAMPolicyDocumentSourceBlankConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckStateValue("data.aws_iam_policy_document.test_source_blank", "json", + resource.TestCheckResourceAttr("data.aws_iam_policy_document.test_source_blank", "json", testAccAWSIAMPolicyDocumentSourceBlankExpectedJSON, ), ), @@ -65,7 +63,7 @@ func TestAccAWSDataSourceIAMPolicyDocument_sourceConflicting(t *testing.T) { { Config: testAccAWSIAMPolicyDocumentSourceConflictingConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckStateValue("data.aws_iam_policy_document.test_source_conflicting", "json", + resource.TestCheckResourceAttr("data.aws_iam_policy_document.test_source_conflicting", "json", testAccAWSIAMPolicyDocumentSourceConflictingExpectedJSON, ), ), @@ -82,7 +80,7 @@ func TestAccAWSDataSourceIAMPolicyDocument_override(t *testing.T) { { Config: testAccAWSIAMPolicyDocumentOverrideConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckStateValue("data.aws_iam_policy_document.test_override", "json", + resource.TestCheckResourceAttr("data.aws_iam_policy_document.test_override", "json", testAccAWSIAMPolicyDocumentOverrideExpectedJSON, ), ), @@ -99,7 +97,7 @@ func TestAccAWSDataSourceIAMPolicyDocument_noStatementMerge(t *testing.T) { { Config: testAccAWSIAMPolicyDocumentNoStatementMergeConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckStateValue("data.aws_iam_policy_document.yak_politik", "json", + resource.TestCheckResourceAttr("data.aws_iam_policy_document.yak_politik", "json", testAccAWSIAMPolicyDocumentNoStatementMergeExpectedJSON, ), ), @@ -116,7 +114,7 @@ func TestAccAWSDataSourceIAMPolicyDocument_noStatementOverride(t *testing.T) { { Config: testAccAWSIAMPolicyDocumentNoStatementOverrideConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckStateValue("data.aws_iam_policy_document.yak_politik", "json", + resource.TestCheckResourceAttr("data.aws_iam_policy_document.yak_politik", "json", testAccAWSIAMPolicyDocumentNoStatementOverrideExpectedJSON, ), ), @@ -137,7 +135,7 @@ func TestAccAWSDataSourceIAMPolicyDocument_duplicateSid(t *testing.T) { { Config: testAccAWSIAMPolicyDocumentDuplicateBlankSidConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckStateValue("data.aws_iam_policy_document.test", "json", + resource.TestCheckResourceAttr("data.aws_iam_policy_document.test", "json", testAccAWSIAMPolicyDocumentDuplicateBlankSidExpectedJSON, ), ), @@ -146,24 +144,39 @@ func TestAccAWSDataSourceIAMPolicyDocument_duplicateSid(t *testing.T) { }) } -func testAccCheckStateValue(id, name, value string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[id] - if !ok { - return fmt.Errorf("Not found: %s", id) - } - if rs.Primary.ID == "" { - return fmt.Errorf("No ID is set") - } - - v := rs.Primary.Attributes[name] - if v != value { - return fmt.Errorf( - "Value for %s is %s, not %s", name, v, value) - } - - return nil - } +func TestAccAWSDataSourceIAMPolicyDocument_Version_20081017(t *testing.T) { + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017ConversionCondition, + ExpectError: regexp.MustCompile(`found \&\{ sequence in \(.+\), which is not supported in document version 2008-10-17`), + }, + { + Config: testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017ConversionNotPrincipals, + ExpectError: regexp.MustCompile(`found \&\{ sequence in \(.+\), which is not supported in document version 2008-10-17`), + }, + { + Config: testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017ConversionNotResources, + ExpectError: regexp.MustCompile(`found \&\{ sequence in \(.+\), which is not supported in document version 2008-10-17`), + }, + { + Config: testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017ConversionPrincipal, + ExpectError: regexp.MustCompile(`found \&\{ sequence in \(.+\), which is not supported in document version 2008-10-17`), + }, + { + Config: testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017ConversionResources, + ExpectError: regexp.MustCompile(`found \&\{ sequence in \(.+\), which is not supported in document version 2008-10-17`), + }, + { + Config: testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.aws_iam_policy_document.test", "json", testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017ExpectedJSON), + ), + }, + }, + }) } var testAccAWSIAMPolicyDocumentConfig = ` @@ -702,3 +715,94 @@ var testAccAWSIAMPolicyDocumentDuplicateBlankSidExpectedJSON = `{ } ] }` + +const testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017 = ` +data "aws_iam_policy_document" "test" { + version = "2008-10-17" + statement { + actions = ["ec2:*"] + resources = ["*"] + } +} +` + +const testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017ExpectedJSON = `{ + "Version": "2008-10-17", + "Statement": [ + { + "Sid": "", + "Effect": "Allow", + "Action": "ec2:*", + "Resource": "*" + } + ] +}` + +const testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017ConversionCondition = ` +data "aws_iam_policy_document" "test" { + version = "2008-10-17" + statement { + actions = ["*"] + resources = ["*"] + + condition { + test = "StringLike" + values = [ + "home/", + "home/&{aws:username}/", + ] + variable = "s3:prefix" + } + } +} +` + +const testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017ConversionNotPrincipals = ` +data "aws_iam_policy_document" "test" { + version = "2008-10-17" + statement { + actions = ["*"] + resources = ["*"] + + not_principals { + identifiers = ["&{aws:username}"] + type = "AWS" + } + } +} +` + +const testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017ConversionNotResources = ` +data "aws_iam_policy_document" "test" { + version = "2008-10-17" + statement { + actions = ["*"] + not_resources = ["arn:aws:s3:::foo/home/&{aws:username}",] + } +} +` + +const testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017ConversionPrincipal = ` +data "aws_iam_policy_document" "test" { + version = "2008-10-17" + statement { + actions = ["*"] + resources = ["*"] + + principals { + identifiers = ["&{aws:username}"] + type = "AWS" + } + } +} +` + +const testAccAWSIAMPolicyDocumentDataSourceConfigVersion20081017ConversionResources = ` +data "aws_iam_policy_document" "test" { + version = "2008-10-17" + statement { + actions = ["*"] + resources = ["arn:aws:s3:::foo/home/&{aws:username}",] + } +} +` diff --git a/website/docs/d/iam_policy_document.html.markdown b/website/docs/d/iam_policy_document.html.markdown index 18f5b0c702e..efc2b63e01e 100644 --- a/website/docs/d/iam_policy_document.html.markdown +++ b/website/docs/d/iam_policy_document.html.markdown @@ -90,6 +90,7 @@ The following arguments are supported: Statements without an `sid` cannot be overwritten. * `statement` (Optional) - A nested configuration block (described below) configuring one *statement* to be included in the policy document. +* `version` (Optional) - IAM policy document version. Valid values: `2008-10-17`, `2012-10-17`. Defaults to `2012-10-17`. For more information, see the [AWS IAM User Guide](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_version.html). Each document configuration may have one or more `statement` blocks, which each accept the following arguments: