AWS Security Hub — Integration Setup
How CMDash signs in: a role (recommended) or an access key (legacy)
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
ACTIVErecord state to be picked up.
Step 1: Create the role
-
In CMDash, go to Integrations, find AWS Security Hub and click Connect.
-
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.
-
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 issecurityhub:GetFindings(no write action, no wildcard action, no AWS managed policy). ItsRoleArnoutput 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
RoleArnoutput. - Or upload the template: download it from the link on the form, then CloudFormation → Create stack → Upload a template file, with
CmdashPrincipalArnandExternalIdfrom the form,IncludeConfigChecks=falseandIncludeSecurityHub=true.
Delete the stack to remove CMDash's access. Or create the role by hand in the AWS IAM Console:
-
Roles → Create role → Custom trust policy, with the two values from the form:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "<CMDash principal to trust>" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "<External ID>" } } } ] } -
Attach a policy granting read-only Security Hub access, and nothing else:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "securityhub:GetFindings", "Resource": "*" } ] } -
Name the role, e.g.
CMDashSecurityHubRead, create it, and copy its ARN.
- 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
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:ExternalIdcondition 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 tous-east-1if 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)
- In the AWS IAM Console, Users → Create user, e.g.
cmdash-integration, with thesecurityhub:GetFindingspolicy above. - 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.
- 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.
- Click Test Connection, then Connect.
What Syncs
| Data Type | Security Hub API | Sync 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 prefix | Every 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-Keyheaders, which are not part of AWS's protocol — AWS ignores unrecognisedX-*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
Principalis exactly the CMDash principal to trust from the form; and that thests:ExternalIdcondition 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 usableAuthorizationheader. 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 lackssecurityhub:GetFindingson 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. SignatureDoesNotMatchmentioning the date: the host clock has drifted. AWS rejects a signature whosex-amz-dateis 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
GetFindingscall; a persistent failure usually means the credentials were rotated/deleted on the AWS side without updating CMDash.
Rate Limits & Sync Behavior
| Setting | Value |
|---|---|
| Sync frequency | Every 4 hours by default (syncInterval is configurable per connection) |
| First sync | Historical active findings pulled on initial connection, up to the 2,000-record cap |
| Pagination cap | 2,000 findings per sync run |
| Rate limit handling | Every outbound request is paced through CMDash's shared per-tenant token bucket for this provider (#507) |
| Failed sync retry | Job 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:
- In the AWS IAM console, create a new access key for the
cmdash-integrationuser (AWS allows two active keys per user, so you can rotate without downtime). - In CMDash: Settings → Integrations → AWS Security Hub → Edit.
- Enter the new Access Key ID and Secret Access Key, then Save.
- 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:
- Repeat Step 1 in the additional account/region.
- In CMDash: Settings → Integrations → Add Integration → AWS Security Hub.
- Name the connection descriptively (e.g.,
AWS Security Hub - Prod us-east-1,AWS Security Hub - Prod eu-west-1). - 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.
| Framework | Control | Description |
|---|---|---|
| PCI DSS | 11.3 | Vulnerability scanning — Security Hub findings satisfy internal scan/finding evidence |
| PCI DSS | 6.2 | Patch management — configuration-check findings mapped to patch/config posture |
| HITRUST | 10.m | Patch management — finding age and remediation status |
| CMMC L2 | RA.2.141 | Vulnerability scanning — Security Hub findings mapped to scanning evidence |
| SOC 2 | CC7.1 | Threat detection — Security Hub threat findings feed the threat-detection evidence bucket |