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

data-source/aws_iam_policy_document: Add functionality to merge multiple policy documents #12055

Merged
merged 14 commits into from
Feb 10, 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
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