diff --git a/packages/apps/vpc/templates/vpc.yaml b/packages/apps/vpc/templates/vpc.yaml index 6c0d2249..cb860279 100644 --- a/packages/apps/vpc/templates/vpc.yaml +++ b/packages/apps/vpc/templates/vpc.yaml @@ -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 diff --git a/packages/apps/vpc/values.schema.json b/packages/apps/vpc/values.schema.json index a975d2d7..c3d5d65a 100644 --- a/packages/apps/vpc/values.schema.json +++ b/packages/apps/vpc/values.schema.json @@ -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", diff --git a/packages/apps/vpc/values.yaml b/packages/apps/vpc/values.yaml index 3af8b26b..8bd27589 100644 --- a/packages/apps/vpc/values.yaml +++ b/packages/apps/vpc/values.yaml @@ -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" diff --git a/packages/system/virtualprivatecloud-rd/cozyrds/virtualprivatecloud.yaml b/packages/system/virtualprivatecloud-rd/cozyrds/virtualprivatecloud.yaml index d5694a2c..ad3b26e4 100644 --- a/packages/system/virtualprivatecloud-rd/cozyrds/virtualprivatecloud.yaml +++ b/packages/system/virtualprivatecloud-rd/cozyrds/virtualprivatecloud.yaml @@ -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: []