Phase 2: Core API Development - 15 REST API endpoints (packages, patches, system, jobs, websocket) - mTLS authentication layer (src/auth/mtls.rs) - IP whitelist enforcement (src/auth/whitelist.rs) - Job manager with async operation support - WebSocket streaming for job status Phase 3: Security Hardening - Security testing: 16/16 tests passing - Fuzz testing: 21 tests, all findings resolved - Threat model validation (STRIDE matrix) - TLS binding fix (critical vulnerability resolved) - Security documentation complete Phase 4: Production Readiness - Performance benchmarking (all targets met) - Package creation (.deb/.rpm structures) - Documentation (README, API docs, deployment guide) - Security hardening (6 vulnerabilities fixed) Deliverables: - API_DOCUMENTATION.md (889 lines) - DEPLOYMENT_GUIDE.md (733 lines) - SECURITY.md (346 lines) - README.md (525 lines) - debian/ package structure - linux-patch-api.spec (RPM) - install.sh installer script - benches/api_benchmarks.rs - Multiple security/performance reports Security Status: 0 vulnerabilities remaining Test Coverage: 31 unit tests, 21 integration tests Build Status: Release optimized
331 lines
9.9 KiB
Bash
Executable File
331 lines
9.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# Linux Patch API - Interactive Installation Script
|
|
# For manual deployment on systems without package manager
|
|
# Supports Debian/Ubuntu, RHEL/CentOS/Fedora, Alpine, Arch
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Configuration
|
|
APP_NAME="linux-patch-api"
|
|
VERSION="1.0.0"
|
|
INSTALL_DIR="/usr/bin"
|
|
CONFIG_DIR="/etc/linux_patch_api"
|
|
CERTS_DIR="${CONFIG_DIR}/certs"
|
|
DATA_DIR="/var/lib/linux_patch_api"
|
|
LOG_DIR="/var/log/linux_patch_api"
|
|
SERVICE_FILE="/lib/systemd/system/linux-patch-api.service"
|
|
SYSTEM_USER="linux-patch-api"
|
|
SYSTEM_GROUP="linux-patch-api"
|
|
|
|
# Logging functions
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
}
|
|
|
|
log_warning() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
# Check if running as root
|
|
check_root() {
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
log_error "This script must be run as root"
|
|
exit 1
|
|
fi
|
|
log_info "Running as root - OK"
|
|
}
|
|
|
|
# Detect OS and package manager
|
|
detect_os() {
|
|
if [ -f /etc/os-release ]; then
|
|
. /etc/os-release
|
|
OS_ID=$ID
|
|
OS_VERSION=$VERSION_ID
|
|
log_info "Detected OS: ${OS_ID} ${OS_VERSION}"
|
|
else
|
|
log_error "Cannot detect operating system"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Check prerequisites
|
|
check_prerequisites() {
|
|
log_info "Checking prerequisites..."
|
|
|
|
# Check for systemd
|
|
if ! command -v systemctl &> /dev/null; then
|
|
log_error "systemd is required but not found"
|
|
exit 1
|
|
fi
|
|
log_info " - systemd: OK"
|
|
|
|
# Check for required directories
|
|
log_info " - Checking directory structure..."
|
|
|
|
# Check if binary exists
|
|
if [ -f "target/x86_64-unknown-linux-gnu/release/${APP_NAME}" ]; then
|
|
BINARY_PATH="target/x86_64-unknown-linux-gnu/release/${APP_NAME}"
|
|
log_info " - Binary found: ${BINARY_PATH}"
|
|
elif [ -f "target/release/${APP_NAME}" ]; then
|
|
BINARY_PATH="target/release/${APP_NAME}"
|
|
log_info " - Binary found: ${BINARY_PATH}"
|
|
else
|
|
log_error "Binary not found. Please build first with: cargo build --release"
|
|
exit 1
|
|
fi
|
|
|
|
log_success "Prerequisites check passed"
|
|
}
|
|
|
|
# Create system user and group
|
|
create_system_user() {
|
|
log_info "Creating system user and group..."
|
|
|
|
# Create group if it doesn't exist
|
|
if ! getent group ${SYSTEM_GROUP} > /dev/null 2>&1; then
|
|
groupadd --system ${SYSTEM_GROUP}
|
|
log_info " - Created group: ${SYSTEM_GROUP}"
|
|
else
|
|
log_info " - Group already exists: ${SYSTEM_GROUP}"
|
|
fi
|
|
|
|
# Create user if it doesn't exist
|
|
if ! getent passwd ${SYSTEM_USER} > /dev/null 2>&1; then
|
|
useradd --system \
|
|
--gid ${SYSTEM_GROUP} \
|
|
--home-dir ${DATA_DIR} \
|
|
--no-create-home \
|
|
--shell /usr/sbin/nologin \
|
|
--comment "Linux Patch API Service" \
|
|
${SYSTEM_USER}
|
|
log_info " - Created user: ${SYSTEM_USER}"
|
|
else
|
|
log_info " - User already exists: ${SYSTEM_USER}"
|
|
fi
|
|
}
|
|
|
|
# Create directory structure
|
|
create_directories() {
|
|
log_info "Creating directory structure..."
|
|
|
|
mkdir -p ${CONFIG_DIR}
|
|
mkdir -p ${CERTS_DIR}
|
|
mkdir -p ${DATA_DIR}
|
|
mkdir -p ${LOG_DIR}
|
|
|
|
# Set ownership
|
|
chown -R ${SYSTEM_USER}:${SYSTEM_GROUP} ${DATA_DIR}
|
|
chown -R ${SYSTEM_USER}:${SYSTEM_GROUP} ${LOG_DIR}
|
|
chown -R ${SYSTEM_USER}:${SYSTEM_GROUP} ${CONFIG_DIR}
|
|
|
|
# Set permissions
|
|
chmod 750 ${CONFIG_DIR}
|
|
chmod 750 ${CERTS_DIR}
|
|
chmod 755 ${DATA_DIR}
|
|
chmod 755 ${LOG_DIR}
|
|
|
|
log_success "Directory structure created"
|
|
}
|
|
|
|
# Install binary
|
|
install_binary() {
|
|
log_info "Installing binary to ${INSTALL_DIR}..."
|
|
|
|
cp ${BINARY_PATH} ${INSTALL_DIR}/${APP_NAME}
|
|
chmod 755 ${INSTALL_DIR}/${APP_NAME}
|
|
|
|
log_success "Binary installed: ${INSTALL_DIR}/${APP_NAME}"
|
|
}
|
|
|
|
# Install configuration files
|
|
install_config() {
|
|
log_info "Installing configuration files..."
|
|
|
|
# Copy example configs if they don't exist
|
|
if [ ! -f "${CONFIG_DIR}/config.yaml" ]; then
|
|
if [ -f "configs/config.yaml.example" ]; then
|
|
cp configs/config.yaml.example ${CONFIG_DIR}/config.yaml
|
|
chmod 640 ${CONFIG_DIR}/config.yaml
|
|
log_info " - Created default config.yaml"
|
|
else
|
|
log_warning " - config.yaml.example not found"
|
|
fi
|
|
else
|
|
log_info " - config.yaml already exists"
|
|
fi
|
|
|
|
if [ ! -f "${CONFIG_DIR}/whitelist.yaml" ]; then
|
|
if [ -f "configs/whitelist.yaml.example" ]; then
|
|
cp configs/whitelist.yaml.example ${CONFIG_DIR}/whitelist.yaml
|
|
chmod 640 ${CONFIG_DIR}/whitelist.yaml
|
|
log_info " - Created default whitelist.yaml"
|
|
else
|
|
log_warning " - whitelist.yaml.example not found"
|
|
fi
|
|
else
|
|
log_info " - whitelist.yaml already exists"
|
|
fi
|
|
|
|
log_success "Configuration files installed"
|
|
}
|
|
|
|
# Install systemd service
|
|
install_service() {
|
|
log_info "Installing systemd service..."
|
|
|
|
if [ -f "configs/linux-patch-api.service" ]; then
|
|
cp configs/linux-patch-api.service ${SERVICE_FILE}
|
|
chmod 644 ${SERVICE_FILE}
|
|
systemctl daemon-reload
|
|
log_success "Systemd service installed"
|
|
else
|
|
log_error "Service file not found: configs/linux-patch-api.service"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Generate self-signed certificates (optional)
|
|
generate_certificates() {
|
|
log_info "Checking for TLS certificates..."
|
|
|
|
if [ ! -f "${CERTS_DIR}/server.pem" ] || [ ! -f "${CERTS_DIR}/server.key.pem" ]; then
|
|
echo ""
|
|
echo -e "${YELLOW}No TLS certificates found.${NC}"
|
|
read -p "Generate self-signed certificates for testing? (y/n): " -n 1 -r
|
|
echo ""
|
|
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
log_info "Generating self-signed certificates..."
|
|
|
|
# Generate CA
|
|
openssl genrsa -out ${CERTS_DIR}/ca.key.pem 4096
|
|
openssl req -x509 -new -nodes -sha256 -days 3650 \
|
|
-key ${CERTS_DIR}/ca.key.pem \
|
|
-out ${CERTS_DIR}/ca.pem \
|
|
-subj "/CN=Linux Patch API CA"
|
|
|
|
# Generate server key and CSR
|
|
openssl genrsa -out ${CERTS_DIR}/server.key.pem 2048
|
|
openssl req -new \
|
|
-key ${CERTS_DIR}/server.key.pem \
|
|
-out ${CERTS_DIR}/server.csr.pem \
|
|
-subj "/CN=localhost"
|
|
|
|
# Sign server certificate
|
|
openssl x509 -req -sha256 -days 365 \
|
|
-in ${CERTS_DIR}/server.csr.pem \
|
|
-CA ${CERTS_DIR}/ca.pem \
|
|
-CAkey ${CERTS_DIR}/ca.key.pem \
|
|
-CAcreateserial \
|
|
-out ${CERTS_DIR}/server.pem
|
|
|
|
# Set secure permissions
|
|
chmod 600 ${CERTS_DIR}/*.key.pem
|
|
chmod 644 ${CERTS_DIR}/*.pem
|
|
chown -R ${SYSTEM_USER}:${SYSTEM_GROUP} ${CERTS_DIR}
|
|
|
|
log_success "Self-signed certificates generated"
|
|
log_warning "NOTE: Self-signed certificates are for testing only. Use proper CA-signed certs in production."
|
|
else
|
|
log_warning "Skipping certificate generation. Please place certificates in ${CERTS_DIR} manually."
|
|
fi
|
|
else
|
|
log_info " - Certificates already exist"
|
|
fi
|
|
}
|
|
|
|
# Enable and start service
|
|
enable_service() {
|
|
echo ""
|
|
read -p "Enable and start the service now? (y/n): " -n 1 -r
|
|
echo ""
|
|
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
log_info "Enabling service..."
|
|
systemctl enable ${APP_NAME}.service
|
|
|
|
log_info "Starting service..."
|
|
systemctl start ${APP_NAME}.service
|
|
|
|
# Check service status
|
|
if systemctl is-active --quiet ${APP_NAME}.service; then
|
|
log_success "Service started successfully"
|
|
systemctl status ${APP_NAME}.service --no-pager
|
|
else
|
|
log_error "Service failed to start. Check logs: journalctl -u ${APP_NAME}"
|
|
exit 1
|
|
fi
|
|
else
|
|
log_info "Service not started. You can start it later with: systemctl start ${APP_NAME}"
|
|
fi
|
|
}
|
|
|
|
# Display installation summary
|
|
display_summary() {
|
|
echo ""
|
|
echo -e "${GREEN}========================================${NC}"
|
|
echo -e "${GREEN} Linux Patch API Installation Complete${NC}"
|
|
echo -e "${GREEN}========================================${NC}"
|
|
echo ""
|
|
echo -e "Version: ${VERSION}"
|
|
echo -e "Binary: ${INSTALL_DIR}/${APP_NAME}"
|
|
echo -e "Config: ${CONFIG_DIR}/config.yaml"
|
|
echo -e "Whitelist: ${CONFIG_DIR}/whitelist.yaml"
|
|
echo -e "Certificates: ${CERTS_DIR}/"
|
|
echo -e "Data: ${DATA_DIR}/"
|
|
echo -e "Logs: ${LOG_DIR}/"
|
|
echo -e "Service: ${APP_NAME}.service"
|
|
echo ""
|
|
echo -e "${YELLOW}Next Steps:${NC}"
|
|
echo " 1. Review and configure ${CONFIG_DIR}/config.yaml"
|
|
echo " 2. Configure IP whitelist in ${CONFIG_DIR}/whitelist.yaml"
|
|
echo " 3. Replace self-signed certificates with CA-signed certs for production"
|
|
echo " 4. Start service: systemctl start ${APP_NAME}"
|
|
echo " 5. Check status: systemctl status ${APP_NAME}"
|
|
echo " 6. View logs: journalctl -u ${APP_NAME} -f"
|
|
echo ""
|
|
echo -e "API Endpoint: https://localhost:12443/api/v1/"
|
|
echo ""
|
|
}
|
|
|
|
# Main installation flow
|
|
main() {
|
|
echo ""
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE} Linux Patch API Installer v${VERSION}${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo ""
|
|
|
|
check_root
|
|
detect_os
|
|
check_prerequisites
|
|
create_system_user
|
|
create_directories
|
|
install_binary
|
|
install_config
|
|
install_service
|
|
generate_certificates
|
|
enable_service
|
|
display_summary
|
|
|
|
log_success "Installation completed successfully!"
|
|
}
|
|
|
|
# Run main function
|
|
main "$@"
|