Skip to content

Commit

Permalink
Merge pull request #25362 from daftkid/f-add_fms_policy_option
Browse files Browse the repository at this point in the history
r/aws_fms_policy: Added policy_option config block for FMS policy
  • Loading branch information
johnsonaj committed Jul 13, 2023
2 parents 9197fe5 + 52445a7 commit b24adcc
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .changelog/25362.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_fms_policy: Add `policy_option` attribute for `security_service_policy_data` block
```
1 change: 1 addition & 0 deletions internal/service/fms/fms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func TestAccFMS_serial(t *testing.T) {
"cloudfrontDistribution": testAccPolicy_cloudFrontDistribution,
"includeMap": testAccPolicy_includeMap,
"update": testAccPolicy_update,
"policyOption": testAccPolicy_policyOption,
"resourceTags": testAccPolicy_resourceTags,
"tags": testAccPolicy_tags,
},
Expand Down
140 changes: 139 additions & 1 deletion internal/service/fms/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import (
"github.com/hashicorp/terraform-provider-aws/names"
)

const (
ResNamePolicy = "Policy"
)

// @SDKResource("aws_fms_policy", name="Policy")
// @Tags(identifierAttribute="arn")
func ResourcePolicy() *schema.Resource {
Expand Down Expand Up @@ -151,6 +155,43 @@ func ResourcePolicy() *schema.Resource {
Optional: true,
DiffSuppressFunc: verify.SuppressEquivalentJSONDiffs,
},
"policy_option": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"network_firewall_policy": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"firewall_deployment_model": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice(fms.FirewallDeploymentModel_Values(), false),
},
},
},
},
"third_party_firewall_policy": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"firewall_deployment_model": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice(fms.FirewallDeploymentModel_Values(), false),
},
},
},
},
},
},
},
"type": {
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -222,9 +263,10 @@ func resourcePolicyRead(ctx context.Context, d *schema.ResourceData, meta interf
if err := d.Set("resource_type_list", policy.ResourceTypeList); err != nil {
sdkdiag.AppendErrorf(diags, "setting resource_type_list: %s", err)
}
securityServicePolicy := []map[string]string{{
securityServicePolicy := []map[string]interface{}{{
"type": aws.StringValue(policy.SecurityServicePolicyData.Type),
"managed_service_data": aws.StringValue(policy.SecurityServicePolicyData.ManagedServiceData),
"policy_option": flattenPolicyOption(policy.SecurityServicePolicyData.PolicyOption),
}}
if err := d.Set("security_service_policy_data", securityServicePolicy); err != nil {
sdkdiag.AppendErrorf(diags, "setting security_service_policy_data: %s", err)
Expand Down Expand Up @@ -332,9 +374,59 @@ func resourcePolicyExpandPolicy(d *schema.ResourceData) *fms.Policy {
Type: aws.String(securityServicePolicy["type"].(string)),
}

if v, ok := securityServicePolicy["policy_option"].([]interface{}); ok && len(v) > 0 && v[0] != nil {
fmsPolicy.SecurityServicePolicyData.PolicyOption = expandPolicyOption(v[0].(map[string]interface{}))
}

return fmsPolicy
}

func expandPolicyOption(tfMap map[string]interface{}) *fms.PolicyOption {
if tfMap == nil {
return nil
}

apiObject := &fms.PolicyOption{}

if v, ok := tfMap["network_firewall_policy"].([]interface{}); ok && len(v) > 0 && v[0] != nil {
apiObject.NetworkFirewallPolicy = expandPolicyOptionNetworkFirewall(v[0].(map[string]interface{}))
}

if v, ok := tfMap["third_party_firewall_policy"].([]interface{}); ok && len(v) > 0 && v[0] != nil {
apiObject.ThirdPartyFirewallPolicy = expandPolicyOptionThirdPartyFirewall(v[0].(map[string]interface{}))
}

return apiObject
}

func expandPolicyOptionNetworkFirewall(tfMap map[string]interface{}) *fms.NetworkFirewallPolicy {
if tfMap == nil {
return nil
}

apiObject := &fms.NetworkFirewallPolicy{}

if v, ok := tfMap["firewall_deployment_model"].(string); ok {
apiObject.FirewallDeploymentModel = aws.String(v)
}

return apiObject
}

func expandPolicyOptionThirdPartyFirewall(tfMap map[string]interface{}) *fms.ThirdPartyFirewallPolicy {
if tfMap == nil {
return nil
}

apiObject := &fms.ThirdPartyFirewallPolicy{}

if v, ok := tfMap["firewall_deployment_model"].(string); ok {
apiObject.FirewallDeploymentModel = aws.String(v)
}

return apiObject
}

func expandPolicyMap(set []interface{}) map[string][]*string {
fmsPolicyMap := map[string][]*string{}
if len(set) > 0 {
Expand Down Expand Up @@ -375,6 +467,52 @@ func flattenPolicyMap(fmsPolicyMap map[string][]*string) []interface{} {
return []interface{}{flatPolicyMap}
}

func flattenPolicyOption(fmsPolicyOption *fms.PolicyOption) []interface{} {
if fmsPolicyOption == nil {
return nil
}

tfMap := map[string]interface{}{}

if v := fmsPolicyOption.NetworkFirewallPolicy; v != nil {
tfMap["network_firewall_policy"] = flattenPolicyOptionNetworkFirewall(fmsPolicyOption.NetworkFirewallPolicy)
}

if v := fmsPolicyOption.ThirdPartyFirewallPolicy; v != nil {
tfMap["third_party_firewall_policy"] = flattenPolicyOptionThirdPartyFirewall(fmsPolicyOption.ThirdPartyFirewallPolicy)
}

return []interface{}{tfMap}
}

func flattenPolicyOptionNetworkFirewall(fmsNetworkFirewallPolicy *fms.NetworkFirewallPolicy) []interface{} {
if fmsNetworkFirewallPolicy == nil {
return nil
}

tfMap := map[string]interface{}{}

if v := fmsNetworkFirewallPolicy.FirewallDeploymentModel; v != nil {
tfMap["firewall_deployment_model"] = aws.StringValue(v)
}

return []interface{}{tfMap}
}

func flattenPolicyOptionThirdPartyFirewall(fmsThirdPartyFirewallPolicy *fms.ThirdPartyFirewallPolicy) []interface{} {
if fmsThirdPartyFirewallPolicy == nil {
return nil
}

tfMap := map[string]interface{}{}

if v := fmsThirdPartyFirewallPolicy.FirewallDeploymentModel; v != nil {
tfMap["firewall_deployment_model"] = aws.StringValue(v)
}

return []interface{}{tfMap}
}

func flattenResourceTags(resourceTags []*fms.ResourceTag) map[string]interface{} {
resTags := map[string]interface{}{}

Expand Down
78 changes: 78 additions & 0 deletions internal/service/fms/policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,47 @@ func testAccPolicy_update(t *testing.T) {
})
}

func testAccPolicy_policyOption(t *testing.T) {
ctx := acctest.Context(t)
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_fms_policy.test"

resource.Test(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckOrganizationsEnabled(ctx, t)
acctest.PreCheckOrganizationManagementAccount(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, fms.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckPolicyDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccPolicyConfig_policyOption(rName, rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckPolicyExists(ctx, resourceName),
acctest.CheckResourceAttrRegionalARNIgnoreRegionAndAccount(resourceName, "arn", "fms", "policy/.+"),
resource.TestCheckResourceAttr(resourceName, "delete_unused_fm_managed_resources", "false"),
resource.TestCheckResourceAttr(resourceName, "name", rName),
resource.TestCheckResourceAttr(resourceName, "security_service_policy_data.#", "1"),
resource.TestCheckResourceAttr(resourceName, "security_service_policy_data.policy_option.#", "1"),
resource.TestCheckResourceAttr(resourceName, "security_service_policy_data.policy_option.0.network_firewall_policy.#", "1"),
resource.TestCheckResourceAttr(resourceName, "security_service_policy_data.policy_option.0.network_firewall_policy.0.firewall_deployment_model", "CENTRALIZED"),
resource.TestCheckResourceAttr(resourceName, "security_service_policy_data.policy_option.0.third_party_firewall_policy.#", "1"),
resource.TestCheckResourceAttr(resourceName, "security_service_policy_data.policy_option.0.third_party_firewall_policy.0.firewall_deployment_model", "DISTRIBUTED"),
resource.TestCheckResourceAttr(resourceName, "tags.%", "0"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"policy_update_token", "delete_all_policy_resources"},
},
},
})
}

func testAccPolicy_resourceTags(t *testing.T) {
ctx := acctest.Context(t)
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
Expand Down Expand Up @@ -310,6 +351,43 @@ resource "aws_wafregional_rule_group" "test" {
`, policyName, ruleGroupName))
}

