Skip to content

Commit

Permalink
Merge pull request #12055 from aborrello/master
Browse files Browse the repository at this point in the history
data-source/aws_iam_policy_document: Add functionality to merge multiple policy documents
  • Loading branch information
YakDriver committed Feb 10, 2021
2 parents 97603ec + 0935bb5 commit a8825cf
Show file tree
Hide file tree
Showing 4 changed files with 566 additions and 170 deletions.
3 changes: 3 additions & 0 deletions .changelog/12055.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
data-source/aws_iam_policy_document: Support merging policy documents by adding `source_policy_documents` and `override_policy_documents` arguments
```
113 changes: 83 additions & 30 deletions aws/data_source_aws_iam_policy_document.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,19 @@ func dataSourceAwsIamPolicyDocument() *schema.Resource {
Read: dataSourceAwsIamPolicyDocumentRead,

Schema: map[string]*schema.Schema{
"json": {
Type: schema.TypeString,
Computed: true,
},
"override_json": {
Type: schema.TypeString,
Optional: true,
},
"override_policy_documents": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"policy_id": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -39,27 +48,17 @@ func dataSourceAwsIamPolicyDocument() *schema.Resource {
Type: schema.TypeString,
Optional: true,
},
"source_policy_documents": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"statement": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"sid": {
Type: schema.TypeString,
Optional: true,
},
"effect": {
Type: schema.TypeString,
Optional: true,
Default: "Allow",
ValidateFunc: validation.StringInSlice([]string{"Allow", "Deny"}, false),
},
"actions": setOfString,
"not_actions": setOfString,
"resources": setOfString,
"not_resources": setOfString,
"principals": dataSourceAwsIamPolicyPrincipalSchema(),
"not_principals": dataSourceAwsIamPolicyPrincipalSchema(),
"actions": setOfString,
"condition": {
Type: schema.TypeSet,
Optional: true,
Expand All @@ -69,20 +68,35 @@ func dataSourceAwsIamPolicyDocument() *schema.Resource {
Type: schema.TypeString,
Required: true,
},
"variable": {
Type: schema.TypeString,
Required: true,
},
"values": {
Type: schema.TypeSet,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"variable": {
Type: schema.TypeString,
Required: true,
},
},
},
},
"effect": {
Type: schema.TypeString,
Optional: true,
Default: "Allow",
ValidateFunc: validation.StringInSlice([]string{"Allow", "Deny"}, false),
},
"not_actions": setOfString,
"not_principals": dataSourceAwsIamPolicyPrincipalSchema(),
"not_resources": setOfString,
"principals": dataSourceAwsIamPolicyPrincipalSchema(),
"resources": setOfString,
"sid": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
Expand All @@ -95,24 +109,50 @@ func dataSourceAwsIamPolicyDocument() *schema.Resource {
"2012-10-17",
}, false),
},
"json": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceAwsIamPolicyDocumentRead(d *schema.ResourceData, meta interface{}) error {
mergedDoc := &IAMPolicyDoc{}

// populate mergedDoc directly with any source_json
if sourceJSON, hasSourceJSON := d.GetOk("source_json"); hasSourceJSON {
if err := json.Unmarshal([]byte(sourceJSON.(string)), mergedDoc); err != nil {
if v, ok := d.GetOk("source_json"); ok {
if err := json.Unmarshal([]byte(v.(string)), mergedDoc); err != nil {
return err
}
}

if v, ok := d.GetOk("source_policy_documents"); ok && len(v.([]interface{})) > 0 {
// generate sid map to assure there are no duplicates in source jsons
sidMap := make(map[string]struct{})
for _, stmt := range mergedDoc.Statements {
if stmt.Sid != "" {
sidMap[stmt.Sid] = struct{}{}
}
}

// merge sourceDocs in order specified
for sourceJSONIndex, sourceJSON := range v.([]interface{}) {
sourceDoc := &IAMPolicyDoc{}
if err := json.Unmarshal([]byte(sourceJSON.(string)), sourceDoc); err != nil {
return err
}

// assure all statements in sourceDoc are unique before merging
for stmtIndex, stmt := range sourceDoc.Statements {
if stmt.Sid != "" {
if _, sidExists := sidMap[stmt.Sid]; sidExists {
return fmt.Errorf("duplicate Sid (%s) in source_policy_documents (item %d; statement %d). Remove the Sid or ensure Sids are unique.", stmt.Sid, sourceJSONIndex, stmtIndex)
}
sidMap[stmt.Sid] = struct{}{}
}
}

mergedDoc.Merge(sourceDoc)
}

}

// process the current document
doc := &IAMPolicyDoc{
Version: d.Get("version").(string),
Expand All @@ -135,7 +175,7 @@ func dataSourceAwsIamPolicyDocumentRead(d *schema.ResourceData, meta interface{}

if sid, ok := cfgStmt["sid"]; ok {
if _, ok := sidMap[sid.(string)]; ok {
return fmt.Errorf("Found duplicate sid (%s). Either remove the sid or ensure the sid is unique across all statements.", sid.(string))
return fmt.Errorf("duplicate Sid (%s). Remove the Sid or ensure the Sid is unique.", sid.(string))
}
stmt.Sid = sid.(string)
if len(stmt.Sid) > 0 {
Expand Down Expand Up @@ -203,10 +243,23 @@ func dataSourceAwsIamPolicyDocumentRead(d *schema.ResourceData, meta interface{}
// merge our current document into mergedDoc
mergedDoc.Merge(doc)

// merge override_policy_documents policies into mergedDoc in order specified
if v, ok := d.GetOk("override_policy_documents"); ok && len(v.([]interface{})) > 0 {
for _, overrideJSON := range v.([]interface{}) {
overrideDoc := &IAMPolicyDoc{}
if err := json.Unmarshal([]byte(overrideJSON.(string)), overrideDoc); err != nil {
return err
}

mergedDoc.Merge(overrideDoc)
}

}

// merge in override_json
if overrideJSON, hasOverrideJSON := d.GetOk("override_json"); hasOverrideJSON {
if v, ok := d.GetOk("override_json"); ok {
overrideDoc := &IAMPolicyDoc{}
if err := json.Unmarshal([]byte(overrideJSON.(string)), overrideDoc); err != nil {
if err := json.Unmarshal([]byte(v.(string)), overrideDoc); err != nil {
return err
}

Expand Down
Loading

0 comments on commit a8825cf

Please sign in to comment.