This guide walks you through creating Amazon EventBridge rules that route Cloud Security events to SQS queues, and configuring Synqly to read those queues. Each operation type can use a separate queue, so you deploy one EventBridge pipeline per operation. The integration uses the same AWS credential options as other AWS providers: static credentials (IAM user access keys) or role-based access (IAM role assumption).
For AWS EventBridge SQS, the recommended split is:
| Queue key | Intended source | Purpose |
|---|---|---|
query_compliance_findings | Security Hub compliance/control findings | Compliance Finding data |
query_threats | Security Hub threat/detection findings and/or native GuardDuty findings | Detection / threat data |
query_cloud_resource_inventory | Reserved for a future inventory pipeline | Cloud resource inventory |
query_events | Reserved for a future events pipeline | Cloud activity events |
Today, query_compliance_findings and query_threats are supported in the AWS EventBridge SQS provider. The other queue keys are available in configuration so you can pre-wire queues as the additional operations are implemented.
Before you begin, ensure the following AWS services are enabled in your target account and Region:
- AWS Security Hub – Publishes compliance/control findings and can also aggregate partner or service findings. See: Enabling Security Hub CSPM.
- AWS GuardDuty – Publishes detection findings. See: Getting started with GuardDuty.
If you want Security Hub to aggregate GuardDuty findings, open Security Hub → Integrations and ensure Amazon: GuardDuty shows Accepting findings. See: Integrating with AWS Security Hub.
Deploy one CloudFormation stack per queue. The recommended starting point is:
- A compliance stack for
query_compliance_findings - A threats stack for
query_threats
Each stack creates:
- An SQS Standard queue
- An IAM role that lets EventBridge send messages to that queue
- One or more EventBridge rules that route the intended source events into that queue
Use this queue for queues.query_compliance_findings. It accepts only Security Hub compliance/control findings, rather than all Security Hub or GuardDuty findings.
The compliance rule is intentionally strict. It keeps only:
source = aws.securityhubdetail-type = Security Hub Findings - ImportedProductName = Security HubGeneratorIdvalues that start withsecurity-control/- findings with
Compliance.SecurityControlIdandCompliance.Status RecordState = ACTIVE
This keeps the compliance queue aligned with OCSF Compliance Finding data and avoids mixing in threat/detection findings.
Save the following template as eventbridge-sqs-compliance.yaml and deploy it:
AWSTemplateFormatVersion: "2010-09-09"
Description: >
Send Security Hub compliance/control findings to an SQS Standard queue via EventBridge.
Parameters:
QueueName:
Type: String
Default: synqly-compliance-findings
Description: "Name of the SQS Standard queue that will hold Security Hub compliance/control findings."
Resources:
SecurityEventsQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: !Ref QueueName
MessageRetentionPeriod: 1209600
VisibilityTimeout: 60
EventBridgeToSqsRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: events.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: "SendEventsToSqsPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- sqs:SendMessage
Resource: !GetAtt SecurityEventsQueue.Arn
SecurityEventsRule:
Type: AWS::Events::Rule
Properties:
Description: "Send Security Hub compliance/control findings to an SQS Standard queue"
EventBusName: "default"
State: ENABLED
EventPattern:
source:
- "aws.securityhub"
detail-type:
- "Security Hub Findings - Imported"
detail:
findings:
ProductArn:
- prefix: "arn:aws:securityhub:"
ProductName:
- "Security Hub"
GeneratorId:
- prefix: "security-control/"
Compliance:
SecurityControlId:
- exists: true
Status:
- exists: true
RecordState:
- "ACTIVE"
Targets:
- Id: "SecurityEventsQueueTarget"
Arn: !GetAtt SecurityEventsQueue.Arn
RoleArn: !GetAtt EventBridgeToSqsRole.Arn
Outputs:
QueueUrl:
Description: "URL of the SQS Standard queue that receives compliance findings"
Value: !Ref SecurityEventsQueue
QueueArn:
Description: "ARN of the SQS Standard queue that receives compliance findings"
Value: !GetAtt SecurityEventsQueue.Arn
EventBridgeRoleArn:
Description: "IAM role used by EventBridge to send messages to the SQS queue"
Value: !GetAtt EventBridgeToSqsRole.ArnThese queue settings are intentional:
MessageRetentionPeriod: 1209600keeps messages for 14 days, which is the maximum SQS retention window and gives you more time to recover if Synqly is temporarily unable to consume the queue.VisibilityTimeout: 60hides a received message for 60 seconds so Synqly can process and delete it without immediate redelivery.
Use this queue for queues.query_threats. It creates a single SQS queue and routes:
- Security Hub threat/detection findings
- Native GuardDuty findings
The threats stack uses two EventBridge rules that feed the same queue:
- A Security Hub rule that keeps active threat findings and excludes compliance/control findings by requiring
Types = ThreatsandCompliance.SecurityControlId = false - A GuardDuty rule that accepts native
GuardDuty Findingevents directly
Save the following template as eventbridge-sqs-threats.yaml and deploy it:
AWSTemplateFormatVersion: "2010-09-09"
Description: >
Send Security Hub threat/detection findings and native GuardDuty findings to an SQS Standard queue via EventBridge.
Parameters:
QueueName:
Type: String
Default: synqly-threat-findings
Description: "Name of the SQS Standard queue that will hold Security Hub threat/detection findings and GuardDuty findings."
Resources:
ThreatEventsQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: !Ref QueueName
MessageRetentionPeriod: 1209600
VisibilityTimeout: 60
EventBridgeToSqsRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: events.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: "SendThreatEventsToSqsPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- sqs:SendMessage
Resource: !GetAtt ThreatEventsQueue.Arn
SecurityHubThreatsRule:
Type: AWS::Events::Rule
Properties:
Description: "Send Security Hub threat/detection findings to an SQS Standard queue"
EventBusName: "default"
State: ENABLED
EventPattern:
source:
- "aws.securityhub"
detail-type:
- "Security Hub Findings - Imported"
detail:
findings:
RecordState:
- "ACTIVE"
Types:
- "Threats"
Compliance:
SecurityControlId:
- exists: false
Targets:
- Id: "SecurityHubThreatsQueueTarget"
Arn: !GetAtt ThreatEventsQueue.Arn
RoleArn: !GetAtt EventBridgeToSqsRole.Arn
GuardDutyThreatsRule:
Type: AWS::Events::Rule
Properties:
Description: "Send native GuardDuty findings to an SQS Standard queue"
EventBusName: "default"
State: ENABLED
EventPattern:
source:
- "aws.guardduty"
detail-type:
- "GuardDuty Finding"
Targets:
- Id: "GuardDutyThreatsQueueTarget"
Arn: !GetAtt ThreatEventsQueue.Arn
RoleArn: !GetAtt EventBridgeToSqsRole.Arn
Outputs:
QueueUrl:
Description: "URL of the SQS Standard queue that receives threat findings"
Value: !Ref ThreatEventsQueue
QueueArn:
Description: "ARN of the SQS Standard queue that receives threat findings"
Value: !GetAtt ThreatEventsQueue.Arn
EventBridgeRoleArn:
Description: "IAM role used by EventBridge to send messages to the SQS queue"
Value: !GetAtt EventBridgeToSqsRole.ArnThese queue settings are intentional:
MessageRetentionPeriod: 1209600keeps messages for 14 days, which is the maximum SQS retention window and gives you more time to recover if Synqly is temporarily unable to consume the queue.VisibilityTimeout: 60hides a received message for 60 seconds so Synqly can process and delete it without immediate redelivery.
From a directory containing the templates:
aws cloudformation deploy \
--template-file eventbridge-sqs-compliance.yaml \
--stack-name eventbridge-sqs-compliance \
--region us-east-1 \
--capabilities CAPABILITY_NAMED_IAMaws cloudformation deploy \
--template-file eventbridge-sqs-threats.yaml \
--stack-name eventbridge-sqs-threats \
--region us-east-1 \
--capabilities CAPABILITY_NAMED_IAMTo use different queue names:
--parameter-overrides QueueName=my-security-queueRecommended defaults:
- Compliance queue:
synqly-compliance-findings - Threats queue:
synqly-threat-findings
After deployment, get the Queue URL and Queue ARN from each stack:
aws cloudformation describe-stacks \
--stack-name eventbridge-sqs-compliance \
--region us-east-1 \
--query 'Stacks[0].Outputs'aws cloudformation describe-stacks \
--stack-name eventbridge-sqs-threats \
--region us-east-1 \
--query 'Stacks[0].Outputs'Copy each QueueUrl value that you want to use in the integration. The URL includes your AWS account ID, for example:
https://sqs.us-east-1.amazonaws.com/123456789012/synqly-compliance-findingshttps://sqs.us-east-1.amazonaws.com/123456789012/synqly-threat-findings
To find your account ID separately, run aws sts get-caller-identity and use the Account value.
The credential (IAM user or role) used by Synqly must have these permissions on each queue you configure:
sqs:ReceiveMessagesqs:DeleteMessagesqs:GetQueueAttributes
If you use an AdministratorAccess role, you already have them. Otherwise, create a policy with the queue ARN and attach it to the identity Synqly uses.
Get the queue ARN from the stack outputs (see Retrieve stack outputs above), or run:
aws cloudformation describe-stacks \
--stack-name eventbridge-sqs-compliance \
--region us-east-1 \
--query 'Stacks[0].Outputs[?OutputKey==`QueueArn`].OutputValue' \
--output textIf you also deploy the threats stack, repeat the same command with --stack-name eventbridge-sqs-threats.
Example policy (replace the queue ARNs with the queues you use):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:GetQueueAttributes"
],
"Resource": [
"<compliance-queue-arn>",
"<threats-queue-arn>"
]
}
]
}Attach this policy to the IAM user or role (or SSO permission set) that Synqly uses.
Synqly supports two methods for authenticating with AWS: static credentials (IAM user access keys) and role-based access (IAM role assumption). Role-based access is recommended for production environments because it uses short-lived credentials and provides better auditability through CloudTrail.
Role-Based access is recommended and is considered an AWS best practice.
Role-based access uses AWS IAM roles to grant Synqly temporary credentials to access resources in your AWS account. This eliminates long-lived credentials and provides better security through the principle of least privilege.
Create a role in your AWS account with a name that starts with SynqlyAccess (for example, SynqlyAccessS3Reader). This naming convention is required.
- In the AWS IAM console, go to Roles and choose Create role.
- For trusted entity type, choose Custom trust policy.
- Enter the following trust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::733459310821:role/SynqlyIntegrationAccess"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "YOUR_EXTERNAL_ID"
}
}
}
]
}Replace YOUR_EXTERNAL_ID with a unique identifier you generate (for example, a UUID). You will provide this External ID when configuring the integration.
- Name the role with a
SynqlyAccessprefix (for example,SynqlyAccessMyIntegration). - Attach the appropriate permissions policy for your use case.
- Create the role and note its ARN.
For more details, see:
The External ID is a security mechanism that prevents the confused deputy problem. It ensures that only authorized requests from Synqly can assume your role.
The External ID must contain only the following characters:
- Alphanumeric characters (a-z, A-Z, 0-9)
- Special characters:
+ = , . @ : / - - Must be between 2 and 1224 characters in length
When creating an AWS integration in Synqly, provide the following configuration values based on your chosen authentication method.
| Credential Parameter | Description |
|---|---|
| Role ARN | The ARN of the IAM role you created, for example arn:aws:iam::123456789012:role/SynqlyAccessMyIntegration. The role name must start with SynqlyAccess |
| External ID | The External ID you specified in the role's trust policy. This value must match exactly |
| Role Session Name | OPTIONAL: A name for the role session. If not specified, Synqly generates a default session name |
| Duration | OPTIONAL: The duration of the role session in seconds. The value can range from 900 seconds (15 minutes) up to the maximum session duration configured on your role (default is 1 hour) |
Create your integration by supplying the following configuration values.
| Integration Parameter | Description |
|---|---|
| Credential | AWS credentials with access to the SQS queue(s) (static or role-based, per the tabs above). |
| Queues | Map of operation to queue URL. Add entries for each operation you want to enable. See below. |
Synqly infers the AWS Region from the configured SQS queue URL. If you configure multiple queues, use queues from the same AWS Region.
Use the queues object to map each Cloud Security operation to its SQS queue URL. Each operation can use a different queue and EventBridge pipeline.
| Queue key | Operation | Description |
|---|---|---|
query_compliance_findings | Compliance findings | Security Hub compliance/control findings. Supported today. |
query_threats | Threats | Security Hub threat/detection findings and/or GuardDuty findings. Supported today. |
query_cloud_resource_inventory | Cloud resource inventory | Reserved for a future inventory pipeline. |
query_events | Events | Reserved for a future events pipeline. |
Compliance only:
{
"type": "cloudsecurity_awseventbridgesqs",
"credential": { "..." },
"queues": {
"query_compliance_findings": "https://sqs.us-east-1.amazonaws.com/123456789012/synqly-compliance-findings"
}
}Compliance + threats:
{
"type": "cloudsecurity_awseventbridgesqs",
"credential": { "..." },
"queues": {
"query_compliance_findings": "https://sqs.us-east-1.amazonaws.com/123456789012/synqly-compliance-findings",
"query_threats": "https://sqs.us-east-1.amazonaws.com/123456789012/synqly-threat-findings"
}
}Legacy (deprecated): You can still use queue_url for compliance findings. It is equivalent to queues.query_compliance_findings. When both are present, queues takes precedence.
Synqly retrieves up to 10 messages per query or async operation. This limit is imposed by Amazon SQS message quotas: a single ReceiveMessage request can return at most 10 messages.
Synqly treats these queues as consumable event queues. After Synqly successfully reads and processes a message, it deletes that message from SQS so it is not returned again on a later read.
You can pass a limit parameter on the API request to request fewer messages (for example, limit=5), but the maximum remains 10.