Custom Resources

Specifications for all 7 unbounded-net CRDs.

unbounded-net uses seven Custom Resource Definitions (CRDs) in the net.unbounded-cloud.io API group. For a conceptual introduction to Sites and GatewayPools, see Networking Concepts.

Site

A Site represents a network location containing nodes. Nodes are automatically assigned to sites based on their internal IP addresses matching the site’s nodeCidrs.

Example

apiVersion: net.unbounded-cloud.io/v1alpha1
kind: Site
metadata:
  name: site-east
spec:
  nodeCidrs:
    - "10.0.0.0/16"
    - "10.1.0.0/16"
  podCidrAssignments:
    - assignmentEnabled: true
      cidrBlocks:
        - "100.64.0.0/16"
        - "fdde:1::/48"
      nodeBlockSizes:
        ipv4: 24
        ipv6: 80
      nodeRegex:
        - "^worker-.*"
      priority: 100
  manageCniPlugin: true

Spec Fields

FieldTypeRequiredDescription
spec.nodeCidrs[]stringYesCIDR blocks containing internal IPs of nodes at this site.
spec.podCidrAssignments[]PodCidrAssignmentNoPod CIDR allocation rules for this site.
spec.manageCniPlugin*boolNoControls CNI and WireGuard behavior (default: true).
spec.nonMasqueradeCIDRs[]stringNoCIDRs that should NOT be masqueraded when traffic leaves via the default gateway.
spec.localCidrs[]stringNoCIDRs considered local; traffic to these is never routed via gateway pools.
spec.healthCheckSettingsHealthCheckSettingsNoHealth check settings for node-to-node routes within this site.
spec.tunnelProtocolstringNoWireGuard, IPIP, GENEVE, VXLAN, None, or Auto (default).
spec.tunnelMTU*int32NoTunnel MTU for routes in this scope (576-9000).

PodCidrAssignment Fields

FieldTypeRequiredDescription
assignmentEnabled*boolNoEnables this assignment (default: true).
cidrBlocks[]stringNoCIDR pools to allocate from (IPv4 and/or IPv6).
nodeBlockSizes.ipv4intNoIPv4 subnet size for node allocations (default: /24).
nodeBlockSizes.ipv6intNoIPv6 subnet size for node allocations (default: pool prefix + 16).
nodeRegex[]stringNoRegex patterns to match node names. Empty means no filtering.
priority*int32NoAssignment priority; lower values win (default: 100).

Status Fields

FieldTypeDescription
status.nodeCountintNumber of nodes assigned to this site.
status.sliceCountintNumber of SiteNodeSlice objects.

manageCniPlugin Behavior

ValueCNI ConfigSame-Site WireGuardGateway WireGuard
true (default)WrittenCreatedCreated
falseNot writtenNot createdCreated

Set to false when using an external CNI plugin (e.g., Cilium, Calico) for intra-site networking while unbounded-net handles only cross-site routing.

Admission Validation

  • nodeCidrs must be valid CIDRs and cannot overlap across sites.
  • Pod CIDR assignment blocks cannot overlap across sites.
  • Pod CIDR mask sizes must be consistent within a site.
  • IPv6 masks must be no more than 16 bits larger than the pool prefix.
  • nodeRegex values must be valid regex patterns.
  • Sites with active nodes cannot be deleted.

SiteNodeSlice

Contains a slice of nodes belonging to a site. Each slice holds up to 500 nodes to prevent exceeding Kubernetes object size limits.

Automatically managed by the controller. Do not create, modify, or delete these manually. They are owned by their parent Site and garbage collected when the Site is deleted.

Example

apiVersion: net.unbounded-cloud.io/v1alpha1
kind: SiteNodeSlice
metadata:
  name: site-east-0
  ownerReferences:
    - apiVersion: net.unbounded-cloud.io/v1alpha1
      kind: Site
      name: site-east
siteName: site-east
sliceIndex: 0
nodeCount: 2
nodes:
  - name: node-001
    wireGuardPublicKey: "abc123...="
    internalIPs: ["10.0.1.5"]
    podCIDRs: ["100.64.0.0/24", "fdde:1::100/80"]
  - name: node-002
    wireGuardPublicKey: "def456...="
    internalIPs: ["10.0.1.6"]
    podCIDRs: ["100.64.1.0/24"]

Fields

FieldTypeRequiredDescription
siteNamestringYesParent Site name.
sliceIndexintYesZero-based index of this slice.
nodeCountintNoNumber of nodes in this slice.
nodes[].namestringYesNode name.
nodes[].wireGuardPublicKeystringNoWireGuard public key.
nodes[].internalIPs[]stringNoInternal IP addresses.
nodes[].podCIDRs[]stringNoPod CIDRs assigned to this node.

