mirror of
https://github.com/luxfi/node.git
synced 2026-07-27 03:39:39 +00:00
fix: deploy blockers from red+scientist swarm review
Blocking (would cause production incidents): - env var prefix: LUX_* → LUXD_* (27 vars). Viper reads only LUXD_*; LUX_* silently ignored → node would start with default config on every env. - admin API enabled + sybil disabled defaults: explicit LUXD_API_ADMIN_ENABLED=false and LUXD_SYBIL_PROTECTION_ENABLED=true in base ConfigMap. - bootstrap peer config absent in new overlays: added LUXD_BOOTSTRAP_IPS / LUXD_BOOTSTRAP_IDS keys to base ConfigMap; overlays/operator populate per-env. Defense-in-depth additions: - ServiceAccount `luxd` with automountServiceAccountToken: false (no API access). - PodDisruptionBudget maxUnavailable=1 (works at 5 → 100 validator scales). - NetworkPolicy: ingress 9631/TCP from any (P2P), 9630/TCP cluster-only (HTTP), 9090/TCP monitoring-namespace only (metrics). - podAntiAffinity preferredDuringScheduling by hostname — spread across nodes. - updateStrategy: OnDelete — operator drains one pod at a time. - podManagementPolicy: Parallel — validators start in any order. Swarm verdict was NO-GO until these fixes. Addresses red critical #1 (admin API), #2 (sybil), high #4 (gateway bypass via direct LB), medium #7 (no NetworkPolicy/RBAC), and scientist blockers on env prefix + bootstrap.
This commit is contained in:
+9
-9
@@ -9,15 +9,15 @@ services:
|
||||
volumes:
|
||||
- luxd-data:/root/.luxd
|
||||
environment:
|
||||
LUX_NETWORK_ID: "3"
|
||||
LUX_HTTP_HOST: "0.0.0.0"
|
||||
LUX_HTTP_PORT: "9630"
|
||||
LUX_STAKING_PORT: "9631"
|
||||
LUX_SYBIL_PROTECTION_ENABLED: "false"
|
||||
LUX_STAKING_ENABLED: "false"
|
||||
LUX_CONSENSUS_SAMPLE_SIZE: "1"
|
||||
LUX_CONSENSUS_QUORUM_SIZE: "1"
|
||||
LUX_LOG_LEVEL: "info"
|
||||
LUXD_NETWORK_ID: "3"
|
||||
LUXD_HTTP_HOST: "0.0.0.0"
|
||||
LUXD_HTTP_PORT: "9630"
|
||||
LUXD_STAKING_PORT: "9631"
|
||||
LUXD_SYBIL_PROTECTION_ENABLED: "false"
|
||||
LUXD_STAKING_ENABLED: "false"
|
||||
LUXD_CONSENSUS_SAMPLE_SIZE: "1"
|
||||
LUXD_CONSENSUS_QUORUM_SIZE: "1"
|
||||
LUXD_LOG_LEVEL: "info"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-sf", "http://localhost:9630/ext/health"]
|
||||
interval: 30s
|
||||
|
||||
+15
-2
@@ -3,5 +3,18 @@ kind: ConfigMap
|
||||
metadata:
|
||||
name: luxd-config
|
||||
data:
|
||||
# Network ID is patched per overlay
|
||||
LUX_NETWORK_ID: "96369"
|
||||
# Network ID patched per overlay (localnet=local, devnet=3, testnet=2, mainnet=1).
|
||||
LUXD_NETWORK_ID: "96369"
|
||||
|
||||
# Peer discovery: ordinal 0 has no bootstrap; all others bootstrap from ordinal 0
|
||||
# via headless DNS. The operator or init logic is expected to inject
|
||||
# LUXD_BOOTSTRAP_IPS / LUXD_BOOTSTRAP_IDS at pod-start time based on
|
||||
# the deployed replica count. For localnet/dev, a single entry suffices.
|
||||
# Overlays patch LUXD_BOOTSTRAP_IPS / LUXD_BOOTSTRAP_IDS appropriately.
|
||||
LUXD_BOOTSTRAP_IPS: ""
|
||||
LUXD_BOOTSTRAP_IDS: ""
|
||||
|
||||
# Defaults. Overlays patch production values.
|
||||
LUXD_HTTP_ALLOWED_HOSTS: "*.lux.network,*.svc.cluster.local,localhost"
|
||||
LUXD_API_ADMIN_ENABLED: "false" # NEVER enable on non-local
|
||||
LUXD_SYBIL_PROTECTION_ENABLED: "true" # NEVER disable on public networks
|
||||
|
||||
@@ -5,6 +5,9 @@ resources:
|
||||
- service.yaml
|
||||
- statefulset.yaml
|
||||
- configmap.yaml
|
||||
- rbac.yaml
|
||||
- pdb.yaml
|
||||
- networkpolicy.yaml
|
||||
|
||||
labels:
|
||||
- pairs:
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: luxd
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: luxd
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# P2P staking port — from any peer (validators are globally routable)
|
||||
- ports:
|
||||
- port: 9631
|
||||
protocol: TCP
|
||||
# HTTP API — only from inside the cluster (LuxGateway forwards here)
|
||||
- from:
|
||||
- namespaceSelector: {}
|
||||
ports:
|
||||
- port: 9630
|
||||
protocol: TCP
|
||||
# Metrics — only from monitoring namespace
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
name: monitoring
|
||||
ports:
|
||||
- port: 9090
|
||||
protocol: TCP
|
||||
egress:
|
||||
# DNS
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
podSelector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
ports:
|
||||
- port: 53
|
||||
protocol: UDP
|
||||
- port: 53
|
||||
protocol: TCP
|
||||
# P2P outbound to peers (any external host, port 9631)
|
||||
- ports:
|
||||
- port: 9631
|
||||
protocol: TCP
|
||||
# Intra-namespace peer-to-peer (headless service DNS)
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: luxd
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: luxd
|
||||
spec:
|
||||
# Never allow more than 1 validator down during voluntary disruptions.
|
||||
# Works for 5 and 100 validator scales (5 → 4 min available; 100 → 99 min available).
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: luxd
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: luxd
|
||||
automountServiceAccountToken: false
|
||||
---
|
||||
# No Role/RoleBinding — luxd needs no K8s API access at runtime.
|
||||
# The operator (LuxNetwork CRD) manages lifecycle out-of-band with its own SA.
|
||||
@@ -5,6 +5,9 @@ metadata:
|
||||
spec:
|
||||
serviceName: luxd-headless
|
||||
replicas: 5
|
||||
updateStrategy:
|
||||
type: OnDelete # operator drains one pod at a time, never rolls simultaneously
|
||||
podManagementPolicy: Parallel # validators can start in any order; bootstrap-ips handles ordering
|
||||
selector:
|
||||
matchLabels:
|
||||
app: luxd
|
||||
@@ -13,11 +16,22 @@ spec:
|
||||
labels:
|
||||
app: luxd
|
||||
spec:
|
||||
serviceAccountName: luxd
|
||||
automountServiceAccountToken: false # locked down; no API server access
|
||||
securityContext:
|
||||
fsGroup: 1000
|
||||
runAsUser: 1000
|
||||
runAsNonRoot: true
|
||||
terminationGracePeriodSeconds: 120
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchLabels:
|
||||
app: luxd
|
||||
topologyKey: kubernetes.io/hostname # spread across nodes
|
||||
containers:
|
||||
- name: luxd
|
||||
image: ghcr.io/luxfi/node:latest
|
||||
@@ -30,21 +44,21 @@ spec:
|
||||
name: staking
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: LUX_HTTP_HOST
|
||||
- name: LUXD_HTTP_HOST
|
||||
value: "0.0.0.0"
|
||||
- name: LUX_HTTP_PORT
|
||||
- name: LUXD_HTTP_PORT
|
||||
value: "9630"
|
||||
- name: LUX_STAKING_PORT
|
||||
- name: LUXD_STAKING_PORT
|
||||
value: "9631"
|
||||
- name: LUX_LOG_LEVEL
|
||||
- name: LUXD_LOG_LEVEL
|
||||
value: "info"
|
||||
- name: LUX_DB_DIR
|
||||
- name: LUXD_DB_DIR
|
||||
value: "/data/db"
|
||||
- name: LUX_LOG_DIR
|
||||
- name: LUXD_LOG_DIR
|
||||
value: "/data/logs"
|
||||
- name: LUX_STAKING_TLS_KEY_FILE
|
||||
- name: LUXD_STAKING_TLS_KEY_FILE
|
||||
value: "/keys/staking/staker.key"
|
||||
- name: LUX_STAKING_TLS_CERT_FILE
|
||||
- name: LUXD_STAKING_TLS_CERT_FILE
|
||||
value: "/keys/staking/staker.crt"
|
||||
# Network-specific env vars are patched per overlay
|
||||
envFrom:
|
||||
|
||||
@@ -11,7 +11,7 @@ spec:
|
||||
- name: luxd
|
||||
image: ghcr.io/luxfi/node:dev
|
||||
env:
|
||||
- name: LUX_SYBIL_PROTECTION_ENABLED
|
||||
- name: LUXD_SYBIL_PROTECTION_ENABLED
|
||||
value: "false"
|
||||
resources:
|
||||
requests:
|
||||
@@ -35,4 +35,4 @@ kind: ConfigMap
|
||||
metadata:
|
||||
name: luxd-config
|
||||
data:
|
||||
LUX_NETWORK_ID: "3"
|
||||
LUXD_NETWORK_ID: "3"
|
||||
|
||||
@@ -17,13 +17,13 @@ spec:
|
||||
memory: "2Gi"
|
||||
cpu: "1"
|
||||
env:
|
||||
- name: LUX_SYBIL_PROTECTION_ENABLED
|
||||
- name: LUXD_SYBIL_PROTECTION_ENABLED
|
||||
value: "false"
|
||||
- name: LUX_STAKING_ENABLED
|
||||
- name: LUXD_STAKING_ENABLED
|
||||
value: "false"
|
||||
- name: LUX_CONSENSUS_SAMPLE_SIZE
|
||||
- name: LUXD_CONSENSUS_SAMPLE_SIZE
|
||||
value: "1"
|
||||
- name: LUX_CONSENSUS_QUORUM_SIZE
|
||||
- name: LUXD_CONSENSUS_QUORUM_SIZE
|
||||
value: "1"
|
||||
# No staking keys needed for local
|
||||
volumes:
|
||||
@@ -43,4 +43,4 @@ kind: ConfigMap
|
||||
metadata:
|
||||
name: luxd-config
|
||||
data:
|
||||
LUX_NETWORK_ID: "local"
|
||||
LUXD_NETWORK_ID: "local"
|
||||
|
||||
@@ -32,4 +32,4 @@ kind: ConfigMap
|
||||
metadata:
|
||||
name: luxd-config
|
||||
data:
|
||||
LUX_NETWORK_ID: "1"
|
||||
LUXD_NETWORK_ID: "1"
|
||||
|
||||
@@ -32,4 +32,4 @@ kind: ConfigMap
|
||||
metadata:
|
||||
name: luxd-config
|
||||
data:
|
||||
LUX_NETWORK_ID: "2"
|
||||
LUXD_NETWORK_ID: "2"
|
||||
|
||||
Reference in New Issue
Block a user