chat.ai: gate root with API key

This commit is contained in:
Brad Stein 2025-12-31 13:43:24 -03:00
parent a815322f6e
commit ee6bcec3c5
8 changed files with 165 additions and 18 deletions

View File

@ -0,0 +1,78 @@
# services/bstein-dev-home/chat-ai-gateway-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: chat-ai-gateway
namespace: bstein-dev-home
data:
gateway.py: |
import json
import os
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib import request, error
UPSTREAM = os.environ.get("UPSTREAM_URL", "http://bstein-dev-home-backend/api/chat")
KEY_MATRIX = os.environ.get("CHAT_KEY_MATRIX", "")
KEY_HOMEPAGE = os.environ.get("CHAT_KEY_HOMEPAGE", "")
ALLOWED = {k for k in (KEY_MATRIX, KEY_HOMEPAGE) if k}
class Handler(BaseHTTPRequestHandler):
def _send_json(self, code: int, payload: dict):
body = json.dumps(payload).encode()
self.send_response(code)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def do_GET(self): # noqa: N802
if self.path in ("/healthz", "/"):
return self._send_json(200, {"ok": True})
return self._send_json(404, {"error": "not_found"})
def do_POST(self): # noqa: N802
if self.path != "/":
return self._send_json(404, {"error": "not_found"})
key = self.headers.get("x-api-key", "")
if not key or key not in ALLOWED:
return self._send_json(401, {"error": "unauthorized"})
length = int(self.headers.get("content-length", "0") or "0")
raw = self.rfile.read(length) if length else b"{}"
try:
upstream_req = request.Request(
UPSTREAM,
data=raw,
headers={"Content-Type": "application/json"},
method="POST",
)
with request.urlopen(upstream_req, timeout=90) as resp:
data = resp.read()
self.send_response(resp.status)
for k, v in resp.headers.items():
if k.lower() in ("content-length", "connection", "server", "date"):
continue
self.send_header(k, v)
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
except error.HTTPError as e:
data = e.read() if hasattr(e, "read") else b""
self.send_response(e.code)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
except Exception:
return self._send_json(502, {"error": "bad_gateway"})
def main():
port = int(os.environ.get("PORT", "8080"))
httpd = HTTPServer(("0.0.0.0", port), Handler)
httpd.serve_forever()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,69 @@
# services/bstein-dev-home/chat-ai-gateway-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: chat-ai-gateway
namespace: bstein-dev-home
spec:
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
app: chat-ai-gateway
template:
metadata:
labels:
app: chat-ai-gateway
spec:
nodeSelector:
kubernetes.io/arch: arm64
node-role.kubernetes.io/worker: "true"
containers:
- name: gateway
image: python:3.11-slim
command: ["/bin/sh","-c"]
args:
- python /app/gateway.py
env:
- name: UPSTREAM_URL
value: http://bstein-dev-home-backend/api/chat
- name: CHAT_KEY_MATRIX
valueFrom:
secretKeyRef:
name: chat-ai-keys-runtime
key: matrix
- name: CHAT_KEY_HOMEPAGE
valueFrom:
secretKeyRef:
name: chat-ai-keys-runtime
key: homepage
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 2
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 10
periodSeconds: 10
resources:
requests:
cpu: 20m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
volumeMounts:
- name: code
mountPath: /app/gateway.py
subPath: gateway.py
volumes:
- name: code
configMap:
name: chat-ai-gateway

View File

@ -0,0 +1,13 @@
# services/bstein-dev-home/chat-ai-gateway-service.yaml
apiVersion: v1
kind: Service
metadata:
name: chat-ai-gateway
namespace: bstein-dev-home
spec:
selector:
app: chat-ai-gateway
ports:
- name: http
port: 80
targetPort: 8080

View File

@ -32,15 +32,9 @@ spec:
- host: chat.ai.bstein.dev
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: bstein-dev-home-backend
port: { number: 80 }
- path: /
pathType: Prefix
backend:
service:
name: bstein-dev-home-frontend
name: chat-ai-gateway
port: { number: 80 }

View File

@ -6,6 +6,9 @@ resources:
- namespace.yaml
- image.yaml
- rbac.yaml
- chat-ai-gateway-configmap.yaml
- chat-ai-gateway-deployment.yaml
- chat-ai-gateway-service.yaml
- frontend-deployment.yaml
- frontend-service.yaml
- backend-deployment.yaml

View File

@ -38,7 +38,7 @@ spec:
- name: CHAT_API_KEY
valueFrom:
secretKeyRef:
name: chat-ai-keys
name: chat-ai-keys-runtime
key: matrix
- name: OLLAMA_URL
value: https://chat.ai.bstein.dev/

View File

@ -1,9 +0,0 @@
# services/communication/chat-ai-keys.yaml
apiVersion: v1
kind: Secret
metadata:
name: chat-ai-keys
namespace: communication
type: Opaque
stringData:
matrix: "3d9b1e5e80f146f2b3f6a9fbe01b7b77"

View File

@ -16,7 +16,6 @@ resources:
- element-call-deployment.yaml
- pin-othrys-job.yaml
- guest-name-job.yaml
- chat-ai-keys.yaml
- atlasbot-credentials.yaml
- atlasbot-configmap.yaml
- atlasbot-deployment.yaml