V2.1 (#21)
Working version Reviewed-on: #21
This commit was merged in pull request #21.
This commit is contained in:
Executable
+45
@@ -0,0 +1,45 @@
|
||||
# Kubernetes mainnet preparation
|
||||
|
||||
This directory intentionally contains no apply-ready manifests yet. The code is mainnet-first and supports a genesis frozen into the browser bundle and runtime image, but the current launch gate requires deployment facts that were not supplied. Placeholder origins, approval IDs, TLS secrets, or storage settings would not produce a working or safe deployment.
|
||||
|
||||
## Required topology for this implementation
|
||||
|
||||
- Build and publish one immutable image with `WIKIDECK_NETWORK=mainnet` and one chosen `WIKIDECK_GENESIS_TIME`. Give every peer and browser bundle that same chain identity. A runtime-only genesis override is rejected by the image manifest check.
|
||||
- Give each node a stable, unique public HTTPS origin. TLS must terminate at an operator-managed ingress/reverse proxy; the application listener itself is HTTP on port 3001.
|
||||
- Configure at least two other distinct public HTTPS peer origins per node for public peering. Private IPs/DNS and HTTP are rejected by default. An operator-controlled private candidate cluster may explicitly set `WIKIDECK_ALLOW_PRIVATE_PEERS=1` and use distinct per-node ClusterIP DNS origins. This opt-in does not change the exact chain-ID/risk/genesis gates or the HTTPS browser-origin requirement.
|
||||
- Route each public peer hostname deterministically to exactly one node. A shared load-balanced hostname is not a stable peer identity. Separate per-peer Deployments/Services/Ingress routes are the simplest current shape; each node must exclude its own origin from its peer list.
|
||||
- Give every node an exclusive persistent volume mounted at `/app/data`. Never share a ledger volume between pods. Agree the storage class, capacity, backup/restore procedure, resource limits, failure domains, and upgrade/reorg policy before enabling the launch approval.
|
||||
- Configure the exact manifest `CHAIN_ID` as `WIKIDECK_MAINNET_LAUNCH`, and explicitly set `WIKIDECK_MAINNET_RISK_ACK=operator-accepts-unaudited-risk`. The latter accepts unaudited residual risk; it is not an audit or readiness check.
|
||||
|
||||
## Pod hardening baseline
|
||||
|
||||
Use a dedicated namespace and least-privilege service account (or disable token automount if no Kubernetes API access is needed), non-root execution matching the image's `node` user, read-only root filesystem, dropped Linux capabilities, `allowPrivilegeEscalation: false`, `seccompProfile: RuntimeDefault`, and a bounded writable `/tmp` volume. Use resource requests and limits based on measured RandomX/replay/sync behavior, not guesses. Readiness/liveness should use `/healthz`; allow a startup grace period for ledger replay and native engine initialization. Restrict ingress to the reviewed edge and egress to DNS, the configured public peers, and required Wikimedia endpoints. Add NetworkPolicy, TLS, image provenance/signature enforcement, monitoring, and tested encrypted backups through the cluster's established platform controls.
|
||||
|
||||
Do not make the public origin or configured peers imply that peers are independent or that the network is secure. This software has no external audit, public bootstrap service, peer discovery, or demonstrated production capacity.
|
||||
|
||||
## Private candidate cluster
|
||||
|
||||
Deploy the public node and two internal peers as three separate single-replica
|
||||
role instances, each with its own Service and PVC. Configure each peer list with
|
||||
the other two Services, for example `http://wikideck-peer-a.wikideck.svc.cluster.local:80`.
|
||||
Allow same-namespace validator pods on target TCP 3001 through both ingress and
|
||||
egress NetworkPolicy; Service port 80 is translated to that target port. Only the
|
||||
public node needs ingress; all nodes may use the public node's HTTPS browser
|
||||
origin. Keep API credentials and wallet keys out of validator pods.
|
||||
|
||||
Read `--network-manifest` from the exact published image to obtain the candidate
|
||||
chain ID without opening storage or starting a listener. Its
|
||||
`privatePeersSupported: true` capability distinguishes updated images from older
|
||||
images that reject this topology. Do not override genesis at runtime. The default
|
||||
image genesis is now fixed at November 1, 2026, 00:00 UTC (`1793491200`), so no
|
||||
January wait or custom build argument is needed. Rebuild and publish the updated
|
||||
image; an older published image still contains its previous genesis. Existing
|
||||
ledgers and wallets must retain their original chain identity.
|
||||
|
||||
Private peer RPC is unauthenticated and, with HTTP, unencrypted. Use a trusted
|
||||
cluster boundary and scoped policies; add mesh transport protection if needed.
|
||||
This topology does not demonstrate independent peers/miners or production readiness.
|
||||
|
||||
## Values needed before manifests can be finalized
|
||||
|
||||
Choose the genesis timestamp and image registry/digest; provide the namespace, ingress class and TLS/certificate mechanism, public DNS name per node, peer topology, storage class/size, resource budget, network-policy egress model, backup destination/retention, and desired availability/recovery behavior. Then calculate and publish the exact manifest and chain approval. Until those values and the peer topology are available, this checklist is the safe preparation artifact rather than a misleading runnable YAML template.
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
# Example for nginx on the SAME host as loopback-bound node :3201.
|
||||
# Not installed by this repository. Replace host/cert paths and validate real topology.
|
||||
# Node: WIKIDECK_TRUSTED_PROXIES=127.0.0.1,::1 (never use this for a container bridge without adjustment).
|
||||
limit_req_zone $binary_remote_addr zone=wikideck_ip:10m rate=5r/s;
|
||||
limit_conn_zone $binary_remote_addr zone=wikideck_conn:10m;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name wikideck.example.invalid;
|
||||
return 308 https://$host$request_uri;
|
||||
}
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name wikideck.example.invalid;
|
||||
ssl_certificate /etc/ssl/wikideck/fullchain.pem;
|
||||
ssl_certificate_key /etc/ssl/wikideck/private.key;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
server_tokens off;
|
||||
client_max_body_size 68k;
|
||||
client_body_timeout 15s;
|
||||
client_header_timeout 10s;
|
||||
keepalive_timeout 10s;
|
||||
send_timeout 30s;
|
||||
limit_conn wikideck_conn 16;
|
||||
limit_req_status 429;
|
||||
# Do not proxy private operations listener. Its port must never be publicly published.
|
||||
location / {
|
||||
limit_req zone=wikideck_ip burst=20 nodelay;
|
||||
proxy_pass http://127.0.0.1:3201;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
# Overwrite, do NOT append an untrusted client-supplied X-Forwarded-For chain.
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Forwarded "";
|
||||
proxy_set_header Connection "";
|
||||
proxy_connect_timeout 5s;
|
||||
proxy_send_timeout 15s;
|
||||
proxy_read_timeout 30s;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user