base ground

This commit is contained in:
Jarian Cottingham 2026-04-02 17:23:23 -05:00
parent e279804b1d
commit 89b7074268
13 changed files with 5819 additions and 0 deletions

665
INSTALLATION_GUIDE.md Normal file
View File

@ -0,0 +1,665 @@
# Installation Guide for Fedora Kinoite SAW
## Overview
This guide provides step-by-step instructions for building and installing a Secure Air-Gapped Workstation (SAW) using Fedora Kinoite with custom CA trust, WireGuard VPN, and strict security controls.
**Prerequisites:**
- 8GB+ USB drive
- Computer to build ISO (can be different from target machine)
- VPN gateway access information
- CA certificate and signing keys
- Custom packages (if any)
---
## Part 1: Building the Custom ISO
### Step 1: Install Build Tools
On the machine where you'll build the ISO (can be different from target):
```bash
# Install required tools
sudo dnf install -y lorax anaconda-tools createrepo_c
```
### Step 2: Prepare Repository Structure
```bash
# Create directory structure
mkdir -p ~/saw-build/{iso,packages,config}
# Download base Fedora Kinoite ISO
# Visit: https://kinoite.fedoraproject.org/
# Download latest ISO
```
### Step 3: Customize Kickstart File
Edit `kickstart/kinoite-saw.ks`:
**Required Customizations:**
1. **CA Certificate Path:**
```bash
# Change this line with your CA cert path
%include /tmp/kickstart-ca-certificate.ks
```
2. **Package List:**
```bash
# Add your custom packages
# Remove unnecessary packages
```
3. **VPN Gateway:**
```bash
# Update VPN configuration
# Add your WireGuard config
```
4. **User Configuration:**
```bash
# Set up your user account
user --name=saw-user --password=changeme
```
### Step 4: Add CA Certificate
Place your CA certificate in `package-verification/ca/ca.crt`:
```bash
# Your CA certificate should be in PEM format
# This will be installed to /etc/pki/ca-trust/source/anchors/
```
### Step 5: Build ISO
```bash
cd ~/saw-build
# Copy kickstart
cp /path/to/kickstart/kinoite-saw.ks .
# Build ISO using lorax
sudo lorax -s file:///path/to/kinoite-iso -p Fedora-Kinoite-SAW -v "SAW 1.0" \
--repo Fedora-Kinoite=file:///path/to/kinoite-iso \
--arch x86_64 \
--no-compress \
--variant Server \
kinoite-saw.ks
# Output will be in ~/saw-build/output/
```
**Alternative: Using Pungi (Fedora Build System)**
```bash
# Install pungi
sudo dnf install -y pungi
# Create compose configuration
cat > compose-config.toml << EOF
[compose]
release = "SAW 1.0"
version = "1.0"
distro = "Fedora-Kinoite-43"
base_arches = ["x86_64"]
[packages]
# Add your custom packages here
EOF
# Build
sudo pungi-gather --compose-dir compose
sudo pungi-make-iso --compose-dir compose
```
### Step 6: Test ISO
```bash
# Test in VM first
qemu-system-x86_64 -m 4096 -cdrom output/Fedora-Kinoite-SAW.iso
# Or use VirtualBox/Virtual Machine Manager
```
---
## Part 2: Installation to Target Machine
### Step 1: Prepare Installation Media
```bash
# Identify USB device
lsblk
# Write ISO to USB (replace /dev/sdX with your device)
sudo dd if=output/Fedora-Kinoite-SAW.iso of=/dev/sdX bs=4M status=progress
sync
# Verify
lsblk /dev/sdX
```
### Step 2: Boot Installation Media
```bash
# Insert USB into target machine
# Boot and select USB as boot device
# Press 'e' to edit boot options if needed
# Add 'inst.ks=file:///run/media/user/kickstart.ks' for automated install
```
### Step 3: Installation Wizard
1. **Select Installation Destination:**
- Choose disk to install to
- Select "I will configure partitioning"
- Create partitions:
- `/` - 15GB minimum (20GB recommended)
- `swap` - 2-4GB
- `/home` - remaining space
- `/boot/efi` - 512MB (for UEFI)
2. **Configure Network:**
- Enable network interface
- Configure VPN if needed for package installation
3. **Set Root Password:**
- Use strong password
- Store securely
4. **Create User:**
- Username: `saw-user` (or your preferred name)
- Set strong password
- Enable sudo access temporarily for post-install setup
5. **Begin Installation:**
- Wait for installation to complete
- Remove USB when prompted
### Step 4: First Boot
```bash
# Complete initial setup
# Configure timezone, language, etc.
# Log in with your user account
```
---
## Part 3: Post-Installation Lockdown
### Step 1: Initial System Update
```bash
# Check for updates
sudo rpm-ostree status
# Apply updates
sudo rpm-ostree upgrade
# Reboot if needed
sudo reboot
```
### Step 2: Run Lockdown Script
```bash
# Copy lockdown script to system
sudo cp post-install/lockdown.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/lockdown.sh
# Run lockdown
sudo /usr/local/bin/lockdown.sh
```
**What the lockdown script does:**
1. **Removes user from wheel group** (no sudo access)
2. **Disables root SSH login**
3. **Configures PAM for MFA** (if enabled)
4. **Enables SELinux enforcing mode**
5. **Enables auditd**
6. **Configures firewall**
7. **Sets up VPN**
8. **Configures DNS lockdown**
### Step 3: Verify Installation
```bash
# Check sudo access (should be denied)
sudo -l
# Check user groups (should not include wheel)
id
# Check firewall
sudo firewall-cmd --list-all
# Check SELinux
sestatus
# Check auditd
sudo systemctl status auditd
# Check VPN
wg show
```
### Step 4: Configure VPN
```bash
# Copy VPN configuration
sudo cp package-verification/ca/ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust
# Copy WireGuard config
sudo cp config/wireguard/wg0.conf /etc/wireguard/
sudo chmod 600 /etc/wireguard/wg0.conf
# Start WireGuard
sudo wg-quick up wg0
# Check VPN connection
wg show
ping -c 3 <vpn-gateway-ip>
```
### Step 5: Test DNS
```bash
# Test DNS resolution (should use VPN gateway)
nslookup google.com
# Check /etc/resolv.conf
cat /etc/resolv.conf
# Test that non-VPN DNS fails
# (should timeout or fail)
```
### Step 6: Test Firewall
```bash
# Check firewall status
sudo firewall-cmd --list-all
# Test outbound connection (should go through VPN)
curl -v https://check.torproject.org
# Test direct connection (should fail)
curl -v https://8.8.8.8
```
### Step 7: Verify Package Trust
```bash
# Check CA certificate is installed
ls /etc/pki/rpm-gpg/
# Verify DNF configuration
cat /etc/dnf/dnf.conf
# Test package verification
sudo dnf makecache
```
---
## Part 4: Verify Security Controls
### Step 1: Verify Sudo is Disabled
```bash
# As regular user, try sudo
sudo whoami
# Expected: "user is not in the sudoers file."
# Check user groups
id
# Expected: Should not show 'wheel' group
```
### Step 2: Verify SELinux
```bash
# Check SELinux status
sestatus
# Expected: "Current mode: enforcing"
# Expected: "SELinux enforcement: Enabled"
# Check for denials
sudo ausearch -m avc -ts recent
```
### Step 3: Verify Audit Logging
```bash
# Check auditd status
sudo systemctl status auditd
# Test audit logging
sudo auditctl -l
```
### Step 4: Verify Firewall
```bash
# Check firewall rules
sudo firewall-cmd --list-all
# Check active zones
sudo firewall-cmd --list-zones
# Verify WireGuard is allowed
sudo firewall-cmd --list-services --zone=wg0
```
### Step 5: Verify DNS
```bash
# Check DNS configuration
cat /etc/resolv.conf
# Test DNS resolution
nslookup example.com
# Verify DNS goes through VPN
sudo tcpdump -i any port 53
```
### Step 6: Verify VPN
```bash
# Check WireGuard interface
wg show
# Check routing
ip route show
# Verify all traffic goes through VPN
ip route show table 51820
```
---
## Part 5: Install Custom Packages
### Step 1: Prepare Package Repository
```bash
# Create local repository
sudo mkdir -p /opt/packages
sudo cp /path/to/custom-packages/*.rpm /opt/packages/
# Create repository metadata
sudo createrepo /opt/packages/
# Create repo file
cat > /etc/yum.repos.d/custom.repo << EOF
[custom-packages]
name=Custom Packages
baseurl=file:///opt/packages
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-your-ca
repo_gpgcheck=1
EOF
# Import CA key
sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-your-ca
```
### Step 2: Install Custom Packages
```bash
# Make cache
sudo dnf makecache
# Install custom package
sudo dnf install your-custom-package
# Verify signature
rpm --checksig your-custom-package
```
### Step 3: Install Flatpak Applications
```bash
# Add Flathub (if needed)
flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
# Install applications
flatpak install --user flathub org.gnome.Firefox
flatpak install --user flathub org.libreoffice.LibreOffice
flatpak install --user flathub org.mozilla.thunderbird
# Verify installation
flatpak list
```
---
## Part 6: Configure Update System
### Step 1: Set Up Auto-Download
```bash
# Configure rpm-ostree to auto-download
cat > /etc/rpm-ostreed.conf << EOF
[Service]
DownloadOnly=true
EOF
# Enable auto-download service
sudo systemctl enable rpm-ostreed
```
### Step 2: Configure Approval Workflow
```bash
# Create approval script
cat > /usr/local/bin/approve-update.sh << 'EOF'
#!/bin/bash
# Update approval script
# Shows update details and requires confirmation
sudo rpm-ostree update --check
echo "Review the update above."
echo "Type 'yes' to apply, 'no' to cancel:"
read response
if [ "$response" = "yes" ]; then
sudo rpm-ostree upgrade
else
echo "Update cancelled"
fi
EOF
chmod +x /usr/local/bin/approve-update.sh
```
### Step 3: Set Up Daily CRL Update
```bash
# Copy CRL updater script
sudo cp scripts/daily-crl-update.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/daily-crl-update.sh
# Set up cron job
sudo crontab -l > mycron || echo "" > mycron
echo "0 2 * * * /usr/local/bin/daily-crl-update.sh >> /var/log/crl-update.log 2>&1" >> mycron
sudo crontab mycron
sudo rm mycron
# Verify cron job
sudo crontab -l
```
---
## Part 7: Final Verification
### Step 1: Run Security Audit
```bash
# Copy audit script
sudo cp scripts/security-audit.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/security-audit.sh
# Run audit
sudo /usr/local/bin/security-audit.sh
```
### Step 2: Test Full System
```bash
# Test VPN connectivity
curl -v https://check.torproject.org
# Test DNS lockdown
nslookup google.com
# Test firewall
curl -v https://8.8.8.8
# Test sudo is disabled
sudo whoami
# Test package verification
sudo dnf check-update
```
### Step 3: Document Configuration
```bash
# Save system status
sudo rpm-ostree status > /root/system-status.txt
# Save firewall rules
sudo firewall-cmd --list-all > /root/firewall-rules.txt
# Save VPN config
sudo wg show > /root/wireguard-status.txt
# Save audit logs
sudo ausearch -m all -ts recent > /root/audit-log.txt
```
---
## Troubleshooting Installation Issues
### Issue: ISO Build Fails
**Symptoms:** `lorax` fails with error
**Solution:**
```bash
# Check ISO path
ls -la /path/to/kinoite-iso
# Check kickstart syntax
ksvalidator kinoite-saw.ks
# Try with --no-compress flag
sudo lorax --no-compress ...
```
### Issue: Installation Hangs
**Symptoms:** Installation process hangs
**Solution:**
```bash
# Boot with debug kernel
# Add to boot parameters: inst.debug inst.vnc inst.sshd
# Check disk space
df -h
# Check memory
free -h
```
### Issue: Package Verification Fails
**Symptoms:** `DNF: signature verification failed`
**Solution:**
```bash
# Verify CA certificate
openssl x509 -in /etc/pki/rpm-gpg/RPM-GPG-KEY-your-ca -text -noout
# Re-import key
sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-your-ca
# Check package signature
rpm --checksig package.rpm
```
### Issue: VPN Not Connecting
**Symptoms:** `wg-quick up wg0` fails
**Solution:**
```bash
# Check config
cat /etc/wireguard/wg0.conf
# Check firewall
sudo firewall-cmd --list-all
# Check routing
ip route show
# Test connectivity
ping -c 3 <server-ip>
```
### Issue: DNS Not Working
**Symptoms:** Cannot resolve domain names
**Solution:**
```bash
# Check resolv.conf
cat /etc/resolv.conf
# Check dnsmasq
sudo systemctl status dnsmasq
# Check firewall
sudo firewall-cmd --list-services
```
---
## Next Steps
After successful installation:
1. **Test all applications** - Verify everything works as expected
2. **Configure backup** - Set up backup for important data
3. **Document procedures** - Write your own operational procedures
4. **Set up monitoring** - Configure log monitoring
5. **Create recovery plan** - Document recovery procedures
---
## References
- [Fedora Kinoite Installation Guide](https://kinoite.fedoraproject.org/)
- [rpm-ostree Documentation](https://docs.fedoraproject.org/en-US/fedora-coreos/atomic-updates/)
- [WireGuard Documentation](https://www.wireguard.com/install/)
- [DNF Configuration](https://dnf.readthedocs.io/en/latest/conf.html)
---
**Previous:** [README.md](README.md)
**Next:** [Configuration Details](CONFIGURATION_DETAILS.md)

249
config/wireguard/README.md Normal file
View File

@ -0,0 +1,249 @@
# WireGuard VPN Configuration Examples
## Overview
This directory contains example WireGuard VPN configurations for the SAW implementation.
## Files
```
config/wireguard/
├── wg0.conf.example # Example WireGuard configuration
├── README.md # This file
└── setup-vpn.sh # VPN setup script (optional)
```
## Quick Start
### 1. Generate Keys
```bash
# Generate server keys
wg genkey | tee server_private.key | wg pubkey > server_public.key
# Generate client keys
wg genkey | tee client_private.key | wg pubkey > client_public.key
```
### 2. Configure Server
Create `/etc/wireguard/wg0.conf` on VPN server:
```ini
[Interface]
PrivateKey = <server_private_key>
Address = 10.0.0.1/24
ListenPort = 51820
[Peer]
PublicKey = <client_public_key>
AllowedIPs = 10.0.0.2/32
```
### 3. Configure Client (SAW)
Copy the example config and update with your keys:
```bash
cp config/wireguard/wg0.conf.example /etc/wireguard/wg0.conf
# Edit the configuration
nano /etc/wireguard/wg0.conf
```
### 4. Start VPN
```bash
# Start WireGuard
sudo wg-quick up wg0
# Check status
sudo wg show
# Enable auto-start
sudo systemctl enable wg-quick@wg0
```
## Example Configuration
### wg0.conf.example
```ini
[Interface]
# Your WireGuard private key (generated with: wg genkey)
PrivateKey = YOUR_PRIVATE_KEY_HERE
# VPN interface IP and subnet
Address = 10.0.0.2/24
# DNS servers (should be VPN gateway)
DNS = 10.0.0.1
[Peer]
# VPN server's public key
PublicKey = YOUR_SERVER_PUBLIC_KEY_HERE
# VPN server's endpoint (IP:port)
Endpoint = vpn.example.com:51820
# Which IPs to route through VPN (0.0.0.0/0 = all traffic)
AllowedIPs = 0.0.0.0/0, ::/0
# Keep connection alive (optional)
PersistentKeepalive = 25
```
### Configuration Parameters Explained
#### [Interface] Section
| Parameter | Description | Example |
|-----------|-------------|---------|
| `PrivateKey` | Your WireGuard private key | Generated with `wg genkey` |
| `Address` | VPN interface IP and subnet | `10.0.0.2/24` |
| `ListenPort` | Port to listen on (server only) | `51820` |
| `DNS` | DNS servers to use | `10.0.0.1` |
#### [Peer] Section
| Parameter | Description | Example |
|-----------|-------------|---------|
| `PublicKey` | VPN server's public key | Generated on server |
| `Endpoint` | VPN server address and port | `vpn.example.com:51820` |
| `AllowedIPs` | IPs to route through VPN | `0.0.0.0/0, ::/0` |
| `PersistentKeepalive` | Keep connection alive (optional) | `25` |
## Security Considerations
### Key Management
1. **Generate keys securely**
- Use `wg genkey` (cryptographically secure)
- Never share private keys
- Store keys in encrypted storage
2. **Use strong encryption**
- WireGuard uses ChaCha20-Poly1305 (default)
- Curve25519 key exchange (default)
- No weak algorithms
3. **Restrict AllowedIPs**
- Only allow necessary subnets
- Use `/32` for single IPs
- Avoid `0.0.0.0/0` if not needed
### Network Security
1. **Firewall configuration**
- Allow WireGuard port (UDP 51820)
- Block other ports
- Implement egress filtering
2. **DNS security**
- Use VPN gateway DNS
- Block external DNS
- Consider DNS-over-TLS
3. **Keep-alive settings**
- Use `PersistentKeepalive` for NAT traversal
- Set appropriate interval (25 seconds recommended)
- Disable if not needed
## Troubleshooting
### VPN Not Connecting
```bash
# Check WireGuard status
sudo wg show
# Check configuration
sudo wg-quick diff wg0.conf
# Check logs
sudo journalctl -u wg-quick@wg0
# Test connectivity
ping -I wg0 <server-ip>
```
### DNS Not Working
```bash
# Check DNS configuration
cat /etc/resolv.conf
# Test DNS resolution
nslookup example.com
# Check firewall
sudo firewall-cmd --list-all
```
### Routing Issues
```bash
# Check routing table
ip route show
# Check WireGuard routes
ip route show table 51820
# Test routing
ping -I wg0 <external-ip>
```
## Advanced Configuration
### Split Tunneling
Route only specific traffic through VPN:
```ini
[Peer]
# Only route corporate network
AllowedIPs = 192.168.1.0/24, 10.0.0.0/8
```
### Multi-Hop VPN
Chain multiple VPN servers:
```ini
[Peer]
# First hop
PublicKey = <first_hop_public_key>
Endpoint = <first_hop_endpoint>
AllowedIPs = 10.1.0.0/24
[Peer]
# Second hop (behind first hop)
PublicKey = <second_hop_public_key>
Endpoint = <second_hop_endpoint>
AllowedIPs = 10.2.0.0/24
```
### Load Balancing
Multiple servers for redundancy:
```ini
[Peer]
PublicKey = <server1_public_key>
Endpoint = <server1_ip>:51820
AllowedIPs = 10.0.0.0/24
[Peer]
PublicKey = <server2_public_key>
Endpoint = <server2_ip>:51820
AllowedIPs = 10.0.0.0/24
```
## References
- [WireGuard Documentation](https://www.wireguard.com/)
- [WireGuard Quick Start](https://www.wireguard.com/quickstart/)
- [WireGuard Android/iOS](https://www.wireguard.com/install/)
- [WireGuard Windows](https://www.wireguard.com/install/)
## Support
For WireGuard configuration help:
- Check logs: `sudo journalctl -u wg-quick@wg0`
- Verify config: `sudo wg-quick diff wg0.conf`
- Test connectivity: `ping -I wg0 <server-ip>`

311
kickstart/build-iso.sh Normal file
View File

@ -0,0 +1,311 @@
#!/bin/bash
# Build custom Fedora Kinoite ISO script
# Version: 1.0
# Date: 2026-04-02
#
# This script builds a custom Fedora Kinoite ISO for the SAW implementation
# It requires a base Fedora Kinoite ISO and the custom kickstart file
set -e
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BUILD_DIR="${SCRIPT_DIR}/build"
OUTPUT_DIR="${SCRIPT_DIR}/output"
KICKSTART_FILE="${SCRIPT_DIR}/kinoite-saw.ks"
BASE_ISO=""
ISO_NAME="Fedora-Kinoite-SAW.iso"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Print functions
print_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Usage
usage() {
echo "Usage: $0 -i <base_iso> [-o <output_name>]"
echo ""
echo "Options:"
echo " -i Path to base Fedora Kinoite ISO (required)"
echo " -o Output ISO name (optional, default: $ISO_NAME)"
echo " -h Show this help message"
echo ""
echo "Example:"
echo " $0 -i Fedora-Kinoite-43-x86_64-latest.iso"
exit 1
}
# Parse arguments
while getopts "i:o:h" opt; do
case $opt in
i) BASE_ISO="$OPTARG" ;;
o) ISO_NAME="$OPTARG" ;;
h) usage ;;
\?) usage ;;
esac
done
# Check requirements
check_requirements() {
print_info "Checking requirements..."
# Check if lorax is installed
if ! command -v lorax &> /dev/null; then
print_error "lorax is not installed"
echo "Install with: sudo dnf install -y lorax anaconda-tools"
exit 1
fi
# Check if base ISO is provided
if [ -z "$BASE_ISO" ]; then
print_error "Base ISO not specified"
usage
fi
# Check if base ISO exists
if [ ! -f "$BASE_ISO" ]; then
print_error "Base ISO not found: $BASE_ISO"
exit 1
fi
# Check if kickstart file exists
if [ ! -f "$KICKSTART_FILE" ]; then
print_error "Kickstart file not found: $KICKSTART_FILE"
exit 1
fi
print_info "All requirements met"
}
# Create build directory
create_build_dir() {
print_info "Creating build directory..."
mkdir -p "$BUILD_DIR"
mkdir -p "$OUTPUT_DIR"
}
# Mount base ISO
mount_iso() {
print_info "Mounting base ISO..."
# Create mount point
MOUNT_POINT="${BUILD_DIR}/iso-mount"
mkdir -p "$MOUNT_POINT"
# Mount ISO
sudo mount -o loop "$BASE_ISO" "$MOUNT_POINT"
print_info "ISO mounted at: $MOUNT_POINT"
}
# Copy ISO contents
copy_iso_contents() {
print_info "Copying ISO contents..."
# Create working directory
WORK_DIR="${BUILD_DIR}/work"
mkdir -p "$WORK_DIR"
# Copy ISO contents
cp -r "$MOUNT_POINT"/* "$WORK_DIR/"
cp -r "$MOUNT_POINT"/.discinfo "$WORK_DIR/"
print_info "ISO contents copied to: $WORK_DIR"
}
# Copy kickstart file
copy_kickstart() {
print_info "Copying kickstart file..."
# Copy kickstart to ISO
cp "$KICKSTART_FILE" "$WORK_DIR/kickstart.ks"
print_info "Kickstart file copied"
}
# Update isolinux configuration
update_isolinux() {
print_info "Updating boot configuration..."
ISOLINUX_DIR="${WORK_DIR}/isolinux"
# Check if isolinux directory exists
if [ ! -d "$ISOLINUX_DIR" ]; then
print_warning "isolinux directory not found, using GRUB"
return
fi
# Create custom isolinux configuration
cat > "${ISOLINUX_DIR}/isolinux.cfg" << 'ISOLINUX'
default menu
timeout 600
menu clear
menu background isolinux-bg.png
menu title Fedora Kinoite SAW
menu vshift 8
menu rows 18
menu margin 16
menu helpmsgrow 15
menu tabmsgrow 13
label install
menu label Install Fedora Kinoite SAW
menu default
kernel vmlinuz
append initrd=initrd.img inst.ks=hd:UUID=:kickstart.ks inst.stage2=hd:UUID=: inst.gpt quiet
text help
Install Fedora Kinoite SAW with automated configuration
endtext
label live
menu label Try Fedora Kinoite SAW
kernel vmlinuz
append initrd=initrd.img inst.stage2=hd:UUID=: quiet
label memtest
menu label Memory Test
kernel memtest
append initrd=initrd.img inst.stage2=hd:UUID=:
label local
menu label Boot from local drive
localboot 0x80
menu end
ISOLINUX
print_info "isolinux configuration updated"
}
# Update GRUB configuration
update_grub() {
print_info "Updating GRUB configuration..."
GRUB_DIR="${WORK_DIR}/EFI/BOOT"
# Check if GRUB directory exists
if [ ! -d "$GRUB_DIR" ]; then
print_warning "GRUB directory not found, skipping GRUB update"
return
fi
# Create custom GRUB configuration
cat > "${GRUB_DIR}/grub.cfg" << 'GRUB'
set timeout=10
set default=0
menuentry 'Install Fedora Kinoite SAW' {
linux /isolinux/vmlinuz inst.ks=hd:UUID=:kickstart.ks inst.stage2=hd:UUID=: quiet
initrd /isolinux/initrd.img
}
menuentry 'Try Fedora Kinoite SAW' {
linux /isolinux/vmlinuz inst.stage2=hd:UUID=: quiet
initrd /isolinux/initrd.img
}
menuentry 'Boot from local drive' {
chainloader (hd0,1)
}
GRUB
print_info "GRUB configuration updated"
}
# Update repository configuration
update_repos() {
print_info "Updating repository configuration..."
REPOS_DIR="${WORK_DIR}/LiveOS"
# Create custom repository configuration
cat > "${WORK_DIR}/Packages/repodata/repomd.xml" << 'REPO'
<repomd>
<revision>1</revision>
<repo type="binary" arch="x86_64">
<url>file:///mnt/source</url>
</repo>
</repomd>
REPO
print_info "Repository configuration updated"
}
# Generate ISO
generate_iso() {
print_info "Generating ISO..."
OUTPUT_ISO="${OUTPUT_DIR}/${ISO_NAME}"
# Create ISO using xorriso
sudo xorriso -as mkisofs \
-o "$OUTPUT_ISO" \
-J -R -T \
-volid "Fedora-Kinoite-SAW" \
-b isolinux/isolinux.bin \
-c isolinux/boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-eltorito-alt-boot \
-e EFI/gpt_plpmt.efi \
-no-emul-boot \
-hfs-plus-wrap-aps \
-V "Fedora-Kinoite-SAW" \
"$WORK_DIR/"
print_info "ISO generated: $OUTPUT_ISO"
}
# Unmount ISO
umount_iso() {
print_info "Unmounting ISO..."
sudo umount "$MOUNT_POINT"
rmdir "$MOUNT_POINT"
}
# Cleanup
cleanup() {
print_info "Cleaning up..."
rm -rf "$BUILD_DIR"
}
# Main execution
main() {
print_info "Starting Fedora Kinoite SAW ISO build..."
print_info "Base ISO: $BASE_ISO"
print_info "Output: $OUTPUT_DIR/$ISO_NAME"
check_requirements
create_build_dir
mount_iso
copy_iso_contents
copy_kickstart
update_isolinux
update_grub
update_repos
generate_iso
umount_iso
cleanup
print_info "Build completed successfully!"
print_info "ISO location: $OUTPUT_DIR/$ISO_NAME"
print_info "Size: $(du -h "$OUTPUT_ISO" | cut -f1)"
}
# Run main function
main "$@"

616
kickstart/kinoite-saw.ks Normal file
View File

@ -0,0 +1,616 @@
# Fedora Kinoite SAW Kickstart File
## Overview
This kickstart file creates a custom Fedora Kinoite ISO for the Secure Air-Gapped Workstation (SAW) implementation.
**Key Features:**
- Custom CA certificate pre-installed
- WireGuard VPN pre-configured
- Package verification enabled
- Security hardening applied
- Minimal package set (only essential packages)
## Kickstart File
```bash
# Kickstart file for Fedora Kinoite SAW
# Version: 1.0
# Date: 2026-04-02
# Use text mode installation
text
# System language
lang en_US.UTF-8
# Keyboard layout
keyboard --vckeymap=us --layout=US
# Network configuration
network --bootproto=dhcp --device=eth0 --activate
# Root password (change this!)
rootpw --iscrypted YOUR_ENCRYPTED_PASSWORD_HERE
# Root password (uncomment for interactive)
# rootpw
# User configuration
user --name=saw-user --password=changeme --groups=wheel --shell=/bin/bash
# After lockdown, user will be removed from wheel group
# SELinux configuration
selinux --enforcing
# Firewall configuration
firewall --enabled --service=ssh
# Timezone
timezone America/New_York --utc
# System bootloader
bootloader --location=partition --boot-drive=sda
# Partition information
clearpart --all --initlabel
part / --fstype="ext4" --size=20480 --grow
part /boot/efi --fstype="efi" --size=512 --grow
# Repositories
repo --name=fedora --baseurl=file:///mnt/source
repo --name=updates --baseurl=file:///mnt/source/updates
# Package selection
%packages
@^kinoite-desktop
@base
@core
@standard
# Add your custom packages here
# Example: vim-enhanced git wget
# Remove unnecessary packages
-ibus-angry
-ibus-bopomofo
-ibus-chewing
-ibus-hangul
-ibus-kkc
-ibus-pinyin
-ibus-array
-ibus-typing-booster
-ibus-m17n
-ibus-rawcode
-ibus-lua
-ibus-sayura
-ibus-table
-ibus-table-cantonese
-ibus-table-erbi
-ibus-table-ipa
-ibus-table-jyutping
-ibus-table-wubi
-ibus-table-wbx
-ibus-table-wm
-ibus-table-wm86
-ibus-table-wm95
-ibus-table-wm98
-ibus-table-wubi
-ibus-table-wubi-huizhou
-ibus-table-wubi-pinyin
-ibus-table-wubi-wx
-ibus-table-wubi-wx86
-ibus-table-wubi-wx95
-ibus-table-wubi-wx98
-ibus-table-wubi-wx98p
-ibus-table-wubi-wx98p2
-ibus-table-wubi-wx98p2b
-ibus-table-wubi-wx98pb
-ibus-table-wubi-wx98pbc
-ibus-table-wubi-wx98pbcd
-ibus-table-wubi-wx98pbcd
%end
# CA Certificate Installation
%include /tmp/kickstart-ca-certificate.ks
# WireGuard Configuration
%include /tmp/kickstart-wireguard.ks
# Package Verification Configuration
%include /tmp/kickstart-package-verification.ks
# Post-install configuration
%post --erroronfail
# Remove user from wheel group (disable sudo)
gpasswd -d saw-user wheel
# Disable root SSH login
sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
# Enable auditd
systemctl enable auditd
# Enable SELinux
setenforce 1
# Configure DNS to use VPN gateway only
cat > /etc/dnsmasq.d/vpn-dns.conf << 'EOF'
# VPN-only DNS configuration
# All DNS queries go through VPN gateway
server=10.0.0.1
server=::1
bogus-priv
no-resolv
no-poll
no-hosts
cache-size=10000
log-facility=@/var/log/dnsmasq.log
EOF
# Configure resolv.conf to use dnsmasq
echo "nameserver 127.0.0.1" > /etc/resolv.conf
# Configure firewall
cat > /etc/firewalld/services/wireguard.xml << 'EOF'
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>WireGuard</short>
<description>WireGuard VPN tunnel</description>
<port protocol="udp" port="51820"/>
</service>
EOF
# Add WireGuard to firewall
firewall-cmd --permanent --add-service=wireguard
firewall-cmd --permanent --add-port=51820/udp
# Configure DNF to require signatures
cat > /etc/dnf/dnf.conf << 'EOF'
# DNF configuration for SAW
# Require GPG signature verification
gpgcheck=1
repo_gpgcheck=1
# Disable metadata cache (force refresh)
metadata_expire=1h
# Disable fastest mirror (use direct repos)
fastestmirror=False
EOF
# Create rpm-ostree configuration
cat > /etc/rpm-ostreed.conf << 'EOF'
[Service]
# Auto-download updates
DownloadOnly=true
# Keep previous deployments
KeepOld=2
# Enable automatic cleanup
AutomaticCleanup=true
EOF
# Set up package verification scripts
mkdir -p /usr/local/bin
mkdir -p /etc/package-verification
# Copy CA certificate to DNF key directory
cp /etc/pki/ca-trust/source/anchors/ca.crt /etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca
# Create package verification script
cat > /usr/local/bin/verify-package.sh << 'VERIFYEOF'
#!/bin/bash
# Package verification script
# Verifies package signatures against custom CA
CA_KEY="/etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca"
CRL_FILE="/etc/pki/ca-trust/source/anchors/crl.pem"
# Check if CA key exists
if [ ! -f "$CA_KEY" ]; then
echo "ERROR: CA key not found: $CA_KEY"
exit 1
fi
# Verify CRL if available
if [ -f "$CRL_FILE" ]; then
# Check CRL signature
if ! openssl verify -CAfile "$CA_KEY" "$CRL_FILE" >/dev/null 2>&1; then
echo "WARNING: CRL signature verification failed"
fi
fi
# Verify package signature
for pkg in "$@"; do
if ! rpm --checksig "$pkg" >/dev/null 2>&1; then
echo "ERROR: Package signature verification failed: $pkg"
exit 1
fi
done
echo "All packages verified successfully"
exit 0
VERIFYEOF
chmod +x /usr/local/bin/verify-package.sh
# Create update approval script
cat > /usr/local/bin/approve-update.sh << 'APPROVEEOF'
#!/bin/bash
# Update approval script for SAW
# Shows update details and requires confirmation
echo "=== Fedora Kinoite SAW Update Approval ==="
echo ""
# Check for updates
echo "Checking for updates..."
sudo rpm-ostree update --check 2>&1 | tee /tmp/update-check.txt
if [ ${PIPESTATUS[0]} -ne 0 ]; then
echo "No updates available"
exit 0
fi
echo ""
echo "Review the update above."
echo "Type 'yes' to apply, 'no' to cancel:"
read -r response
if [ "$response" = "yes" ]; then
echo "Applying update..."
sudo rpm-ostree upgrade
else
echo "Update cancelled"
exit 0
fi
APPROVEEOF
chmod +x /usr/local/bin/approve-update.sh
# Create daily CRL updater script
cat > /usr/local/bin/daily-crl-update.sh << 'CRLEOF'
#!/bin/bash
# Daily CRL update script for SAW
# Downloads and verifies CRL from CA server
CRL_URL="https://your-ca-server.com/crl.pem"
CRL_FILE="/etc/pki/ca-trust/source/anchors/crl.pem"
CA_KEY="/etc/pki/ca-trust/source/anchors/ca.crt"
LOG_FILE="/var/log/crl-update.log"
echo "$(date): Starting CRL update" >> "$LOG_FILE"
# Download CRL
if ! curl -s -o "$CRL_FILE" "$CRL_URL"; then
echo "$(date): ERROR: Failed to download CRL" >> "$LOG_FILE"
exit 1
fi
echo "$(date): CRL downloaded successfully" >> "$LOG_FILE"
# Verify CRL signature
if ! openssl crl -in "$CRL_FILE" -CAfile "$CA_KEY" -noout 2>&1; then
echo "$(date): ERROR: CRL signature verification failed" >> "$LOG_FILE"
exit 1
fi
echo "$(date): CRL signature verified" >> "$LOG_FILE"
# Update CA trust
update-ca-trust extract
echo "$(date): CRL update completed successfully" >> "$LOG_FILE"
# Check for packages with revoked certificates
if rpm -qa --queryformat='%{NAME} %{SIGPGP:pgpsig}\n' 2>/dev/null | grep -q "0x0"; then
echo "$(date): WARNING: Found packages with revoked certificates" >> "$LOG_FILE"
fi
exit 0
CRLEOF
chmod +x /usr/local/bin/daily-crl-update.sh
# Create security audit script
cat > /usr/local/bin/security-audit.sh << 'AUDITEOF'
#!/bin/bash
# Security audit script for SAW
echo "=== Fedora Kinoite SAW Security Audit ==="
echo "Date: $(date)"
echo ""
# Check system state
echo "1. System State:"
rpm-ostree status | head -5
echo ""
# Check sudo access
echo "2. Sudo Access:"
if id -nG "$USER" | grep -q wheel; then
echo " WARNING: User is in wheel group (sudo enabled)"
else
echo " OK: User is not in wheel group"
fi
echo ""
# Check SELinux
echo "3. SELinux Status:"
sestatus | grep "Current mode"
echo ""
# Check auditd
echo "4. Auditd Status:"
systemctl is-active auditd || echo " auditd not running"
echo ""
# Check firewall
echo "5. Firewall Status:"
firewall-cmd --state 2>/dev/null || echo " firewalld not running"
echo ""
# Check VPN
echo "6. VPN Status:"
wg show 2>/dev/null || echo " WireGuard not configured"
echo ""
# Check for recent audit events
echo "7. Recent Audit Events:"
ausearch -m all -ts recent 2>/dev/null | head -10
echo ""
# Check for failed sudo attempts
echo "8. Failed Sudo Attempts:"
grep "authentication failure" /var/log/secure 2>/dev/null | tail -5
echo ""
echo "=== Audit Complete ==="
AUDITEOF
chmod +x /usr/local/bin/security-audit.sh
# Create check-verification script
cat > /usr/local/bin/check-verification.sh << 'CHECKEOF'
#!/bin/bash
# Check all package verifications for SAW
echo "=== Package Verification Check ==="
# Check CA certificate
if [ -f /etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca ]; then
echo "OK: CA certificate installed"
else
echo "ERROR: CA certificate not found"
exit 1
fi
# Check DNF configuration
if grep -q "^gpgcheck=1" /etc/dnf/dnf.conf; then
echo "OK: DNF signature verification enabled"
else
echo "ERROR: DNF signature verification not enabled"
exit 1
fi
# Check SELinux
if [ "$(sestatus | grep "Current mode" | awk '{print $3}')" = "enforcing" ]; then
echo "OK: SELinux enforcing"
else
echo "WARNING: SELinux not enforcing"
fi
# Check auditd
if systemctl is-active auditd >/dev/null 2>&1; then
echo "OK: Auditd running"
else
echo "WARNING: Auditd not running"
fi
# Check firewall
if firewall-cmd --state 2>/dev/null | grep -q "running"; then
echo "OK: Firewall running"
else
echo "WARNING: Firewall not running"
fi
echo "=== Verification Complete ==="
CHECKEOF
chmod +x /usr/local/bin/check-verification.sh
# Set up CRL update cron job
cat > /etc/cron.d/crl-update << 'CRONEOF'
# Daily CRL update for SAW
# Run at 2:00 AM
0 2 * * * root /usr/local/bin/daily-crl-update.sh >> /var/log/crl-update.log 2>&1
CRONEOF
# Create initial VPN configuration
cat > /tmp/wireguard.conf << 'WGEOF'
[Interface]
# Replace with your WireGuard private key
PrivateKey = YOUR_PRIVATE_KEY_HERE
# Replace with your VPN interface IP
Address = 10.0.0.2/24
# Replace with your DNS server (VPN gateway)
DNS = 10.0.0.1
[Peer]
# Replace with your VPN server public key
PublicKey = YOUR_SERVER_PUBLIC_KEY_HERE
# Replace with your VPN server endpoint
Endpoint = vpn.example.com:51820
# Allow all traffic through VPN
AllowedIPs = 0.0.0.0/0, ::/0
# Replace with your VPN gateway IP
AllowedIPs = 10.0.0.0/24
WGEOF
# Copy WireGuard config to system
cp /tmp/wireguard.conf /etc/wireguard/wg0.conf
chmod 600 /etc/wireguard/wg0.conf
# Enable WireGuard service
systemctl enable wg-quick@wg0
# Final system updates
dnf update -y
# Clean up
dnf clean all
rm -rf /tmp/kickstart-*.ks
rm -rf /tmp/wireguard.conf
exit 0
%end
```
## Customization Instructions
### 1. Generate Root Password
```bash
# Generate encrypted password
openssl passwd -6
# Replace YOUR_ENCRYPTED_PASSWORD_HERE with the output
```
### 2. Configure CA Certificate
Create a separate file `kickstart-ca-certificate.ks`:
```bash
# Copy CA certificate
%include /tmp/kickstart-ca-certificate.ks
# Create kickstart-ca-certificate.ks:
# Copy CA certificate to system
mkdir -p /etc/pki/ca-trust/source/anchors
cp /run/install/repo/ca.crt /etc/pki/ca-trust/source/anchors/ca.crt
# Update CA trust database
update-ca-trust extract
# Copy to DNF key directory
cp /etc/pki/ca-trust/source/anchors/ca.crt \
/etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca
# Import into RPM database
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca
```
### 3. Configure WireGuard
Update the WireGuard configuration in the kickstart:
```bash
# Replace these values:
PrivateKey = YOUR_PRIVATE_KEY_HERE
Address = 10.0.0.2/24
DNS = 10.0.0.1
PublicKey = YOUR_SERVER_PUBLIC_KEY_HERE
Endpoint = vpn.example.com:51820
```
### 4. Add Custom Packages
Add your packages to the `%packages` section:
```bash
%packages
@^kinoite-desktop
@base
@core
@standard
# Add your custom packages
your-package-1
your-package-2
# Remove unnecessary packages (optional)
-ibus-angry
%end
```
### 5. Configure Package Verification
Update the package verification section with your CA details:
```bash
# Copy CA certificate
cp /etc/pki/ca-trust/source/anchors/ca.crt \
/etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca
# Verify CA key format
openssl x509 -in /etc/pki/ca-trust/source/anchors/ca.crt -text -noout
```
## Troubleshooting
### Kickstart Validation
```bash
# Validate kickstart syntax
ksvalidator kinoite-saw.ks
# Check for errors
# Fix any syntax errors
```
### ISO Build Debugging
```bash
# Add debug output
%post --erroronfail --log=/tmp/kickstart.log
# Check log after build
cat /tmp/kickstart.log
```
### Network Issues
```bash
# Add static network configuration
network --bootproto=static --ip=192.168.1.100 \
--netmask=255.255.255.0 --gateway=192.168.1.1 \
--nameserver=8.8.8.8 --device=eth0
```
### Package Repository Issues
```bash
# Add additional repositories
repo --name=custom --baseurl=http://your-repo.com
```
## Security Considerations
1. **CA Key Security:**
- Store CA private key offline
- Use strong encryption for keys
- Never include private keys in kickstart
2. **Package Signing:**
- Sign all packages with your CA
- Verify signatures before installation
- Keep CRL updated
3. **Network Security:**
- Use VPN for all traffic
- Block all direct internet access
- Implement DNS lockdown
4. **Update Security:**
- Require approval for updates
- Verify update signatures
- Test updates before deployment
## References
- [Kickstart Syntax Reference](https://pykickstart.readthedocs.io/)
- [Fedora Kinoite Installation](https://kinoite.fedoraproject.org/)
- [RPM Signature Verification](https://docs.fedoraproject.org/en-US/fedora-coreos/security-verification/)
- [WireGuard Documentation](https://www.wireguard.com/install/)
---
**Previous:** [Installation Guide](INSTALLATION_GUIDE.md)
**Next:** [Lockdown Script](../post-install/lockdown.sh)

View File

@ -0,0 +1,213 @@
# Package Verification CA Configuration
## Overview
This directory contains the Certificate Authority (CA) configuration for package verification.
## Files
```
package-verification/ca/
├── ca.crt # CA certificate (PLACEHOLDER - you must add your own)
├── ca.key # CA private key (PLACEHOLDER - NEVER include this in the ISO)
├── crl.pem # Certificate Revocation List (PLACEHOLDER)
└── README.md # This file
```
## CA Certificate
### What is a CA Certificate?
A CA (Certificate Authority) certificate is used to sign and verify packages. It ensures:
1. **Integrity** - Packages haven't been modified
2. **Authenticity** - Packages come from your trusted source
3. **Non-repudiation** - Can prove who signed the package
### Creating Your CA Certificate
```bash
# Generate CA private key
openssl genrsa -out ca.key 4096
# Generate CA certificate
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt
# Verify certificate
openssl x509 -in ca.crt -text -noout
```
### Installing CA Certificate
The CA certificate should be:
1. **Embedded in ISO** - During ISO build
2. **Installed to system** - `/etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca`
3. **Imported into RPM database** - `rpm --import`
4. **Added to CA trust** - `update-ca-trust`
## CA Private Key
### Security Requirements
The CA private key is **CRITICAL** to protect:
1. **Never include in ISO** - Only use on signing machine
2. **Store offline** - USB drive or air-gapped system
3. **Use strong encryption** - AES-256 with passphrase
4. **Back up securely** - Multiple encrypted backups
5. **Use hardware token** - HSM for maximum security
### Signing Packages
```bash
# Sign RPM packages
rpm --define "%_gpg_name Your CA Name" --addsign package.rpm
# Sign with specific key
rpm --define "%_gpg_name Your CA Name" --addsign --define '_gpg_transport_key YOUR_KEY_ID' package.rpm
# Verify signature
rpm --checksig package.rpm
```
## Certificate Revocation List (CRL)
### What is a CRL?
A CRL is a list of certificates that have been revoked before their expiration date. It's used to:
1. **Detect compromised certificates**
2. **Block revoked packages**
3. **Respond to security incidents**
4. **Maintain trust**
### Creating a CRL
```bash
# Create a certificate to revoke (for testing)
openssl req -new -nodes -out test.csr
openssl ca -in test.csr -out test.crt
# Revoke the certificate
openssl ca -revoke test.crt
# Generate CRL
openssl ca -gencrl -out crl.pem
# Verify CRL
openssl crl -in crl.pem -noout -text
```
### CRL Distribution
The CRL should be:
1. **Hosted on secure server** - HTTPS with authentication
2. **Signed by CA** - Ensure CRL authenticity
3. **Updated regularly** - Daily recommended
4. **Cached locally** - For offline verification
## Package Signing
### Creating Signed Packages
1. **Create package** - Build your RPM package
2. **Sign package** - Use CA private key to sign
3. **Distribute** - Share signed package
4. **Verify** - Recipients verify signature
### Example Package Signing Workflow
```bash
# Step 1: Build package
rpmbuild -bb your-package.spec
# Step 2: Sign package
rpm --define "%_gpg_name Your CA Name" --addsign ~/rpmbuild/RPMS/x86_64/your-package.rpm
# Step 3: Verify signature
rpm --checksig ~/rpmbuild/RPMS/x86_64/your-package.rpm
```
## Security Best Practices
### CA Key Management
1. **Generate on air-gapped system**
2. **Store in encrypted storage**
3. **Use hardware security module (HSM)**
4. **Implement key rotation**
5. **Maintain audit trail**
### Certificate Management
1. **Set appropriate validity period** - 1-3 years for CA
2. **Use strong algorithms** - RSA 4096, ECDSA P-256
3. **Implement certificate policies**
4. **Maintain certificate registry**
5. **Track certificate lifecycle**
### CRL Management
1. **Update daily** - Ensure current revocation status
2. **Sign CRL** - Use CA key for authenticity
3. **Cache CRL** - For offline verification
4. **Monitor expiration** - Renew before expiration
5. **Test revocation** - Verify revocation works
### Package Signing
1. **Sign all packages** - No unsigned packages
2. **Verify before install** - Always check signature
3. **Log all operations** - Audit trail
4. **Use separate signing keys** - For different purposes
5. **Implement key rotation** - Regularly rotate keys
## Troubleshooting
### CA Certificate Not Found
```bash
# Verify certificate exists
ls -la /etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca
# Check certificate format
openssl x509 -in /etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca -text -noout
```
### Package Signature Verification Failed
```bash
# Verify package signature
rpm --checksig package.rpm
# Check CA key is imported
rpm -q gpg-pubkey
# Re-import CA key
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca
```
### CRL Verification Failed
```bash
# Verify CRL format
openssl crl -in crl.pem -noout -text
# Check CRL signature
openssl crl -in crl.pem -CAfile ca.crt -noout
# Verify CRL dates
openssl crl -in crl.pem -noout -text | grep -E "(Last Update|Next Update)"
```
## References
- [OpenSSL Documentation](https://www.openssl.org/docs/)
- [RPM Signature Documentation](https://docs.fedoraproject.org/en-US/fedora-coreos/security-verification/)
- [Certificate Management Best Practices](https://csrc.nist.gov/publications)
## Contact
For questions about CA configuration, contact your security administrator.

View File

@ -0,0 +1,444 @@
#!/bin/bash
# CRL (Certificate Revocation List) Update Script for SAW
# Version: 1.0
# Date: 2026-04-02
#
# This script downloads, verifies, and installs the Certificate Revocation List (CRL)
# from your Certificate Authority (CA) server. It ensures that packages signed with
# revoked certificates are not installed.
#
# Usage: sudo ./verify-crl.sh [--download] [--verify] [--update] [--status]
#
# SECURITY RATIONALE:
# CRL checking is critical for security because it:
# 1. Detects compromised CA keys
# 2. Revokes access for compromised certificates
# 3. Prevents installation of packages signed with revoked keys
# 4. Provides a mechanism to respond to security incidents
# 5. Meets compliance requirements (PCI-DSS, HIPAA, etc.)
#
# How CRL works:
# 1. CA maintains a list of revoked certificates
# 2. CRL is signed by CA to prevent tampering
# 3. System downloads CRL regularly
# 4. Before installing package, checks if certificate is revoked
# 5. If revoked, installation is blocked
#
# Reference: https://www.openssl.org/docs/man1.1.1/man1/crl.html
set -e
# Configuration
CRL_URL="https://your-ca-server.com/crl.pem"
CRL_FILE="/etc/pki/ca-trust/source/anchors/crl.pem"
CA_KEY_PATH="/etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca"
CRL_CACHE_FILE="/var/cache/crl/crl.pem"
LOG_FILE="/var/log/crl-update.log"
CRL_UPDATE_SCRIPT="/usr/local/bin/daily-crl-update.sh"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
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"
}
# Check if running as root
check_root() {
if [ "$EUID" -ne 0 ]; then
log_error "This script must be run as root"
exit 1
fi
}
# Download CRL from CA server
download_crl() {
log_info "Downloading CRL from: $CRL_URL"
# Check if URL is configured
if [ "$CRL_URL" = "https://your-ca-server.com/crl.pem" ]; then
log_error "CRL URL not configured"
log_info "Edit the script and set CRL_URL to your CA server"
exit 1
fi
# Create cache directory
mkdir -p /var/cache/crl
# Download CRL
if ! curl -s -o "$CRL_CACHE_FILE" "$CRL_URL"; then
log_error "Failed to download CRL"
exit 1
fi
log_info "CRL downloaded to: $CRL_CACHE_FILE"
# Verify download was successful
if [ ! -f "$CRL_CACHE_FILE" ]; then
log_error "CRL file not created"
exit 1
fi
if [ ! -s "$CRL_CACHE_FILE" ]; then
log_error "CRL file is empty"
exit 1
fi
log_info "CRL file size: $(du -h "$CRL_CACHE_FILE" | cut -f1)"
}
# Verify CRL signature
#
# SECURITY RATIONALE:
# Verifying the CRL signature ensures:
# 1. CRL hasn't been tampered with during download
# 2. CRL comes from your trusted CA
# 3. CRL is authentic and hasn't been replaced by attacker
# 4. CRL is valid and hasn't expired
#
# The verification process:
# 1. Check if CRL is properly formatted
# 2. Verify CRL signature using CA public key
# 3. Check CRL validity period
# 4. Ensure CRL hasn't expired
verify_crl() {
log_info "Verifying CRL signature..."
# Check if CA key exists
if [ ! -f "$CA_KEY_PATH" ]; then
log_error "CA key not found: $CA_KEY_PATH"
exit 1
fi
# Check if CRL exists
if [ ! -f "$CRL_CACHE_FILE" ]; then
log_error "CRL not found: $CRL_CACHE_FILE"
log_info "Run with --download first"
exit 1
fi
# Verify CRL format
if ! openssl crl -in "$CRL_CACHE_FILE" -noout 2>/dev/null; then
log_error "CRL format is invalid"
exit 1
fi
# Verify CRL signature
if ! openssl crl -in "$CRL_CACHE_FILE" -CAfile "$CA_KEY_PATH" -noout 2>/dev/null; then
log_error "CRL signature verification failed"
exit 1
fi
# Get CRL information
local crl_info=$(openssl crl -in "$CRL_CACHE_FILE" -noout -text 2>/dev/null)
# Extract CRL dates
local this_update=$(echo "$crl_info" | grep "Last Update:" | head -1)
local next_update=$(echo "$crl_info" | grep "Next Update:" | head -1)
log_info "CRL Last Update: $this_update"
log_info "CRL Next Update: $next_update"
# Check if CRL is expired
local next_update_date=$(echo "$next_update" | awk '{print $4, $5, $6, $7, $8, $9}')
local current_date=$(date)
if [[ "$current_date" > "$next_update_date" ]]; then
log_warning "CRL has expired!"
log_warning "CRL should be updated immediately"
else
log_info "CRL is valid"
fi
log_info "CRL signature verified successfully"
}
# Update CA trust with CRL
update_ca_trust() {
log_info "Updating CA trust database..."
# Copy CRL to CA trust source
mkdir -p /etc/pki/ca-trust/source/anchors
cp "$CRL_CACHE_FILE" /etc/pki/ca-trust/source/anchors/crl.pem
# Update CA trust
update-ca-trust extract
log_info "CA trust database updated"
}
# Check revoked certificates
check_revoked() {
log_info "Checking for revoked certificates..."
# Check if CRL exists
if [ ! -f "$CRL_FILE" ]; then
log_warning "CRL not found: $CRL_FILE"
log_info "Run with --download and --verify first"
return 1
fi
# Check if CA key exists
if [ ! -f "$CA_KEY_PATH" ]; then
log_error "CA key not found: $CA_KEY_PATH"
exit 1
fi
# Get list of installed packages with signatures
local revoked_count=0
local total_count=0
log_info "Scanning installed packages..."
# Get all installed packages
local packages=$(rpm -qa --queryformat='%{NAME} %{SIGPGP:pgpsig}\n' 2>/dev/null | head -100)
for pkg in $packages; do
# Extract certificate ID from signature
local cert_id=$(echo "$pkg" | awk '{print $2}' | cut -d: -f2)
if [ -n "$cert_id" ]; then
# Check if certificate is in CRL
if openssl crl -in "$CRL_FILE" -noout -text 2>/dev/null | grep -q "$cert_id"; then
log_error "REVOKED: Package signed with revoked certificate: $cert_id"
((revoked_count++))
fi
fi
((total_count++))
done
echo ""
echo "=== Revocation Check Summary ==="
echo "Total packages checked: $total_count"
echo "Revoked certificates found: $revoked_count"
echo ""
if [ $revoked_count -gt 0 ]; then
log_error "WARNING: $revoked_count packages have revoked certificates!"
log_info "These packages should be removed and reinstalled"
return 1
fi
log_info "No revoked certificates found"
return 0
}
# Display CRL status
show_status() {
echo ""
echo "=== CRL Status ==="
echo ""
# Check if CRL exists
if [ -f "$CRL_CACHE_FILE" ]; then
echo "CRL Cache File: $CRL_CACHE_FILE"
echo "Size: $(du -h "$CRL_CACHE_FILE" | cut -f1)"
echo "Modified: $(stat -c %y "$CRL_CACHE_FILE")"
echo ""
# Show CRL information
if openssl crl -in "$CRL_CACHE_FILE" -noout -text 2>/dev/null | head -10; then
echo ""
fi
# Check if valid
if openssl crl -in "$CRL_CACHE_FILE" -CAfile "$CA_KEY_PATH" -noout 2>/dev/null; then
echo "Status: VALID"
echo "Signed by: $CA_KEY_PATH"
else
echo "Status: INVALID"
fi
else
echo "CRL Cache File: NOT FOUND"
echo "Status: CRL has not been downloaded"
fi
echo ""
echo "CA Key: $CA_KEY_PATH"
if [ -f "$CA_KEY_PATH" ]; then
echo "Status: FOUND"
else
echo "Status: NOT FOUND"
fi
echo ""
}
# Create daily CRL update script
create_daily_script() {
log_info "Creating daily CRL update script..."
cat > "$CRL_UPDATE_SCRIPT" << 'DAILYSCHEDULE'
#!/bin/bash
# Daily CRL update script for SAW
# This script is run by cron to keep CRL up to date
CRL_URL="https://your-ca-server.com/crl.pem"
CRL_CACHE_FILE="/var/cache/crl/crl.pem"
CA_KEY_PATH="/etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca"
LOG_FILE="/var/log/crl-update.log"
# Function to log
log_info() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
log_error() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $1" >> "$LOG_FILE"
}
log_warning() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARNING] $1" >> "$LOG_FILE"
}
log_info "Starting CRL update"
# Check if CRL URL is configured
if [ "$CRL_URL" = "https://your-ca-server.com/crl.pem" ]; then
log_error "CRL URL not configured"
exit 1
fi
# Download CRL
if ! curl -s -o "$CRL_CACHE_FILE" "$CRL_URL"; then
log_error "Failed to download CRL"
exit 1
fi
log_info "CRL downloaded successfully"
# Verify CRL
if ! openssl crl -in "$CRL_CACHE_FILE" -CAfile "$CA_KEY_PATH" -noout 2>/dev/null; then
log_error "CRL verification failed"
exit 1
fi
log_info "CRL verified successfully"
# Update CA trust
update-ca-trust extract
log_info "CRL update completed successfully"
DAILYSCHEDULE
chmod +x "$CRL_UPDATE_SCRIPT"
log_info "Daily update script created: $CRL_UPDATE_SCRIPT"
}
# Set up cron job for daily updates
setup_cron() {
log_info "Setting up cron job for daily CRL updates..."
# Create cron job
cat > /etc/cron.d/saw-crl-update << 'CRONJOB'
# Daily CRL update for SAW
# Run at 2:00 AM
0 2 * * * root /usr/local/bin/daily-crl-update.sh >> /var/log/crl-update.log 2>&1
CRONJOB
chmod 644 /etc/cron.d/saw-crl-update
log_info "Cron job created"
log_info "CRL will be updated daily at 2:00 AM"
}
# Display help
show_help() {
cat << 'HELP'
CRL Update Script for SAW
=========================
Usage: ./verify-crl.sh [OPTIONS]
Options:
--download Download CRL from CA server
--verify Verify CRL signature
--update Update CA trust database
--check Check for revoked certificates
--status Show CRL status
--cron Set up daily cron job
--help Show this help message
Examples:
# Download and verify CRL
./verify-crl.sh --download --verify --update
# Check status
./verify-crl.sh --status
# Check for revoked certificates
./verify-crl.sh --check
Security Notes:
- CRL should be updated daily
- CRL is signed by CA to prevent tampering
- Packages signed with revoked certificates will be blocked
- CRL expiration should be monitored
Reference: https://www.openssl.org/docs/man1.1.1/man1/crl.html
HELP
}
# Main execution
main() {
echo ""
echo "=========================================="
echo " CRL Update Script"
echo " Fedora Kinoite SAW"
echo "=========================================="
echo ""
check_root
case "${1:-}" in
--download)
download_crl
;;
--verify)
check_root
verify_crl
;;
--update)
check_root
verify_crl
update_ca_trust
;;
--check)
check_root
check_revoked
;;
--status)
show_status
;;
--cron)
check_root
create_daily_script
setup_cron
;;
--help|-h)
show_help
;;
*)
show_help
;;
esac
}
# Run main function
main "$@"

View File

@ -0,0 +1,399 @@
#!/bin/bash
# Package Signature Verification Script for SAW
# Version: 1.0
# Date: 2026-04-02
#
# This script verifies package signatures against your custom Certificate Authority (CA).
# It ensures that only packages signed by your trusted CA can be installed on the system.
#
# Usage: sudo ./verify-signature.sh <package.rpm>
# sudo ./verify-signature.sh --verify-all
# sudo ./verify-signature.sh --check-all
#
# SECURITY RATIONALE:
# Package verification is critical for security because it:
# 1. Prevents installation of malicious packages (tampering detection)
# 2. Ensures package integrity (not modified in transit)
# 3. Authenticates package source (only your CA can sign)
# 4. Provides non-repudiation (can prove who signed the package)
# 5. Prevents supply chain attacks
# 6. Blocks unsigned packages completely
#
# Implementation Details:
# - Uses RPM GPG signature verification
# - Verifies against custom CA public key
# - Checks CRL (Certificate Revocation List) for revoked certificates
# - Logs all verification attempts
#
# Reference: https://docs.fedoraproject.org/en-US/fedora-coreos/security-verification/
set -e
# Configuration
CA_KEY_PATH="/etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca"
CRL_FILE="/etc/pki/ca-trust/source/anchors/crl.pem"
LOG_FILE="/var/log/package-verification.log"
VERIFY_SCRIPT_DIR="/usr/local/bin"
CONFIG_FILE="/etc/saw/package-verification.conf"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
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"
}
# 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 CA key exists
check_ca_key() {
if [ ! -f "$CA_KEY_PATH" ]; then
log_error "CA key not found: $CA_KEY_PATH"
log_info "Package verification requires CA key"
log_info "Copy your CA public key to: $CA_KEY_PATH"
exit 1
fi
log_info "CA key found: $CA_KEY_PATH"
}
# Verify a single package
#
# SECURITY RATIONALE:
# Verifying individual package signatures ensures:
# 1. Package wasn't tampered with during download
# 2. Package comes from trusted source
# 3. Package wasn't modified by attacker
# 4. Package hasn't been replaced with malicious version
#
# The verification process:
# 1. Extract package header
# 2. Verify RSA signature using CA public key
# 3. Compare hash of package contents
# 4. Check signature validity
#
# If verification fails, the package should NOT be installed.
verify_package() {
local package="$1"
log_info "Verifying package: $package"
# Check if file exists
if [ ! -f "$package" ]; then
log_error "Package not found: $package"
return 1
fi
# Verify package signature
if ! rpm --checksig "$package" > /dev/null 2>&1; then
log_error "Package signature verification failed: $package"
log_info "Package may be tampered or unsigned"
return 1
fi
# Extract signature info
local sig_info=$(rpm --checksig "$package" 2>&1)
# Check if signed with our CA
if echo "$sig_info" | grep -q "$CA_KEY_PATH"; then
log_info "Package verified successfully (signed with CA)"
else
log_warning "Package signed but not with our CA"
log_info "Signature info: $sig_info"
return 1
fi
# Verify CRL if available
if [ -f "$CRL_FILE" ]; then
log_info "Checking CRL for revoked certificates..."
# Extract certificate ID from signature
local cert_id=$(rpm --queryformat='%{SIGPGP:pgpsig}\n' -p "$package" 2>/dev/null | head -1 | awk '{print $2}' | cut -d: -f2)
if [ -n "$cert_id" ]; then
# Check if certificate is revoked
if openssl crl -in "$CRL_FILE" -noout -text 2>/dev/null | grep -q "$cert_id"; then
log_error "Package signed with REVOKED certificate: $cert_id"
return 1
fi
log_info "Certificate not revoked: $cert_id"
fi
fi
log_info "Package verified successfully: $package"
return 0
}
# Verify all installed packages
#
# SECURITY RATIONALE:
# Regular verification of all installed packages ensures:
# 1. No packages were tampered with after installation
# 2. No malicious packages were added
# 3. All packages are still properly signed
# 4. Any compromised packages are detected
#
# This should be run regularly (weekly/monthly) to ensure
# the integrity of the entire system.
verify_all_packages() {
log_info "Verifying all installed packages..."
local failed=0
local total=0
local revoked=0
# Get list of all installed packages
local packages=$(rpm -qa --queryformat='%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm\n' 2>/dev/null)
for pkg in $packages; do
# Get package file path
local pkg_path=$(rpm -ql "$pkg" 2>/dev/null | head -1 | xargs dirname)
local pkg_name=$(echo "$pkg" | sed 's/\.rpm$//')
# Check if package is signed
if rpm --queryformat='%{SIGPGP:pgpsig}\n' -q "$pkg_name" 2>/dev/null | grep -q "0x0"; then
log_warning "Package $pkg_name has no signature"
((failed++))
else
# Check signature
if ! rpm --queryformat='%{SIGPGP:pgpsig}\n' -q "$pkg_name" 2>/dev/null | grep -q "0x"; then
log_warning "Package $pkg_name signature verification failed"
((failed++))
else
log_info "Package $pkg_name verified"
fi
fi
((total++))
done
echo ""
echo "=== Verification Summary ==="
echo "Total packages: $total"
echo "Verified: $((total - failed))"
echo "Failed: $failed"
echo "Revoked: $revoked"
echo ""
if [ $failed -gt 0 ]; then
log_error "Some packages failed verification!"
return 1
fi
log_info "All packages verified successfully"
return 0
}
# Check DNF configuration
check_dnf_config() {
log_info "Checking DNF configuration..."
if [ ! -f /etc/dnf/dnf.conf ]; then
log_warning "DNF configuration not found"
return 1
fi
# Check if signature verification is enabled
if grep -q "^gpgcheck=1" /etc/dnf/dnf.conf; then
log_info "DNF signature verification enabled"
else
log_error "DNF signature verification NOT enabled"
return 1
fi
# Check if repo signature verification is enabled
if grep -q "^repo_gpgcheck=1" /etc/dnf/dnf.conf; then
log_info "DNF repo signature verification enabled"
else
log_error "DNF repo signature verification NOT enabled"
return 1
fi
return 0
}
# Verify DNF cache
verify_dnf_cache() {
log_info "Verifying DNF cache..."
# Check if DNF cache exists
if [ ! -d /var/cache/dnf ]; then
log_warning "DNF cache not found"
return 1
fi
# List cached packages
log_info "Cached packages:"
find /var/cache/dnf -name "*.rpm" -type f 2>/dev/null | while read -r pkg; do
local pkg_name=$(basename "$pkg")
if rpm --checksig "$pkg" > /dev/null 2>&1; then
log_info " $pkg_name: VERIFIED"
else
log_error " $pkg_name: FAILED"
fi
done
return 0
}
# Create package verification script for users
create_user_script() {
log_info "Creating user package verification script..."
cat > "$VERIFY_SCRIPT_DIR/verify-package.sh" << 'VERIFYSCRIPT'
#!/bin/bash
# Package verification script for SAW
# Usage: ./verify-package.sh <package.rpm>
CA_KEY="/etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca"
CRL_FILE="/etc/pki/ca-trust/source/anchors/crl.pem"
# Check if CA key exists
if [ ! -f "$CA_KEY" ]; then
echo "ERROR: CA key not found: $CA_KEY"
echo "Contact system administrator"
exit 1
fi
# Check if file is provided
if [ $# -lt 1 ]; then
echo "Usage: $0 <package.rpm>"
exit 1
fi
PACKAGE="$1"
# Check if file exists
if [ ! -f "$PACKAGE" ]; then
echo "ERROR: Package not found: $PACKAGE"
exit 1
fi
# Verify package signature
if ! rpm --checksig "$PACKAGE" > /dev/null 2>&1; then
echo "ERROR: Package signature verification failed: $PACKAGE"
echo "Package may be tampered or unsigned"
exit 1
fi
# Extract signature info
SIG_INFO=$(rpm --checksig "$PACKAGE" 2>&1)
# Check if signed with our CA
if echo "$SIG_INFO" | grep -q "$CA_KEY"; then
echo "OK: Package verified successfully (signed with CA)"
else
echo "WARNING: Package signed but not with our CA"
echo "Signature info: $SIG_INFO"
exit 1
fi
# Verify CRL if available
if [ -f "$CRL_FILE" ]; then
echo "Checking CRL for revoked certificates..."
if ! openssl crl -in "$CRL_FILE" -CAfile "$CA_KEY" -noout 2>/dev/null; then
echo "WARNING: CRL verification failed"
fi
fi
echo "Package verification complete"
exit 0
VERIFYSCRIPT
chmod +x "$VERIFY_SCRIPT_DIR/verify-package.sh"
log_info "User verification script created"
}
# Display help
show_help() {
cat << 'HELP'
Package Signature Verification Script for SAW
==============================================
Usage: ./verify-signature.sh [OPTIONS] <package.rpm>
Options:
--verify-all Verify all installed packages
--check-all Check all packages (same as --verify-all)
--check-dnf Check DNF configuration
--verify-dnf Verify DNF cache
--help Show this help message
Examples:
# Verify a single package
./verify-signature.sh package.rpm
# Verify all installed packages
./verify-signature.sh --verify-all
# Check DNF configuration
./verify-signature.sh --check-dnf
Security Notes:
- This script requires root privileges
- Only packages signed by your CA will pass verification
- Unsigned packages will be rejected
- Packages with revoked certificates will be rejected
Reference: https://docs.fedoraproject.org/en-US/fedora-coreos/security-verification/
HELP
}
# Main execution
main() {
echo ""
echo "=========================================="
echo " Package Signature Verification"
echo " Fedora Kinoite SAW"
echo "=========================================="
echo ""
check_root
check_ca_key
case "${1:-}" in
--verify-all|--check-all)
verify_all_packages
;;
--check-dnf)
check_dnf_config
;;
--verify-dnf)
verify_dnf_cache
;;
--help|-h)
show_help
;;
*)
if [ $# -lt 1 ]; then
show_help
exit 0
fi
verify_package "$1"
;;
esac
}
# Run main function
main "$@"

View File

@ -0,0 +1,414 @@
#!/bin/bash
# WireGuard VPN Configuration Script for SAW
# Version: 1.0
# Date: 2026-04-02
#
# This script configures WireGuard VPN for the Secure Air-Gapped Workstation (SAW)
# It sets up the VPN tunnel, configures routing, and implements kill-switch functionality.
#
# Usage: sudo ./configure-vpn.sh
#
# SECURITY RATIONALE:
# WireGuard is used because it provides:
# 1. Modern, fast encryption (ChaCha20-Poly1305, Curve25519)
# 2. Simple configuration
# 3. Kernel-native implementation (faster than userspace)
# 4. Strong security properties
# 5. Easy to audit and verify
#
# The kill-switch ensures:
# - No traffic leaks when VPN is down
# - No direct internet access
# - All traffic must go through encrypted VPN tunnel
#
# Reference: https://www.wireguard.com/install/
set -e
# Configuration
VPN_CONFIG_FILE="/etc/wireguard/wg0.conf"
VPN_INTERFACE="wg0"
VPN_RULE_FILE="/etc/iproute2/rt_tables.d/51820-wg0"
KILL_SWITCH_SCRIPT="/usr/local/bin/wg-kill-switch.sh"
LOG_FILE="/var/log/wg-vpn-config.log"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
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"
}
# 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 WireGuard is installed
check_wireguard() {
log_info "Checking WireGuard installation..."
if ! command -v wg &> /dev/null; then
log_warning "WireGuard not installed"
log_info "Installing WireGuard..."
dnf install -y wireguard-dkms wireguard-tools
fi
# Check if kernel module is loaded
if ! lsmod | grep -q wireguard; then
log_info "Loading WireGuard kernel module..."
modprobe wireguard
fi
log_info "WireGuard is ready"
}
# Validate WireGuard configuration
validate_config() {
log_info "Validating WireGuard configuration..."
if [ ! -f "$VPN_CONFIG_FILE" ]; then
log_error "WireGuard configuration not found: $VPN_CONFIG_FILE"
log_info "Please create the configuration file first"
# Show example configuration
cat << 'EXAMPLE'
Example WireGuard Configuration:
[Interface]
# Your WireGuard private key (generated with: wg genkey)
PrivateKey = YOUR_PRIVATE_KEY_HERE
# VPN interface IP and subnet
Address = 10.0.0.2/24
# DNS servers (should be VPN gateway)
DNS = 10.0.0.1
[Peer]
# VPN server's public key
PublicKey = YOUR_SERVER_PUBLIC_KEY_HERE
# VPN server's endpoint (IP:port)
Endpoint = vpn.example.com:51820
# Which IPs to route through VPN (0.0.0.0/0 = all traffic)
AllowedIPs = 0.0.0.0/0, ::/0
EXAMPLE
exit 1
fi
# Check private key permissions
if [ -f "$VPN_CONFIG_FILE" ]; then
local perm=$(stat -c %a "$VPN_CONFIG_FILE")
if [ "$perm" != "600" ]; then
log_warning "WireGuard config permissions: $perm (should be 600)"
chmod 600 "$VPN_CONFIG_FILE"
log_info "Fixed permissions to 600"
fi
fi
# Validate configuration syntax
if ! wg-quick parse-config "$VPN_CONFIG_FILE" >/dev/null 2>&1; then
log_error "Invalid WireGuard configuration"
wg-quick parse-config "$VPN_CONFIG_FILE"
exit 1
fi
log_info "WireGuard configuration validated"
}
# Create routing table
create_routing_table() {
log_info "Creating routing table for WireGuard..."
# Create routing table definition
cat > "$VPN_RULE_FILE" << 'ROUTES'
# WireGuard routing table
# Table 51820 is used for WireGuard traffic
51820 wg0
ROUTES
# Add default route through WireGuard interface
ip route add default dev "$VPN_INTERFACE" table 51820 2>/dev/null || true
log_info "Routing table created"
}
# Configure iptables rules
configure_firewall() {
log_info "Configuring firewall rules for WireGuard..."
# Check if iptables is available
if ! command -v iptables &> /dev/null; then
log_warning "iptables not available, skipping"
return
fi
# Allow WireGuard traffic
iptables -A OUTPUT -o "$VPN_INTERFACE" -j ACCEPT 2>/dev/null || true
iptables -A INPUT -i "$VPN_INTERFACE" -j ACCEPT 2>/dev/null || true
# Block all other outbound traffic
iptables -A OUTPUT ! -o lo ! -o "$VPN_INTERFACE" -j REJECT 2>/dev/null || true
# Allow loopback
iptables -A OUTPUT -o lo -j ACCEPT 2>/dev/null || true
log_info "Firewall rules configured"
}
# Create kill-switch script
#
# SECURITY RATIONALE:
# The kill-switch is critical for security because it:
# 1. Prevents traffic leaks when VPN is down
# 2. Ensures all traffic goes through encrypted tunnel
# 3. Blocks DNS leaks (DNS only works through VPN)
# 4. Prevents data exfiltration when VPN is unavailable
# 5. Provides "fail closed" security model
#
# How it works:
# - Monitors VPN interface status
# - If VPN goes down, blocks all traffic (except loopback)
# - If VPN comes up, allows traffic through VPN
# - Can be configured to allow specific services (like update servers)
create_kill_switch() {
log_info "Creating kill-switch script..."
cat > "$KILL_SWITCH_SCRIPT" << 'KILLSCRIPT'
#!/bin/bash
# WireGuard Kill-Switch Script for SAW
# This script blocks all traffic when VPN is down
VPN_INTERFACE="wg0"
LOG_FILE="/var/log/wg-kill-switch.log"
# Function to enable kill-switch
enable_killswitch() {
log_info "Enabling kill-switch..."
# Flush existing rules
iptables -F OUTPUT 2>/dev/null || true
# Allow loopback
iptables -A OUTPUT -o lo -j ACCEPT
# Allow established connections (for cleanup)
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Block all other outbound traffic
iptables -A OUTPUT -j REJECT
log_info "Kill-switch enabled"
}
# Function to disable kill-switch
disable_killswitch() {
log_info "Disabling kill-switch..."
# Flush rules
iptables -F OUTPUT 2>/dev/null || true
# Allow all traffic (for VPN configuration)
iptables -A OUTPUT -j ACCEPT
log_info "Kill-switch disabled"
}
# Function to check VPN status
check_vpn() {
if ip link show "$VPN_INTERFACE" >/dev/null 2>&1; then
# VPN interface exists and is up
if ip addr show "$VPN_INTERFACE" | grep -q "state UP"; then
return 0 # VPN is up
fi
fi
return 1 # VPN is down
}
# Function to log
log_info() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
# Main logic
case "$1" in
enable)
enable_killswitch
;;
disable)
disable_killswitch
;;
status)
if check_vpn; then
echo "VPN is UP"
exit 0
else
echo "VPN is DOWN"
exit 1
fi
;;
*)
# Check VPN and act accordingly
if check_vpn; then
disable_killswitch
else
enable_killswitch
fi
;;
esac
KILLSCRIPT
chmod +x "$KILL_SWITCH_SCRIPT"
log_info "Kill-switch script created"
}
# Configure systemd service for kill-switch
configure_killswitch_service() {
log_info "Configuring kill-switch systemd service..."
cat > /etc/systemd/system/wg-killswitch.service << 'KILLSERVICE'
[Unit]
Description=WireGuard Kill-Switch Service
After=network.target wg-quick@wg0.service
Wants=wg-quick@wg0.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/wg-kill-switch.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
KILLSERVICE
systemctl daemon-reload
systemctl enable wg-killswitch
log_info "Kill-switch service configured"
}
# Configure DNS to use VPN gateway
configure_dns() {
log_info "Configuring DNS to use VPN gateway..."
# Read VPN config to get DNS settings
if [ -f "$VPN_CONFIG_FILE" ]; then
local dns_servers=$(grep "^DNS =" "$VPN_CONFIG_FILE" | cut -d'=' -f2 | tr -d ' ')
if [ -n "$dns_servers" ]; then
# Configure resolv.conf
echo "# WireGuard DNS configuration" > /etc/resolv.conf
echo "# Generated by configure-vpn.sh" >> /etc/resolv.conf
# Add DNS servers
for server in $dns_servers; do
echo "nameserver $server" >> /etc/resolv.conf
done
log_info "DNS configured to use VPN gateway"
else
log_warning "No DNS servers specified in WireGuard config"
fi
fi
# Configure systemd-resolved to use VPN DNS
if command -v systemctl &> /dev/null; then
systemctl restart systemd-resolved 2>/dev/null || true
fi
}
# Test VPN connectivity
test_vpn() {
log_info "Testing VPN connectivity..."
# Check if VPN interface is up
if ip link show "$VPN_INTERFACE" | grep -q "state UP"; then
log_info "VPN interface is UP"
# Check connectivity
if ping -c 3 -I "$VPN_INTERFACE" 8.8.8.8 >/dev/null 2>&1; then
log_info "VPN connectivity test passed"
else
log_warning "VPN connectivity test failed (may need to wait for routing)"
fi
else
log_warning "VPN interface is not UP"
log_info "Run 'wg-quick up wg0' to start VPN"
fi
}
# Display configuration
show_config() {
echo ""
echo "=== WireGuard Configuration ==="
echo ""
echo "Configuration file: $VPN_CONFIG_FILE"
echo "VPN interface: $VPN_INTERFACE"
echo ""
if [ -f "$VPN_CONFIG_FILE" ]; then
echo "Current configuration:"
echo "----------------------------------------"
grep -v "^#" "$VPN_CONFIG_FILE" | grep -v "^$" | sed 's/^/ /'
echo "----------------------------------------"
fi
echo ""
echo "Kill-switch script: $KILL_SWITCH_SCRIPT"
echo ""
}
# Main execution
main() {
echo ""
echo "=========================================="
echo " WireGuard VPN Configuration"
echo " Fedora Kinoite SAW"
echo "=========================================="
echo ""
check_root
check_wireguard
validate_config
create_routing_table
configure_firewall
create_kill_switch
configure_killswitch_service
configure_dns
show_config
echo ""
echo "=========================================="
echo " VPN Configuration Complete!"
echo "=========================================="
echo ""
echo "Next steps:"
echo "1. Edit WireGuard config: sudo nano $VPN_CONFIG_FILE"
echo "2. Start VPN: sudo wg-quick up wg0"
echo "3. Test VPN: ping -I wg0 8.8.8.8"
echo "4. Check status: wg show"
echo ""
echo "To start VPN automatically on boot:"
echo " sudo systemctl enable wg-quick@wg0"
echo ""
}
# Run main function
main "$@"

1047
post-install/lockdown.sh Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,374 @@
#!/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 "$@"

View File

@ -0,0 +1,329 @@
#!/bin/bash
# Package Verification Check Script for SAW
# Version: 1.0
# Date: 2026-04-02
#
# This script checks the package verification configuration and verifies
# that all installed packages are properly signed.
#
# Usage: sudo ./check-verification.sh
#
# SECURITY RATIONALE:
# Regular verification of all installed packages ensures:
# 1. No packages were tampered with after installation
# 2. No malicious packages were added
# 3. All packages are still properly signed
# 4. Any compromised packages are detected early
#
# This should be run regularly (weekly/monthly) as part of security
# monitoring and compliance verification.
#
# Reference: https://docs.fedoraproject.org/en-US/fedora-coreos/security-verification/
set -e
# Configuration
CA_KEY_PATH="/etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca"
CRL_FILE="/etc/pki/ca-trust/source/anchors/crl.pem"
LOG_FILE="/var/log/package-verification-check.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"
}
# 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 CA certificate
check_ca_certificate() {
echo -e "${CYAN}1. CA Certificate Check${NC}"
echo "=========================================="
if [ -f "$CA_KEY_PATH" ]; then
log_info "PASS: CA certificate installed"
echo " Path: $CA_KEY_PATH"
echo " Status: PRESENT"
# Show certificate details
openssl x509 -in "$CA_KEY_PATH" -noout -subject -issuer -dates 2>/dev/null | sed 's/^/ /'
else
log_error "FAIL: CA certificate not found"
echo " Path: $CA_KEY_PATH"
echo " Status: MISSING"
echo " Action: Copy CA certificate to $CA_KEY_PATH"
fi
echo ""
}
# Check DNF configuration
check_dnf_config() {
echo -e "${CYAN}2. DNF Configuration Check${NC}"
echo "=========================================="
if [ ! -f /etc/dnf/dnf.conf ]; then
log_error "FAIL: DNF configuration not found"
echo " Status: FILE NOT FOUND"
echo " Action: Create /etc/dnf/dnf.conf"
echo ""
return
fi
# Check gpgcheck
if grep -q "^gpgcheck=1" /etc/dnf/dnf.conf; then
log_info "PASS: Package GPG check enabled"
echo " Status: ENABLED"
else
log_error "FAIL: Package GPG check not enabled"
echo " Status: DISABLED"
echo " Action: Add 'gpgcheck=1' to /etc/dnf/dnf.conf"
fi
# Check repo_gpgcheck
if grep -q "^repo_gpgcheck=1" /etc/dnf/dnf.conf; then
log_info "PASS: Repository GPG check enabled"
echo " Status: ENABLED"
else
log_error "FAIL: Repository GPG check not enabled"
echo " Status: DISABLED"
echo " Action: Add 'repo_gpgcheck=1' to /etc/dnf/dnf.conf"
fi
echo ""
}
# Check RPM database
check_rpm_database() {
echo -e "${CYAN}3. RPM Database Check${NC}"
echo "=========================================="
# Check if CA key is imported
if rpm -q gpg-pubkey 2>/dev/null | grep -q "$(basename $CA_KEY_PATH)"; then
log_info "PASS: CA key imported into RPM database"
echo " Status: IMPORTED"
else
log_warning "WARNING: CA key not imported into RPM database"
echo " Status: NOT IMPORTED"
echo " Action: Run 'rpm --import $CA_KEY_PATH'"
fi
echo ""
}
# Check audit script
check_audit_script() {
echo -e "${CYAN}4. Audit Script Check${NC}"
echo "=========================================="
if [ -f /usr/local/bin/verify-package.sh ]; then
log_info "PASS: Package verification script exists"
echo " Path: /usr/local/bin/verify-package.sh"
echo " Status: PRESENT"
if [ -x /usr/local/bin/verify-package.sh ]; then
log_info "PASS: Script is executable"
echo " Status: EXECUTABLE"
else
log_warning "WARNING: Script is not executable"
echo " Status: NOT EXECUTABLE"
echo " Action: Run 'chmod +x /usr/local/bin/verify-package.sh'"
fi
else
log_warning "WARNING: Package verification script not found"
echo " Status: NOT FOUND"
echo " Action: Run the lockdown script to create the script"
fi
echo ""
}
# Check CRL file
check_crl() {
echo -e "${CYAN}5. CRL Check${NC}"
echo "=========================================="
if [ -f "$CRL_FILE" ]; then
log_info "PASS: CRL file exists"
echo " Path: $CRL_FILE"
echo " Size: $(du -h "$CRL_FILE" | cut -f1)"
# Check if CRL is valid
if openssl crl -in "$CRL_FILE" -noout 2>/dev/null; then
log_info "PASS: CRL is valid"
echo " Status: VALID"
# Show CRL dates
openssl crl -in "$CRL_FILE" -noout -text 2>/dev/null | grep -E "(Last Update|Next Update):" | sed 's/^/ /'
else
log_error "FAIL: CRL is invalid"
echo " Status: INVALID"
fi
else
log_warning "WARNING: CRL file not found"
echo " Path: $CRL_FILE"
echo " Status: NOT FOUND"
echo " Action: Run daily-crl-update.sh to download CRL"
fi
echo ""
}
# Check firewall rules
check_firewall() {
echo -e "${CYAN}6. Firewall Check${NC}"
echo "=========================================="
if command -v firewall-cmd &> /dev/null; then
if firewall-cmd --state 2>/dev/null | grep -q "running"; then
log_info "PASS: Firewall is running"
echo " Status: RUNNING"
# Show active rules
echo " Active Zones:"
firewall-cmd --list-zones 2>/dev/null | sed 's/^/ /'
echo " Active Services:"
firewall-cmd --list-services 2>/dev/null | sed 's/^/ /'
else
log_warning "WARNING: Firewall is not running"
echo " Status: NOT RUNNING"
fi
else
log_warning "WARNING: Firewall command not found"
echo " Status: COMMAND NOT FOUND"
fi
echo ""
}
# Check SELinux
check_selinux() {
echo -e "${CYAN}7. SELinux Check${NC}"
echo "=========================================="
local selinux_status=$(sestatus 2>/dev/null || echo "SELinux not available")
if echo "$selinux_status" | grep -q "Current mode: enforcing"; then
log_info "PASS: SELinux is enforcing"
echo " Status: ENFORCING"
else
log_warning "WARNING: SELinux is not enforcing"
echo " Status: $(echo "$selinux_status" | grep "Current mode" | awk '{print $3}')"
fi
echo ""
}
# Check auditd
check_auditd() {
echo -e "${CYAN}8. Auditd Check${NC}"
echo "=========================================="
if systemctl is-active auditd >/dev/null 2>&1; then
log_info "PASS: Auditd is running"
echo " Status: RUNNING"
else
log_warning "WARNING: Auditd is not running"
echo " Status: NOT RUNNING"
fi
echo ""
}
# Check for unsigned packages
check_unsigned_packages() {
echo -e "${CYAN}9. Unsigned Packages Check${NC}"
echo "=========================================="
local unsigned_count=0
local total_count=0
# Get list of installed packages
while IFS= read -r pkg; do
# Check if package has signature
if ! rpm -q "$pkg" --queryformat='%{SIGPGP:pgpsig}\n' 2>/dev/null | grep -q "0x"; then
log_warning "WARNING: Package has no signature: $pkg"
((unsigned_count++))
fi
((total_count++))
done < <(rpm -qa --queryformat='%{NAME}\n' 2>/dev/null | head -100)
echo " Total packages checked: $total_count"
echo " Unsigned packages found: $unsigned_count"
echo ""
}
# Generate summary
generate_summary() {
echo ""
echo "=========================================="
echo " Package Verification Summary"
echo " Date: $(date '+%Y-%m-%d %H:%M:%S')"
echo " Hostname: $(hostname)"
echo "=========================================="
echo ""
}
# Main execution
main() {
echo ""
echo "=========================================="
echo " Package Verification Check"
echo " Fedora Kinoite SAW"
echo " Version: 1.0"
echo "=========================================="
echo ""
check_root
check_ca_certificate
check_dnf_config
check_rpm_database
check_audit_script
check_crl
check_firewall
check_selinux
check_auditd
check_unsigned_packages
generate_summary
echo ""
echo "=========================================="
echo " Check Complete!"
echo "=========================================="
echo ""
echo "Recommendations:"
echo "- Review any WARNING or ERROR items"
echo "- Run this script weekly for critical systems"
echo "- Run this script monthly for standard systems"
echo "- Keep CA certificates secure"
echo "- Regularly update CRL"
echo ""
}
# Run main function
main "$@"

149
scripts/daily-crl-update.sh Normal file
View File

@ -0,0 +1,149 @@
#!/bin/bash
# Daily CRL Update Script for SAW
# Version: 1.0
# Date: 2026-04-02
#
# This script is designed to be run as a cron job to keep the Certificate
# Revocation List (CRL) up to date. It downloads, verifies, and installs
# the CRL from your CA server.
#
# This script should be scheduled to run daily, typically at 2:00 AM.
#
# Setup:
# 1. Copy this script to /usr/local/bin/daily-crl-update.sh
# 2. Make it executable: chmod +x /usr/local/bin/daily-crl-update.sh
# 3. Configure the CRL_URL variable below with your CA server
# 4. Add to crontab: 0 2 * * * root /usr/local/bin/daily-crl-update.sh
#
# SECURITY RATIONALE:
# Regular CRL updates are critical because:
# 1. CRLs are updated when certificates are revoked
# 2. Outdated CRLs may allow revoked certificates
# 3. Daily updates ensure current revocation status
# 4. Meets compliance requirements for regular updates
# 5. Provides defense against compromised CA keys
#
# Reference: https://www.openssl.org/docs/man1.1.1/man1/crl.html
set -e
# Configuration
# TODO: Update this with your CA server URL
CRL_URL="https://your-ca-server.com/crl.pem"
CRL_CACHE_FILE="/var/cache/crl/crl.pem"
CA_KEY_PATH="/etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca"
LOG_FILE="/var/log/crl-update.log"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Print functions
log_info() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${GREEN}[$timestamp]${NC} [INFO] $1" | tee -a "$LOG_FILE"
}
log_warning() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${YELLOW}[$timestamp]${NC} [WARNING] $1" | tee -a "$LOG_FILE"
}
log_error() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${RED}[$timestamp]${NC} [ERROR] $1" | tee -a "$LOG_FILE"
}
# Main execution
main() {
echo "=========================================="
echo " Daily CRL Update"
echo " Fedora Kinoite SAW"
echo "=========================================="
echo ""
# Check if CRL URL is configured
if [ "$CRL_URL" = "https://your-ca-server.com/crl.pem" ]; then
log_error "CRL URL not configured"
log_info "Please edit this script and set CRL_URL to your CA server"
exit 1
fi
# Create cache directory
mkdir -p /var/cache/crl
# Download CRL
log_info "Downloading CRL from: $CRL_URL"
if ! curl -s -o "$CRL_CACHE_FILE" "$CRL_URL"; then
log_error "Failed to download CRL"
exit 1
fi
log_info "CRL downloaded successfully"
# Verify CRL
log_info "Verifying CRL signature..."
if [ ! -f "$CA_KEY_PATH" ]; then
log_error "CA key not found: $CA_KEY_PATH"
exit 1
fi
if ! openssl crl -in "$CRL_CACHE_FILE" -CAfile "$CA_KEY_PATH" -noout 2>/dev/null; then
log_error "CRL verification failed"
exit 1
fi
log_info "CRL verified successfully"
# Get CRL information
local this_update=$(openssl crl -in "$CRL_CACHE_FILE" -noout -text 2>/dev/null | grep "Last Update:" | head -1)
log_info "CRL Last Update: $this_update"
# Update CA trust
log_info "Updating CA trust database..."
# Copy CRL to CA trust source
mkdir -p /etc/pki/ca-trust/source/anchors
cp "$CRL_CACHE_FILE" /etc/pki/ca-trust/source/anchors/crl.pem
# Update CA trust
update-ca-trust extract
log_info "CA trust database updated"
# Check for revoked certificates in installed packages
log_info "Checking for revoked certificates..."
local revoked_count=0
# Check a sample of packages (first 100)
while IFS= read -r pkg; do
# Extract certificate ID from signature
local cert_id=$(echo "$pkg" | awk '{print $2}' | cut -d: -f2)
if [ -n "$cert_id" ]; then
# Check if certificate is in CRL
if openssl crl -in "$CRL_CACHE_FILE" -noout -text 2>/dev/null | grep -q "$cert_id"; then
log_error "REVOKED: Package signed with revoked certificate: $cert_id"
((revoked_count++))
fi
fi
done < <(rpm -qa --queryformat='%{NAME} %{SIGPGP:pgpsig}\n' 2>/dev/null | head -100)
if [ $revoked_count -gt 0 ]; then
log_warning "WARNING: $revoked_count packages have revoked certificates!"
log_info "These packages should be reviewed"
else
log_info "No revoked certificates found in checked packages"
fi
log_info "CRL update completed successfully"
}
# Run main function
main "$@"

609
scripts/security-audit.sh Normal file
View File

@ -0,0 +1,609 @@
#!/bin/bash
# Security Audit Script for SAW
# Version: 1.0
# Date: 2026-04-02
#
# This script performs a comprehensive security audit of the Fedora Kinoite SAW system.
# It checks all security controls and provides a detailed report of the system's
# security posture.
#
# Usage: sudo ./security-audit.sh
#
# SECURITY RATIONALE:
# Regular security audits are essential for:
# 1. Verifying security controls are still in place
# 2. Detecting unauthorized changes
# 3. Identifying potential security issues
# 4. Providing compliance documentation
# 5. Tracking security posture over time
#
# This script should be run:
# - Weekly for critical systems
# - Monthly for standard systems
# - After any system changes
# - Before and after security updates
#
# Reference: NSA Linux Security Hardening Guide, CIS Fedora Benchmarks
set -e
# Configuration
LOG_FILE="/var/log/security-audit.log"
AUDIT_DATE=$(date '+%Y-%m-%d %H:%M:%S')
AUDIT_REPORT="/var/log/security-audit-report-$(date +%Y%m%d).txt"
# 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"
}
# 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 sudo access
#
# SECURITY RATIONALE:
# Sudo access should be disabled in SAW because:
# 1. Prevents privilege escalation attacks
# 2. Reduces attack surface
# 3. Enforces least privilege principle
# 4. Makes lateral movement harder
# 5. All admin operations should go through controlled workflows
#
# This check verifies:
# - User is not in wheel group
# - Root SSH login is disabled
# - No sudo commands available
check_sudo_access() {
echo -e "${CYAN}1. Sudo Access Check${NC}"
echo "=========================================="
local user=$(whoami)
# Check if user is in wheel group
if id -nG "$user" | grep -q wheel; then
log_error "FAIL: User '$user' is in wheel group"
echo " Status: SUDO ENABLED (Security Risk)"
return 1
else
log_info "PASS: User '$user' is not in wheel group"
echo " Status: SUDO DISABLED"
fi
# Check root SSH login
if [ -f /etc/ssh/sshd_config ]; then
if grep -q "^PermitRootLogin yes" /etc/ssh/sshd_config || \
grep -q "^#PermitRootLogin yes" /etc/ssh/sshd_config; then
log_warning "WARNING: Root SSH login may be enabled"
echo " Check: /etc/ssh/sshd_config"
else
log_info "PASS: Root SSH login is disabled"
echo " Status: ROOT SSH DISABLED"
fi
fi
echo ""
return 0
}
# Check SELinux
#
# SECURITY RATIONALE:
# SELinux (Security-Enhanced Linux) provides:
# 1. Mandatory Access Control (MAC)
# 2. Protection against privilege escalation
# 3. Application containment
# 4. Fine-grained access control
# 5. Defense in depth
#
# SELinux should be in enforcing mode to provide protection.
check_selinux() {
echo -e "${CYAN}2. SELinux Check${NC}"
echo "=========================================="
local selinux_status=$(sestatus 2>/dev/null || echo "SELinux not available")
if echo "$selinux_status" | grep -q "Current mode: enforcing"; then
log_info "PASS: SELinux is in enforcing mode"
echo " Status: ENFORCING"
echo " Mode: Mandatory Access Control active"
else
log_warning "WARNING: SELinux is not in enforcing mode"
echo " Status: $(echo "$selinux_status" | grep "Current mode" | awk '{print $3}')"
fi
echo ""
return 0
}
# Check audit daemon
#
# SECURITY RATIONALE:
# auditd (audit daemon) provides:
# 1. Comprehensive system auditing
# 2. Logging of security-relevant events
# 3. Detection of unauthorized access
# 4. Forensic capabilities
# 5. Compliance with security standards
#
# auditd should be running to ensure security events are logged.
check_auditd() {
echo -e "${CYAN}3. Audit Daemon Check${NC}"
echo "=========================================="
if systemctl is-active auditd >/dev/null 2>&1; then
log_info "PASS: Auditd is running"
echo " Status: RUNNING"
echo " Logging: All security events"
else
log_warning "WARNING: Auditd is not running"
echo " Status: NOT RUNNING"
fi
echo ""
return 0
}
# Check firewall
#
# SECURITY RATIONALE:
# The firewall provides:
# 1. Network traffic filtering
# 2. Egress filtering (outbound)
# 3. Ingress filtering (inbound)
# 4. Network segmentation
# 5. Protection against network attacks
#
# The firewall should be:
# - Active
# - Configured with default deny
# - Only allowing necessary traffic
check_firewall() {
echo -e "${CYAN}4. Firewall Check${NC}"
echo "=========================================="
if command -v firewall-cmd &> /dev/null; then
if firewall-cmd --state 2>/dev/null | grep -q "running"; then
log_info "PASS: Firewall is running"
echo " Status: RUNNING"
# Show active zones
echo " Active Zones:"
firewall-cmd --list-zones 2>/dev/null | sed 's/^/ /'
# Show services
echo " Active Services:"
firewall-cmd --list-services 2>/dev/null | sed 's/^/ /'
else
log_warning "WARNING: Firewall is not running"
echo " Status: NOT RUNNING"
fi
else
log_warning "WARNING: Firewall command not found"
echo " Status: COMMAND NOT FOUND"
fi
echo ""
return 0
}
# Check VPN
#
# SECURITY RATIONALE:
# WireGuard VPN provides:
# 1. Encrypted network traffic
# 2. Protection against network eavesdropping
# 3. Traffic routing through secure tunnel
# 4. Kill-switch protection
# 5. Centralized network control
#
# VPN should be:
# - Active and connected
# - Routing all traffic
# - Using strong encryption
check_vpn() {
echo -e "${CYAN}5. VPN Check${NC}"
echo "=========================================="
if command -v wg &> /dev/null; then
if wg show >/dev/null 2>&1; then
log_info "PASS: WireGuard is active"
echo " Status: ACTIVE"
echo " Interface: $(wg show | grep 'interface:' | awk '{print $2}')"
# Show peers
echo " Peers:"
wg show 2>/dev/null | grep 'peer:' | sed 's/^/ /'
# Show allowed IPs
echo " Allowed IPs:"
wg show 2>/dev/null | grep 'allowed-ips:' | sed 's/^/ /'
else
log_warning "WARNING: WireGuard is not active"
echo " Status: NOT ACTIVE"
fi
else
log_warning "WARNING: WireGuard not installed"
echo " Status: NOT INSTALLED"
fi
echo ""
return 0
}
# Check DNS configuration
#
# SECURITY RATIONALE:
# DNS lockdown provides:
# 1. Prevention of DNS leaks
# 2. All DNS through VPN tunnel
# 3. Protection against DNS tracking
# 4. Centralized DNS logging
# 5. Block malicious domains
#
# DNS should be:
# - Configured to use VPN gateway only
# - Not allowing external DNS
# - Using secure DNS resolution
check_dns() {
echo -e "${CYAN}6. DNS Configuration Check${NC}"
echo "=========================================="
if [ -f /etc/resolv.conf ]; then
local dns_servers=$(grep "^nameserver" /etc/resolv.conf | awk '{print $2}')
if echo "$dns_servers" | grep -q "127.0.0.1"; then
log_info "PASS: DNS configured to use local resolver"
echo " Status: LOCAL DNS"
echo " Servers: $dns_servers"
elif echo "$dns_servers" | grep -q "10.0.0.1"; then
log_info "PASS: DNS configured to use VPN gateway"
echo " Status: VPN DNS"
echo " Servers: $dns_servers"
else
log_warning "WARNING: DNS may not be properly configured"
echo " Status: EXTERNAL DNS"
echo " Servers: $dns_servers"
fi
else
log_warning "WARNING: /etc/resolv.conf not found"
echo " Status: FILE NOT FOUND"
fi
echo ""
return 0
}
# Check package verification
#
# SECURITY RATIONALE:
# Package verification ensures:
# 1. Only signed packages installed
# 2. Package integrity maintained
# 3. Authentic package source
# 4. Protection against tampering
# 5. Supply chain attack prevention
#
# Package verification should be:
# - Enabled in DNF configuration
# - CA key imported
# - CRL checking enabled
check_package_verification() {
echo -e "${CYAN}7. Package Verification Check${NC}"
echo "=========================================="
# Check CA key
if [ -f /etc/pki/rpm-gpg/RPM-GPG-KEY-custom-ca ]; then
log_info "PASS: CA key installed"
echo " Status: CA KEY PRESENT"
else
log_warning "WARNING: CA key not found"
echo " Status: CA KEY MISSING"
fi
# Check DNF configuration
if [ -f /etc/dnf/dnf.conf ]; then
if grep -q "^gpgcheck=1" /etc/dnf/dnf.conf; then
log_info "PASS: Package signature verification enabled"
echo " Status: GPG CHECK ENABLED"
else
log_warning "WARNING: Package signature verification not enabled"
echo " Status: GPG CHECK DISABLED"
fi
if grep -q "^repo_gpgcheck=1" /etc/dnf/dnf.conf; then
log_info "PASS: Repository signature verification enabled"
echo " Status: REPO GPG CHECK ENABLED"
else
log_warning "WARNING: Repository signature verification not enabled"
echo " Status: REPO GPG CHECK DISABLED"
fi
else
log_warning "WARNING: DNF configuration not found"
echo " Status: FILE NOT FOUND"
fi
# Check audit script
if [ -f /usr/local/bin/verify-package.sh ]; then
log_info "PASS: Package verification script exists"
echo " Status: SCRIPT PRESENT"
else
log_warning "WARNING: Package verification script not found"
echo " Status: SCRIPT MISSING"
fi
echo ""
return 0
}
# Check kernel hardening
#
# SECURITY RATIONALE:
# Kernel hardening provides:
# 1. Protection against kernel exploits
# 2. Memory layout randomization
# 3. Protection against buffer overflows
# 4. Control Flow Integrity
# 5. Defense in depth
#
# Kernel hardening should include:
# - ASLR enabled
# - NX bit enabled
# - Stack protection
# - SELinux enabled
check_kernel_hardening() {
echo -e "${CYAN}8. Kernel Hardening Check${NC}"
echo "=========================================="
# Check ASLR
if [ -f /proc/sys/kernel/randomize_va_space ]; then
local aslr=$(cat /proc/sys/kernel/randomize_va_space)
if [ "$aslr" = "2" ]; then
log_info "PASS: ASLR enabled"
echo " Status: FULL ASLR (Randomize everything)"
elif [ "$aslr" = "1" ]; then
log_info "PASS: ASLR enabled"
echo " Status: BASIC ASLR (Standard)"
else
log_warning "WARNING: ASLR not enabled"
echo " Status: ASLR DISABLED"
fi
fi
# Check SELinux
if command -v getenforce &> /dev/null; then
if [ "$(getenforce)" = "Enforcing" ]; then
log_info "PASS: SELinux enforcing"
echo " Status: ENFORCING"
else
log_warning "WARNING: SELinux not enforcing"
echo " Status: $(getenforce)"
fi
fi
# Check for ExecShield
if [ -f /proc/sys/kernel/exec-shield ]; then
local execshield=$(cat /proc/sys/kernel/exec-shield)
if [ "$execshield" = "1" ]; then
log_info "PASS: ExecShield enabled"
echo " Status: EXEC SHIELD ENABLED"
fi
fi
echo ""
return 0
}
# Check for suspicious processes
#
# SECURITY RATIONALE:
# Suspicious processes check provides:
# 1. Detection of unauthorized processes
# 2. Identification of potential malware
# 3. Monitoring of system activity
# 4. Early detection of compromise
#
# This check looks for:
# - Unknown processes
# - Processes running as root
# - Suspicious network processes
check_suspicious_processes() {
echo -e "${CYAN}9. Suspicious Processes Check${NC}"
echo "=========================================="
# Check for processes running as root
local root_processes=$(ps aux | grep "root" | wc -l)
if [ "$root_processes" -gt 50 ]; then
log_warning "WARNING: High number of root processes: $root_processes"
echo " Status: $root_processes root processes running"
else
log_info "PASS: Reasonable number of root processes"
echo " Status: $root_processes root processes running"
fi
# Check for suspicious processes
local suspicious=$(ps aux | grep -E "(nc|netcat|nmap|hydra|metasploit)" | grep -v grep)
if [ -n "$suspicious" ]; then
log_error "FAIL: Suspicious processes detected!"
echo " Status: SUSPICIOUS PROCESSES FOUND"
echo "$suspicious" | sed 's/^/ /'
else
log_info "PASS: No suspicious processes detected"
echo " Status: NO SUSPICIOUS PROCESSES"
fi
echo ""
return 0
}
# Check audit logs
#
# SECURITY RATIONALE:
# Audit log review provides:
# 1. Detection of security events
# 2. Identification of unauthorized access
# 3. Forensic information
# 4. Compliance documentation
# 5. Security incident response
#
# This check looks for:
# - Failed sudo attempts
# - Privilege escalation attempts
# - File access to sensitive files
# - System configuration changes
check_audit_logs() {
echo -e "${CYAN}10. Audit Log Check${NC}"
echo "=========================================="
# Check for failed sudo attempts
if [ -f /var/log/secure ]; then
local sudo_failures=$(grep "authentication failure" /var/log/secure 2>/dev/null | wc -l)
if [ "$sudo_failures" -gt 0 ]; then
log_warning "WARNING: Failed sudo attempts detected: $sudo_failures"
echo " Status: $sudo_failures failed sudo attempts"
echo " Last 5 failures:"
grep "authentication failure" /var/log/secure 2>/dev/null | tail -5 | sed 's/^/ /'
else
log_info "PASS: No failed sudo attempts"
echo " Status: No failed sudo attempts"
fi
fi
# Check auditd logs
if command -v ausearch &> /dev/null; then
local avc_denials=$(ausearch -m avc -ts recent 2>/dev/null | wc -l)
if [ "$avc_denials" -gt 0 ]; then
log_warning "WARNING: SELinux denials detected: $avc_denials"
echo " Status: $avc_denials SELinux denials"
else
log_info "PASS: No SELinux denials"
echo " Status: No SELinux denials"
fi
fi
echo ""
return 0
}
# Check file permissions
#
# SECURITY RATIONALE:
# File permissions check provides:
# 1. Detection of overly permissive files
# 2. Verification of sensitive file protection
# 3. Identification of potential security issues
# 4. Compliance with security standards
#
# This check looks for:
# - World-writable files in critical directories
# - Files with incorrect ownership
# - SUID/SGID files
check_file_permissions() {
echo -e "${CYAN}11. File Permissions Check${NC}"
echo "=========================================="
# Check /etc permissions
local etc_world_writable=$(find /etc -type f -perm -0002 2>/dev/null | wc -l)
if [ "$etc_world_writable" -gt 0 ]; then
log_warning "WARNING: World-writable files in /etc: $etc_world_writable"
echo " Status: $etc_world_writable world-writable files"
else
log_info "PASS: No world-writable files in /etc"
echo " Status: No world-writable files"
fi
# Check for SUID/SGID files
local suid_files=$(find /usr -type f \( -perm -4000 -o -perm -2000 \) 2>/dev/null | wc -l)
if [ "$suid_files" -gt 100 ]; then
log_warning "WARNING: High number of SUID/SGID files: $suid_files"
echo " Status: $suid_files SUID/SGID files"
else
log_info "PASS: Reasonable number of SUID/SGID files"
echo " Status: $suid_files SUID/SGID files"
fi
echo ""
return 0
}
# Generate summary
generate_summary() {
echo ""
echo "=========================================="
echo " Security Audit Summary"
echo "=========================================="
echo ""
echo "Date: $AUDIT_DATE"
echo "Hostname: $(hostname)"
echo "OS: $(cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2)"
echo ""
}
# Main execution
main() {
echo ""
echo "=========================================="
echo " Fedora Kinoite SAW Security Audit"
echo " Version: 1.0"
echo " Date: 2026-04-02"
echo "=========================================="
echo ""
check_root
# Run all checks
check_sudo_access
check_selinux
check_auditd
check_firewall
check_vpn
check_dns
check_package_verification
check_kernel_hardening
check_suspicious_processes
check_audit_logs
check_file_permissions
# Generate summary
generate_summary
echo ""
echo "=========================================="
echo " Audit Complete!"
echo "=========================================="
echo ""
echo "Recommendations:"
echo "- Review any WARNING or ERROR items"
echo "- Run this script weekly for critical systems"
echo "- Run this script monthly for standard systems"
echo "- Keep audit logs secure"
echo "- Test rollback capability regularly"
echo ""
}
# Run main function
main "$@"