Files
audit-web/docker-service.sh
T
2026-08-26 14:11:37 +07:00

464 lines
13 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# =============================================================================
# Audit Hardening Tool - Docker Service Management Script
# =============================================================================
# Script quản lý Docker container cho Audit Hardening Tool
# Hỗ trợ workflow: Build trên máy có internet → Export → Load trên server dịch vụ
# Tương thích: Docker Compose V1 (docker-compose) & V2 (docker compose)
#
# Usage: ./docker-service.sh [command]
#
# Commands:
# build - Build Docker image
# start - Start container (docker compose up)
# stop - Stop container
# restart - Restart container
# status - Show container status
# logs - View container logs
# export - Export image to .tar file for offline deployment
# load - Load image from .tar file (on server without internet)
# clean - Remove container, image, and volumes
# help - Show this help message
# =============================================================================
set -e
# Configuration
IMAGE_NAME="audit-hardening-tool"
CONTAINER_NAME="audit-hardening-tool"
EXPORT_DIR="./docker-export"
COMPOSE_FILE="docker-compose.yml"
# Auto-detect Docker Compose version
# V2: "docker compose" (plugin) → COMPOSE_CMD="docker compose -f docker-compose.yml"
# V1: "docker-compose" (standalone) → COMPOSE_CMD="docker-compose -f docker-compose.yml"
detect_compose() {
if docker compose version >/dev/null 2>&1; then
COMPOSE_CMD="docker compose -f ${COMPOSE_FILE}"
COMPOSE_VER="V2 (plugin)"
elif command -v docker-compose >/dev/null 2>&1; then
COMPOSE_CMD="docker-compose -f ${COMPOSE_FILE}"
COMPOSE_VER="V1 (standalone)"
else
echo "ERROR: Neither 'docker compose' nor 'docker-compose' found!"
echo "Please install Docker Compose: https://docs.docker.com/compose/install/"
exit 1
fi
}
# Run detection at script start
detect_compose
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Print header
print_header() {
echo ""
echo -e "${CYAN}=========================================${NC}"
echo -e "${CYAN} Audit Hardening Tool - Docker Service${NC}"
echo -e "${CYAN}=========================================${NC}"
echo -e "${CYAN} Compose: ${COMPOSE_VER}${NC}"
echo ""
}
# Print success message
print_ok() {
echo -e "${GREEN}$1${NC}"
}
# Print error message
print_error() {
echo -e "${RED}$1${NC}"
}
# Print info message
print_info() {
echo -e "${BLUE} $1${NC}"
}
# Print warning message
print_warn() {
echo -e "${YELLOW}$1${NC}"
}
# ================================
# BUILD - Build Docker image
# ================================
cmd_build() {
print_header
echo -e "${BLUE}Building Docker image...${NC}"
echo ""
# Check Dockerfile exists
if [ ! -f "Dockerfile" ]; then
print_error "Dockerfile not found in current directory!"
exit 1
fi
$COMPOSE_CMD build --no-cache
echo ""
print_ok "Docker image built successfully!"
# Show image info
echo ""
echo -e "${CYAN}Image info:${NC}"
docker images | grep -E "REPOSITORY|${IMAGE_NAME}" || true
}
# ================================
# START - Start container
# ================================
cmd_start() {
print_header
echo -e "${BLUE}Starting container...${NC}"
echo ""
# Check required files exist
check_required_files
# If no Dockerfile present (offline server), skip build
if [ -f "Dockerfile" ]; then
$COMPOSE_CMD up -d
else
print_info "No Dockerfile found - using pre-loaded image (offline mode)"
$COMPOSE_CMD up -d --no-build
fi
echo ""
print_ok "Container started successfully!"
echo ""
# Show status
$COMPOSE_CMD ps
echo ""
print_info "Access the application at: http://localhost:8888/audit/"
print_info "View logs with: $0 logs"
}
# ================================
# STOP - Stop container
# ================================
cmd_stop() {
print_header
echo -e "${BLUE}Stopping container...${NC}"
echo ""
$COMPOSE_CMD down
echo ""
print_ok "Container stopped successfully!"
}
# ================================
# RESTART - Restart container
# ================================
cmd_restart() {
print_header
echo -e "${BLUE}Restarting container...${NC}"
echo ""
$COMPOSE_CMD restart
echo ""
print_ok "Container restarted successfully!"
echo ""
$COMPOSE_CMD ps
}
# ================================
# STATUS - Show container status
# ================================
cmd_status() {
print_header
echo -e "${CYAN}Container status:${NC}"
echo ""
$COMPOSE_CMD ps
echo ""
# Show resource usage if running
if docker ps --format "{{.Names}}" | grep -q "$CONTAINER_NAME"; then
echo -e "${CYAN}Resource usage:${NC}"
docker stats --no-stream "$CONTAINER_NAME" 2>/dev/null || true
fi
}
# ================================
# LOGS - View container logs
# ================================
cmd_logs() {
print_header
echo -e "${CYAN}Container logs (last 100 lines, follow mode):${NC}"
echo -e "${YELLOW}Press Ctrl+C to stop following...${NC}"
echo ""
$COMPOSE_CMD logs --tail=100 -f
}
# ================================
# EXPORT - Export image to .tar
# ================================
cmd_export() {
print_header
echo -e "${BLUE}Exporting Docker image for offline deployment...${NC}"
echo ""
# Check if image exists - try to get image name from compose config
IMAGE_FULL=$($COMPOSE_CMD config --images 2>/dev/null | head -1) || true
if [ -z "$IMAGE_FULL" ]; then
# Fallback: try to find image by name pattern
IMAGE_FULL=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "${IMAGE_NAME}" | head -1) || true
fi
if [ -z "$IMAGE_FULL" ]; then
IMAGE_FULL="${IMAGE_NAME}:latest"
fi
if ! docker image inspect "$IMAGE_FULL" > /dev/null 2>&1; then
print_warn "Image not found. Building first..."
cmd_build
echo ""
# Re-detect image name after build
IMAGE_FULL=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "${IMAGE_NAME}" | head -1) || true
if [ -z "$IMAGE_FULL" ]; then
IMAGE_FULL="${IMAGE_NAME}:latest"
fi
fi
# Create export directory
mkdir -p "$EXPORT_DIR"
# Generate filename with timestamp
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
EXPORT_FILE="${EXPORT_DIR}/${IMAGE_NAME}_${TIMESTAMP}.tar"
echo -e "${CYAN}Saving image: ${IMAGE_FULL}${NC}"
echo -e "${CYAN}Export file: ${EXPORT_FILE}${NC}"
echo ""
docker save -o "$EXPORT_FILE" "$IMAGE_FULL"
# Show file size
FILE_SIZE=$(du -h "$EXPORT_FILE" | cut -f1)
echo ""
print_ok "Image exported successfully!"
echo ""
echo -e "${CYAN}Export details:${NC}"
echo -e " File: ${EXPORT_FILE}"
echo -e " Size: ${FILE_SIZE}"
echo ""
echo -e "${YELLOW}=== HƯỚNG DẪN DEPLOY OFFLINE ===${NC}"
echo ""
echo "1. Copy các file sau lên server dịch vụ:"
echo " - ${EXPORT_FILE}"
echo " - docker-compose.yml"
echo " - docker-service.sh"
echo " - app/ (thư mục source code của ứng dụng)"
echo " - config/ (thư mục chứa checklist + config)"
echo " - keys/ (thư mục chứa private/public key)"
echo " - tools/ (thư mục chứa hardening tools)"
echo " - radius_config.json"
echo " - email_config.json"
echo " - unit_mapping.json"
echo ""
echo "2. Trên server dịch vụ, chạy:"
echo " ./docker-service.sh load ${EXPORT_FILE}"
echo " ./docker-service.sh start"
echo ""
}
# ================================
# LOAD - Load image from .tar
# ================================
cmd_load() {
print_header
TAR_FILE="$1"
# If no file specified, find the latest .tar in export dir
if [ -z "$TAR_FILE" ]; then
if [ -d "$EXPORT_DIR" ]; then
TAR_FILE=$(ls -t "${EXPORT_DIR}"/*.tar 2>/dev/null | head -1)
fi
fi
if [ -z "$TAR_FILE" ] || [ ! -f "$TAR_FILE" ]; then
print_error "No .tar file specified or found!"
echo ""
echo "Usage: $0 load <path-to-image.tar>"
echo ""
echo "Example:"
echo " $0 load ./docker-export/audit-hardening-tool_20260408.tar"
exit 1
fi
FILE_SIZE=$(du -h "$TAR_FILE" | cut -f1)
echo -e "${BLUE}Loading Docker image from: ${TAR_FILE} (${FILE_SIZE})${NC}"
echo ""
docker load -i "$TAR_FILE"
echo ""
print_ok "Image loaded successfully!"
echo ""
# Show loaded image
echo -e "${CYAN}Available images:${NC}"
docker images | grep -E "REPOSITORY|${IMAGE_NAME}" || true
echo ""
print_info "Now start the container with: $0 start"
}
# ================================
# CLEAN - Remove everything
# ================================
cmd_clean() {
print_header
echo -e "${RED}WARNING: This will remove the container, image, and dangling volumes!${NC}"
echo ""
read -p "Are you sure? (y/N): " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo "Cancelled."
exit 0
fi
echo ""
echo -e "${BLUE}Stopping and removing container...${NC}"
$COMPOSE_CMD down --rmi local --remove-orphans 2>/dev/null || true
echo ""
print_ok "Cleanup completed!"
}
# ================================
# CHECK REQUIRED FILES
# ================================
check_required_files() {
local has_error=false
if [ ! -d "app" ]; then
print_error "Directory 'app/' not found! Ensure application source code is available."
has_error=true
fi
if [ ! -d "config" ]; then
print_error "Directory 'config/' not found!"
has_error=true
fi
if [ ! -d "keys" ]; then
print_error "Directory 'keys/' not found!"
has_error=true
fi
if [ ! -f "users_config.json" ]; then
print_warn "users_config.json not found (will use defaults)"
fi
if [ ! -f "radius_config.json" ]; then
print_warn "radius_config.json not found (RADIUS auth disabled)"
fi
if [ ! -f "email_config.json" ]; then
print_warn "email_config.json not found (email notifications disabled)"
fi
if [ ! -f "unit_mapping.json" ]; then
print_warn "unit_mapping.json not found (using default unit mapping)"
fi
if [ ! -d "tools" ]; then
print_warn "Directory 'tools/' not found (hardening tools won't be available)"
fi
if $has_error; then
print_error "Required files missing. Cannot start!"
exit 1
fi
}
# ================================
# HELP - Show help message
# ================================
cmd_help() {
print_header
echo "Usage: $0 [command] [options]"
echo ""
echo -e "${CYAN}Commands:${NC}"
echo -e " ${GREEN}build${NC} Build Docker image"
echo -e " ${GREEN}start${NC} Start container (docker compose up -d)"
echo -e " ${GREEN}stop${NC} Stop container"
echo -e " ${GREEN}restart${NC} Restart container"
echo -e " ${GREEN}status${NC} Show container status & resource usage"
echo -e " ${GREEN}logs${NC} View container logs (follow mode)"
echo -e " ${GREEN}export${NC} Export image to .tar for offline deployment"
echo -e " ${GREEN}load${NC} [file.tar] Load image from .tar file"
echo -e " ${GREEN}clean${NC} Remove container, image, and volumes"
echo -e " ${GREEN}help${NC} Show this help message"
echo ""
echo -e "${CYAN}Offline Deployment Workflow:${NC}"
echo -e " ${YELLOW}Máy có internet:${NC}"
echo " 1. $0 build # Build image"
echo " 2. $0 export # Export thành file .tar"
echo ""
echo -e " ${YELLOW}Server dịch vụ (không internet):${NC}"
echo " 1. Copy file .tar + các file config lên server"
echo " 2. $0 load file.tar # Load image từ .tar"
echo " 3. $0 start # Chạy container"
echo ""
echo -e "${CYAN}Required files for deployment:${NC}"
echo " app/ Application source code"
echo " config/ Checklist & config files (ro)"
echo " keys/ RSA keys (ro)"
echo " tools/ Hardening tools (rw)"
echo " users_config.json User whitelist (ro)"
echo " radius_config.json RADIUS config (ro)"
echo " email_config.json Email config (ro)"
echo " unit_mapping.json Unit mapping config (ro)"
echo " docker-compose.yml Docker Compose config"
echo ""
}
# ================================
# MAIN - Entry point
# ================================
case "${1:-help}" in
build)
cmd_build
;;
start)
cmd_start
;;
stop)
cmd_stop
;;
restart)
cmd_restart
;;
status)
cmd_status
;;
logs)
cmd_logs
;;
export)
cmd_export
;;
load)
cmd_load "$2"
;;
clean)
cmd_clean
;;
help|--help|-h)
cmd_help
;;
*)
print_error "Unknown command: $1"
echo ""
cmd_help
exit 1
;;
esac