hashicorp / terraform-provider-aws

The AWS Provider enables Terraform to manage AWS resources.
https://registry.terraform.io/providers/hashicorp/aws
Mozilla Public License 2.0
9.65k stars 9.03k forks source link

Cannot re-enable aws_securityhub_standards_control rules without taint #20434

Open mrwacky42 opened 2 years ago

mrwacky42 commented 2 years ago

Community Note

Terraform CLI and Terraform AWS Provider Version

Terraform v0.13.7
+ provider registry.terraform.io/hashicorp/archive v2.1.0
+ provider registry.terraform.io/hashicorp/aws v3.51.0
+ provider registry.terraform.io/hashicorp/external v2.1.0
+ provider registry.terraform.io/hashicorp/null v2.1.2
+ provider registry.terraform.io/hashicorp/template v2.1.2

Affected Resource(s)

Terraform Configuration Files

data "aws_caller_identity" "current" {}
resource aws_securityhub_standards_control something {
  standards_control_arn = "arn:aws:securityhub:us-east-1:${data.aws_caller_identity.current.id}:control/cis-aws-foundations-benchmark/v/1.2.0/1.14"
  control_status        = "DISABLED"
  disabled_reason       = "We have our reasons"
}

Debug Output

N/A

Panic Output

N/A

Expected Behavior

I expect Terraform to re-enable the Security Hub control.

Actual Behavior

I cannot simply re-enable the control, because Terraform is updating the resource in place, and not null-ing out the disabled_reason. I get a response:

{
  RespMetadata: {
    StatusCode: 400,
    RequestID: "880e5c5e-0416-464d-b275-d2506c2e08e2"
  },
  Code_: "InvalidInputException",
  Message_: "DisabledReason should not be given for action other than disabling control: arn:aws:securityhub:us-east-1:12345:control/cis-aws-foundations-benchmark/v/1.2.0/1.14"
}

You can see that in the plan that looks something like this:

  # aws_securityhub_standards_control.something will be updated in-place
  ~ resource "aws_securityhub_standards_control" "something" {
        control_id                = "CIS.1.14"
      ~ control_status            = "DISABLED" -> "ENABLED"
        control_status_updated_at = "2021-08-03T21:55:34Z"
        description               = "The root account is the most privileged user in an AWS account. MFA adds an extra layer of protection on top of a user name and password. With MFA enabled, when a user signs in to an AWS website, they will be prompted for their user name and password as well as for an authentication code from their AWS MFA device. For Level 2, it is recommended that the root account be protected with a hardware MFA."
        disabled_reason           = "We check global resources in us-west-2 region only."
        id                        = "arn:aws:securityhub:us-east-1:12345:control/cis-aws-foundations-benchmark/v/1.2.0/1.14"
        related_requirements      = [
            "CIS AWS Foundations 1.14",
        ]
        remediation_url           = "https://docs.aws.amazon.com/console/securityhub/standards-cis-1.14/remediation"
        severity_rating           = "CRITICAL"
        standards_control_arn     = "arn:aws:securityhub:us-east-1:12345:control/cis-aws-foundations-benchmark/v/1.2.0/1.14"
        title                     = "Ensure hardware MFA is enabled for the \"root\" account"
    }

Steps to Reproduce

  1. terraform apply the original snippet to disable a Security Hub control

  2. Try to re-enable it with the same resource name: Example of trying to enable the control again:

    data "aws_caller_identity" "current" {}
    resource aws_securityhub_standards_control something {
    standards_control_arn = "arn:aws:securityhub:us-east-1:${data.aws_caller_identity.current.id}:control/cis-aws-foundations-benchmark/v/1.2.0/1.14"
    control_status        = "ENABLED"
    }

    (I tried also disabled_reason = null and disabled_reason = "" to no avail. The proposed plan is always only tweaking the control_status and not the disabled_reason.)

  3. terraform apply and šŸ˜¢ as noted above.

Important Factoids

terraform taint aws_securityhub_standards_control.something seems to do the trick.

References

daytonpa commented 2 years ago

I am also experiencing this while updating aws_securityhub_standards_control resources from "DISABLED" to "ENABLED". The only way I have been able to successfully apply a change is to taint the resource or destroy the stack and rebuild.

resource "aws_securityhub_standards_control" "apig_5" {
  control_status        = var.ec_apig_5 == true ? "ENABLED" : "DISABLED"
  disabled_reason       = var.ec_apig_5 == true ? null : "Disabled to comply with company policy."
  standards_control_arn = "arn:aws:securityhub:${data.aws_region.main.name}:${data.aws_caller_identity.main.account_id}:control/aws-foundational-security-best-practices/v/1.0.0/APIGateway.5"
}

Initial creation of the resource is successful regardless of a true or false variable, but the modification from false to true on previously created resources causes the following:

ā”‚ Error: error updating Security Hub Standards Control (arn:aws:securityhub:us-east-1:949728939094:control/aws-foundational-security-best-practices/v/1.0.0/APIGateway.5): InvalidInputException: DisabledReason should not be given for action other than disabling control: arn:aws:securityhub:us-east-1:949728939094:control/aws-foundational-security-best-practices/v/1.0.0/APIGateway.5
ā”‚ {
ā”‚   RespMetadata: {
ā”‚     StatusCode: 401,
ā”‚     RequestID: "7156eb70-d004-4d41-bd79-58b476a0e0c1"
ā”‚   },
ā”‚   Code_: "InvalidInputException",
ā”‚   Message_: "DisabledReason should not be given for action other than disabling control: arn:aws:securityhub:us-east-1:949728939094:control/aws-foundational-security-best-practices/v/1.0.0/APIGateway.5"
ā”‚ }
ā”‚ 
ā”‚   with aws_securityhub_control.aws_securityhub_standards_control.apig_5,
ā”‚   on ./main.tf line 38, in resource "aws_securityhub_standards_control" "apig_5":
ā”‚   38: resource "aws_securityhub_standards_control" "apig_5" {
sakojun commented 1 year ago

I have confirmed that this can be avoided by making such a statement, but this is a hacky cop-out.

resource "null_resource" "apig_5" {
  triggers = {
    status = var.ec_apig_5 == true ? "ENABLED" : "DISABLED"
  }
}

resource "aws_securityhub_standards_control" "apig_5" {
  control_status        = var.ec_apig_5 == true ? "ENABLED" : "DISABLED"
  disabled_reason       = var.ec_apig_5 == true ? null : "Disabled to comply with company policy."
  standards_control_arn = "arn:aws:securityhub:${data.aws_region.main.name}:${data.aws_caller_identity.main.account_id}:control/aws-foundational-security-best-practices/v/1.0.0/APIGateway.5"

  lifecycle {
    replace_triggered_by  = [null_resource.apig_5]
  }
}
sakojun commented 1 year ago

There was an update to allow cloud formation to specify which controls to disable. It might be a good idea to allow terraform to be configured in the same way. https://aws.amazon.com/about-aws/whats-new/2023/06/aws-security-hub-enhanced-management-capabilities-cloudformation https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-securityhub-standard.html