Sync the self-hosting stack
This commit is contained in:
@@ -58,6 +58,10 @@ data:
|
||||
# first decides whether a restart leaves a closed transcript or a half-written one.
|
||||
RUN_SHUTDOWN_GRACE_SEC: "25"
|
||||
|
||||
# The browser service — a separate pod on purpose, see 09-browser.yaml. COMMENTED OUT to match
|
||||
# that file: with no browser deployed, setting this only turns "unavailable" into a timeout.
|
||||
# BROWSER_URL: "http://jarvis-browser:3000"
|
||||
|
||||
# No demo organization and no seeded administrator: the install screen is the way in. The seed
|
||||
# refuses an instance that already has accounts anyway, but a Deployment has no business
|
||||
# furnishing anything.
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
# The headless browser Jarvis is allowed to use, and the policy that keeps it away from everything
|
||||
# else.
|
||||
#
|
||||
# WHY IT IS ITS OWN POD. A browser's entire purpose is to fetch code written by strangers and run it.
|
||||
# The api pod holds VAULT_MASTER_KEY, the database URL and a live connection to Postgres and Redis;
|
||||
# putting Chromium in it would let any page the assistant is pointed at reach all three — and reach
|
||||
# the node's metadata endpoint on 169.254.169.254, which is how instance credentials get read out
|
||||
# loud. PowerShell is in the api image and this is not, and the difference is exactly that: the
|
||||
# Exchange module talks to Microsoft, and a browser talks to whoever the model was told to look at.
|
||||
#
|
||||
# THE NETWORK POLICY BELOW IS THE REAL CONTROL. `browser.client.ts` refuses private addresses before
|
||||
# it asks, which is the half that can EXPLAIN itself to the model — but it cannot survive a redirect
|
||||
# and it cannot survive DNS rebinding, because by then the browser is already connecting. The policy
|
||||
# can, because it is enforced on the packet.
|
||||
#
|
||||
# DELETE THIS FILE (and its line in kustomization.yaml, and BROWSER_URL from 02-config.yaml) if you
|
||||
# would rather Jarvis had no web access. Nothing else stops working: the two web tools report
|
||||
# themselves unavailable and every other tool is unaffected.
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: jarvis-browser
|
||||
labels:
|
||||
app.kubernetes.io/name: jarvis
|
||||
app.kubernetes.io/component: browser
|
||||
spec:
|
||||
# One is enough and more is not better: each replica is a Chromium, and a render is short. Scale
|
||||
# this only if the assistant is genuinely browsing concurrently across many conversations.
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: jarvis
|
||||
app.kubernetes.io/component: browser
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: jarvis
|
||||
app.kubernetes.io/component: browser
|
||||
spec:
|
||||
# No service account token. This pod has no business talking to the Kubernetes API, and a
|
||||
# mounted token is the first thing anything escaping a renderer would look for.
|
||||
automountServiceAccountToken: false
|
||||
containers:
|
||||
- name: browser
|
||||
image: git.luxit.be/luxit/jarvis-browser:stable
|
||||
ports:
|
||||
- containerPort: 3000
|
||||
name: http
|
||||
# No envFrom, no secretRef, no volume. Deliberately: this container should hold nothing
|
||||
# worth stealing, so that escaping the renderer is not the same as reaching anything.
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
# Chromium will use whatever it is given on a heavy page. The limit is what stops one
|
||||
# bad page evicting the api from the same node.
|
||||
memory: 1Gi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
# `pwuser` in the Playwright image.
|
||||
runAsUser: 1000
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
# NOT read-only: Chromium writes its profile, its cache and its shared memory. The
|
||||
# writable surface is an emptyDir that dies with the pod rather than the image.
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
- name: home
|
||||
mountPath: /home/pwuser
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: http
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
volumes:
|
||||
- name: tmp
|
||||
emptyDir:
|
||||
# /dev/shm is small by default and Chromium is the classic victim of it; the server
|
||||
# passes --disable-dev-shm-usage and writes here instead.
|
||||
sizeLimit: 512Mi
|
||||
- name: home
|
||||
emptyDir:
|
||||
sizeLimit: 512Mi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: jarvis-browser
|
||||
spec:
|
||||
selector:
|
||||
app.kubernetes.io/name: jarvis
|
||||
app.kubernetes.io/component: browser
|
||||
ports:
|
||||
- port: 3000
|
||||
targetPort: http
|
||||
name: http
|
||||
---
|
||||
# WHAT THE BROWSER MAY TALK TO, and it is the file's reason for existing.
|
||||
#
|
||||
# Ingress: the api pods, and nothing else. Nothing in this namespace should be calling a browser.
|
||||
#
|
||||
# Egress: DNS, and then the internet MINUS every private range. The exception list is the whole
|
||||
# point — 10/8, 172.16/12 and 192.168/16 are where the cluster and the customer's estate live, and
|
||||
# 169.254.0.0/16 is the metadata endpoint. Without these `except` clauses a page could ask the
|
||||
# browser to fetch http://169.254.169.254/ and read the node's cloud credentials back as page text.
|
||||
#
|
||||
# NOTE THIS NEEDS A CNI THAT ENFORCES NetworkPolicy. Calico, Cilium and most managed clusters do;
|
||||
# plain kube-proxy with flannel does NOT, and on such a cluster this file is documentation rather
|
||||
# than a control. Check before relying on it — `browser.client.ts` still refuses private addresses
|
||||
# on the near side either way, but that half cannot survive a redirect.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: jarvis-browser
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: jarvis
|
||||
app.kubernetes.io/component: browser
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: jarvis
|
||||
app.kubernetes.io/component: api
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 3000
|
||||
egress:
|
||||
# DNS, to the cluster resolver. Without this nothing resolves and every page fails.
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
podSelector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
# The public internet, and nothing that is not.
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 0.0.0.0/0
|
||||
except:
|
||||
- 10.0.0.0/8
|
||||
- 172.16.0.0/12
|
||||
- 192.168.0.0/16
|
||||
- 169.254.0.0/16
|
||||
- 127.0.0.0/8
|
||||
- 100.64.0.0/10
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
@@ -42,6 +42,11 @@ resources:
|
||||
# Remove this line if you point REDIS_URL at a managed Redis. It deploys three Redis processes and
|
||||
# three sentinels; see the README on what that costs on three nodes.
|
||||
- 08-redis-sentinel.yaml
|
||||
# The headless browser and the NetworkPolicy that isolates it. COMMENTED OUT: web access is a
|
||||
# decision rather than a default, and an assistant that can read the internet is a new class of
|
||||
# input into a system that administers customers. Uncomment this AND set BROWSER_URL in
|
||||
# 02-config.yaml to enable it; leaving both alone changes nothing.
|
||||
# - 09-browser.yaml
|
||||
|
||||
# ─── THE THREE IMAGES ───────────────────────────────────────────────────────────────────────────
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user