Deshabilitar Security Hub controles en una organización en AWS
Published: 2023-10-11 22:29:03

## Objetivo

En este blog, exploraremos la automatización del proceso para habilitar o deshabilitar controles en [AWS Security Hub](https://docs.aws.amazon.com/securityhub/latest/userguide/what-is-securityhub.html) a través de una organización que comprende múltiples cuentas y regiones. A pesar de que Security Hub proporciona una funcionalidad de administración de controles, no existe una solución nativa que permita habilitar o deshabilitar controles de manera global.

La solución descrita a continuación se encuentra basada en este [AWS blog](https://aws.amazon.com/blogs/security/disabling-security-hub-controls-in-a-multi-account-environment/) adicionado las mejoras descritas a continuación:

- Facilitar la habilitación o deshabilitación de controles a través de múltiples estándares, aprovechando una vista consolidada y empleando un ControlId común.
- Ofrecer flexibilidad para habilitar o deshabilitar controles de forma global o por regiones.
- Habilitar o deshabilitar controles en toda la organización sin necesidad de listar todas las cuentas de AWS.
- Tratar la cuenta administrativa de Security Hub como una cuenta miembro de la organización, garantizando una gestión unificada.
- Integración con s3 para ejecutar la State Machine cuando se detecta una actualización o adición de un elemento en la base de datos de DynamoDB.
- Uso de una tabla de DynamoDB que almacena información sobre regiones por cuenta de AWS, lo que resulta útil en organizaciones de gran envergadura con distintas necesidades de negocio que pueden involucrar habilitar diferentes regiones por cuenta.

## Descripción

Esta solución consiste en lo siguiente:

- **cross-account IAM role** que se establece en todas las cuentas de la organización, otorgando los permisos necesarios para activar o desactivar controles a través de diversos estándares.

- **AWS Step Function Machine** que asume el rol en las cuentas miembro de la organización, gestionando la habilitación o deshabilitación de controles y garantizando el cumplimiento según los estándares configurados en la cuenta administrativa.

- **tabla DynamoDB** que almacena todas las excepciones, incluyendo los controles que deben ser activados o desactivados en cada cuenta o región de la organización.

- **S3 Bucket** donde se carga el archivo [items.json](https://github.com/4ndr4s/AWS-SecHub-Cross-Account-Region-Controls-Disabler/blob/main/Terraform/lambda/items.json), que contiene la lista de controles y su estado deseado.

- **process_ddb_lambda Función Lambda** la cual se invoca cada vez que [items.json](https://github.com/4ndr4s/AWS-SecHub-Cross-Account-Region-Controls-Disabler/blob/main/Terraform/lambda/items.json) se actualiza en el bucket de s3.

- **DynamoDB para cuentas y regions** Tabla de datos que almacena la relación de regiones habilitadas por cuenta de AWS.

- **StateMachineLambdaTrigger Función Lambda** encargada de iniciar la ejecución de la máquina de estado **Step Function Machine**.


![Diagrama](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/el91uuqcy8xdh3qf70hh.png)

## Configuración

### Requisitos

Para desplegar esta solución usted necesita:

- [AWS CLI V2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
- [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)
- [Terraform](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli)

### Cuentas miembro

Despliegue cross-account IAM role definido en [member-iam-role/template.yaml](https://github.com/4ndr4s/AWS-SecHub-Cross-Account-Region-Controls-Disabler/blob/main/member-iam-role/template.yaml) en todas las cuentas de la organización.

#### Despliegue

Reemplace *my-stackset* y *AccountID* con el valor deseado y cree el stack-set.

```
aws cloudformation create-stack-set \
--stack-set-name <my-stackset> \
--template-body file://member-iam-role/template.yaml \
--capabilities CAPABILITY_NAMED_IAM \
--call-as DELEGATED_ADMIN --permission-model SERVICE_MANAGED\ --auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false \
--parameters ParameterKey=SecurityHubAdminAccountId,ParameterValue=<AccountID>
```
#### Parameters

| Name                      | Description                                                                                       | Default                        |
|---------------------------|---------------------------------------------------------------------------------------------------|--------------------------------|
| SecurityHubAdminAccountId | Account ID of SecurityHub administrator Account                   | *None*                           |
| IAMRolePath               | Path for IAM Role - this must match the `MemberIAMRolePath` parameter in the `UpdateMembers` stack. | /                      |
| IAMRoleName               | Name of IAM Role - this must match the `MemberIAMRoleName` parameter in the `UpdateMembers` stack.    | securityhub-UpdateControl-role |

Crear stack instances, reemplace *ORG-ID* con el OU en el cual desea desplegar, si desea desplegar el role a nivel de la organización use el root ID de su organización.

```
aws cloudformation create-stack-instances --stack-set-name my-stackset \
--deployment-targets OrganizationalUnitIds='["ORG-ID"]' \
--regions '["us-east-1"]'  --call-as DELEGATED_ADMIN \
--operation-preferences FailureTolerancePercentage=100,MaxConcurrentCount=20
```

### Security Hub Administrator Account

#### SAM

Despliegue de la maquina de estado descrita en [CFN/template.yaml](https://github.com/4ndr4s/AWS-SecHub-Cross-Account-Region-Controls-Disabler/blob/main/CFN/template.yaml).

#### Prerrequisitos

Debido a que template.yaml usa Serverless transformation, se require la creación de un artifact bucket en la cuenta administradora de Security Hub, el siguiente comando crea este bucket con el nombre *<artifact-bucket>*:

```
aws s3 mb s3://<artifact-bucket>
```

#### Despliegue

```
sam package --template-file CFN/template.yaml --output-template-file CFN/template-out.yaml --s3-bucket <artifact-bucket>
aws cloudformation deploy --template-file CFN/template-out.yaml --capabilities CAPABILITY_IAM --stack-name <stack-name> --parameter-overrides SecurityHubAdminAccountId=<AccountID>
```

#### Parameters
| Name                      | Description                                                                                                  | Default                        |
|---------------------------|--------------------------------------------------------------------------------------------------------------|--------------------------------|
| Schedule |  The scheduling expression that determines when and how often the Security Hub Disabler runs.                             | rate(1 day)                           |
| MemberIAMRolePath         | Path of IAM Role in member account - this must match the `IAMRolePath` parameter in the `memeber-iam-role` stack. | /                      |
| MemberIAMRoleName         | Name of IAM Role in member account - this must match the `IAMRoleName` parameter in the `memeber-iam-role` stack.   | securityhub-UpdateControl-role |
| Path                      | Path of IAM LambdaExecution Roles                                                                            | /                      |
| EventTriggerState                      | The state of the SecurityHubUpdateEvent rule monitoring Security Hub control updates and triggering the state machine                                                                            | DISABLED                      |
| NotificationEmail1                      | Optional - E-mail address to receive notification if the state machine fails.  |                       |
| NotificationEmail2                      | Optional - E-mail address to receive notification if the state machine fails.  |                       |
| NotificationEmail3                      | Optional - E-mail address to receive notification if the state machine fails.  |                       |

#### Terraform

Despliegue la solución descrita en el folder terraform la cual se encargara de crear el bucket de s3 y la función lambda que se encargara de actualizar la base de datos cuando se sube un nuevo archivo json con los controles a deshabilitar o habilitar.

```
## Inicie terraform
terraform init

## Ejecute el plan para evaluar cambios
terraform plan

## Ejecute apply
terraform apply
```

#### Uso

Luego de desplegar esta solución, se ejecutara con base en los siguientes triggers:

Ejecución programada.

Este tipo de ejecución se inicia según un cronograma predefinido. Puede configurar el intervalo de tiempo utilizando el parámetro "Schedule," siendo un día el valor predeterminado. Puede hacer uso de las siguientes [expresiones](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule-schedule.html) para personalizar el cronograma. 

Esta ejecución está diseñada para mantener la organización en cumplimiento de los estándares habilitados y para propagar estos estándares junto con el estado de los controles a las nuevas cuentas en toda la organización.

Ejecución basada en eventos.

Esta modalidad de ejecución se dispara cada vez que se habilita o deshabilita un control en la cuenta administradora de Security Hub. Es importante tener en cuenta una limitación: si se realizan numerosos cambios en los controles en un corto período de tiempo, este evento puede generar múltiples ejecuciones paralelas, lo que podría llevar a la saturación de la API. 

Para este proyecto en particular, hemos optado por mantener esta ejecución desactivada, ya que tenemos diversas necesidades de negocio que no requieren que el estado de los controles en la cuenta administradora se refleje en las cuentas miembro.


Ejecución basada en eventos de S3

Cada vez que se agrega o actualiza un nuevo archivo en el bucket de S3 después de actualizar las bases de datos, se inicia una ejecución de la *State Machine*.


#### Configurando excepciones

Para añadir elementos a la tabla de DynamoDB alojada en la cuenta administradora de Security Hub, cada elemento representará una excepción. Cada excepción contendrá, al menos, una cuenta de AWS. Cada vez que un archivo es añadido o actualizado en el bucket de S3, se desencadenará la ejecución de una función Lambda, la cual, a su vez, iniciará una ejecución de la *State Machine*. Esto garantizará la actualización de la(s) cuenta(s) relacionada(s) con dicha excepción.

Para agregar elementos se debe editar el archivo [items.json](https://github.com/4ndr4s/AWS-SecHub-Cross-Account-Region-Controls-Disabler/blob/main/Terraform/lambda/items.json), como ejemplo puede ver el archivo [items.json.template](https://github.com/4ndr4s/AWS-SecHub-Cross-Account-Region-Controls-Disabler/blob/main/Terraform/lambda/items.json.template).

```
  {
    "ControlId": "CloudTrail.5",
    "Disabled": [ "ALL" ],
    "DisabledReason": "We are not monitoring CT at Organization level, Jira Ticket XXX-01"
  },
  {
    "ControlId": "CloudTrail.6",
    "Disabled": ["123456789012", "123456789089", "123456789076"],
    "DisabledReason": "We are not monitoring CT at Organization level, Jira Ticket XXX-02"
  },
  {
      "ControlId": "IAM.9",
      "Enabled": ["ALL"],
      "DisabledReason": "Global resource control, should be enabled only in us-east-1, Jira Ticket XXX-03",
      "Region": ["us-east-1"]
  }


```

Para agregar una excepción a toda la organización incluyendo la cuenta administradora de Security Hub debe usar "ALL".

Para deshabilitar un control global, debe usar "Enabled" y la región donde desea que este control este habilitado. por ejemplo:

```
## Deshabilitar IAM.9 en todas las regiones a excepción de us-east-1
  {
      "ControlId": "IAM.9",
      "Enabled": ["ALL"],
      "DisabledReason": "Global resource control, should be enabled only in us-east-1, Jira Ticket XXX-03",
      "Region": ["us-east-1"]
  }
```
**Adicionando o actualizando cuentas**: para actualizar las cuentas o agregar una cuenta y sus regions se debe editar el archivo [accounts.json](https://github.com/4ndr4s/AWS-SecHub-Cross-Account-Region-Controls-Disabler/blob/main/Terraform/lambda/accounts.json). Luego de que una cuenta es adicionada o sus regiones actualizadas, una función lambda es invocada para luego de actualizar las bases de datos iniciar una ejecución de la *State Machine*.

```
[
    {
      "AccountId": "123456789012",
      "Regions": [
        "ap-northeast-1",
        "ap-northeast-2",
        "ap-northeast-3",
        "ap-south-1",
        "ap-southeast-1",
        "ap-southeast-2",
        "ca-central-1",
        "eu-central-1",
        "eu-north-1",
        "eu-west-1",
        "eu-west-2",
        "eu-west-3",
        "sa-east-1",
        "us-east-2",
        "us-west-1",
        "us-west-2",
        "us-east-1"
      ]
    },
    {
      "AccountId": "123456789012",
      "Regions": [
        "us-east-2",
        "us-west-1",
        "us-west-2",
        "us-east-1"
      ]
    }
  ]
```

Luego de agregar o actualizar un elemento en el archivo [items.json](https://github.com/4ndr4s/AWS-SecHub-Cross-Account-Region-Controls-Disabler/blob/main/Terraform/lambda/items.json) para aplicar estos cambios debe ejecutar terraform plan y terraform apply.