Connecting your AWS account(s)
This is the complete, do-it-once setup to let the platform scan your AWS for misconfigurations and compliance gaps. It is agentless and read-only: you never give us an access key or password — you create a read-only IAM role in your own account that we assume cross-account, locked to a secret External ID that only you and we hold.
You have two paths:
- Path A — a single AWS account (CloudFormation). 5 minutes.
- Path B — a whole AWS Organization (StackSet) — every account at once, and new accounts automatically. Use this if you have an AWS Organization.
Both end the same way: validate access, then run your first scan.
:::info What we can and cannot see
The role grants AWS's own SecurityAudit + ViewOnlyAccess policies plus
a short list of extra read/list/describe permissions for full posture coverage.
No write access. No reading your data (no object downloads from S3, no database
rows) — only configuration and metadata. The full permission list is in the
template you deploy; nothing is hidden.
:::
Before you start
From the platform (your console → Cloud → Connect AWS account), click Add account. You'll be shown two values — keep them handy:
| Value | What it is |
|---|---|
| External ID | A per-customer secret we mint for you. It stops anyone else from tricking us into assuming your role ("confused deputy"). Treat it like a password. |
| Assumer ARN | Our identity that your role will trust. You paste this into the template. |
Behind the scenes this is the API call POST /org/aws/accounts (your UI does it
for you); the account is created in state pending until you finish the steps
below and validate.
The template you deploy
Both paths below deploy the same CloudFormation template,
customer-readonly-role.yaml. It creates one IAM role that trusts our Assumer
ARN (gated by your External ID) and grants AWS's SecurityAudit +
ViewOnlyAccess plus the read/list/describe permissions a full posture scan
needs — no write access, no data reads. The platform links you a pre-filled
copy, or copy it here:
customer-readonly-role.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: >
Binary Networks Scanners - read-only CSPM role. Creates an IAM role that the
Binary Networks scanner assumes (cross-account, External ID gated) to run a
read-only posture scan. SecurityAudit + ViewOnlyAccess + the documented extra
read permissions. No write access, no data-object reads.
Deploy as a single stack (one account) or via a StackSet (whole AWS Organization).
Parameters:
AssumerRoleArn:
Type: String
Description: The Binary Networks principal allowed to assume this role (the Assumer ARN from the platform).
AllowedPattern: "arn:aws:iam::[0-9]{12}:(role|user)/.+"
ExternalId:
Type: String
Description: Per-customer External ID (confused-deputy guard). Provided by Binary Networks.
MinLength: 16
NoEcho: true
RoleName:
Type: String
Default: BinaryNetworksScannerReadOnly
Description: Name of the read-only role to create.
Resources:
ScannerReadOnlyRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Ref RoleName
Description: Read-only role assumed by Binary Networks Scanners for CSPM.
MaxSessionDuration: 3600
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS: !Ref AssumerRoleArn
Action: sts:AssumeRole
Condition:
StringEquals:
sts:ExternalId: !Ref ExternalId
ManagedPolicyArns:
- arn:aws:iam::aws:policy/SecurityAudit
- arn:aws:iam::aws:policy/job-function/ViewOnlyAccess
Policies:
- PolicyName: ProwlerAdditions
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- account:Get*
- appstream:Describe*
- appstream:List*
- backup:List*
- cloudtrail:GetInsightSelectors
- codeartifact:List*
- codebuild:BatchGet*
- cognito-idp:GetUserPoolMfaConfig
- dlm:Get*
- drs:Describe*
- ds:Get*
- ds:Describe*
- ds:List*
- dynamodb:GetResourcePolicy
- ec2:GetEbsEncryptionByDefault
- ec2:GetSnapshotBlockPublicAccessState
- ec2:GetInstanceMetadataDefaults
- ecr:Describe*
- ecr:GetRegistryScanningConfiguration
- elasticfilesystem:DescribeBackupPolicy
- glue:GetConnections
- glue:GetSecurityConfiguration*
- glue:SearchTables
- lambda:GetFunction*
- logs:FilterLogEvents
- macie2:GetMacieSession
- s3:GetAccountPublicAccessBlock
- shield:DescribeProtection
- shield:GetSubscriptionState
- securityhub:BatchImportFindings
- securityhub:GetFindings
- ssm:GetDocument
- ssm-incidents:List*
- support:Describe*
- tag:GetTagKeys
- wellarchitected:List*
Resource: "*"
Tags:
- Key: ManagedBy
Value: BinaryNetworksScanners
- Key: Purpose
Value: CSPM-ReadOnly
Outputs:
RoleArn:
Description: Paste this ARN back into the Binary Networks console to finish connecting.
Value: !GetAtt ScannerReadOnlyRole.Arn
AccountId:
Description: The AWS account this role was created in.
Value: !Ref AWS::AccountId
Path A — single account (CloudFormation)
Do this in the AWS account you want scanned.
1. Deploy the read-only role
Console:
- Open CloudFormation → Create stack → With new resources.
- Upload the template
customer-readonly-role.yaml(provided by us / linked in the platform). - Fill the parameters:
- AssumerRoleArn — the Assumer ARN from the platform.
- ExternalId — the External ID from the platform.
- RoleName — leave the default
BinaryNetworksScannerReadOnly.
- Acknowledge that the stack creates an IAM role and click Create stack.
- When it shows
CREATE_COMPLETE, open the Outputs tab and copyRoleArn.
CLI equivalent:
aws cloudformation deploy \
--template-file customer-readonly-role.yaml \
--stack-name binarynetworks-scanner-role \
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides \
AssumerRoleArn="arn:aws:iam::<our-account>:role/BinaryNetworksScannerAssumer" \
ExternalId="<your-external-id>"
# then read the role ARN back:
aws cloudformation describe-stacks --stack-name binarynetworks-scanner-role \
--query "Stacks[0].Outputs[?OutputKey=='RoleArn'].OutputValue" --output text
2. Paste the role ARN back
In the platform, paste the RoleArn into the account you just added and save.
That's the whole connection. Now validate.
Path B — whole organization (StackSet)
If you run an AWS Organization, deploy the same read-only role to every member account in one operation — and have it land in new accounts automatically as your org grows. No per-account clicking.
:::note One-time org prerequisite
Service-managed StackSets need, in your management account:
Organizations → all features enabled, and trusted access for CloudFormation
StackSets turned on (CloudFormation offers a one-click button the first time, or
run aws organizations enable-aws-service-access --service-principal member.org.stacksets.cloudformation.amazonaws.com).
:::
1. Create the StackSet (management or delegated-admin account)
Console:
- CloudFormation → StackSets → Create StackSet.
- Permissions: Service-managed permissions.
- Upload
customer-readonly-role.yaml; set the same parameters as Path A (AssumerRoleArn, ExternalId, keep RoleName default). - Deployment targets: your entire organization, or pick specific OUs.
- Automatic deployment: Enabled — new accounts that join get the role with no further action.
- Regions: pick one (e.g.
us-east-1). IAM is global, so one region is enough — do not fan it out to every region. - Create, and wait for the StackSet operation to reach SUCCEEDED.
CLI equivalent:
aws cloudformation create-stack-set \
--stack-set-name binarynetworks-scanner-role \
--template-body file://customer-readonly-role.yaml \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false \
--capabilities CAPABILITY_NAMED_IAM \
--parameters \
ParameterKey=AssumerRoleArn,ParameterValue="arn:aws:iam::<our-account>:role/BinaryNetworksScannerAssumer" \
ParameterKey=ExternalId,ParameterValue="<your-external-id>"
# deploy to the whole org (or pass OU ids instead of the root):
aws cloudformation create-stack-instances \
--stack-set-name binarynetworks-scanner-role \
--deployment-targets OrganizationalUnitIds=<r-xxxx-root-or-ou-id> \
--regions us-east-1
2. Register each account in the platform
Every account now has a role with the same name — only the account number differs:
arn:aws:iam::<ACCOUNT_ID>:role/BinaryNetworksScannerReadOnly
Add each AWS account you want scanned in the platform (same Add account flow); the External ID is shared across your org, so you reuse it. Paste each account's ARN (swap in its account number).
You can list your org's account IDs with
aws organizations list-accounts --query "Accounts[].Id" --output text.
(Auto-discovering org accounts so you don't register them one by one is on our
roadmap; today you add the accounts you want in scope.)
3. Validate access
Before any scan, confirm the role works. In the platform click Validate on the
account (API: POST /org/aws/accounts/{id}/validate). We do a live test
role-assumption through the cross-account chain and report back:
validated✓ — access works; the account is ready to scan.invalid✗ — with the reason (wrong External ID, ARN typo, role not yet propagated). Fix and re-validate.
Check overall readiness any time with the status endpoint
(GET /org/aws/status → { enabled, validated_accounts, can_run }).
4. Run your first scan
Once at least one account is validated:
- Platform: Cloud → Run scan.
- API:
POST /org/scans { "module": "aws" }.
The scan runs one read-only pass per connected account and returns when done. It is
gated on a validated account (you'll get a 409 if none is validated yet), and the
normal one-scan-per-14-days cooldown applies (independent of EASM/DAST).
When it finishes you'll have:
- Findings — the failures, grouped by issue with the affected resources listed and a "5 of 20 remaining" rollup.
- Full posture — every pass and fail (
GET /org/aws/results), filterable by service, severity, account, region. - Compliance — pick any framework (
GET /org/aws/frameworkslists them) and get an overall score plus a control-by-control breakdown (GET /org/aws/compliance?framework=CIS-3.0→ e.g. "247/300, 82% passing"). One scan reports against every framework — CIS, ISO 27001, SOC 2, NIST, PCI, HIPAA, and ~50 more. The framework is a view, never a re-scan.
5. Fix, then prove it's fixed
Cloud findings use the same lifecycle as the rest of the platform, tracked per resource:
- Mark a finding In Progress / Resolved / Accepted Risk / False Positive.
- Fix it in AWS.
- Rescan. Resolution is confirmed by the scan, not by the click: a finding you marked Resolved closes when the next scan no longer sees it; a fix you didn't triage auto-closes after 2 consecutive clean scans. If a closed issue comes back it reopens (regression). Fix 15 of 20 affected resources and exactly those 15 close — the other 5 stay open.
A finding that keeps showing up across scans is flagged recurring so you can spot what isn't sticking.
Troubleshooting
| Symptom | Cause / fix |
|---|---|
Validate returns invalid: AccessDenied | External ID mismatch, or the role's trust policy doesn't list our Assumer ARN. Re-check both template parameters. |
Validate returns invalid: role not found | Wrong account number in the ARN, or the stack/StackSet instance hasn't finished. Wait for CREATE_COMPLETE / SUCCEEDED. |
| StackSet won't create | Trusted access for StackSets isn't enabled in the org, or you're not in the management / delegated-admin account. |
| New org accounts aren't scanned | Auto-deployment puts the role there automatically, but you still register the account in the platform to bring it in scope. |
| "Can you see our data?" | No. Read-only config/metadata only (SecurityAudit + ViewOnlyAccess + read/list/describe). The template is the full, auditable list. |
What we never expose
The scanning engine is white-labeled end to end: it isn't named in your findings, and in your own CloudTrail the scanner's API calls carry our product's user-agent and role-session name — not the underlying tool's. You see Binary Networks Scanner, nothing else.