Files
bluejay-infra/apps/voice/voice.yaml
2026-06-04 13:20:16 -05:00

128 lines
7.2 KiB
YAML

# Twilio Voice Bridge - Traefik ingress to edge1
# ArgoCD managed - BlueJay Lab
# Routes voice.bluejay.dev (TwiML) and voice-ws.bluejay.dev (WebSocket)
# to edge1 Pi5 at 10.0.57.15 (PROD VLAN)
---
apiVersion: v1
kind: Namespace
metadata:
name: voice
labels:
app.kubernetes.io/part-of: bluejay-infra
---
# Cloudflare origin cert for *.bluejay.dev
apiVersion: v1
kind: Secret
metadata:
name: cf-origin-bluejay-dev
namespace: voice
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVvakNDQTRxZ0F3SUJBZ0lVTkxnemZ4UVRzMElyWWRaZUZKUGN5TjRyNmFjd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2dZc3hDekFKQmdOVkJBWVRBbFZUTVJrd0Z3WURWUVFLRXhCRGJHOTFaRVpzWVhKbExDQkpibU11TVRRdwpNZ1lEVlFRTEV5dERiRzkxWkVac1lYSmxJRTl5YVdkcGJpQlRVMHdnUTJWeWRHbG1hV05oZEdVZ1FYVjBhRzl5CmFYUjVNUll3RkFZRFZRUUhFdzFUWVc0Z1JuSmhibU5wYzJOdk1STXdFUVlEVlFRSUV3cERZV3hwWm05eWJtbGgKTUI0WERUSTJNRE14TURBMU1USXdNRm9YRFRReE1ETXdOakExTVRJd01Gb3dZakVaTUJjR0ExVUVDaE1RUTJ4dgpkV1JHYkdGeVpTd2dTVzVqTGpFZE1Cc0dBMVVFQ3hNVVEyeHZkV1JHYkdGeVpTQlBjbWxuYVc0Z1EwRXhKakFrCkJnTlZCQU1USFVOc2IzVmtSbXhoY21VZ1QzSnBaMmx1SUVObGNuUnBabWxqWVhSbE1JSUJJakFOQmdrcWhraUcKOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXlPODBJQ3dPV0RWTEpQNm9RenI3aXVENmtWMGNWZ01VbUx5VApKVnVYUlhZSEY3M2ZrM2pPbytCQVE1M2pmbERHUFVYc0UvNlV6VDRoUDVYTlVLaUNXaitvYy84eE1BSWsxcWwrClZnbFI1MDBUQ0FtZDliazNZVkxiZjBSejVMMUQ0WGJmOEVzamhOUVV2Z3Y0dTZoQzdnRmdrVGplc1dIZjg0K04KNERETDdmTjFQZHR4RVBiVWZrbGN1MUZSdXdlMk9QNkFEMlJvdkphNWZwODRHcVY2TDAzdjY2RjFtMnBST1VmRwpFdWpRNG4zSms2cUx5NHZTTENzOGJlOGRBRW5QcDgyZ2NRZk9mUVlIS2JTUWhiQnMwK01vK3lkTHpHSzFRdklRCnVPcDZRT1BtM0lac09Eb0VCdG5kMTh2amx6Y1JSdE94cjNzaFovdmNWY0o0YUJNZDVRSURBUUFCbzRJQkpEQ0MKQVNBd0RnWURWUjBQQVFIL0JBUURBZ1dnTUIwR0ExVWRKUVFXTUJRR0NDc0dBUVVGQndNQ0JnZ3JCZ0VGQlFjRApBVEFNQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkRGdRV0JCVHgyYmFCUGlvWjZUd2U3THhnaTViUS82cUFkakFmCkJnTlZIU01FR0RBV2dCUWs2Rk5YWFh3MFFJZXA2NVRidXVFV2VQd3BwREJBQmdnckJnRUZCUWNCQVFRME1ESXcKTUFZSUt3WUJCUVVITUFHR0pHaDBkSEE2THk5dlkzTndMbU5zYjNWa1pteGhjbVV1WTI5dEwyOXlhV2RwYmw5agpZVEFsQmdOVkhSRUVIakFjZ2cwcUxtSnNkV1ZxWVhrdVpHVjJnZ3RpYkhWbGFtRjVMbVJsZGpBNEJnTlZIUjhFCk1UQXZNQzJnSzZBcGhpZG9kSFJ3T2k4dlkzSnNMbU5zYjNWa1pteGhjbVV1WTI5dEwyOXlhV2RwYmw5allTNWoKY213d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFDS0ZVRXhYbFB5KzlPRytJc1VWN1NXS09Udkk0b2JrUkd6bwpOckhudWZ3dGtxa0dzUGErUU5LbUk1UVNaYTVMS1YybWZJdWsrNE12U1FvZklmbUFUb1JEWEdQK041aWxEbWRSCk5rS2ttSUpZL242UzM3MGdZN0JQMjFwNjJKUnZkVUU5ZmV5RU1iMUdNbGNINjN6MUQxMzZZOWlvQ1FnYWNFZVUKOFZSVWFPZkJvby9sVzlYbXA1ZDZzcTBic2tybUhRN1ZSTjUxZCtsL0RvY2lkU2xZcHQxbXljSUN3c1F4U0dpMApYN1pMTXhHdCtDVG9jcFRFbkdrQ2t0NnhrKzVJUElXaHYvVnZuTnlQNUwxM0ZRN1d4QzFsaUIwcVdKMkEwcWpoCkR2cmxPNUpsclNWWEtNc0hwSWRFN3pJZ29JUUc2cnU1N1V4UjJyeko0d0VrSXcrd1ZyMD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRREk3elFnTEE1WU5Vc2sKL3FoRE92dUs0UHFSWFJ4V0F4U1l2Sk1sVzVkRmRnY1h2ZCtUZU02ajRFQkRuZU4rVU1ZOVJld1QvcFROUGlFLwpsYzFRcUlKYVA2aHovekV3QWlUV3FYNVdDVkhuVFJNSUNaMzF1VGRoVXR0L1JIUGt2VVBoZHQvd1N5T0UxQlMrCkMvaTdxRUx1QVdDUk9ONnhZZC96ajQzZ01NdnQ4M1U5MjNFUTl0UitTVnk3VVZHN0I3WTQvb0FQWkdpOGxybCsKbnpnYXBYb3ZUZS9yb1hXYmFsRTVSOFlTNk5EaWZjbVRxb3ZMaTlJc0t6eHQ3eDBBU2MrbnphQnhCODU5QmdjcAp0SkNGc0d6VDR5ajdKMHZNWXJWQzhoQzQ2bnBBNCtiY2htdzRPZ1FHMmQzWHkrT1hOeEZHMDdHdmV5Rm4rOXhWCnduaG9FeDNsQWdNQkFBRUNnZ0VBRFpWeU9peVFTYkZNbzdNZGovSDRXR0t1UGM2RUlHSno3WUZ1Rnl2eWRZMHQKbkpMRy94Sy9NWC96Q0Q4dnhuWFNlUWoxbFVKMEw4M2Y5SXI5aHRMbGdSRmxvM1hnanVUT05iN2VuaFZpTnBkVQp6b25MNW5VL2c3SlV5VzFJd25GekdkWnQvREl3TkFZY1l0NnZVWXhsL2U0VTU2eG5EYW5XdUlIL2J1VU5uRWZtCjZNcnlIblhseDA0TzZzOElLSCtXNUxDam1ma1Jac0VveE9Damt6T2hucmdCTk4xSWxWSWhhMDhLOXBxRk5qM0wKaWd4MVNYZDhqaHNZUHJxaDNkak0rVUNKSitKMURuMjhaUmoyZUtqWDMvZmFDbGFpOEFzUVBtQTJScjZYZ3kzeApaR090dzRPL2Nxb1hnOUFDU05NanRNK3VtaXM3QzNncWp6VUZ4MWwvNFFLQmdRRFNvSGVDY1dXSUJQV3grR01hCnBSMENHejQ0eDNPRUhnNWYza2RvK3BDK0I3RnYxREV5bktqUUY4VFBYaWJXVGZVL1pBRG5DVmIvU1Z2L1QyNnkKT2NlaW44UGRqdXkraE05ZUxjWXU4QVZiK0VKOHFMUUsrZE5QZm1nYXZJMWR2V3U2Tm8wSTNSSzZWUkpiQXEyWgpLcjdsVEloMjdZMDRMajlaaUIxU01YZ0J0UUtCZ1FEME9EbEVCNHRHa1l2dTVLMkFoaDBmdnlIaUVoUTd5dWUzCmZXdG1VYnRxV0ZlM1R5UG9JTWJWMTM3MkNIdlh6MFNEMXRwYzJxa3hxN3c4d1BYM3RJZGk5NWxMbVMzZm8zWFoKdTNTYVo4enozTlAwR3JXK1Y0c3hHb1VnbWgwL2lzOXJoaWxXZGF5bU5SWEQ5U0MyUU5IdTU5NDY2UjFkczNnbgpiZlJlUkw4SmNRS0JnREptVjNLTk0rQmlYM0Jnb1VaRThEWUswczYvV3pMb0JrU0dhY3dDK1JPZnY2T2t3TWo5Cmw1K0RzSUoyWXhDd3d0aVNVMnoxWFMzbEhmQnZ6MnN5VEVUcnVmQ1FQTEl5RVhUVnV6Q01HcHd4UWFlV3JzNVoKaldqZU5JY0JTMHA5QXdRaC9ZbDdiUG5OVllFVm1QaW5zOW9tZ0JrRkt0K2dvV1FKSUFzRTcxUnBBb0dCQUxNSgphTW43c2RuNUo1bnA0VnhBZGFkcGFvQ2VlbURmUG9KaEd0UTNCT3RRZW5Xek9nS1p6TXJHSVpoaTNjOTNicVlzClk0Y0E4bHFzcU9IdElDVUpIdHVwNHFMdVdCZ0VjSWcvaVpzTWo4OFRTL3MvZlk5ZUJIZnFGa0N4V3RIVGhINHkKSzZucnVMZGNZV2w0RWhRcWJ2enkxUk5oQkp0Rno4Y3dMNTdRVFRDeEFvR0FjZFFkbzk3bzZmS0dQa3kvREpnNApoTGlLbHVkTjF3bmJaTHFVM0UwNzBwVDhJQkx3TFNpTUNpYXRXWWtScHFpdUQyMSsya1p4SE1NdnNoZWJXQmFmCmVqWU9jcHVvQ3VWdWc1K1dlbmc0cmUxSTl2c2czUE5WYkdrNW1xNmZDbndsbGFnMkEvSVBVRFFOaUpCVGM1WUQKc25udzhVTjNBTFBMSTlPVVd1eXJUckk9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
---
# Service (no selector) pointing to external edge1
apiVersion: v1
kind: Service
metadata:
name: voice-bridge
namespace: voice
spec:
ports:
- name: twiml
port: 8766
targetPort: 8766
protocol: TCP
- name: websocket
port: 8765
targetPort: 8765
protocol: TCP
---
# Manual Endpoints for edge1 (outside K8s)
apiVersion: v1
kind: Endpoints
metadata:
name: voice-bridge
namespace: voice
subsets:
- addresses:
- ip: 10.0.57.15
ports:
- name: twiml
port: 8766
protocol: TCP
- name: websocket
port: 8765
protocol: TCP
---
# TwiML webhook: voice.bluejay.dev -> edge1:8766
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: voice-twiml
namespace: voice
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`voice.bluejay.dev`) && (Method(`GET`) || Method(`HEAD`) || Method(`POST`) || Method(`OPTIONS`))
services:
- name: voice-bridge
port: 8766
tls:
secretName: cf-origin-bluejay-dev
---
# WebSocket media stream: voice-ws.bluejay.dev -> edge1:8765
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: voice-ws
namespace: voice
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`voice-ws.bluejay.dev`) && (Method(`GET`) || Method(`HEAD`))
services:
- name: voice-bridge
port: 8765
tls:
secretName: cf-origin-bluejay-dev
---
# NetworkPolicy: allow Traefik ingress only
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: voice-netpol
namespace: voice
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik-system
egress:
- to:
- ipBlock:
cidr: 10.0.57.15/32
ports:
- port: 8765
protocol: TCP
- port: 8766
protocol: TCP
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP