Skip to main content
CMDashCybersecurity Maturity Dashboard
← Back to AWS Security Hub

AWS Security Hub — Integration Setup

Connect with a read-only IAM role in your account that trusts CMDash and requires an External ID CMDash issues for this connection. CMDash stores only the role ARN and signs with 15-minute sessions; there is no long-lived key to leak or rotate, and every call shows up in your CloudTrail under the session name cmdash-<connection id>. The access key mode stays for connections made before the role mode existed, and for a self-hosted CMDash whose operator has not configured an integration principal (the setup form says so when you choose the role).

Prerequisites

  • An AWS account with Security Hub enabled in at least one region
  • Permission to create an IAM role (or user) with securityhub:GetFindings
  • CMDash Essentials tier or above

Note: Security Hub must already be enabled for the region(s) you want to monitor (Security Hub console → Settings → General), and findings must be in an ACTIVE record state to be picked up.

Step 1: Create the role

  1. In CMDash, go to Integrations, find AWS Security Hub and click Connect.

  2. Keep Create a role with CloudFormation (recommended) selected. CMDash shows the External ID issued for this connection (it stays the same if you close the form, disconnect or reconnect) and the CMDash principal to trust.

  3. Create the role with the CMDash CloudFormation template, cmdash-integration-role.yaml — the same template as the Amazon Web Services connector, with Security Hub switched on and the configuration checks off. It creates one IAM role whose trust allows only the CMDash principal to trust, only with this connection's External ID, and whose only permission is securityhub:GetFindings (no write action, no wildcard action, no AWS managed policy). Its RoleArn output is the value you paste back.

    • Launch the stack in AWS (on the form when your CMDash deployment publishes the template to Amazon S3, which CloudFormation requires for a one-click launch) opens CloudFormation with every parameter filled in: tick the IAM acknowledgement, Create stack, and copy the RoleArn output.
    • Or upload the template: download it from the link on the form, then CloudFormation → Create stack → Upload a template file, with CmdashPrincipalArn and ExternalId from the form, IncludeConfigChecks = false and IncludeSecurityHub = true.

    Delete the stack to remove CMDash's access. Or create the role by hand in the AWS IAM Console:

    1. Roles → Create role → Custom trust policy, with the two values from the form:

      json
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Principal": { "AWS": "<CMDash principal to trust>" },
            "Action": "sts:AssumeRole",
            "Condition": { "StringEquals": { "sts:ExternalId": "<External ID>" } }
          }
        ]
      }
      
    2. Attach a policy granting read-only Security Hub access, and nothing else:

      json
      {
        "Version": "2012-10-17",
        "Statement": [
          { "Effect": "Allow", "Action": "securityhub:GetFindings", "Resource": "*" }
        ]
      }
      
    3. Name the role, e.g. CMDashSecurityHubRead, create it, and copy its ARN.

Why the External ID matters — and why the trust policy must require it. CMDash serves many customers, and your role trusts CMDash. The External ID stops another CMDash customer from pointing CMDash at your role: CMDash issues a different one for every connection, always sends the one it issued, and never accepts one typed in. That protects you only if your trust policy requires the External ID (the sts:ExternalId condition above); without it the role would accept any CMDash customer's request.

CMDash checks this for you: when you connect or test, it asks AWS for a session with a random External ID it never issued, and your role must refuse it. If it is accepted — or CMDash cannot assume the role at all yet — CMDash does not connect and tells you why; nothing is saved until the role passes. The check repeats every time CMDash starts a new session on your role (every sync) and with every health check. With the condition in place, someone who learns your role ARN cannot get CMDash to use it.

Step 2: Connect in CMDash

Back in the same Connect form, enter:

  • IAM role ARN — arn:aws:iam::<12-digit account id>:role/<name>
  • AWS region (e.g. us-east-1; defaults to us-east-1 if left blank)

Click Test Connection, then Connect. CMDash refuses a role ARN in any of CMDash's own AWS accounts, and one whose account ID is not exactly 12 digits, before contacting AWS, and checks that the trust policy requires the External ID before anything is saved. It reaches STS through your region's own endpoint when that region is enabled by default in every AWS account, and through sts.us-east-1.amazonaws.com for an opt-in region. Opening the role setup does not use one of your plan's integrations; connecting does.

Switching an existing access-key connection to a role: disconnect it, then connect again and choose the role.

