feat: add native deployment and separate docker|native structure

- Restructure repo into docker/ and native/ deployment types with a shared
  common/wallarm-lib.sh (logging, detection, validation, connectivity, env parsing)
- Move Docker scripts + artifacts (binaries/, images/) under docker/ (git mv, history preserved)
- Refactor Docker scripts to source the shared library; update artifact URLs
- Add native/ scripts for no-Docker deployment using the Wallarm all-in-one installer
  (check, deploy, reconfigure, uninstall) with version pinning via WALLARM_VERSION
- Add native/wallarm-native.sh unified node manager (Wallarm Native Node, connector
  mode) with preflight checks, parallel multi-node install, config/remove/status
- Update setup.sh to download scripts per deployment type (DEPLOYMENT_TYPE=...)
- Update README.md and changelog.md
This commit is contained in:
Sechpoint Admin 2026-08-01 08:36:37 +01:00
parent 424786b181
commit aa3d716f61
19 changed files with 3091 additions and 859 deletions

337
README.md
View file

@ -1,23 +1,34 @@
# Wallarm Deployment System # Wallarm Deployment System
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 support for multiple instances on the same server. 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).
## Deployment Types
| | **Docker** | **Native** |
|---|---|---|
| Runtime | Wallarm container on Docker engine | Wallarm NGINX module installed directly on the OS |
| Artifacts | Docker static binaries + Wallarm image (from Git repo or local) | Wallarm all-in-one installer (`meganode.wallarm.com`) |
| Multi-node on one host | ✅ Yes (unique ports) | ⚠️ One node per host (single system NGINX) |
| Directory | `docker/` | `native/` |
| Requires Docker | ✅ (installed automatically) | ❌ Never installed |
| Best for | LXC/containers, multiple nodes, air-gapped | Simple single VM, minimal footprint, no containers |
## Features ## Features
- **Automated Preflight Checks** Validates system readiness, network connectivity, and resource availability - **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 - **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 - **Multiple Node Support (Docker)** Deploy multiple Wallarm instances on the same VM with unique port configurations
- **Interactive Configuration** User-friendly prompts for cloud region, ports, token, and upstream applications - **Interactive Configuration** User-friendly prompts for cloud region, ports, token, and upstream applications
- **Comprehensive Validation** Network tests, port availability checks, and deployment verification - **Comprehensive Validation** Network tests, port availability checks, and deployment verification
- **Persistence & Management** Automatic service creation, start scripts, and health monitoring - **Persistence & Management** Automatic service creation (systemd/OpenRC/SysV), start scripts, and health monitoring
- **PostDeployment Reconfiguration** Easily update trusted proxy IPs and change operation mode without redeploying - **PostDeployment Reconfiguration** Easily update trusted proxy IPs and change operation mode without redeploying
- **Clean Uninstallation** Safe removal of containers, images, and configuration files - **Clean Uninstallation** Safe removal of containers, packages, and configuration files
## Prerequisites ## Prerequisites
### System Requirements ### System Requirements
- **Operating System**: Linux (Ubuntu 20.04+, CentOS/RHEL 8+, Debian 11+) - **Operating System**: Linux (Ubuntu 20.04+, CentOS/RHEL 8+, Debian 11+, Alpine)
- **Architecture**: x86_64 (amd64) - **Architecture**: x86_64 (amd64) or aarch64 (arm64) for native; x86_64 for Docker artifacts
- **Memory**: Minimum 2GB RAM (4GB recommended for production) - **Memory**: Minimum 2GB RAM (4GB recommended for production)
- **Storage**: Minimum 10GB free disk space - **Storage**: Minimum 10GB free disk space
- **Network**: Outbound connectivity to Wallarm cloud endpoints - **Network**: Outbound connectivity to Wallarm cloud endpoints
@ -25,52 +36,71 @@ A comprehensive solution for deploying Wallarm filtering nodes on virtual machin
### Software Dependencies ### Software Dependencies
- **Bash**: Version 4.0+ (included with most Linux distributions) - **Bash**: Version 4.0+ (included with most Linux distributions)
- **curl** or **wget**: For downloading scripts and artifacts - **curl** or **wget**: For downloading scripts and artifacts
- **sudo**: For Docker installation and system configuration - **sudo**: For package installation and system configuration
- **systemd** or **sysvinit**: For service management - **systemd**, **OpenRC** or **sysvinit**: For service management
## Quick Start ## Quick Start
### 1. Download the Scripts ### 1. Download the Scripts
Use the wrapper script to download all necessary tools: Use the wrapper script to download all necessary tools. You will be asked to select the deployment type (`docker` or `native`):
```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/setup.sh" | bash
``` ```
This will download and make executable: To select non-interactively (e.g. for automation):
- `wallarm-ct-check.sh` Preflight validation ```bash
- `wallarm-ct-deploy.sh` Main deployment script DEPLOYMENT_TYPE=native curl -fsSL "https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/setup.sh" | bash
- `wallarm-ct-reconfigure.sh` Modify configuration after deployment ```
- `wallarm-ct-uninstall.sh` Remove a Wallarm node
The setup script downloads the shared library and makes executable:
- `common/wallarm-lib.sh` Shared functions for both deployment types
- `docker/wallarm-ct-check.sh` Preflight validation (Docker)
- `docker/wallarm-ct-deploy.sh` Main deployment script (Docker)
- `docker/wallarm-ct-reconfigure.sh` Modify configuration after deployment (Docker)
- `docker/wallarm-ct-uninstall.sh` Remove a Wallarm node (Docker)
- `native/wallarm-ct-check.sh` Preflight validation (Native)
- `native/wallarm-ct-deploy.sh` Main deployment script (Native)
- `native/wallarm-ct-reconfigure.sh` Modify configuration after deployment (Native)
- `native/wallarm-ct-uninstall.sh` Remove a Wallarm node (Native)
- `native/wallarm-native.sh` Unified single-script manager for the Wallarm Native Node (connector mode)
### 2. Run Preflight Check ### 2. Run Preflight Check
```bash ```bash
./wallarm-ct-check.sh # Docker deployment
./docker/wallarm-ct-check.sh
# Native deployment
./native/wallarm-ct-check.sh
``` ```
The preflight check will: The preflight check will:
- Verify system compatibility (OS, architecture, init system) - Verify system compatibility (OS, architecture, init system)
- Test network connectivity to Wallarm cloud endpoints - Test network connectivity to Wallarm cloud endpoints
- Check for existing Docker installations - Validate artifact availability (Docker: Git repo / local files; Native: all-in-one installer)
- Validate resource availability - Validate resource availability
- Generate a `.env` file with results - Generate a `.env` file with results
### 3. Deploy Wallarm Node ### 3. Deploy Wallarm Node
```bash ```bash
sudo ./wallarm-ct-deploy.sh # Docker deployment
sudo ./docker/wallarm-ct-deploy.sh
# Native deployment
sudo ./native/wallarm-ct-deploy.sh
``` ```
The deployment script will: The deployment script will:
1. Read preflight check results 1. Read preflight check results
2. Prompt for configuration (ports, upstream application, Wallarm token, trusted proxies) 2. Prompt for configuration (ports, upstream application, Wallarm token, trusted proxies)
3. Install Docker if not present 3. **Docker**: Install Docker, download and load the Wallarm image, configure and start the container
4. Download and load Wallarm Docker image 4. **Native**: Download and run the Wallarm all-in-one installer, configure NGINX, reload and verify
5. Configure and start the Wallarm container 5. Verify deployment with health checks
6. Verify deployment with health checks
## Required Information Before Deployment ## Required Information Before Deployment
@ -79,17 +109,17 @@ To ensure a smooth deployment, have the following information ready before start
| Item | Description | Example | Notes | | Item | Description | Example | Notes |
|------|-------------|---------|-------| |------|-------------|---------|-------|
| **Inbound Port** | The port on which the Wallarm node will listen for incoming HTTP traffic. | `80` (HTTP) or `8080` | Must be unused on the server. If port 80 is already in use, choose another. | | **Inbound Port** | The port on which the Wallarm node will listen for incoming HTTP traffic. | `80` (HTTP) or `8080` | Must be unused on the server. If port 80 is already in use, choose another. |
| **Application Server (Upstream) IP/Hostname** | 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 **container**. If the application runs on the same physical machine, do **not** use `127.0.0.1` use the hosts actual IP (e.g., `172.17.0.1` for the default Docker bridge, or the machines LAN IP). | | **Application Server (Upstream) IP/Hostname** | 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. If the application runs on the same physical machine, do **not** use `127.0.0.1` use the host's actual IP. |
| **Application Server Port** | The port on which the backend application listens. | `8080` | Must be open and listening. | | **Application Server Port** | 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. | | **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. |
| **Trusted Proxy IPs/CIDRs** (Optional) | The IP address(es) of any load balancers, firewalls, or CDNs that sit in front of the Wallarm node and set the `X-Real-IP` header. | `10.0.0.10` or `192.168.0.0/24` | If the node is directly accessible from the internet (no proxy in front), leave empty. If there is a proxy, you must list its IP(s) so that Wallarm can extract the real client IP. Multiple entries can be space-separated. | | **Trusted Proxy IPs/CIDRs** (Optional) | The IP address(es) of any load balancers, firewalls, or CDNs that sit in front of the Wallarm node and set the `X-Real-IP` header. | `10.0.0.10` or `192.168.0.0/24` | If the node is directly accessible from the internet (no proxy in front), leave empty. Multiple entries can be space-separated. |
| **Wallarm Cloud Region** | Which Wallarm cloud to use US or EU. | `US` or `EU` | The script will test connectivity to both and only show reachable ones. | | **Wallarm Cloud Region** | Which Wallarm cloud to use US or EU. | `US` or `EU` | The script will test connectivity to both and only show reachable ones. |
| **Operation Mode** (Optional, can be changed later) | The initial operation mode. `monitoring` only logs attacks, `block` actively blocks. | `monitoring` (recommended for first deployment) | The script defaults to `monitoring`. You can change it later using the reconfigure script. | | **Operation Mode** (Optional, can be changed later) | The initial operation mode. `monitoring` only logs attacks, `block` actively blocks. | `monitoring` (recommended for first deployment) | The script defaults to `monitoring`. You can change it later using the reconfigure script. |
### Additional Preparation Steps ### Additional Preparation Steps
- **Ensure the backend application is running** and reachable from the Wallarm server. Test with `telnet <upstream_ip> <upstream_port>`. - **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 servers public IP (or the load balancer) the Wallarm node itself does not require a domain for basic setup. - **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) the Wallarm node itself does not require a domain for basic setup.
- **If the server is behind a firewall**, open the inbound port (e.g., 80) to allow traffic from the internet 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 ## Detailed Usage
@ -104,7 +134,7 @@ To ensure a smooth deployment, have the following information ready before start
Before deployment, you need a Wallarm Node Token from the Wallarm Console: Before deployment, you need a Wallarm Node Token from the Wallarm Console:
- **Create Token**: Navigate to Wallarm Console → **Nodes** → **Create node** - **Create Token**: Navigate to Wallarm Console → **Nodes** → **Create node**
- **Token Format**: Base64 encoded string (alphanumeric with `+`, `/`, `=`, `-`, `_`) - **Token Format**: Base64 encoded string (alphanumeric with `+`, `/`, `=`, `-`, `_`)
- **Documentation**: [Official Wallarm Documentation](https://docs.wallarm.com/admin-en/installation-docker-en/) - **Documentation**: [Official Wallarm Documentation](https://docs.wallarm.com/)
#### Header Configuration for Firewalls/Ingress Controllers #### Header Configuration for Firewalls/Ingress Controllers
To ensure proper IP address detection and metadata forwarding, configure your firewall or ingress controller to include these headers: To ensure proper IP address detection and metadata forwarding, configure your firewall or ingress controller to include these headers:
@ -116,7 +146,9 @@ proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Host $host;
``` ```
**Note**: The deployment script configures the first three headers automatically. You must manually add `X-Forwarded-Host: "$host"` to your existing firewall/ingress configuration. **Note**: The deployment scripts configure 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 ### Multiple Node Deployment on Same VM
@ -133,7 +165,7 @@ You can deploy multiple Wallarm nodes on the same virtual machine by:
3. **Isolated Configuration**: Each instance has its own: 3. **Isolated Configuration**: Each instance has its own:
- Docker container with unique name - Docker container with unique name
- Configuration directory (`/opt/wallarm/<instance-name>/`) - Configuration directory (`/opt/wallarm-<instance-name>/`)
- Port binding and network namespace - Port binding and network namespace
- Log files and start scripts - Log files and start scripts
@ -142,6 +174,47 @@ You can deploy multiple Wallarm nodes on the same virtual machine by:
- Each instance requires ~2GB disk space - Each instance requires ~2GB disk space
- Consider CPU allocation (1 vCPU core per 2-3 instances for moderate traffic) - Consider CPU allocation (1 vCPU core per 2-3 instances for moderate traffic)
## Native Deployment (`native/`)
The native deployment installs Wallarm directly on the operating system **without Docker**, using the official Wallarm **all-in-one installer**:
- The installer is downloaded from `https://meganode.wallarm.com/` (version configurable via the `WALLARM_VERSION` environment variable, default `6.12.7`)
- It automatically detects your OS and NGINX version, adds the Wallarm repositories, installs `wallarm-node` + the NGINX dynamic module, and registers the node
- Node registration is performed by the installer itself in batch mode (using your Wallarm token)
- The node configuration is written to `/opt/wallarm/etc/wallarm/node.yaml`
- The system NGINX is configured with a `wallarm-<instance>.conf` server block in `/etc/nginx/conf.d/`
**Notes on native deployment:**
- **One node per host**: native uses the system NGINX, so multiple Wallarm nodes on one host are not supported (unlike Docker). Use unique ingress ports only if you run a single node alongside other services.
- The deploy script keeps a copy of the generated NGINX config in `/opt/wallarm/<instance-name>/nginx.conf` and a log of the `nginx -t` test.
- `curl http://127.0.0.8/wallarm-status` reports Wallarm module statistics after deployment.
### Example: Version Pinning
```bash
WALLARM_VERSION=6.12.7 sudo ./native/wallarm-ct-deploy.sh
```
### Unified Node Manager (`native/wallarm-native.sh`)
For the **Wallarm Native Node** product (go-node, `connector-server` mode, no NGINX module), the repository provides a unified single-script manager. It 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
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`)
> **Note:** This script targets the Wallarm **Native Node** (connector mode). The `native/wallarm-ct-*.sh` scripts target the **NGINX-module** native deployment. Both are no-Docker options; choose the one that matches your Wallarm product.
## Reconfiguration Script (`wallarm-ct-reconfigure.sh`) ## Reconfiguration Script (`wallarm-ct-reconfigure.sh`)
After deployment, you may need to adjust: After deployment, you may need to adjust:
@ -149,44 +222,54 @@ After deployment, you may need to adjust:
- **Trusted proxy IPs/CIDRs** When the network topology changes (new load balancer, CDN, firewall) - **Trusted proxy IPs/CIDRs** When the network topology changes (new load balancer, CDN, firewall)
- **Operation mode** Switch from `monitoring` to `block` after verifying correct operation - **Operation mode** Switch from `monitoring` to `block` after verifying correct operation
The reconfigure script safely modifies the `nginx.conf` of an existing instance, creates a backup, and restarts the container. The reconfigure script safely modifies the configuration of an existing instance, creates a backup, and applies the changes (Docker: restarts the container; Native: tests and reloads NGINX).
**Usage**: **Usage**:
```bash ```bash
sudo ./wallarm-ct-reconfigure.sh # Docker
sudo ./docker/wallarm-ct-reconfigure.sh
# Native
sudo ./native/wallarm-ct-reconfigure.sh
``` ```
It will detect installed instances, show current settings, and guide you through the changes. It will detect installed instances, show current settings, and guide you through the changes.
## Uninstallation (`wallarm-ct-uninstall.sh`) ## Uninstallation (`wallarm-ct-uninstall.sh`)
To completely remove a Wallarm node and optionally Docker: To completely remove a Wallarm node:
```bash ```bash
sudo ./wallarm-ct-uninstall.sh # Docker: remove container/image and optionally Docker
sudo ./docker/wallarm-ct-uninstall.sh
# Native: remove NGINX config, Wallarm packages, and node data
sudo ./native/wallarm-ct-uninstall.sh
``` ```
## Artifact Sources (Priority Order) ## Artifact Sources
The system uses a smart fallback approach for artifact retrieval: ### Docker Deployment (Priority Order)
### 1. **Primary Source**: Git Repositorys The Docker deployment uses a smart fallback approach for artifact retrieval:
1. **Primary Source**: Git Repositorys
- URL: `https://git.sechpoint.app/customer-engineering/wallarm` - URL: `https://git.sechpoint.app/customer-engineering/wallarm`
- Contains: Docker binaries and Wallarm images with SHA256 checksums - Contains: `docker/binaries/` (Docker static binaries) and `docker/images/` (Wallarm images) with SHA256 checksums
- Benefits: Version control, access control, audit trail - Benefits: Version control, access control, audit trail
### 2. **Secondary Source**: Local Directories 2. **Secondary Source**: Local Directories
- `./binaries/` Docker static binaries (`docker-29.2.1.tgz`) - `docker/binaries/` Docker static binaries (`docker-29.2.1.tgz`)
- `./images/` Wallarm Docker images (`wallarm-node-6.11.0-rc1.tar.gz`) - `docker/images/` Wallarm Docker images (`wallarm-node-6.11.0-rc1.tar.gz`)
- Benefits: Airgapped environments, faster deployment - Benefits: Airgapped environments, faster deployment
### 3. **Tertiary Source**: Current Directory 3. **Tertiary Source**: Current Directory
- Any `docker-*.tgz` or `wallarm-node-*.tar.gz` files in script location - Any `docker-*.tgz` or `wallarm-node-*.tar.gz` files in script location
- Benefits: Adhoc deployments, testing scenarios - Benefits: Adhoc deployments, testing scenarios
### 4. **Fallback Source**: Internal Proxy Servers ### Native Deployment (Source)
- Original infrastructure URLs (with embedded credentials)
- Used only when other sources are unavailable The native deployment downloads the Wallarm **all-in-one installer** directly from `https://meganode.wallarm.com/`. No Docker artifacts are required. Current versions are listed at [node-artifact-versions](https://docs.wallarm.com/updating-migrating/node-artifact-versions/).
## Suggested Resources ## Suggested Resources
@ -211,30 +294,42 @@ The system uses a smart fallback approach for artifact retrieval:
## Script Reference ## Script Reference
### `wallarm-ct-check.sh` ### `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` / `native/wallarm-ct-check.sh`
**Purpose**: System validation and preflight checks **Purpose**: System validation and preflight checks
**Key Functions**: **Key Functions**:
- OS compatibility verification (Ubuntu, CentOS, Debian) - OS compatibility verification (Ubuntu, CentOS, Debian, Alpine)
- Network connectivity testing (US/EU cloud endpoints) - Network connectivity testing (US/EU cloud endpoints)
- Resource availability assessment - Resource availability assessment
- Docker installation checking - Artifact source validation (Docker: binaries/images; Native: installer)
- Environment file generation (`.env`) - Environment file generation (`.env`)
**Usage**: **Usage**:
```bash ```bash
# Run check with default settings # Run check with default settings
./wallarm-ct-check.sh ./<type>/wallarm-ct-check.sh
# Enable debug output # Enable debug output
DEBUG=1 ./wallarm-ct-check.sh DEBUG=1 ./<type>/wallarm-ct-check.sh
# Disable SSL certificate validation (for self-signed certs) # Disable SSL certificate validation (for self-signed certs)
WALLARM_INSECURE_SSL=0 ./wallarm-ct-check.sh WALLARM_INSECURE_SSL=0 ./<type>/wallarm-ct-check.sh
``` ```
### `wallarm-ct-deploy.sh` ### `docker/wallarm-ct-deploy.sh`
**Purpose**: Wallarm node deployment and configuration **Purpose**: Wallarm node deployment and configuration (Docker)
**Key Functions**: **Key Functions**:
- Interactive configuration wizard - Interactive configuration wizard
@ -247,10 +342,56 @@ WALLARM_INSECURE_SSL=0 ./wallarm-ct-check.sh
**Usage**: **Usage**:
```bash ```bash
# Interactive deployment # Interactive deployment
sudo ./wallarm-ct-deploy.sh sudo ./docker/wallarm-ct-deploy.sh
# Deployment with pre-filled environment (optional) # Deployment with pre-filled environment (optional)
WALLARM_TOKEN="your_token_here" sudo ./wallarm-ct-deploy.sh WALLARM_TOKEN="your_token_here" sudo ./docker/wallarm-ct-deploy.sh
```
### `native/wallarm-ct-deploy.sh`
**Purpose**: Wallarm node deployment and configuration (Native, no Docker)
**Key Functions**:
- Interactive configuration wizard
- Downloads and runs the Wallarm all-in-one installer (batch mode)
- Node registration with your Wallarm token
- NGINX server block configuration (proxy, wallarm_mode, trusted proxies, health endpoint)
- NGINX test + reload
- Health check and deployment verification
**Usage**:
```bash
# Interactive deployment
sudo ./native/wallarm-ct-deploy.sh
# Pin a specific Wallarm version
WALLARM_VERSION=6.12.7 sudo ./native/wallarm-ct-deploy.sh
# Add node labels (group)
WALLARM_LABELS='group=prod' sudo ./native/wallarm-ct-deploy.sh
```
### `native/wallarm-native.sh`
**Purpose**: Unified single-script manager for the Wallarm Native Node (connector mode, no Docker/NGINX module)
**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
``` ```
### `wallarm-ct-reconfigure.sh` ### `wallarm-ct-reconfigure.sh`
@ -260,11 +401,11 @@ WALLARM_TOKEN="your_token_here" sudo ./wallarm-ct-deploy.sh
- Update `set_real_ip_from` (trusted proxy IPs/CIDRs) - Update `set_real_ip_from` (trusted proxy IPs/CIDRs)
- Change `wallarm_mode` (monitoring/block) - Change `wallarm_mode` (monitoring/block)
- Create backup of current configuration - Create backup of current configuration
- Restart container to apply changes - Apply changes (Docker: container restart; Native: NGINX reload)
**Usage**: **Usage**:
```bash ```bash
sudo ./wallarm-ct-reconfigure.sh sudo ./<type>/wallarm-ct-reconfigure.sh
``` ```
### `wallarm-ct-uninstall.sh` ### `wallarm-ct-uninstall.sh`
@ -272,21 +413,14 @@ sudo ./wallarm-ct-reconfigure.sh
**Key Functions**: **Key Functions**:
- Interactive confirmation with safety checks - Interactive confirmation with safety checks
- Container stopping and removal - Docker: container/image removal, Docker cleanup; Native: NGINX config + package removal
- Image cleanup
- Configuration directory removal - Configuration directory removal
- Optional Docker binary cleanup - Optional artifact cleanup
**Usage**: **Usage**:
```bash ```bash
# Interactive uninstallation # Interactive uninstallation
sudo ./wallarm-ct-uninstall.sh sudo ./<type>/wallarm-ct-uninstall.sh
# Force removal without prompts (use with caution)
FORCE=1 sudo ./wallarm-ct-uninstall.sh
# Remove Docker binaries (if no other containers exist)
REMOVE_DOCKER=1 sudo ./wallarm-ct-uninstall.sh
``` ```
## Troubleshooting ## Troubleshooting
@ -310,7 +444,7 @@ cat /etc/os-release
#### 2. Deployment Fails Port Conflicts #### 2. Deployment Fails Port Conflicts
```bash ```bash
# Check for listening ports # Check for listening ports
sudo ss -tlnp | grep ':80\|:90\|:8080' sudo ss -tlnp | grep ':80\|:8080'
# Find process using port # Find process using port
sudo lsof -i :80 sudo lsof -i :80
@ -324,7 +458,7 @@ sudo lsof -i :80
echo "your_token" | base64 -d 2>/dev/null | base64 echo "your_token" | base64 -d 2>/dev/null | base64
# Get new token from Wallarm Console # Get new token from Wallarm Console
# https://docs.wallarm.com/admin-en/installation-docker-en/ # https://docs.wallarm.com/
``` ```
#### 4. Docker Installation Problems #### 4. Docker Installation Problems
@ -339,7 +473,19 @@ groups $USER
docker run --rm hello-world docker run --rm hello-world
``` ```
#### 5. Header Configuration Warnings #### 5. Native Installer Fails
```bash
# The all-in-one installer logs its output to the terminal and to files
# Check the current version at https://docs.wallarm.com/updating-migrating/node-artifact-versions/
# Verify node registration
ls -la /opt/wallarm/etc/wallarm/node.yaml
# Check Wallarm module status
curl http://127.0.0.8/wallarm-status
```
#### 6. Header Configuration Warnings
Ensure your upstream firewall/load balancer includes: Ensure your upstream firewall/load balancer includes:
- `X-Real-IP: "$remote_addr"` - `X-Real-IP: "$remote_addr"`
- `X-Forwarded-For: "$proxy_add_x_forwarded_for"` - `X-Forwarded-For: "$proxy_add_x_forwarded_for"`
@ -347,42 +493,65 @@ Ensure your upstream firewall/load balancer includes:
- `X-Forwarded-Host: "$host"` - `X-Forwarded-Host: "$host"`
### Log Files ### Log Files
- **Preflight Check**: `~/logs/wallarm-check.log` - **Preflight Check**: `~/logs/wallarm-check.log` (Docker) / `~/logs/wallarm-check-native.log` (Native)
- **Deployment**: `~/logs/wallarm-deployment.log` - **Deployment**: `~/logs/wallarm-deployment.log` (Docker) / `~/logs/wallarm-deployment-native.log` (Native)
- **Container Logs**: `/opt/wallarm/<instance-name>/container.log` - **Docker Container Logs**: `/opt/wallarm-<instance-name>/container.log`
- **NGINX Logs (Native)**: `/var/log/nginx/error.log`
- **System Logs**: `/var/log/syslog` or `/var/log/messages` - **System Logs**: `/var/log/syslog` or `/var/log/messages`
## Security Considerations ## Security Considerations
### Network Security ### Network Security
- Use firewall rules to restrict access to monitoring ports (default: 90, 190, 290, etc.) - Use firewall rules to restrict access to monitoring endpoints
- Consider VPN or private networking for management interfaces - Consider VPN or private networking for management interfaces
- Implement rate limiting for ingress ports - Implement rate limiting for ingress ports
### Access Control ### Access Control
- Restrict `sudo` access to deployment scripts - Restrict `sudo` access to deployment scripts
- Use separate service accounts for Wallarm containers - Use separate service accounts for Wallarm services
- Implement proper secret management for Wallarm tokens - Implement proper secret management for Wallarm tokens
### Monitoring & Auditing ### Monitoring & Auditing
- Enable Docker logging driver with rotation - Enable logging with rotation
- Monitor container resource usage - Monitor resource usage
- Regular security updates for Docker and host OS - Regular security updates for Docker/NGINX and host OS
## Maintenance ## Maintenance
### Regular Tasks ### Regular Tasks
1. **Log Rotation**: Configure logrotate for container logs 1. **Log Rotation**: Configure logrotate for logs
2. **Docker Updates**: Periodically update Docker engine 2. **Updates**: Periodically update Docker engine/NGINX and Wallarm node
3. **Image Updates**: Check for new Wallarm node versions 3. **Image/Version Updates**: Check for new Wallarm node versions
4. **Backup**: Regular backup of configuration directories 4. **Backup**: Regular backup of configuration directories
### Version Updates ### Version Updates
When updating Wallarm node version: When updating Wallarm node version:
1. Pull new image from Git Repositorys or official registry 1. **Docker**: Pull new image from Git Repositorys or official registry, stop existing container, deploy new container with updated image, verify functionality before removing old container
2. Stop existing container 2. **Native**: Set `WALLARM_VERSION` to the new version and re-run the deploy script, or follow the [official upgrade guide](https://docs.wallarm.com/updating-migrating/)
3. Deploy new container with updated image
4. Verify functionality before removing old container ## Repository Structure
```
wallarm/
├── README.md
├── changelog.md
├── setup.sh # Downloads scripts for a chosen deployment type
├── common/
│ └── wallarm-lib.sh # Shared library (both deployment types)
├── docker/ # Docker deployment
│ ├── wallarm-ct-check.sh
│ ├── wallarm-ct-deploy.sh
│ ├── wallarm-ct-reconfigure.sh
│ ├── wallarm-ct-uninstall.sh
│ ├── binaries/ # Docker static binaries
│ └── images/ # Wallarm Docker images
└── native/ # Native deployment (no Docker)
├── wallarm-ct-check.sh
├── wallarm-ct-deploy.sh
├── wallarm-ct-reconfigure.sh
├── wallarm-ct-uninstall.sh
└── wallarm-native.sh # Unified single-script node manager (Native Node product)
```
## Disclaimer ## Disclaimer

View file

@ -5,6 +5,41 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to date-based versioning (YYYY-MM.x). and this project adheres to date-based versioning (YYYY-MM.x).
## [2026-08.1] - 2026-08-01
### Added
- **Native deployment type**: Wallarm filtering node can now be deployed directly on the OS **without Docker**
- `native/wallarm-ct-check.sh` Preflight validation for native deployment (no Docker artifact checks)
- `native/wallarm-ct-deploy.sh` Downloads and runs the official Wallarm all-in-one installer (`meganode.wallarm.com`, version configurable via `WALLARM_VERSION`), configures the NGINX server block, reloads and verifies the node
- `native/wallarm-ct-reconfigure.sh` Update trusted proxies / `wallarm_mode` via NGINX test + reload
- `native/wallarm-ct-uninstall.sh` Remove NGINX config, Wallarm packages/repos, and `/opt/wallarm` data
- **Unified node manager**: `native/wallarm-native.sh` single-script manager for the Wallarm Native Node (go-node, connector-server mode)
- `--preflight` checks (root, systemd, architecture, required commands, installer + Wallarm cloud connectivity, disk/memory, listen-port availability); auto-run before `--install`
- Interactive parallel multi-node installation with per-node systemd template units (`wallarm-node@<name>.service`)
- `--config` (address/token/labels, safe env rewrite), `--remove`, `--status [NODE]`
- All-in-one installer from `repo.wallarm.com` (overridable via `WALLARM_INSTALLER_URL`/`WALLARM_INSTALLER_ARCH`)
- **Shared library**: `common/wallarm-lib.sh` extracted and reused by both deployment types
- Colors, logging (`log_message`, `fail_with_remediation`), early error handler
- System detection (OS/arch/init), network connectivity tests
- Preflight `.env` parsing (`load_env_file`), cloud region selection (`select_cloud_region`)
- Validation helpers (IP, CIDR, port), artifact download + checksum verification
### Changed
- **Repository structure** now separates deployment types:
- `docker/` all Docker-based scripts moved here (`git mv`, history preserved)
- `docker/binaries/` and `docker/images/` Docker artifacts moved into the Docker tree
- `native/` new native (no-Docker) deployment scripts
- `common/` shared library
- **Artifact URLs** updated to the `docker/` prefix (`/docker/binaries/...`, `/docker/images/...`)
- **Docker scripts** refactored to source `common/wallarm-lib.sh` (removed duplicated helper functions; behavior preserved)
- **setup.sh** now prompts for a deployment type (`docker` or `native`), downloads the matching scripts into `docker/` or `native/` (native now includes `wallarm-native.sh`); supports `DEPLOYMENT_TYPE=native` for non-interactive use
- **README.md** rewritten to document both deployment types, the new structure, the unified manager, and native-specific usage
### Notes
- Native deployment supports one node per host (system NGINX); multi-node remains a Docker feature
- Native installer version defaults to `6.12.7` and can be pinned via `WALLARM_VERSION`
- Docker deployment behavior is unchanged apart from the new directory layout
- The unified manager targets the Wallarm **Native Node** product; the `native/wallarm-ct-*.sh` scripts target the **NGINX-module** native deployment. Both are no-Docker options
## [2026-04.1] - 2026-04-21 ## [2026-04.1] - 2026-04-21
### Added ### Added
- Initial changelog file with versioning schema - Initial changelog file with versioning schema

530
common/wallarm-lib.sh Executable file
View file

@ -0,0 +1,530 @@
#!/bin/bash
# ==============================================================================
# WALLARM COMMON LIBRARY - shared functions for docker/ and native/ deployment
# ==============================================================================
# Purpose: Single source of truth for functionality shared by both deployment
# types (Docker container vs native NGINX install).
# Usage: Scripts source this file AFTER setting `set -euo pipefail` and before
# defining their own functions:
# source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../common/wallarm-lib.sh"
# The library does NOT set the error trap itself; each script owns its
# error handling configuration.
# ==============================================================================
# ------------------------------------------------------------------------------
# COLOR DEFINITIONS (for better UX)
# ------------------------------------------------------------------------------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
BOLD='\033[1m'
NC='\033[0m' # No Color
# ------------------------------------------------------------------------------
# SSL SECURITY SETTINGS
# WALLARM_INSECURE_SSL=1 disables SSL certificate validation (for self-signed
# certs). Kept as a default of 1 for backward compatibility with existing usage.
# ------------------------------------------------------------------------------
INSECURE_SSL="${WALLARM_INSECURE_SSL:-1}"
if [ "$INSECURE_SSL" = "1" ]; then
CURL_INSECURE_FLAG="-k"
else
CURL_INSECURE_FLAG=""
fi
# ------------------------------------------------------------------------------
# EARLY ERROR HANDLER
# Use with: trap early_error_handler ERR
# Handles failures before log_message is available (or when logging is not set).
# ------------------------------------------------------------------------------
early_error_handler() {
echo -e "${RED}${BOLD}[ERROR]${NC} Script failed at line $LINENO. Command: $BASH_COMMAND" >&2
exit 1
}
# ------------------------------------------------------------------------------
# LOGGING
# ------------------------------------------------------------------------------
# Log a message to stderr (colored) and to $LOG_FILE (if set).
log_message() {
local level="$1"
local message="$2"
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local color="$NC"
case "$level" in
"INFO") color="${BLUE}" ;;
"SUCCESS") color="${GREEN}" ;;
"WARNING") color="${YELLOW}" ;;
"ERROR") color="${RED}" ;;
"DEBUG") color="${CYAN}" ;;
esac
echo -e "${color}[${timestamp}] ${level}: ${message}${NC}" >&2
if [ -n "${LOG_FILE:-}" ]; then
echo "[${timestamp}] ${level}: ${message}" >> "$LOG_FILE"
fi
}
# Log an ERROR, print a remediation banner, and exit non-zero.
fail_with_remediation() {
local error_msg="$1"
local remediation="$2"
log_message "ERROR" "$error_msg"
echo -e "\n${RED}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${RED}${BOLD}║ DEPLOYMENT FAILED ║${NC}"
echo -e "${RED}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}"
echo -e "\n${YELLOW}${BOLD}Root Cause:${NC} $error_msg"
echo -e "\n${YELLOW}${BOLD}How to Fix:${NC}"
echo -e "$remediation"
echo -e "\n${YELLOW}Check the full log for details:${NC} ${LOG_FILE:-stdout}"
exit 1
}
# ------------------------------------------------------------------------------
# MISC HELPERS
# ------------------------------------------------------------------------------
# Extract hostname from a URL, stripping protocol and credentials for safe logging.
extract_hostname_from_url() {
local url="$1"
local hostpart="${url#*://}"
hostpart="${hostpart#*@}"
hostpart="${hostpart%%[:/]*}"
echo "$hostpart"
}
# Check whether a command exists (respects PATH + common system directories).
command_exists() {
local cmd="$1"
if command -v "$cmd" >/dev/null 2>&1; then
return 0
fi
local system_dirs=("/usr/sbin" "/sbin" "/usr/local/sbin" "/usr/bin" "/bin" "/usr/local/bin")
for dir in "${system_dirs[@]}"; do
if [ -x "$dir/$cmd" ]; then
return 0
fi
done
return 1
}
# Validate an IPv4 address (basic format + octet range check).
validate_ip_address() {
local ip="$1"
if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
return 1
fi
IFS='.' read -r i1 i2 i3 i4 <<< "$ip"
if [ "$i1" -gt 255 ] || [ "$i2" -gt 255 ] || [ "$i3" -gt 255 ] || [ "$i4" -gt 255 ]; then
return 1
fi
return 0
}
# Validate an IP or CIDR entry (IPv4 with optional /prefix). Returns 0 if valid.
validate_ip_or_cidr() {
local entry="$1"
if [[ ! "$entry" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(/[0-9]{1,2})?$ ]]; then
return 1
fi
IFS='/' read -r ip cidr <<< "$entry"
IFS='.' read -r o1 o2 o3 o4 <<< "$ip"
if [ "$o1" -gt 255 ] || [ "$o2" -gt 255 ] || [ "$o3" -gt 255 ] || [ "$o4" -gt 255 ]; then
return 1
fi
if [ -n "$cidr" ] && { [ "$cidr" -lt 0 ] || [ "$cidr" -gt 32 ]; }; then
return 1
fi
return 0
}
# Check if a TCP/UDP port is currently in use. Returns 0 when available.
check_port_available() {
local port="$1"
local protocol="${2:-tcp}"
log_message "DEBUG" "Checking port $port/$protocol availability..."
if command -v ss >/dev/null 2>&1; then
if ss -"${protocol:0:1}"ln | grep -q ":$port "; then
return 1 # Port in use
fi
elif command -v netstat >/dev/null 2>&1; then
if netstat -tulpn 2>/dev/null | grep -E ":$port\s" >/dev/null 2>&1; then
return 1 # Port in use
fi
else
log_message "WARNING" "Neither ss nor netstat available, cannot check port $port"
fi
return 0 # Port available (or cannot check)
}
# ------------------------------------------------------------------------------
# SYSTEM DETECTION
# ------------------------------------------------------------------------------
# Detect OS name and version. Prints "name:version".
detect_os_and_version() {
log_message "INFO" "Detecting OS and version..."
local os_name=""
local os_version=""
if [ -f /etc/os-release ]; then
. /etc/os-release
os_name="$ID"
os_version="$VERSION_ID"
elif [ -f /etc/redhat-release ]; then
os_name="rhel"
os_version=$(sed -e 's/.*release \([0-9]\+\)\..*/\1/' /etc/redhat-release)
elif [ -f /etc/alpine-release ]; then
os_name="alpine"
os_version=$(cat /etc/alpine-release)
else
os_name=$(uname -s | tr '[:upper:]' '[:lower:]')
os_version=$(uname -r)
fi
os_name="${os_name//[$'\t\r\n']/}"
os_version="${os_version//[$'\t\r\n']/}"
case "$os_name" in
"ubuntu"|"debian"|"centos"|"rhel"|"alpine"|"amzn"|"ol"|"rocky"|"almalinux")
log_message "SUCCESS" "OS detected: $os_name $os_version (supported)"
;;
*)
log_message "WARNING" "OS '$os_name' not explicitly tested but may work"
;;
esac
echo "$os_name:$os_version"
}
# Detect architecture. Prints a normalized value (x86_64/aarch64/armhf/unknown).
detect_architecture() {
log_message "INFO" "Detecting system architecture..."
local arch
arch=$(uname -m)
local docker_arch=""
case "$arch" in
x86_64|x64|amd64)
docker_arch="x86_64"
log_message "SUCCESS" "Architecture: x86_64 (Intel/AMD 64-bit)"
;;
aarch64|arm64)
docker_arch="aarch64"
log_message "SUCCESS" "Architecture: aarch64 (ARM 64-bit)"
;;
armv7l|armhf)
docker_arch="armhf"
log_message "SUCCESS" "Architecture: armhf (ARM 32-bit)"
;;
*)
log_message "ERROR" "Unsupported architecture: $arch"
docker_arch="unknown"
;;
esac
echo "$docker_arch"
}
# Detect the init system. Prints one of systemd/openrc/sysvinit/upstart/unknown.
detect_init_system() {
log_message "INFO" "Detecting init system..."
local init_system="unknown"
if [ "$(uname -s)" = "Darwin" ]; then
init_system="darwin"
log_message "SUCCESS" "Init system: darwin (macOS)"
elif command -v systemctl >/dev/null 2>&1 && systemctl --version >/dev/null 2>&1; then
init_system="systemd"
log_message "SUCCESS" "Init system: systemd"
elif { [ -d /etc/init.d ] && [ -x /sbin/initctl ]; } || [ -x /sbin/init ]; then
init_system="sysvinit"
log_message "SUCCESS" "Init system: sysvinit"
elif [ -d /etc/rc.d ] && [ -x /sbin/rc-service ]; then
init_system="openrc"
log_message "SUCCESS" "Init system: openrc (Alpine)"
elif [ -x /sbin/upstart ]; then
init_system="upstart"
log_message "SUCCESS" "Init system: upstart"
else
log_message "WARNING" "Could not determine init system"
fi
echo "$init_system"
}
# ------------------------------------------------------------------------------
# NETWORK CONNECTIVITY
# ------------------------------------------------------------------------------
# Test connectivity to a host/URL. Returns 0 when reachable.
test_connectivity() {
local host="$1"
local description="$2"
local timeout="${3:-10}"
local display_host
display_host=$(extract_hostname_from_url "$host")
log_message "INFO" "Testing connectivity to $description ($display_host)..."
local url="$host"
if [[ ! "$host" =~ ^https?:// ]]; then
url="https://$host"
fi
if curl -sL $CURL_INSECURE_FLAG --connect-timeout "$timeout" "$url" >/dev/null 2>&1; then
log_message "SUCCESS" "$description is reachable"
return 0
else
log_message "ERROR" "$description is NOT reachable"
return 1
fi
}
# Test a set of cloud endpoints. Prints "true" if all reachable, else "false".
test_cloud_endpoints() {
local cloud_name="$1"
shift
local endpoints=("$@")
log_message "INFO" "Testing $cloud_name cloud endpoints..."
local all_reachable=true
local endpoint
for endpoint in "${endpoints[@]}"; do
if ! test_connectivity "$endpoint" "$cloud_name cloud endpoint $endpoint"; then
all_reachable=false
fi
done
if [ "$all_reachable" = "true" ]; then
log_message "SUCCESS" "All $cloud_name cloud endpoints reachable"
echo "true"
else
log_message "WARNING" "Some $cloud_name cloud endpoints unreachable"
echo "false"
fi
}
# ------------------------------------------------------------------------------
# ENVIRONMENT FILE HANDLING
# ------------------------------------------------------------------------------
# Load a preflight .env file into global variables. Returns 1 if file missing.
load_env_file() {
local env_file="${1:-$ENV_FILE}"
if [ ! -f "$env_file" ]; then
log_message "ERROR" "Environment file not found: $env_file"
return 1
fi
local key value
while IFS='=' read -r key value; do
[[ "$key" =~ ^#.*$ ]] && continue
[[ -z "$key" ]] && continue
value="${value%\"}"
value="${value#\"}"
case "$key" in
result) CHECK_RESULT="$value" ;;
os_name) OS_NAME="$value" ;;
os_version) OS_VERSION="$value" ;;
architecture) ARCHITECTURE="$value" ;;
init_system) INIT_SYSTEM="$value" ;;
us_cloud_reachable) US_CLOUD_REACHABLE="$value" ;;
eu_cloud_reachable) EU_CLOUD_REACHABLE="$value" ;;
registry_reachable) REGISTRY_REACHABLE="$value" ;;
download_reachable) DOWNLOAD_REACHABLE="$value" ;;
git_reachable) GIT_REACHABLE="$value" ;;
installer_reachable) INSTALLER_REACHABLE="$value" ;;
esac
done < "$env_file"
log_message "SUCCESS" "Loaded preflight results from $env_file"
return 0
}
# ------------------------------------------------------------------------------
# CLOUD REGION SELECTION
# Sets CLOUD_REGION and API_HOST based on reachability from the preflight check.
# ------------------------------------------------------------------------------
select_cloud_region() {
log_message "INFO" "Selecting Wallarm Cloud region..."
echo -e "\n${CYAN}${BOLD}Wallarm Cloud Region Selection:${NC}"
local available_options=()
if [ "${US_CLOUD_REACHABLE:-false}" = "true" ]; then
echo -e "1. ${YELLOW}US Cloud${NC} (us1.api.wallarm.com) - For US-based deployments"
available_options+=("1" "US")
fi
if [ "${EU_CLOUD_REACHABLE:-false}" = "true" ]; then
echo -e "2. ${YELLOW}EU Cloud${NC} (api.wallarm.com) - For EU-based deployments"
available_options+=("2" "EU")
fi
if [ ${#available_options[@]} -eq 0 ]; then
fail_with_remediation "No cloud regions available" \
"Preflight check showed no reachable cloud regions.
1. Check network connectivity to Wallarm endpoints
2. Run the preflight check again
3. Contact network administrator if behind firewall"
fi
local pattern
pattern="^($(IFS='|'; echo "${available_options[*]}"))$"
local cloud_choice=""
while [[ ! "$cloud_choice" =~ $pattern ]]; do
if [ ${#available_options[@]} -eq 2 ]; then
if [ "${US_CLOUD_REACHABLE:-false}" = "true" ]; then
cloud_choice="US"
break
else
cloud_choice="EU"
break
fi
fi
read -r -p "$(echo -e "${YELLOW}Enter choice [1/US or 2/EU]: ${NC}")" cloud_choice
cloud_choice=$(echo "$cloud_choice" | tr '[:lower:]' '[:upper:]')
case "$cloud_choice" in
1|"US")
if [ "${US_CLOUD_REACHABLE:-false}" = "true" ]; then
CLOUD_REGION="US"
API_HOST="us1.api.wallarm.com"
log_message "INFO" "Selected US Cloud"
else
echo -e "${RED}US Cloud is not reachable (per preflight check)${NC}"
cloud_choice=""
fi
;;
2|"EU")
if [ "${EU_CLOUD_REACHABLE:-false}" = "true" ]; then
CLOUD_REGION="EU"
API_HOST="api.wallarm.com"
log_message "INFO" "Selected EU Cloud"
else
echo -e "${RED}EU Cloud is not reachable (per preflight check)${NC}"
cloud_choice=""
fi
;;
*)
if [ -n "$cloud_choice" ]; then
echo -e "${RED}Invalid choice. Select from available options above.${NC}"
fi
;;
esac
done
log_message "SUCCESS" "Cloud region selected: $CLOUD_REGION ($API_HOST)"
}
# ------------------------------------------------------------------------------
# ARTIFACT DOWNLOAD (Git Repositorys primary source)
# ------------------------------------------------------------------------------
# Download a file from Git Repositorys. Returns 0 on success.
download_from_git() {
local url="$1"
local output_path="$2"
local description="$3"
log_message "INFO" "Attempting to download $description from Git Repositorys..."
log_message "DEBUG" "URL: $url"
log_message "DEBUG" "Output path: $output_path"
if curl -fL "$CURL_INSECURE_FLAG" --connect-timeout 30 --max-time 300 --progress-bar "$url" -o "$output_path"; then
log_message "SUCCESS" "Downloaded $description to $output_path"
return 0
else
local curl_exit=$?
log_message "ERROR" "Failed to download $description from Git Repositorys (curl exit: $curl_exit)"
if [ -f "$output_path" ]; then
rm -f "$output_path"
log_message "DEBUG" "Removed partial download: $output_path"
fi
return 1
fi
}
# Verify a file against a checksum file or URL. Returns 0 on success;
# skips verification (returns 0) when the checksum cannot be obtained.
verify_checksum() {
local file_path="$1"
local checksum_file_or_url="$2"
local description="$3"
log_message "INFO" "Verifying $description checksum..."
local checksum_file=""
if [[ "$checksum_file_or_url" =~ ^https?:// ]]; then
checksum_file="/tmp/$(basename "$checksum_file_or_url")"
log_message "DEBUG" "Downloading checksum from URL: $checksum_file_or_url"
if ! curl -fL "$CURL_INSECURE_FLAG" --connect-timeout 10 --max-time 30 -s "$checksum_file_or_url" -o "$checksum_file"; then
log_message "WARNING" "Could not download checksum file, skipping verification"
return 0
fi
else
checksum_file="$checksum_file_or_url"
fi
if [ ! -f "$checksum_file" ]; then
log_message "WARNING" "Checksum file not found: $checksum_file, skipping verification"
return 0
fi
local expected_checksum
expected_checksum=$(awk '{print $1}' "$checksum_file" 2>/dev/null)
if [ -z "$expected_checksum" ]; then
log_message "WARNING" "Could not read checksum from $checksum_file, skipping verification"
return 0
fi
log_message "DEBUG" "Computing SHA256 checksum of $file_path..."
local actual_checksum
if command -v sha256sum >/dev/null 2>&1; then
actual_checksum=$(sha256sum "$file_path" | awk '{print $1}')
elif command -v shasum >/dev/null 2>&1; then
actual_checksum=$(shasum -a 256 "$file_path" | awk '{print $1}')
else
log_message "WARNING" "sha256sum or shasum not available, skipping checksum verification"
return 0
fi
if [ "$expected_checksum" = "$actual_checksum" ]; then
log_message "SUCCESS" "$description checksum verified successfully"
return 0
else
log_message "ERROR" "$description checksum verification FAILED"
log_message "DEBUG" "Expected: $expected_checksum"
log_message "DEBUG" "Actual: $actual_checksum"
rm -f "$file_path"
log_message "INFO" "Removed corrupted file: $file_path"
return 1
fi
}

View file

@ -1,72 +1,39 @@
#!/bin/bash #!/bin/bash
# ============================================================================== # ==============================================================================
# WALLARM PREFLIGHT CHECK SCRIPT - V1.2 # WALLARM PREFLIGHT CHECK SCRIPT - V1.3 (Docker deployment)
# ============================================================================== # ==============================================================================
# Purpose: Validate system readiness for Wallarm deployment # Purpose: Validate system readiness for Wallarm Docker deployment
# Features: # Features:
# - Non-interactive system validation (sudo, OS, architecture, init system) # - Non-interactive system validation (sudo, OS, architecture, init system)
# - Network connectivity testing (US/EU cloud) # - Network connectivity testing (US/EU cloud)
# - Docker artifact source validation (Git Repositorys / local binaries/images)
# - Outputs results to .env file for deployment script # - Outputs results to .env file for deployment script
# - DAU-friendly error messages with remediation # - DAU-friendly error messages with remediation
# ============================================================================== # ==============================================================================
# Color definitions for better UX # Script location and shared library (colors, logging, validation, detection, connectivity)
RED='\033[0;31m' SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
GREEN='\033[0;32m' # shellcheck source=../common/wallarm-lib.sh
YELLOW='\033[1;33m' source "$SCRIPT_DIR/../common/wallarm-lib.sh"
BLUE='\033[1;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m' # No Color
# Strict error handling # Strict error handling
set -euo pipefail set -euo pipefail
# Simple error handler for early failures (before log_message is defined)
early_error_handler() {
echo -e "${RED}${BOLD}[ERROR]${NC} Script failed at line $LINENO. Command: $BASH_COMMAND" >&2
exit 1
}
trap early_error_handler ERR trap early_error_handler ERR
# Extract hostname from URL (strip protocol and credentials for safe logging)
extract_hostname_from_url() {
local url="$1"
# Remove protocol
local hostpart="${url#*://}"
# Remove credentials if present (username:password@)
hostpart="${hostpart#*@}"
# Remove port and path
hostpart="${hostpart%%[:/]*}"
echo "$hostpart"
}
# Configuration # Configuration
ENV_FILE=".env" ENV_FILE=".env"
LOG_FILE="${HOME:-.}/logs/wallarm-check.log" LOG_FILE="${HOME:-.}/logs/wallarm-check.log"
# SSL security settings # Git Repositorys artifact URLs (primary source) - Docker deployment artifacts
# WALLARM_INSECURE_SSL=1 to disable SSL certificate validation (insecure, for self-signed certs)
INSECURE_SSL="${WALLARM_INSECURE_SSL:-1}" # Default to insecure for backward compatibility
if [ "$INSECURE_SSL" = "1" ]; then
CURL_INSECURE_FLAG="-k"
# Warning will be logged later when log_message is available
else
CURL_INSECURE_FLAG=""
fi
# Git Repositorys artifact URLs (primary source) - same as deployment script
GIT_BASE_URL="https://git.sechpoint.app/customer-engineering/wallarm" GIT_BASE_URL="https://git.sechpoint.app/customer-engineering/wallarm"
GIT_RAW_URL="https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main" GIT_RAW_URL="https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main"
GIT_DOCKER_BINARY_URL="${GIT_RAW_URL}/binaries/docker-29.2.1.tgz" GIT_DOCKER_BINARY_URL="${GIT_RAW_URL}/docker/binaries/docker-29.2.1.tgz"
GIT_WALLARM_IMAGE_URL="${GIT_RAW_URL}/images/wallarm-node-6.11.0-rc1.tar.gz" GIT_WALLARM_IMAGE_URL="${GIT_RAW_URL}/docker/images/wallarm-node-6.11.0-rc1.tar.gz"
# Local artifact directories (relative to script location) # Local artifact directories (relative to script location)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOCAL_BINARY_DIR="${SCRIPT_DIR}/binaries" LOCAL_BINARY_DIR="${SCRIPT_DIR}/binaries"
LOCAL_IMAGE_DIR="${SCRIPT_DIR}/images" LOCAL_IMAGE_DIR="${SCRIPT_DIR}/images"
# Cloud endpoints (from Wallarm documentation) # Cloud endpoints (from Wallarm documentation)
EU_DATA_NODES=("api.wallarm.com" "node-data0.eu1.wallarm.com" "node-data1.eu1.wallarm.com") EU_DATA_NODES=("api.wallarm.com" "node-data0.eu1.wallarm.com" "node-data1.eu1.wallarm.com")
US_DATA_NODES=("us1.api.wallarm.com" "node-data0.us1.wallarm.com" "node-data1.us1.wallarm.com") US_DATA_NODES=("us1.api.wallarm.com" "node-data0.us1.wallarm.com" "node-data1.us1.wallarm.com")
@ -74,31 +41,12 @@ US_DATA_NODES=("us1.api.wallarm.com" "node-data0.us1.wallarm.com" "node-data1.us
# Global result tracking # Global result tracking
CHECK_RESULT="pass" CHECK_RESULT="pass"
CHECK_ERRORS=() CHECK_ERRORS=()
GIT_REACHABLE="false" GIT_REACHABLE="false"
# ============================================================================== # ==============================================================================
# LOGGING & ERROR HANDLING FUNCTIONS # RESULT TRACKING & ENV FILE
# ============================================================================== # ==============================================================================
log_message() {
local level="$1"
local message="$2"
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
case "$level" in
"INFO") color="${BLUE}" ;;
"SUCCESS") color="${GREEN}" ;;
"WARNING") color="${YELLOW}" ;;
"ERROR") color="${RED}" ;;
"DEBUG") color="${CYAN}" ;;
*) color="${NC}" ;;
esac
echo -e "${color}[${timestamp}] ${level}: ${message}${NC}" >&2
echo "[${timestamp}] ${level}: ${message}" >> "$LOG_FILE"
}
add_error() { add_error() {
local error_msg="$1" local error_msg="$1"
CHECK_ERRORS+=("$error_msg") CHECK_ERRORS+=("$error_msg")
@ -117,7 +65,6 @@ write_env_file() {
local download_reachable="$8" local download_reachable="$8"
local git_reachable="${9:-false}" local git_reachable="${9:-false}"
# Create .env file
cat > "$ENV_FILE" << EOF cat > "$ENV_FILE" << EOF
# Wallarm Preflight Check Results # Wallarm Preflight Check Results
# Generated: $(date '+%Y-%m-%d %H:%M:%S') # Generated: $(date '+%Y-%m-%d %H:%M:%S')
@ -136,7 +83,6 @@ git_reachable=$git_reachable
EOF EOF
# Add errors if any
if [ ${#CHECK_ERRORS[@]} -gt 0 ]; then if [ ${#CHECK_ERRORS[@]} -gt 0 ]; then
echo "# Errors:" >> "$ENV_FILE" echo "# Errors:" >> "$ENV_FILE"
for i in "${!CHECK_ERRORS[@]}"; do for i in "${!CHECK_ERRORS[@]}"; do
@ -154,25 +100,20 @@ EOF
validate_sudo_access() { validate_sudo_access() {
log_message "INFO" "Validating sudo access..." log_message "INFO" "Validating sudo access..."
# Detect OS
local os_name local os_name
os_name=$(uname -s | tr '[:upper:]' '[:lower:]') os_name=$(uname -s | tr '[:upper:]' '[:lower:]')
# Check if user can run sudo
if ! command -v sudo >/dev/null 2>&1; then if ! command -v sudo >/dev/null 2>&1; then
add_error "sudo command not found" add_error "sudo command not found"
return 1 return 1
fi fi
# On macOS, we can't reliably test sudo authentication without prompting
# Skip the actual authentication test but warn
if [ "$os_name" = "darwin" ]; then if [ "$os_name" = "darwin" ]; then
log_message "WARNING" "macOS detected: sudo authentication test skipped (may prompt during deployment)" log_message "WARNING" "macOS detected: sudo authentication test skipped (may prompt during deployment)"
log_message "INFO" "Note: macOS is not a supported deployment target. This check is for Linux servers." log_message "INFO" "Note: macOS is not a supported deployment target. This check is for Linux servers."
return 0 return 0
fi fi
# Test sudo with password prompt if needed
if ! sudo -v; then if ! sudo -v; then
add_error "sudo authentication failed" add_error "sudo authentication failed"
return 1 return 1
@ -187,7 +128,6 @@ validate_required_commands() {
local missing_commands=() local missing_commands=()
# Detect OS
local os_name local os_name
os_name=$(uname -s | tr '[:upper:]' '[:lower:]') os_name=$(uname -s | tr '[:upper:]' '[:lower:]')
@ -221,24 +161,8 @@ validate_required_commands() {
) )
fi fi
# Helper function to check if a command exists (including system directories) # Check each core command (command_exists comes from common library)
command_exists() { local cmd
local cmd="$1"
# First try command -v (respects PATH)
if command -v "$cmd" >/dev/null 2>&1; then
return 0
fi
# Check common system directories (for commands that might be in sbin)
local system_dirs=("/usr/sbin" "/sbin" "/usr/local/sbin" "/usr/bin" "/bin" "/usr/local/bin")
for dir in "${system_dirs[@]}"; do
if [ -x "$dir/$cmd" ]; then
return 0
fi
done
return 1
}
# Check each core command
for cmd in "${core_commands[@]}"; do for cmd in "${core_commands[@]}"; do
if ! command_exists "$cmd"; then if ! command_exists "$cmd"; then
missing_commands+=("$cmd") missing_commands+=("$cmd")
@ -246,7 +170,6 @@ validate_required_commands() {
done done
# Check for port checking utility (ss or netstat) # Check for port checking utility (ss or netstat)
# On macOS, netstat is available, ss is not
if [ "$os_name" != "darwin" ]; then if [ "$os_name" != "darwin" ]; then
if ! command_exists ss && ! command_exists netstat; then if ! command_exists ss && ! command_exists netstat; then
missing_commands+=("ss or netstat") missing_commands+=("ss or netstat")
@ -254,7 +177,6 @@ validate_required_commands() {
fi fi
# Detect init system and validate its control command # Detect init system and validate its control command
# Skip on macOS as it's not a deployment target
if [ "$os_name" != "darwin" ]; then if [ "$os_name" != "darwin" ]; then
local init_system local init_system
init_system=$(detect_init_system) init_system=$(detect_init_system)
@ -288,7 +210,6 @@ validate_required_commands() {
log_message "INFO" "Skipping init system validation on macOS (not a deployment target)" log_message "INFO" "Skipping init system validation on macOS (not a deployment target)"
fi fi
# Report any missing commands
if [ ${#missing_commands[@]} -gt 0 ]; then if [ ${#missing_commands[@]} -gt 0 ]; then
local missing_list local missing_list
missing_list=$(IFS=', '; echo "${missing_commands[*]}") missing_list=$(IFS=', '; echo "${missing_commands[*]}")
@ -298,7 +219,6 @@ validate_required_commands() {
fi fi
# Special check: iptables version must be 1.4 or higher for Docker static binaries # Special check: iptables version must be 1.4 or higher for Docker static binaries
# Skip on macOS as it's not a deployment target
if [ "$os_name" != "darwin" ]; then if [ "$os_name" != "darwin" ]; then
log_message "INFO" "Checking iptables version (requires 1.4+ for Docker)..." log_message "INFO" "Checking iptables version (requires 1.4+ for Docker)..."
if command_exists iptables; then if command_exists iptables; then
@ -306,7 +226,6 @@ validate_required_commands() {
iptables_version=$(iptables --version 2>/dev/null | head -1 | grep -o '[0-9]\+\.[0-9]\+' | head -1) iptables_version=$(iptables --version 2>/dev/null | head -1 | grep -o '[0-9]\+\.[0-9]\+' | head -1)
if [ -n "$iptables_version" ]; then if [ -n "$iptables_version" ]; then
log_message "INFO" "Found iptables version $iptables_version" log_message "INFO" "Found iptables version $iptables_version"
# Compare version numbers (basic check for 1.4 or higher)
local major_version minor_version local major_version minor_version
major_version=$(echo "$iptables_version" | cut -d. -f1) major_version=$(echo "$iptables_version" | cut -d. -f1)
minor_version=$(echo "$iptables_version" | cut -d. -f2) minor_version=$(echo "$iptables_version" | cut -d. -f2)
@ -320,7 +239,6 @@ validate_required_commands() {
log_message "WARNING" "Could not determine iptables version, continuing anyway" log_message "WARNING" "Could not determine iptables version, continuing anyway"
fi fi
else else
# Should not happen since iptables is in required commands, but just in case
add_error "iptables command not found (required for Docker network bridge)" add_error "iptables command not found (required for Docker network bridge)"
return 1 return 1
fi fi
@ -332,205 +250,13 @@ validate_required_commands() {
return 0 return 0
} }
detect_os_and_version() { # ==============================================================================
log_message "INFO" "Detecting OS and version..." # NETWORK CONNECTIVITY & ARTIFACT SOURCE TESTING
# ==============================================================================
local os_name=""
local os_version=""
# Check for /etc/os-release first (modern systems)
if [ -f /etc/os-release ]; then
. /etc/os-release
os_name="$ID"
os_version="$VERSION_ID"
# Check for older RedHat/CentOS
elif [ -f /etc/redhat-release ]; then
os_name="rhel"
os_version=$(sed -e 's/.*release \([0-9]\+\)\..*/\1/' /etc/redhat-release)
# Check for Alpine
elif [ -f /etc/alpine-release ]; then
os_name="alpine"
os_version=$(cat /etc/alpine-release)
else
os_name=$(uname -s | tr '[:upper:]' '[:lower:]')
os_version=$(uname -r)
fi
# Remove any carriage returns or newlines from variables
os_name="${os_name//[$'\t\r\n']/}"
os_version="${os_version//[$'\t\r\n']/}"
# Normalize OS names
case "$os_name" in
"ubuntu"|"debian"|"centos"|"rhel"|"alpine"|"amzn"|"ol"|"rocky"|"almalinux")
# Valid supported OS
log_message "SUCCESS" "OS detected: $os_name $os_version (supported)"
;;
*)
log_message "WARNING" "OS '$os_name' not explicitly tested but may work"
;;
esac
echo "$os_name:$os_version"
}
detect_architecture() {
log_message "INFO" "Detecting system architecture..."
local arch
arch=$(uname -m)
local docker_arch=""
case "$arch" in
x86_64|x64|amd64)
docker_arch="x86_64"
log_message "SUCCESS" "Architecture: x86_64 (Intel/AMD 64-bit)"
;;
aarch64|arm64)
docker_arch="aarch64"
log_message "SUCCESS" "Architecture: aarch64 (ARM 64-bit)"
;;
armv7l|armhf)
docker_arch="armhf"
log_message "SUCCESS" "Architecture: armhf (ARM 32-bit)"
;;
*)
log_message "ERROR" "Unsupported architecture: $arch"
docker_arch="unknown"
;;
esac
echo "$docker_arch"
}
# Critical fix from review: Init system detection
detect_init_system() {
log_message "INFO" "Detecting init system..."
local init_system="unknown"
# Detect macOS/Darwin first
if [ "$(uname -s)" = "Darwin" ]; then
init_system="darwin"
log_message "SUCCESS" "Init system: darwin (macOS)"
elif command -v systemctl >/dev/null 2>&1 && systemctl --version >/dev/null 2>&1; then
init_system="systemd"
log_message "SUCCESS" "Init system: systemd"
elif [ -d /etc/init.d ] && [ -x /sbin/initctl ] || [ -x /sbin/init ]; then
init_system="sysvinit"
log_message "SUCCESS" "Init system: sysvinit"
elif [ -d /etc/rc.d ] && [ -x /sbin/rc-service ]; then
init_system="openrc"
log_message "SUCCESS" "Init system: openrc (Alpine)"
elif [ -x /sbin/upstart ]; then
init_system="upstart"
log_message "SUCCESS" "Init system: upstart"
else
log_message "WARNING" "Could not determine init system"
init_system="unknown"
fi
echo "$init_system"
}
# Critical fix from review: Proper IP validation
validate_ip_address() {
local ip="$1"
# Check basic format
if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
return 1
fi
# Check each octet is 0-255
IFS='.' read -r i1 i2 i3 i4 <<< "$ip"
if [ "$i1" -gt 255 ] || [ "$i2" -gt 255 ] || [ "$i3" -gt 255 ] || [ "$i4" -gt 255 ]; then
return 1
fi
return 0
}
# Critical fix from review: Port conflict detection with fallback
check_port_available() {
local port="$1"
local protocol="${2:-tcp}"
log_message "DEBUG" "Checking port $port/$protocol availability..."
# Try ss first (modern, usually available)
if command -v ss >/dev/null 2>&1; then
if ss -"${protocol:0:1}"ln | grep -q ":$port "; then
return 1 # Port in use
fi
# Fallback to netstat
elif command -v netstat >/dev/null 2>&1; then
if netstat -tulpn 2>/dev/null | grep -E ":$port\s" >/dev/null 2>&1; then
return 1 # Port in use
fi
else
log_message "WARNING" "Neither ss nor netstat available, cannot check port $port"
fi
return 0 # Port available (or cannot check)
}
# Network connectivity testing
test_connectivity() {
local host="$1"
local description="$2"
local timeout="${3:-10}"
# Extract hostname for safe logging (without credentials)
local display_host
display_host=$(extract_hostname_from_url "$host")
log_message "INFO" "Testing connectivity to $description ($display_host)..."
local url="$host"
if [[ ! "$host" =~ ^https?:// ]]; then
url="https://$host"
fi
# Use -sL (GET + follow redirects) instead of -sI (HEAD only)
# HEAD requests may not work reliably on all Forgejo/Gitea raw endpoints.
# GET with -L follows redirects, and output goes to /dev/null.
if curl -sL $CURL_INSECURE_FLAG --connect-timeout "$timeout" "$url" >/dev/null 2>&1; then
log_message "SUCCESS" "$description is reachable"
return 0
else
log_message "ERROR" "$description is NOT reachable"
return 1
fi
}
test_cloud_endpoints() {
local cloud_name="$1"
shift
local endpoints=("$@")
log_message "INFO" "Testing $cloud_name cloud endpoints..."
local all_reachable=true
for endpoint in "${endpoints[@]}"; do
if ! test_connectivity "$endpoint" "$cloud_name endpoint $endpoint"; then
all_reachable=false
fi
done
if [ "$all_reachable" = true ]; then
log_message "SUCCESS" "All $cloud_name cloud endpoints reachable"
echo "true"
else
log_message "WARNING" "Some $cloud_name cloud endpoints unreachable"
echo "false"
fi
}
perform_network_tests() { perform_network_tests() {
log_message "INFO" "=== NETWORK CONNECTIVITY TESTING ===" log_message "INFO" "=== NETWORK CONNECTIVITY TESTING ==="
# Test US cloud endpoints # Test US cloud endpoints
local us_reachable local us_reachable
us_reachable=$(test_cloud_endpoints "US" "${US_DATA_NODES[@]}") us_reachable=$(test_cloud_endpoints "US" "${US_DATA_NODES[@]}")
@ -549,27 +275,27 @@ perform_network_tests() {
local has_local_docker=false local has_local_docker=false
local docker_sources=() local docker_sources=()
# Check local binaries directory
if [ -d "$LOCAL_BINARY_DIR" ]; then if [ -d "$LOCAL_BINARY_DIR" ]; then
log_message "INFO" "Checking local binaries directory: $LOCAL_BINARY_DIR" log_message "INFO" "Checking local binaries directory: $LOCAL_BINARY_DIR"
local binary_files=$(ls "$LOCAL_BINARY_DIR"/*.tgz 2>/dev/null | head -5) local binary_files
binary_files=$(ls "$LOCAL_BINARY_DIR"/*.tgz 2>/dev/null | head -5)
if [ -n "$binary_files" ]; then if [ -n "$binary_files" ]; then
log_message "SUCCESS" "Found local Docker binaries in $LOCAL_BINARY_DIR:" log_message "SUCCESS" "Found local Docker binaries in $LOCAL_BINARY_DIR:"
for file in $binary_files; do while IFS= read -r file; do
log_message "SUCCESS" " - $(basename "$file")" log_message "SUCCESS" " - $(basename "$file")"
done done <<< "$binary_files"
has_local_docker=true has_local_docker=true
docker_sources+=("$LOCAL_BINARY_DIR/") docker_sources+=("$LOCAL_BINARY_DIR/")
fi fi
fi fi
# Check current directory local current_docker_files
local current_docker_files=$(ls docker-*.tgz 2>/dev/null | head -5) current_docker_files=$(ls docker-*.tgz 2>/dev/null | head -5)
if [ -n "$current_docker_files" ]; then if [ -n "$current_docker_files" ]; then
log_message "SUCCESS" "Found local Docker binaries in current directory:" log_message "SUCCESS" "Found local Docker binaries in current directory:"
for file in $current_docker_files; do while IFS= read -r file; do
log_message "SUCCESS" " - $file" log_message "SUCCESS" " - $file"
done done <<< "$current_docker_files"
has_local_docker=true has_local_docker=true
docker_sources+=("current directory") docker_sources+=("current directory")
fi fi
@ -584,27 +310,27 @@ perform_network_tests() {
local has_local_wallarm=false local has_local_wallarm=false
local wallarm_sources=() local wallarm_sources=()
# Check local images directory (prefers .tar.gz format)
if [ -d "$LOCAL_IMAGE_DIR" ]; then if [ -d "$LOCAL_IMAGE_DIR" ]; then
log_message "INFO" "Checking local images directory: $LOCAL_IMAGE_DIR" log_message "INFO" "Checking local images directory: $LOCAL_IMAGE_DIR"
local image_files=$(ls "$LOCAL_IMAGE_DIR"/*.tar.gz "$LOCAL_IMAGE_DIR"/*.tar 2>/dev/null | head -5) local image_files
image_files=$(ls "$LOCAL_IMAGE_DIR"/*.tar.gz "$LOCAL_IMAGE_DIR"/*.tar 2>/dev/null | head -5)
if [ -n "$image_files" ]; then if [ -n "$image_files" ]; then
log_message "SUCCESS" "Found local Wallarm images in $LOCAL_IMAGE_DIR:" log_message "SUCCESS" "Found local Wallarm images in $LOCAL_IMAGE_DIR:"
for file in $image_files; do while IFS= read -r file; do
log_message "SUCCESS" " - $(basename "$file")" log_message "SUCCESS" " - $(basename "$file")"
done done <<< "$image_files"
has_local_wallarm=true has_local_wallarm=true
wallarm_sources+=("$LOCAL_IMAGE_DIR/") wallarm_sources+=("$LOCAL_IMAGE_DIR/")
fi fi
fi fi
# Check current directory (.tar.gz and .tar formats) local current_image_files
local current_image_files=$(ls wallarm-node-*.tar.gz wallarm-node-*.tar 2>/dev/null | head -5) current_image_files=$(ls wallarm-node-*.tar.gz wallarm-node-*.tar 2>/dev/null | head -5)
if [ -n "$current_image_files" ]; then if [ -n "$current_image_files" ]; then
log_message "SUCCESS" "Found local Wallarm images in current directory:" log_message "SUCCESS" "Found local Wallarm images in current directory:"
for file in $current_image_files; do while IFS= read -r file; do
log_message "SUCCESS" " - $file" log_message "SUCCESS" " - $file"
done done <<< "$current_image_files"
has_local_wallarm=true has_local_wallarm=true
wallarm_sources+=("current directory") wallarm_sources+=("current directory")
fi fi
@ -626,13 +352,12 @@ main() {
clear clear
echo -e "${BLUE}${BOLD}" echo -e "${BLUE}${BOLD}"
echo "╔══════════════════════════════════════════════════════════════╗" echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ WALLARM PREFLIGHT CHECK SCRIPT - V1.2 ║" echo "║ WALLARM PREFLIGHT CHECK SCRIPT (Docker) - V1.3 ║"
echo "║ System Readiness Validation for Deployment ║" echo "║ System Readiness Validation for Deployment ║"
echo "╚══════════════════════════════════════════════════════════════╝${NC}" echo "╚══════════════════════════════════════════════════════════════╝${NC}"
echo -e "\n${YELLOW}Starting preflight check at: $(date)${NC}" echo -e "\n${YELLOW}Starting preflight check at: $(date)${NC}"
# Initialize logging # Initialize logging
# Create logs directory if it doesn't exist
local log_dir="${HOME:-.}/logs" local log_dir="${HOME:-.}/logs"
if [ ! -d "$log_dir" ]; then if [ ! -d "$log_dir" ]; then
if ! mkdir -p "$log_dir"; then if ! mkdir -p "$log_dir"; then
@ -654,7 +379,6 @@ main() {
log_message "INFO" "=== Wallarm Preflight Check Started ===" log_message "INFO" "=== Wallarm Preflight Check Started ==="
# SSL security warning
if [ "$INSECURE_SSL" = "1" ]; then if [ "$INSECURE_SSL" = "1" ]; then
log_message "WARNING" "SSL certificate validation is DISABLED (insecure). Set WALLARM_INSECURE_SSL=0 to enable validation." log_message "WARNING" "SSL certificate validation is DISABLED (insecure). Set WALLARM_INSECURE_SSL=0 to enable validation."
fi fi
@ -694,7 +418,6 @@ main() {
# Phase 2: Network connectivity testing # Phase 2: Network connectivity testing
log_message "INFO" "=== PHASE 2: NETWORK CONNECTIVITY TESTING ===" log_message "INFO" "=== PHASE 2: NETWORK CONNECTIVITY TESTING ==="
# Test Git Repositorys connectivity (primary artifact source)
log_message "INFO" "Testing connectivity to Git Repositorys artifact repository..." log_message "INFO" "Testing connectivity to Git Repositorys artifact repository..."
GIT_REACHABLE="false" GIT_REACHABLE="false"
if test_connectivity "$GIT_DOCKER_BINARY_URL" "Git Repositorys Docker artifact"; then if test_connectivity "$GIT_DOCKER_BINARY_URL" "Git Repositorys Docker artifact"; then
@ -718,17 +441,14 @@ main() {
# Critical check: Need at least one source for Docker and Wallarm # Critical check: Need at least one source for Docker and Wallarm
# Priority: Git Repositorys (primary) -> local files # Priority: Git Repositorys (primary) -> local files
# If Git Repositorys is reachable, we have our primary source
if [ "$GIT_REACHABLE" = "true" ]; then if [ "$GIT_REACHABLE" = "true" ]; then
log_message "SUCCESS" "Git Repositorys artifact repository is reachable (primary source available)" log_message "SUCCESS" "Git Repositorys artifact repository is reachable (primary source available)"
else else
log_message "WARNING" "Git Repositorys artifact repository is not reachable - checking fallback sources" log_message "WARNING" "Git Repositorys artifact repository is not reachable - checking fallback sources"
# Check for local files in multiple locations
local has_local_docker=false local has_local_docker=false
local has_local_wallarm=false local has_local_wallarm=false
# Check Docker binary locations
if [ -d "$LOCAL_BINARY_DIR" ] && [ -n "$(ls "$LOCAL_BINARY_DIR"/*.tgz 2>/dev/null)" ]; then if [ -d "$LOCAL_BINARY_DIR" ] && [ -n "$(ls "$LOCAL_BINARY_DIR"/*.tgz 2>/dev/null)" ]; then
has_local_docker=true has_local_docker=true
log_message "INFO" "Found local Docker binaries in $LOCAL_BINARY_DIR/" log_message "INFO" "Found local Docker binaries in $LOCAL_BINARY_DIR/"
@ -737,7 +457,6 @@ main() {
log_message "INFO" "Found local Docker binaries in current directory" log_message "INFO" "Found local Docker binaries in current directory"
fi fi
# Check Wallarm image locations (support both .tar.gz and .tar)
if [ -d "$LOCAL_IMAGE_DIR" ] && [ -n "$(ls "$LOCAL_IMAGE_DIR"/*.tar.gz "$LOCAL_IMAGE_DIR"/*.tar 2>/dev/null)" ]; then if [ -d "$LOCAL_IMAGE_DIR" ] && [ -n "$(ls "$LOCAL_IMAGE_DIR"/*.tar.gz "$LOCAL_IMAGE_DIR"/*.tar 2>/dev/null)" ]; then
has_local_wallarm=true has_local_wallarm=true
log_message "INFO" "Found local Wallarm images in $LOCAL_IMAGE_DIR/" log_message "INFO" "Found local Wallarm images in $LOCAL_IMAGE_DIR/"
@ -746,7 +465,6 @@ main() {
log_message "INFO" "Found local Wallarm images in current directory" log_message "INFO" "Found local Wallarm images in current directory"
fi fi
# Determine if we have sufficient resources
local has_sufficient_resources=true local has_sufficient_resources=true
if [ "$has_local_docker" = "false" ]; then if [ "$has_local_docker" = "false" ]; then
@ -796,10 +514,10 @@ Possible sources:
echo -e "\n${GREEN}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}" echo -e "\n${GREEN}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}${BOLD}║ PREFLIGHT CHECK PASSED - SYSTEM READY ║${NC}" echo -e "${GREEN}${BOLD}║ PREFLIGHT CHECK PASSED - SYSTEM READY ║${NC}"
echo -e "${GREEN}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}" echo -e "${GREEN}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}"
echo -e "\n${CYAN}System is ready for Wallarm deployment.${NC}" echo -e "\n${CYAN}System is ready for Wallarm Docker deployment.${NC}"
echo -e "${YELLOW}Check results: $ENV_FILE${NC}" echo -e "${YELLOW}Check results: $ENV_FILE${NC}"
echo -e "${YELLOW}Full log: $LOG_FILE${NC}" echo -e "${YELLOW}Full log: $LOG_FILE${NC}"
echo -e "\n${GREEN}Next step: Run ./wallarm-ct-deploy.sh to proceed with deployment${NC}" echo -e "\n${GREEN}Next step: Run ./docker/wallarm-ct-deploy.sh to proceed with deployment${NC}"
exit 0 exit 0
else else
log_message "ERROR" "=== PREFLIGHT CHECK FAILED ===" log_message "ERROR" "=== PREFLIGHT CHECK FAILED ==="

View file

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
# ============================================================================== # ==============================================================================
# WALLARM DEPLOYMENT SCRIPT - V1.2 # WALLARM DEPLOYMENT SCRIPT - V1.3 (Docker deployment)
# ============================================================================== # ==============================================================================
# Purpose: Deploy Wallarm filtering node after preflight check # Purpose: Deploy Wallarm filtering node (Docker container) after preflight check
# Features: # Features:
# - Reads preflight check results from .env file # - Reads preflight check results from .env file
# - Interactive configuration (cloud region, ports, token, upstream) # - Interactive configuration (cloud region, ports, token, upstream)
@ -12,61 +12,28 @@
# - DAU-friendly error handling with remediation # - DAU-friendly error handling with remediation
# ============================================================================== # ==============================================================================
# Color definitions for better UX # Script location and shared library (colors, logging, validation, detection, connectivity)
RED='\033[0;31m' SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
GREEN='\033[0;32m' # shellcheck source=../common/wallarm-lib.sh
YELLOW='\033[1;33m' source "$SCRIPT_DIR/../common/wallarm-lib.sh"
BLUE='\033[1;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
BOLD='\033[1m'
NC='\033[0m' # No Color
# Strict error handling # Strict error handling
set -euo pipefail set -euo pipefail
# Simple error handler for early failures (before log_message is defined)
early_error_handler() {
echo -e "${RED}${BOLD}[ERROR]${NC} Script failed at line $LINENO. Command: $BASH_COMMAND" >&2
exit 1
}
trap early_error_handler ERR trap early_error_handler ERR
# Extract hostname from URL (strip protocol and credentials for safe logging)
extract_hostname_from_url() {
local url="$1"
# Remove protocol
local hostpart="${url#*://}"
# Remove credentials if present (username:password@)
hostpart="${hostpart#*@}"
# Remove port and path
hostpart="${hostpart%%[:/]*}"
echo "$hostpart"
}
# Configuration # Configuration
ENV_FILE=".env" ENV_FILE=".env"
LOG_FILE="${HOME:-.}/logs/wallarm-deployment.log" LOG_FILE="${HOME:-.}/logs/wallarm-deployment.log"
# SSL security settings # Git Repositorys artifact URLs (primary source) - Docker deployment artifacts
# WALLARM_INSECURE_SSL=1 to disable SSL certificate validation (insecure, for self-signed certs)
INSECURE_SSL="${WALLARM_INSECURE_SSL:-1}" # Default to insecure for backward compatibility
if [ "$INSECURE_SSL" = "1" ]; then
CURL_INSECURE_FLAG="-k"
# Warning will be logged later when log_message is available
else
CURL_INSECURE_FLAG=""
fi
# Git Repositorys artifact URLs (primary source)
GIT_BASE_URL="https://git.sechpoint.app/customer-engineering/wallarm" GIT_BASE_URL="https://git.sechpoint.app/customer-engineering/wallarm"
GIT_RAW_URL="https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main" GIT_RAW_URL="https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main"
GIT_DOCKER_BINARY_URL="${GIT_RAW_URL}/binaries/docker-29.2.1.tgz" GIT_DOCKER_BINARY_URL="${GIT_RAW_URL}/docker/binaries/docker-29.2.1.tgz"
GIT_DOCKER_CHECKSUM_URL="${GIT_RAW_URL}/binaries/docker-29.2.1.tgz.sha256" GIT_DOCKER_CHECKSUM_URL="${GIT_RAW_URL}/docker/binaries/docker-29.2.1.tgz.sha256"
GIT_WALLARM_IMAGE_URL="${GIT_RAW_URL}/images/wallarm-node-6.11.0-rc1.tar.gz" GIT_WALLARM_IMAGE_URL="${GIT_RAW_URL}/docker/images/wallarm-node-6.11.0-rc1.tar.gz"
GIT_WALLARM_CHECKSUM_URL="${GIT_RAW_URL}/images/wallarm-node-6.11.0-rc1.tar.gz.sha256" GIT_WALLARM_CHECKSUM_URL="${GIT_RAW_URL}/docker/images/wallarm-node-6.11.0-rc1.tar.gz.sha256"
# Local artifact directories (relative to script location) # Local artifact directories (relative to script location)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOCAL_BINARY_DIR="${SCRIPT_DIR}/binaries" LOCAL_BINARY_DIR="${SCRIPT_DIR}/binaries"
LOCAL_IMAGE_DIR="${SCRIPT_DIR}/images" LOCAL_IMAGE_DIR="${SCRIPT_DIR}/images"
@ -93,134 +60,6 @@ REGISTRY_REACHABLE="false"
DOWNLOAD_REACHABLE="false" DOWNLOAD_REACHABLE="false"
GIT_REACHABLE="false" GIT_REACHABLE="false"
# ==============================================================================
# LOGGING & ERROR HANDLING FUNCTIONS
# ==============================================================================
log_message() {
local level="$1"
local message="$2"
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
case "$level" in
"INFO") color="${BLUE}" ;;
"SUCCESS") color="${GREEN}" ;;
"WARNING") color="${YELLOW}" ;;
"ERROR") color="${RED}" ;;
"DEBUG") color="${CYAN}" ;;
*) color="${NC}" ;;
esac
echo -e "${color}[${timestamp}] ${level}: ${message}${NC}" >&2
echo "[${timestamp}] ${level}: ${message}" >> "$LOG_FILE"
}
fail_with_remediation() {
local error_msg="$1"
local remediation="$2"
log_message "ERROR" "$error_msg"
echo -e "\n${RED}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${RED}${BOLD}║ DEPLOYMENT FAILED ║${NC}"
echo -e "${RED}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}"
echo -e "\n${YELLOW}${BOLD}Root Cause:${NC} $error_msg"
echo -e "\n${YELLOW}${BOLD}How to Fix:${NC}"
echo -e "$remediation"
echo -e "\n${YELLOW}Check the full log for details:${NC} $LOG_FILE"
exit 1
}
# ==============================================================================
# GIT ARTIFACT FUNCTIONS
# ==============================================================================
download_from_git() {
local url="$1"
local output_path="$2"
local description="$3"
log_message "INFO" "Attempting to download $description from Git Repositorys..."
log_message "DEBUG" "URL: $url"
log_message "DEBUG" "Output path: $output_path"
# Use curl with follow redirects, fail on HTTP error, timeout settings
if curl -fL "$CURL_INSECURE_FLAG" --connect-timeout 30 --max-time 300 --progress-bar "$url" -o "$output_path"; then
log_message "SUCCESS" "Downloaded $description to $output_path"
return 0
else
local curl_exit=$?
log_message "ERROR" "Failed to download $description from Git Repositorys (curl exit: $curl_exit)"
# Clean up partial download if it exists
if [ -f "$output_path" ]; then
rm -f "$output_path"
log_message "DEBUG" "Removed partial download: $output_path"
fi
return 1
fi
}
verify_checksum() {
local file_path="$1"
local checksum_file_or_url="$2"
local description="$3"
log_message "INFO" "Verifying $description checksum..."
local checksum_file=""
# If checksum is a URL, download it first
if [[ "$checksum_file_or_url" =~ ^https?:// ]]; then
checksum_file="/tmp/$(basename "$checksum_file_or_url")"
log_message "DEBUG" "Downloading checksum from URL: $checksum_file_or_url"
if ! curl -fL "$CURL_INSECURE_FLAG" --connect-timeout 10 --max-time 30 -s "$checksum_file_or_url" -o "$checksum_file"; then
log_message "WARNING" "Could not download checksum file, skipping verification"
return 0 # Skip verification if checksum can't be downloaded
fi
else
checksum_file="$checksum_file_or_url"
fi
# Verify checksum file exists
if [ ! -f "$checksum_file" ]; then
log_message "WARNING" "Checksum file not found: $checksum_file, skipping verification"
return 0
fi
# Get expected checksum (first field from checksum file)
local expected_checksum
expected_checksum=$(awk '{print $1}' "$checksum_file" 2>/dev/null)
if [ -z "$expected_checksum" ]; then
log_message "WARNING" "Could not read checksum from $checksum_file, skipping verification"
return 0
fi
# Compute actual checksum
log_message "DEBUG" "Computing SHA256 checksum of $file_path..."
local actual_checksum
if command -v sha256sum >/dev/null 2>&1; then
actual_checksum=$(sha256sum "$file_path" | awk '{print $1}')
elif command -v shasum >/dev/null 2>&1; then
actual_checksum=$(shasum -a 256 "$file_path" | awk '{print $1}')
else
log_message "WARNING" "sha256sum or shasum not available, skipping checksum verification"
return 0
fi
# Compare checksums
if [ "$expected_checksum" = "$actual_checksum" ]; then
log_message "SUCCESS" "$description checksum verified successfully"
return 0
else
log_message "ERROR" "$description checksum verification FAILED"
log_message "DEBUG" "Expected: $expected_checksum"
log_message "DEBUG" "Actual: $actual_checksum"
# Clean up corrupted file
rm -f "$file_path"
log_message "INFO" "Removed corrupted file: $file_path"
return 1
fi
}
# ============================================================================== # ==============================================================================
# PREFLIGHT CHECK VERIFICATION # PREFLIGHT CHECK VERIFICATION
# ============================================================================== # ==============================================================================
@ -236,53 +75,36 @@ verify_preflight_check() {
echo echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then if [[ ! $REPLY =~ ^[Nn]$ ]]; then
echo -e "${CYAN}Running preflight check...${NC}" echo -e "${CYAN}Running preflight check...${NC}"
if ! ./wallarm-ct-check.sh; then if ! "$SCRIPT_DIR/wallarm-ct-check.sh"; then
fail_with_remediation "Preflight check failed" \ fail_with_remediation "Preflight check failed" \
"Run the preflight check manually and fix any issues: "Run the preflight check manually and fix any issues:
1. ./wallarm-ct-check.sh 1. $SCRIPT_DIR/wallarm-ct-check.sh
2. Review the errors in $ENV_FILE 2. Review the errors in $ENV_FILE
3. Fix the issues and run this script again" 3. Fix the issues and run this script again"
fi fi
else else
fail_with_remediation "Preflight check required" \ fail_with_remediation "Preflight check required" \
"Run the preflight check before deployment: "Run the preflight check before deployment:
1. ./wallarm-ct-check.sh 1. $SCRIPT_DIR/wallarm-ct-check.sh
2. Review results in $ENV_FILE 2. Review results in $ENV_FILE
3. Run this script again" 3. Run this script again"
fi fi
fi fi
# Load environment variables from .env file # Load environment variables from .env file (from shared library)
# Use a safer approach than sourcing (avoid code injection) if ! load_env_file "$ENV_FILE"; then
while IFS='=' read -r key value; do fail_with_remediation "Cannot load preflight results" \
# Remove comments and empty lines "The preflight check results file could not be read.
[[ "$key" =~ ^#.*$ ]] && continue 1. Run the preflight check: $SCRIPT_DIR/wallarm-ct-check.sh
[[ -z "$key" ]] && continue 2. Verify $ENV_FILE exists and is readable
3. Run this script again"
# Remove quotes from value fi
value="${value%\"}"
value="${value#\"}"
# Export variable
case "$key" in
result) CHECK_RESULT="$value" ;;
os_name) OS_NAME="$value" ;;
os_version) OS_VERSION="$value" ;;
architecture) ARCHITECTURE="$value" ;;
init_system) INIT_SYSTEM="$value" ;;
us_cloud_reachable) US_CLOUD_REACHABLE="$value" ;;
eu_cloud_reachable) EU_CLOUD_REACHABLE="$value" ;;
registry_reachable) REGISTRY_REACHABLE="$value" ;;
download_reachable) DOWNLOAD_REACHABLE="$value" ;;
git_reachable) GIT_REACHABLE="$value" ;;
esac
done < "$ENV_FILE"
if [ "$CHECK_RESULT" != "pass" ]; then if [ "$CHECK_RESULT" != "pass" ]; then
log_message "ERROR" "Preflight check failed (result: $CHECK_RESULT)" log_message "ERROR" "Preflight check failed (result: $CHECK_RESULT)"
echo -e "\n${YELLOW}Preflight check found issues. Please review:${NC}" echo -e "\n${YELLOW}Preflight check found issues. Please review:${NC}"
echo -e "${YELLOW}1. Check file: $ENV_FILE${NC}" echo -e "${YELLOW}1. Check file: $ENV_FILE${NC}"
echo -e "${YELLOW}2. Run: ./wallarm-ct-check.sh${NC}" echo -e "${YELLOW}2. Run: $SCRIPT_DIR/wallarm-ct-check.sh${NC}"
echo -e "${YELLOW}3. Fix the issues and try again${NC}" echo -e "${YELLOW}3. Fix the issues and try again${NC}"
exit 1 exit 1
fi fi
@ -324,7 +146,7 @@ verify_preflight_check() {
"Network connectivity issues detected: "Network connectivity issues detected:
1. Check firewall rules for Wallarm cloud endpoints 1. Check firewall rules for Wallarm cloud endpoints
2. Verify network connectivity 2. Verify network connectivity
3. Run preflight check again: ./wallarm-ct-check.sh" 3. Run preflight check again: $SCRIPT_DIR/wallarm-ct-check.sh"
fi fi
# Validate we have resources for Docker/Wallarm # Validate we have resources for Docker/Wallarm
@ -365,126 +187,8 @@ verify_preflight_check() {
# ============================================================================== # ==============================================================================
# CONFIGURATION COLLECTION FUNCTIONS # CONFIGURATION COLLECTION FUNCTIONS
# ============================================================================== # ==============================================================================
# select_cloud_region, validate_ip_address and check_port_available are provided
select_cloud_region() { # by the shared library (../common/wallarm-lib.sh).
log_message "INFO" "Selecting Wallarm Cloud region..."
echo -e "\n${CYAN}${BOLD}Wallarm Cloud Region Selection:${NC}"
# Show available regions based on preflight check
local available_options=()
if [ "$US_CLOUD_REACHABLE" = "true" ]; then
echo -e "1. ${YELLOW}US Cloud${NC} (us1.api.wallarm.com) - For US-based deployments"
available_options+=("1" "US")
fi
if [ "$EU_CLOUD_REACHABLE" = "true" ]; then
echo -e "2. ${YELLOW}EU Cloud${NC} (api.wallarm.com) - For EU-based deployments"
available_options+=("2" "EU")
fi
if [ ${#available_options[@]} -eq 0 ]; then
fail_with_remediation "No cloud regions available" \
"Preflight check showed no reachable cloud regions.
1. Check network connectivity to Wallarm endpoints
2. Run preflight check again: ./wallarm-ct-check.sh
3. Contact network administrator if behind firewall"
fi
# Build regex pattern for validation
local pattern
pattern="^($(IFS='|'; echo "${available_options[*]}"))$"
local cloud_choice=""
while [[ ! "$cloud_choice" =~ $pattern ]]; do
if [ ${#available_options[@]} -eq 2 ]; then
# Only one region available
if [ "$US_CLOUD_REACHABLE" = "true" ]; then
cloud_choice="US"
break
else
cloud_choice="EU"
break
fi
fi
read -r -p "$(echo -e "${YELLOW}Enter choice [1/US or 2/EU]: ${NC}")" cloud_choice
cloud_choice=$(echo "$cloud_choice" | tr '[:lower:]' '[:upper:]')
case "$cloud_choice" in
1|"US")
if [ "$US_CLOUD_REACHABLE" = "true" ]; then
CLOUD_REGION="US"
API_HOST="us1.api.wallarm.com"
log_message "INFO" "Selected US Cloud"
else
echo -e "${RED}US Cloud is not reachable (per preflight check)${NC}"
cloud_choice=""
fi
;;
2|"EU")
if [ "$EU_CLOUD_REACHABLE" = "true" ]; then
CLOUD_REGION="EU"
API_HOST="api.wallarm.com"
log_message "INFO" "Selected EU Cloud"
else
echo -e "${RED}EU Cloud is not reachable (per preflight check)${NC}"
cloud_choice=""
fi
;;
*)
if [ -n "$cloud_choice" ]; then
echo -e "${RED}Invalid choice. Select from available options above.${NC}"
fi
;;
esac
done
log_message "SUCCESS" "Cloud region selected: $CLOUD_REGION ($API_HOST)"
}
# Critical fix from review: Proper IP validation
validate_ip_address() {
local ip="$1"
# Check basic format
if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
return 1
fi
# Check each octet is 0-255
IFS='.' read -r i1 i2 i3 i4 <<< "$ip"
if [ "$i1" -gt 255 ] || [ "$i2" -gt 255 ] || [ "$i3" -gt 255 ] || [ "$i4" -gt 255 ]; then
return 1
fi
return 0
}
# Critical fix from review: Port conflict detection with fallback
check_port_available() {
local port="$1"
local protocol="${2:-tcp}"
log_message "DEBUG" "Checking port $port/$protocol availability..."
# Try ss first (modern, usually available)
if command -v ss >/dev/null 2>&1; then
if ss -"${protocol:0:1}"ln | grep -q ":$port "; then
return 1 # Port in use
fi
# Fallback to netstat
elif command -v netstat >/dev/null 2>&1; then
if netstat -tulpn 2>/dev/null | grep -E ":$port\s" >/dev/null 2>&1; then
return 1 # Port in use
fi
else
log_message "WARNING" "Neither ss nor netstat available, cannot check port $port"
fi
return 0 # Port available (or cannot check)
}
collect_configuration() { collect_configuration() {
log_message "INFO" "Collecting deployment configuration..." log_message "INFO" "Collecting deployment configuration..."
@ -1863,7 +1567,7 @@ main() {
clear clear
echo -e "${BLUE}${BOLD}" echo -e "${BLUE}${BOLD}"
echo "╔══════════════════════════════════════════════════════════════╗" echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ WALLARM DEPLOYMENT SCRIPT - V1.2 ║" echo "║ WALLARM DEPLOYMENT SCRIPT (Docker) - V1.3 ║"
echo "║ LXC-Optimized Filtering Node Deployment ║" echo "║ LXC-Optimized Filtering Node Deployment ║"
echo "╚══════════════════════════════════════════════════════════════╝${NC}" echo "╚══════════════════════════════════════════════════════════════╝${NC}"
echo -e "\n${YELLOW}Starting deployment at: $(date)${NC}" echo -e "\n${YELLOW}Starting deployment at: $(date)${NC}"

View file

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
# ============================================================================== # ==============================================================================
# WALLARM RECONFIGURATION SCRIPT - V1.0 # WALLARM RECONFIGURATION SCRIPT - V1.1 (Docker deployment)
# ============================================================================== # ==============================================================================
# Purpose: Modify nginx configuration of an existing Wallarm node # Purpose: Modify nginx configuration of an existing Wallarm Docker node
# Features: # Features:
# - Update set_real_ip_from (trusted proxy IPs/CIDRs) # - Update set_real_ip_from (trusted proxy IPs/CIDRs)
# - Change wallarm_mode (monitoring/block) # - Change wallarm_mode (monitoring/block)
@ -10,16 +10,13 @@
# - Interactive prompts with validation # - Interactive prompts with validation
# ============================================================================== # ==============================================================================
set -euo pipefail # Script location and shared library (colors, logging, validation)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=../common/wallarm-lib.sh
source "$SCRIPT_DIR/../common/wallarm-lib.sh"
# Color definitions set -euo pipefail
RED='\033[0;31m' trap early_error_handler ERR
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
# ============================================================================== # ==============================================================================
# CHECK FOR SUDO / ROOT PRIVILEGES # CHECK FOR SUDO / ROOT PRIVILEGES

View file

@ -1,8 +1,8 @@
#!/bin/bash #!/bin/bash
# ============================================================================== # ==============================================================================
# WALLARM UNINSTALL SCRIPT - V1.0 # WALLARM UNINSTALL SCRIPT - V1.1 (Docker deployment)
# ============================================================================== # ==============================================================================
# Purpose: Safely remove Wallarm filtering node and cleanup Docker installation # Purpose: Safely remove a Wallarm Docker node and cleanup Docker installation
# Features: # Features:
# - Interactive confirmation with safety checks # - Interactive confirmation with safety checks
# - Stops and removes Wallarm container and image # - Stops and removes Wallarm container and image
@ -12,43 +12,18 @@
# - DAU-friendly warnings and confirmations # - DAU-friendly warnings and confirmations
# ============================================================================== # ==============================================================================
# Color definitions for better UX # Script location and shared library (colors, logging, validation)
RED='\033[0;31m' SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
GREEN='\033[0;32m' # shellcheck source=../common/wallarm-lib.sh
YELLOW='\033[1;33m' source "$SCRIPT_DIR/../common/wallarm-lib.sh"
BLUE='\033[1;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
BOLD='\033[1m'
NC='\033[0m' # No Color
# Strict error handling # Strict error handling
set -euo pipefail set -euo pipefail
# Simple error handler for early failures (before log_message is defined)
early_error_handler() {
echo -e "${RED}${BOLD}[ERROR]${NC} Script failed at line $LINENO. Command: $BASH_COMMAND" >&2
exit 1
}
trap early_error_handler ERR trap early_error_handler ERR
# Logging function # ==============================================================================
log_message() { # FUNCTIONS
local level="$1" # ==============================================================================
local message="$2"
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
case "$level" in
"INFO") color="${BLUE}" ;;
"SUCCESS") color="${GREEN}" ;;
"WARNING") color="${YELLOW}" ;;
"ERROR") color="${RED}" ;;
"DEBUG") color="${CYAN}" ;;
*) color="${NC}" ;;
esac
echo -e "${color}[${timestamp}] ${level}: ${message}${NC}" >&2
}
# Ask for confirmation # Ask for confirmation
confirm() { confirm() {

364
native/wallarm-ct-check.sh Executable file
View file

@ -0,0 +1,364 @@
#!/bin/bash
# ==============================================================================
# WALLARM PREFLIGHT CHECK SCRIPT - V1.0 (Native deployment)
# ==============================================================================
# Purpose: Validate system readiness for native (no-Docker) Wallarm deployment
# Features:
# - Non-interactive system validation (sudo, OS, architecture, init system)
# - Network connectivity testing (US/EU cloud + Wallarm all-in-one installer)
# - Resource availability assessment
# - Outputs results to .env file for deployment script
# - DAU-friendly error messages with remediation
# ==============================================================================
# Script location and shared library (colors, logging, validation, detection, connectivity)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=../common/wallarm-lib.sh
source "$SCRIPT_DIR/../common/wallarm-lib.sh"
# Strict error handling
set -euo pipefail
trap early_error_handler ERR
# Configuration
ENV_FILE=".env"
LOG_FILE="${HOME:-.}/logs/wallarm-check-native.log"
# Native install artifacts (Wallarm all-in-one installer)
WALLARM_VERSION="${WALLARM_VERSION:-6.12.7}"
INSTALLER_BASE_URL="https://meganode.wallarm.com/${WALLARM_VERSION%.*}"
INSTALLER_NAME="wallarm-${WALLARM_VERSION}.x86_64-glibc.sh"
INSTALLER_URL="${INSTALLER_BASE_URL}/${INSTALLER_NAME}"
# Cloud endpoints (from Wallarm documentation)
EU_DATA_NODES=("api.wallarm.com" "node-data0.eu1.wallarm.com" "node-data1.eu1.wallarm.com")
US_DATA_NODES=("us1.api.wallarm.com" "node-data0.us1.wallarm.com" "node-data1.us1.wallarm.com")
# Global result tracking
CHECK_RESULT="pass"
CHECK_ERRORS=()
INSTALLER_REACHABLE="false"
# ==============================================================================
# RESULT TRACKING & ENV FILE
# ==============================================================================
add_error() {
local error_msg="$1"
CHECK_ERRORS+=("$error_msg")
CHECK_RESULT="fail"
log_message "ERROR" "$error_msg"
}
write_env_file() {
local os_name="$1"
local os_version="$2"
local architecture="$3"
local init_system="$4"
local us_cloud_reachable="$5"
local eu_cloud_reachable="$6"
local installer_reachable="${7:-false}"
cat > "$ENV_FILE" << EOF
# Wallarm Preflight Check Results (Native deployment)
# Generated: $(date '+%Y-%m-%d %H:%M:%S')
# Script: $0
result=$CHECK_RESULT
os_name=$os_name
os_version=$os_version
architecture=$architecture
init_system=$init_system
us_cloud_reachable=$us_cloud_reachable
eu_cloud_reachable=$eu_cloud_reachable
installer_reachable=$installer_reachable
EOF
if [ ${#CHECK_ERRORS[@]} -gt 0 ]; then
echo "# Errors:" >> "$ENV_FILE"
for i in "${!CHECK_ERRORS[@]}"; do
echo "error_$i=\"${CHECK_ERRORS[$i]}\"" >> "$ENV_FILE"
done
fi
log_message "SUCCESS" "Check results written to $ENV_FILE"
}
# ==============================================================================
# PRE-FLIGHT VALIDATION FUNCTIONS
# ==============================================================================
validate_sudo_access() {
log_message "INFO" "Validating sudo access..."
local os_name
os_name=$(uname -s | tr '[:upper:]' '[:lower:]')
if ! command -v sudo >/dev/null 2>&1; then
add_error "sudo command not found"
return 1
fi
if [ "$os_name" = "darwin" ]; then
log_message "WARNING" "macOS detected: sudo authentication test skipped (may prompt during deployment)"
log_message "INFO" "Note: macOS is not a supported deployment target. This check is for Linux servers."
return 0
fi
if ! sudo -v; then
add_error "sudo authentication failed"
return 1
fi
log_message "SUCCESS" "Sudo access validated"
return 0
}
validate_required_commands() {
log_message "INFO" "Validating required system commands..."
local missing_commands=()
local os_name
os_name=$(uname -s | tr '[:upper:]' '[:lower:]')
# Core commands required for native check and deployment scripts
local core_commands=(
"curl" # Required for downloading the all-in-one installer
"grep" # Used extensively
"cut" # Used for parsing output
"tr" # Used for text transformations
"sed" # Used for text processing
"head" # Used for limiting output
"tail" # Used for limiting output
"ls" # Used for file listing
"date" # Used for logging timestamps
"mkdir" # Used for creating directories
"chmod" # Used for permission changes
"tee" # Required for writing configuration files
"rm" # Required for cleanup operations
)
# Check each core command (command_exists comes from common library)
local cmd
for cmd in "${core_commands[@]}"; do
if ! command_exists "$cmd"; then
missing_commands+=("$cmd")
fi
done
# Check for port checking utility (ss or netstat)
if [ "$os_name" != "darwin" ]; then
if ! command_exists ss && ! command_exists netstat; then
missing_commands+=("ss or netstat")
fi
fi
# Detect init system and validate its control command
if [ "$os_name" != "darwin" ]; then
local init_system
init_system=$(detect_init_system)
case "$init_system" in
"systemd")
if ! command_exists systemctl; then
missing_commands+=("systemctl")
fi
;;
"openrc")
if ! command_exists rc-service; then
missing_commands+=("rc-service")
fi
;;
"sysvinit")
if ! command_exists service; then
missing_commands+=("service")
fi
;;
"upstart")
if ! command_exists initctl; then
missing_commands+=("initctl")
fi
;;
*)
log_message "WARNING" "Unknown init system '$init_system', cannot validate init command"
;;
esac
else
log_message "INFO" "Skipping init system validation on macOS (not a deployment target)"
fi
if [ ${#missing_commands[@]} -gt 0 ]; then
local missing_list
missing_list=$(IFS=', '; echo "${missing_commands[*]}")
add_error "Missing required commands: $missing_list"
log_message "ERROR" "Please install missing commands and run the check again."
return 1
fi
log_message "SUCCESS" "All required system commands are available"
return 0
}
# ==============================================================================
# NETWORK CONNECTIVITY TESTING
# ==============================================================================
perform_network_tests() {
log_message "INFO" "=== NETWORK CONNECTIVITY TESTING ==="
# Test US cloud endpoints
local us_reachable
us_reachable=$(test_cloud_endpoints "US" "${US_DATA_NODES[@]}")
# Test EU cloud endpoints
local eu_reachable
eu_reachable=$(test_cloud_endpoints "EU" "${EU_DATA_NODES[@]}")
# Test Wallarm all-in-one installer reachability (needed for native install)
log_message "INFO" "Testing Wallarm all-in-one installer availability..."
if test_connectivity "$INSTALLER_URL" "Wallarm all-in-one installer"; then
INSTALLER_REACHABLE="true"
log_message "SUCCESS" "Wallarm installer is reachable (version $WALLARM_VERSION)"
else
log_message "WARNING" "Wallarm installer is not reachable at $INSTALLER_URL"
log_message "INFO" "Check https://docs.wallarm.com/updating-migrating/node-artifact-versions/ for the latest version."
fi
echo "$us_reachable:$eu_reachable:$INSTALLER_REACHABLE"
}
# ==============================================================================
# MAIN FUNCTION
# ==============================================================================
main() {
clear
echo -e "${BLUE}${BOLD}"
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ WALLARM PREFLIGHT CHECK SCRIPT (Native) - V1.0 ║"
echo "║ System Readiness Validation for Deployment ║"
echo "╚══════════════════════════════════════════════════════════════╝${NC}"
echo -e "\n${YELLOW}Starting preflight check at: $(date)${NC}"
# Initialize logging
local log_dir="${HOME:-.}/logs"
if [ ! -d "$log_dir" ]; then
if ! mkdir -p "$log_dir"; then
echo -e "${YELLOW}Cannot create log directory $log_dir, falling back to current directory...${NC}"
log_dir="."
fi
fi
LOG_FILE="$log_dir/wallarm-check-native.log"
if ! : > "$LOG_FILE"; then
echo -e "${RED}Cannot create log file at $LOG_FILE${NC}"
echo -e "${YELLOW}Falling back to current directory...${NC}"
LOG_FILE="./wallarm-check-native.log"
: > "$LOG_FILE" 2>/dev/null || true
fi
if ! chmod 644 "$LOG_FILE" 2>/dev/null; then
echo -e "${YELLOW}Warning: Could not set permissions on log file${NC}"
fi
log_message "INFO" "=== Wallarm Preflight Check (Native) Started ==="
if [ "$INSECURE_SSL" = "1" ]; then
log_message "WARNING" "SSL certificate validation is DISABLED (insecure). Set WALLARM_INSECURE_SSL=0 to enable validation."
fi
# Phase 1: System validation
log_message "INFO" "=== PHASE 1: SYSTEM VALIDATION ==="
if ! validate_required_commands; then
add_error "Required system commands validation failed"
fi
if ! validate_sudo_access; then
add_error "Sudo access validation failed"
fi
local os_info
os_info=$(detect_os_and_version)
local os_name
os_name=$(echo "$os_info" | cut -d: -f1)
local os_version
os_version=$(echo "$os_info" | cut -d: -f2)
local architecture
architecture=$(detect_architecture)
if [ "$architecture" = "unknown" ]; then
add_error "Unsupported architecture detected"
fi
local init_system
init_system=$(detect_init_system)
log_message "SUCCESS" "System validation completed:"
log_message "SUCCESS" " OS: $os_name $os_version"
log_message "SUCCESS" " Architecture: $architecture"
log_message "SUCCESS" " Init System: $init_system"
# Phase 2: Network connectivity testing
log_message "INFO" "=== PHASE 2: NETWORK CONNECTIVITY TESTING ==="
local network_results
network_results=$(perform_network_tests)
local us_reachable
us_reachable=$(echo "$network_results" | cut -d: -f1)
local eu_reachable
eu_reachable=$(echo "$network_results" | cut -d: -f2)
local installer_reachable
installer_reachable=$(echo "$network_results" | cut -d: -f3)
log_message "SUCCESS" "Network testing completed:"
log_message "SUCCESS" " US Cloud Reachable: $us_reachable"
log_message "SUCCESS" " EU Cloud Reachable: $eu_reachable"
log_message "SUCCESS" " Wallarm Installer Reachable: $installer_reachable"
# Phase 3: Write results
log_message "INFO" "=== PHASE 3: WRITING RESULTS ==="
write_env_file "$os_name" "$os_version" "$architecture" "$init_system" \
"$us_reachable" "$eu_reachable" "$installer_reachable"
# Final summary
if [ "$CHECK_RESULT" = "pass" ]; then
log_message "SUCCESS" "=== PREFLIGHT CHECK PASSED ==="
echo -e "\n${GREEN}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}${BOLD}║ PREFLIGHT CHECK PASSED - SYSTEM READY ║${NC}"
echo -e "${GREEN}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}"
echo -e "\n${CYAN}System is ready for native Wallarm deployment.${NC}"
echo -e "${YELLOW}Check results: $ENV_FILE${NC}"
echo -e "${YELLOW}Full log: $LOG_FILE${NC}"
echo -e "\n${GREEN}Next step: Run ./native/wallarm-ct-deploy.sh to proceed with deployment${NC}"
exit 0
else
log_message "ERROR" "=== PREFLIGHT CHECK FAILED ==="
echo -e "\n${RED}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${RED}${BOLD}║ PREFLIGHT CHECK FAILED - SYSTEM NOT READY ║${NC}"
echo -e "${RED}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}"
echo -e "\n${YELLOW}${BOLD}Issues found:${NC}"
for error in "${CHECK_ERRORS[@]}"; do
echo -e " ${RED}${NC} $error"
done
echo -e "\n${YELLOW}Check results: $ENV_FILE${NC}"
echo -e "${YELLOW}Full log: $LOG_FILE${NC}"
echo -e "\n${CYAN}Please fix the issues above and run the check again.${NC}"
exit 1
fi
}
# ==============================================================================
# SCRIPT EXECUTION
# ==============================================================================
# Ensure we're in bash
if [ -z "$BASH_VERSION" ]; then
echo "Error: This script must be run with bash" >&2
exit 1
fi
# Run main function
main "$@"

673
native/wallarm-ct-deploy.sh Executable file
View file

@ -0,0 +1,673 @@
#!/bin/bash
# ==============================================================================
# WALLARM DEPLOYMENT SCRIPT - V1.0 (Native deployment)
# ==============================================================================
# Purpose: Deploy Wallarm filtering node natively (NO Docker) after preflight
# Features:
# - Reads preflight check results from .env file
# - Interactive configuration (cloud region, ports, token, upstream)
# - Downloads and runs the official Wallarm all-in-one installer (meganode.wallarm.com)
# - Configures NGINX server block (proxy, wallarm_mode, trusted proxies, health)
# - Deployment verification (health endpoint, wallarm-status, node registration)
# - DAU-friendly error handling with remediation
# ==============================================================================
# Script location and shared library (colors, logging, validation, detection, connectivity)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=../common/wallarm-lib.sh
source "$SCRIPT_DIR/../common/wallarm-lib.sh"
# Strict error handling
set -euo pipefail
trap early_error_handler ERR
# Configuration
ENV_FILE=".env"
LOG_FILE="${HOME:-.}/logs/wallarm-deployment-native.log"
# Wallarm all-in-one installer (current recommended native install method)
# Override WALLARM_VERSION to pin a different version.
WALLARM_VERSION="${WALLARM_VERSION:-6.12.7}"
INSTALLER_BASE_URL="https://meganode.wallarm.com/${WALLARM_VERSION%.*}"
# Optional node labels for the installer (e.g. 'group=prod')
WALLARM_LABELS="${WALLARM_LABELS:-}"
# Deployment variables (set during execution)
CLOUD_REGION=""
API_HOST=""
INGRESS_PORT=""
UPSTREAM_IP=""
UPSTREAM_PORT=""
WALLARM_TOKEN=""
INSTANCE_NAME=""
INSTANCE_DIR=""
NGINX_CONFIG=""
# Resource reachability from check script
US_CLOUD_REACHABLE="false"
EU_CLOUD_REACHABLE="false"
INSTALLER_REACHABLE="false"
# ==============================================================================
# PREFLIGHT CHECK VERIFICATION
# ==============================================================================
verify_preflight_check() {
log_message "INFO" "Verifying preflight check results..."
if [ ! -f "$ENV_FILE" ]; then
log_message "ERROR" "Preflight check file not found: $ENV_FILE"
echo -e "\n${YELLOW}Preflight check has not been run or .env file is missing.${NC}"
echo -e "${YELLOW}Would you like to run the preflight check now?${NC}"
read -r -p "$(echo -e "${YELLOW}Run preflight check? (Y/n): ${NC}")" -n 1
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
echo -e "${CYAN}Running preflight check...${NC}"
if ! "$SCRIPT_DIR/wallarm-ct-check.sh"; then
fail_with_remediation "Preflight check failed" \
"Run the preflight check manually and fix any issues:
1. $SCRIPT_DIR/wallarm-ct-check.sh
2. Review the errors in $ENV_FILE
3. Fix the issues and run this script again"
fi
else
fail_with_remediation "Preflight check required" \
"Run the preflight check before deployment:
1. $SCRIPT_DIR/wallarm-ct-check.sh
2. Review results in $ENV_FILE
3. Run this script again"
fi
fi
# Load environment variables from .env file (from shared library)
if ! load_env_file "$ENV_FILE"; then
fail_with_remediation "Cannot load preflight results" \
"The preflight check results file could not be read.
1. Run the preflight check: $SCRIPT_DIR/wallarm-ct-check.sh
2. Verify $ENV_FILE exists and is readable
3. Run this script again"
fi
if [ "${CHECK_RESULT:-}" != "pass" ]; then
log_message "ERROR" "Preflight check failed (result: $CHECK_RESULT)"
echo -e "\n${YELLOW}Preflight check found issues. Please review:${NC}"
echo -e "${YELLOW}1. Check file: $ENV_FILE${NC}"
echo -e "${YELLOW}2. Run: $SCRIPT_DIR/wallarm-ct-check.sh${NC}"
echo -e "${YELLOW}3. Fix the issues and try again${NC}"
exit 1
fi
log_message "SUCCESS" "Preflight check verified:"
log_message "SUCCESS" " OS: $OS_NAME $OS_VERSION"
log_message "SUCCESS" " Architecture: $ARCHITECTURE"
log_message "SUCCESS" " Init System: $INIT_SYSTEM"
log_message "SUCCESS" " US Cloud Reachable: $US_CLOUD_REACHABLE"
log_message "SUCCESS" " EU Cloud Reachable: $EU_CLOUD_REACHABLE"
log_message "SUCCESS" " Wallarm Installer Reachable: $INSTALLER_REACHABLE"
# Validate we have at least one cloud region reachable
if [ "$US_CLOUD_REACHABLE" = "false" ] && [ "$EU_CLOUD_REACHABLE" = "false" ]; then
fail_with_remediation "No Wallarm cloud region reachable" \
"Network connectivity issues detected:
1. Check firewall rules for Wallarm cloud endpoints
2. Verify network connectivity
3. Run preflight check again: $SCRIPT_DIR/wallarm-ct-check.sh"
fi
# The all-in-one installer must be reachable for a native deployment
if [ "$INSTALLER_REACHABLE" != "true" ]; then
fail_with_remediation "Wallarm all-in-one installer not reachable" \
"Native deployment requires access to the Wallarm all-in-one installer:
1. Verify network access to $INSTALLER_BASE_URL
2. Check the current version at https://docs.wallarm.com/updating-migrating/node-artifact-versions/
3. Pin the version with: WALLARM_VERSION=<version> sudo ./$0"
fi
}
# ==============================================================================
# CONFIGURATION COLLECTION
# ==============================================================================
# select_cloud_region, validate_ip_address and check_port_available are provided
# by the shared library (../common/wallarm-lib.sh).
collect_configuration() {
log_message "INFO" "Collecting deployment configuration..."
# Get ingress port
local default_port=80
local ingress_port=""
while [[ ! "$ingress_port" =~ ^[0-9]+$ ]] || [ "$ingress_port" -lt 1 ] || [ "$ingress_port" -gt 65535 ]; do
read -r -p "$(echo -e "${YELLOW}Enter inbound port [${default_port}]: ${NC}")" ingress_port
ingress_port="${ingress_port:-$default_port}"
if [[ ! "$ingress_port" =~ ^[0-9]+$ ]]; then
echo -e "${RED}Port must be a number${NC}"
elif [ "$ingress_port" -lt 1 ] || [ "$ingress_port" -gt 65535 ]; then
echo -e "${RED}Port must be between 1 and 65535${NC}"
elif ! check_port_available "$ingress_port"; then
echo -e "${RED}Port $ingress_port is already in use${NC}"
ingress_port=""
fi
done
# Get application server details
local upstream_ip=""
local upstream_port=""
echo -e "\n${CYAN}${BOLD}Application Server Configuration:${NC}"
echo -e "${YELLOW}Enter the IP/hostname and port of your backend application${NC}"
while [[ -z "$upstream_ip" ]]; do
read -r -p "$(echo -e "${YELLOW}Upstream App IP/Hostname [127.0.0.1]: ${NC}")" upstream_ip
upstream_ip="${upstream_ip:-127.0.0.1}"
if ! validate_ip_address "$upstream_ip" && \
! [[ "$upstream_ip" =~ ^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]$ ]]; then
echo -e "${RED}Invalid IP/hostname format${NC}"
upstream_ip=""
fi
done
while [[ ! "$upstream_port" =~ ^[0-9]+$ ]] || [ "$upstream_port" -lt 1 ] || [ "$upstream_port" -gt 65535 ]; do
read -r -p "$(echo -e "${YELLOW}Upstream App Port [8080]: ${NC}")" upstream_port
upstream_port="${upstream_port:-8080}"
if [[ ! "$upstream_port" =~ ^[0-9]+$ ]]; then
echo -e "${RED}Port must be a number${NC}"
elif [ "$upstream_port" -lt 1 ] || [ "$upstream_port" -gt 65535 ]; then
echo -e "${RED}Port must be between 1 and 65535${NC}"
fi
done
# Verify application server reachability
log_message "INFO" "Verifying application server reachability..."
if timeout 5 bash -c "cat < /dev/null > /dev/tcp/$upstream_ip/$upstream_port" 2>/dev/null; then
log_message "SUCCESS" "Application server $upstream_ip:$upstream_port is reachable"
else
log_message "WARNING" "Application server $upstream_ip:$upstream_port is not reachable"
echo -e "${YELLOW}${BOLD}Warning:${NC} Cannot reach application server at $upstream_ip:$upstream_port"
echo -e "${YELLOW}This may cause the Wallarm node to fail. Possible reasons:${NC}"
echo -e "1. Application server is not running"
echo -e "2. Firewall blocking port $upstream_port"
echo -e "3. Wrong IP/hostname"
echo -e "4. Application server not listening on that port"
read -r -p "$(echo -e "${YELLOW}Continue anyway? (y/N): ${NC}")" -n 1
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
fail_with_remediation "Application server unreachable" \
"Ensure your application server is accessible:
1. Start your application server
2. Check it's listening: sudo ss -tlnp | grep :$upstream_port
3. Verify firewall rules allow inbound connections
4. Test connectivity: telnet $upstream_ip $upstream_port
5. If using hostname, verify DNS resolution: nslookup $upstream_ip"
fi
fi
# Get Wallarm node token
local wallarm_token=""
echo -e "\n${CYAN}${BOLD}Wallarm Node Token:${NC}"
echo -e "${YELLOW}Get your token from Wallarm Console:${NC}"
echo -e "Create a new 'Wallarm node' and copy the token (will be visible as you type)"
while [[ -z "$wallarm_token" ]]; do
read -r -p "$(echo -e "${YELLOW}Paste Wallarm Node Token: ${NC}")" wallarm_token
wallarm_token=$(echo "$wallarm_token" | tr -d '[:space:]')
if [[ -z "$wallarm_token" ]]; then
echo -e "${RED}Token cannot be empty${NC}"
elif [[ ! "$wallarm_token" =~ ^[A-Za-z0-9_+/=\-]+$ ]]; then
echo -e "${RED}Token contains invalid characters. Wallarm tokens are base64 strings (A-Z, a-z, 0-9, _, -, +, /, =)${NC}"
echo -e "${YELLOW}First 20 chars of what you entered: '${wallarm_token:0:20}...'${NC}"
wallarm_token=""
else
token_length=${#wallarm_token}
echo -e "${GREEN}Token accepted (${token_length} characters).${NC}"
echo -e "${YELLOW}First 8 chars for verification: ${wallarm_token:0:8}...${NC}"
fi
done
# Get trusted proxy IPs for real IP configuration
local trusted_proxies=""
echo -e "\n${CYAN}${BOLD}Real Client IP Configuration:${NC}"
echo -e "${YELLOW}For Wallarm to see the real client IP, specify the IP address(es) of trusted proxies"
echo -e "(e.g., load balancers, firewalls, CDNs) that forward traffic to this node.${NC}"
echo -e "${YELLOW}You can enter:${NC}"
echo -e " - Single IP: 10.0.0.10"
echo -e " - CIDR range: 10.0.0.0/24"
echo -e " - Multiple entries separated by spaces: 10.0.0.10 10.0.1.0/24 192.168.1.1"
echo -e "${YELLOW}If unsure, you can leave empty and configure later${NC}"
read -r -p "$(echo -e "${YELLOW}Trusted proxy IPs/CIDRs (space-separated): ${NC}")" trusted_proxies_input
local validated_proxies=()
if [[ -n "$trusted_proxies_input" ]]; then
IFS=' ' read -ra proxy_array <<< "$trusted_proxies_input"
for proxy in "${proxy_array[@]}"; do
proxy=$(echo "$proxy" | xargs)
if [[ -n "$proxy" ]]; then
if validate_ip_or_cidr "$proxy"; then
validated_proxies+=("$proxy")
else
echo -e "${RED}Invalid IP/CIDR format: $proxy${NC}"
echo -e "${YELLOW}Example valid formats: 10.0.0.10, 10.0.0.0/24, 192.168.1.1${NC}"
fi
fi
done
if [[ ${#validated_proxies[@]} -eq 0 ]]; then
echo -e "${YELLOW}No valid proxy IPs provided. Will skip set_real_ip_from configuration.${NC}"
echo -e "${YELLOW}You can configure it later with the reconfigure script.${NC}"
trusted_proxies=""
else
trusted_proxies="${validated_proxies[*]}"
echo -e "${GREEN}Trusted proxies configured: $trusted_proxies${NC}"
fi
else
echo -e "${YELLOW}No trusted proxies specified. The node will see the last hop IP only.${NC}"
fi
# Generate instance name and directory
local instance_name
instance_name="wallarm-$(hostname -s | tr '[:upper:]' '[:lower:]')-$(date +%Y%m%d)"
local instance_dir="/opt/wallarm/$instance_name"
sudo mkdir -p "$instance_dir"
log_message "SUCCESS" "Configuration collected:"
log_message "SUCCESS" " Ingress Port: $ingress_port"
log_message "SUCCESS" " Upstream: $upstream_ip:$upstream_port"
if [[ -n "$trusted_proxies" ]]; then
log_message "SUCCESS" " Trusted Proxies: $trusted_proxies"
else
log_message "INFO" " Trusted Proxies: Not configured (will need manual setup)"
fi
log_message "SUCCESS" " Instance: $instance_name"
log_message "SUCCESS" " Directory: $instance_dir"
INGRESS_PORT="$ingress_port"
UPSTREAM_IP="$upstream_ip"
UPSTREAM_PORT="$upstream_port"
WALLARM_TOKEN="$wallarm_token"
INSTANCE_NAME="$instance_name"
INSTANCE_DIR="$instance_dir"
TRUSTED_PROXIES="$trusted_proxies"
}
# ==============================================================================
# WALLARM NATIVE INSTALLATION (all-in-one installer)
# ==============================================================================
install_wallarm_native() {
log_message "INFO" "Installing Wallarm filtering node natively (all-in-one installer)..."
# Select the correct installer for the detected architecture
local arch_suffix
case "$ARCHITECTURE" in
"x86_64") arch_suffix="x86_64-glibc" ;;
"aarch64") arch_suffix="aarch64-glibc" ;;
*)
fail_with_remediation "Unsupported architecture for native install: $ARCHITECTURE" \
"The Wallarm all-in-one installer supports x86_64 and aarch64.
1. Check architecture: uname -m
2. If you are on a 32-bit system, consider the Docker deployment instead.
3. See https://docs.wallarm.com/installation/nginx/all-in-one/ for supported platforms."
;;
esac
local installer_name="wallarm-${WALLARM_VERSION}.${arch_suffix}.sh"
local installer_url="${INSTALLER_BASE_URL}/${installer_name}"
log_message "INFO" "Downloading Wallarm installer: $installer_name"
if ! download_from_git "$installer_url" "$installer_name" "Wallarm all-in-one installer"; then
fail_with_remediation "Failed to download Wallarm installer" \
"Could not download $installer_url
1. Verify network access to meganode.wallarm.com
2. Check the current version at https://docs.wallarm.com/updating-migrating/node-artifact-versions/
3. Pin the version with: WALLARM_VERSION=<version> sudo ./$0"
fi
chmod +x "$installer_name"
# Build installer arguments (batch mode)
local install_args="-- --batch -t $WALLARM_TOKEN"
if [ "$CLOUD_REGION" = "US" ]; then
install_args="$install_args -c US"
log_message "INFO" "Using US cloud (us1.api.wallarm.com)"
else
log_message "INFO" "Using EU cloud (api.wallarm.com)"
fi
# Run the installer (batch mode). The installer registers the node with the
# token and configures NGINX + the Wallarm module automatically.
log_message "INFO" "Running Wallarm all-in-one installer (this may take several minutes)..."
if [ -n "$WALLARM_LABELS" ]; then
log_message "INFO" "Using node labels: $WALLARM_LABELS"
if ! sudo env WALLARM_LABELS="$WALLARM_LABELS" sh "$installer_name" $install_args; then
rm -f "$installer_name"
fail_with_remediation "Wallarm installer failed" \
"The all-in-one installer exited with an error. Check:
1. The installer log output above for the exact error
2. Token validity in the Wallarm Console
3. Network access to Wallarm repositories (the installer adds them automatically)
4. Disk space and memory: df -h / && free -h
5. Retry with a higher log verbosity, or see https://docs.wallarm.com/installation/nginx/all-in-one/"
fi
else
if ! sudo sh "$installer_name" $install_args; then
rm -f "$installer_name"
fail_with_remediation "Wallarm installer failed" \
"The all-in-one installer exited with an error. Check:
1. The installer log output above for the exact error
2. Token validity in the Wallarm Console
3. Network access to Wallarm repositories (the installer adds them automatically)
4. Disk space and memory: df -h / && free -h
5. Retry with a higher log verbosity, or see https://docs.wallarm.com/installation/nginx/all-in-one/"
fi
fi
rm -f "$installer_name"
log_message "SUCCESS" "Wallarm all-in-one installer completed"
# Verify the node was registered
if [ -f "/opt/wallarm/etc/wallarm/node.yaml" ]; then
log_message "SUCCESS" "Wallarm node configuration found: /opt/wallarm/etc/wallarm/node.yaml"
else
log_message "WARNING" "Wallarm node configuration not found at /opt/wallarm/etc/wallarm/node.yaml"
echo -e "${YELLOW}The node may not have been registered. Check the installer output.${NC}"
fi
}
# ==============================================================================
# NGINX CONFIGURATION
# ==============================================================================
# Detect existing NGINX server blocks that would conflict with our ingress port
# and disable the default site if necessary.
resolve_port_conflict() {
local port="$1"
log_message "INFO" "Checking for NGINX config conflicts on port $port..."
# Only relevant for default port 80 where distro default sites listen
if [ "$port" != "80" ]; then
return 0
fi
# Look for default server blocks listening on port 80
local conflicting
conflicting=$(grep -rl "listen.*80" /etc/nginx/sites-enabled/ /etc/nginx/conf.d/ 2>/dev/null | head -1 || true)
if [ -n "$conflicting" ]; then
log_message "WARNING" "Default NGINX site found: $conflicting"
echo -e "${YELLOW}The default site listens on port 80 and may conflict with the Wallarm node.${NC}"
read -r -p "$(echo -e "${YELLOW}Disable it (backup to .bak)? (Y/n): ${NC}")" -n 1
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
sudo mv "$conflicting" "${conflicting}.bak"
log_message "SUCCESS" "Disabled $conflicting (backup: ${conflicting}.bak)"
else
log_message "WARNING" "Keeping default site. The Wallarm node may not receive traffic on port 80."
fi
fi
}
create_nginx_config() {
NGINX_CONFIG="/etc/nginx/conf.d/wallarm-${INSTANCE_NAME}.conf"
log_message "INFO" "Creating NGINX configuration: $NGINX_CONFIG"
# Also keep a copy in the instance directory for reference/backup
sudo tee "$NGINX_CONFIG" > /dev/null <<EOF
# Wallarm filtering node: $INSTANCE_NAME
# Generated: $(date)
server {
listen $INGRESS_PORT;
server_name _;
EOF
# Add set_real_ip_from directives if trusted proxies are configured
if [[ -n "$TRUSTED_PROXIES" ]]; then
for proxy in $TRUSTED_PROXIES; do
sudo tee -a "$NGINX_CONFIG" > /dev/null <<EOF
set_real_ip_from $proxy;
EOF
done
sudo tee -a "$NGINX_CONFIG" > /dev/null <<EOF
real_ip_header X-Real-IP;
real_ip_recursive on;
EOF
fi
# Add the rest of the configuration
sudo tee -a "$NGINX_CONFIG" > /dev/null <<EOF
location / {
proxy_pass http://$UPSTREAM_IP:$UPSTREAM_PORT;
proxy_set_header Host \$host;
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-Server \$http_x_forwarded_server;
# Wallarm directives
wallarm_mode monitoring;
}
# Health check endpoint
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
EOF
# Keep a reference copy in the instance directory
sudo cp "$NGINX_CONFIG" "$INSTANCE_DIR/nginx.conf"
log_message "SUCCESS" "NGINX configuration created: $NGINX_CONFIG"
if [[ -n "$TRUSTED_PROXIES" ]]; then
log_message "INFO" " Configured trusted proxies: $TRUSTED_PROXIES"
else
log_message "INFO" " No trusted proxies configured - real client IP detection may be limited"
fi
}
reload_nginx() {
log_message "INFO" "Testing and reloading NGINX..."
if ! sudo nginx -t 2>&1 | tee "$INSTANCE_DIR/nginx-test.log"; then
fail_with_remediation "NGINX configuration test failed" \
"NGINX rejected the configuration. Check the test output above.
1. Review the generated config: $NGINX_CONFIG
2. Look for port conflicts or syntax errors
3. Restore the backup if the default site was disabled
4. Manual test: sudo nginx -t"
fi
# Reload according to init system
case "${INIT_SYSTEM:-systemd}" in
"systemd")
sudo systemctl reload nginx 2>/dev/null || sudo systemctl restart nginx
;;
"openrc")
sudo rc-service nginx reload 2>/dev/null || sudo rc-service nginx restart
;;
"sysvinit")
sudo service nginx reload 2>/dev/null || sudo service nginx restart
;;
*)
sudo nginx -s reload 2>/dev/null || true
;;
esac
log_message "SUCCESS" "NGINX reloaded with Wallarm configuration"
}
# ==============================================================================
# DEPLOYMENT VERIFICATION
# ==============================================================================
verify_deployment() {
log_message "INFO" "Verifying native Wallarm deployment..."
# Test ingress port
log_message "INFO" "Testing ingress port $INGRESS_PORT..."
if ! check_port_available "$INGRESS_PORT"; then
log_message "SUCCESS" "Ingress port $INGRESS_PORT is in use (as expected)"
else
log_message "WARNING" "Ingress port $INGRESS_PORT appears available (NGINX may not be listening)"
fi
# Test health check endpoint
log_message "INFO" "Testing health check endpoint..."
local health_check_url="http://localhost:$INGRESS_PORT/health"
if curl -sf --connect-timeout 5 "$health_check_url" >/dev/null 2>&1; then
log_message "SUCCESS" "Health check endpoint responsive"
else
log_message "WARNING" "Health check endpoint not responsive (may need time to start)"
sleep 5
if curl -sf --connect-timeout 5 "$health_check_url" >/dev/null 2>&1; then
log_message "SUCCESS" "Health check endpoint now responsive"
else
log_message "WARNING" "Health check endpoint still not responsive (check nginx config)"
fi
fi
# Test handshake through filtering node
log_message "INFO" "Testing handshake through filtering node to upstream..."
local test_url="http://localhost:$INGRESS_PORT/"
if curl -sfI --connect-timeout 10 "$test_url" >/dev/null 2>&1; then
log_message "SUCCESS" "Handshake successful: filtering node can reach upstream"
else
log_message "WARNING" "Handshake failed (upstream may not be responding)"
log_message "INFO" "Checking if upstream is directly reachable..."
if timeout 5 bash -c "cat < /dev/null > /dev/tcp/$UPSTREAM_IP/$UPSTREAM_PORT" 2>/dev/null; then
log_message "ERROR" "Upstream is reachable but filtering node cannot proxy"
echo -e "${YELLOW}Possible NGINX configuration issue. Check:${NC}"
echo -e "1. NGINX error log: sudo tail -50 /var/log/nginx/error.log"
echo -e "2. NGINX config: $NGINX_CONFIG"
else
log_message "WARNING" "Upstream server is not reachable (as previously warned)"
fi
fi
# Check Wallarm module status endpoint
log_message "INFO" "Checking Wallarm module status..."
if curl -sf --connect-timeout 5 "http://127.0.0.8/wallarm-status" >/dev/null 2>&1; then
log_message "SUCCESS" "Wallarm module is active (wallarm-status responsive)"
else
log_message "WARNING" "wallarm-status not responsive (module may need more time or a restart)"
fi
# Check node registration file
if [ -f "/opt/wallarm/etc/wallarm/node.yaml" ]; then
log_message "SUCCESS" "Node is registered (node.yaml present)"
else
log_message "WARNING" "node.yaml not found - node may not be registered with the cloud"
fi
log_message "SUCCESS" "Deployment verification completed"
echo -e "\n${GREEN}${BOLD}Verification Summary:${NC}"
echo -e " ${GREEN}${NC} NGINX + Wallarm module installed"
echo -e " ${GREEN}${NC} Ingress port: $INGRESS_PORT"
echo -e " ${GREEN}${NC} Upstream: $UPSTREAM_IP:$UPSTREAM_PORT"
echo -e " ${GREEN}${NC} Cloud region: $CLOUD_REGION ($API_HOST)"
}
# ==============================================================================
# MAIN FUNCTION
# ==============================================================================
main() {
clear
echo -e "${BLUE}${BOLD}"
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ WALLARM DEPLOYMENT SCRIPT (Native) - V1.0 ║"
echo "║ Filtering Node Deployment Without Docker ║"
echo "╚══════════════════════════════════════════════════════════════╝${NC}"
echo -e "\n${YELLOW}Starting deployment at: $(date)${NC}"
# Initialize logging
local log_dir="${HOME:-.}/logs"
if [ ! -d "$log_dir" ]; then
if ! mkdir -p "$log_dir"; then
echo -e "${YELLOW}Cannot create log directory $log_dir, falling back to current directory...${NC}"
log_dir="."
fi
fi
LOG_FILE="$log_dir/wallarm-deployment-native.log"
if ! : > "$LOG_FILE"; then
echo -e "${RED}Cannot create log file at $LOG_FILE${NC}"
echo -e "${YELLOW}Falling back to current directory...${NC}"
LOG_FILE="./wallarm-deployment-native.log"
: > "$LOG_FILE" 2>/dev/null || true
fi
if ! chmod 644 "$LOG_FILE" 2>/dev/null; then
echo -e "${YELLOW}Warning: Could not set permissions on log file${NC}"
fi
log_message "INFO" "=== Wallarm Native Deployment Started ==="
if [ "$INSECURE_SSL" = "1" ]; then
log_message "WARNING" "SSL certificate validation is DISABLED (insecure). Set WALLARM_INSECURE_SSL=0 to enable validation."
fi
# Phase 1: Verify preflight check
log_message "INFO" "=== PHASE 1: PREFLIGHT CHECK VERIFICATION ==="
verify_preflight_check
# Phase 2: Configuration collection
log_message "INFO" "=== PHASE 2: CONFIGURATION COLLECTION ==="
select_cloud_region
collect_configuration
# Phase 3: Native installation (all-in-one installer)
log_message "INFO" "=== PHASE 3: WALLARM NATIVE INSTALLATION ==="
install_wallarm_native
# Phase 4: NGINX configuration
log_message "INFO" "=== PHASE 4: NGINX CONFIGURATION ==="
resolve_port_conflict "$INGRESS_PORT"
create_nginx_config
reload_nginx
# Phase 5: Verification
log_message "INFO" "=== PHASE 5: VERIFICATION ==="
verify_deployment
# Success message
log_message "SUCCESS" "=== WALLARM NATIVE DEPLOYMENT COMPLETED SUCCESSFULLY ==="
echo -e "\n${GREEN}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}${BOLD}║ WALLARM FILTERING NODE DEPLOYMENT SUCCESSFUL ║${NC}"
echo -e "${GREEN}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}"
echo -e "\n${CYAN}The Wallarm filtering node is now active and protecting your application.${NC}"
echo -e "${YELLOW}Full deployment log: $LOG_FILE${NC}"
echo -e "${YELLOW}Instance directory: $INSTANCE_DIR${NC}"
echo -e "\n${GREEN}To stop the node:${NC} sudo systemctl stop nginx"
echo -e "${GREEN}To restart:${NC} sudo systemctl restart nginx"
echo -e "${GREEN}To view logs:${NC} sudo tail -f /var/log/nginx/error.log"
echo -e "${GREEN}Node status:${NC} curl http://127.0.0.8/wallarm-status"
echo -e "\n${MAGENTA}${BOLD}Deployment completed successfully!${NC}"
echo -e "\n${YELLOW}Important next steps:${NC}"
echo -e "1. Monitor sync status in Wallarm Console"
echo -e "2. Test attack detection with safe test: curl http://localhost:$INGRESS_PORT/?wallarm_test=1"
echo -e "3. Review logs periodically: sudo tail -50 /var/log/nginx/error.log"
echo -e "4. Switch to block mode after validation: sudo ./native/wallarm-ct-reconfigure.sh"
}
# ==============================================================================
# SCRIPT EXECUTION
# ==============================================================================
# Ensure we're in bash
if [ -z "$BASH_VERSION" ]; then
echo "Error: This script must be run with bash" >&2
exit 1
fi
# Run main function
main "$@"

227
native/wallarm-ct-reconfigure.sh Executable file
View file

@ -0,0 +1,227 @@
#!/bin/bash
# ==============================================================================
# WALLARM RECONFIGURATION SCRIPT - V1.0 (Native deployment)
# ==============================================================================
# Purpose: Modify NGINX configuration of an existing native Wallarm node
# Features:
# - Update set_real_ip_from (trusted proxy IPs/CIDRs)
# - Change wallarm_mode (monitoring/block)
# - Backup current config before changes
# - NGINX test + reload instead of container restart
# - Interactive prompts with validation
# ==============================================================================
# Script location and shared library (colors, logging, validation)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=../common/wallarm-lib.sh
source "$SCRIPT_DIR/../common/wallarm-lib.sh"
set -euo pipefail
trap early_error_handler ERR
# ==============================================================================
# CHECK FOR SUDO / ROOT PRIVILEGES
# ==============================================================================
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}${BOLD}ERROR:${NC} This script must be run with sudo or as root."
echo -e "${YELLOW}Please run: sudo $0${NC}"
exit 1
fi
# ==============================================================================
# CONFIGURATION
# ==============================================================================
CONFIG_GLOB="/etc/nginx/conf.d/wallarm-*.conf"
CONFIG_FILE=""
INSTANCE_NAME=""
# ==============================================================================
# FUNCTIONS
# ==============================================================================
# Find the Wallarm NGINX config file(s)
find_wallarm_config() {
local configs=()
while IFS= read -r file; do
configs+=("$file")
done < <(ls $CONFIG_GLOB 2>/dev/null)
if [ ${#configs[@]} -eq 0 ]; then
echo -e "${RED}No Wallarm NGINX configuration found ($CONFIG_GLOB).${NC}"
echo -e "${YELLOW}Has the native deployment been run? Check /etc/nginx/conf.d/wallarm-*.conf${NC}"
exit 1
elif [ ${#configs[@]} -eq 1 ]; then
CONFIG_FILE="${configs[0]}"
INSTANCE_NAME=$(basename "$CONFIG_FILE" | sed 's/^wallarm-//; s/\.conf$//')
echo -e "${GREEN}Found Wallarm config: $CONFIG_FILE${NC}"
else
echo -e "${YELLOW}Multiple Wallarm NGINX configs found:${NC}"
for i in "${!configs[@]}"; do
echo "$((i+1)). ${configs[$i]}"
done
read -r -p "Select config number: " choice
if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#configs[@]} ]; then
CONFIG_FILE="${configs[$((choice-1))]}"
INSTANCE_NAME=$(basename "$CONFIG_FILE" | sed 's/^wallarm-//; s/\.conf$//')
else
echo -e "${RED}Invalid selection.${NC}"
exit 1
fi
fi
}
# Parse current configuration to get existing values
parse_current_config() {
local config_file="$1"
current_mode=$(grep -oP 'wallarm_mode\s+\K\S+' "$config_file" | head -1)
current_proxies=$(grep -oP 'set_real_ip_from\s+\K\S+' "$config_file")
}
# Update configuration
update_config() {
local config_file="$1"
local backup_file="$config_file.backup.$(date +%Y%m%d_%H%M%S)"
echo -e "${YELLOW}Backing up current config to $backup_file${NC}"
cp "$config_file" "$backup_file"
echo -e "\n${CYAN}${BOLD}Current set_real_ip_from entries:${NC}"
if [ -n "$current_proxies" ]; then
while read -r proxy; do
echo " $proxy"
done <<< "$current_proxies"
else
echo " (none)"
fi
echo -e "\n${YELLOW}Do you want to change the trusted proxy IPs/CIDRs? (y/N)${NC}"
read -r change_proxy
new_proxies=()
if [[ "$change_proxy" =~ ^[Yy]$ ]]; then
echo -e "${YELLOW}Enter new trusted proxy IPs/CIDRs (space-separated, or empty to remove all):${NC}"
read -r new_proxies_input
if [[ -n "$new_proxies_input" ]]; then
IFS=' ' read -ra proxy_array <<< "$new_proxies_input"
for proxy in "${proxy_array[@]}"; do
proxy=$(echo "$proxy" | xargs)
if validate_ip_or_cidr "$proxy"; then
new_proxies+=("$proxy")
else
echo -e "${RED}Invalid format: $proxy. Skipping.${NC}"
fi
done
fi
else
# Keep existing
while read -r proxy; do
new_proxies+=("$proxy")
done <<< "$current_proxies"
fi
echo -e "\n${CYAN}${BOLD}Current wallarm_mode:${NC} ${current_mode:-not set}"
echo -e "${YELLOW}Do you want to change the wallarm_mode? (y/N)${NC}"
read -r change_mode
if [[ "$change_mode" =~ ^[Yy]$ ]]; then
echo -e "${YELLOW}Select new mode:${NC}"
echo "1. monitoring"
echo "2. block"
read -r mode_choice
case "$mode_choice" in
1) new_mode="monitoring" ;;
2) new_mode="block" ;;
*) echo -e "${RED}Invalid choice, keeping current mode.${NC}"; new_mode="$current_mode" ;;
esac
else
new_mode="$current_mode"
fi
# Rebuild the config file
temp_config=$(mktemp)
in_server_block=false
while IFS= read -r line; do
if [[ "$line" =~ ^[[:space:]]*server[[:space:]]*{ ]]; then
in_server_block=true
fi
if $in_server_block; then
if [[ "$line" =~ ^[[:space:]]*set_real_ip_from[[:space:]]+ ]]; then
continue
fi
if [[ "$line" =~ ^[[:space:]]*wallarm_mode[[:space:]]+ ]]; then
continue
fi
if [[ "$line" =~ ^[[:space:]]*real_ip_header[[:space:]]+ ]]; then
continue
fi
if [[ "$line" =~ ^[[:space:]]*real_ip_recursive[[:space:]]+ ]]; then
continue
fi
fi
echo "$line" >> "$temp_config"
if $in_server_block && [[ "$line" =~ ^[[:space:]]*}$ ]]; then
in_server_block=false
if [ ${#new_proxies[@]} -gt 0 ]; then
for proxy in "${new_proxies[@]}"; do
echo " set_real_ip_from $proxy;" >> "$temp_config"
done
echo " real_ip_header X-Real-IP;" >> "$temp_config"
echo " real_ip_recursive on;" >> "$temp_config"
fi
if [ -n "$new_mode" ]; then
echo " wallarm_mode $new_mode;" >> "$temp_config"
fi
fi
done < "$config_file"
mv "$temp_config" "$config_file"
chmod 644 "$config_file"
echo -e "${GREEN}Configuration updated.${NC}"
}
reload_nginx() {
echo -e "${YELLOW}Testing NGINX configuration...${NC}"
if ! sudo nginx -t; then
echo -e "${RED}NGINX configuration test failed. Restoring backup...${NC}"
cp "$CONFIG_FILE.backup."*. "$CONFIG_FILE" 2>/dev/null || true
exit 1
fi
echo -e "${YELLOW}Reloading NGINX to apply changes...${NC}"
sudo systemctl reload nginx 2>/dev/null || sudo nginx -s reload 2>/dev/null || {
sudo systemctl restart nginx 2>/dev/null || {
echo -e "${RED}Could not reload NGINX. Please do it manually: sudo systemctl reload nginx${NC}"
exit 1
}
}
echo -e "${GREEN}NGINX reloaded.${NC}"
}
main() {
echo -e "${BLUE}${BOLD}"
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ WALLARM RECONFIGURATION SCRIPT (Native) - V1.0 ║"
echo "║ Modify NGINX config (trusted proxies / mode) ║"
echo "╚══════════════════════════════════════════════════════════════╝${NC}"
find_wallarm_config
parse_current_config "$CONFIG_FILE"
update_config "$CONFIG_FILE"
echo -e "${YELLOW}Do you want to reload NGINX now? (Y/n)${NC}"
read -r reload_choice
if [[ ! "$reload_choice" =~ ^[Nn]$ ]]; then
reload_nginx
else
echo -e "${YELLOW}Changes will take effect after NGINX reload.${NC}"
echo -e "You can reload later with: sudo systemctl reload nginx"
fi
echo -e "\n${GREEN}${BOLD}Reconfiguration completed.${NC}"
}
main "$@"

299
native/wallarm-ct-uninstall.sh Executable file
View file

@ -0,0 +1,299 @@
#!/bin/bash
# ==============================================================================
# WALLARM UNINSTALL SCRIPT - V1.0 (Native deployment)
# ==============================================================================
# Purpose: Safely remove a native (no-Docker) Wallarm filtering node
# Features:
# - Interactive confirmation with safety checks
# - Removes Wallarm NGINX configuration (with backup)
# - Restores disabled default NGINX sites
# - Uninstalls Wallarm packages and repository definitions
# - Removes /opt/wallarm node data
# - Preserves user data and logs (with option to remove)
# - DAU-friendly warnings and confirmations
# ==============================================================================
# Script location and shared library (colors, logging, validation)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=../common/wallarm-lib.sh
source "$SCRIPT_DIR/../common/wallarm-lib.sh"
# Strict error handling
set -euo pipefail
trap early_error_handler ERR
# ==============================================================================
# CONFIGURATION
# ==============================================================================
CONFIG_GLOB="/etc/nginx/conf.d/wallarm-*.conf"
DEFAULT_BACKUP_GLOB="/etc/nginx/sites-enabled/*.bak"
WALLARM_NODE_DIR="/opt/wallarm"
# ==============================================================================
# FUNCTIONS
# ==============================================================================
# Ask for confirmation
confirm() {
local prompt="$1"
local default="${2:-n}"
local options="[y/N]"
if [ "$default" = "y" ]; then
options="[Y/n]"
fi
echo -e -n "${YELLOW}${prompt} ${options}${NC} "
read -r response
case "$response" in
[yY][eE][sS]|[yY]) return 0 ;;
[nN][oO]|[nN]) return 1 ;;
"")
if [ "$default" = "y" ]; then
return 0
else
return 1
fi
;;
*) return 1 ;;
esac
}
# Detect the package manager in use
detect_package_manager() {
if command -v apt-get >/dev/null 2>&1; then
echo "apt"
elif command -v yum >/dev/null 2>&1; then
echo "yum"
elif command -v dnf >/dev/null 2>&1; then
echo "dnf"
elif command -v apk >/dev/null 2>&1; then
echo "apk"
else
echo "unknown"
fi
}
# Remove Wallarm NGINX configuration files
remove_nginx_configs() {
log_message "INFO" "Looking for Wallarm NGINX configurations..."
local configs=()
while IFS= read -r file; do
configs+=("$file")
done < <(ls $CONFIG_GLOB 2>/dev/null)
if [ ${#configs[@]} -eq 0 ]; then
log_message "INFO" "No Wallarm NGINX configurations found"
return
fi
log_message "INFO" "Found ${#configs[@]} Wallarm NGINX configuration(s)"
for file in "${configs[@]}"; do
if confirm "Remove $file? (backup created)" "y"; then
cp "$file" "$file.uninstall-$(date +%Y%m%d_%H%M%S).bak"
rm -f "$file"
log_message "SUCCESS" "Removed $file (backup created)"
else
log_message "INFO" "Skipping $file"
fi
done
}
# Restore any default NGINX sites we disabled during deployment
restore_default_sites() {
log_message "INFO" "Looking for disabled default NGINX sites..."
local restored=0
while IFS= read -r backup; do
if [ -f "$backup" ]; then
local target="${backup%.bak}"
log_message "INFO" "Restoring $target from $backup"
if confirm "Restore $target?" "y"; then
cp "$backup" "$target"
rm -f "$backup"
restored=$((restored + 1))
fi
fi
done < <(ls $DEFAULT_BACKUP_GLOB 2>/dev/null)
if [ "$restored" -gt 0 ]; then
log_message "SUCCESS" "Restored $restored default site(s)"
else
log_message "INFO" "No disabled default sites found"
fi
}
# Reload NGINX to drop the removed configurations
reload_nginx() {
log_message "INFO" "Testing and reloading NGINX..."
if sudo nginx -t 2>/dev/null; then
sudo systemctl reload nginx 2>/dev/null || sudo nginx -s reload 2>/dev/null || true
log_message "SUCCESS" "NGINX reloaded"
else
log_message "WARNING" "NGINX configuration test failed - reload skipped"
echo -e "${YELLOW}Run 'sudo nginx -t' manually to diagnose the issue.${NC}"
fi
}
# Uninstall Wallarm packages via the system package manager
remove_wallarm_packages() {
local pkg_manager
pkg_manager=$(detect_package_manager)
log_message "INFO" "Detected package manager: $pkg_manager"
if ! confirm "Uninstall Wallarm packages? (wallarm-node, wallarm modules)" "y"; then
log_message "INFO" "Skipping Wallarm package removal"
return
fi
case "$pkg_manager" in
"apt")
log_message "INFO" "Removing Wallarm packages (apt)..."
sudo apt-get purge -y "wallarm-node" "wallarm-node-nginx" "nginx-module-wallarm*" 2>/dev/null || true
sudo apt-get autoremove -y 2>/dev/null || true
;;
"yum")
log_message "INFO" "Removing Wallarm packages (yum)..."
sudo yum remove -y "wallarm-node" "nginx-module-wallarm*" 2>/dev/null || true
;;
"dnf")
log_message "INFO" "Removing Wallarm packages (dnf)..."
sudo dnf remove -y "wallarm-node" "nginx-module-wallarm*" 2>/dev/null || true
;;
"apk")
log_message "INFO" "Removing Wallarm packages (apk)..."
sudo apk del "wallarm-node" "nginx-module-wallarm" 2>/dev/null || true
;;
*)
log_message "WARNING" "Unknown package manager. Please remove Wallarm packages manually."
echo -e "${YELLOW}Relevant packages usually include: wallarm-node, nginx-module-wallarm${NC}"
return
;;
esac
log_message "SUCCESS" "Wallarm packages removed"
}
# Remove Wallarm repository definitions added by the installer
remove_wallarm_repos() {
log_message "INFO" "Removing Wallarm repository definitions..."
local removed=0
while IFS= read -r file; do
if [ -f "$file" ]; then
sudo rm -f "$file"
log_message "SUCCESS" "Removed repo file: $file"
removed=$((removed + 1))
fi
done < <(ls /etc/apt/sources.list.d/*wallarm* /etc/yum.repos.d/*wallarm* 2>/dev/null)
if [ "$removed" -eq 0 ]; then
log_message "INFO" "No Wallarm repository files found"
fi
}
# Remove Wallarm node data directory
remove_wallarm_data() {
if [ -d "$WALLARM_NODE_DIR" ]; then
log_message "WARNING" "Found Wallarm data directory: $WALLARM_NODE_DIR"
log_message "WARNING" "This contains node registration and local data."
if confirm "Remove $WALLARM_NODE_DIR? (node will need re-registration)" "n"; then
sudo rm -rf "$WALLARM_NODE_DIR"
log_message "SUCCESS" "Removed $WALLARM_NODE_DIR"
else
log_message "INFO" "Skipping removal of $WALLARM_NODE_DIR"
fi
else
log_message "INFO" "No Wallarm data directory found"
fi
}
# Remove Wallarm log files (optional)
remove_wallarm_logs() {
local log_dir="$HOME/logs"
if [ -d "$log_dir" ]; then
log_message "INFO" "Found log directory: $log_dir"
if [ -z "$(ls -A "$log_dir" 2>/dev/null)" ]; then
log_message "INFO" "Log directory is empty, removing..."
sudo rmdir "$log_dir" 2>/dev/null || true
else
log_message "INFO" "Log directory contains files, preserving..."
fi
fi
if [ -f ".env" ]; then
if confirm "Remove .env preflight file?" "n"; then
rm -f ".env"
log_message "SUCCESS" "Removed .env file"
fi
fi
}
# ==============================================================================
# MAIN
# ==============================================================================
main() {
echo -e "${CYAN}${BOLD}"
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ WALLARM UNINSTALLATION (Native) ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo -e "${NC}"
echo -e "${YELLOW}This script will remove the native Wallarm filtering node.${NC}"
echo -e "${YELLOW}You will be asked for confirmation before each destructive operation.${NC}"
echo ""
if ! confirm "Do you want to continue with the uninstallation?" "n"; then
log_message "INFO" "Uninstallation cancelled by user"
exit 0
fi
# Step 1: Remove Wallarm NGINX configurations
echo ""
echo -e "${CYAN}${BOLD}Step 1: Remove Wallarm NGINX configurations${NC}"
remove_nginx_configs
restore_default_sites
reload_nginx
# Step 2: Uninstall Wallarm packages
echo ""
echo -e "${CYAN}${BOLD}Step 2: Uninstall Wallarm packages${NC}"
remove_wallarm_packages
remove_wallarm_repos
# Step 3: Remove Wallarm data
echo ""
echo -e "${CYAN}${BOLD}Step 3: Remove Wallarm data${NC}"
remove_wallarm_data
# Step 4: Cleanup
echo ""
echo -e "${CYAN}${BOLD}Step 4: Logs and files cleanup${NC}"
if confirm "Remove Wallarm log files and .env?" "n"; then
remove_wallarm_logs
else
log_message "INFO" "Skipping log/file cleanup"
fi
# Final message
echo ""
echo -e "${GREEN}${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}${BOLD}║ UNINSTALLATION COMPLETE ║${NC}"
echo -e "${GREEN}${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${GREEN}The native Wallarm filtering node has been removed.${NC}"
echo ""
echo -e "${YELLOW}Note:${NC}"
echo -e " • NGINX itself was kept installed (may be used by other applications)"
echo -e " • The Wallarm module may remain in NGINX's modules directory"
echo -e " • Wallarm repositories were removed from your package sources"
echo ""
}
# Run main function
main "$@"

483
native/wallarm-native.sh Executable file
View file

@ -0,0 +1,483 @@
#!/bin/bash
# ==============================================================================
# Wallarm Native Node Manager - Install, Configure, Remove, and Control
# ==============================================================================
# Unified single-script manager for the Wallarm Native Node (connector mode,
# NO Docker). Manages multiple isolated nodes under ${BASE_DIR}/nodes with a
# systemd template unit (wallarm-node@<name>.service).
#
# NOTE: This targets the Wallarm Native Node product (go-node, connector-server
# mode, all-in-one installer) - distinct from the NGINX-module based native
# deployment in ./wallarm-ct-deploy.sh.
#
# Commands:
# --preflight Run preflight checks only (no installation).
# --install Interactive installation of one or more nodes (parallel).
# --config Update an existing node's configuration.
# Options: --node NAME --address IP:PORT [--token TOKEN] [--labels LABELS]
# --remove Remove a node completely.
# Options: --node NAME
# --status [NODE] Show systemd status for a node, or all nodes.
# --help|-h Show help.
# ==============================================================================
set -euo pipefail
# Script location and shared library (logging, detection, connectivity, validation)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=../common/wallarm-lib.sh
source "$SCRIPT_DIR/../common/wallarm-lib.sh"
# --- Constants ---
BASE_DIR="/opt/wallarm"
NODES_DIR="${BASE_DIR}/nodes"
SYSTEMD_TEMPLATE="/etc/systemd/system/wallarm-node@.service"
# Wallarm Native Node all-in-one installer (latest, x86_64 by default)
# Override WALLARM_INSTALLER_URL to pin a version; WALLARM_INSTALLER_ARCH to
# select the architecture suffix.
INSTALLER_BASE_URL="https://repo.wallarm.com/linux/wallarm-native-node/latest/all-in-one"
INSTALLER_ARCH="${WALLARM_INSTALLER_ARCH:-x86_64}"
INSTALLER_URL="${WALLARM_INSTALLER_URL:-${INSTALLER_BASE_URL}/wallarm-native-node-aio-${INSTALLER_ARCH}-latest.sh}"
# Wallarm cloud endpoints (for connectivity checks)
EU_DATA_NODES=("api.wallarm.com" "node-data0.eu1.wallarm.com" "node-data1.eu1.wallarm.com")
US_DATA_NODES=("us1.api.wallarm.com" "node-data0.us1.wallarm.com" "node-data1.us1.wallarm.com")
# --- Helper functions ---
log() { echo ">>> $*"; }
err() { echo "!!! $*" >&2; }
check_root() {
if [[ $EUID -ne 0 ]]; then
err "This script must be run as root (for systemd and /opt write access)."
exit 1
fi
}
ensure_dirs() {
mkdir -p "${NODES_DIR}"
}
generate_systemd_template() {
if [[ ! -f "${SYSTEMD_TEMPLATE}" ]]; then
log "Creating systemd template: ${SYSTEMD_TEMPLATE}"
cat > "${SYSTEMD_TEMPLATE}" <<EOF
[Unit]
Description=Wallarm Native Node - %I
After=network.target
[Service]
Type=simple
WorkingDirectory=${NODES_DIR}/%i
EnvironmentFile=${NODES_DIR}/%i/env
ExecStart=${NODES_DIR}/%i/wallarm-native-node-aio.sh start
ExecStop=${NODES_DIR}/%i/wallarm-native-node-aio.sh stop
Restart=on-failure
RestartSec=5
User=root
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
fi
}
write_env_file() {
local node_name="$1"
local api_token="$2"
local labels="$3"
local config_path="${NODES_DIR}/${node_name}/etc/go-node.yaml"
local env_file="${NODES_DIR}/${node_name}/env"
cat > "${env_file}" <<EOF
WALLARM_API_TOKEN=${api_token}
WALLARM_LABELS=${labels}
WALLARM_CONFIG_PATH=${config_path}
EOF
chmod 600 "${env_file}" # token is sensitive
}
# --- Preflight checks ---
run_preflight() {
local failed=0
log "Running preflight checks..."
# 1. Root privileges
if [[ $EUID -ne 0 ]]; then
err "Preflight failed: must be run as root."
failed=1
fi
# 2. Init system must be systemd (template unit management)
local init_system
init_system=$(detect_init_system)
if [[ "$init_system" != "systemd" ]]; then
err "Preflight failed: this manager requires systemd (detected: $init_system)."
failed=1
fi
# 3. Architecture
local arch
arch=$(detect_architecture)
if [[ "$arch" != "x86_64" && "$arch" != "aarch64" ]]; then
err "Preflight failed: unsupported architecture '$arch' for the native node installer."
failed=1
fi
log "Architecture: ${arch} (installer suffix: ${INSTALLER_ARCH})"
# 4. Required commands
local required_cmds=(curl systemctl sed mkdir rm sleep)
local missing=()
local cmd
for cmd in "${required_cmds[@]}"; do
if ! command_exists "$cmd"; then
missing+=("$cmd")
fi
done
if [[ ${#missing[@]} -gt 0 ]]; then
err "Preflight failed: missing required commands: ${missing[*]}"
failed=1
fi
# 5. Installer reachability
if ! test_connectivity "$INSTALLER_URL" "Wallarm native node installer"; then
err "Preflight failed: installer not reachable: $INSTALLER_URL"
failed=1
fi
# 6. Wallarm cloud reachability (must have at least one reachable region)
local us eu
us=$(test_cloud_endpoints "US" "${US_DATA_NODES[@]}")
eu=$(test_cloud_endpoints "EU" "${EU_DATA_NODES[@]}")
if [[ "$us" != "true" && "$eu" != "true" ]]; then
err "Preflight failed: no Wallarm cloud region reachable (US/EU)."
failed=1
fi
# 7. Disk space (>= 2GB free on the nodes volume)
local avail_kb
avail_kb=$(df -k "$BASE_DIR" 2>/dev/null | awk 'NR==2 {print $4}' || true)
if [[ -n "$avail_kb" ]] && (( avail_kb < 2097152 )); then
err "Preflight failed: insufficient disk space on $BASE_DIR (need >= 2GB free)."
failed=1
fi
# 8. Memory (>= 2GB recommended; warning only)
if command_exists free; then
local mem_mb
mem_mb=$(free -m 2>/dev/null | awk '/Mem:/ {print $2}')
if [[ -n "$mem_mb" ]] && (( mem_mb < 2048 )); then
err "Warning: only ${mem_mb}MB RAM detected (2GB+ recommended)."
fi
fi
if [[ $failed -ne 0 ]]; then
err "Preflight check FAILED. Resolve the issues above and re-run."
return 1
fi
log "Preflight checks passed."
return 0
}
# Validate a listen address (IP:PORT) and check its port is free
check_listen_port() {
local address="$1"
local port="${address##*:}"
if [[ ! "$port" =~ ^[0-9]+$ ]] || (( port < 1 || port > 65535 )); then
err "Invalid listen address (expected IP:PORT): $address"
return 1
fi
if ! check_port_available "$port"; then
err "Listen port $port (for $address) is already in use."
return 1
fi
return 0
}
# --- Core actions ---
install_single_node() {
local node_name="$1"
local listen_address="$2"
local api_token="$3"
local labels="${4:-group=${node_name}}"
local work_dir="${NODES_DIR}/${node_name}"
local installer_path="${work_dir}/wallarm-native-node-aio.sh"
log "[${node_name}] Installing (listening on ${listen_address})..."
mkdir -p "${work_dir}/etc" "${work_dir}/var/log" "${work_dir}/var/run"
# 1. Write config
cat > "${work_dir}/etc/go-node.yaml" <<EOF
mode: connector-server
connector:
address: "${listen_address}"
EOF
# 2. Download installer if missing
if [[ ! -f "${installer_path}" ]]; then
log "[${node_name}] Downloading installer..."
curl -fsSL -o "${installer_path}" "${INSTALLER_URL}" || {
err "[${node_name}] Download failed"
return 1
}
chmod +x "${installer_path}"
fi
# 3. Write environment file (used by systemd and manual scripts)
write_env_file "${node_name}" "${api_token}" "${labels}"
# 4. Run installer
cd "${work_dir}" || return 1
if WALLARM_API_TOKEN="${api_token}" \
WALLARM_LABELS="${labels}" \
WALLARM_CONFIG_PATH="${work_dir}/etc/go-node.yaml" \
./wallarm-native-node-aio.sh install \
-- --config-dir "${work_dir}/etc" \
-- --log-dir "${work_dir}/var/log" \
-- --pid-dir "${work_dir}/var/run" \
> "${work_dir}/install.log" 2>&1; then
log "[${node_name}] Installation successful."
# Enable and start the systemd service
systemctl enable "wallarm-node@${node_name}" 2>/dev/null || true
systemctl start "wallarm-node@${node_name}"
log "[${node_name}] Service started (systemctl status wallarm-node@${node_name})"
else
err "[${node_name}] Installation failed. Check ${work_dir}/install.log"
return 1
fi
}
cmd_preflight() {
check_root
echo ""
if run_preflight; then
log "Preflight passed - system ready for --install."
exit 0
else
exit 1
fi
}
cmd_install() {
check_root
if ! run_preflight; then
exit 1
fi
ensure_dirs
generate_systemd_template
read -p "Enter Wallarm API Token (with Deploy role): " WALLARM_API_TOKEN
if [[ -z "$WALLARM_API_TOKEN" ]]; then
err "API Token cannot be empty."
exit 1
fi
echo ""
echo "Enter each node's name and listening address (format: name IP:Port)"
echo "Example: node1 0.0.0.0:8081"
echo "Leave name blank to finish."
declare -a NODE_NAMES
declare -a NODE_ADDRESSES
while true; do
read -p "Node name (blank to stop): " name
[[ -z "$name" ]] && break
read -p "Listening address (e.g., 0.0.0.0:8081): " address
if [[ -z "$address" ]]; then
err "Address cannot be empty, skipping."
continue
fi
NODE_NAMES+=("$name")
NODE_ADDRESSES+=("$address")
done
if [[ ${#NODE_NAMES[@]} -eq 0 ]]; then
err "No nodes provided."
exit 1
fi
# Validate listen ports before installing anything
local address
for address in "${NODE_ADDRESSES[@]}"; do
if ! check_listen_port "$address"; then
exit 1
fi
done
echo ""
echo "Will install ${#NODE_NAMES[@]} nodes in parallel:"
for i in "${!NODE_NAMES[@]}"; do
echo " - ${NODE_NAMES[$i]} -> ${NODE_ADDRESSES[$i]}"
done
read -p "Proceed? (y/N): " confirm
[[ ! "$confirm" =~ ^[Yy]$ ]] && { echo "Cancelled."; exit 0; }
echo ""
log "Starting parallel installations..."
declare -a INSTALL_PIDS
for i in "${!NODE_NAMES[@]}"; do
install_single_node "${NODE_NAMES[$i]}" "${NODE_ADDRESSES[$i]}" "$WALLARM_API_TOKEN" &
INSTALL_PIDS+=($!)
done
FAILED=0
local pid
for pid in "${INSTALL_PIDS[@]}"; do
wait "$pid" || ((FAILED++))
done
if [[ $FAILED -eq 0 ]]; then
log "All nodes installed and started via systemd."
else
err "$FAILED node(s) failed. Check individual install.log files."
fi
}
cmd_config() {
# Usage: --config --node NAME --address IP:PORT [--token TOKEN] [--labels LABELS]
check_root
local node_name="" address="" token="" labels=""
while [[ $# -gt 0 ]]; do
case "$1" in
--node) [[ $# -ge 2 ]] || { err "--node requires a value"; exit 1; }; node_name="$2"; shift 2 ;;
--address) [[ $# -ge 2 ]] || { err "--address requires a value"; exit 1; }; address="$2"; shift 2 ;;
--token) [[ $# -ge 2 ]] || { err "--token requires a value"; exit 1; }; token="$2"; shift 2 ;;
--labels) [[ $# -ge 2 ]] || { err "--labels requires a value"; exit 1; }; labels="$2"; shift 2 ;;
*) err "Unknown config option: $1"; exit 1 ;;
esac
done
if [[ -z "$node_name" ]]; then
err "Missing --node"
exit 1
fi
local work_dir="${NODES_DIR}/${node_name}"
if [[ ! -d "$work_dir" ]]; then
err "Node '$node_name' does not exist in ${NODES_DIR}"
exit 1
fi
# Update config file
if [[ -n "$address" ]]; then
if ! check_listen_port "$address"; then
exit 1
fi
log "Updating listening address to $address"
sed -i "s|^\([[:space:]]*address: \).*|\1\"${address}\"|" "${work_dir}/etc/go-node.yaml"
fi
# Update env file if token or labels provided (rewrite to avoid sed escaping issues)
if [[ -n "$token" || -n "$labels" ]]; then
local env_file="${work_dir}/env"
[[ -f "$env_file" ]] || { err "env file not found"; exit 1; }
local current_token current_labels
current_token=$(grep '^WALLARM_API_TOKEN=' "$env_file" | cut -d= -f2-)
current_labels=$(grep '^WALLARM_LABELS=' "$env_file" | cut -d= -f2-)
write_env_file "$node_name" "${token:-$current_token}" "${labels:-$current_labels}"
log "Token/labels updated for $node_name."
fi
log "Configuration updated for $node_name. Restart with: systemctl restart wallarm-node@${node_name}"
}
cmd_remove() {
check_root
local node_name=""
while [[ $# -gt 0 ]]; do
case "$1" in
--node) [[ $# -ge 2 ]] || { err "--node requires a value"; exit 1; }; node_name="$2"; shift 2 ;;
*) err "Unknown remove option: $1"; exit 1 ;;
esac
done
if [[ -z "$node_name" ]]; then
err "Missing --node"
exit 1
fi
local work_dir="${NODES_DIR}/${node_name}"
if [[ ! -d "$work_dir" ]]; then
err "Node '$node_name' does not exist."
exit 1
fi
log "Stopping and disabling service..."
systemctl stop "wallarm-node@${node_name}" 2>/dev/null || true
systemctl disable "wallarm-node@${node_name}" 2>/dev/null || true
log "Removing directory ${work_dir}..."
rm -rf "$work_dir"
log "Node $node_name removed."
}
cmd_status() {
# Show systemd status for all found nodes or a specific one
local node_name="${1:-}"
if [[ -n "$node_name" ]]; then
systemctl status "wallarm-node@${node_name}" --no-pager
else
echo "Wallarm Nodes status:"
local dir name
for dir in "${NODES_DIR}"/*/; do
if [[ -d "$dir" ]]; then
name=$(basename "$dir")
echo "--- $name ---"
systemctl status "wallarm-node@${name}" --no-pager | head -5
echo ""
fi
done
fi
}
# --- Help ---
show_help() {
cat <<EOF
Usage: $0 [COMMAND] [OPTIONS]
Commands:
--preflight Run preflight checks only (no installation).
--install Interactive installation of one or more nodes (parallel).
--config Update an existing node's configuration.
Options: --node NAME --address IP:PORT [--token TOKEN] [--labels LABELS]
--remove Remove a node completely.
Options: --node NAME
--status [NODE] Show systemd status for a node, or all nodes.
Environment:
WALLARM_INSTALLER_URL Override the all-in-one installer URL (default: repo.wallarm.com latest).
WALLARM_INSTALLER_ARCH Installer architecture suffix (default: x86_64).
Examples:
$0 --preflight
$0 --install
$0 --config --node node1 --address 0.0.0.0:9090
$0 --remove --node node2
$0 --status
EOF
}
# --- Main argument parsing ---
if [[ $# -eq 0 ]]; then
show_help
exit 0
fi
case "$1" in
--preflight) shift; cmd_preflight "$@" ;;
--install) shift; cmd_install "$@" ;;
--config) shift; cmd_config "$@" ;;
--remove) shift; cmd_remove "$@" ;;
--status) shift; cmd_status "$@" ;;
--help|-h) show_help ;;
*) err "Unknown command: $1"; show_help; exit 1 ;;
esac

114
setup.sh Normal file → Executable file
View file

@ -4,6 +4,13 @@
# ============================================================================== # ==============================================================================
# Downloads all necessary Wallarm deployment scripts from the Git repository # Downloads all necessary Wallarm deployment scripts from the Git repository
# and makes them executable. # and makes them executable.
#
# The repository supports two deployment types:
# 1. docker - Wallarm filtering node as a Docker container
# 2. native - Wallarm filtering node installed directly on the OS (no Docker)
#
# Usage: curl -fsSL "https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/setup.sh" | bash
# DEPLOYMENT_TYPE=native curl -fsSL ".../setup.sh" | bash (non-interactive)
# ============================================================================== # ==============================================================================
set -euo pipefail set -euo pipefail
@ -19,13 +26,23 @@ NC='\033[0m'
# Git repository URL base # Git repository URL base
GIT_BASE="https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/" GIT_BASE="https://git.sechpoint.app/customer-engineering/wallarm/raw/branch/main/"
SCRIPTS=(
# Per-deployment-type scripts
DOCKER_SCRIPTS=(
"wallarm-ct-check.sh" "wallarm-ct-check.sh"
"wallarm-ct-deploy.sh" "wallarm-ct-deploy.sh"
"wallarm-ct-reconfigure.sh" "wallarm-ct-reconfigure.sh"
"wallarm-ct-uninstall.sh" "wallarm-ct-uninstall.sh"
) )
NATIVE_SCRIPTS=(
"wallarm-ct-check.sh"
"wallarm-ct-deploy.sh"
"wallarm-ct-reconfigure.sh"
"wallarm-ct-uninstall.sh"
"wallarm-native.sh"
)
# Detect download command # Detect download command
if command -v curl >/dev/null 2>&1; then if command -v curl >/dev/null 2>&1; then
DOWNLOAD_CMD="curl -fL -O" DOWNLOAD_CMD="curl -fL -O"
@ -39,31 +56,43 @@ else
exit 1 exit 1
fi fi
download_script() { # Select the deployment type (interactive or via DEPLOYMENT_TYPE env var)
local script="$1" select_deployment_type() {
local url="${GIT_BASE}/${script}" if [[ "${DEPLOYMENT_TYPE:-}" =~ ^(docker|native)$ ]]; then
echo -e "${YELLOW}Downloading ${script}...${NC}" DEPLOY_TYPE="$DEPLOYMENT_TYPE"
if [ -f "$script" ]; then echo -e "${GREEN}Deployment type: $DEPLOY_TYPE${NC}"
echo -e "${YELLOW} File already exists. Overwrite? (y/N)${NC}"
read -r answer
if [[ ! "$answer" =~ ^[Yy]$ ]]; then
echo -e "${BLUE} Skipping.${NC}"
return 0 return 0
fi fi
rm -f "$script"
fi
echo -e "${CYAN}${BOLD}Select the deployment type:${NC}"
echo -e " 1. ${YELLOW}docker${NC} - Wallarm filtering node as a Docker container (LXC-optimized)"
echo -e " 2. ${YELLOW}native${NC} - Wallarm filtering node installed directly on the OS (no Docker)"
read -r -p "$(echo -e "${YELLOW}Enter choice [1/2] (default: docker): ${NC}")" choice
case "${choice:-1}" in
1|docker) DEPLOY_TYPE="docker" ;;
2|native) DEPLOY_TYPE="native" ;;
*) DEPLOY_TYPE="docker" ;;
esac
}
download_file() {
local url="$1"
local dest="$2"
local description="$3"
echo -e "${YELLOW}Downloading ${description}...${NC}"
if [ "$DOWNLOAD_NAME" = "curl" ]; then if [ "$DOWNLOAD_NAME" = "curl" ]; then
curl -fL "$url" -o "$script" curl -fL "$url" -o "$dest"
else else
wget -q "$url" -O "$script" wget -q "$url" -O "$dest"
fi fi
if [ $? -eq 0 ] && [ -s "$script" ]; then if [ -s "$dest" ]; then
chmod +x "$script" chmod +x "$dest"
echo -e "${GREEN} Success: ${script} downloaded and made executable.${NC}" echo -e "${GREEN} Success: ${description} downloaded to ${dest}${NC}"
else else
echo -e "${RED} Failed to download ${script}. Check network connectivity.${NC}" rm -f "$dest"
echo -e "${RED} Failed to download ${description}. Check network connectivity.${NC}"
exit 1 exit 1
fi fi
} }
@ -77,9 +106,17 @@ echo "║ Downloads all necessary deployment tools ║"
echo "╚══════════════════════════════════════════════════════════════╝${NC}" echo "╚══════════════════════════════════════════════════════════════╝${NC}"
echo echo
# Select deployment type
select_deployment_type
# Determine target directories
COMMON_DIR="common"
TARGET_DIR="$DEPLOY_TYPE"
echo -e "${BLUE}Target directory: ${TARGET_DIR}/${NC}"
# Check for existing scripts # Check for existing scripts
if ls wallarm-ct-*.sh 2>/dev/null | grep -q .; then if ls "$TARGET_DIR"/wallarm-ct-*.sh 2>/dev/null | grep -q .; then
echo -e "${YELLOW}Existing Wallarm scripts found.${NC}" echo -e "${YELLOW}Existing $DEPLOY_TYPE Wallarm scripts found.${NC}"
echo -e "${YELLOW}Do you want to re-download all? (y/N)${NC}" echo -e "${YELLOW}Do you want to re-download all? (y/N)${NC}"
read -r answer read -r answer
if [[ ! "$answer" =~ ^[Yy]$ ]]; then if [[ ! "$answer" =~ ^[Yy]$ ]]; then
@ -88,19 +125,40 @@ if ls wallarm-ct-*.sh 2>/dev/null | grep -q .; then
fi fi
fi fi
# Download each script # Select the script list for the chosen deployment type
case "$DEPLOY_TYPE" in
native) SCRIPTS=("${NATIVE_SCRIPTS[@]}") ;;
*) SCRIPTS=("${DOCKER_SCRIPTS[@]}") ;;
esac
# Create target directories
mkdir -p "$TARGET_DIR" "$COMMON_DIR"
# Download shared library
download_file "${GIT_BASE}common/wallarm-lib.sh" "${COMMON_DIR}/wallarm-lib.sh" "shared library (${COMMON_DIR}/wallarm-lib.sh)"
# Download the deployment type scripts
for script in "${SCRIPTS[@]}"; do for script in "${SCRIPTS[@]}"; do
download_script "$script" download_file "${GIT_BASE}${TARGET_DIR}/${script}" "${TARGET_DIR}/${script}" "$DEPLOY_TYPE/$script"
done done
echo echo
echo -e "${GREEN}${BOLD}All scripts downloaded successfully!${NC}" echo -e "${GREEN}${BOLD}All $DEPLOY_TYPE scripts downloaded successfully!${NC}"
echo echo
echo -e "${CYAN}Next steps:${NC}" if [ "$DEPLOY_TYPE" = "native" ]; then
echo -e " 1. Run the preflight check: ${YELLOW}./wallarm-ct-check.sh${NC}" echo -e "${CYAN}Next steps:${NC}"
echo -e " 2. Deploy a Wallarm node: ${YELLOW}./wallarm-ct-deploy.sh${NC}" echo -e " 1. Run the preflight check: ${YELLOW}./native/wallarm-ct-check.sh${NC}"
echo -e " 3. Reconfigure existing node: ${YELLOW}./wallarm-ct-reconfigure.sh${NC}" echo -e " 2. Deploy a Wallarm node: ${YELLOW}./native/wallarm-ct-deploy.sh${NC}"
echo -e " 4. Uninstall a node: ${YELLOW}./wallarm-ct-uninstall.sh${NC}" echo -e " 3. Unified node manager: ${YELLOW}./native/wallarm-native.sh --preflight${NC} (then --install)"
echo -e " 4. Reconfigure existing node: ${YELLOW}./native/wallarm-ct-reconfigure.sh${NC}"
echo -e " 5. Uninstall a node: ${YELLOW}./native/wallarm-ct-uninstall.sh${NC}"
else
echo -e "${CYAN}Next steps:${NC}"
echo -e " 1. Run the preflight check: ${YELLOW}./docker/wallarm-ct-check.sh${NC}"
echo -e " 2. Deploy a Wallarm node: ${YELLOW}./docker/wallarm-ct-deploy.sh${NC}"
echo -e " 3. Reconfigure existing node: ${YELLOW}./docker/wallarm-ct-reconfigure.sh${NC}"
echo -e " 4. Uninstall a node: ${YELLOW}./docker/wallarm-ct-uninstall.sh${NC}"
fi
echo echo
echo -e "${YELLOW}Note: Some scripts require sudo. Run them with: sudo ./<script>${NC}" echo -e "${YELLOW}Note: Some scripts require sudo. Run them with: sudo ./<script>${NC}"
echo -e "${YELLOW}Make sure you have the required information ready (see documentation).${NC}" echo -e "${YELLOW}Make sure you have the required information ready (see documentation).${NC}"