374 lines
9.3 KiB
Bash
374 lines
9.3 KiB
Bash
#!/bin/bash
|
|
# Update Approval System for SAW
|
|
# Version: 1.0
|
|
# Date: 2026-04-02
|
|
#
|
|
# This script implements a controlled workflow for applying system updates,
|
|
# ensuring that updates are reviewed and approved before being applied.
|
|
#
|
|
# Usage: sudo ./approve-update.sh
|
|
#
|
|
# SECURITY RATIONALE:
|
|
# The update approval system provides:
|
|
# 1. Prevents unauthorized updates
|
|
# 2. Allows security team review before deployment
|
|
# 3. Enables testing in staging environment
|
|
# 4. Provides audit trail for updates
|
|
# 5. Prevents automatic deployment of compromised updates
|
|
# 6. Ensures updates don't break security controls
|
|
#
|
|
# How it works:
|
|
# 1. Check for available updates
|
|
# 2. Display update details to user
|
|
# 3. Require explicit approval
|
|
# 4. Log all update activities
|
|
# 5. Enable easy rollback if needed
|
|
#
|
|
# Reference: https://docs.fedoraproject.org/en-US/fedora-coreos/atomic-updates/
|
|
|
|
set -e
|
|
|
|
# Configuration
|
|
LOG_FILE="/var/log/update-approval.log"
|
|
APPROVAL_LOG="/var/log/update-approval-records.log"
|
|
LOCK_FILE="/var/lock/saw-update-lock"
|
|
UPDATE_LOG="/var/log/saw-updates.log"
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
# Print functions
|
|
log_info() {
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
echo -e "${GREEN}[$timestamp]${NC} ${BLUE}[INFO]${NC} $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
log_warning() {
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
echo -e "${YELLOW}[$timestamp]${NC} ${YELLOW}[WARNING]${NC} $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
log_error() {
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
echo -e "${RED}[$timestamp]${NC} ${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
log_approval() {
|
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
local user=$(whoami)
|
|
echo "[$timestamp] User: $user - $1" | tee -a "$APPROVAL_LOG"
|
|
}
|
|
|
|
# Check if running as root
|
|
check_root() {
|
|
if [ "$EUID" -ne 0 ]; then
|
|
log_error "This script must be run as root"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Check if another update is running
|
|
check_lock() {
|
|
if [ -f "$LOCK_FILE" ]; then
|
|
log_error "Another update is already running"
|
|
log_info "Lock file: $LOCK_FILE"
|
|
log_info "If this is an error, remove the lock file"
|
|
exit 1
|
|
fi
|
|
|
|
# Create lock file
|
|
touch "$LOCK_FILE"
|
|
log_info "Lock file created"
|
|
|
|
# Set up trap to remove lock on exit
|
|
trap 'rm -f "$LOCK_FILE"; log_info "Lock file removed"; exit' EXIT
|
|
}
|
|
|
|
# Check for updates
|
|
check_updates() {
|
|
log_info "Checking for updates..."
|
|
|
|
# Use rpm-ostree to check for updates
|
|
if ! rpm-ostree update --check 2>&1 | tee /tmp/update-check.txt; then
|
|
# No updates available
|
|
log_info "No updates available"
|
|
return 1
|
|
fi
|
|
|
|
# Save update information
|
|
cp /tmp/update-check.txt /var/log/saw-latest-update.txt
|
|
|
|
return 0
|
|
}
|
|
|
|
# Display update details
|
|
display_updates() {
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " Available Updates"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
if [ -f /tmp/update-check.txt ]; then
|
|
cat /tmp/update-check.txt
|
|
else
|
|
echo "No update information available"
|
|
fi
|
|
|
|
echo ""
|
|
echo "=========================================="
|
|
echo ""
|
|
}
|
|
|
|
# Get approval
|
|
#
|
|
# SECURITY RATIONALE:
|
|
# The approval process ensures:
|
|
# 1. Authorized personnel review updates
|
|
# 2. Updates are documented
|
|
# 3. No surprise updates
|
|
# 4. Accountability for update decisions
|
|
# 5. Audit trail for compliance
|
|
#
|
|
# We use a simple yes/no approval with logging.
|
|
get_approval() {
|
|
echo "=========================================="
|
|
echo " Update Approval Request"
|
|
echo "=========================================="
|
|
echo ""
|
|
echo "The following updates are available:"
|
|
echo ""
|
|
cat /tmp/update-check.txt | head -50
|
|
echo ""
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
# Ask for approval
|
|
read -p "Do you want to apply these updates? (yes/no): " response
|
|
|
|
case "$response" in
|
|
yes|YES|y|Y)
|
|
log_approval "APPROVED: User $USER approved update"
|
|
return 0
|
|
;;
|
|
no|NO|n|N)
|
|
log_approval "REJECTED: User $USER rejected update"
|
|
log_info "Update cancelled by user"
|
|
exit 0
|
|
;;
|
|
*)
|
|
log_error "Invalid response"
|
|
log_info "Please enter 'yes' or 'no'"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Apply updates
|
|
apply_updates() {
|
|
log_info "Applying updates..."
|
|
|
|
# Show warning
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " WARNING"
|
|
echo "=========================================="
|
|
echo ""
|
|
echo "This will apply system updates."
|
|
echo "A reboot may be required."
|
|
echo "Ensure you have backups."
|
|
echo ""
|
|
echo "Updates will be applied to:"
|
|
echo "- System packages"
|
|
echo "- Kernel"
|
|
echo "- Security updates"
|
|
echo ""
|
|
echo "This process may take several minutes."
|
|
echo ""
|
|
|
|
read -p "Are you sure you want to proceed? (yes/no): " confirm
|
|
|
|
if [ "$confirm" != "yes" ]; then
|
|
log_approval "CANCELLED: User $USER cancelled update"
|
|
log_info "Update cancelled"
|
|
exit 0
|
|
fi
|
|
|
|
log_approval "STARTED: User $USER started update"
|
|
|
|
# Apply updates
|
|
if rpm-ostree upgrade; then
|
|
log_approval "COMPLETED: User $USER completed update"
|
|
log_info "Updates applied successfully"
|
|
log_info "A reboot is recommended"
|
|
return 0
|
|
else
|
|
log_approval "FAILED: User $USER update failed"
|
|
log_error "Update failed"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Show update history
|
|
show_history() {
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " Update History"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
if [ -f "$APPROVAL_LOG" ]; then
|
|
cat "$APPROVAL_LOG" | tail -20
|
|
else
|
|
echo "No update history available"
|
|
fi
|
|
|
|
echo ""
|
|
}
|
|
|
|
# Show update status
|
|
show_status() {
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " Update Status"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
# Show current deployment
|
|
echo "Current Deployment:"
|
|
rpm-ostree status | head -5
|
|
echo ""
|
|
|
|
# Show pending deployment
|
|
echo "Pending Deployment:"
|
|
if [ -f /tmp/update-check.txt ]; then
|
|
echo "Updates available for review"
|
|
else
|
|
echo "No updates pending"
|
|
fi
|
|
echo ""
|
|
|
|
# Show last update
|
|
echo "Last Update:"
|
|
if [ -f /var/log/saw-latest-update.txt ]; then
|
|
echo "Last update check: $(stat -c %y /var/log/saw-latest-update.txt)"
|
|
else
|
|
echo "No recent update check"
|
|
fi
|
|
echo ""
|
|
}
|
|
|
|
# Setup update check cron job
|
|
setup_cron() {
|
|
log_info "Setting up update check cron job..."
|
|
|
|
# Create cron job for daily check
|
|
cat > /etc/cron.d/saw-update-check << 'CRONJOB'
|
|
# SAW Update Check - Daily at 6:00 AM
|
|
# Only downloads updates, does not apply them
|
|
0 6 * * * root /usr/bin/rpm-ostree update --check >> /var/log/saw-updates.log 2>&1
|
|
CRONJOB
|
|
|
|
chmod 644 /etc/cron.d/saw-update-check
|
|
log_info "Cron job created"
|
|
log_info "Updates will be checked daily at 6:00 AM"
|
|
}
|
|
|
|
# Display help
|
|
show_help() {
|
|
cat << 'HELP'
|
|
Update Approval System for SAW
|
|
==============================
|
|
|
|
Usage: ./approve-update.sh [OPTIONS]
|
|
|
|
Options:
|
|
--check Check for available updates
|
|
--approve Check and prompt for approval
|
|
--apply Apply updates (requires approval first)
|
|
--history Show update history
|
|
--status Show update status
|
|
--cron Set up daily update check
|
|
--help Show this help message
|
|
|
|
Examples:
|
|
# Check for updates
|
|
./approve-update.sh --check
|
|
|
|
# Check and prompt for approval
|
|
./approve-update.sh --approve
|
|
|
|
# Apply updates
|
|
./approve-update.sh --apply
|
|
|
|
Security Notes:
|
|
- Updates require explicit approval
|
|
- All approval decisions are logged
|
|
- Updates can be reviewed before applying
|
|
- Rollback is available if needed
|
|
|
|
Reference: https://docs.fedoraproject.org/en-US/fedora-coreos/atomic-updates/
|
|
HELP
|
|
}
|
|
|
|
# Main execution
|
|
main() {
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " Update Approval System"
|
|
echo " Fedora Kinoite SAW"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
check_root
|
|
check_lock
|
|
|
|
case "${1:-}" in
|
|
--check)
|
|
if check_updates; then
|
|
display_updates
|
|
log_info "Updates available for review"
|
|
else
|
|
log_info "No updates available"
|
|
fi
|
|
;;
|
|
--approve)
|
|
check_updates
|
|
display_updates
|
|
get_approval
|
|
;;
|
|
--apply)
|
|
if [ ! -f /tmp/update-check.txt ]; then
|
|
log_error "No update information available"
|
|
log_info "Run with --check first"
|
|
exit 1
|
|
fi
|
|
display_updates
|
|
get_approval
|
|
apply_updates
|
|
;;
|
|
--history)
|
|
show_history
|
|
;;
|
|
--status)
|
|
show_status
|
|
;;
|
|
--cron)
|
|
setup_cron
|
|
;;
|
|
--help|-h)
|
|
show_help
|
|
;;
|
|
*)
|
|
show_help
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Run main function
|
|
main "$@" |