Access key setup (legacy)

  1. In the AWS IAM Console, Users → Create user, e.g. cmdash-integration, with the securityhub:GetFindings policy above.
  2. Security credentials → Create access key (use case Third-party service). Copy the Access Key ID and Secret Access Key — the secret is shown only once.
  3. In CMDash, click Connect on AWS Security Hub, choose Access key (legacy), and enter the AWS access key ID (stored as this connection's access token), the AWS secret access key and the AWS region.
  4. Click Test Connection, then Connect.

What Syncs

Data TypeSecurity Hub APISync Frequency
Vulnerabilities (findings of type Software and Configuration Checks...)POST /findings (GetFindings, filtered to RecordState=ACTIVE)Every 4 hours by default (configurable per connection)
Incidents (findings of type Threat...)Same GetFindings call, split by Finding.Type prefixEvery 4 hours by default (configurable per connection)

CMDash pages through results using Security Hub's NextToken and stops after 2,000 findings in a single sync to bound run time. Findings are split into CMDash's Vulnerability and Incident buckets purely by the Type field prefix returned by Security Hub — a finding tagged Software and Configuration Checks/... becomes a vulnerability record, one tagged Threat/... becomes an incident record.

Authentication Notes

CMDash signs every Security Hub request with AWS Signature Version 4, the only authentication scheme AWS service APIs accept. Each request carries an Authorization: AWS4-HMAC-SHA256 … header and an x-amz-date, computed over the exact method, path, query string, headers and body being sent — so a signature is valid only for the one request it was generated for, and only against the endpoint it was addressed to. Each page of a paginated sync is signed separately.

Scope the IAM role (or user) as tightly as possible: securityhub:GetFindings on the target region is sufficient, and nothing in this integration issues any other call.

Role mode. CMDash's own integration principal assumes your role with sts:AssumeRole, sending this connection's External ID and a 15-minute duration, and signs every Security Hub request with the session it gets back (including x-amz-security-token). One session covers every page of a sync; it is renewed after 12 minutes. Nothing long-lived about your account is stored.

Access key mode. The access key pair is long-lived, so rotate it on a schedule (see Credential Rotation below).

Changed in v3.5.0. Earlier releases sent the access key and secret as custom X-Aws-Access-Key-Id / X-Aws-Secret-Access-Key headers, which are not part of AWS's protocol — AWS ignores unrecognised X-* headers and rejects the request. This integration could not authenticate for any tenant before v3.5.0, and an earlier version of this page described that behaviour as an intentional trade-off. It was not.

Troubleshooting

  • "The role's trust policy does not require the External ID" (role mode): add "Condition": { "StringEquals": { "sts:ExternalId": "<External ID>" } } to the statement that trusts CMDash, then connect again. CMDash will not connect a role without it.
  • "CMDash could not confirm that the role's trust policy requires the External ID": AWS did not answer the check clearly. Nothing was connected; try again in a minute.
  • "AWS refused to let CMDash assume the role" (role mode): AWS answers the same way for three causes, on purpose. Check the role ARN; that the trust policy's Principal is exactly the CMDash principal to trust from the form; and that the sts:ExternalId condition is exactly the External ID from the form (re-open the Connect form to see it again).
  • "Role-based AWS connections are not available on this deployment": the CMDash operator has not configured the integration principal (see the Operator setup section of the Amazon Web Services setup guide). Use an access key until they do.
  • 403 InvalidSignatureException: the request was signed but the signature does not match — usually a secret access key copied with leading/trailing whitespace, or a key rotated on the AWS side without updating CMDash.
  • 403 MissingAuthenticationToken: the request reached AWS without a usable Authorization header. On v3.5.0+ this should not occur; if it does, the connection is still running against a pre-v3.5.0 deployment (see Authentication Notes).
  • 403 AccessDeniedException: the signature verified, but the IAM principal lacks securityhub:GetFindings on the target region. This is the only one of the three that an IAM policy change fixes — the other two are credential or version problems, and widening the policy will not resolve them.
  • SignatureDoesNotMatch mentioning the date: the host clock has drifted. AWS rejects a signature whose x-amz-date is more than 5 minutes from its own clock; check NTP on the CMDash host.
  • Empty findings list: Confirm Security Hub is enabled in the region you configured and that at least one integration (GuardDuty, Inspector, a third-party product, etc.) is feeding it findings.
  • Wrong region data: The adapter only queries the single region you configure. If you run Security Hub in multiple regions, each region needs its own CMDash connection.
  • Connection shows UNHEALTHY: The health check performs a 1-result GetFindings call; a persistent failure usually means the credentials were rotated/deleted on the AWS side without updating CMDash.

Rate Limits & Sync Behavior

SettingValue
Sync frequencyEvery 4 hours by default (syncInterval is configurable per connection)
First syncHistorical active findings pulled on initial connection, up to the 2,000-record cap
Pagination cap2,000 findings per sync run
Rate limit handlingEvery outbound request is paced through CMDash's shared per-tenant token bucket for this provider (#507)
Failed sync retryJob queue retries 3 times with exponential backoff (starting at 30s) — see docs/developers/dead-letter.md

Credential Rotation

Role mode: nothing to rotate. To cut CMDash off, delete the role or remove CMDash from its trust policy.

Access key mode: IAM access keys do not expire on a fixed schedule, so CMDash cannot display an automatic expiry warning banner for this integration. Better still, move the connection to a role (disconnect, then connect with Create a role).

To rotate an access key:

  1. In the AWS IAM console, create a new access key for the cmdash-integration user (AWS allows two active keys per user, so you can rotate without downtime).
  2. In CMDash: Settings → Integrations → AWS Security Hub → Edit.
  3. Enter the new Access Key ID and Secret Access Key, then Save.
  4. Once the connection tests healthy, deactivate and delete the old access key in AWS IAM.

Multiple Instances / Multi-Site

If you run Security Hub in more than one AWS account or region, each account/region pair needs its own CMDash connection (the adapter only ever queries the single region configured on a connection).

To add another account or region:

  1. Repeat Step 1 in the additional account/region.
  2. In CMDash: Settings → Integrations → Add Integration → AWS Security Hub.
  3. Name the connection descriptively (e.g., AWS Security Hub - Prod us-east-1, AWS Security Hub - Prod eu-west-1).
  4. Click Save & Test Connection.

Findings from all connected accounts/regions are merged in the CMDash compliance dashboard.

Compliance Framework Coverage

The AWS Security Hub integration provides evidence for the following controls. Coverage is automatically mapped when data is synced.

FrameworkControlDescription
PCI DSS11.3Vulnerability scanning — Security Hub findings satisfy internal scan/finding evidence
PCI DSS6.2Patch management — configuration-check findings mapped to patch/config posture
HITRUST10.mPatch management — finding age and remediation status
CMMC L2RA.2.141Vulnerability scanning — Security Hub findings mapped to scanning evidence
SOC 2CC7.1Threat detection — Security Hub threat findings feed the threat-detection evidence bucket

Ready to see your posture?

Start a 30-day free trial of any paid plan — a card is required, and it converts unless you cancel — or sign up for Free with no card at all.