Deletion is blocked while a slice still references active nodes.


GatewayPool

Defines a pool of gateway nodes selected by labels. Gateway nodes route traffic between sites.

Example

apiVersion: net.unbounded-cloud.io/v1alpha1
kind: GatewayPool
metadata:
  name: main-gateways
spec:
  type: External
  nodeSelector:
    net.unbounded-cloud.io/gateway: "true"
  routedCidrs:
    - "172.16.0.0/12"
  healthCheckSettings:
    enabled: true
  tunnelProtocol: Auto

Spec Fields

FieldTypeRequiredDescription
spec.typestringNoExternal (default) or Internal. Controls IP resolution for cross-site connections.
spec.nodeSelectormap[string]stringYesLabel selector for gateway nodes.
spec.routedCidrs[]stringNoAdditional CIDRs routed through this pool.
spec.healthCheckSettingsHealthCheckSettingsNoHealth check settings for routes to peers.
spec.tunnelProtocolstringNoTunnel encapsulation (default: Auto).
spec.tunnelMTU*int32NoTunnel MTU (576-9000).

Status Fields

FieldTypeDescription
status.nodeCountintNumber of nodes in the pool.
status.connectedSites[]stringSites directly connected via peering.
status.reachableSites[]stringAll reachable sites (including transitive).
status.nodes[].namestringNode name.
status.nodes[].siteNamestringNode’s site.
status.nodes[].internalIPs[]stringInternal IPs.
status.nodes[].externalIPs[]stringExternal IPs.
status.nodes[].healthEndpoints[]stringHealth check IPs.
status.nodes[].wireGuardPublicKeystringWireGuard public key.
status.nodes[].gatewayWireguardPortint32WireGuard listen port (assigned by controller, starting at 51821).
status.nodes[].podCIDRs[]stringPod CIDRs.

Gateway Node Requirements

A node is included in the pool status when it:

  1. Matches the nodeSelector labels.
  2. Has a WireGuard public key annotation.

Gateway Peer IP Resolution

ConditionIP Used
Same siteInternal IP
Sites are network-peered (SitePeering)Internal IP
Pool type is External, different siteExternal IP
Pool type is Internal, different siteNo endpoint (WireGuard learns)

Deletion is blocked while a pool has active matching nodes.


GatewayPoolNode

Represents an individual node’s membership in a gateway pool. Automatically created by the controller; the node agent patches status with route advertisements and heartbeat timestamps.

Automatically managed. Do not create or modify manually.

Fields

FieldTypeRequiredDescription
spec.nodeNamestringYesKubernetes node name.
spec.gatewayPoolstringYesParent GatewayPool.
spec.sitestringNoSite name (from node labels).
status.lastUpdatedstringLast heartbeat timestamp.
status.routesmap[string]GatewayNodeRouteRoute advertisements keyed by CIDR.

SitePeering

Defines direct peering between sites. When meshNodes is true (default), nodes in peered sites create direct WireGuard tunnels, bypassing gateways.

Example

apiVersion: net.unbounded-cloud.io/v1alpha1
kind: SitePeering
metadata:
  name: east-west-peering
spec:
  sites:
    - "site-east"
    - "site-west"
    - "site-central"
  meshNodes: true
  healthCheckSettings:
    enabled: true
    detectMultiplier: 3
    receiveInterval: 300ms
    transmitInterval: 300ms
  tunnelProtocol: Auto

Spec Fields

FieldTypeRequiredDescription
spec.enabled*boolNoWhether active (default: true).
spec.sites[]stringNoSites to peer (min 2).
spec.meshNodes*boolNoDirect node-to-node tunnels (default: true). When false, sites are network-peered but nodes don’t mesh directly.
spec.healthCheckSettingsHealthCheckSettingsNoHealth check settings for inter-site routes.
spec.tunnelProtocolstringNoTunnel encapsulation (default: Auto).
spec.tunnelMTU*int32NoTunnel MTU (576-9000).

Status Fields

FieldTypeDescription
status.peeredSiteCountintNumber of peered sites that exist.
status.totalNodeCountintTotal nodes across peered sites.

Behavior

meshNodesEffect
true (default)Direct node-to-node WireGuard tunnels. Traffic bypasses gateways. Pod CIDRs from all peered sites combined in route table.
falseNo direct tunnels. Gateway pool peerings between these sites use internal IPs instead of external IPs. Combine with tunnelProtocol: None for externally-peered sites.

