cq-source-upwind

command module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 11, 2025 License: MPL-2.0 Imports: 4 Imported by: 0

README

CloudQuery Upwind Source Plugin

Go Report Card

A CloudQuery source plugin for extracting security and vulnerability data from Upwind.

Features

  • Vulnerability Findings: Extract comprehensive vulnerability data including CVE details, CVSS scores, affected packages, container images, and cloud resources
  • Advanced Filtering: Filter vulnerabilities by exposure, exploitability, severity, cloud accounts, clusters, namespaces, and more
  • Memory Efficient: Streaming architecture handles large datasets without loading everything into memory
  • Production Ready: Built-in rate limiting, retry logic, and comprehensive error handling

Quick Start

Prerequisites
Installation
Option 1: Local Development

Build the plugin locally:

git clone https://github.com/tektite-io/cq-source-upwind.git
cd cq-source-upwind
make build
Option 2: Use with CloudQuery (after publishing)
cloudquery sync config.yml
Configuration

Create a config.yml file:

kind: source
spec:
  name: upwind
  registry: local
  path: ./cq-source-upwind
  version: v1.0.0
  tables: ["*"]
  destinations: ["postgresql"]
  
  spec:
    # Required: Upwind API credentials
    client_id: "${UPWIND_CLIENT_ID}"
    client_secret: "${UPWIND_CLIENT_SECRET}"
    organization_id: "${UPWIND_ORGANIZATION_ID}"
    
    # Optional: API region (US, EU, ME), defaults to US
    region: "US"
    
    # Optional: Performance tuning
    max_retries: 3
    max_concurrency: 10
    page_size: 100
    rate_limit_per_second: 10
    
    # Optional: Filter vulnerabilities
    vulnerability_filters:
      severity: "CRITICAL"              # Filter by severity
      is_exploitable: true              # Only exploitable vulnerabilities
      is_exposed: true                  # Only internet-exposed
      is_in_use: true                   # Only packages in use
      # cloud_account_id: "123456789"   # Filter by cloud account
      # cluster_id: "my-cluster"        # Filter by cluster
      # namespace: "production"         # Filter by namespace
      # framework: "golang"             # Filter by package framework
      # image_name: "nginx"             # Filter by image name

---
kind: destination
spec:
  name: postgresql
  path: cloudquery/postgresql
  registry: cloudquery
  version: "v8.12.2"
  
  spec:
    connection_string: "${DATABASE_URL}"

Set your environment variables:

export UPWIND_CLIENT_ID="your-client-id"
export UPWIND_CLIENT_SECRET="your-client-secret"
export UPWIND_ORGANIZATION_ID="your-org-id"
export DATABASE_URL="postgresql://user:pass@localhost:5432/dbname"

Run the sync:

cloudquery sync config.yml

Configuration Reference

Authentication (Required)
Field Type Description
client_id string OAuth2 client ID from Upwind
client_secret string OAuth2 client secret from Upwind
organization_id string Your Upwind organization ID
region string API region: US, EU, or ME (default: US)
Performance Tuning (Optional)
Field Type Default Description
max_retries int 3 Maximum retry attempts for failed requests
max_concurrency int 10 Maximum concurrent API requests
page_size int 100 Page size for paginated requests (1-10000)
rate_limit_per_second int 10 Maximum requests per second (0 = no limit)
Vulnerability Filters (Optional)

All filters are optional and can be combined:

Field Type Description
cloud_account_id string Filter by cloud account ID
cluster_id string Filter by Kubernetes cluster ID
namespace string Filter by Kubernetes namespace
is_exposed bool Filter by internet exposure (ingress active communication)
has_internet_exposure bool Filter by internet exposure
is_in_use bool Filter by whether package is in use
is_exploitable bool Filter by exploitability
is_fixed bool Filter by fix availability
severity string Filter by severity: LOW, MEDIUM, HIGH, CRITICAL
image_name string Filter by container image name (partial match)
framework string Filter by package framework

Tables

upwind_vulnerability_findings

Vulnerability findings with comprehensive context including CVE details, CVSS scores, affected packages, container images, and cloud resources.

Schema: 44 columns including:

  • Core finding metadata (ID, status, source, timestamps)
  • Vulnerability details (CVE ID, CVSS v2/v3/v4 scores, exploitability)
  • Container image information (name, digest, registry, OS)
  • Package details (name, version, framework, usage status)
  • Cloud resource context (accounts, regions, clusters, namespaces, exposure)

For detailed schema, see generated documentation.

Example Queries

Critical Exploitable Vulnerabilities
SELECT 
  vulnerability_nvd_cve_id,
  vulnerability_nvd_cvss_v3_score,
  package_name,
  package_version,
  resource_name,
  resource_namespace
FROM upwind_vulnerability_findings
WHERE vulnerability_exploitable = true
  AND vulnerability_nvd_cvss_v3_severity = 'CRITICAL'
ORDER BY vulnerability_nvd_cvss_v3_score DESC;
Internet-Exposed Vulnerabilities
SELECT 
  vulnerability_nvd_cve_id,
  resource_name,
  resource_namespace,
  image_name,
  vulnerability_nvd_cvss_v3_severity
FROM upwind_vulnerability_findings
WHERE resource_internet_exposure_ingress_active_communication = true
ORDER BY 
  CASE vulnerability_nvd_cvss_v3_severity
    WHEN 'CRITICAL' THEN 1
    WHEN 'HIGH' THEN 2
    WHEN 'MEDIUM' THEN 3
    WHEN 'LOW' THEN 4
  END;
Vulnerability Summary by Severity
SELECT 
  vulnerability_nvd_cvss_v3_severity,
  COUNT(*) as count,
  COUNT(DISTINCT vulnerability_nvd_cve_id) as unique_cves,
  COUNT(DISTINCT resource_name) as affected_resources
FROM upwind_vulnerability_findings
GROUP BY vulnerability_nvd_cvss_v3_severity
ORDER BY 
  CASE vulnerability_nvd_cvss_v3_severity
    WHEN 'CRITICAL' THEN 1
    WHEN 'HIGH' THEN 2
    WHEN 'MEDIUM' THEN 3
    WHEN 'LOW' THEN 4
  END;
Vulnerabilities by Cloud Account
SELECT 
  resource_cloud_account_name,
  COUNT(DISTINCT vulnerability_nvd_cve_id) as unique_cves,
  COUNT(*) as total_findings,
  SUM(CASE WHEN vulnerability_nvd_cvss_v3_severity = 'CRITICAL' THEN 1 ELSE 0 END) as critical,
  SUM(CASE WHEN vulnerability_nvd_cvss_v3_severity = 'HIGH' THEN 1 ELSE 0 END) as high
FROM upwind_vulnerability_findings
GROUP BY resource_cloud_account_name
ORDER BY critical DESC, high DESC;

Development

Building
make build
Running as gRPC Server (for debugging)

Terminal 1:

make serve

Terminal 2:

# Update config.yml to use grpc registry
cloudquery sync config.yml
Testing
make test
Code Quality
make fmt      # Format code
make lint     # Run linter
make verify   # Run all checks

Troubleshooting

Authentication Errors

Error: 401 Unauthorized or failed to create Upwind client

Solution: Verify your credentials are correct:

echo $UPWIND_CLIENT_ID
echo $UPWIND_CLIENT_SECRET
echo $UPWIND_ORGANIZATION_ID

Ensure the region setting matches your Upwind account region.

Rate Limiting

Error: 429 Too Many Requests

Solution: Reduce request rate in your configuration:

spec:
  spec:
    rate_limit_per_second: 5
    max_concurrency: 5
Memory Issues

Solution: Reduce page size and apply filters:

spec:
  spec:
    page_size: 50
    vulnerability_filters:
      severity: "CRITICAL"
      is_exploitable: true
Configuration Errors

Error: json: unknown field "client_id"

Solution: Ensure plugin configuration is nested under spec.spec:

kind: source
spec:
  name: upwind
  tables: ["*"]
  destinations: ["postgresql"]
  
  spec:  # Plugin config goes here
    client_id: "..."
    client_secret: "..."

Architecture

  • Streaming: Memory-efficient channel-based streaming from Upwind API
  • Concurrency: Configurable concurrent requests for optimal performance
  • Resilience: Automatic retry with exponential backoff
  • Observability: Structured logging with zerolog

License

This project is licensed under the Mozilla Public License Version 2.0 - see the LICENSE file for details.

Support

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
resources

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL