在現代軟體開發生命週期中,安全性已經從傳統的事後檢測轉變為開發流程中不可或缺的一環。DevSecOps 理念強調將安全實踐融入開發和營運的每個階段,而 Bash 指令碼作為 Linux 環境中最強大的自動化工具之一,為實現這一目標提供了靈活且高效的手段。本文將深入探討如何運用 Bash 指令碼來強化 DevSecOps 流程,涵蓋 GitLab CI/CD 整合安全掃描、建置即時安全監控系統,以及自動化建置客製化 Kali Linux 系統等關鍵主題,並透過完整的程式碼範例展示這些技術在實務中的應用。
DevSecOps 安全自動化架構
在開始探討具體的實作細節之前,我們需要先理解 DevSecOps 安全自動化的整體架構。一個完善的 DevSecOps 流程應該包含程式碼提交時的安全掃描、執行時的安全監控,以及測試環境的標準化建置等多個面向。
@startuml
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100
rectangle "DevSecOps 安全自動化架構" {
rectangle "程式碼安全" as CS {
rectangle "靜態分析" as SA
rectangle "依賴檢查" as DC
rectangle "密碼掃描" as SS
}
rectangle "CI/CD 整合" as CI {
rectangle "GitLab Runner" as GR
rectangle "安全掃描管線" as SP
rectangle "報告生成" as RG
}
rectangle "即時監控" as RM {
rectangle "日誌分析" as LA
rectangle "異常偵測" as AD
rectangle "警示通知" as AN
}
rectangle "測試環境" as TE {
rectangle "Kali Linux 建置" as KB
rectangle "工具自動化" as TA
rectangle "環境標準化" as ES
}
rectangle "安全報告" as SR {
rectangle "弱點報告" as VR
rectangle "合規檢查" as CC
rectangle "風險評估" as RA
}
}
CS --> CI : 觸發掃描
CI --> SR : 生成報告
RM --> AN : 發送警示
TE --> CS : 滲透測試
SP --> LA : 日誌收集
@enduml這個架構展示了 DevSecOps 安全自動化的各個核心元件。程式碼安全層負責在開發階段進行各種靜態分析和安全檢查。CI/CD 整合層將這些安全檢查自動化並整合到持續整合流程中。即時監控層負責在系統運作期間偵測異常活動並發送警示。測試環境層提供標準化的滲透測試環境。安全報告層則彙整所有安全檢查的結果,提供完整的安全態勢視圖。
GitLab CI/CD 安全掃描整合
將安全掃描整合到 CI/CD 流程是 DevSecOps 的核心實踐之一。透過自動化的安全掃描,每次程式碼提交都會觸發安全檢查,確保問題能夠在早期被發現和修復。GitLab 提供了豐富的 CI/CD 功能,配合適當的安全掃描工具,可以建立完整的安全掃描管線。
首先,我們需要準備專案環境並建立 GitLab Runner。以下的 Bash 指令碼展示了如何自動化這個過程:
#!/usr/bin/env bash
# DevSecOps GitLab 專案初始化指令碼
# 此指令碼用於設定 GitLab 專案並整合安全掃描工具
set -euo pipefail
# 顏色定義用於輸出格式化
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# 日誌函式
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 檢查必要工具是否已安裝
check_prerequisites() {
log_info "檢查必要工具..."
local tools=("git" "curl" "docker" "jq")
for tool in "${tools[@]}"; do
if ! command -v "$tool" &> /dev/null; then
log_error "找不到 $tool,請先安裝此工具"
exit 1
fi
done
log_info "所有必要工具已就緒"
}
# 初始化專案結構
initialize_project() {
local project_name=$1
local project_dir="./$project_name"
log_info "初始化專案: $project_name"
# 建立專案目錄結構
mkdir -p "$project_dir"/{src,tests,reports,scripts}
# 建立 .gitignore 檔案
# 排除敏感檔案和建置產物
cat > "$project_dir/.gitignore" << 'EOF'
# 環境變數和敏感資訊
.env
*.pem
*.key
credentials.json
# 建置產物
__pycache__/
*.pyc
node_modules/
dist/
build/
# 報告目錄
reports/*.html
reports/*.json
# 日誌檔案
*.log
EOF
# 建立 reports 目錄的 .gitkeep 檔案
# 這確保空目錄也會被 Git 追蹤
touch "$project_dir/reports/.gitkeep"
log_info "專案結構已建立"
}
# 建立 GitLab CI/CD 配置檔
create_gitlab_ci_config() {
local project_dir=$1
log_info "建立 GitLab CI/CD 配置..."
# 建立完整的 .gitlab-ci.yml 配置檔
# 此配置包含多個安全掃描階段
cat > "$project_dir/.gitlab-ci.yml" << 'EOF'
# DevSecOps 安全掃描管線配置
stages:
- build
- security-scan
- test
- deploy
variables:
# 設定 Docker 映像標籤
DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
# 安全掃描報告目錄
SECURITY_REPORTS_DIR: reports
# 建置 Docker 映像
build:
stage: build
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $DOCKER_IMAGE .
- docker push $DOCKER_IMAGE
only:
- main
- merge_requests
# 靜態應用安全測試 (SAST)
sast_scan:
stage: security-scan
image: python:3.11
before_script:
- pip install bandit safety
script:
# 使用 Bandit 進行 Python 程式碼安全分析
- bandit -r src/ -f json -o $SECURITY_REPORTS_DIR/bandit-report.json || true
# 使用 Safety 檢查依賴套件的已知弱點
- safety check --json > $SECURITY_REPORTS_DIR/safety-report.json || true
artifacts:
paths:
- $SECURITY_REPORTS_DIR/
expire_in: 30 days
# 密碼和敏感資訊掃描
secret_scan:
stage: security-scan
image: trufflesecurity/trufflehog:latest
script:
# 使用 TruffleHog 掃描程式碼中的敏感資訊
- trufflehog filesystem --directory=. --json > $SECURITY_REPORTS_DIR/secrets-report.json || true
artifacts:
paths:
- $SECURITY_REPORTS_DIR/
expire_in: 30 days
# 容器映像弱點掃描
container_scan:
stage: security-scan
image: aquasec/trivy:latest
script:
# 使用 Trivy 掃描容器映像中的弱點
- trivy image --format json --output $SECURITY_REPORTS_DIR/trivy-report.json $DOCKER_IMAGE
artifacts:
paths:
- $SECURITY_REPORTS_DIR/
expire_in: 30 days
dependencies:
- build
# 動態應用安全測試 (DAST)
dast_scan:
stage: security-scan
image: owasp/zap2docker-stable
script:
# 使用 OWASP ZAP 進行動態安全測試
- mkdir -p $SECURITY_REPORTS_DIR
- zap-baseline.py -t $APP_URL -J $SECURITY_REPORTS_DIR/zap-report.json || true
artifacts:
paths:
- $SECURITY_REPORTS_DIR/
expire_in: 30 days
only:
- main
# 單元測試
unit_tests:
stage: test
image: python:3.11
script:
- pip install -r requirements.txt
- pytest tests/ --junitxml=reports/pytest-report.xml
artifacts:
reports:
junit: reports/pytest-report.xml
# 安全報告彙整
security_report:
stage: deploy
image: python:3.11
script:
- python scripts/aggregate_security_reports.py
artifacts:
paths:
- $SECURITY_REPORTS_DIR/
expire_in: 90 days
dependencies:
- sast_scan
- secret_scan
- container_scan
EOF
log_info "GitLab CI/CD 配置已建立"
}
# 建立安全報告彙整指令碼
create_report_aggregator() {
local project_dir=$1
log_info "建立安全報告彙整指令碼..."
mkdir -p "$project_dir/scripts"
# 建立 Python 指令碼用於彙整所有安全掃描報告
cat > "$project_dir/scripts/aggregate_security_reports.py" << 'EOF'
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
安全報告彙整工具
此指令碼用於彙整各種安全掃描工具產生的報告
"""
import json
import os
from datetime import datetime
from pathlib import Path
def load_json_report(filepath):
"""載入 JSON 格式的報告檔案"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
return json.load(f)
except (FileNotFoundError, json.JSONDecodeError) as e:
print(f"無法載入報告 {filepath}: {e}")
return None
def aggregate_reports(reports_dir):
"""彙整所有安全掃描報告"""
reports_path = Path(reports_dir)
aggregated = {
'timestamp': datetime.now().isoformat(),
'summary': {
'total_issues': 0,
'high_severity': 0,
'medium_severity': 0,
'low_severity': 0
},
'reports': {}
}
# 處理 Bandit 報告
bandit_report = load_json_report(reports_path / 'bandit-report.json')
if bandit_report:
bandit_issues = bandit_report.get('results', [])
aggregated['reports']['bandit'] = {
'tool': 'Bandit',
'description': 'Python 程式碼安全分析',
'issues_count': len(bandit_issues),
'issues': bandit_issues
}
aggregated['summary']['total_issues'] += len(bandit_issues)
# 處理 Safety 報告
safety_report = load_json_report(reports_path / 'safety-report.json')
if safety_report:
safety_issues = safety_report.get('vulnerabilities', [])
aggregated['reports']['safety'] = {
'tool': 'Safety',
'description': '依賴套件弱點檢查',
'issues_count': len(safety_issues),
'issues': safety_issues
}
aggregated['summary']['total_issues'] += len(safety_issues)
# 處理 Trivy 報告
trivy_report = load_json_report(reports_path / 'trivy-report.json')
if trivy_report:
trivy_results = trivy_report.get('Results', [])
trivy_issues = []
for result in trivy_results:
trivy_issues.extend(result.get('Vulnerabilities', []))
aggregated['reports']['trivy'] = {
'tool': 'Trivy',
'description': '容器映像弱點掃描',
'issues_count': len(trivy_issues),
'issues': trivy_issues
}
aggregated['summary']['total_issues'] += len(trivy_issues)
# 寫入彙整報告
output_path = reports_path / 'aggregated-security-report.json'
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(aggregated, f, indent=2, ensure_ascii=False)
print(f"安全報告已彙整至 {output_path}")
print(f"發現問題總數: {aggregated['summary']['total_issues']}")
if __name__ == '__main__':
aggregate_reports('reports')
EOF
chmod +x "$project_dir/scripts/aggregate_security_reports.py"
log_info "報告彙整指令碼已建立"
}
# 主程式
main() {
local project_name="${1:-devsecops-demo}"
log_info "開始 DevSecOps 專案初始化..."
check_prerequisites
initialize_project "$project_name"
create_gitlab_ci_config "$project_name"
create_report_aggregator "$project_name"
log_info "專案初始化完成"
log_info "請執行以下命令完成 Git 初始化:"
echo ""
echo " cd $project_name"
echo " git init"
echo " git add ."
echo " git commit -m 'Initial DevSecOps project setup'"
echo ""
}
main "$@"
這個指令碼展示了如何自動化建立一個完整的 DevSecOps 專案結構。它包含了專案初始化、GitLab CI/CD 配置建立,以及安全報告彙整指令碼的生成。GitLab CI/CD 配置檔定義了多個安全掃描階段,包括靜態應用安全測試(SAST)、密碼掃描、容器映像弱點掃描和動態應用安全測試(DAST)。這些掃描會在每次程式碼提交時自動執行,確保安全問題能夠及早發現。
即時安全監控系統
除了在開發階段進行安全掃描之外,在系統運作期間進行即時監控也是 DevSecOps 的重要組成部分。即時監控系統能夠偵測異常活動並及時發送警示,讓安全團隊能夠快速回應潛在的安全威脅。
以下的 Bash 指令碼展示了如何建立一個完整的安全監控系統,它監控系統日誌中的可疑活動並在偵測到異常時發送警示:
#!/usr/bin/env bash
# DevSecOps 即時安全監控系統
# 此指令碼監控系統日誌中的安全事件並發送警示
set -euo pipefail
# 確保以 root 身份執行
if [[ $EUID -ne 0 ]]; then
echo "此指令碼必須以 root 身份執行"
exit 1
fi
# 配置變數
# 失敗登入嘗試的閾值
FAILED_LOGIN_THRESHOLD=5
# 檢查間隔(秒)
CHECK_INTERVAL=300
# 警示電子郵件地址
ALERT_EMAIL="security@example.com"
# 日誌檔案位置
declare -A LOG_FILES=(
["auth"]="/var/log/auth.log"
["gitlab"]="/srv/gitlab/logs/gitlab-rails/application_json.log"
["nginx"]="/var/log/nginx/access.log"
["syslog"]="/var/log/syslog"
)
# PID 檔案用於避免重複執行
PID_FILE="/var/run/security-monitor.pid"
# 日誌目錄
MONITOR_LOG="/var/log/security-monitor.log"
# 日誌函式
log_message() {
local level=$1
local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" >> "$MONITOR_LOG"
}
# 發送警示通知
send_alert() {
local alert_type=$1
local alert_message=$2
local details=$3
# 組合警示內容
local email_body="DevSecOps 安全警示
警示類型: $alert_type
時間: $(date '+%Y-%m-%d %H:%M:%S')
主機: $(hostname)
詳細資訊:
$alert_message
事件詳情:
$details
此郵件由 DevSecOps 安全監控系統自動發送。
"
# 發送電子郵件警示
echo "$email_body" | mail -s "安全警示 - $alert_type" "$ALERT_EMAIL"
# 記錄警示日誌
log_message "ALERT" "$alert_type: $alert_message"
# 可選:發送到 Slack 或其他通知系統
if [[ -n "${SLACK_WEBHOOK_URL:-}" ]]; then
send_slack_alert "$alert_type" "$alert_message"
fi
}
# 發送 Slack 警示
send_slack_alert() {
local alert_type=$1
local alert_message=$2
# 建構 Slack 訊息 JSON
local slack_payload=$(cat << EOF
{
"text": "安全警示: $alert_type",
"attachments": [
{
"color": "danger",
"fields": [
{
"title": "警示類型",
"value": "$alert_type",
"short": true
},
{
"title": "主機",
"value": "$(hostname)",
"short": true
},
{
"title": "詳細資訊",
"value": "$alert_message",
"short": false
}
],
"footer": "DevSecOps 安全監控系統",
"ts": $(date +%s)
}
]
}
EOF
)
# 發送到 Slack
curl -s -X POST \
-H 'Content-type: application/json' \
--data "$slack_payload" \
"$SLACK_WEBHOOK_URL" > /dev/null
}
# 監控失敗登入嘗試
monitor_failed_logins() {
local log_file="${LOG_FILES[auth]}"
if [[ ! -f "$log_file" ]]; then
log_message "WARN" "找不到認證日誌檔: $log_file"
return
fi
# 計算時間視窗
local current_time=$(date +%s)
local window_start=$((current_time - CHECK_INTERVAL))
# 從日誌中提取失敗登入嘗試
local failed_attempts=$(grep "Failed password" "$log_file" | while read -r line; do
# 提取日誌時間戳
log_date=$(echo "$line" | awk '{print $1, $2, $3}')
log_timestamp=$(date -d "$log_date" +%s 2>/dev/null || echo "0")
# 檢查是否在時間視窗內
if [[ $log_timestamp -ge $window_start ]]; then
echo "$line"
fi
done)
# 計算失敗次數
local failed_count=$(echo "$failed_attempts" | grep -c "Failed password" || echo "0")
# 如果超過閾值,發送警示
if [[ $failed_count -gt $FAILED_LOGIN_THRESHOLD ]]; then
local ip_summary=$(echo "$failed_attempts" | grep -oP 'from \K[0-9.]+' | sort | uniq -c | sort -rn | head -10)
send_alert "大量失敗登入嘗試" \
"在過去 $((CHECK_INTERVAL / 60)) 分鐘內偵測到 $failed_count 次失敗登入嘗試" \
"來源 IP 統計:\n$ip_summary"
fi
}
# 監控 GitLab 安全事件
monitor_gitlab_security() {
local log_file="${LOG_FILES[gitlab]}"
if [[ ! -f "$log_file" ]]; then
log_message "WARN" "找不到 GitLab 日誌檔: $log_file"
return
fi
# 計算時間視窗
local current_time=$(date +%s)
local window_start=$((current_time - CHECK_INTERVAL))
local window_start_iso=$(date -u -d "@$window_start" +"%Y-%m-%dT%H:%M:%S")
# 搜尋失敗登入事件
local failed_logins=$(grep "Failed Login" "$log_file" | while read -r line; do
log_time=$(echo "$line" | jq -r '.time' 2>/dev/null | cut -d'.' -f1)
if [[ "$log_time" > "$window_start_iso" ]]; then
echo "$line"
fi
done)
# 計算失敗次數
local failed_count=$(echo "$failed_logins" | grep -c "Failed Login" || echo "0")
# 如果超過閾值,發送警示
if [[ $failed_count -gt $FAILED_LOGIN_THRESHOLD ]]; then
local user_summary=$(echo "$failed_logins" | jq -r '.message' 2>/dev/null | head -20)
send_alert "GitLab 失敗登入警示" \
"GitLab 在過去 $((CHECK_INTERVAL / 60)) 分鐘內偵測到 $failed_count 次失敗登入" \
"$user_summary"
fi
}
# 監控可疑的網路活動
monitor_network_activity() {
# 檢查異常的網路連線數量
local connection_count=$(netstat -an | grep ESTABLISHED | wc -l)
local connection_threshold=1000
if [[ $connection_count -gt $connection_threshold ]]; then
local top_connections=$(netstat -an | grep ESTABLISHED | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -10)
send_alert "異常網路連線" \
"目前有 $connection_count 個已建立的連線,超過閾值 $connection_threshold" \
"連線最多的 IP:\n$top_connections"
fi
# 檢查可疑的監聽端口
local suspicious_ports=$(netstat -tlnp | grep -E ':([0-9]{4,5})' | grep -v -E ':(22|80|443|3306|5432|6379|9200)')
if [[ -n "$suspicious_ports" ]]; then
send_alert "可疑監聽端口" \
"偵測到非預期的監聽端口" \
"$suspicious_ports"
fi
}
# 監控檔案系統變更
monitor_file_integrity() {
local critical_files=(
"/etc/passwd"
"/etc/shadow"
"/etc/sudoers"
"/etc/ssh/sshd_config"
)
local checksum_file="/var/lib/security-monitor/checksums"
# 如果 checksum 檔案不存在,建立初始 checksums
if [[ ! -f "$checksum_file" ]]; then
mkdir -p "$(dirname "$checksum_file")"
for file in "${critical_files[@]}"; do
if [[ -f "$file" ]]; then
md5sum "$file" >> "$checksum_file"
fi
done
return
fi
# 檢查檔案是否被修改
local modified_files=""
for file in "${critical_files[@]}"; do
if [[ -f "$file" ]]; then
local current_sum=$(md5sum "$file" | awk '{print $1}')
local stored_sum=$(grep "$file" "$checksum_file" | awk '{print $1}')
if [[ "$current_sum" != "$stored_sum" ]]; then
modified_files+="$file\n"
fi
fi
done
# 如果發現修改,發送警示
if [[ -n "$modified_files" ]]; then
send_alert "關鍵檔案被修改" \
"偵測到以下關鍵系統檔案被修改" \
"$modified_files"
fi
}
# 監控磁碟空間
monitor_disk_space() {
local threshold=90
# 檢查每個掛載點的使用率
df -h | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{print $5 " " $6}' | while read -r output; do
usage=$(echo "$output" | awk '{print $1}' | tr -d '%')
partition=$(echo "$output" | awk '{print $2}')
if [[ $usage -ge $threshold ]]; then
send_alert "磁碟空間警告" \
"分割區 $partition 使用率達到 $usage%" \
"請檢查並清理不必要的檔案"
fi
done
}
# 處理程序清理
cleanup() {
log_message "INFO" "正在停止安全監控系統..."
rm -f "$PID_FILE"
exit 0
}
# 主監控迴圈
main_loop() {
log_message "INFO" "安全監控系統已啟動"
# 註冊信號處理
trap cleanup SIGTERM SIGINT
while true; do
log_message "INFO" "執行安全檢查..."
# 執行各項監控
monitor_failed_logins
monitor_gitlab_security
monitor_network_activity
monitor_file_integrity
monitor_disk_space
log_message "INFO" "安全檢查完成,等待下次檢查"
# 等待下一個檢查週期
sleep "$CHECK_INTERVAL"
done
}
# 主程式
main() {
# 檢查是否已經在執行
if [[ -f "$PID_FILE" ]]; then
local old_pid=$(cat "$PID_FILE")
if ps -p "$old_pid" > /dev/null 2>&1; then
echo "安全監控系統已在執行 (PID: $old_pid)"
exit 1
fi
fi
# 寫入 PID 檔案
echo $$ > "$PID_FILE"
# 確保日誌目錄存在
touch "$MONITOR_LOG"
# 開始監控
main_loop
}
main "$@"
這個監控指令碼實現了多層次的安全監控功能。它監控認證日誌中的失敗登入嘗試、GitLab 應用程式日誌中的安全事件、網路連線狀態、關鍵系統檔案的完整性,以及磁碟空間使用情況。當偵測到異常活動時,系統會透過電子郵件和 Slack 發送警示通知。這種多層次的監控方式能夠提供全面的安全態勢感知,幫助安全團隊及時發現和回應潛在的安全威脅。
自動化 Kali Linux 客製化建置
對於滲透測試團隊來說,擁有一個標準化且可重複建置的測試環境是非常重要的。Kali Linux 是最受歡迎的滲透測試發行版之一,它提供了 Live Build 工具來建立客製化的 ISO 映像。透過自動化這個建置過程,團隊可以確保每次測試都使用一致的環境配置。
以下的 Bash 指令碼展示了如何自動化建置客製化的 Kali Linux 系統:
#!/usr/bin/env bash
# Kali Linux 客製化建置自動化指令碼
# 此指令碼用於建立客製化的 Kali Linux ISO 映像
set -euo pipefail
# 顏色定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# 建置配置
# 桌面環境選項:gnome, kde, xfce, i3, mate
DESKTOP_ENVIRONMENT="${DESKTOP_ENV:-xfce}"
# 架構選項:amd64, arm64
ARCHITECTURE="${ARCH:-amd64}"
# 版本標識
VERSION="${BUILD_VERSION:-custom-$(date +%Y%m%d)}"
# 建置類型選項:installer, live
BUILD_TYPE="${BUILD_TYPE:-installer}"
# 建置目錄
BUILD_DIR="${BUILD_DIR:-/opt/kali-build}"
# 映像輸出目錄
OUTPUT_DIR="${OUTPUT_DIR:-/opt/kali-images}"
# 日誌函式
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_section() {
echo -e "\n${BLUE}========================================${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}========================================${NC}\n"
}
# 檢查系統需求
check_system_requirements() {
log_section "檢查系統需求"
# 確保在 Debian/Kali 系統上執行
if [[ ! -f /etc/debian_version ]]; then
log_error "此指令碼必須在 Debian 或 Kali Linux 系統上執行"
exit 1
fi
# 確保以 root 身份執行
if [[ $EUID -ne 0 ]]; then
log_error "此指令碼必須以 root 身份執行"
exit 1
fi
# 檢查磁碟空間(至少需要 50GB)
local available_space=$(df -BG "$BUILD_DIR" 2>/dev/null | awk 'NR==2 {print $4}' | tr -d 'G')
if [[ -z "$available_space" || "$available_space" -lt 50 ]]; then
log_error "磁碟空間不足,至少需要 50GB 可用空間"
exit 1
fi
# 檢查記憶體(建議至少 8GB)
local total_memory=$(free -g | awk 'NR==2 {print $2}')
if [[ "$total_memory" -lt 8 ]]; then
log_warn "系統記憶體少於 8GB,建置過程可能較慢"
fi
log_info "系統需求檢查通過"
}
# 安裝必要套件
install_dependencies() {
log_section "安裝必要套件"
# 更新套件列表
apt-get update
# 安裝建置工具
# git: 用於克隆建置指令碼
# live-build: Debian Live 系統建置工具
# simple-cdd: 簡化的客製化 Debian 發行版工具
# cdebootstrap: Debian 基礎系統建立工具
# curl: 用於下載檔案
apt-get install -y \
git \
live-build \
simple-cdd \
cdebootstrap \
curl \
debootstrap \
squashfs-tools \
xorriso \
grub-pc-bin \
grub-efi-amd64-bin \
mtools
log_info "必要套件安裝完成"
}
# 克隆建置指令碼
clone_build_scripts() {
log_section "克隆 Kali Linux 建置指令碼"
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
# 如果目錄已存在,更新它
if [[ -d "live-build-config" ]]; then
log_info "更新現有的建置指令碼..."
cd live-build-config
git pull
else
log_info "克隆建置指令碼..."
git clone https://gitlab.com/kalilinux/build-scripts/live-build-config.git
cd live-build-config
fi
log_info "建置指令碼已就緒"
}
# 設定客製化配置
configure_customization() {
log_section "設定客製化配置"
cd "$BUILD_DIR/live-build-config"
# 建立自訂配置目錄
mkdir -p kali-config/common/includes.chroot/etc/live/config
mkdir -p kali-config/common/includes.chroot/root
mkdir -p kali-config/common/includes.chroot/etc/skel
# 設定預設使用者配置
# 這些設定會套用到 Live 環境中的使用者
cat > kali-config/common/includes.chroot/etc/live/config/user-setup << 'EOF'
LIVE_USER_DEFAULT_GROUPS="audio cdrom dip floppy video plugdev netdev powerdev scanner bluetooth sudo kali-trusted"
LIVE_USER_FULLNAME="Kali User"
EOF
log_info "設定自動登入配置..."
# 建立桌面自動啟動項目
mkdir -p kali-config/common/includes.chroot/etc/skel/.config/autostart
# 建立歡迎訊息指令碼
cat > kali-config/common/includes.chroot/root/welcome.sh << 'EOF'
#!/bin/bash
# Kali Linux 客製化版本歡迎訊息
echo "=========================================="
echo " 歡迎使用客製化 Kali Linux"
echo " 版本: CUSTOM_VERSION"
echo " 建置時間: BUILD_DATE"
echo "=========================================="
EOF
chmod +x kali-config/common/includes.chroot/root/welcome.sh
# 替換版本資訊
sed -i "s/CUSTOM_VERSION/$VERSION/g" kali-config/common/includes.chroot/root/welcome.sh
sed -i "s/BUILD_DATE/$(date '+%Y-%m-%d %H:%M:%S')/g" kali-config/common/includes.chroot/root/welcome.sh
log_info "客製化配置已設定"
}
# 設定自訂套件列表
configure_packages() {
log_section "設定自訂套件列表"
cd "$BUILD_DIR/live-build-config"
# 建立自訂套件列表目錄
local variant_dir="kali-config/variant-$DESKTOP_ENVIRONMENT"
mkdir -p "$variant_dir/package-lists"
# 建立額外的安全工具套件列表
# 這些工具會額外安裝到系統中
cat > "$variant_dir/package-lists/custom-tools.list.chroot" << 'EOF'
# 網路分析工具
wireshark
tcpdump
nmap
masscan
# 網頁安全測試
burpsuite
zaproxy
# 密碼工具
hashcat
john
hydra
# 漏洞掃描
nikto
sqlmap
wpscan
# 無線網路工具
aircrack-ng
kismet
# 逆向工程
radare2
ghidra
# 報告工具
cherrytree
keepnote
# 開發工具
git
vim
tmux
python3-pip
python3-venv
# 系統工具
htop
ncdu
tree
EOF
log_info "套件列表已設定"
}
# 設定網路配置
configure_network() {
log_section "設定網路配置"
cd "$BUILD_DIR/live-build-config"
# 建立網路介面配置
mkdir -p kali-config/common/includes.chroot/etc/network
cat > kali-config/common/includes.chroot/etc/network/interfaces << 'EOF'
# 網路介面配置
# 由客製化建置指令碼自動產生
auto lo
iface lo inet loopback
# 預設以 DHCP 取得 IP
auto eth0
iface eth0 inet dhcp
EOF
# 設定 DNS 解析
mkdir -p kali-config/common/includes.chroot/etc
cat > kali-config/common/includes.chroot/etc/resolv.conf << 'EOF'
# DNS 配置
nameserver 8.8.8.8
nameserver 8.8.4.4
EOF
log_info "網路配置已設定"
}
# 執行建置
run_build() {
log_section "開始建置 Kali Linux 映像"
cd "$BUILD_DIR/live-build-config"
log_info "建置配置:"
log_info " 桌面環境: $DESKTOP_ENVIRONMENT"
log_info " 架構: $ARCHITECTURE"
log_info " 版本: $VERSION"
log_info " 建置類型: $BUILD_TYPE"
# 清理之前的建置
log_info "清理之前的建置..."
./build.sh --clean 2>/dev/null || true
# 執行建置
log_info "開始建置,這可能需要 1-2 小時..."
./build.sh \
--verbose \
--variant "$DESKTOP_ENVIRONMENT" \
--arch "$ARCHITECTURE" \
--version "$VERSION" \
--"$BUILD_TYPE"
# 檢查建置結果
if [[ $? -eq 0 ]]; then
log_info "建置完成"
else
log_error "建置失敗"
exit 1
fi
}
# 複製映像到輸出目錄
copy_output() {
log_section "複製映像到輸出目錄"
mkdir -p "$OUTPUT_DIR"
# 尋找產生的 ISO 檔案
local iso_file=$(find "$BUILD_DIR/live-build-config/images" -name "*.iso" -type f | head -1)
if [[ -n "$iso_file" ]]; then
local output_name="kali-linux-$VERSION-$DESKTOP_ENVIRONMENT-$ARCHITECTURE.iso"
cp "$iso_file" "$OUTPUT_DIR/$output_name"
log_info "映像已複製到: $OUTPUT_DIR/$output_name"
# 計算並儲存 SHA256 校驗碼
sha256sum "$OUTPUT_DIR/$output_name" > "$OUTPUT_DIR/$output_name.sha256"
log_info "校驗碼已儲存到: $OUTPUT_DIR/$output_name.sha256"
else
log_error "找不到產生的 ISO 檔案"
exit 1
fi
}
# 建立 QEMU 測試指令碼
create_test_script() {
log_section "建立 QEMU 測試指令碼"
local iso_name="kali-linux-$VERSION-$DESKTOP_ENVIRONMENT-$ARCHITECTURE.iso"
cat > "$OUTPUT_DIR/test-kali.sh" << EOF
#!/bin/bash
# Kali Linux 映像測試指令碼
# 確保 QEMU 已安裝
if ! command -v qemu-system-x86_64 &> /dev/null; then
echo "請先安裝 QEMU: apt install qemu-system-x86"
exit 1
fi
# 建立測試磁碟
DISK_IMAGE="/tmp/kali-test.qcow2"
if [[ ! -f "\$DISK_IMAGE" ]]; then
qemu-img create -f qcow2 "\$DISK_IMAGE" 20G
fi
# 啟動虛擬機器
qemu-system-x86_64 \\
-enable-kvm \\
-m 4096 \\
-smp 2 \\
-drive if=virtio,aio=threads,cache=unsafe,format=qcow2,file="\$DISK_IMAGE" \\
-cdrom "$OUTPUT_DIR/$iso_name" \\
-boot once=d \\
-vga virtio \\
-display gtk
EOF
chmod +x "$OUTPUT_DIR/test-kali.sh"
log_info "測試指令碼已建立: $OUTPUT_DIR/test-kali.sh"
}
# 顯示建置摘要
show_summary() {
log_section "建置摘要"
local iso_name="kali-linux-$VERSION-$DESKTOP_ENVIRONMENT-$ARCHITECTURE.iso"
local iso_path="$OUTPUT_DIR/$iso_name"
if [[ -f "$iso_path" ]]; then
local iso_size=$(du -h "$iso_path" | cut -f1)
echo "映像檔案: $iso_path"
echo "檔案大小: $iso_size"
echo "校驗碼檔案: $iso_path.sha256"
echo ""
echo "測試映像:"
echo " $OUTPUT_DIR/test-kali.sh"
echo ""
echo "燒錄到 USB:"
echo " sudo dd if=$iso_path of=/dev/sdX bs=4M status=progress"
echo ""
fi
}
# 主程式
main() {
log_section "Kali Linux 客製化建置系統"
check_system_requirements
install_dependencies
clone_build_scripts
configure_customization
configure_packages
configure_network
run_build
copy_output
create_test_script
show_summary
log_info "建置程序完成"
}
main "$@"
這個建置指令碼提供了完整的 Kali Linux 客製化建置流程。它首先檢查系統需求和安裝必要的建置工具,然後克隆官方的建置指令碼並進行客製化配置。配置包括使用者設定、自訂套件列表和網路配置等。建置完成後,指令碼會將產生的 ISO 映像複製到輸出目錄,並建立用於測試的 QEMU 啟動指令碼。
透過這個自動化流程,滲透測試團隊可以快速建立符合特定需求的 Kali Linux 環境。每次建置都會產生一致的結果,確保所有團隊成員使用相同的工具和配置。這種標準化的方法不僅提高了測試效率,也減少了因環境差異導致的問題。
Python 輔助工具整合
除了 Bash 指令碼之外,Python 也是 DevSecOps 工作流程中常用的程式語言。以下的 Python 程式碼展示了如何建立一個安全掃描協調器,用於整合多種安全掃描工具並彙整結果:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
DevSecOps 安全掃描協調器
整合多種安全掃描工具並彙整結果
"""
import subprocess
import json
import logging
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Optional
from dataclasses import dataclass, asdict
import concurrent.futures
# 配置日誌記錄器
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
@dataclass
class ScanResult:
"""安全掃描結果資料結構"""
tool_name: str
scan_type: str
timestamp: str
issues_count: int
high_severity: int
medium_severity: int
low_severity: int
details: List[Dict]
class SecurityScanner:
"""
安全掃描協調器
整合多種安全掃描工具並提供統一的介面
"""
def __init__(self, project_path: str, reports_dir: str = "reports"):
# 專案路徑
self.project_path = Path(project_path)
# 報告目錄
self.reports_dir = self.project_path / reports_dir
self.reports_dir.mkdir(parents=True, exist_ok=True)
# 掃描結果儲存
self.results: List[ScanResult] = []
logger.info(f"安全掃描協調器已初始化,專案路徑: {project_path}")
def run_bandit_scan(self) -> Optional[ScanResult]:
"""
執行 Bandit Python 程式碼安全掃描
Bandit 是 Python 程式碼的靜態安全分析工具
"""
logger.info("執行 Bandit 掃描...")
try:
# 執行 Bandit 掃描
result = subprocess.run(
[
"bandit",
"-r", str(self.project_path / "src"),
"-f", "json",
"-o", str(self.reports_dir / "bandit-report.json")
],
capture_output=True,
text=True
)
# 載入結果
report_path = self.reports_dir / "bandit-report.json"
if report_path.exists():
with open(report_path, 'r', encoding='utf-8') as f:
report = json.load(f)
# 分析嚴重程度
issues = report.get('results', [])
high = sum(1 for i in issues if i.get('issue_severity') == 'HIGH')
medium = sum(1 for i in issues if i.get('issue_severity') == 'MEDIUM')
low = sum(1 for i in issues if i.get('issue_severity') == 'LOW')
scan_result = ScanResult(
tool_name="Bandit",
scan_type="SAST",
timestamp=datetime.now().isoformat(),
issues_count=len(issues),
high_severity=high,
medium_severity=medium,
low_severity=low,
details=issues
)
logger.info(f"Bandit 掃描完成,發現 {len(issues)} 個問題")
return scan_result
except Exception as e:
logger.error(f"Bandit 掃描失敗: {e}")
return None
def run_safety_scan(self) -> Optional[ScanResult]:
"""
執行 Safety 依賴套件弱點掃描
Safety 用於檢查 Python 依賴套件中的已知安全弱點
"""
logger.info("執行 Safety 掃描...")
try:
# 執行 Safety 掃描
result = subprocess.run(
[
"safety", "check",
"--json",
"-r", str(self.project_path / "requirements.txt")
],
capture_output=True,
text=True
)
# 解析結果
if result.stdout:
report = json.loads(result.stdout)
# 提取弱點資訊
vulnerabilities = report.get('vulnerabilities', [])
scan_result = ScanResult(
tool_name="Safety",
scan_type="SCA",
timestamp=datetime.now().isoformat(),
issues_count=len(vulnerabilities),
high_severity=0,
medium_severity=0,
low_severity=len(vulnerabilities),
details=vulnerabilities
)
# 儲存報告
report_path = self.reports_dir / "safety-report.json"
with open(report_path, 'w', encoding='utf-8') as f:
json.dump(report, f, indent=2, ensure_ascii=False)
logger.info(f"Safety 掃描完成,發現 {len(vulnerabilities)} 個弱點")
return scan_result
except Exception as e:
logger.error(f"Safety 掃描失敗: {e}")
return None
def run_trufflehog_scan(self) -> Optional[ScanResult]:
"""
執行 TruffleHog 密碼掃描
TruffleHog 用於偵測程式碼中的敏感資訊如 API 金鑰和密碼
"""
logger.info("執行 TruffleHog 掃描...")
try:
# 執行 TruffleHog 掃描
result = subprocess.run(
[
"trufflehog",
"filesystem",
f"--directory={self.project_path}",
"--json"
],
capture_output=True,
text=True
)
# 解析結果(每行一個 JSON 物件)
secrets = []
for line in result.stdout.strip().split('\n'):
if line:
try:
secrets.append(json.loads(line))
except json.JSONDecodeError:
pass
scan_result = ScanResult(
tool_name="TruffleHog",
scan_type="Secret Scan",
timestamp=datetime.now().isoformat(),
issues_count=len(secrets),
high_severity=len(secrets),
medium_severity=0,
low_severity=0,
details=secrets
)
# 儲存報告
report_path = self.reports_dir / "trufflehog-report.json"
with open(report_path, 'w', encoding='utf-8') as f:
json.dump(secrets, f, indent=2, ensure_ascii=False)
logger.info(f"TruffleHog 掃描完成,發現 {len(secrets)} 個敏感資訊")
return scan_result
except Exception as e:
logger.error(f"TruffleHog 掃描失敗: {e}")
return None
def run_all_scans(self, parallel: bool = True) -> List[ScanResult]:
"""
執行所有安全掃描
Args:
parallel: 是否平行執行掃描
"""
logger.info("開始執行所有安全掃描...")
# 定義要執行的掃描
scan_functions = [
self.run_bandit_scan,
self.run_safety_scan,
self.run_trufflehog_scan
]
if parallel:
# 平行執行掃描
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
futures = [executor.submit(func) for func in scan_functions]
for future in concurrent.futures.as_completed(futures):
result = future.result()
if result:
self.results.append(result)
else:
# 依序執行掃描
for func in scan_functions:
result = func()
if result:
self.results.append(result)
return self.results
def generate_summary_report(self) -> Dict:
"""
產生彙整報告
"""
logger.info("產生彙整報告...")
# 計算總計
total_issues = sum(r.issues_count for r in self.results)
total_high = sum(r.high_severity for r in self.results)
total_medium = sum(r.medium_severity for r in self.results)
total_low = sum(r.low_severity for r in self.results)
# 建立報告
report = {
'timestamp': datetime.now().isoformat(),
'project_path': str(self.project_path),
'summary': {
'total_issues': total_issues,
'high_severity': total_high,
'medium_severity': total_medium,
'low_severity': total_low,
'scans_completed': len(self.results)
},
'scans': [asdict(r) for r in self.results]
}
# 儲存報告
report_path = self.reports_dir / "security-summary.json"
with open(report_path, 'w', encoding='utf-8') as f:
json.dump(report, f, indent=2, ensure_ascii=False)
logger.info(f"彙整報告已儲存至 {report_path}")
return report
def main():
"""主程式"""
# 建立掃描器
scanner = SecurityScanner(
project_path="/path/to/project",
reports_dir="security-reports"
)
# 執行所有掃描
results = scanner.run_all_scans(parallel=True)
# 產生彙整報告
summary = scanner.generate_summary_report()
# 輸出摘要
print("\n" + "=" * 60)
print("安全掃描摘要")
print("=" * 60)
print(f"總問題數: {summary['summary']['total_issues']}")
print(f"高嚴重度: {summary['summary']['high_severity']}")
print(f"中嚴重度: {summary['summary']['medium_severity']}")
print(f"低嚴重度: {summary['summary']['low_severity']}")
print("=" * 60)
if __name__ == "__main__":
main()
這個 Python 程式提供了一個統一的介面來協調多種安全掃描工具。SecurityScanner 類別整合了 Bandit(Python 程式碼靜態分析)、Safety(依賴套件弱點檢查)和 TruffleHog(密碼掃描)等工具。透過平行執行功能,可以同時運行多個掃描以節省時間。所有掃描結果會被彙整成一份統一格式的報告,方便後續的分析和追蹤。
總結
本文深入探討了如何運用 Bash 指令碼來強化 DevSecOps 流程中的安全性。我們首先建立了完整的 GitLab CI/CD 安全掃描管線,包含靜態應用安全測試、密碼掃描、容器映像弱點掃描和動態應用安全測試等多個階段。接著,我們實作了一個多層次的即時安全監控系統,能夠偵測失敗登入嘗試、網路異常活動和關鍵檔案變更等安全事件。最後,我們建立了自動化的 Kali Linux 客製化建置流程,讓滲透測試團隊能夠快速建立標準化的測試環境。
Bash 指令碼作為 Linux 環境中最強大的自動化工具之一,在 DevSecOps 實踐中扮演著不可或缺的角色。透過結合各種安全工具和自動化技術,我們可以建立一個完整的安全自動化框架,將安全性融入軟體開發生命週期的每個階段。這種方法不僅能夠及早發現和修復安全問題,也能夠提高團隊的工作效率,確保系統的整體安全性。
在實際應用中,開發和安全團隊應該根據組織的具體需求和風險狀況來調整這些工具和流程。持續改進和更新安全措施是維護系統安全的關鍵,因為安全威脅和攻擊技術也在不斷演進。透過自動化的安全掃描和監控,團隊可以更有效地管理安全風險,同時保持開發速度和靈活性。