GithubHelp home page GithubHelp logo

aws-security-hub-cross-account-controls-disabler's Introduction

AWS Security Hub Cross-Account Controls Disabler

Goal

AWS Security Hub allows you to disable controls of security standards such as CIS AWS Foundations controls or AWS Foundational Security Best Practices controls. However, in a multi account setup with a dedicated Security Hub administrator account, there is no native way to disable specific controls globally for all Security Hub member accounts. This project intends to close this gap by propagating the action of enabling or disabling security standards and its controls in the Security Hub administrator account across all of the Security Hub member accounts.

Overview

The solution consists of the following:

  • A cross-account IAM role in the member accounts with the requied Security Hub permissions to disable/enable Security standard controls.
  • An AWS Step Function state machine assuming the cross-account IAM role and disable/enable the controls in the member accounts to reflect the setup in the administrator account.
  • An DynamoDB Table containing exceptions. The table contains information about which control should be disabled or enabled in which account. This information overrides the configurations fetched from the Security Hub Administrator for the specified acount.

Architecture

NOTE: If you want to update controls across multiple accounts NOT managed by a Security Hub administrator then you can use the script provided in this blog post.

Setup

Requirements

To deploy this solution, you need

Also, make sure that one of the AWS accounts is designated as the Security Hub administrator account.

Member Accounts

Deploy the cross-account IAM role defined in member-iam-role/template.yaml in all member accounts.
For SecurityHubAdminAccountId, set the Account ID of the Security Hub administrator account.

Deployment

Set an arbitrary <stack-name> and the Security Hub administrator account ID for <AccountId> and execute following command in a Security Hub member account:

aws cloudformation deploy --template-file member-iam-role/template.yaml --capabilities CAPABILITY_NAMED_IAM --stack-name <stack-name> --parameter-overrides SecurityHubAdminAccountId=<AccountID>

For a more efficient deployment to multiple member accounts at once, AWS CloudFormation StackSets can be used.

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

Security Hub administrator account

Deploy the state machine defined in UpdateMembers/template.yaml

Prerequisites

Since UpdateMembers/template.yaml is using the Serverless transformation, you need to have an artifact bucket in the Security Hub administrator account. The following command creates such a bucket with the name <artifact-bucket>:

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

Deployment

The artifact bucket created in the preqrequisites is referenced by <artifact-bucket> in the code below. Chose an arbitrary <stack-name> and execute following commands to deploy the UpdateMembers/template.yaml:

sam package --template-file UpdateMembers/template.yaml --output-template-file UpdateMembers/template-out.yaml --s3-bucket <artifact-bucket>
aws cloudformation deploy --template-file UpdateMembers/template-out.yaml --capabilities CAPABILITY_IAM --stack-name <stack-name>

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.

Usage

After deployment, the solution runs automatically based on the following two triggers:

  • Scheduled Trigger
    The timeframe, when the state machine is triggered on a scheduled basis, can be defined by the Schedule parameter. The default value is rate(1 day). You can use scheduling expressions as described here: https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-rule-schedule.html.
    The Scheduled Trigger makes sure, that new accounts are updated by this solution after they get added as a Security Hub member account. Also, it propagates the status of the controls which were already disabled before the solutions was deployed to all existing member accounts.
  • Event Trigger
    The state machine is triggered each time a control is disabled/enabled in the Security Hub administrator account. The state of the Event Trigger can be controlled by the EventTriggerState parameter during deployment.
    Limitation: If a lot of controls are changed in a very short timeframe (e.g. when done programmatically via Security Hub Controls CLI), the Event Trigger causes multiple parallel executions which may lead to API throttling and thus failure of the execution.

Setting exceptions

The DynamoDB table deployed in the SecurityHub administrator account can be filled with exceptions. If an exception is defined for an account, the account will be updated as specified in the exception instead of reflecting the configuration in the SecurityHub Administrator account.

Schema

Field names ControlId Disabled Enabled DisabledReason
Description The ControlId for which an exception should be defined. Primary key of the table. List of accounts for which the Control should be disabled List of accounts for which the Control should be enabled DisabledReason to be specified in the update_standards_control API call when disabling a control. If omitted, "Exception" is used as default.
Type String List of Strings List of Strings String
Example CIS.1.1 [ { "S" : "111111111111" } ] [ { "S" : "222222222222" } ] Some_Reason

Update DynamoDB table

To create an exception, an item in the DynamoDB table needs to be created. The following JSON object creates an exception for control CIS.1.1:

{
 "ControlId": {
  "S": "CIS.1.1"
 },
 "Disabled": {
  "L": [
   {
    "S": "11111111111"
   }
  ]
 },
 "Enabled": {
  "L": [
   {
    "S": "22222222222"
   }
  ]
 },
 "DisabledReasod": {
  "S": "Some_Reason"
 }
}

This JSON object can either be put via the AWS Console or via the AWS CLI. The following AWS CLI command creates an item in the DynamoDB table <DynamoDB-table-name>:

aws dynamodb put-item --table-name <DynamoDB-table-name> --item '{ "ControlId": { "S": "CIS.1.1" }, "Disabled": { "L": [ { "S": "11111111111" } ] }, "Enabled": { "L": [ { "S": "22222222222" } ] }, "DisabledReasod": { "S": "Some_Reason" } } '

The DynamoDB table name can be found in the Outputs section of the CloudFormation stack in the SecurityHub administrator account under the name AccountExceptionsDynamoDBTableName. It can also be retrieved with the following AWS CLI command:

aws cloudformation describe-stacks --query "Stacks[].Outputs[?OutputKey=='AccountExceptionsDynamoDBTableName'].OutputValue" --output text

Example

In this section, the evaluation logic is explained using the following example: Exception

  • CIS.1.1 will be disabled for account 11111111111, overriding the information fetched from the SecurityHub administrator. No exceptions are defined to enable this control. Some_Reason will be specified in the update_standards_control API call when disabling this control for account 11111111111.
  • CIS.1.2 will be enabled for account 11111111111, overriding the information fetched from the SecurityHub administrator. No exceptions are defined to disable this control.
  • CIS.1.3 will be enabled for account 22222222222, overriding the information fetched from the SecurityHub administrator. No exceptions are defined to disable this control. The empty entry in Disabled has the same effect as an empty list ([]).
  • CIS.1.4 will be disabled for account 22222222222, overriding the information fetched from the SecurityHub administrator. No exceptions are defined to enabled this control. Exception will be specified in the update_standards_control API call when disabling this control for account 22222222222, since no explicit DisabledReason was given.
  • CIS.1.5 specifies the same account in both, Disabled and Enabled list. This is a conflict and the exception will be ignored. A warning will be logged in the UpdateMembers Lambda function and the control for the account 22222222222 will be set as specified in the SecurityHub administrator as a fallback.
  • Any other account and control will be set as specified in the SecurityHub administrator.

Security Hub Controls CLI

Security Hub Controls CLI is a CLI tool to disable and enable security standards controls in AWS Security Hub. It also supports the exception handling described here.

Workflow and Troubleshooting

Since the solution is implemented via AWS Step Functions state machine, each execution can be inspected in the AWS Step Functions state machine dashboard.

A successfull execution can be seen in the following picture:
Successfull

A failed execution can be seen in the following picture:
Failed

An execution can fail, for example, if the cross-acccount IAM Role is not deployed in the member account or any other ClientError is raised in the UpdateMember Lambda function.

In that case, a message is published to the SNS topic in the SendSNS step, containing information about which accounts were not updated successfully and providing the according error message per account. E-Mail addresses receiving the message can be set during deployment via the NotificationEmail* parameters.
The same information can be inspected in the the state machine logs. You find this information for example in the Step Input section of the PipelineFailed step as seen in the following picture:
Failed inpsection

Customization

It may be desired to change or add other subscription types into the SNS topic. The sections to be changed for that are marked with # TODO - Subscriptions in the UpdateMembers/template.yaml file.

aws-security-hub-cross-account-controls-disabler's People

Contributors

ahmedqe avatar amazon-auto avatar h-kwnm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

aws-security-hub-cross-account-controls-disabler's Issues

Mismatched control sync

I have deployed this solution to our AWS organization and it appears that multiple controls are consistently synced incorrectly from our security hub admin account to our member accounts. They either incorrectly identify that controls are enabled in the admin account and proceed to enable them in the member accounts or they correctly id controls as disabled in the member accounts and then fail to update them in member accounts. Not sure if this is because of previously disabled controls in a number of accounts before the solution was deployed or if it is another issue. The step function deployed in the admin account indicates that the executions are successful when I initiate them manually. Any ideas on this? Let me know if any additional information is needed.

Possibility to control regions in exclusions

Hello folks,
I'm trying to get benefits from the Security Hub in cross-account cross-region setup and this project looks like the thing that I was looking for.

Also, I want to reduce finding noise from global resources controls(i.e. only keep them in one region like AWS docs suggest link)

The project looks awesome, but as for now, it seems like lack of this feature. Would be awesome to have it implemented.

Thanks!

How can i automatically add the members accounts list in dyanamodb table

hello,
We have more than 500 accounts and it will grow as well. Is there any possibility to add the member's accounts list automatically in dynamoDB table?

how can I disable the below Security hub check-in around 500 accounts, I mean based on your solution?
ex: Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password

Thanks,
Surya

Unexpected behavior due to addition of controls due to AWS update

I have deployed this solution to my AWS organization.
When a new control is introduced on the AWS side, settings that differ from the control settings in the Administrator account are executed, resulting in unexpected behavior.
Is it possible to update this solution?
Or, would it be possible for you to tell me the part of the Lambda function to be modified and what kind of modification to make?

The following describes what actions were taken and what was confirmed.

We recognize that this solution has the following characteristics:
①The control setting status is referenced in the order of Administrator account → member account
②Current control settings are referenced in the order of names from A to Z.
③ When a new control is added, it will be incorporated in the order of ②.
④When updating the member account controls, it is executed by referring to the previous settings of the member account controls.
⑤ When running this solution, if a new control is added from the AWS side to both the Administrator account and member account, the process will be performed normally.
⑥ When running this solution, if a new control is only added to either the Administrator account or the member account, strange processing will occur.

Confirmed operation of ⑥

Example) Normal
SecurityHub Admin Account Control
・Security_AA (DISABLED)
・Security_BB (DISABLED)
・Security_CC (ENABLED)
・Security_DD (ENABLED)
・Security_EE (DISABLED)

Member account control
・Member_AA (DISABLED)
・Member_BB (DISABLED)
・Member_CC (ENABLED)
・Member_DD (ENABLED)
・Member_EE (DISABLED)

process
・Security_AA (DISABLED)
→・Member_AA (DISABLED)

・Security_BB (DISABLED)
→・Member_BB (DISABLED)

・Security_CC (ENABLED)
→・Member_CC (ENABLED)

・Security_DD (ENABLED)
→・Member_DD (ENABLED)

・Security_EE (DISABLED)
→・Member_EE (DISABLED)

Member account control
・Member_AA (DISABLED)
・Member_BB (DISABLED)
・Member_CC (ENABLED)
・Member_DD (ENABLED)
・Member_EE (DISABLED)

Example) Abnormality
SecurityHub Admin Account Control
・Security_AA (DISABLED)
・Security_BB (DISABLED)
・Security_CC (ENABLED)
・Security_CZ (DISABLED) ←NEW Control
・Security_DD (ENABLED)
・Security_EE (DISABLED)
・Security_FF (ENABLED)