Use Cases

  • Low-latency cross-site: Sites with fast connectivity (same cloud region, dedicated interconnect). Use meshNodes: true for direct WireGuard tunnels.

  • Externally peered sites (ExpressRoute, Direct Connect, VPN): Two sites already connected over a private L3 link can be merged into one logical network. Use meshNodes: false and tunnelProtocol: None to route pod traffic directly over the existing connection with zero encapsulation overhead. WireGuard is still available for any other site pairs in the same cluster.

    spec:
      sites:
        - site-on-prem
        - site-azure
      meshNodes: false
      tunnelProtocol: None
    
  • Large sites without full mesh: Use meshNodes: false to avoid O(n²) tunnels while still benefiting from internal IP routing via gateways.


SiteGatewayPoolAssignment

Defines which gateway pools serve which sites.

Example

apiVersion: net.unbounded-cloud.io/v1alpha1
kind: SiteGatewayPoolAssignment
metadata:
  name: east-gateways
spec:
  sites:
    - "site-east"
  gatewayPools:
    - "main-gateways"
    - "backup-gateways"
  healthCheckSettings:
    enabled: true
  tunnelProtocol: Auto

Spec Fields

FieldTypeRequiredDescription
spec.enabled*boolNoWhether active (default: true).
spec.sites[]stringNoSites to assign.
spec.gatewayPools[]stringNoGateway pools to assign.
spec.healthCheckSettingsHealthCheckSettingsNoHealth check settings for site-to-pool routes.
spec.tunnelProtocolstringNoOverrides Site’s tunnelProtocol for gateway peer connections. Falls back to Site’s setting when Auto or nil.
spec.tunnelMTU*int32NoTunnel MTU (576-9000).

GatewayPoolPeering

Defines peering between gateway pools, enabling cross-pool routing.

Example

apiVersion: net.unbounded-cloud.io/v1alpha1
kind: GatewayPoolPeering
metadata:
  name: east-west-pool-peering
spec:
  gatewayPools:
    - "east-gateways"
    - "west-gateways"
  healthCheckSettings:
    enabled: true
  tunnelProtocol: Auto

Spec Fields

FieldTypeRequiredDescription
spec.enabled*boolNoWhether active (default: true).
spec.gatewayPools[]stringNoPools to peer.
spec.healthCheckSettingsHealthCheckSettingsNoHealth check settings.
spec.tunnelProtocolstringNoTunnel encapsulation (default: Auto).
spec.tunnelMTU*int32NoTunnel MTU (576-9000).

HealthCheckSettings

The healthCheckSettings object is shared across Site, SitePeering, GatewayPool, SiteGatewayPoolAssignment, and GatewayPoolPeering:

FieldTypeDefaultDescription
enabled*booltrueEnable health checks for routes in this scope.
detectMultiplier*int323Number of consecutive failures before marking unhealthy.
receiveIntervalstring300msExpected interval between received probes.
transmitIntervalstring300msInterval between sent probes.

Precedence

  • Same-site routes: Site.spec.healthCheckSettings
  • Peered-site routes: SitePeering.spec.healthCheckSettings
  • Gateway pool routes: SiteGatewayPoolAssignment.spec.healthCheckSettingsGatewayPool.spec.healthCheckSettingsSite.spec.healthCheckSettings

If multiple peerings define conflicting settings, peerings are processed in deterministic name order and the first profile is kept.


Labels, Annotations, and Taints

Labels

LabelApplied ToDescription
net.unbounded-cloud.io/siteNodeSite membership (set by controller).

Annotations

AnnotationApplied ToDescription
net.unbounded-cloud.io/wg-pubkeyNodeWireGuard public key (set by node agent).

Taints

TaintEffectDescription
net.unbounded-cloud.io/gateway-node=trueNoSchedulePrevents regular workloads on gateway nodes.

Short Names

ResourceShort NameExample
Sitestkubectl get st
SiteNodeSlicesnskubectl get sns
GatewayPoolgpkubectl get gp
GatewayPoolNodegpnkubectl get gpn
SitePeeringsprkubectl get spr
SiteGatewayPoolAssignmentsgpakubectl get sgpa
GatewayPoolPeeringgppkubectl get gpp

CRD Relationships

Networking CRD relationships: Site owns SiteNodeSlice and contains Nodes, GatewayPool selects Nodes and contains GatewayPoolNodes, SitePeering peers Sites, SiteGatewayPoolAssignment assigns Site to GatewayPool, GatewayPoolPeering peers GatewayPools

Next Steps