Back to Checks
aws

Security Hub has delegated admin configured and is enabled in all regions with organization auto-enable

securityhub_delegated_admin_enabled_all_regions
Service: securityhubSeverity: high
OfficialBuilt-inVerified
Categories:forensics-ready
Resource Type:AwsSecurityHubHub

AWS Security Hub has a delegated administrator configured at the organization level, hubs are active in all opted-in regions, and organization auto-enable is active so that new member accounts are automatically enrolled.

Risk

Without org-wide AWS Security Hub configuration, findings can be aggregated inconsistently, delegated admin may be missing in some regions, and new accounts will not be auto-enrolled. This fragments security posture visibility, delays incident response, and lets misconfigurations and compliance drift go undetected across the organization.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks securityhub_delegated_admin_enabled_all_regions

Recommendation

Configure a delegated administrator for AWS Security Hub via AWS Organizations. Enable Security Hub in all opted-in regions and turn on auto-enable so new member accounts are automatically enrolled. This ensures uniform security posture monitoring across the entire organization.

Remediation

CLI

aws securityhub enable-organization-admin-account --admin-account-id <ADMIN_ACCOUNT_ID> && aws securityhub update-organization-configuration --auto-enable --auto-enable-standards DEFAULT

Other

1Sign in to the AWS Organizations management account
2Open the AWS Organizations console
3Navigate to Services > AWS Security Hub
4Click Register delegated administrator and enter the security account ID
5Switch to the delegated admin account
6In Security Hub console, go to Settings > Accounts
7Enable auto-enable for new organization accounts
8Repeat hub enablement for all opted-in regions

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.securityhub.securityhub_client import (
    securityhub_client,
)


class securityhub_delegated_admin_enabled_all_regions(Check):
    """Ensure Security Hub has a delegated admin and is enabled in all regions.

    This check verifies that:
    1. A delegated administrator account is configured for Security Hub
    2. Security Hub is active (ACTIVE status) in each region
    3. Organization auto-enable is configured for new member accounts
    """

    def execute(self) -> list[Check_Report_AWS]:
        """Execute the check logic.

        Returns:
            A list of reports containing the result of the check for each region.
        """
        findings = []

        # Build a set of regions that have an organization admin account configured
        regions_with_admin = {
            admin.region
            for admin in securityhub_client.organization_admin_accounts
            if admin.admin_status == "ENABLED"
        }

        for securityhub in securityhub_client.securityhubs:
            report = Check_Report_AWS(metadata=self.metadata(), resource=securityhub)

            # Check if this region has a delegated admin
            has_delegated_admin = securityhub.region in regions_with_admin

            # The lookup is tracked per region so that a failure in one region does
            # not mask the result of the others. A partial failure is only relevant
            # when no delegated admin was found: if one was, the status is known.
            admin_lookup_failed = (
                not has_delegated_admin
                and securityhub.region
                in securityhub_client.organization_admin_lookup_failed_regions
            )

            # Check if hub is active
            hub_active = securityhub.status == "ACTIVE"

            # Check if auto-enable is configured for organization members
            auto_enable_on = securityhub.organization_auto_enable

            # Determine overall status
            issues = []
            if not admin_lookup_failed and not has_delegated_admin:
                issues.append("no delegated administrator configured")
            if not hub_active:
                issues.append("Security Hub not enabled")
            if (
                hub_active
                and securityhub.organization_config_available
                and not auto_enable_on
            ):
                # Only report auto-enable issue if hub is active and org config data
                # is available (i.e., we could actually read AutoEnable from the API).
                issues.append("organization auto-enable not configured")

            if issues:
                report.status = "FAIL"
                report.status_extended = (
                    f"Security Hub in region {securityhub.region} has issues: "
                    f"{', '.join(issues)}."
                )
                if admin_lookup_failed:
                    report.status_extended = (
                        f"{report.status_extended[:-1]}; the delegated administrator "
                        f"status could not be determined."
                    )
            elif admin_lookup_failed:
                # Not being able to read the delegated administrator is a lack of
                # visibility, not a misconfiguration: the API is only available to
                # the management or delegated administrator account.
                report.status = "MANUAL"
                report.status_extended = (
                    f"Security Hub delegated administrator status in region "
                    f"{securityhub.region} could not be determined; run this check "
                    f"from the organization management or delegated administrator "
                    f"account."
                )
            else:
                report.status = "PASS"
                report.status_extended = (
                    f"Security Hub in region {securityhub.region} has delegated "
                    f"admin configured with hub active and organization auto-enable "
                    f"enabled."
                )

            # Support muting non-default regions if configured
            if report.status == "FAIL" and (
                securityhub_client.audit_config.get("mute_non_default_regions", False)
                and securityhub.region != securityhub_client.region
            ):
                report.muted = True

            findings.append(report)

        return findings