Member account control
・Member_AA (DISABLED)
・Member_BB (DISABLED)
・Member_CC (ENABLED)
・Member_DD (ENABLED)
・Member_EE (DISABLED)
・Member_FF (ENABLED)

process
・Security_AA (DISABLED)
→・Member_AA (DISABLED)

・Security_BB (DISABLED)
→・Member_BB (DISABLED)

・Security_CC (ENABLED)
→・Member_CC (ENABLED)

・Security_CZ (DISABLED)
→・Member_DD (ENABLED)

・Security_DD (ENABLED)
→・Member_EE (DISABLED)

・Security_EE (DISABLED)
→・Member_FF (ENABLED)

Member account control
・Member_AA (DISABLED)
・Member_BB (DISABLED)
・Member_CC (ENABLED)
・Member_DD (DISABLED) ← Abnormal
・Member_EE (ENABLED) ← Abnormal
・Member_FF (DISABLED) ← Abnormal

Newly disabled controls not being worked

I disabled 3 controls then checked and what I find is there is nothing in DynamoDB, I see no new state machines running. I then waited 4 hours and still nothing.

I was under the impression that in DynamoDB I would find all the controls present in my master Security Hub and weather or not they are disabled or enabled. I would then use the state machines to push whats in DynamoDB out to all the sub accounts. But yet even after having set this all up on Friday and setting it to refresh every 24 hours I have an empty DynamoDB and not all the disabled controls have been pushed out to all my accounts.

Is there something else I should be doing to validate that this is working as expected?

Pagination error in the UpdateMember Lambda function

The maximum number of items that can be returned by the Security Hub describe_standard_controls API call is limited to 100 outputs. The response returns a next token that can be used to retrieve the next <=100 items. The previous version of this solution had an issue when retrieving the entire list of AWS Foundational Security Best Practices Standard Controls.

The issue has been fixed by this pull request

Found a bug in exception loop

@ahmedqe
Hi, this sample code helped a lot to set up Security Hub in our AWS environment. Thank you so much.
I found a bug in the UpdateMember/index.py, so let me explain.

There are admin_control and member_control generated by zip(admin_controls[admin_key], member_controls[member_key]) at iine 159, but items in admin_controls[admin_key] and member_controls[member_key] are not always in the same order.

https://github.com/aws-samples/aws-security-hub-cross-account-controls-disabler/blob/main/UpdateMembers/src/UpdateMember/index.py#L159

In this case, itertools.product() is supposed to be used instead of zip() to combine all cases, and add a condition to compare admin_control["ControlId"] with member_control["ControlId"] to move on to the following process.

    for admin_key in admin_controls:
        for member_key in member_controls:
            if admin_key == member_key:
                # Same security standard TODO
                for admin_control, member_control in itertools.product(
                    admin_controls[admin_key], member_controls[member_key]
                ):
                    if admin_control["ControlId"] == member_control["ControlId"]:
                        # Check for exceptions first
                        if admin_control["ControlId"] in exceptions["Disabled"]:
                            if member_control["ControlStatus"] != DISABLED:
                                # Disable control in member account
                                update_control_status(
                                    member_control,
                                    member_security_hub_client,
                                    DISABLED,
                                    disabled_reason=exceptions["DisabledReason"][
                                        admin_control["ControlId"]
                                    ],
                                )

Checks no longer disabling

I have deployed this solution multiple times but I am getting a strange result.
I am not sure if it is related to the release of CIS v1.4 or something else.
The Disabled 'Reason', As well as control status, updates to 'disabled' in each child account as expected. However, the total score and disabled check count are not reflected as true with the disabled checks.
CleanShot 2022-12-12 at 14 11 37
CleanShot 2022-12-12 at 14 13 08

multiple regions

is this solution for one region only it can vbe scaled to multiple regions.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.