Skip to content
dukebolesPublic

About

Scan an AWS account for TLS endpoints that permit or actually negotiate CBC-mode cipher suites, with concrete remediation for every finding.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

cbcscan

Scan an AWS account for TLS endpoints that permit — or have actually negotiated — CBC-mode cipher suites, and get a concrete fix for every finding.

The goal: eliminate any possibility of a connection to your account being made with a CBC-family cipher.

What it checks

Scanner key Surface How ciphers are determined
alb-nlb ALB/NLB HTTPS & TLS listeners live, via elbv2 describe-ssl-policies
clb Classic ELB SSL negotiation policies live, per-cipher policy attributes
cloudfront Distribution viewer security policies (global) docs-derived static map, classifier-verified
apigw API Gateway custom domains (REST + HTTP/WS) AWS-managed: even TLS_1_2 includes CBC → flagged as not-removable
opensearch Domain endpoint TLS policies conservative: 2019 policies flagged; PFS-2023-10 gets a probe-to-verify INFO finding
lightsail Lightsail load balancer TLS policies live, via get-load-balancer-tls-policies

With --usage, it additionally queries access logs via Athena (ALB, NLB, CLB, CloudFront — each records the negotiated cipher per connection) and reports every resource where clients actually negotiated CBC in the lookback window, including per-cipher connection counts and sample client IPs so you can find the offending clients before you break them.

TLS-serving resources with access logging disabled get a NO_VISIBILITY finding — you cannot prove CBC absence without logs.

Finding types

Type Severity Meaning
OBSERVED_CBC_CONNECTIONS CRITICAL real clients negotiated CBC in the lookback window
CONFIG_ALLOWS_CBC HIGH configuration permits CBC (INFO when unverifiable)
CBC_NOT_REMOVABLE MEDIUM AWS-managed cipher list includes CBC and cannot be tightened
NO_VISIBILITY MEDIUM TLS served, but no access logs to verify actual usage

Every report also lists blind spots (self-managed TLS on EC2, API Gateway default endpoints, AWS service endpoints, managed-service data planes) so a clean scan is never mistaken for "no CBC anywhere".

Install

Requires Python 3.11+.

uv venv && uv pip install -e .        # or: pip install -e .

Usage

# Config scan (read-only, no side effects)
cbcscan scan --region us-east-1 --profile myprofile

# Config + actual-usage scan via Athena
cbcscan scan --region us-east-1 --usage --days 30 \
  --athena-output s3://my-athena-results/cbcscan/

# Outputs and CI
cbcscan scan --region us-east-1 --output findings.json --html report.html --fail-on high

cbcscan list-services       # available scanner keys for --services

Exit codes: 0 clean, 2 findings at/above --fail-on threshold, 1 runtime/auth error.

Notes:

  • CloudFront is a global service; it is scanned regardless of --region.
  • The tool never modifies AWS configuration. In --usage mode the only side effects are a Glue database/tables named cbcscan and Athena query results written to --athena-output.
  • Athena cost is ~$5/TB scanned. ALB/NLB/CLB tables use date partition projection, so --days bounds the scan. CloudFront legacy standard logs are unpartitioned — the whole log prefix is scanned (the tool warns when this happens); consider CloudFront standard logging v2 with partitioning.

Required IAM permissions

Config scan (pure read-only):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CbcscanConfigScan",
      "Effect": "Allow",
      "Action": [
        "sts:GetCallerIdentity",
        "elasticloadbalancing:Describe*",
        "cloudfront:ListDistributions",
        "cloudfront:GetDistributionConfig",
        "apigateway:GET",
        "es:ListDomainNames",
        "es:DescribeDomains",
        "lightsail:GetLoadBalancers",
        "lightsail:GetLoadBalancerTlsPolicies"
      ],
      "Resource": "*"
    }
  ]
}

Usage mode additionally needs:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CbcscanAthena",
      "Effect": "Allow",
      "Action": [
        "athena:StartQueryExecution",
        "athena:GetQueryExecution",
        "athena:GetQueryResults",
        "athena:StopQueryExecution",
        "athena:GetWorkGroup",
        "glue:CreateDatabase",
        "glue:GetDatabase",
        "glue:CreateTable",
        "glue:GetTable",
        "glue:UpdateTable"
      ],
      "Resource": "*"
    },
    {
      "Sid": "CbcscanReadLogBuckets",
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:ListBucket", "s3:GetBucketLocation"],
      "Resource": ["arn:aws:s3:::<log-bucket>", "arn:aws:s3:::<log-bucket>/*"]
    },
    {
      "Sid": "CbcscanAthenaResults",
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:ListBucket", "s3:GetBucketLocation"],
      "Resource": ["arn:aws:s3:::<athena-results-bucket>", "arn:aws:s3:::<athena-results-bucket>/*"]
    }
  ]
}

End-to-end smoke test (against a test account)

  1. Create an ALB with an HTTPS listener pinned to ELBSecurityPolicy-2016-08 and access logs enabled to a test bucket.
  2. cbcscan scan --region us-east-1 → expect a CONFIG_ALLOWS_CBC finding listing suites like ECDHE-RSA-AES128-SHA256, AES128-SHA, and the exact modify-listener remediation command; exit code 2.
  3. Generate CBC traffic, then wait ~5 minutes for log delivery:
    curl --ciphers ECDHE-RSA-AES128-SHA256 --tls-max 1.2 -k https://<alb-dns>/
  4. cbcscan scan --region us-east-1 --usage --days 1 --athena-output s3://<results-bucket>/cbcscan/ → expect OBSERVED_CBC_CONNECTIONS with the cipher count and your source IP.
  5. Apply the emitted remediation command verbatim and re-run — the finding disappears, and the curl from step 3 now fails to handshake. That failure is the point: CBC is no longer possible on that endpoint.
  6. Disable the ALB's access logs and re-run → expect a NO_VISIBILITY finding.

Development

uv pip install -e ".[dev]"
pytest            # 137 tests: classifier tables, per-scanner moto/Stubber, Athena state machine, CLI contract
ruff check src tests

Adding a service scanner: subclass cbcscan.scanners.base.Scanner, implement scan() (and discover_log_sources() if the service writes access logs with cipher fields), and register the class in cbcscan/scanners/__init__.py.

About

Scan an AWS account for TLS endpoints that permit or actually negotiate CBC-mode cipher suites, with concrete remediation for every finding.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages