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

feat: add GuardDuty organization features #1045

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

darrenl33
Copy link
Contributor

@darrenl33 darrenl33 commented May 23, 2024

what

  • Enable and configure new GuardDuty features across member AWS accounts
  • GuardDuty API changes in March 2023, new features are only available with the features object
  • Add GuardDuty terraform resource, aws_guardduty_organization_configuration_feature

why

  • Add support for new GuardDuty protection features

references

@darrenl33 darrenl33 requested review from a team as code owners May 23, 2024 05:16
Copy link
Member

@RoseSecurity RoseSecurity left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a really big fan of these features and would like to see them incorporated. Once we iron out some of the structure, I am excited to see this addition!

Comment on lines +17 to +53
guardduty_features = {
"s3_data_events" = {
name = "S3_DATA_EVENTS"
additional_configuration = []
enable = var.s3_protection_enabled
},
"eks_audit_logs" = {
name = "EKS_AUDIT_LOGS"
additional_configuration = []
enable = var.kubernetes_audit_logs_enabled
},
"ebs_malware_protection" = {
name = "EBS_MALWARE_PROTECTION"
additional_configuration = []
enable = var.malware_protection_scan_ec2_ebs_volumes_enabled
},
"rds_login_events" = {
name = "RDS_LOGIN_EVENTS"
additional_configuration = []
enable = var.rds_login_events_enabled
},
"eks_runtime_monitoring" = {
name = "EKS_RUNTIME_MONITORING"
additional_configuration = ["EKS_ADDON_MANAGEMENT"]
enable = var.eks_runtime_monitoring_enabled
},
"lambda_network_logs" = {
name = "LAMBDA_NETWORK_LOGS"
additional_configuration = []
enable = var.lambda_network_logs_enabled
},
"runtime_monitoring" = {
name = "RUNTIME_MONITORING"
additional_configuration = ["EKS_ADDON_MANAGEMENT", "ECS_FARGATE_AGENT_MANAGEMENT", "EC2_AGENT_MANAGEMENT"]
enable = var.runtime_monitoring_enabled
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@darrenl33 How would you feel about consolidating this configuration into a variable similar to the following? I think this could provide a better experience by allowing to consolidate multiple variables into one structure that can be iterated over

variable "guardduty_features" {
  type = optional(object({
    auto_enable_guardduty_organization_features                           = optional(string, "NONE")
    auto_enable_guardduty_organization_features_additional_configurations = optional(string, "NONE")
    s3_data_events = object({
      name                     = "S3_DATA_EVENTS"
      additional_configuration = list(string)
      enable                   = optional(bool, false)
    })
    eks_audit_logs = object({
      name                     = "EKS_AUDIT_LOGS"
      additional_configuration = list(string)
      enable                   = optional(bool, false)
    })
    ebs_malware_protection = object({
      name                     = "EBS_MALWARE_PROTECTION"
      additional_configuration = list(string)
      enable                   = optional(bool, false)
    })
    rds_login_events = object({
      name                     = "RDS_LOGIN_EVENTS"
      additional_configuration = list(string)
      enable                   = optional(bool, false)
    })
    eks_runtime_monitoring = object({
      name                     = "EKS_RUNTIME_MONITORING"
      additional_configuration = optional(list(string), ["EKS_ADDON_MANAGEMENT"])
      enable                   = optional(bool, false)
    })
    lambda_network_logs = object({
      name                     = "LAMBDA_NETWORK_LOGS"
      additional_configuration = list(string)
      enable                   = optional(bool, false)
    })
    runtime_monitoring = object({
      name                     = "RUNTIME_MONITORING"
      additional_configuration = optional(list(string), ["EKS_ADDON_MANAGEMENT", "ECS_FARGATE_AGENT_MANAGEMENT", "EC2_AGENT_MANAGEMENT"])
      enable                   = optional(bool, false)
    })
  }))
  default     = {}
  nullable    = false
  description = <<DOC
    Configuration for enabling and managing various GuardDuty features within an organization.
    Defaults:
    - auto_enable_guardduty_organization_features: "NONE"
    - auto_enable_guardduty_organization_features_additional_configurations: "NONE"
    - enable (all features): false
    - additional_configuration (where applicable): []

    This object includes settings for automatically enabling GuardDuty features across an organization, as well as configurations for specific services:

    auto_enable_guardduty_organization_features: Optional string to auto-enable GuardDuty features for the organization.
    auto_enable_guardduty_organization_features_additional_configurations: Optional string for additional configurations when auto-enabling GuardDuty features for the organization.

    Features:
    s3_data_events: Configuration for S3 Data Events.
    eks_audit_logs: Configuration for EKS Audit Logs.
    ebs_malware_protection: Configuration for EBS Malware Protection.
    rds_login_events: Configuration for RDS Login Events.
    eks_runtime_monitoring: Configuration for EKS Runtime Monitoring.
    lambda_network_logs: Configuration for Lambda Network Logs.
    runtime_monitoring: Configuration for Runtime Monitoring.

    For each feature:
    name: (Constant) The feature name.
    additional_configuration: A list of additional configuration strings.
    enable: Optional boolean to enable this feature. Default is false.
    DOC
}

@goruha
Copy link
Member

goruha commented Oct 3, 2024

@darrenl33 Thanks for your contribution.
This feature is handy.
At the same time, I agree with @RoseSecurity that the inputs are confusing.
But I think we can do even better.

Something like that.

variable "guardduty_features" {
  type = map(object({
      auto_enable  = optional(string, "NONE")
      additional_configuration = optional(map(object({
         auto_enable  = optional(string, "None")
      })), {})
    })
  }))

  validation {
    condition     = alltrue([ for k in keys(var.guardduty_features) : contains(["S3_DATA_EVENTS", "EKS_AUDIT_LOGS", "EBS_MALWARE_PROTECTION", "RDS_LOGIN_EVENTS", "EKS_RUNTIME_MONITORING", "LAMBDA_NETWORK_LOGS", "RUNTIME_MONITORING"],  k) ])
    error_message = "Guardduty features can but only one of [\"S3_DATA_EVENTS\", \"EKS_AUDIT_LOGS\", \"EBS_MALWARE_PROTECTION\", \"RDS_LOGIN_EVENTS\", \"EKS_RUNTIME_MONITORING\", \"LAMBDA_NETWORK_LOGS\", \"RUNTIME_MONITORING\"]"
  }

  validation {
    condition     =  ! (contains(keys(var.guardduty_features), "EKS_RUNTIME_MONITORING") &&  contains(keys(var.guardduty_features), "RUNTIME_MONITORING"))
    error_message = "Only one of two features \"EKS_RUNTIME_MONITORING\" or \"RUNTIME_MONITORING\" can be added"
  }

  validation {
    condition     =  alltrue([ for k, v in var.guardduty_features :  length(v.additional_configuration) == 0 if !contains(["EKS_RUNTIME_MONITORING", "RUNTIME_MONITORING"], k) ])
    error_message = "Additional feature configuration block allowed only for features \"EKS_RUNTIME_MONITORING\" or \"RUNTIME_MONITORING\""
  }

  validation {
    condition     =  alltrue([ for k, v in var.guardduty_features :  contains(["NEW", "ALL", "NONE"], v.auto_enable)
    error_message = "Auto enabled valid values are \"NEW\", \"ALL\", \"NONE\""
  }

  validation {
    condition     =  alltrue([ for k, v in var.guardduty_features :  alltrue([ for k1, v1 in v.additional_configuration : contains(["EKS_ADDON_MANAGEMENT", "ECS_FARGATE_AGENT_MANAGEMENT", "EC2_AGENT_MANAGEMENT"], k1)])   if contains(["EKS_RUNTIME_MONITORING", "RUNTIME_MONITORING"], k) ])
    error_message = "Guardduty features  additional_configuration can but only one of [\"EKS_ADDON_MANAGEMENT\", \"ECS_FARGATE_AGENT_MANAGEMENT\", \"EC2_AGENT_MANAGEMENT\"]"
  }

  validation {
    condition     =  alltrue([ for k, v in var.guardduty_features :  alltrue([ for k1, v1 in v.additional_configuration : contains(["NEW", "ALL", "NONE"], v1.auto_enable]) if contains(["EKS_RUNTIME_MONITORING", "RUNTIME_MONITORING"], k) ])
    error_message = "Auto enabled valid values are \"NEW\", \"ALL\", \"NONE\""
  }


  default     = {}
  nullable    = false
}

I have not tested this by runtime.
So, it can contain errors, but you can get the idea.

Usage of such input would be like

module "guardduty" {
...

guardduty_features = {
    S3_DATA_EVENTS = {
      auto_enable = "ALL"
    },
    EKS_AUDIT_LOGS = {
      auto_enable = "NEW"
    },
    EBS_MALWARE_PROTECTION = {
      auto_enable = "NONE"
    },
    RDS_LOGIN_EVENTS = {
      auto_enable = "ALL"
    },
    EKS_RUNTIME_MONITORING = {
      auto_enable = "ALL"
      additional_configuration = {
        EKS_ADDON_MANAGEMENT = {
            auto_enable = "ALL"
        },
        ECS_FARGATE_AGENT_MANAGEMENT = {
            auto_enable = "NONE"
        }
        EC2_AGENT_MANAGEMENT = {
             auto_enable = "NEW"
        }
      }
    }
}
...
}

@RoseSecurity @darrenl33, what do you think about this?

Copy link
Member

@goruha goruha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the comments ^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants