Files
zeekayandHanzo Dev be899471ee feat(sovereignty): Zoo own KMS + MPC ring (LIVE, DKG+sign proven)
zoo-mpc (5-node, 3-of-5, ghcr.io/zooai/mpc:1.17.9) + zoo-kms
(ghcr.io/zooai/kms:1.11.8, lux-kms-go parity, Zoo-branded OIDC) in
do-sfo3-zoo-k8s. DKG proven: wallet zoo-treasury-v1 EVM
0x8756621734fe274fdc426381c9a4f9dec8656243, 3-of-5 threshold sign OK.
KMS in-cluster health+login 200. Investigation: ZERO Zoo secrets in the
Hanzo KMS (proven) -> repoint strands nothing. Repoint + DAO/Z Safes
staged, HELD for owner go (Zoo EVM 200200 not producing blocks).

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-14 10:53:53 -07:00

200 lines
6.4 KiB
YAML

# Zoo MPC — Zoo's OWN canonical threshold-signing ring (crypto-sovereign).
# Namespace: zoo-mpc. Architecture: 5-node consensus, threshold 3-of-5.
# Image: ghcr.io/zooai/mpc:v1.17.9 — the Zoo-branded rebrand of the canonical
# lux-native mpcd (wraps ghcr.io/luxfi/mpc:v1.17.9; same convention as
# hanzoai/mpc). Binary is `mpcd`. Pin is semver-immutable (no :main/:latest).
#
# Mirrors the PROVEN hanzo-mpc / lux-mpc rings (own DKG key, own store), but
# 3-of-5 and in the dedicated zoo-mpc namespace the Zoo bridge tenant.yaml
# already targets (mpc-node-0..4.mpc-node-headless.zoo-mpc.svc, threshold 3).
#
# DNS/pod identity: StatefulSet `mpc-node` → pods mpc-node-{0..4} (matches the
# bridge tenant mpc.url). MPC protocol node-id = zoo-mpc-node-{ordinal} (matches
# the bridge tenant `operators` allowlist). Both contracts satisfied.
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mpc-node
namespace: zoo-mpc
labels:
app: mpc-node
app.kubernetes.io/name: mpc-node
app.kubernetes.io/component: signer
app.kubernetes.io/part-of: mpc
brand: zoo
spec:
serviceName: mpc-node-headless
replicas: 5
podManagementPolicy: Parallel
selector:
matchLabels:
app: mpc-node
template:
metadata:
labels:
app: mpc-node
app.kubernetes.io/part-of: mpc
brand: zoo
spec:
imagePullSecrets:
- name: ghcr-zooai
containers:
- name: mpc-node
image: ghcr.io/zooai/mpc:1.17.9
imagePullPolicy: IfNotPresent
# mpcd flags: DNS peer list over StatefulSet DNS (stable + deterministic);
# 3-of-5 threshold; p2p :9999, internal API :9800, dashboard API :8081.
# node-id carries the Zoo operator prefix to match the bridge allowlist.
command:
- /bin/sh
- -c
- |
ORD="${POD_NAME##*-}"
# Peers MUST use the explicit `nodeID@host:port` form so the registry's
# filterSelf() matches this node's --node-id and drops the self-entry
# (a bare host:port yields synthetic `peer-N` ids that never match self,
# inflating the expected-peer count to N+1 and stalling keygen). The
# nodeIDs (zoo-mpc-node-0..4) are identical across all pods and match
# the Zoo bridge tenant `operators` allowlist.
exec mpcd start \
--node-id="zoo-mpc-node-${ORD}" \
--data=/data/mpcd \
--listen=:9999 \
--api=:9800 \
--api-listen=:8081 \
--threshold=3 \
--jwt-secret="${MPC_JWT_SECRET}" \
--peer="zoo-mpc-node-0@mpc-node-0.mpc-node-headless.zoo-mpc.svc.cluster.local:9999" \
--peer="zoo-mpc-node-1@mpc-node-1.mpc-node-headless.zoo-mpc.svc.cluster.local:9999" \
--peer="zoo-mpc-node-2@mpc-node-2.mpc-node-headless.zoo-mpc.svc.cluster.local:9999" \
--peer="zoo-mpc-node-3@mpc-node-3.mpc-node-headless.zoo-mpc.svc.cluster.local:9999" \
--peer="zoo-mpc-node-4@mpc-node-4.mpc-node-headless.zoo-mpc.svc.cluster.local:9999"
ports:
- containerPort: 9999
name: p2p
protocol: TCP
- containerPort: 9800
name: internal
protocol: TCP
- containerPort: 8081
name: api
protocol: TCP
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
# All secret material is bootstrap-generated into the mpc-secrets Secret
# (see secrets.yaml + deploy.sh) and mirrored into the Zoo KMS for
# durability. NEVER hardcoded, NEVER committed in plaintext.
# Bearer/dashboard JWT signing key:
- name: MPC_JWT_SECRET
valueFrom:
secretKeyRef:
name: mpc-secrets
key: jwt-secret
# ZapDB at-rest encryption password (REK). hsm-provider defaults to
# `env`, which reads MPC_PASSWORD. LOSS = unreadable DKG store.
- name: MPC_PASSWORD
valueFrom:
secretKeyRef:
name: mpc-secrets
key: mpc-password
# Shared static bearers — identical across all 5 nodes so cloud/peers
# present ONE token. Random 32-byte, in the mpc-internal-api Secret.
- name: MPC_INTERNAL_API_KEY
valueFrom:
secretKeyRef:
name: mpc-internal-api
key: MPC_INTERNAL_API_KEY
- name: MPC_THRESHOLD_AUTH_TOKEN
valueFrom:
secretKeyRef:
name: mpc-internal-api
key: MPC_THRESHOLD_AUTH_TOKEN
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "2Gi"
cpu: "1000m"
volumeMounts:
- name: data
mountPath: /data/mpcd
readinessProbe:
httpGet:
path: /readyz
port: api
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
livenessProbe:
httpGet:
path: /health
port: api
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
volumeClaimTemplates:
- metadata:
name: data
labels:
app.kubernetes.io/part-of: mpc
spec:
accessModes: ["ReadWriteOnce"]
# Retain so an accidental PVC delete never nukes the Zoo DKG store.
storageClassName: do-block-storage-retain
resources:
requests:
storage: 10Gi
---
# Headless service for StatefulSet DNS (pod-to-pod peer discovery).
apiVersion: v1
kind: Service
metadata:
name: mpc-node-headless
namespace: zoo-mpc
labels:
app: mpc-node
app.kubernetes.io/part-of: mpc
brand: zoo
spec:
clusterIP: None
selector:
app: mpc-node
ports:
- port: 9999
targetPort: 9999
name: p2p
- port: 9800
targetPort: 9800
name: internal
- port: 8081
targetPort: 8081
name: api
---
# Dashboard/API service — fronts all 5 nodes on the dashboard API port.
# Backs the mpc.zoo.network route (ingress.yaml).
apiVersion: v1
kind: Service
metadata:
name: mpc-api-svc
namespace: zoo-mpc
labels:
app: mpc-node
app.kubernetes.io/component: api
app.kubernetes.io/part-of: mpc
brand: zoo
spec:
type: ClusterIP
selector:
app: mpc-node
ports:
- port: 8081
targetPort: 8081
name: api