175 lines
6.6 KiB
YAML
175 lines
6.6 KiB
YAML
# 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
|
|
# A version, not a channel: nothing has promoted a browser to stable, because promotion
|
|
# means "it ran on a canary" and no canary deploys one — this manifest is commented out of
|
|
# kustomization.yaml by default. Pin a digest here as you do for the other images.
|
|
image: git.luxit.be/luxit/jarvis-browser:0.1.0
|
|
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
|