diff --git a/dist/linux-x64/README.md b/dist/linux-x64/README.md index 998bf8e..b23e7fa 100644 --- a/dist/linux-x64/README.md +++ b/dist/linux-x64/README.md @@ -21,7 +21,14 @@ Universal Linux binaries (statically linked with musl) for OSTP VPN server and c ## 🚀 Quick Start -### Server Installation +### Deployment Modes + +The OSTP server can be deployed in two modes: + +1. **Full Stack Mode** - Deploy ostp-server + oncp-master on one host (master node) +2. **Standalone Mode** - Connect ostp-server to existing master node using enrollment token + +### Server Installation (Recommended Method) #### 1. Verify Integrity @@ -29,19 +36,29 @@ Universal Linux binaries (statically linked with musl) for OSTP VPN server and c sha256sum -c SHA256SUMS ``` -#### 2. Deploy with Script (Recommended) +#### 2. Deploy with Script ```bash chmod +x deploy.sh sudo ./deploy.sh ``` -The script will: -- Install binaries to `/usr/local/bin/` +The script will prompt you to choose deployment mode: +- **Mode 1 (Standalone)**: Connect to existing master node with enrollment token +- **Mode 2 (Full Stack)**: Install both master and server on this host + +**Full Stack Mode** will: +- Install both ostp-server and oncp-master +- Generate PSK and enrollment tokens +- Set up 10.X.0.0/16 network - Create systemd services -- Generate PSK and network configuration -- Set up firewall rules -- Start services +- Configure firewall rules + +**Standalone Mode** will: +- Install ostp-server only +- Submit enrollment request to master +- Wait for admin approval +- Auto-configure after approval ### Client Installation @@ -88,6 +105,8 @@ sudo ostp-client-linux disconnect ### 3. Manual Installation +#### Full Stack Mode (Master + Server) + ```bash # Make binaries executable chmod +x ostp-server oncp-master @@ -102,29 +121,104 @@ echo "Generated PSK: $PSK" # Start oncp-master (control plane) sudo ./oncp-master serve --listen 0.0.0.0:8080 --network-octet 42 -# Generate enrollment token (expires in 3 minutes) -./oncp-master node token --expiry 3 +# Generate enrollment token (expires in 60 minutes) +./oncp-master node token --expiry 60 # Start ostp-server (VPN server) -sudo ./ostp-server -l 0.0.0.0:443 -p $PSK --master http://localhost:8080 +sudo ./ostp-server -c /etc/ostp/server.json +``` + +#### Standalone Mode (Connect to Existing Master) + +```bash +# Copy server binary +chmod +x ostp-server +sudo cp ostp-server /usr/local/bin/ + +# Create enrollment config (see server-enrollment.json.example) +cat > /etc/ostp/server.json < + +# After approval, update config with provided PSK and restart ``` ## 🔧 Configuration -### ostp-server Configuration +### ostp-server Configuration (Full Stack Mode) Create `/etc/ostp/server.json`: ```json { - "listen_addr": "0.0.0.0:443", + "listen": "0.0.0.0:443", "psk": "YOUR_64_CHAR_HEX_PSK", - "master_url": "http://localhost:8080", + "master_node_url": "http://localhost:8080", "country_code": "US", - "max_clients": 1000 + "max_connections": 1000 } ``` +### ostp-server Configuration (Standalone Mode with Enrollment) + +Create `/etc/ostp/server.json` (see `server-enrollment.json.example`): + +```json +{ + "listen": "0.0.0.0:443", + "psk": "AUTO", + "master_node_url": "http://master.example.com:8080", + "enrollment_token": "TOKEN_FROM_MASTER", + "node_name": "node-01", + "country_code": "US", + "region": "eu-central", + "hardware_id": "server-123", + "max_connections": 1000 +} +``` (Time-Limited One-Time Passwords) + +Nodes **must** provide a valid enrollment token to join the network: + +```bash +# Generate token on master node (60 minute expiry) +./oncp-master node token --expiry 60 + +# Token is shown once, must be used immediately +# Example: A1B2C3D4E5 + +# Invalid or expired tokens are silently dropped (no error response) +# This prevents token enumeration attacks +``` + +**Token Security:** +- Cryptographically secure random generation +- Stored in memory only (wiped after use or expiration) +- One-time use (consumed on first valid request) +- Time-based expiration (default 3 minutes) +- Silent drop on validation failure (no fingerprinting)rop if invalid - no error message) +4. Admin approves: `oncp-master node approve ` +5. Node receives PSK and assigned IP from 10.X.0.0/16 pool +6. Update config with PSK, change `psk: "AUTO"` to actual PSK +7. Restart server + ### oncp-master Configuration Environment variables: diff --git a/dist/linux-x64/SHA256SUMS b/dist/linux-x64/SHA256SUMS index 1cf1266..fbed33e 100644 --- a/dist/linux-x64/SHA256SUMS +++ b/dist/linux-x64/SHA256SUMS @@ -1,3 +1,3 @@ -cf3996eac77ed62d184452b3032e3bffc60c120e77cee57899a33893322b0cc4 ostp-client-linux -d3ec5b5ee8c90f1f92667458f44a795159157ae64e8d5073888838fbfce286e2 ostp-server +d9306f297f1b4558169098acd07fb455352fe198715b89064f20955371671eee ostp-server 53de7690ddcd22828d1d2c55bec75e7a43aa6476827d8162615549b08a1a39dc oncp-master +cf3996eac77ed62d184452b3032e3bffc60c120e77cee57899a33893322b0cc4 ostp-client-linux diff --git a/dist/linux-x64/deploy.sh b/dist/linux-x64/deploy.sh index 90486d6..11d97e2 100644 --- a/dist/linux-x64/deploy.sh +++ b/dist/linux-x64/deploy.sh @@ -45,15 +45,26 @@ fi # Configuration prompts echo echo -e "${YELLOW}═══ Configuration ═══${NC}" -read -p "Network octet (10.X.0.0/16, default 42): " NETWORK_OCTET -NETWORK_OCTET=${NETWORK_OCTET:-42} +echo "Deployment mode:" +echo " 1) Standalone server (connect to existing Master Node)" +echo " 2) Full stack (ostp-server + oncp-master on this host)" +read -p "Select mode (1 or 2, default 2): " DEPLOY_MODE +DEPLOY_MODE=${DEPLOY_MODE:-2} + +if [ "$DEPLOY_MODE" = "1" ]; then + read -p "Master Node URL (e.g., http://master.example.com:8080): " MASTER_URL + read -p "Enrollment token: " ENROLL_TOKEN + NETWORK_OCTET=0 # Will be assigned by master +else + read -p "Network octet (10.X.0.0/16, default 42): " NETWORK_OCTET + NETWORK_OCTET=${NETWORK_OCTET:-42} + read -p "oncp-master listen port (default 8080): " ONCP_PORT + ONCP_PORT=${ONCP_PORT:-8080} +fi read -p "ostp-server listen port (default 443): " OSTP_PORT OSTP_PORT=${OSTP_PORT:-443} -read -p "oncp-master listen port (default 8080): " ONCP_PORT -ONCP_PORT=${ONCP_PORT:-8080} - read -p "Install directory (default /usr/local/bin): " INSTALL_DIR INSTALL_DIR=${INSTALL_DIR:-/usr/local/bin} @@ -63,12 +74,16 @@ CONFIG_DIR=${CONFIG_DIR:-/etc/ostp} read -p "Database directory (default /var/lib/ostp): " DATA_DIR DATA_DIR=${DATA_DIR:-/var/lib/ostp} -# Generate PSK -echo -echo -e "${YELLOW}→${NC} Generating PSK..." -PSK=$(openssl rand -hex 32) -echo -e "${GREEN}✓${NC} PSK generated: ${YELLOW}${PSK}${NC}" -echo -e "${RED}⚠ SAVE THIS PSK! It will be stored in ${CONFIG_DIR}/server.json${NC}" +# Generate PSK (only for full stack mode) +if [ "$DEPLOY_MODE" = "2" ]; then + echo + echo -e "${YELLOW}→${NC} Generating PSK..." + PSK=$(openssl rand -hex 32) + echo -e "${GREEN}✓${NC} PSK generated: ${YELLOW}${PSK}${NC}" + echo -e "${RED}⚠ SAVE THIS PSK! It will be stored in ${CONFIG_DIR}/server.json${NC}" +else + PSK="AUTO" # Will be assigned by master after approval +fi # Create directories echo @@ -85,19 +100,36 @@ chmod +x "$INSTALL_DIR/ostp-server" "$INSTALL_DIR/oncp-master" echo -e "${GREEN}✓${NC} Binaries installed to $INSTALL_DIR" # Create ostp-server config -cat > "$CONFIG_DIR/server.json" < "$CONFIG_DIR/server.json" < "$CONFIG_DIR/server.json" < /etc/systemd/system/oncp-master.service < /etc/systemd/system/ostp-server.service </dev/null | grep -A1 "Token:" | tail -1 | xargs) -echo -e "${GREEN}✓${NC} Enrollment token (60 min): ${YELLOW}${TOKEN}${NC}" - -# Start ostp-server -systemctl start ostp-server +if [ "$DEPLOY_MODE" = "2" ]; then + # Full stack mode + systemctl enable oncp-master ostp-server + systemctl start oncp-master + + # Wait for oncp-master to start + sleep 2 + + # Generate enrollment token + echo -e "${YELLOW}→${NC} Generating enrollment token..." + TOKEN=$(${INSTALL_DIR}/oncp-master node token --expiry 60 2>/dev/null | grep -A1 "Token:" | tail -1 | xargs) + echo -e "${GREEN}✓${NC} Enrollment token (60 min): ${YELLOW}${TOKEN}${NC}" + + # Start ostp-server + systemctl start ostp-server +else + # Standalone mode - just enable and start ostp-server + systemctl enable ostp-server + systemctl start ostp-server + TOKEN="N/A (using enrollment token from config)" +fi echo echo -e "${GREEN}╔════════════════════════════════════════╗${NC}" @@ -193,23 +235,40 @@ echo -e "${GREEN}║ Deployment Complete! ✓ ║${NC}" echo -e "${GREEN}╚════════════════════════════════════════╝${NC}" echo echo -e "${YELLOW}Services Status:${NC}" -systemctl status oncp-master --no-pager -l || true +if [ "$DEPLOY_MODE" = "2" ]; then + systemctl status oncp-master --no-pager -l || true +fi systemctl status ostp-server --no-pager -l || true echo echo -e "${YELLOW}Important Information:${NC}" -echo -e " • Network: ${GREEN}10.${NETWORK_OCTET}.0.0/16${NC}" -echo -e " • Master IP: ${GREEN}10.${NETWORK_OCTET}.0.1${NC}" -echo -e " • PSK: ${YELLOW}${PSK}${NC}" -echo -e " • Enrollment Token: ${YELLOW}${TOKEN}${NC} (expires in 60 minutes)" +if [ "$DEPLOY_MODE" = "2" ]; then + echo -e " • Mode: ${GREEN}Full Stack (Master + Server)${NC}" + echo -e " • Network: ${GREEN}10.${NETWORK_OCTET}.0.0/16${NC}" + echo -e " • Master IP: ${GREEN}10.${NETWORK_OCTET}.0.1${NC}" + echo -e " • PSK: ${YELLOW}${PSK}${NC}" + echo -e " • Enrollment Token: ${YELLOW}${TOKEN}${NC} (expires in 60 minutes)" + echo -e " • Database: ${DATA_DIR}/oncp.db" +else + echo -e " • Mode: ${GREEN}Standalone Server${NC}" + echo -e " • Master URL: ${GREEN}${MASTER_URL}${NC}" + echo -e " • Status: ${YELLOW}Waiting for approval${NC}" +fi +echo -e " • Listen: ${GREEN}0.0.0.0:${OSTP_PORT}${NC}" echo -e " • Config: ${CONFIG_DIR}/server.json" -echo -e " • Database: ${DATA_DIR}/oncp.db" echo -e " • Logs: /var/log/ostp/" echo -echo -e "${YELLOW}Next Steps:${NC}" -echo -e " 1. Enroll nodes: ${GREEN}ostp-server --token ${TOKEN} --master https://your-master${NC}" -echo -e " 2. Approve nodes: ${GREEN}oncp-master node pending${NC} → ${GREEN}oncp-master node approve ${NC}" -echo -e " 3. Create users: ${GREEN}oncp-master user create --quota 100 --days 30${NC}" -echo -e " 4. Monitor logs: ${GREEN}journalctl -u ostp-server -f${NC}" +if [ "$DEPLOY_MODE" = "2" ]; then + echo -e "${YELLOW}Next Steps (Master Node):${NC}" + echo -e " 1. Approve nodes: ${GREEN}oncp-master node pending${NC} → ${GREEN}oncp-master node approve ${NC}" + echo -e " 2. Create users: ${GREEN}oncp-master user create --quota 100 --days 30${NC}" + echo -e " 3. Monitor logs: ${GREEN}journalctl -u oncp-master -f${NC}" +else + echo -e "${YELLOW}Next Steps (Standalone Server):${NC}" + echo -e " 1. Ask admin to approve node on master" + echo -e " 2. Check approval status: ${GREEN}journalctl -u ostp-server -f${NC}" + echo -e " 3. After approval, server will auto-restart with assigned PSK and IP" +fi +echo -e " 4. Monitor server: ${GREEN}journalctl -u ostp-server -f${NC}" echo echo -e "${RED}⚠ Security Reminder:${NC}" echo -e " • Save PSK in password manager" diff --git a/dist/linux-x64/ostp-server b/dist/linux-x64/ostp-server index 11f2aa1..0b27628 100644 Binary files a/dist/linux-x64/ostp-server and b/dist/linux-x64/ostp-server differ diff --git a/dist/linux-x64/server-enrollment.json.example b/dist/linux-x64/server-enrollment.json.example index 5c0e3cd..f1f34cf 100644 --- a/dist/linux-x64/server-enrollment.json.example +++ b/dist/linux-x64/server-enrollment.json.example @@ -1,8 +1,11 @@ { - "listen_addr": "0.0.0.0:443", - "enrollment_token": "ABC123XYZ0", - "master_url": "https://master-node.example.com:8080", + "listen": "0.0.0.0:443", + "psk": "AUTO", + "master_node_url": "http://master.example.com:8080", + "enrollment_token": "PASTE_TOKEN_FROM_MASTER_NODE_HERE", + "node_name": "node-01", "country_code": "US", - "region": "us-west", - "node_name": "node-01" + "region": "eu-central", + "hardware_id": "server-123", + "max_connections": 1000 } diff --git a/dist/linux-x64/server.json.example b/dist/linux-x64/server.json.example index 686096d..c3315ba 100644 --- a/dist/linux-x64/server.json.example +++ b/dist/linux-x64/server.json.example @@ -1,7 +1,7 @@ { - "listen_addr": "0.0.0.0:443", + "listen": "0.0.0.0:443", "psk": "CHANGE_THIS_64_CHARACTER_HEX_PSK_GENERATED_WITH_OPENSSL_RAND", - "master_url": "http://127.0.0.1:8080", + "master_node_url": "http://127.0.0.1:8080", "country_code": "US", - "max_clients": 1000 + "max_connections": 1000 } diff --git a/dist/ostp-server-linux-x64.tar.gz b/dist/ostp-server-linux-x64.tar.gz index 37a0cc5..2a458bb 100644 Binary files a/dist/ostp-server-linux-x64.tar.gz and b/dist/ostp-server-linux-x64.tar.gz differ diff --git a/ostp-server/src/main.rs b/ostp-server/src/main.rs index 86d0f48..e816a9d 100644 --- a/ostp-server/src/main.rs +++ b/ostp-server/src/main.rs @@ -58,6 +58,7 @@ struct ConfigFile { // Node enrollment settings master_node_url: Option, + enrollment_token: Option, node_name: Option, hardware_id: Option, region: Option, @@ -154,10 +155,16 @@ async fn main() -> Result<()> { if let Some(master_url) = config.master_node_url { if config.psk == "AUTO" { // Node needs to enroll - request PSK from master + let token = config.enrollment_token.ok_or_else(|| { + anyhow::anyhow!("enrollment_token is required when psk is AUTO") + })?; + tracing::info!("Node not enrolled - requesting to join network..."); + tracing::info!("Using enrollment token: {}...{}", &token[..4], &token[token.len().saturating_sub(4)..]); let enrollment_result = request_enrollment( &master_url, + &token, config.node_name.as_deref().unwrap_or("ostp-node"), &listen.to_string(), config.country_code.as_deref().unwrap_or("US"), @@ -214,6 +221,7 @@ async fn main() -> Result<()> { /// Submit enrollment request to master node async fn request_enrollment( master_url: &str, + token: &str, name: &str, address: &str, country_code: &str, @@ -222,6 +230,7 @@ async fn request_enrollment( ) -> Result { #[derive(serde::Serialize)] struct EnrollmentRequest { + token: String, name: String, address: String, country_code: String, @@ -242,6 +251,7 @@ async fn request_enrollment( .build()?; let request = EnrollmentRequest { + token: token.to_string(), name: name.to_string(), address: address.to_string(), country_code: country_code.to_string(),