This commit is contained in:
Luftmensch
2026-08-26 14:11:37 +07:00
commit e528419f9a
135 changed files with 413970 additions and 0 deletions
+463
View File
@@ -0,0 +1,463 @@
#!/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