func testAccPolicyConfig_policyOption(policyName, ruleGroupName string) string {
return acctest.ConfigCompose(testAccPolicyConfig_baseOrgMgmtAccount, fmt.Sprintf(`
resource "aws_fms_policy" "test" {
exclude_resource_tags = false
name = %[1]q
remediation_enabled = false
resource_type_list = ["AWS::ElasticLoadBalancingV2::LoadBalancer"]
exclude_map {
account = [data.aws_caller_identity.current.account_id]
}
security_service_policy_data {
type = "WAF"
managed_service_data = "{\"type\": \"WAF\", \"ruleGroups\": [{\"id\":\"${aws_wafregional_rule_group.test.id}\", \"overrideAction\" : {\"type\": \"COUNT\"}}],\"defaultAction\": {\"type\": \"BLOCK\"}, \"overrideCustomerWebACLAssociation\": false}"
policy_option {
network_firewall_policy {
firewall_deployment_model = "CENTRALIZED"
}
third_party_firewall_policy {
firewall_deployment_model = "DISTRIBUTED"
}
}
}
depends_on = [aws_fms_admin_account.test]
}
resource "aws_wafregional_rule_group" "test" {
metric_name = "MyTest"
name = %[2]q
}
`, policyName, ruleGroupName))
}

func testAccPolicyConfig_cloudFrontDistribution(rName string) string {
return acctest.ConfigCompose(testAccPolicyConfig_baseOrgMgmtAccount, fmt.Sprintf(`
resource "aws_fms_policy" "test" {
Expand Down
2 changes: 1 addition & 1 deletion internal/service/ssm/sweep.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func sweepResourcePatchBaselines(region string) error {
}
}

if err := sweep.SweepOrchestrator(ctx, sweepables);err != nil {
if err := sweep.SweepOrchestrator(ctx, sweepables); err != nil {
errs = multierror.Append(errs, fmt.Errorf("sweeping Patch Baselines for %s: %w", region, err))
}

Expand Down
18 changes: 17 additions & 1 deletion website/docs/r/fms_policy.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ description: |-

Provides a resource to create an AWS Firewall Manager policy. You need to be using AWS organizations and have enabled the Firewall Manager administrator account.

~> **NOTE:** Due to limitations with testing, we provide it as best effort. If you find it useful, and have the ability to help test or notice issues, consider reaching out to us on [GitHub](https://github.com/hashicorp/terraform-provider-aws).

## Example Usage

```terraform
Expand Down Expand Up @@ -82,9 +84,23 @@ You can specify inclusions or exclusions, but not both. If you specify an `inclu

## `security_service_policy_data` Configuration Block

* `managed_service_data` (Optional) Details about the service that are specific to the service type, in JSON format. For service type `SHIELD_ADVANCED`, this is an empty string. Examples depending on `type` can be found in the [AWS Firewall Manager SecurityServicePolicyData API Reference](https://docs.aws.amazon.com/fms/2018-01-01/APIReference/API_SecurityServicePolicyData.html).
* `managed_service_data` - (Optional) Details about the service that are specific to the service type, in JSON format. For service type `SHIELD_ADVANCED`, this is an empty string. Examples depending on `type` can be found in the [AWS Firewall Manager SecurityServicePolicyData API Reference](https://docs.aws.amazon.com/fms/2018-01-01/APIReference/API_SecurityServicePolicyData.html).
* `policy_option` - (Optional) Contains the Network Firewall firewall policy options to configure a centralized deployment model. Documented below.
* `type` - (Required, Forces new resource) The service that the policy is using to protect the resources. For the current list of supported types, please refer to the [AWS Firewall Manager SecurityServicePolicyData API Type Reference](https://docs.aws.amazon.com/fms/2018-01-01/APIReference/API_SecurityServicePolicyData.html#fms-Type-SecurityServicePolicyData-Type).

## `policy_option` Configuration Block

* `network_firewall_policy` - (Optional) Defines the deployment model to use for the firewall policy. Documented below.
* `thirdparty_firewall_policy` - (Optional) Defines the policy options for a third-party firewall policy. Documented below.

## `network_firewall_policy` Configuration Block

* `firewall_deployment_model` - (Optional) Defines the deployment model to use for the firewall policy. To use a distributed model, remove the `policy_option` section. Valid values are `CENTRALIZED` and `DISTRIBUTED`.

## `thirdparty_firewall_policy` Configuration Block

* `firewall_deployment_model` - (Optional) Defines the deployment model to use for the third-party firewall policy. Valid values are `CENTRALIZED` and `DISTRIBUTED`.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:
Expand Down

0 comments on commit b24adcc

Please sign in to comment.