diff --git a/README.md b/README.md index 7cff05b..13d7a65 100644 --- a/README.md +++ b/README.md @@ -1 +1,20 @@ # beelocal + +Spinup local k8s infra with geth and bee up and running. + +## P2P-WSS Support + +Enable P2P WebSocket Secure (WSS) support by setting `P2P_WSS_ENABLE=true`. This deploys: + +- **Pebble**: ACME test CA for certificate issuance +- **p2p-forge**: DNS server for ACME DNS-01 challenge handling + +### Bee Node Configuration + +When `P2P_WSS_ENABLE=true`, configure your Bee nodes with: + +```bash +--autotls-domain="local.test" +--autotls-registration-endpoint="http://p2p-forge.local.svc.cluster.local:8080" +--autotls-ca-endpoint="https://pebble:14000/dir" +``` diff --git a/beelocal.sh b/beelocal.sh index 8b89e59..ce42b9b 100755 --- a/beelocal.sh +++ b/beelocal.sh @@ -37,6 +37,10 @@ declare -x SETUP_CONTRACT_IMAGE=${SETUP_CONTRACT_IMAGE:-ethersphere/bee-localcha declare -x SETUP_CONTRACT_IMAGE_TAG=${SETUP_CONTRACT_IMAGE_TAG:-latest} declare -x NAMESPACE=${NAMESPACE:-local} declare -x BEEKEEPER_CLUSTER=${BEEKEEPER_CLUSTER:-local} +declare -x P2P_WSS_ENABLE=${P2P_WSS_ENABLE:-false} +declare -x PEBBLE_IMAGE_TAG=${PEBBLE_IMAGE_TAG:-2.9.0} +declare -x P2P_FORGE_IMAGE_TAG=${P2P_FORGE_IMAGE_TAG:-v0.7.0} +declare -x PEBBLE_CERTIFICATE_VALIDITY_PERIOD=${PEBBLE_CERTIFICATE_VALIDITY_PERIOD:-300} check() { if ! grep -qE "docker|admin" <<< "$(id "$(whoami)")"; then @@ -111,11 +115,25 @@ config() { trap 'rm -rf ${BEE_TEMP}' EXIT curl -sSL https://raw.githubusercontent.com/ethersphere/beelocal/"${BEELOCAL_BRANCH}"/config/k3d.yaml -o "${BEE_TEMP}"/k3d.yaml curl -sSL https://raw.githubusercontent.com/ethersphere/beelocal/"${BEELOCAL_BRANCH}"/config/geth-swap.yaml -o "${BEE_TEMP}"/geth-swap.yaml + if [[ "${P2P_WSS_ENABLE}" == "true" ]]; then + # download, but if it fails or file is invalid, use local files in deploy-p2p-wss + if ! curl -sSL https://raw.githubusercontent.com/ethersphere/beelocal/"${BEELOCAL_BRANCH}"/config/pebble-deployment.yaml -o "${BEE_TEMP}"/pebble-deployment.yaml 2>/dev/null || \ + ! grep -q "^apiVersion:" "${BEE_TEMP}"/pebble-deployment.yaml 2>/dev/null; then + rm -f "${BEE_TEMP}"/pebble-deployment.yaml + fi + if ! curl -sSL https://raw.githubusercontent.com/ethersphere/beelocal/"${BEELOCAL_BRANCH}"/config/p2p-forge-deployment.yaml -o "${BEE_TEMP}"/p2p-forge-deployment.yaml 2>/dev/null || \ + ! grep -q "^apiVersion:" "${BEE_TEMP}"/p2p-forge-deployment.yaml 2>/dev/null; then + rm -f "${BEE_TEMP}"/p2p-forge-deployment.yaml + fi + fi if [[ -n $CI ]]; then curl -sSL https://raw.githubusercontent.com/ethersphere/beelocal/"${BEELOCAL_BRANCH}"/hack/registries.yaml -o "${BEE_TEMP}"/registries.yaml sudo cp "${BEE_TEMP}"/registries.yaml /etc/rancher/k3s/registries.yaml fi BEE_CONFIG="${BEE_TEMP}" + else + # Use local config files + BEE_CONFIG="config" fi } @@ -260,6 +278,78 @@ geth() { fi } +deploy-p2p-wss() { + if [[ "${P2P_WSS_ENABLE}" != "true" ]]; then + return 0 + fi + + if [[ -z $BEE_CONFIG ]]; then + config + fi + + echo "deploying P2P-WSS support..." + + # Apply Pebble deployment - use remote file if it exists and is valid, otherwise use local + echo "deploying Pebble (ghcr.io/letsencrypt/pebble:${PEBBLE_IMAGE_TAG})..." + if [[ -f "${BEE_CONFIG}"/pebble-deployment.yaml ]] && grep -q "^apiVersion:" "${BEE_CONFIG}"/pebble-deployment.yaml 2>/dev/null; then + envsubst '${PEBBLE_IMAGE_TAG},${PEBBLE_CERTIFICATE_VALIDITY_PERIOD}' < "${BEE_CONFIG}"/pebble-deployment.yaml | kubectl apply -f - + elif [[ -f config/pebble-deployment.yaml ]]; then + envsubst '${PEBBLE_IMAGE_TAG}' < config/pebble-deployment.yaml | kubectl apply -f - + else + echo "pebble-deployment.yaml not found..." + return 1 + fi + + # Wait for Pebble to be ready + echo "waiting for Pebble to be ready..." + kubectl rollout status deployment/pebble -n "${NAMESPACE}" --timeout=120s || true + + # Apply p2p-forge deployment - use remote file if it exists and is valid, otherwise use local + echo "deploying p2p-forge (ghcr.io/ipshipyard/p2p-forge:${P2P_FORGE_IMAGE_TAG})..." + if [[ -f "${BEE_CONFIG}"/p2p-forge-deployment.yaml ]] && grep -q "^apiVersion:" "${BEE_CONFIG}"/p2p-forge-deployment.yaml 2>/dev/null; then + envsubst '${P2P_FORGE_IMAGE_TAG}' < "${BEE_CONFIG}"/p2p-forge-deployment.yaml | kubectl apply -f - + elif [[ -f config/p2p-forge-deployment.yaml ]]; then + envsubst '${P2P_FORGE_IMAGE_TAG}' < config/p2p-forge-deployment.yaml | kubectl apply -f - + else + echo "p2p-forge-deployment.yaml not found..." + return 1 + fi + + # Wait for p2p-forge to be ready + echo "waiting for p2p-forge to be ready..." + kubectl rollout status deployment/p2p-forge -n "${NAMESPACE}" --timeout=120s || true + + # Configure CoreDNS to forward local.test queries to p2p-forge + echo "configuring CoreDNS to forward local.test to p2p-forge..." + + # Check if local.test forwarding is already configured + if kubectl get cm coredns -n kube-system -o jsonpath='{.data.Corefile}' | grep -q "local.test"; then + echo "CoreDNS already configured for local.test, skipping..." + else + # Patch CoreDNS configmap to add local.test forwarding + P2P_FORGE_IP=$(kubectl get svc p2p-forge -n "${NAMESPACE}" -o jsonpath='{.spec.clusterIP}') + LOCAL_TEST_BLOCK="local.test:53 { + errors + cache 30 + forward . ${P2P_FORGE_IP}:53 +}" + # Get current Corefile, append local.test block, and apply + CURRENT_COREFILE=$(kubectl get cm coredns -n kube-system -o jsonpath='{.data.Corefile}') + NEW_COREFILE="${CURRENT_COREFILE} +${LOCAL_TEST_BLOCK}" + + kubectl create configmap coredns -n kube-system \ + --from-literal=Corefile="${NEW_COREFILE}" \ + --dry-run=client -o yaml | kubectl apply -f - + + kubectl rollout restart deployment coredns -n kube-system + kubectl rollout status deployment/coredns -n kube-system --timeout=60s || true + echo "CoreDNS configured for local.test forwarding..." + fi + + echo "Pebble and p2p-forge deployed successfully..." +} + stop() { if [[ -n $CI ]]; then echo "action not supported for CI" @@ -351,6 +441,7 @@ if [[ " ${ACTIONS[*]} " == *"$ACTION"* ]]; then elif ! k3d cluster list bee --no-headers &> /dev/null; then k8s-local fi + deploy-p2p-wss install elif [[ $ACTION == "prepare" ]]; then check @@ -362,6 +453,7 @@ if [[ " ${ACTIONS[*]} " == *"$ACTION"* ]]; then elif [[ -z $SKIP_LOCAL ]]; then build fi + deploy-p2p-wss else $ACTION fi diff --git a/config/p2p-forge-deployment.yaml b/config/p2p-forge-deployment.yaml new file mode 100644 index 0000000..8a80554 --- /dev/null +++ b/config/p2p-forge-deployment.yaml @@ -0,0 +1,86 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: p2p-forge-config + namespace: local +data: + Corefile: | + .:53 { + errors + log + acme local.test { + registration-domain p2p-forge.local.svc.cluster.local:8080 listen-address=:8080 external-tls=true + database-type badger /data + } + } +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: p2p-forge + namespace: local + labels: + app: p2p-forge +spec: + replicas: 1 + selector: + matchLabels: + app: p2p-forge + template: + metadata: + labels: + app: p2p-forge + spec: + containers: + - name: p2p-forge + image: ghcr.io/ipshipyard/p2p-forge:${P2P_FORGE_IMAGE_TAG} + args: + - "-conf" + - "/config/Corefile" + ports: + - name: api + containerPort: 8080 + protocol: TCP + - name: dns + containerPort: 53 + protocol: UDP + volumeMounts: + - name: p2p-forge-config + mountPath: /config + - name: p2p-forge-data + mountPath: /data + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumes: + - name: p2p-forge-config + configMap: + name: p2p-forge-config + - name: p2p-forge-data + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: p2p-forge + namespace: local + labels: + app: p2p-forge +spec: + type: ClusterIP + ports: + - name: api + port: 8080 + targetPort: 8080 + protocol: TCP + - name: dns + port: 53 + targetPort: 53 + protocol: UDP + selector: + app: p2p-forge + diff --git a/config/pebble-deployment.yaml b/config/pebble-deployment.yaml new file mode 100644 index 0000000..c268d58 --- /dev/null +++ b/config/pebble-deployment.yaml @@ -0,0 +1,105 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: pebble-config + namespace: local +data: + pebble-config.json: | + { + "pebble": { + "listenAddress": "0.0.0.0:14000", + "managementListenAddress": "0.0.0.0:15000", + "certificate": "/test/certs/localhost/cert.pem", + "privateKey": "/test/certs/localhost/key.pem", + "httpPort": 5002, + "tlsPort": 5001, + "ocspResponderURL": "", + "externalAccountBindingRequired": false, + "certificateValidityPeriod": ${PEBBLE_CERTIFICATE_VALIDITY_PERIOD} + } + } +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pebble + namespace: local + labels: + app: pebble +spec: + replicas: 1 + selector: + matchLabels: + app: pebble + template: + metadata: + labels: + app: pebble + spec: + containers: + - name: pebble + image: ghcr.io/letsencrypt/pebble:${PEBBLE_IMAGE_TAG} + args: + - "-config" + - "/config/pebble-config.json" + ports: + - name: http + containerPort: 5002 + protocol: TCP + - name: https + containerPort: 5001 + protocol: TCP + - name: acme + containerPort: 14000 + protocol: TCP + - name: management + containerPort: 15000 + protocol: TCP + env: + - name: PEBBLE_VA_ALWAYS_VALID + value: "1" + - name: PEBBLE_WFE_NONCEREJECT + value: "0" + volumeMounts: + - name: pebble-config + mountPath: /config + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumes: + - name: pebble-config + configMap: + name: pebble-config +--- +apiVersion: v1 +kind: Service +metadata: + name: pebble + namespace: local + labels: + app: pebble +spec: + type: ClusterIP + ports: + - name: http + port: 80 + targetPort: 5002 + protocol: TCP + - name: https + port: 443 + targetPort: 5001 + protocol: TCP + - name: acme + port: 14000 + targetPort: 14000 + protocol: TCP + - name: management + port: 15000 + targetPort: 15000 + protocol: TCP + selector: + app: pebble