[vpc] Add VPC peering support for multi-tenant environments
Implement bilateral VPC peering using Kube-OVN's native vpcPeerings mechanism. Each VPC can declare peers by specifying the remote VPC name and tenant namespace. Peering is only activated by Kube-OVN when both sides declare each other, ensuring mutual consent. Key features: - Deterministic remote VPC ID resolution via sha256 hash - Auto-allocated link-local peering IPs (169.254.0.0/16) derived from sorted pair hash, eliminating manual IP coordination - Static routes support for fine-grained inter-VPC routing - ConfigMap enrichment with peer discovery info - Schema validation enforcing tenant- namespace prefix pattern Signed-off-by: Mattia Eleuteri <mattia.eleuteri@hidora.io> Signed-off-by: mattia-eleuteri <mattia@hidora.io>
This commit is contained in:
parent
9bb6625c28
commit
2c0a9fb2cc
4 changed files with 107 additions and 2 deletions
|
|
@ -15,6 +15,39 @@ spec:
|
|||
enableExternal: false
|
||||
namespaces:
|
||||
- {{ .Release.Namespace }}
|
||||
{{- if .Values.peers }}
|
||||
{{- $hexLookup := dict "0" 0 "1" 1 "2" 2 "3" 3 "4" 4 "5" 5 "6" 6 "7" 7 "8" 8 "9" 9 "a" 10 "b" 11 "c" 12 "d" 13 "e" 14 "f" 15 }}
|
||||
vpcPeerings:
|
||||
{{- range .Values.peers }}
|
||||
{{- $remoteRelease := printf "virtualprivatecloud-%s" .vpcName }}
|
||||
{{- $remoteVpcId := printf "vpc-%s" (printf "%s/%s" .tenantNamespace $remoteRelease | sha256sum | trunc 6) }}
|
||||
{{- $sorted := list $vpcId $remoteVpcId | sortAlpha }}
|
||||
{{- $pairKey := join "/" $sorted }}
|
||||
{{- $pairHash := sha256sum $pairKey }}
|
||||
{{- $h0 := int (get $hexLookup (substr 0 1 $pairHash)) }}
|
||||
{{- $h1 := int (get $hexLookup (substr 1 2 $pairHash)) }}
|
||||
{{- $h2 := int (get $hexLookup (substr 2 3 $pairHash)) }}
|
||||
{{- $h3 := int (get $hexLookup (substr 3 4 $pairHash)) }}
|
||||
{{- $byte0 := add (mul $h0 16) $h1 }}
|
||||
{{- $byte1 := add (mul $h2 16) $h3 }}
|
||||
{{- $oct3 := int (add (mod $byte0 254) 1) }}
|
||||
{{- $base4 := int (mul (mod $byte1 64) 4) }}
|
||||
{{- if eq $vpcId (index $sorted 0) }}
|
||||
- remoteVpc: {{ $remoteVpcId }}
|
||||
localConnectIP: {{ printf "169.254.%d.%d" $oct3 (int (add $base4 1)) }}
|
||||
{{- else }}
|
||||
- remoteVpc: {{ $remoteVpcId }}
|
||||
localConnectIP: {{ printf "169.254.%d.%d" $oct3 (int (add $base4 2)) }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.routes }}
|
||||
staticRoutes:
|
||||
{{- range .Values.routes }}
|
||||
- cidr: {{ .cidr | quote }}
|
||||
nextHopIP: {{ .nextHopIP | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- range .Values.subnets }}
|
||||
{{- $subnetId := print "subnet-" (print $.Release.Namespace "/" $vpcId "/" .name | sha256sum | trunc 8) }}
|
||||
|
|
@ -70,6 +103,12 @@ data:
|
|||
{{ .name }}.ID: {{ print "subnet-" (print $.Release.Namespace "/" $vpcId "/" .name | sha256sum | trunc 8) }}
|
||||
{{ .name }}.CIDR: {{ .cidr }}
|
||||
{{- end }}
|
||||
{{- range .Values.peers }}
|
||||
{{- $remoteRelease := printf "virtualprivatecloud-%s" .vpcName }}
|
||||
{{- $remoteVpcId := printf "vpc-%s" (printf "%s/%s" .tenantNamespace $remoteRelease | sha256sum | trunc 6) }}
|
||||
peer.{{ .tenantNamespace }}.{{ .vpcName }}.vpcId: {{ $remoteVpcId | quote }}
|
||||
peer.{{ .tenantNamespace }}.{{ .vpcName }}.tenantNamespace: {{ .tenantNamespace | quote }}
|
||||
{{- end }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
|
|
|
|||
|
|
@ -2,6 +2,50 @@
|
|||
"title": "Chart Values",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"peers": {
|
||||
"description": "VPC peering connections (bidirectional declaration required)",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"tenantNamespace",
|
||||
"vpcName"
|
||||
],
|
||||
"properties": {
|
||||
"tenantNamespace": {
|
||||
"description": "Namespace of the remote tenant",
|
||||
"type": "string"
|
||||
},
|
||||
"vpcName": {
|
||||
"description": "Logical name of the remote VPC (without \"virtualprivatecloud-\" prefix)",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"routes": {
|
||||
"description": "Static routes for the VPC",
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"cidr",
|
||||
"nextHopIP"
|
||||
],
|
||||
"properties": {
|
||||
"cidr": {
|
||||
"description": "Destination CIDR",
|
||||
"type": "string"
|
||||
},
|
||||
"nextHopIP": {
|
||||
"description": "Next hop IP address",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"subnets": {
|
||||
"description": "Subnets of a VPC",
|
||||
"type": "array",
|
||||
|
|
|
|||
|
|
@ -14,3 +14,25 @@ subnets: []
|
|||
## cidr: "172.16.0.0/24"
|
||||
## - name: mysubnet1
|
||||
## cidr: "172.16.1.0/24"
|
||||
|
||||
## @typedef {struct} Peer - VPC peering target
|
||||
## @field {string} vpcName - Logical name of the remote VPC (without "virtualprivatecloud-" prefix)
|
||||
## @field {string} tenantNamespace - Namespace of the remote tenant
|
||||
|
||||
## @param {[]Peer} peers - VPC peering connections (bidirectional declaration required)
|
||||
peers: []
|
||||
## Example:
|
||||
## peers:
|
||||
## - vpcName: "other-vpc"
|
||||
## tenantNamespace: "tenant-other"
|
||||
|
||||
## @typedef {struct} Route - Static route entry
|
||||
## @field {string} cidr - Destination CIDR
|
||||
## @field {string} nextHopIP - Next hop IP address
|
||||
|
||||
## @param {[]Route} routes - Static routes for the VPC
|
||||
routes: []
|
||||
## Example:
|
||||
## routes:
|
||||
## - cidr: "172.16.1.0/24"
|
||||
## nextHopIP: "10.0.0.1"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ spec:
|
|||
plural: virtualprivateclouds
|
||||
singular: virtualprivatecloud
|
||||
openAPISchema: |-
|
||||
{"title":"Chart Values","type":"object","properties":{"subnets":{"description":"Subnets of a VPC","type":"array","default":[],"items":{"type":"object","required":["name"],"properties":{"cidr":{"description":"IP address range","type":"string"},"name":{"description":"Subnet name","type":"string"}}}}}}
|
||||
{"title":"Chart Values","type":"object","properties":{"peers":{"description":"VPC peering connections (bidirectional declaration required)","type":"array","default":[],"items":{"type":"object","required":["tenantNamespace","vpcName"],"properties":{"tenantNamespace":{"description":"Namespace of the remote tenant","type":"string"},"vpcName":{"description":"Logical name of the remote VPC (without \"virtualprivatecloud-\" prefix)","type":"string"}}}},"routes":{"description":"Static routes for the VPC","type":"array","default":[],"items":{"type":"object","required":["cidr","nextHopIP"],"properties":{"cidr":{"description":"Destination CIDR","type":"string"},"nextHopIP":{"description":"Next hop IP address","type":"string"}}}},"subnets":{"description":"Subnets of a VPC","type":"array","default":[],"items":{"type":"object","required":["name"],"properties":{"cidr":{"description":"IP address range","type":"string"},"name":{"description":"Subnet name","type":"string"}}}}}}
|
||||
release:
|
||||
prefix: "virtualprivatecloud-"
|
||||
labels:
|
||||
|
|
@ -23,7 +23,7 @@ spec:
|
|||
plural: VPCs
|
||||
description: "Isolated networks"
|
||||
icon: PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxNDQiIGhlaWdodD0iMTQ0IiByeD0iMjQiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl8xMDI1XzMpIi8+CjxwYXRoIGQ9Ik0xMDkuNiA4Ni4xSDExNC4zQzExNi44ODUgODYuMSAxMTkgODguMjE1IDExOSA5MC44NDdWMTA0Ljg1M0MxMTkgMTA3LjQ4NSAxMTYuODg1IDEwOS42IDExNC4zIDEwOS42SDk1LjVDOTIuOTE1IDEwOS42IDkwLjggMTA3LjQ4NSA5MC44IDEwNC44NTNWOTAuODQ3QzkwLjggODguMjE1IDkyLjkxNSA4Ni4xIDk1LjUgODYuMUgxMDAuMlY3Ni43SDc2LjdWODYuMUg4MS40QzgzLjk4NSA4Ni4xIDg2LjEgODguMjE1IDg2LjEgOTAuODQ3VjEwNC44NTNDODYuMSAxMDcuNDg1IDgzLjk4NSAxMDkuNiA4MS40IDEwOS42SDYyLjZDNjAuMDE1IDEwOS42IDU3LjkgMTA3LjQ4NSA1Ny45IDEwNC44NTNWOTAuODQ3QzU3LjkgODguMjE1IDYwLjAxNSA4Ni4xIDYyLjYgODYuMUg2Ny4zVjc2LjdINDMuOFY4Ni4xSDQ4LjVDNTEuMDg1IDg2LjEgNTMuMiA4OC4yMTUgNTMuMiA5MC44NDdWMTA0Ljg1M0M1My4yIDEwNy40ODUgNTEuMDg1IDEwOS42IDQ4LjUgMTA5LjZIMjkuN0MyNy4xMTUgMTA5LjYgMjUgMTA3LjQ4NSAyNSAxMDQuODUzVjkwLjg0N0MyNSA4OC4yMTUgMjcuMTE1IDg2LjEgMjkuNyA4Ni4xSDM0LjRWNzYuN0MzNC40IDcxLjUzIDM4LjYzIDY3LjMgNDMuOCA2Ny4zSDY3LjNWNTcuOUg2Mi42QzYwLjAxNSA1Ny45IDU3LjkgNTUuNzg1IDU3LjkgNTMuMTUzVjM5LjE0N0M1Ny45IDM2LjUxNSA2MC4wMTUgMzQuNCA2Mi42IDM0LjRIODEuNEM4My45ODUgMzQuNCA4Ni4xIDM2LjUxNSA4Ni4xIDM5LjE0N1Y1My4xNTNDODYuMSA1NS43ODUgODMuOTg1IDU3LjkgODEuNCA1Ny45SDc2LjdWNjcuM0gxMDAuMkMxMDUuMzcgNjcuMyAxMDkuNiA3MS41MyAxMDkuNiA3Ni43Vjg2LjFaIiBmaWxsPSJ3aGl0ZSIvPgo8ZGVmcz4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzEwMjVfMyIgeDE9IjE0Mi41IiB5MT0iMTQzIiB4Mj0iMy45OTk5OSIgeTI9IjkuNDk5OTkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iIzAwMDgyRSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMyRTMwNjciLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "subnets"]]
|
||||
keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "subnets"], ["spec", "peers"], ["spec", "routes"]]
|
||||
secrets:
|
||||
exclude: []
|
||||
include: []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue