refactor: drop Docker, single-binary native-only world
Removed: - docker/ (scripts, binaries, images) - no longer needed - native/, common/ bash scripts - replaced by Go binary - setup.sh - replaced by deploy.sh - internal/docker/ Go package - no longer needed Added: - deploy.sh - one-command bootstrap - --version flag Result: one binary, one TUI, one deployment type. Zero Docker. Binary distributed via Gitea releases (not in repo).
This commit is contained in:
parent
1a11e40c66
commit
ff5a09b994
6 changed files with 162 additions and 801 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -9,3 +9,4 @@ Thumbs.db
|
||||||
# Local notes (excluded from sync)
|
# Local notes (excluded from sync)
|
||||||
notes/
|
notes/
|
||||||
wallarm
|
wallarm
|
||||||
|
bin/
|
||||||
|
|
|
||||||
588
README.md
588
README.md
|
|
@ -1,550 +1,90 @@
|
||||||
# Wallarm Deployment System
|
# Wallarm Native Node Manager
|
||||||
|
|
||||||
A comprehensive solution for deploying Wallarm filtering nodes on virtual machines or bare metal servers. This system provides automated deployment, preflight checks, and management of Wallarm security nodes with **two deployment types**: **Docker** (containerized) and **Native** (installed directly on the OS, no Docker required).
|
Single-binary deployment and management for Wallarm Native Nodes (connector mode, no Docker).
|
||||||
|
One command to get started, one TUI to manage everything.
|
||||||
## Deployment Types
|
|
||||||
|
|
||||||
| | **Docker** | **Native** |
|
|
||||||
|---|---|---|
|
|
||||||
| Runtime | Wallarm container on Docker engine | Wallarm Native Node (go-node, `connector-server` mode) installed directly on the OS |
|
|
||||||
| Artifacts | Docker static binaries + Wallarm image (from Git repo or local) | Wallarm all-in-one installer (`repo.wallarm.com`) |
|
|
||||||
| Multi-node on one host | ✅ Yes (unique ports) | ✅ Yes (per-node systemd template units) |
|
|
||||||
| Management | 4 scripts (`check`/`deploy`/`reconfigure`/`uninstall`) | 1 unified script (`wallarm-native.sh`) |
|
|
||||||
| Directory | `docker/` | `native/` |
|
|
||||||
| Requires Docker | ✅ (installed automatically) | ❌ Never installed |
|
|
||||||
| Best for | VMs, multiple nodes, air-gapped | Any container environment (LXC etc.), minimal footprint, no containers |
|
|
||||||
|
|
||||||
> **Note on environments:** Docker inside LXC containers is problematic, so the **Docker** deployment is intended for **full VMs**. For container environments (LXC, Proxmox containers, etc.), use the **Native** deployment — it installs the Wallarm node directly on the OS without Docker and works in any container environment.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- **Automated Preflight Checks** – Validates system readiness, network connectivity, and resource availability (per deployment type)
|
|
||||||
- **Smart Artifact Management** – Git Repositorys-first approach with local fallback support (Docker type)
|
|
||||||
- **Multiple Node Support** – Deploy multiple Wallarm instances on the same VM with unique port configurations (Docker) or per-node systemd units (Native)
|
|
||||||
- **Interactive Configuration** – User-friendly prompts for cloud region, ports, token, and upstream applications
|
|
||||||
- **Comprehensive Validation** – Network tests, port availability checks, and deployment verification
|
|
||||||
- **Persistence & Management** – Automatic service creation and health monitoring (systemd/OpenRC/SysV for Docker; systemd template units for Native)
|
|
||||||
- **Post‑Deployment Reconfiguration** – Easily update trusted proxy IPs and change operation mode without redeploying (Docker) or node address/token/labels (Native)
|
|
||||||
- **Clean Uninstallation** – Safe removal of containers, packages, and configuration files
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
### System Requirements
|
|
||||||
- **Operating System**: Linux (Ubuntu 20.04+, CentOS/RHEL 8+, Debian 11+, Alpine)
|
|
||||||
- **Architecture**: x86_64 (amd64) or aarch64 (arm64) for native; x86_64 for Docker artifacts
|
|
||||||
- **Memory**: Minimum 2GB RAM (4GB recommended for production)
|
|
||||||
- **Storage**: Minimum 10GB free disk space
|
|
||||||
- **Network**: Outbound connectivity to Wallarm cloud endpoints
|
|
||||||
|
|
||||||
### Software Dependencies
|
|
||||||
- **Bash**: Version 4.0+ (included with most Linux distributions)
|
|
||||||
- **curl** or **wget**: For downloading scripts and artifacts
|
|
||||||
- **sudo**: For package installation and system configuration
|
|
||||||
- **systemd**: Required for Native deployment (per-node template units); Docker also supports OpenRC/sysvinit
|
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
### 1. Download the Scripts
|
|
||||||
|
|
||||||
Use the wrapper script to download all necessary tools. By default it downloads **both** deployment types (`docker` and `native`), so you can choose later:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL "https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/setup.sh" | bash
|
curl -fsSL "https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/deploy.sh" | bash
|
||||||
|
sudo ./deploy/wallarm
|
||||||
```
|
```
|
||||||
|
|
||||||
To download only one type (e.g. for automation):
|
That's it. The binary runs preflight checks, then opens an interactive TUI:
|
||||||
|
- **First run**: configuration wizard (cloud region, API token, node name, listen address)
|
||||||
|
- **Subsequent runs**: dashboard with node list, add/remove/configure actions
|
||||||
|
|
||||||
```bash
|
## Features
|
||||||
DEPLOYMENT_TYPE=native curl -fsSL "https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/setup.sh" | bash
|
|
||||||
|
- **Single binary** — 7MB, zero runtime dependencies, works on any Linux
|
||||||
|
- **Interactive TUI** — bubbletea-powered forms and dashboard
|
||||||
|
- **Preflight checks** — runs on every start: system, network, cloud reachability, resources
|
||||||
|
- **Multi-node** — manage multiple Wallarm nodes on the same host via systemd
|
||||||
|
- **Remote tunnel** — `wallarm --tunnel` opens a reverse SSH tunnel over TLS:443 via Zoraxy
|
||||||
|
- **State persistence** — `~/.wallarm/state.json` tracks all deployments
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```
|
||||||
|
wallarm Interactive TUI (wizard or dashboard)
|
||||||
|
wallarm --tunnel Start reverse SSH tunnel to sechpoint.app
|
||||||
|
wallarm --version Show version
|
||||||
|
wallarm --help Show help
|
||||||
```
|
```
|
||||||
|
|
||||||
The setup script downloads the shared library and makes executable:
|
## Dashboard
|
||||||
|
|
||||||
- `common/wallarm-lib.sh` – Shared functions for both deployment types
|
```
|
||||||
- `docker/wallarm-ct-check.sh` – Preflight validation (Docker)
|
📊 Wallarm Dashboard
|
||||||
- `docker/wallarm-ct-deploy.sh` – Main deployment script (Docker)
|
Type: native | Cloud: EU (api.wallarm.com)
|
||||||
- `docker/wallarm-ct-reconfigure.sh` – Modify configuration after deployment (Docker)
|
──────────────────────────────────────────────────
|
||||||
- `docker/wallarm-ct-uninstall.sh` – Remove a Wallarm node (Docker)
|
|
||||||
- `native/wallarm-native.sh` – Unified single-script manager for the Wallarm Native Node (connector mode)
|
|
||||||
|
|
||||||
### 2. Run Preflight Check
|
Nodes:
|
||||||
|
● srv1 — running (0.0.0.0:8081)
|
||||||
|
● srv2 — running (0.0.0.0:8082)
|
||||||
|
|
||||||
```bash
|
Actions:
|
||||||
# Docker deployment
|
[a] Add node
|
||||||
./docker/wallarm-ct-check.sh
|
[c] Configure
|
||||||
|
[r] Remove node
|
||||||
# Native deployment
|
[t] Start tunnel
|
||||||
sudo ./native/wallarm-native.sh --preflight
|
[q] Quit
|
||||||
```
|
```
|
||||||
|
|
||||||
The preflight checks will:
|
## Architecture
|
||||||
- Verify system compatibility (OS, architecture, init system)
|
|
||||||
- Test network connectivity to Wallarm cloud endpoints and installers
|
|
||||||
- Validate artifact availability (Docker: Git repo / local files; Native: all-in-one installer)
|
|
||||||
- Validate resource availability and listen-port availability
|
|
||||||
|
|
||||||
### 3. Deploy Wallarm Node
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Docker deployment
|
|
||||||
sudo ./docker/wallarm-ct-deploy.sh
|
|
||||||
|
|
||||||
# Native deployment (interactive, multi-node)
|
|
||||||
sudo ./native/wallarm-native.sh --install
|
|
||||||
```
|
|
||||||
|
|
||||||
The deployment script will:
|
|
||||||
1. Run preflight checks (Native) / read preflight results (Docker)
|
|
||||||
2. Prompt for configuration (Docker: ports, upstream, token, proxies; Native: node names, listen addresses, token)
|
|
||||||
3. **Docker**: Install Docker, download and load the Wallarm image, configure and start the container
|
|
||||||
4. **Native**: Download and run the Wallarm all-in-one installer, register nodes, start per-node systemd units
|
|
||||||
5. Verify deployment with health checks
|
|
||||||
|
|
||||||
## Required Information Before Deployment
|
|
||||||
|
|
||||||
To ensure a smooth deployment, have the following information ready before starting the script:
|
|
||||||
|
|
||||||
| Item | Description | Example | Notes |
|
|
||||||
|------|-------------|---------|-------|
|
|
||||||
| **Inbound Port / Listen Address** | Docker: port the node listens on. Native: `IP:Port` connector address per node. | `80` or `0.0.0.0:8081` | Must be unused on the server. Native can run multiple nodes on different ports. |
|
|
||||||
| **Application Server (Upstream) IP/Hostname** (Docker) | The IP address or hostname of the backend application that Wallarm will forward traffic to. | `192.168.1.100` or `app.internal.local` | Must be reachable from the Wallarm node. Do **not** use `127.0.0.1` for a local app – use the host's actual IP. |
|
|
||||||
| **Application Server Port** (Docker) | The port on which the backend application listens. | `8080` | Must be open and listening. |
|
|
||||||
| **Wallarm Node Token** | A token obtained from the Wallarm Console when creating a new "Wallarm node". | `base64_encoded_string` | Copy it exactly. It will be pasted during the deployment process. Native requires a token with the Deploy role. |
|
|
||||||
| **Node Labels** (Native, optional) | Labels applied to the node (defaults to `group=<node-name>`). | `group=prod` | Can be changed later via `--config --labels`. |
|
|
||||||
| **Trusted Proxy IPs/CIDRs** (Docker, optional) | IP(s) of load balancers/firewalls in front of the node that set the `X-Real-IP` header. | `10.0.0.10` or `192.168.0.0/24` | Leave empty if no proxy in front. Multiple entries space-separated. |
|
|
||||||
| **Wallarm Cloud Region** | Which Wallarm cloud to use – US or EU. | `US` or `EU` | Scripts test connectivity to both and only show reachable ones. |
|
|
||||||
| **Operation Mode** (Docker, optional) | Initial operation mode. `monitoring` logs attacks, `block` blocks. | `monitoring` | Defaults to `monitoring`; changeable later via the reconfigure script. |
|
|
||||||
|
|
||||||
### Additional Preparation Steps
|
|
||||||
|
|
||||||
- **Ensure the backend application is running** and reachable from the Wallarm server. Test with `telnet <upstream_ip> <upstream_port>`.
|
|
||||||
- **If you plan to use a custom domain**, be prepared to configure DNS to point to the server's public IP (or the load balancer).
|
|
||||||
- **If the server is behind a firewall**, open the inbound port (e.g., 80) to allow traffic from the internet or the load balancer.
|
|
||||||
|
|
||||||
## Detailed Usage
|
|
||||||
|
|
||||||
### Workflow Overview
|
|
||||||
|
|
||||||
1. **Preflight Check** → **Deployment** → **Verification** → **Management**
|
|
||||||
|
|
||||||
### Configuration Requirements
|
|
||||||
|
|
||||||
#### Wallarm Node Token
|
|
||||||
Before deployment, you need a Wallarm Node Token from the Wallarm Console:
|
|
||||||
- **Create Token**: Navigate to Wallarm Console → **Nodes** → **Create node**
|
|
||||||
- **Token Format**: Base64 encoded string (alphanumeric with `+`, `/`, `=`, `-`, `_`)
|
|
||||||
- **Documentation**: [Official Wallarm Documentation](https://docs.wallarm.com/)
|
|
||||||
|
|
||||||
#### Header Configuration for Firewalls/Ingress Controllers (Docker)
|
|
||||||
To ensure proper IP address detection and metadata forwarding, configure your firewall or ingress controller to include these headers:
|
|
||||||
|
|
||||||
```nginx
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
proxy_set_header X-Forwarded-Host $host;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note**: The Docker deployment script configures the first three headers automatically. You must manually add `X-Forwarded-Host: "$host"` to your existing firewall/ingress configuration.
|
|
||||||
|
|
||||||
## Docker Deployment (`docker/`)
|
|
||||||
|
|
||||||
### Multiple Node Deployment on Same VM
|
|
||||||
|
|
||||||
You can deploy multiple Wallarm nodes on the same virtual machine by:
|
|
||||||
|
|
||||||
1. **Unique Port Configuration**: Each instance must use unique ingress and monitoring ports
|
|
||||||
- Default ingress port: 80 (configurable during deployment)
|
|
||||||
- Monitoring port: ingress_port + 10 (auto-calculated)
|
|
||||||
- Example: Instance 1 (80/90), Instance 2 (8080/8090), Instance 3 (8888/8898)
|
|
||||||
|
|
||||||
2. **Instance Naming**: Each deployment generates a unique instance name
|
|
||||||
- Format: `wallarm-<hostname>-<date>-<random>`
|
|
||||||
- Example: `wallarm-server1-20250324-ab3c`
|
|
||||||
|
|
||||||
3. **Isolated Configuration**: Each instance has its own:
|
|
||||||
- Docker container with unique name
|
|
||||||
- Configuration directory (`/opt/wallarm-<instance-name>/`)
|
|
||||||
- Port binding and network namespace
|
|
||||||
- Log files and start scripts
|
|
||||||
|
|
||||||
**Resource Considerations for Multiple Nodes**:
|
|
||||||
- Add 500MB RAM per additional Wallarm instance
|
|
||||||
- Each instance requires ~2GB disk space
|
|
||||||
- Consider CPU allocation (1 vCPU core per 2-3 instances for moderate traffic)
|
|
||||||
|
|
||||||
## Native Deployment (`native/`)
|
|
||||||
|
|
||||||
The native deployment installs the **Wallarm Native Node** (go-node, `connector-server` mode) directly on the operating system **without Docker**, using a single unified manager script.
|
|
||||||
|
|
||||||
### Unified Node Manager (`native/wallarm-native.sh`)
|
|
||||||
|
|
||||||
`wallarm-native.sh` manages multiple isolated nodes under `/opt/wallarm/nodes/` via a systemd template unit (`wallarm-node@<name>.service`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo ./native/wallarm-native.sh --preflight # preflight checks only
|
|
||||||
sudo ./native/wallarm-native.sh --install # interactive multi-node install (parallel)
|
|
||||||
sudo ./native/wallarm-native.sh --config --node node1 --address 0.0.0.0:9090 [--token TOKEN] [--labels LABELS]
|
|
||||||
sudo ./native/wallarm-native.sh --remove --node node2
|
|
||||||
sudo ./native/wallarm-native.sh --status [NODE] # node status (all or one)
|
|
||||||
```
|
|
||||||
|
|
||||||
Key characteristics:
|
|
||||||
- **Preflight checks** run automatically before `--install` and are available standalone via `--preflight` (root, systemd, architecture, required commands, installer + Wallarm cloud connectivity, disk/memory, listen-port availability)
|
|
||||||
- Per-node isolated directories (`etc/`, `var/log/`, `var/run/`), with the Wallarm token stored in a `chmod 600` env file
|
|
||||||
- All-in-one installer is downloaded from `https://repo.wallarm.com/linux/wallarm-native-node/latest/all-in-one/` (override with `WALLARM_INSTALLER_URL`, architecture with `WALLARM_INSTALLER_ARCH`)
|
|
||||||
- Parallel installation with per-node install logs (`install.log`)
|
|
||||||
- Nodes are started automatically via systemd and restart on failure
|
|
||||||
|
|
||||||
## Reconfiguration
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
The reconfigure script safely modifies the configuration of an existing instance, creates a backup, and restarts the container:
|
|
||||||
```bash
|
|
||||||
sudo ./docker/wallarm-ct-reconfigure.sh
|
|
||||||
```
|
|
||||||
It can update trusted proxy IPs/CIDRs and switch the operation mode (`monitoring` ↔ `block`).
|
|
||||||
|
|
||||||
### Native
|
|
||||||
Use the unified manager to update an existing node:
|
|
||||||
```bash
|
|
||||||
sudo ./native/wallarm-native.sh --config --node node1 --address 0.0.0.0:9090
|
|
||||||
sudo ./native/wallarm-native.sh --config --node node1 --token <NEW_TOKEN>
|
|
||||||
sudo ./native/wallarm-native.sh --config --node node1 --labels "group=prod"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Uninstallation
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
```bash
|
|
||||||
# Remove container/image and optionally Docker
|
|
||||||
sudo ./docker/wallarm-ct-uninstall.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Native
|
|
||||||
```bash
|
|
||||||
# Remove a single node (stops systemd unit, deletes its directory)
|
|
||||||
sudo ./native/wallarm-native.sh --remove --node node2
|
|
||||||
```
|
|
||||||
|
|
||||||
## Artifact Sources
|
|
||||||
|
|
||||||
### Docker Deployment (Priority Order)
|
|
||||||
|
|
||||||
The Docker deployment uses a smart fallback approach for artifact retrieval:
|
|
||||||
|
|
||||||
1. **Primary Source**: Git Repositorys
|
|
||||||
- URL: `https://git.sechpoint.app/customer-engineering/wallarm`
|
|
||||||
- Contains: `docker/binaries/` (Docker static binaries) and `docker/images/` (Wallarm images) with SHA256 checksums
|
|
||||||
- Benefits: Version control, access control, audit trail
|
|
||||||
|
|
||||||
2. **Secondary Source**: Local Directories
|
|
||||||
- `docker/binaries/` – Docker static binaries (`docker-29.2.1.tgz`)
|
|
||||||
- `docker/images/` – Wallarm Docker images (`wallarm-node-6.11.0-rc1.tar.gz`)
|
|
||||||
- Benefits: Air‑gapped environments, faster deployment
|
|
||||||
|
|
||||||
3. **Tertiary Source**: Current Directory
|
|
||||||
- Any `docker-*.tgz` or `wallarm-node-*.tar.gz` files in script location
|
|
||||||
- Benefits: Ad‑hoc deployments, testing scenarios
|
|
||||||
|
|
||||||
### Native Deployment (Source)
|
|
||||||
|
|
||||||
The native deployment downloads the Wallarm **all-in-one installer** directly from `https://repo.wallarm.com/linux/wallarm-native-node/latest/all-in-one/`. No Docker artifacts are required. Current versions are listed at [node-artifact-versions](https://docs.wallarm.com/updating-migrating/node-artifact-versions/).
|
|
||||||
|
|
||||||
## Suggested Resources
|
|
||||||
|
|
||||||
### Hardware Recommendations
|
|
||||||
|
|
||||||
| Deployment Type | vCPUs | RAM | Storage | Network | Recommended For |
|
|
||||||
|----------------|-------|------|---------|---------|-----------------|
|
|
||||||
| **Development** | 2 | 4GB | 20GB | 100Mbps | Testing, PoC environments |
|
|
||||||
| **Production** | 4 | 8GB | 40GB | 1Gbps | Moderate traffic (up to 100 RPS) |
|
|
||||||
| **Enterprise** | 8+ | 16GB+| 100GB | 10Gbps | High traffic, multiple nodes |
|
|
||||||
|
|
||||||
### Cloud VM Recommendations
|
|
||||||
- **AWS**: t3.large (development), m5.xlarge (production), c5.2xlarge (enterprise)
|
|
||||||
- **Azure**: D2s v3 (development), D4s v3 (production), D8s v3 (enterprise)
|
|
||||||
- **GCP**: e2-standard-4 (development), n2-standard-8 (production), c2-standard-8 (enterprise)
|
|
||||||
|
|
||||||
### Bare Metal Considerations
|
|
||||||
- **CPU**: Intel Xeon Silver/Gold or AMD EPYC (minimum 4 physical cores)
|
|
||||||
- **Memory**: ECC RAM recommended for production environments
|
|
||||||
- **Storage**: SSD/NVMe for better I/O performance
|
|
||||||
- **Network**: Dual NIC for redundancy, 10Gbps recommended
|
|
||||||
|
|
||||||
## Script Reference
|
|
||||||
|
|
||||||
### `common/wallarm-lib.sh`
|
|
||||||
**Purpose**: Shared library used by all deployment scripts (both types)
|
|
||||||
|
|
||||||
**Key Functions**:
|
|
||||||
- Logging (`log_message`, `fail_with_remediation`)
|
|
||||||
- System detection (OS, architecture, init system)
|
|
||||||
- Network connectivity tests
|
|
||||||
- Preflight `.env` parsing (`load_env_file`)
|
|
||||||
- Cloud region selection (`select_cloud_region`)
|
|
||||||
- Validation helpers (IP address, CIDR, port availability)
|
|
||||||
- Artifact download and checksum verification
|
|
||||||
|
|
||||||
### `docker/wallarm-ct-check.sh`
|
|
||||||
**Purpose**: System validation and preflight checks (Docker)
|
|
||||||
|
|
||||||
**Key Functions**:
|
|
||||||
- OS compatibility verification (Ubuntu, CentOS, Debian, Alpine)
|
|
||||||
- Network connectivity testing (US/EU cloud endpoints)
|
|
||||||
- Resource availability assessment
|
|
||||||
- Docker artifact source validation (Git repo / local binaries/images)
|
|
||||||
- Environment file generation (`.env`)
|
|
||||||
|
|
||||||
**Usage**:
|
|
||||||
```bash
|
|
||||||
# Run check with default settings
|
|
||||||
./docker/wallarm-ct-check.sh
|
|
||||||
|
|
||||||
# Enable debug output
|
|
||||||
DEBUG=1 ./docker/wallarm-ct-check.sh
|
|
||||||
|
|
||||||
# Disable SSL certificate validation (for self-signed certs)
|
|
||||||
WALLARM_INSECURE_SSL=0 ./docker/wallarm-ct-check.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### `docker/wallarm-ct-deploy.sh`
|
|
||||||
**Purpose**: Wallarm node deployment and configuration (Docker)
|
|
||||||
|
|
||||||
**Key Functions**:
|
|
||||||
- Interactive configuration wizard
|
|
||||||
- Docker engine installation (with VFS storage driver for LXC)
|
|
||||||
- Artifact download with checksum verification
|
|
||||||
- Wallarm container deployment
|
|
||||||
- Nginx configuration with proper headers
|
|
||||||
- Health check and deployment verification
|
|
||||||
|
|
||||||
**Usage**:
|
|
||||||
```bash
|
|
||||||
# Interactive deployment
|
|
||||||
sudo ./docker/wallarm-ct-deploy.sh
|
|
||||||
|
|
||||||
# Deployment with pre-filled environment (optional)
|
|
||||||
WALLARM_TOKEN="your_token_here" sudo ./docker/wallarm-ct-deploy.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### `docker/wallarm-ct-reconfigure.sh`
|
|
||||||
**Purpose**: Modify configuration of an existing Docker Wallarm node
|
|
||||||
|
|
||||||
**Key Functions**:
|
|
||||||
- Update `set_real_ip_from` (trusted proxy IPs/CIDRs)
|
|
||||||
- Change `wallarm_mode` (monitoring/block)
|
|
||||||
- Create backup of current configuration
|
|
||||||
- Restart container to apply changes
|
|
||||||
|
|
||||||
**Usage**:
|
|
||||||
```bash
|
|
||||||
sudo ./docker/wallarm-ct-reconfigure.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### `docker/wallarm-ct-uninstall.sh`
|
|
||||||
**Purpose**: Safe removal of Docker Wallarm nodes
|
|
||||||
|
|
||||||
**Key Functions**:
|
|
||||||
- Interactive confirmation with safety checks
|
|
||||||
- Container/image removal
|
|
||||||
- Docker cleanup (service files, binaries, config, group)
|
|
||||||
- Configuration directory removal
|
|
||||||
|
|
||||||
**Usage**:
|
|
||||||
```bash
|
|
||||||
# Interactive uninstallation
|
|
||||||
sudo ./docker/wallarm-ct-uninstall.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### `native/wallarm-native.sh`
|
|
||||||
**Purpose**: Unified single-script manager for the Wallarm Native Node (connector mode, no Docker)
|
|
||||||
|
|
||||||
**Key Functions**:
|
|
||||||
- Preflight checks (root, systemd, architecture, commands, connectivity, resources, ports)
|
|
||||||
- Interactive multi-node installation in parallel with per-node systemd template units
|
|
||||||
- Configuration updates (address, token, labels) and node removal
|
|
||||||
- Status reporting via systemd
|
|
||||||
|
|
||||||
**Usage**:
|
|
||||||
```bash
|
|
||||||
# Preflight only
|
|
||||||
sudo ./native/wallarm-native.sh --preflight
|
|
||||||
|
|
||||||
# Interactive install
|
|
||||||
sudo ./native/wallarm-native.sh --install
|
|
||||||
|
|
||||||
# Update config / remove / status
|
|
||||||
sudo ./native/wallarm-native.sh --config --node node1 --address 0.0.0.0:9090
|
|
||||||
sudo ./native/wallarm-native.sh --remove --node node2
|
|
||||||
sudo ./native/wallarm-native.sh --status
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Common Issues
|
|
||||||
|
|
||||||
#### 1. Preflight Check Fails
|
|
||||||
```bash
|
|
||||||
# Docker: check detailed errors
|
|
||||||
cat .env
|
|
||||||
|
|
||||||
# Verify network connectivity manually
|
|
||||||
curl -I https://api.wallarm.com
|
|
||||||
curl -I https://us1.api.wallarm.com
|
|
||||||
|
|
||||||
# Check system compatibility
|
|
||||||
uname -m
|
|
||||||
cat /etc/os-release
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2. Deployment Fails – Port Conflicts
|
|
||||||
```bash
|
|
||||||
# Check for listening ports
|
|
||||||
sudo ss -tlnp | grep ':80\|:8080'
|
|
||||||
|
|
||||||
# Find process using port
|
|
||||||
sudo lsof -i :80
|
|
||||||
|
|
||||||
# Configure different ports during deployment
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3. Wallarm Token Issues
|
|
||||||
```bash
|
|
||||||
# Verify token format (should be base64)
|
|
||||||
echo "your_token" | base64 -d 2>/dev/null | base64
|
|
||||||
|
|
||||||
# Get new token from Wallarm Console
|
|
||||||
# https://docs.wallarm.com/
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 4. Docker Installation Problems
|
|
||||||
```bash
|
|
||||||
# Check Docker service status
|
|
||||||
sudo systemctl status docker
|
|
||||||
|
|
||||||
# Verify Docker group membership
|
|
||||||
groups $USER
|
|
||||||
|
|
||||||
# Test Docker without sudo
|
|
||||||
docker run --rm hello-world
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 5. Native Installer / Node Fails
|
|
||||||
```bash
|
|
||||||
# Check the current version at https://docs.wallarm.com/updating-migrating/node-artifact-versions/
|
|
||||||
# Override the installer URL if needed:
|
|
||||||
WALLARM_INSTALLER_URL="<custom-url>" sudo ./native/wallarm-native.sh --install
|
|
||||||
|
|
||||||
# Check a node's install log and service status
|
|
||||||
sudo cat /opt/wallarm/nodes/<node>/install.log
|
|
||||||
sudo systemctl status wallarm-node@<node> --no-pager
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 6. Header Configuration Warnings (Docker)
|
|
||||||
Ensure your upstream firewall/load balancer includes:
|
|
||||||
- `X-Real-IP: "$remote_addr"`
|
|
||||||
- `X-Forwarded-For: "$proxy_add_x_forwarded_for"`
|
|
||||||
- `X-Forwarded-Proto: "$scheme"`
|
|
||||||
- `X-Forwarded-Host: "$host"`
|
|
||||||
|
|
||||||
### Log Files
|
|
||||||
- **Docker Preflight Check**: `~/logs/wallarm-check.log`
|
|
||||||
- **Docker Deployment**: `~/logs/wallarm-deployment.log`
|
|
||||||
- **Docker Container Logs**: `/opt/wallarm-<instance-name>/container.log`
|
|
||||||
- **Native Node Logs**: `/opt/wallarm/nodes/<node>/install.log` and `/opt/wallarm/nodes/<node>/var/log/`
|
|
||||||
- **System Logs**: `/var/log/syslog` or `/var/log/messages`
|
|
||||||
|
|
||||||
## Security Considerations
|
|
||||||
|
|
||||||
### Network Security
|
|
||||||
- Use firewall rules to restrict access to monitoring endpoints
|
|
||||||
- Consider VPN or private networking for management interfaces
|
|
||||||
- Implement rate limiting for ingress ports
|
|
||||||
|
|
||||||
### Access Control
|
|
||||||
- Restrict `sudo` access to deployment scripts
|
|
||||||
- Use separate service accounts for Wallarm services
|
|
||||||
- Implement proper secret management for Wallarm tokens (Native stores them in `chmod 600` env files)
|
|
||||||
|
|
||||||
### Monitoring & Auditing
|
|
||||||
- Enable logging with rotation
|
|
||||||
- Monitor resource usage
|
|
||||||
- Regular security updates for Docker and host OS
|
|
||||||
|
|
||||||
## Maintenance
|
|
||||||
|
|
||||||
### Regular Tasks
|
|
||||||
1. **Log Rotation**: Configure logrotate for logs
|
|
||||||
2. **Updates**: Periodically update Docker/NGINX and Wallarm node
|
|
||||||
3. **Image/Version Updates**: Check for new Wallarm node versions
|
|
||||||
4. **Backup**: Regular backup of configuration directories
|
|
||||||
|
|
||||||
### Version Updates
|
|
||||||
When updating the Wallarm Native Node version:
|
|
||||||
1. Check the latest version at [node-artifact-versions](https://docs.wallarm.com/updating-migrating/node-artifact-versions/)
|
|
||||||
2. Re-download via the latest all-in-one installer (or pin with `WALLARM_INSTALLER_URL`)
|
|
||||||
3. Remove and re-install the node, or follow the [official upgrade guide](https://docs.wallarm.com/updating-migrating/)
|
|
||||||
|
|
||||||
## Repository Structure
|
|
||||||
|
|
||||||
```
|
```
|
||||||
wallarm/
|
wallarm/
|
||||||
├── README.md
|
├── cmd/wallarm/main.go Entrypoint: preflight → TUI
|
||||||
├── changelog.md
|
├── internal/
|
||||||
├── setup.sh # Downloads scripts for a chosen deployment type
|
│ ├── shared/ System detection, validation, connectivity
|
||||||
├── common/
|
│ ├── preflight/ Mandatory checks on every start
|
||||||
│ └── wallarm-lib.sh # Shared library (both deployment types)
|
│ ├── state/ ~/.wallarm/state.json persistence
|
||||||
├── docker/ # Docker deployment
|
│ ├── native/ Systemd units, installer, node management
|
||||||
│ ├── wallarm-ct-check.sh
|
│ ├── tunnel/ Reverse SSH over TLS:443 via Zoraxy
|
||||||
│ ├── wallarm-ct-deploy.sh
|
│ └── ui/ Bubbletea TUI (wizard + dashboard)
|
||||||
│ ├── wallarm-ct-reconfigure.sh
|
├── bin/
|
||||||
│ ├── wallarm-ct-uninstall.sh
|
│ └── wallarm-linux-amd64 Pre-built binary
|
||||||
│ ├── binaries/ # Docker static binaries
|
├── deploy.sh One-command bootstrap
|
||||||
│ └── images/ # Wallarm Docker images
|
├── go.mod / go.sum
|
||||||
└── native/ # Native deployment (no Docker)
|
└── Makefile Cross-compile targets
|
||||||
└── wallarm-native.sh # Unified single-script node manager (Native Node product)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Disclaimer
|
## Building from Source
|
||||||
|
|
||||||
**IMPORTANT LEGAL NOTICE**
|
```bash
|
||||||
|
go build -ldflags "-s -w -X main.version=$(git describe --tags)" -o wallarm ./cmd/wallarm/
|
||||||
|
make linux-amd64 # Cross-compile
|
||||||
|
make all # All targets
|
||||||
|
```
|
||||||
|
|
||||||
This software is provided "AS IS", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement. In no event shall Sechpoint or its affiliates be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software.
|
## Prerequisites
|
||||||
|
|
||||||
### No Responsibility Clause
|
- Linux (systemd required)
|
||||||
- Sechpoint assumes no responsibility for any harm, damage, or loss caused by the use of this software
|
- x86_64 or aarch64
|
||||||
- Users are solely responsible for testing, validating, and securing their deployments
|
- 2GB+ RAM, 10GB+ disk
|
||||||
- This software may contain bugs, security vulnerabilities, or compatibility issues
|
- Outbound connectivity to Wallarm cloud (US/EU)
|
||||||
- Use at your own risk and with appropriate professional oversight
|
|
||||||
|
|
||||||
### User Responsibilities
|
|
||||||
1. **Testing**: Thoroughly test in non-production environments before deployment
|
|
||||||
2. **Security**: Implement appropriate security controls and monitoring
|
|
||||||
3. **Backup**: Maintain regular backups of configurations and data
|
|
||||||
4. **Updates**: Keep the software and dependencies updated
|
|
||||||
5. **Compliance**: Ensure usage complies with all applicable laws and regulations
|
|
||||||
|
|
||||||
### Support
|
|
||||||
- This is an unsupported deployment tool
|
|
||||||
- No official support, maintenance, or updates are guaranteed
|
|
||||||
- Community contributions are welcome via the Git repository
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Contributions to improve the Wallarm deployment system are welcome:
|
|
||||||
|
|
||||||
1. Fork the repository on Git
|
|
||||||
2. Create a feature branch
|
|
||||||
3. Make changes with comprehensive testing
|
|
||||||
4. Submit a merge request with description
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Proprietary – See disclaimer section for usage terms.
|
Proprietary — see repository for terms.
|
||||||
|
|
||||||
## Contact & Support
|
|
||||||
|
|
||||||
- **Repository**: https://git.sechpoint.app/customer-engineering/wallarm
|
|
||||||
- **Issues**: Use the issue tracker for bug reports
|
|
||||||
- **Documentation**: [Wallarm Official Documentation](https://docs.wallarm.com/)
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@ import (
|
||||||
// go build -ldflags "-X main.tunnelKey=$(cat ~/.wallarm/tunnel_key)"
|
// go build -ldflags "-X main.tunnelKey=$(cat ~/.wallarm/tunnel_key)"
|
||||||
var tunnelKey string
|
var tunnelKey string
|
||||||
|
|
||||||
|
// Version is set at build time with -ldflags "-X main.version=1.0.0"
|
||||||
|
var version = "dev"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Usage = func() {
|
flag.Usage = func() {
|
||||||
fmt.Fprintf(os.Stderr, `wallarm — Wallarm Deployment Manager
|
fmt.Fprintf(os.Stderr, `wallarm — Wallarm Deployment Manager
|
||||||
|
|
@ -38,6 +41,7 @@ deployment. On subsequent runs, it shows your existing deployments.
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
help := flag.Bool("help", false, "Show help")
|
help := flag.Bool("help", false, "Show help")
|
||||||
|
versionFlag := flag.Bool("version", false, "Show version")
|
||||||
tunnelFlag := flag.Bool("tunnel", false, "Start reverse SSH tunnel")
|
tunnelFlag := flag.Bool("tunnel", false, "Start reverse SSH tunnel")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
|
@ -45,6 +49,10 @@ deployment. On subsequent runs, it shows your existing deployments.
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if *versionFlag {
|
||||||
|
fmt.Println("wallarm version", version)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// ── Tunnel mode ──────────────────────────────────────────────
|
// ── Tunnel mode ──────────────────────────────────────────────
|
||||||
if *tunnelFlag {
|
if *tunnelFlag {
|
||||||
|
|
|
||||||
70
deploy.sh
Normal file
70
deploy.sh
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# ==============================================================================
|
||||||
|
# Wallarm Deployment — Single Binary Bootstrap
|
||||||
|
# ==============================================================================
|
||||||
|
# Downloads the wallarm binary from the Git repository and places it in
|
||||||
|
# ~/deploy/. One command to get started:
|
||||||
|
#
|
||||||
|
# curl -fsSL ".../deploy.sh" | bash
|
||||||
|
# sudo ./deploy/wallarm
|
||||||
|
#
|
||||||
|
# The binary handles everything: preflight → TUI wizard → deployment →
|
||||||
|
# dashboard with multi-node management.
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
BOLD='\033[1m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
CYAN='\033[0;36m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
ARCH=$(uname -m)
|
||||||
|
case "$ARCH" in
|
||||||
|
x86_64|amd64) BIN_ARCH="amd64" ;;
|
||||||
|
aarch64|arm64) BIN_ARCH="arm64" ;;
|
||||||
|
*) echo -e "${RED}Unsupported architecture: $ARCH${NC}"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
REPO="https://git.sechpoint.app/customer-engineering/wallarm"
|
||||||
|
BIN_URL="${REPO}/raw/branch/main/bin/wallarm-linux-${BIN_ARCH}"
|
||||||
|
DEPLOY_DIR="${HOME:-/root}/deploy"
|
||||||
|
BIN_PATH="${DEPLOY_DIR}/wallarm"
|
||||||
|
|
||||||
|
mkdir -p "$DEPLOY_DIR"
|
||||||
|
|
||||||
|
echo -e "${BOLD}Wallarm Deployment Bootstrap${NC}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Download the binary
|
||||||
|
echo -e "${YELLOW}Downloading wallarm binary (linux-${BIN_ARCH})...${NC}"
|
||||||
|
if command -v curl >/dev/null 2>&1; then
|
||||||
|
curl -fsSL --progress-bar "$BIN_URL" -o "$BIN_PATH"
|
||||||
|
elif command -v wget >/dev/null 2>&1; then
|
||||||
|
wget -q --show-progress "$BIN_URL" -O "$BIN_PATH"
|
||||||
|
else
|
||||||
|
echo -e "${RED}Neither curl nor wget found. Install one and re-run.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod +x "$BIN_PATH"
|
||||||
|
echo -e "${GREEN} Success: wallarm installed to ${BIN_PATH}${NC}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Quick preflight (just to confirm binary works)
|
||||||
|
echo -e "${YELLOW}Testing binary...${NC}"
|
||||||
|
if "$BIN_PATH" --version 2>/dev/null; then
|
||||||
|
echo -e "${GREEN} Binary OK${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED} Binary verification failed${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${GREEN}${BOLD}Ready!${NC}"
|
||||||
|
echo
|
||||||
|
echo -e " ${CYAN}sudo ${BIN_PATH}${NC} — Start the TUI (wizard on first run, dashboard after)"
|
||||||
|
echo -e " ${CYAN}${BIN_PATH} --help${NC} — Show all commands"
|
||||||
|
echo -e " ${CYAN}${BIN_PATH} --tunnel${NC} — Start remote access tunnel"
|
||||||
|
|
@ -1,202 +0,0 @@
|
||||||
// Package docker implements Wallarm Docker-based deployment.
|
|
||||||
// Ported from docker/wallarm-ct-deploy.sh and companions.
|
|
||||||
package docker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.sechpoint.app/customer-engineering/wallarm/internal/state"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Artifact URLs
|
|
||||||
const (
|
|
||||||
DockerBinaryURL = "https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/docker/binaries/docker-29.2.1.tgz"
|
|
||||||
DockerChecksumURL = "https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/docker/binaries/docker-29.2.1.tgz.sha256"
|
|
||||||
WallarmImageURL = "https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/docker/images/wallarm-node-6.11.0-rc1.tar.gz"
|
|
||||||
WallarmChecksumURL = "https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/docker/images/wallarm-node-6.11.0-rc1.tar.gz.sha256"
|
|
||||||
DockerVersion = "29.2.1"
|
|
||||||
WallarmImageTag = "wallarm/node:6.11.0-rc1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InstallDocker detects the distro and installs Docker engine.
|
|
||||||
func InstallDocker() error {
|
|
||||||
if _, err := exec.LookPath("docker"); err == nil {
|
|
||||||
fmt.Println("Docker is already installed.")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
osID, _ := detectOS()
|
|
||||||
|
|
||||||
switch osID {
|
|
||||||
case "ubuntu", "debian":
|
|
||||||
return installDockerDebian()
|
|
||||||
case "centos", "rhel", "rocky", "almalinux", "ol", "amzn":
|
|
||||||
return installDockerRHEL()
|
|
||||||
case "alpine":
|
|
||||||
return installDockerAlpine()
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupported OS for Docker install: %s", osID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func installDockerDebian() error {
|
|
||||||
cmds := [][]string{
|
|
||||||
{"apt-get", "update", "-qq"},
|
|
||||||
{"apt-get", "install", "-y", "-qq", "ca-certificates", "curl"},
|
|
||||||
{"install", "-m", "0755", "-d", "/etc/apt/keyrings"},
|
|
||||||
// Download and verify Docker static binary (offline-friendly approach)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range cmds {
|
|
||||||
cmd := exec.Command(c[0], c[1:]...)
|
|
||||||
if out, err := cmd.CombinedOutput(); err != nil {
|
|
||||||
return fmt.Errorf("apt: %w\n%s", err, string(out))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write VFS storage driver config (LXC optimization)
|
|
||||||
daemonJSON := `{"storage-driver": "vfs"}`
|
|
||||||
os.MkdirAll("/etc/docker", 0755)
|
|
||||||
if err := os.WriteFile("/etc/docker/daemon.json", []byte(daemonJSON), 0644); err != nil {
|
|
||||||
return fmt.Errorf("write daemon.json: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Docker installed with VFS storage driver.")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func installDockerRHEL() error {
|
|
||||||
cmds := [][]string{
|
|
||||||
{"yum", "install", "-y", "yum-utils"},
|
|
||||||
}
|
|
||||||
for _, c := range cmds {
|
|
||||||
cmd := exec.Command(c[0], c[1:]...)
|
|
||||||
if out, err := cmd.CombinedOutput(); err != nil {
|
|
||||||
return fmt.Errorf("yum: %w\n%s", err, string(out))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func installDockerAlpine() error {
|
|
||||||
cmds := [][]string{
|
|
||||||
{"apk", "add", "--no-cache", "docker"},
|
|
||||||
}
|
|
||||||
for _, c := range cmds {
|
|
||||||
cmd := exec.Command(c[0], c[1:]...)
|
|
||||||
if out, err := cmd.CombinedOutput(); err != nil {
|
|
||||||
return fmt.Errorf("apk: %w\n%s", err, string(out))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeployContainer loads the Wallarm image and starts a container.
|
|
||||||
func DeployContainer(node state.Node, apiToken, apiHost string) error {
|
|
||||||
instanceName := fmt.Sprintf("wallarm-%s", node.Name)
|
|
||||||
instanceDir := filepath.Join("/opt", instanceName)
|
|
||||||
os.MkdirAll(instanceDir, 0755)
|
|
||||||
|
|
||||||
// Load Wallarm image (check local images/ dir first, then download)
|
|
||||||
imagePath := findImage()
|
|
||||||
if imagePath == "" {
|
|
||||||
fmt.Println("Downloading Wallarm image...")
|
|
||||||
imagePath = filepath.Join(instanceDir, "wallarm-node.tar.gz")
|
|
||||||
cmd := exec.Command("curl", "-fsSL", "-o", imagePath, WallarmImageURL)
|
|
||||||
if out, err := cmd.CombinedOutput(); err != nil {
|
|
||||||
return fmt.Errorf("download image: %w\n%s", err, string(out))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Loading Wallarm image into Docker...")
|
|
||||||
loadCmd := exec.Command("docker", "load", "-i", imagePath)
|
|
||||||
if out, err := loadCmd.CombinedOutput(); err != nil {
|
|
||||||
return fmt.Errorf("docker load: %w\n%s", err, string(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run container
|
|
||||||
ingressPort := fmt.Sprintf("%d", node.Port)
|
|
||||||
monitoringPort := fmt.Sprintf("%d", node.Port+10)
|
|
||||||
|
|
||||||
args := []string{
|
|
||||||
"run", "-d",
|
|
||||||
"--name", instanceName,
|
|
||||||
"--restart", "unless-stopped",
|
|
||||||
"-p", ingressPort + ":" + ingressPort,
|
|
||||||
"-p", monitoringPort + ":" + monitoringPort,
|
|
||||||
"-v", instanceDir + ":/opt/wallarm",
|
|
||||||
"-e", "WALLARM_API_TOKEN=" + apiToken,
|
|
||||||
"-e", "WALLARM_API_HOST=" + apiHost,
|
|
||||||
"-e", "WALLARM_MODE=monitoring",
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.UpstreamIP != "" {
|
|
||||||
upstream := fmt.Sprintf("http://%s:%d", node.UpstreamIP, node.UpstreamPort)
|
|
||||||
args = append(args, "-e", "WALLARM_UPSTREAM="+upstream)
|
|
||||||
}
|
|
||||||
|
|
||||||
args = append(args, WallarmImageTag)
|
|
||||||
|
|
||||||
cmd := exec.Command("docker", args...)
|
|
||||||
if out, err := cmd.CombinedOutput(); err != nil {
|
|
||||||
return fmt.Errorf("docker run: %w\n%s", err, string(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Container %s started.\n", instanceName)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveNode stops and removes a Docker Wallarm container.
|
|
||||||
func RemoveNode(nodeName string) error {
|
|
||||||
instanceName := "wallarm-" + nodeName
|
|
||||||
|
|
||||||
for _, action := range []string{"stop", "rm"} {
|
|
||||||
exec.Command("docker", action, instanceName).Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
instanceDir := filepath.Join("/opt", instanceName)
|
|
||||||
os.RemoveAll(instanceDir)
|
|
||||||
|
|
||||||
fmt.Printf("Container %s removed.\n", instanceName)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Status returns running Wallarm containers.
|
|
||||||
func Status() string {
|
|
||||||
cmd := exec.Command("docker", "ps", "--filter", "name=wallarm-",
|
|
||||||
"--format", "table {{.Names}}\t{{.Status}}\t{{.Ports}}")
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
return "Docker is not running or no Wallarm containers found."
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(string(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
func findImage() string {
|
|
||||||
// Check local images/ directory first (for offline deployments)
|
|
||||||
dirs := []string{"images", "../images", "../../images"}
|
|
||||||
for _, d := range dirs {
|
|
||||||
matches, _ := filepath.Glob(filepath.Join(d, "wallarm-node-*.tar.gz"))
|
|
||||||
if len(matches) > 0 {
|
|
||||||
return matches[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func detectOS() (id, version string) {
|
|
||||||
data, err := os.ReadFile("/etc/os-release")
|
|
||||||
if err != nil {
|
|
||||||
return "unknown", ""
|
|
||||||
}
|
|
||||||
for _, line := range strings.Split(string(data), "\n") {
|
|
||||||
if strings.HasPrefix(line, "ID=") {
|
|
||||||
id = strings.Trim(strings.TrimPrefix(line, "ID="), `"`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return id, ""
|
|
||||||
}
|
|
||||||
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"github.com/charmbracelet/huh"
|
"github.com/charmbracelet/huh"
|
||||||
"github.com/charmbracelet/lipgloss"
|
"github.com/charmbracelet/lipgloss"
|
||||||
|
|
||||||
"git.sechpoint.app/customer-engineering/wallarm/internal/docker"
|
|
||||||
"git.sechpoint.app/customer-engineering/wallarm/internal/native"
|
"git.sechpoint.app/customer-engineering/wallarm/internal/native"
|
||||||
"git.sechpoint.app/customer-engineering/wallarm/internal/preflight"
|
"git.sechpoint.app/customer-engineering/wallarm/internal/preflight"
|
||||||
"git.sechpoint.app/customer-engineering/wallarm/internal/state"
|
"git.sechpoint.app/customer-engineering/wallarm/internal/state"
|
||||||
|
|
@ -74,13 +73,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "q", "ctrl+c":
|
case "q", "ctrl+c":
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
case "1":
|
case "1", "2":
|
||||||
if m.state == viewWizard && !m.deploying {
|
if m.state == viewWizard && !m.deploying {
|
||||||
return m, m.startDeploy("docker")
|
return m, m.startDeploy()
|
||||||
}
|
|
||||||
case "2":
|
|
||||||
if m.state == viewWizard && !m.deploying {
|
|
||||||
return m, m.startDeploy("native")
|
|
||||||
}
|
}
|
||||||
case "enter":
|
case "enter":
|
||||||
if m.state == viewDone || m.state == viewError {
|
if m.state == viewDone || m.state == viewError {
|
||||||
|
|
@ -129,25 +124,19 @@ func (m Model) View() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// startDeploy runs the Huh form in a goroutine, then calls the deploy package.
|
// startDeploy runs the Huh form in a goroutine, then deploys.
|
||||||
func (m Model) startDeploy(deployType string) tea.Cmd {
|
func (m Model) startDeploy() tea.Cmd {
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
m.deploying = true
|
m.deploying = true
|
||||||
|
|
||||||
// Run the interactive form
|
s, err := runDeployForm()
|
||||||
s, err := runDeployForm(deployType)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return deployCompleteMsg{err}
|
return deployCompleteMsg{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute deployment
|
// Deploy native node
|
||||||
if deployType == "native" {
|
|
||||||
err = deployNative(s)
|
err = deployNative(s)
|
||||||
} else {
|
|
||||||
err = deployDocker(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save state on success
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
state.Save(&s)
|
state.Save(&s)
|
||||||
}
|
}
|
||||||
|
|
@ -167,10 +156,8 @@ func wizardView(m Model) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
s += dimStyle.Render("No existing deployment found. Let's set one up.") + "\n\n"
|
s += dimStyle.Render("No existing deployment found. Let's set one up.") + "\n\n"
|
||||||
s += activeStyle.Render("Step 1: Choose deployment type") + "\n"
|
s += activeStyle.Render("Wallarm Native Node Deployment") + "\n"
|
||||||
s += " [1] Docker — Wallarm node as a container\n"
|
s += " Press Enter to begin configuration" + "\n\n"
|
||||||
s += " [2] Native — Wallarm node directly on this OS\n"
|
|
||||||
s += dimStyle.Render(" Press 1 or 2 to begin") + "\n\n"
|
|
||||||
|
|
||||||
s += activeStyle.Render("Step 2: Cloud region") + "\n"
|
s += activeStyle.Render("Step 2: Cloud region") + "\n"
|
||||||
r := preflightResult
|
r := preflightResult
|
||||||
|
|
@ -190,9 +177,9 @@ func wizardView(m Model) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// runDeployForm collects configuration via huh interactive forms.
|
// runDeployForm collects configuration via huh interactive forms.
|
||||||
func runDeployForm(deployType string) (state.State, error) {
|
func runDeployForm() (state.State, error) {
|
||||||
var s state.State
|
var s state.State
|
||||||
s.DeploymentType = deployType
|
s.DeploymentType = "native"
|
||||||
|
|
||||||
// Step 1: Cloud region
|
// Step 1: Cloud region
|
||||||
regionOptions := []huh.Option[string]{}
|
regionOptions := []huh.Option[string]{}
|
||||||
|
|
@ -255,18 +242,6 @@ func runDeployForm(deployType string) (state.State, error) {
|
||||||
// Step 3: Node configuration
|
// Step 3: Node configuration
|
||||||
var nodeName, address, labels string
|
var nodeName, address, labels string
|
||||||
nodeForm := huh.NewForm(
|
nodeForm := huh.NewForm(
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewInput().Title("Node name").Value(&nodeName).Validate(func(v string) error {
|
|
||||||
if v == "" {
|
|
||||||
return fmt.Errorf("required")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
if deployType == "native" {
|
|
||||||
nodeForm = huh.NewForm(
|
|
||||||
huh.NewGroup(
|
huh.NewGroup(
|
||||||
huh.NewInput().Title("Node name").Value(&nodeName).Validate(func(v string) error {
|
huh.NewInput().Title("Node name").Value(&nodeName).Validate(func(v string) error {
|
||||||
if v == "" {
|
if v == "" {
|
||||||
|
|
@ -283,24 +258,6 @@ func runDeployForm(deployType string) (state.State, error) {
|
||||||
huh.NewInput().Title("Labels (optional)").Placeholder("group=prod").Value(&labels),
|
huh.NewInput().Title("Labels (optional)").Placeholder("group=prod").Value(&labels),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
var upstreamIP, upstreamPortStr string
|
|
||||||
nodeForm = huh.NewForm(
|
|
||||||
huh.NewGroup(
|
|
||||||
huh.NewInput().Title("Node name").Value(&nodeName).Validate(func(v string) error {
|
|
||||||
if v == "" {
|
|
||||||
return fmt.Errorf("required")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}),
|
|
||||||
huh.NewInput().Title("Ingress port").Placeholder("80").Value(&address),
|
|
||||||
huh.NewInput().Title("Upstream IP").Placeholder("192.168.1.100").Value(&upstreamIP),
|
|
||||||
huh.NewInput().Title("Upstream port").Placeholder("8080").Value(&upstreamPortStr),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
_ = upstreamIP
|
|
||||||
_ = upstreamPortStr
|
|
||||||
}
|
|
||||||
|
|
||||||
err = nodeForm.WithTheme(huh.ThemeCharm()).Run()
|
err = nodeForm.WithTheme(huh.ThemeCharm()).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -309,7 +266,7 @@ func runDeployForm(deployType string) (state.State, error) {
|
||||||
|
|
||||||
s.Nodes = append(s.Nodes, state.Node{
|
s.Nodes = append(s.Nodes, state.Node{
|
||||||
Name: nodeName,
|
Name: nodeName,
|
||||||
Type: deployType,
|
Type: "native",
|
||||||
Address: address,
|
Address: address,
|
||||||
Status: "deploying",
|
Status: "deploying",
|
||||||
CreatedAt: time.Now().Format(time.RFC3339),
|
CreatedAt: time.Now().Format(time.RFC3339),
|
||||||
|
|
@ -334,19 +291,6 @@ func deployNative(s state.State) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// deployDocker executes the Docker deployment.
|
|
||||||
func deployDocker(s state.State) error {
|
|
||||||
if err := docker.InstallDocker(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, node := range s.Nodes {
|
|
||||||
if err := docker.DeployContainer(node, s.APIToken, s.APIHost); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─── Dashboard ───────────────────────────────────────────────────────
|
// ─── Dashboard ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
func dashboardView(m Model) string {
|
func dashboardView(m Model) string {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue