Skip to content

[RFC] Network Topology Extension for SCP #4

@ryanm101

Description

@ryanm101

RFC: Network Topology Extension for SCP

Status: Draft
Author: SCP Core Team
Created: 2026-01-14
Last Updated: 2026-01-14


Abstract

This RFC proposes extending SCP dependencies with minimal, vendor-neutral network metadata (protocol and port). This enables integrations to generate platform-specific firewall policies, validate drift, and automate network security configuration.


Motivation

Problem: Port Drift

depends:
  - system: "urn:scp:fraud-service"
    capability: "fraud-check"
# No way to know:
# - What port is used?
# - Is the firewall rule correct?
# - Did someone open port 8080 when it should be 8443?

Impact: Security vulnerabilities, failed deployments, manual port management

Current Gap

SCP models logical dependencies but lacks network-level detail needed to:

  • Validate firewall rules match declared dependencies
  • Auto-generate NetworkPolicies/Security Groups
  • Detect drift between declared architecture and deployed infrastructure

Goals

  1. Enable network validation - Validate firewall rules match declared dependencies
  2. Maintain simplicity - Store only port/protocol, not cloud-specific configs
  3. Vendor-neutral - Works with AWS, GCP, Azure, Kubernetes, etc.

Non-Goals

  1. Replace IaC - Not building Terraform/CloudFormation competitor
  2. Store cloud identifiers - No ARNs, Security Group IDs, etc. in SCP

Proposed Solution

Core Principle: "Just Enough Information"

SCP stores generic connectivity requirements. Platform-specific integrations translate this to infrastructure policies.

flowchart LR
    scp["scp.yaml<br/>(Generic Data)<br/>URN A → URN B<br/>tcp:8443"]
    json[Unified JSON Graph]

    subgraph integrations["Vendor-Specific Integrations"]
        aws["AWS Integration"]
        k8s["K8s Integration"]
        gcp["GCP Integration"]
    end

    scp -->|export| json
    json -->|reads| aws
    json -->|reads| k8s
    json -->|reads| gcp

    aws -->|creates| awssg[AWS Security Group]
    k8s -->|creates| k8spol[K8s NetworkPolicy]
    gcp -->|creates| gcpfw[GCP Firewall Rule]
Loading

Design Details

Schema Addition

# Extend dependency with network config
network:
  direction: "outbound" | "inbound"  # Which way the connection flows
  protocol: "tcp" | "udp"
  port: 8443
  port_range: [8000, 8100]  # Optional

Direction semantics:

  • outbound (default): This service initiates connection TO the dependency
  • inbound: The dependency initiates connection TO this service

[!IMPORTANT] > Use inbound sparingly. It should only be used for:

  1. External dependencies with callbacks - e.g., Stripe webhooks, PSP notifications
  2. Generic listening ports - e.g., an FTP service accepting connections from unmodelled clients

Do NOT use inbound for internal services. If Service A calls Service B, then Service A's SCP declares outbound to B. The integration will automatically infer that B needs an ingress rule from A when parsing the unified graph. Declaring inbound on B would duplicate information and create maintenance burden.

Pydantic Model

class NetworkConfig(BaseModel):
    """Generic network connectivity configuration."""
    direction: Literal["outbound", "inbound"] = "outbound"
    protocol: Literal["tcp", "udp"] | None = None
    port: int | None = None
    port_range: tuple[int, int] | None = None

class Dependency(BaseModel):
    # ... existing fields ...
    network: NetworkConfig | None = None  # NEW

Example

depends:
  # Outbound: We call the fraud service
  - system: "urn:scp:acmepay-fraud"
    capability: "fraud-check"
    type: "rest"
    criticality: "degraded"
    network:
      direction: "outbound" # We initiate connection (default)
      protocol: "tcp"
      port: 8443

  # Outbound: We connect to database
  - system: "urn:scp:acmepay-db"
    type: "data"
    criticality: "required"
    network:
      protocol: "tcp"
      port: 5432

  # Inbound: PSP sends webhooks TO us
  - system: "urn:scp:external:stripe"
    capability: "payment-webhooks"
    type: "rest"
    criticality: "degraded"
    network:
      direction: "inbound" # External service connects to us
      protocol: "tcp"
      port: 443

How Integrations Use This

Integration Outbound Action Inbound Action
AWS Creates egress Security Group rule Creates ingress Security Group rule
K8s Creates NetworkPolicy egress rule Creates NetworkPolicy ingress rule
GCP Creates egress Firewall rule Creates ingress Firewall rule

JSON Graph Output

{
  "edges": [
    {
      "from": "urn:scp:acmepay-payment",
      "to": "urn:scp:acmepay-fraud",
      "type": "DEPENDS_ON",
      "capability": "fraud-check",
      "criticality": "degraded",
      "network": {
        "direction": "outbound",
        "protocol": "tcp",
        "port": 8443
      }
    },
    {
      "from": "urn:scp:acmepay-payment",
      "to": "urn:scp:external:stripe",
      "type": "DEPENDS_ON",
      "capability": "payment-webhooks",
      "criticality": "degraded",
      "network": {
        "direction": "inbound",
        "protocol": "tcp",
        "port": 443
      }
    }
  ]
}

Use Cases

Use Case 1: Generate Firewall Rules

# Generate K8s NetworkPolicies from SCP
scp-integrations generate --platform k8s --output ./k8s/

# Generate AWS Security Groups
scp-integrations generate --platform aws --output ./terraform/

Use Case 2: Validate Drift

scp-integrations validate --platform aws

# Output:
# ✅ payment → fraud: tcp:8443 matches Security Group
# ❌ DRIFT: payment → ledger: SCP declares tcp:5432, SG allows tcp:5433

Use Case 3: Security Audit

# Find all tier-1 systems and their open ports
scp-integrations query "SELECT * FROM edges WHERE tier=1 AND network.port IS NOT NULL"

Alternatives Considered

Store cloud-specific identifiers

network:
  aws_security_group: "sg-123"
  k8s_networkpolicy: "./policies/fraud.yaml"

Rejected: Violates vendor-neutral principle, creates maintenance burden.

Store full firewall rules

network:
  egress:
    - cidr: "10.0.0.0/8"
      port: 8443

Rejected: Too complex, duplicates IaC tools.


Open Questions

Q1: Multi-port services?

Recommendation: Create multiple dependency entries for clarity.

Q2: Port ranges vs explicit ports?

Recommendation: Support both - port: 8443 for single, port_range: [8000, 8100] for ranges.


References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions