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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

r/aws_fms_policy: Added policy_option config block for FMS policy #25362

Merged
merged 15 commits into from
Jul 13, 2023
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/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
Loading