feat(enrollment): implement token-based enrollment flow

Changes:
1.  Updated SHA256SUMS with new ostp-server binary
2.  Made oncp-master optional in deploy.sh (two deployment modes)
3.  Added enrollment_token support to ostp-server
4.  Updated config examples with token field

Deployment Modes:
- Mode 1 (Standalone): Connect to existing master with enrollment token
- Mode 2 (Full Stack): Deploy both master + server on one host

ostp-server Enrollment Flow:
1. Admin generates token on master: \oncp-master node token --expiry 60\
2. Node submits enrollment with token in config (psk: 'AUTO')
3. Master validates token (silent drop if invalid - security)
4. Admin approves node: \oncp-master node approve <node-id>\
5. Node receives PSK + IP from 10.X.0.0/16 pool
6. Update config with PSK, restart server

deploy.sh Features:
- Interactive mode selection
- Conditional oncp-master installation
- Automated token generation (full stack mode)
- Enrollment submission (standalone mode)

Config Examples:
- server.json.example: Full stack with local master
- server-enrollment.json.example: Standalone with token

Security:
- Token validation before enrollment acceptance
- Silent drop on invalid token (prevents enumeration)
- One-time use tokens with expiration
- IPAM automatic IP allocation from pool

Documentation:
- Updated README with deployment modes
- Added enrollment workflow explanation
- Security features documented
- CLI examples for both modes
This commit is contained in:
2026-01-02 03:36:20 +03:00
parent ec6b608cf7
commit a7ec878518
8 changed files with 231 additions and 65 deletions

View File

@@ -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 <<EOF
{
"listen": "0.0.0.0:443",
"psk": "AUTO",
"master_node_url": "http://master.example.com:8080",
"enrollment_token": "PASTE_TOKEN_HERE",
"node_name": "node-01",
"country_code": "US",
"region": "eu-west",
"hardware_id": "server-xyz",
"max_connections": 1000
}
EOF
# Submit enrollment request
sudo ostp-server -c /etc/ostp/server.json
# Server will submit enrollment and exit
# Ask admin to approve node:
# oncp-master node pending
# oncp-master node approve <node-id>
# 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 <node-id>`
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: