rewrote everything
This commit is contained in:
parent
07e081ac60
commit
92461a8ebf
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,15 +1,12 @@
|
|||||||
# Config files
|
# Config files
|
||||||
build-config.yaml
|
config.yaml
|
||||||
deploy-config.yaml
|
|
||||||
config.ign
|
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
|
# Images
|
||||||
# Downloaded images
|
*.iso
|
||||||
fedora-coreos-*-hetzner.x86_64.raw.xz
|
|
||||||
|
|
||||||
# Environment
|
# Environment
|
||||||
.env
|
.env
|
84
README.md
84
README.md
@ -1,10 +1,12 @@
|
|||||||
|
# nullpoint
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src='./icon.svg' width="150px">
|
<img src='./icon.svg' width="150px">
|
||||||
<h2>nullpoint</h2>
|
<h2>nullpoint</h2>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Secure Fedora Server setup with LUKS encryption, TPM, and BTRFS RAID1 with focus on Hetzner Infra.
|
Secure Fedora Server setup with LUKS encryption, TPM, and BTRFS RAID1 for Hetzner Dedicated Servers.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@ -14,7 +16,8 @@ Secure Fedora Server setup with LUKS encryption, TPM, and BTRFS RAID1 with focus
|
|||||||
- TPM-based boot verification
|
- TPM-based boot verification
|
||||||
- BTRFS RAID1 for data redundancy
|
- BTRFS RAID1 for data redundancy
|
||||||
- Dedicated database subvolume with `nodatacow` and `noatime`
|
- Dedicated database subvolume with `nodatacow` and `noatime`
|
||||||
- Automated deployment to Hetzner
|
- Enhanced shell environment with zsh, Oh My Zsh, Powerlevel10k, and an amazing custom theme
|
||||||
|
- SSH key-only access with early boot SSH via dropbear
|
||||||
|
|
||||||
If you need a dead man's switch to go along with it check out [raven](https://git.dominik-roth.eu/dodox/raven).
|
If you need a dead man's switch to go along with it check out [raven](https://git.dominik-roth.eu/dodox/raven).
|
||||||
|
|
||||||
@ -34,55 +37,76 @@ The system uses multiple methods to unlock the LUKS volumes:
|
|||||||
### TPM Updates
|
### TPM Updates
|
||||||
After firmware updates (UEFI/BIOS), the TPM bindings need to be updated:
|
After firmware updates (UEFI/BIOS), the TPM bindings need to be updated:
|
||||||
(otherwise the system will not be able to boot without recovery phrase)
|
(otherwise the system will not be able to boot without recovery phrase)
|
||||||
1. Use the provided script: `sudo /root/update-tpm-bindings.sh`
|
1. Use the provided script: `sudo /root/update-tpm-bindings.py`
|
||||||
2. The script will:
|
2. The script will:
|
||||||
- Show current PCR values
|
- Show current PCR values
|
||||||
- Update TPM bindings to match new measurements
|
- Update TPM bindings to match new measurements
|
||||||
- Verify all bindings are correct
|
- Verify all bindings are correct
|
||||||
3. Manual passphrase is available in `/root/luks-passphrase.txt` if needed
|
3. Manual passphrase is available in `/root/luks-passphrase.txt` if needed
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Install tools
|
|
||||||
curl -fsSL https://raw.githubusercontent.com/hetznercloud/cli/master/install.sh | bash
|
|
||||||
go install github.com/hetznercloud/hcloud-upload-image@latest
|
|
||||||
sudo dnf install -y jq python3-pyyaml libguestfs-tools cloud-image-utils curl
|
|
||||||
|
|
||||||
# Configure Hetzner
|
|
||||||
export HCLOUD_TOKEN="your-token-here"
|
|
||||||
hcloud ssh-key create --name "fedora-server-hetzner" --public-key "$(cat ~/.ssh/id_ed25519.pub)"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
1. **Configure Build Settings**
|
1. **Configure Installer**
|
||||||
```bash
|
```bash
|
||||||
cp build-config.yaml.example build-config.yaml
|
# Edit the variables at the top of install.sh:
|
||||||
vim build-config.yaml # Edit LUKS, storage, and image settings
|
vim install.sh
|
||||||
```
|
```
|
||||||
|
Set your:
|
||||||
|
- Tang server URLs and thumbprints
|
||||||
|
- TPM PCR settings
|
||||||
|
- Fedora version
|
||||||
|
- SSH public key for the default user
|
||||||
|
|
||||||
2. **Build Base Image** (one-time setup)
|
2. **Install on Hetzner Server**
|
||||||
|
- Log into Hetzner Robot
|
||||||
|
- Select your server
|
||||||
|
- Go to "Rescue" tab
|
||||||
|
- Choose "Linux" and "64 bit"
|
||||||
|
- Activate Rescue System
|
||||||
|
- Upload the installer:
|
||||||
```bash
|
```bash
|
||||||
python3 build.py # Creates and uploads Fedora Server image to Hetzner
|
scp install.sh root@your-server:/root/
|
||||||
```
|
```
|
||||||
|
- SSH into Rescue System:
|
||||||
3. **Configure Deployment Settings**
|
|
||||||
```bash
|
```bash
|
||||||
cp deploy-config.yaml.example deploy-config.yaml
|
ssh root@your-server
|
||||||
vim deploy-config.yaml # Edit server type, location, and hostname settings
|
|
||||||
```
|
```
|
||||||
|
- Make it executable and run:
|
||||||
4. **Deploy Server**
|
|
||||||
```bash
|
```bash
|
||||||
python3 deploy.py # Creates new server from base image
|
chmod +x install.sh
|
||||||
|
./install.sh
|
||||||
```
|
```
|
||||||
|
- Wait for installation to complete
|
||||||
|
- Reboot the server
|
||||||
|
|
||||||
5. **Verify**
|
3. **Verify Installation**
|
||||||
```bash
|
```bash
|
||||||
ssh admin@your-server
|
ssh root@your-server
|
||||||
systemctl status clevis-luks-askpass
|
systemctl status clevis-luks-askpass
|
||||||
lsblk
|
lsblk
|
||||||
btrfs filesystem show # Check RAID1 status
|
btrfs filesystem show # Check RAID1 status
|
||||||
clevis-luks-list -d /dev/sda2
|
clevis-luks-list -d /dev/sda2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Recovery
|
||||||
|
|
||||||
|
If you need to recover the system:
|
||||||
|
|
||||||
|
1. **Using Rescue System**
|
||||||
|
- Boot into Rescue System
|
||||||
|
- Mount the encrypted volumes:
|
||||||
|
```bash
|
||||||
|
cryptsetup luksOpen /dev/sda2 root_a
|
||||||
|
cryptsetup luksOpen /dev/sdb2 root_b
|
||||||
|
mount /dev/mapper/root_a /mnt
|
||||||
|
```
|
||||||
|
- Access your data at `/mnt`
|
||||||
|
|
||||||
|
2. **Using Tang Server**
|
||||||
|
- Ensure your Tang server is accessible
|
||||||
|
- The system should automatically unlock if TPM measurements match
|
||||||
|
|
||||||
|
3. **Using Manual Passphrase**
|
||||||
|
- Connect via SSH during early boot (dropbear)
|
||||||
|
- Enter the LUKS passphrase when prompted
|
||||||
|
- The passphrase is stored in `/root/luks-passphrase.txt` on the installed system
|
@ -1,43 +0,0 @@
|
|||||||
# Build Configuration
|
|
||||||
image:
|
|
||||||
name: nullpoint
|
|
||||||
version: 39
|
|
||||||
arch: x86_64
|
|
||||||
hetzner_arch: x86
|
|
||||||
|
|
||||||
# System Configuration
|
|
||||||
system:
|
|
||||||
# LUKS Configuration
|
|
||||||
luks:
|
|
||||||
tang_servers:
|
|
||||||
- url: https://tang1.example.com
|
|
||||||
thumbprint: your-tang1-thumbprint
|
|
||||||
- url: https://tang2.example.com
|
|
||||||
thumbprint: your-tang2-thumbprint
|
|
||||||
|
|
||||||
# TPM Configuration
|
|
||||||
tpm:
|
|
||||||
pcr_bank: sha256 # PCR bank to use (sha1 or sha256)
|
|
||||||
pcr_ids: [0,4,7,8,9] # PCRs to measure
|
|
||||||
# PCR descriptions:
|
|
||||||
# 0: Core System Firmware executable code (BIOS/UEFI) (RECOMMENDED)
|
|
||||||
# 1: Core System Firmware data (BIOS/UEFI settings)
|
|
||||||
# 2: Extended or pluggable executable code
|
|
||||||
# 3: Extended or pluggable firmware data
|
|
||||||
# 4: Boot Manager Code (bootloader) (RECOMMENDED)
|
|
||||||
# 5: Boot Manager Configuration and Data
|
|
||||||
# 6: Platform-specific code
|
|
||||||
# 7: Platform-specific configuration (RECOMMENDED)
|
|
||||||
# 8: UEFI driver and application code (RECOMMENDED)
|
|
||||||
# 9: UEFI driver and application configuration (RECOMMENDED)
|
|
||||||
# 10: UEFI Handoff Tables
|
|
||||||
# 11: UEFI Boot Services Code
|
|
||||||
# 12: UEFI Boot Services Data
|
|
||||||
# 13: UEFI Runtime Services Code
|
|
||||||
# 14: UEFI Runtime Services Data
|
|
||||||
# 15: UEFI Secure Boot State
|
|
||||||
|
|
||||||
# System Settings
|
|
||||||
timezone: UTC
|
|
||||||
keyboard: us
|
|
||||||
language: en_US.UTF-8
|
|
547
build.py
547
build.py
@ -1,547 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import yaml
|
|
||||||
import subprocess
|
|
||||||
import json
|
|
||||||
import shutil
|
|
||||||
from pathlib import Path
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
def load_config(config_file):
|
|
||||||
"""Load and parse YAML config file."""
|
|
||||||
with open(config_file, 'r') as f:
|
|
||||||
return yaml.safe_load(f)
|
|
||||||
|
|
||||||
def check_prerequisites():
|
|
||||||
"""Check if required tools are installed."""
|
|
||||||
required_tools = ['hcloud', 'hcloud-upload-image', 'jq', 'virt-customize', 'cloud-localds']
|
|
||||||
for tool in required_tools:
|
|
||||||
if not shutil.which(tool):
|
|
||||||
print(f"Error: {tool} not found. Please install it first.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def check_hetzner_token():
|
|
||||||
"""Check if HCLOUD_TOKEN is set."""
|
|
||||||
if not os.environ.get('HCLOUD_TOKEN'):
|
|
||||||
print("Error: HCLOUD_TOKEN environment variable not set")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def generate_cloud_init(config):
|
|
||||||
"""Generate cloud-init configuration."""
|
|
||||||
system = config['system']
|
|
||||||
cloud_init = system['cloud_init']
|
|
||||||
tpm_config = system['luks']['tpm']
|
|
||||||
|
|
||||||
# Generate TPM config
|
|
||||||
tpm_json = {
|
|
||||||
'pcr_bank': tpm_config['pcr_bank'],
|
|
||||||
'pcr_ids': ','.join(map(str, tpm_config['pcr_ids']))
|
|
||||||
}
|
|
||||||
|
|
||||||
# Base cloud-init config
|
|
||||||
cloud_config = {
|
|
||||||
'timezone': cloud_init['timezone'],
|
|
||||||
'users': cloud_init['users'],
|
|
||||||
'package_update': True,
|
|
||||||
'package_upgrade': True,
|
|
||||||
'packages': cloud_init['packages'] + ['mdadm'], # Add mdadm package
|
|
||||||
'write_files': [
|
|
||||||
{
|
|
||||||
'path': '/etc/clevis/tang.conf',
|
|
||||||
'content': f"URL={system['luks']['tang_url']}\nThumbprint={system['luks']['tang_thumbprint']}\n",
|
|
||||||
'permissions': '0644'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'path': '/etc/clevis/tpm2.conf',
|
|
||||||
'content': json.dumps(tpm_json),
|
|
||||||
'permissions': '0644'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'path': '/root/update-tpm-bindings.sh',
|
|
||||||
'content': '''#!/bin/bash
|
|
||||||
# Script to update TPM bindings after firmware updates
|
|
||||||
# Usage: sudo ./update-tpm-bindings.sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Check if running as root
|
|
||||||
if [ "$EUID" -ne 0 ]; then
|
|
||||||
echo "Please run as root"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if TPM is available
|
|
||||||
if ! tpm2_getcap properties-fixed > /dev/null; then
|
|
||||||
echo "Error: TPM not available"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if at least one Tang server is accessible
|
|
||||||
TANG_AVAILABLE=0
|
|
||||||
for tang_url in $(grep -h "url" /etc/clevis/sss.conf | grep -o '"url": "[^"]*"' | cut -d'"' -f4); do
|
|
||||||
if curl -s -f "$tang_url/adv" > /dev/null; then
|
|
||||||
echo "Tang server $tang_url is accessible"
|
|
||||||
TANG_AVAILABLE=1
|
|
||||||
break
|
|
||||||
else
|
|
||||||
echo "Tang server $tang_url is not accessible"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ $TANG_AVAILABLE -eq 0 ]; then
|
|
||||||
echo "Error: No Tang servers are accessible"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get current PCR values
|
|
||||||
echo "Current PCR values:"
|
|
||||||
PCR_IDS=$(grep -h "pcr_ids" /etc/clevis/sss.conf | grep -o '"pcr_ids": "[^"]*"' | cut -d'"' -f4)
|
|
||||||
tpm2_pcrread sha256:$(echo $PCR_IDS | tr ',' ' ')
|
|
||||||
|
|
||||||
# Ask for confirmation
|
|
||||||
read -p "Have you updated firmware? Continue with TPM binding update? [y/N] " -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
echo "Aborted"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get LUKS passphrase
|
|
||||||
if [ -f /root/luks-passphrase.txt ]; then
|
|
||||||
LUKS_PASSPHRASE=$(cat /root/luks-passphrase.txt)
|
|
||||||
else
|
|
||||||
echo "LUKS passphrase file not found. Please enter your LUKS passphrase:"
|
|
||||||
read -s LUKS_PASSPHRASE
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update TPM bindings
|
|
||||||
echo "Updating TPM bindings..."
|
|
||||||
for dev in /dev/sda2 /dev/sdb2; do
|
|
||||||
echo "Processing $dev..."
|
|
||||||
|
|
||||||
# Unbind old SSS binding
|
|
||||||
SLOT=$(clevis luks list -d "$dev" | grep -n "sss" | cut -d: -f1)
|
|
||||||
if [ -n "$SLOT" ]; then
|
|
||||||
echo "Removing old SSS binding from slot $SLOT"
|
|
||||||
clevis luks unbind -d "$dev" -s "$SLOT" || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create new binding with SSS using the same config
|
|
||||||
echo "Adding new SSS binding"
|
|
||||||
echo -n "$LUKS_PASSPHRASE" | clevis luks bind -d "$dev" sss -c /etc/clevis/sss.conf -k-
|
|
||||||
|
|
||||||
# Verify binding was successful
|
|
||||||
if ! clevis luks list -d "$dev" | grep -q "sss"; then
|
|
||||||
echo "Error: Failed to create SSS binding for $dev"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "TPM bindings updated successfully!"
|
|
||||||
echo "Please reboot to verify the changes."
|
|
||||||
''',
|
|
||||||
'permissions': '0700'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
# Use cloud-init's native disk setup for partitioning only
|
|
||||||
'disk_setup': {
|
|
||||||
'/dev/sda': {
|
|
||||||
'table_type': 'gpt',
|
|
||||||
'layout': [
|
|
||||||
[1024, 'boot'], # 1GB for boot
|
|
||||||
['auto', 'data'] # Rest for LUKS1
|
|
||||||
],
|
|
||||||
'overwrite': True
|
|
||||||
},
|
|
||||||
'/dev/sdb': {
|
|
||||||
'table_type': 'gpt',
|
|
||||||
'layout': [
|
|
||||||
[1024, 'boot'], # 1GB for boot mirror
|
|
||||||
['auto', 'data'] # Rest for LUKS2
|
|
||||||
],
|
|
||||||
'overwrite': True
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'runcmd': [
|
|
||||||
# Check if passphrase is set
|
|
||||||
'[ -n "$LUKS_PASSPHRASE" ] || { echo "Error: LUKS passphrase not found"; exit 1; }',
|
|
||||||
# Verify Tang server is accessible
|
|
||||||
f'curl -s -f {system["luks"]["tang_url"]}/adv > /dev/null || {{ echo "Tang server not accessible"; exit 1; }}',
|
|
||||||
# Verify TPM is available
|
|
||||||
'tpm2_getcap properties-fixed > /dev/null || { echo "TPM not available"; exit 1; }',
|
|
||||||
# Create boot RAID1
|
|
||||||
'mdadm --create --verbose /dev/md0 --level=1 --raid-devices=2 /dev/sda1 /dev/sdb1 --metadata=1.2',
|
|
||||||
# Create filesystem on RAID array
|
|
||||||
'mkfs.ext4 -L boot /dev/md0',
|
|
||||||
# Mount boot RAID
|
|
||||||
'mkdir -p /mnt/boot',
|
|
||||||
'mount /dev/md0 /mnt/boot',
|
|
||||||
# Setup LUKS on data partitions
|
|
||||||
'echo -n "${LUKS_PASSPHRASE}" | tr -d "\n" | cryptsetup luksFormat /dev/sda2 --type luks2 --key-file -',
|
|
||||||
'echo -n "${LUKS_PASSPHRASE}" | tr -d "\n" | cryptsetup luksFormat /dev/sdb2 --type luks2 --key-file -',
|
|
||||||
# Setup Clevis with error handling
|
|
||||||
'clevis luks bind -d /dev/sda2 tpm2 -c /etc/clevis/tpm2.conf || { echo "TPM bind failed"; exit 1; }',
|
|
||||||
'clevis luks bind -d /dev/sda2 tang -c /etc/clevis/tang.conf || { echo "Tang bind failed"; exit 1; }',
|
|
||||||
'clevis luks bind -d /dev/sdb2 tpm2 -c /etc/clevis/tpm2.conf || { echo "TPM bind failed"; exit 1; }',
|
|
||||||
'clevis luks bind -d /dev/sdb2 tang -c /etc/clevis/tang.conf || { echo "Tang bind failed"; exit 1; }',
|
|
||||||
# Open LUKS volumes
|
|
||||||
'echo -n "${LUKS_PASSPHRASE}" | tr -d "\n" | cryptsetup luksOpen /dev/sda2 root_a --key-file -',
|
|
||||||
'echo -n "${LUKS_PASSPHRASE}" | tr -d "\n" | cryptsetup luksOpen /dev/sdb2 root_b --key-file -',
|
|
||||||
# Create BTRFS on decrypted devices
|
|
||||||
'mkfs.btrfs -f -d raid1 -m raid1 /dev/mapper/root_a /dev/mapper/root_b',
|
|
||||||
'mount /dev/mapper/root_a /mnt',
|
|
||||||
# Create subvolumes
|
|
||||||
'btrfs subvolume create /mnt/@home',
|
|
||||||
'btrfs subvolume create /mnt/@db',
|
|
||||||
'chattr +C /mnt/@db',
|
|
||||||
# Setup fstab
|
|
||||||
'echo "/dev/md0 /boot ext4 defaults 0 0" >> /etc/fstab',
|
|
||||||
'echo "/dev/mapper/root_a / btrfs compress=zstd 0 0" >> /etc/fstab',
|
|
||||||
'echo "/dev/mapper/root_a /home btrfs subvol=@home,compress=zstd 0 0" >> /etc/fstab',
|
|
||||||
'echo "/dev/mapper/root_a /db btrfs subvol=@db,nodatacow,noatime,compress=zstd 0 0" >> /etc/fstab',
|
|
||||||
# Save RAID configuration
|
|
||||||
'mdadm --detail --scan > /etc/mdadm.conf',
|
|
||||||
# Enable services
|
|
||||||
'systemctl enable clevis-luks-askpass.service',
|
|
||||||
'systemctl enable clevis-luks-askpass.path'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
return yaml.dump(cloud_config)
|
|
||||||
|
|
||||||
def download_fedora_image(config):
|
|
||||||
"""Download Fedora Server netinstall image."""
|
|
||||||
image = config['image']
|
|
||||||
url = f"https://download.fedoraproject.org/pub/fedora/linux/releases/{image['version']}/Server/x86_64/iso/Fedora-Server-netinst-x86_64-{image['version']}-1.6.iso"
|
|
||||||
|
|
||||||
cmd = ['curl', '-L', '-o', 'fedora-server.iso', url]
|
|
||||||
subprocess.run(cmd, check=True)
|
|
||||||
|
|
||||||
def generate_kickstart(config):
|
|
||||||
"""Generate kickstart configuration for automated installation."""
|
|
||||||
system = config['system']
|
|
||||||
|
|
||||||
# TPM update script content
|
|
||||||
tpm_update_script = '''#!/bin/bash
|
|
||||||
# Script to update TPM bindings after firmware updates
|
|
||||||
# Usage: sudo ./update-tpm-bindings.sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Check if running as root
|
|
||||||
if [ "$EUID" -ne 0 ]; then
|
|
||||||
echo "Please run as root"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if TPM is available
|
|
||||||
if ! tpm2_getcap properties-fixed > /dev/null; then
|
|
||||||
echo "Error: TPM not available"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if at least one Tang server is accessible
|
|
||||||
TANG_AVAILABLE=0
|
|
||||||
for tang_url in $(grep -h "url" /etc/clevis/sss.conf | grep -o '"url": "[^"]*"' | cut -d'"' -f4); do
|
|
||||||
if curl -s -f "$tang_url/adv" > /dev/null; then
|
|
||||||
echo "Tang server $tang_url is accessible"
|
|
||||||
TANG_AVAILABLE=1
|
|
||||||
break
|
|
||||||
else
|
|
||||||
echo "Tang server $tang_url is not accessible"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ $TANG_AVAILABLE -eq 0 ]; then
|
|
||||||
echo "Error: No Tang servers are accessible"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get current PCR values
|
|
||||||
echo "Current PCR values:"
|
|
||||||
PCR_IDS=$(grep -h "pcr_ids" /etc/clevis/sss.conf | grep -o '"pcr_ids": "[^"]*"' | cut -d'"' -f4)
|
|
||||||
tpm2_pcrread sha256:$(echo $PCR_IDS | tr ',' ' ')
|
|
||||||
|
|
||||||
# Ask for confirmation
|
|
||||||
read -p "Have you updated firmware? Continue with TPM binding update? [y/N] " -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
echo "Aborted"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get LUKS passphrase
|
|
||||||
if [ -f /root/luks-passphrase.txt ]; then
|
|
||||||
LUKS_PASSPHRASE=$(cat /root/luks-passphrase.txt)
|
|
||||||
else
|
|
||||||
echo "LUKS passphrase file not found. Please enter your LUKS passphrase:"
|
|
||||||
read -s LUKS_PASSPHRASE
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update TPM bindings
|
|
||||||
echo "Updating TPM bindings..."
|
|
||||||
for dev in /dev/sda2 /dev/sdb2; do
|
|
||||||
echo "Processing $dev..."
|
|
||||||
|
|
||||||
# Unbind old SSS binding
|
|
||||||
SLOT=$(clevis luks list -d "$dev" | grep -n "sss" | cut -d: -f1)
|
|
||||||
if [ -n "$SLOT" ]; then
|
|
||||||
echo "Removing old SSS binding from slot $SLOT"
|
|
||||||
clevis luks unbind -d "$dev" -s "$SLOT" || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create new binding with SSS using the same config
|
|
||||||
echo "Adding new SSS binding"
|
|
||||||
echo -n "$LUKS_PASSPHRASE" | clevis luks bind -d "$dev" sss -c /etc/clevis/sss.conf -k-
|
|
||||||
|
|
||||||
# Verify binding was successful
|
|
||||||
if ! clevis luks list -d "$dev" | grep -q "sss"; then
|
|
||||||
echo "Error: Failed to create SSS binding for $dev"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "TPM bindings updated successfully!"
|
|
||||||
echo "Please reboot to verify the changes."
|
|
||||||
'''
|
|
||||||
|
|
||||||
# Create SSS config for TPM + any Tang server
|
|
||||||
tang_servers = []
|
|
||||||
for server in system['luks']['tang_servers']:
|
|
||||||
tang_servers.append({"url": server['url']})
|
|
||||||
|
|
||||||
# Convert Tang servers to JSON for SSS config
|
|
||||||
tang_servers_json = json.dumps(tang_servers)
|
|
||||||
|
|
||||||
# Create SSS policy: Require TPM AND at least one Tang server
|
|
||||||
sss_config = {
|
|
||||||
"t": 2, # Threshold: Both pins must succeed
|
|
||||||
"pins": {
|
|
||||||
"tpm2": {
|
|
||||||
"pcr_bank": system['luks']['tpm']['pcr_bank'],
|
|
||||||
"pcr_ids": ','.join(map(str, system['luks']['tpm']['pcr_ids']))
|
|
||||||
},
|
|
||||||
"tang": {"t": 1, "tang": tang_servers} # Only one Tang server needed from the list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Convert config to JSON string
|
|
||||||
sss_config_json = json.dumps(sss_config)
|
|
||||||
|
|
||||||
kickstart = f"""# Kickstart configuration for Fedora Server
|
|
||||||
# Generated for Nullpoint
|
|
||||||
|
|
||||||
# System language
|
|
||||||
lang en_US.UTF-8
|
|
||||||
|
|
||||||
# Keyboard layouts
|
|
||||||
keyboard --vckeymap=us --xlayouts='us'
|
|
||||||
|
|
||||||
# Network information
|
|
||||||
network --bootproto=dhcp --device=link --activate
|
|
||||||
|
|
||||||
# Root password
|
|
||||||
rootpw --lock
|
|
||||||
|
|
||||||
# System timezone
|
|
||||||
timezone {system['timezone']} --utc
|
|
||||||
|
|
||||||
# Installation type
|
|
||||||
text
|
|
||||||
|
|
||||||
# Wipe all disk
|
|
||||||
zerombr
|
|
||||||
clearpart --all --initlabel
|
|
||||||
|
|
||||||
# Disk partitioning information
|
|
||||||
# Boot partitions (5GB each)
|
|
||||||
part /boot --fstype=btrfs --size=5120 --ondisk=sda
|
|
||||||
part /boot --fstype=btrfs --size=5120 --ondisk=sdb
|
|
||||||
|
|
||||||
# Main data partitions with LUKS
|
|
||||||
part / --fstype=btrfs --encrypted --cipher=aes-xts-plain64 --luks-version=luks2 --grow --ondisk=sda
|
|
||||||
part / --fstype=btrfs --encrypted --cipher=aes-xts-plain64 --luks-version=luks2 --grow --ondisk=sdb
|
|
||||||
|
|
||||||
# Package source
|
|
||||||
url --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-$releasever&arch=$basearch
|
|
||||||
repo --name=fedora
|
|
||||||
repo --name=updates
|
|
||||||
|
|
||||||
# Make sure initial-setup runs
|
|
||||||
firstboot --reconfig
|
|
||||||
|
|
||||||
# Package selection
|
|
||||||
%packages
|
|
||||||
@^server-product
|
|
||||||
@system-tools
|
|
||||||
btrfs-progs
|
|
||||||
clevis
|
|
||||||
clevis-luks
|
|
||||||
clevis-tang
|
|
||||||
clevis-tpm2
|
|
||||||
tpm2-tools
|
|
||||||
tpm2-tss
|
|
||||||
cryptsetup
|
|
||||||
systemd
|
|
||||||
curl
|
|
||||||
shim-x64
|
|
||||||
grub2-efi-x64
|
|
||||||
dropbear
|
|
||||||
%end
|
|
||||||
|
|
||||||
# Pre-installation script
|
|
||||||
%pre
|
|
||||||
# Create TPM and Tang config files
|
|
||||||
mkdir -p /etc/clevis
|
|
||||||
|
|
||||||
# Save SSS config for TPM + Tang servers
|
|
||||||
cat > /etc/clevis/sss.conf << EOF
|
|
||||||
{sss_config_json}
|
|
||||||
EOF
|
|
||||||
%end
|
|
||||||
|
|
||||||
# Post-installation script
|
|
||||||
%post
|
|
||||||
# https://unix.stackexchange.com/a/351755 for handling TTY in anaconda
|
|
||||||
printf "\n=== Nullpoint Installation Progress ===\r\n" > /dev/tty1
|
|
||||||
printf "Press Alt+F3 to view detailed installation logs\r\n" > /dev/tty1
|
|
||||||
printf "Press Alt+F1 to return to main installation screen\r\n" > /dev/tty1
|
|
||||||
printf "Current step: Setting up TPM and Tang...\r\n\n" > /dev/tty1
|
|
||||||
{{
|
|
||||||
# Get the LUKS passphrase that was used during installation
|
|
||||||
LUKS_PASSPHRASE=$(cat /tmp/luks-passphrase.txt)
|
|
||||||
echo "$LUKS_PASSPHRASE" > /root/luks-passphrase.txt
|
|
||||||
chmod 600 /root/luks-passphrase.txt
|
|
||||||
|
|
||||||
# Setup Clevis with SSS policy (TPM + at least one Tang server)
|
|
||||||
printf "Configuring TPM and Tang with SSS policy...\r\n" > /dev/tty1
|
|
||||||
echo "Using SSS policy: TPM verification AND (at least one Tang server)" > /dev/tty1
|
|
||||||
echo -n "$LUKS_PASSPHRASE" | clevis luks bind -d /dev/sda2 sss -c /etc/clevis/sss.conf -k-
|
|
||||||
echo -n "$LUKS_PASSPHRASE" | clevis luks bind -d /dev/sdb2 sss -c /etc/clevis/sss.conf -k-
|
|
||||||
|
|
||||||
# Get BTRFS UUID (same for all devices in the filesystem)
|
|
||||||
BTRFS_UUID=$(blkid -s UUID -o value /dev/mapper/luks-$(blkid -s UUID -o value /dev/sda2))
|
|
||||||
|
|
||||||
# Create subvolumes
|
|
||||||
printf "Creating BTRFS subvolumes...\r\n" > /dev/tty1
|
|
||||||
# Mount both devices for RAID1
|
|
||||||
mount -t btrfs -o raid1 UUID=$BTRFS_UUID /mnt
|
|
||||||
btrfs subvolume create /mnt/@root
|
|
||||||
btrfs subvolume create /mnt/@home
|
|
||||||
btrfs subvolume create /mnt/@db
|
|
||||||
chattr +C /mnt/@db
|
|
||||||
|
|
||||||
# Setup fstab
|
|
||||||
printf "Configuring system mount points...\r\n" > /dev/tty1
|
|
||||||
cat > /etc/fstab << EOF
|
|
||||||
UUID=$BTRFS_UUID / btrfs subvol=@root,compress=zstd,raid1 0 0
|
|
||||||
UUID=$BTRFS_UUID /home btrfs subvol=@home,compress=zstd,raid1 0 0
|
|
||||||
UUID=$BTRFS_UUID /db btrfs subvol=@db,nodatacow,noatime,compress=zstd,raid1 0 0
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Configure dropbear for early SSH access
|
|
||||||
printf "Configuring early SSH access...\r\n" > /dev/tty1
|
|
||||||
mkdir -p /etc/dropbear
|
|
||||||
echo "{config['admin_ssh_key']}" > /etc/dropbear/authorized_keys
|
|
||||||
chmod 600 /etc/dropbear/authorized_keys
|
|
||||||
|
|
||||||
# Enable dropbear for early SSH
|
|
||||||
systemctl enable dropbear
|
|
||||||
systemctl enable dropbear.socket
|
|
||||||
|
|
||||||
# Enable services
|
|
||||||
printf "Enabling system services...\r\n" > /dev/tty1
|
|
||||||
systemctl enable clevis-luks-askpass.service
|
|
||||||
systemctl enable clevis-luks-askpass.path
|
|
||||||
|
|
||||||
# Create TPM update script
|
|
||||||
printf "Creating TPM update script...\r\n" > /dev/tty1
|
|
||||||
cat > /root/update-tpm-bindings.sh << 'EOF'
|
|
||||||
{tpm_update_script}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
chmod +x /root/update-tpm-bindings.sh
|
|
||||||
printf "\nInstallation complete! The system will reboot shortly.\r\n" > /dev/tty1
|
|
||||||
printf "IMPORTANT: LUKS passphrase has been saved to /root/luks-passphrase.txt\r\n" > /dev/tty1
|
|
||||||
}} 2>&1 | tee -a /root/postinstall.log > /dev/tty3
|
|
||||||
%end
|
|
||||||
"""
|
|
||||||
return kickstart
|
|
||||||
|
|
||||||
def customize_image(config):
|
|
||||||
"""Customize the Fedora Server image."""
|
|
||||||
# Generate kickstart config
|
|
||||||
kickstart = generate_kickstart(config)
|
|
||||||
|
|
||||||
# Create kickstart file
|
|
||||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.ks') as f:
|
|
||||||
f.write(kickstart)
|
|
||||||
f.flush()
|
|
||||||
|
|
||||||
# Create custom ISO with kickstart
|
|
||||||
cmd = [
|
|
||||||
'mkisofs',
|
|
||||||
'-o', 'fedora-server-custom.iso',
|
|
||||||
'-b', 'isolinux/isolinux.bin',
|
|
||||||
'-c', 'isolinux/boot.cat',
|
|
||||||
'-boot-info-table',
|
|
||||||
'-no-emul-boot',
|
|
||||||
'-boot-load-size', '4',
|
|
||||||
'-R',
|
|
||||||
'-J',
|
|
||||||
'-v',
|
|
||||||
'-T',
|
|
||||||
'-V', 'Fedora-S-custom',
|
|
||||||
'-A', 'Fedora-S-custom',
|
|
||||||
'fedora-server.iso',
|
|
||||||
f.name
|
|
||||||
]
|
|
||||||
subprocess.run(cmd, check=True)
|
|
||||||
|
|
||||||
def create_snapshot(config):
|
|
||||||
"""Create new snapshot from image."""
|
|
||||||
image = config['image']
|
|
||||||
cmd = [
|
|
||||||
'hcloud-upload-image', 'upload',
|
|
||||||
'--architecture', image['hetzner_arch'],
|
|
||||||
'--compression', 'xz',
|
|
||||||
'--image-path', 'fedora-server-custom.iso',
|
|
||||||
'--name', image['name'],
|
|
||||||
'--labels', f'os=fedora-server,version={image["version"]}',
|
|
||||||
'--description', f'Fedora Server {image["version"]} for Nullpoint'
|
|
||||||
]
|
|
||||||
subprocess.run(cmd, check=True)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Main entry point."""
|
|
||||||
# Load config
|
|
||||||
if not os.path.exists('build-config.yaml'):
|
|
||||||
print("Error: build-config.yaml not found")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
config = load_config('build-config.yaml')
|
|
||||||
|
|
||||||
# Check prerequisites
|
|
||||||
check_prerequisites()
|
|
||||||
check_hetzner_token()
|
|
||||||
|
|
||||||
# Download Fedora Server image
|
|
||||||
print("Downloading Fedora Server image...")
|
|
||||||
download_fedora_image(config)
|
|
||||||
|
|
||||||
# Customize image
|
|
||||||
print("Customizing image...")
|
|
||||||
customize_image(config)
|
|
||||||
|
|
||||||
# Create snapshot
|
|
||||||
print("Creating snapshot...")
|
|
||||||
create_snapshot(config)
|
|
||||||
|
|
||||||
print("Image build complete!")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
@ -1,13 +0,0 @@
|
|||||||
# Deployment Configuration
|
|
||||||
hetzner:
|
|
||||||
datacenter: nbg1
|
|
||||||
server_type: cx31
|
|
||||||
ssh_key_name: fedora-server-hetzner
|
|
||||||
|
|
||||||
# Admin Configuration
|
|
||||||
admin_ssh_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." # Your SSH public key here
|
|
||||||
|
|
||||||
# Hostname Configuration
|
|
||||||
hostname:
|
|
||||||
prefix: nullpoint
|
|
||||||
format: "{prefix}-{date}-{random}" # date format: YYMMDD, random: 000-999
|
|
169
deploy.py
169
deploy.py
@ -1,169 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import yaml
|
|
||||||
import subprocess
|
|
||||||
import json
|
|
||||||
import shutil
|
|
||||||
from datetime import datetime
|
|
||||||
import random
|
|
||||||
import tempfile
|
|
||||||
import secrets
|
|
||||||
import string
|
|
||||||
|
|
||||||
# List of adjectives for hostname generation
|
|
||||||
ADJECTIVES = [
|
|
||||||
# Scientific/Sci-fi
|
|
||||||
'quantum', 'atomic', 'plasma', 'fusion', 'ionic', 'magnetic', 'cosmic',
|
|
||||||
'stellar', 'nebular', 'pulsar', 'quasar', 'warp', 'phaser', 'hyper',
|
|
||||||
'temporal', 'spatial', 'dimensional', 'subspace', 'transwarp',
|
|
||||||
# Cool/Interesting
|
|
||||||
'abysmal', 'adamant', 'aerial', 'arcane', 'astral', 'azure', 'celestial',
|
|
||||||
'crimson', 'cryptic', 'crystalline', 'dormant', 'eerie', 'eldritch',
|
|
||||||
'ethereal', 'fractal', 'frozen', 'ghostly', 'gilded', 'singular',
|
|
||||||
'hollow', 'infernal', 'lunar', 'mystic', 'nebulous', 'obsidian',
|
|
||||||
'occult', 'prismatic', 'radiant', 'shadow', 'solar', 'spectral',
|
|
||||||
'stellar', 'sublime', 'titanic', 'twilight', 'void', 'volcanic'
|
|
||||||
]
|
|
||||||
|
|
||||||
NOUNS = [
|
|
||||||
# Star Trek
|
|
||||||
'enterprise', 'voyager', 'galaxy', 'intrepid', 'nova', 'warbird', 'falcon',
|
|
||||||
'aegis', 'nemesis', 'equinox', 'stargazer', 'challenger', 'discovery',
|
|
||||||
'prometheus', 'odyssey', 'daedalus', 'apollo', 'korolev', 'phoenix', 'orion',
|
|
||||||
# Space
|
|
||||||
'nebula', 'pulsar', 'quasar', 'nova', 'supernova', 'blackhole',
|
|
||||||
'wormhole', 'singularity', 'galaxy', 'void', 'rift', 'nexus',
|
|
||||||
# Cool Concepts
|
|
||||||
'abyss', 'aether', 'anomaly', 'artifact', 'beacon', 'cipher', 'crystal',
|
|
||||||
'echo', 'enigma', 'essence', 'fractal', 'horizon', 'infinity',
|
|
||||||
'paradox', 'phoenix', 'prism', 'spectrum', 'tesseract',
|
|
||||||
'vector', 'vertex', 'vortex', 'zenith'
|
|
||||||
]
|
|
||||||
|
|
||||||
def load_config(config_file):
|
|
||||||
"""Load and parse YAML config file."""
|
|
||||||
with open(config_file, 'r') as f:
|
|
||||||
return yaml.safe_load(f)
|
|
||||||
|
|
||||||
def check_prerequisites():
|
|
||||||
"""Check if required tools are installed."""
|
|
||||||
required_tools = ['hcloud', 'jq']
|
|
||||||
for tool in required_tools:
|
|
||||||
if not shutil.which(tool):
|
|
||||||
print(f"Error: {tool} not found. Please install it first.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def check_hetzner_token():
|
|
||||||
"""Check if HCLOUD_TOKEN is set."""
|
|
||||||
if not os.environ.get('HCLOUD_TOKEN'):
|
|
||||||
print("Error: HCLOUD_TOKEN environment variable not set")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def generate_hostname():
|
|
||||||
"""Generate a unique hostname in adjective-noun-date-time format."""
|
|
||||||
adjective = random.choice(ADJECTIVES)
|
|
||||||
noun = random.choice(NOUNS)
|
|
||||||
timestamp = datetime.now().strftime('%y%m%d-%H%M')
|
|
||||||
return f"{adjective}-{noun}-{timestamp}"
|
|
||||||
|
|
||||||
def get_image_id():
|
|
||||||
"""Get the base image ID."""
|
|
||||||
cmd = [
|
|
||||||
'hcloud', 'image', 'list',
|
|
||||||
'--type=snapshot',
|
|
||||||
'--selector=name=fedora-coreos-nullpoint',
|
|
||||||
'--output', 'json'
|
|
||||||
]
|
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
|
||||||
images = json.loads(result.stdout)
|
|
||||||
|
|
||||||
if not images:
|
|
||||||
print("Error: Base image not found. Run build.py first.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
return images[0]['id']
|
|
||||||
|
|
||||||
def generate_secure_passphrase(length=32):
|
|
||||||
"""Generate a secure random passphrase."""
|
|
||||||
alphabet = string.ascii_letters + string.digits + string.punctuation
|
|
||||||
return ''.join(secrets.choice(alphabet) for _ in range(length))
|
|
||||||
|
|
||||||
def create_server(config, hostname, image_id):
|
|
||||||
"""Create a new server."""
|
|
||||||
hetzner = config['hetzner']
|
|
||||||
|
|
||||||
# Generate cloud-init config for this specific server
|
|
||||||
cloud_init = {
|
|
||||||
'hostname': hostname,
|
|
||||||
'timezone': 'UTC',
|
|
||||||
'users': [
|
|
||||||
{
|
|
||||||
'name': 'admin',
|
|
||||||
'groups': ['wheel'],
|
|
||||||
'sudo': 'ALL=(ALL) NOPASSWD:ALL',
|
|
||||||
'ssh_authorized_keys': [config['admin_ssh_key']]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'package_update': True,
|
|
||||||
'package_upgrade': True
|
|
||||||
}
|
|
||||||
|
|
||||||
# Create temporary cloud-init config
|
|
||||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as f:
|
|
||||||
yaml.dump(cloud_init, f)
|
|
||||||
f.flush()
|
|
||||||
|
|
||||||
cmd = [
|
|
||||||
'hcloud', 'server', 'create',
|
|
||||||
'--name', hostname,
|
|
||||||
'--type', hetzner['server_type'],
|
|
||||||
'--datacenter', hetzner['datacenter'],
|
|
||||||
'--image', str(image_id),
|
|
||||||
'--ssh-key', hetzner['ssh_key_name'],
|
|
||||||
'--user-data-from-file', f.name
|
|
||||||
]
|
|
||||||
subprocess.run(cmd, check=True)
|
|
||||||
|
|
||||||
print(f"\nServer '{hostname}' created successfully!")
|
|
||||||
print("The LUKS passphrase has been saved to /root/luks-passphrase.txt on the server.")
|
|
||||||
print("Please save this passphrase securely - it will be needed if TPM+Tang unlock fails.")
|
|
||||||
print("\nYou can connect using: ssh admin@<server-ip>")
|
|
||||||
|
|
||||||
def get_server_ip(hostname):
|
|
||||||
"""Get the server's IP address."""
|
|
||||||
cmd = ['hcloud', 'server', 'ip', hostname]
|
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
|
||||||
return result.stdout.strip()
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Main entry point."""
|
|
||||||
# Load config
|
|
||||||
if not os.path.exists('deploy-config.yaml'):
|
|
||||||
print("Error: deploy-config.yaml not found")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
config = load_config('deploy-config.yaml')
|
|
||||||
|
|
||||||
# Check prerequisites
|
|
||||||
check_prerequisites()
|
|
||||||
check_hetzner_token()
|
|
||||||
|
|
||||||
# Generate hostname
|
|
||||||
hostname = generate_hostname()
|
|
||||||
|
|
||||||
# Get image ID
|
|
||||||
image_id = get_image_id()
|
|
||||||
|
|
||||||
# Create server
|
|
||||||
print(f"Creating server '{hostname}'...")
|
|
||||||
create_server(config, hostname, image_id)
|
|
||||||
|
|
||||||
# Get server IP
|
|
||||||
server_ip = get_server_ip(hostname)
|
|
||||||
print(f"Server created! IP: {server_ip}")
|
|
||||||
print(f"You can connect using: ssh core@{server_ip}")
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
838
install.sh
Normal file
838
install.sh
Normal file
@ -0,0 +1,838 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
BANNER=$(cat << "EOF"
|
||||||
|
:^7J5GB##&&##GPY?~:
|
||||||
|
^75B&@@@@@@&&&@@@@@@@#GJ~:
|
||||||
|
5&@@@&B5?7~^^^^^~!7YP#@@@@#!
|
||||||
|
Y##P7^ :~JB#B!
|
||||||
|
:: :
|
||||||
|
7PP?: :^~!!~^: :?PP7
|
||||||
|
:B@@B: !5B&@@@@&B5! :#@@B:
|
||||||
|
:!!: ^G@@@&BPPB@@@@G^ :!!:
|
||||||
|
:B@@@5^ ^5@@@B:
|
||||||
|
:7J7: !@@@# :&@@@~ :?J7:
|
||||||
|
J@@@5 :#@@@Y: :Y@@@B: 5@@@J
|
||||||
|
!@@@&^ ~B@@@&G55G&@@@B~ ~&@@@~
|
||||||
|
5@@@G: :7P#@@@@@@#P7: :B@@@Y
|
||||||
|
:P@@@B~ :~!77!~: ~B@@@P
|
||||||
|
Y@@@&Y^ ^5@@@@J
|
||||||
|
!G@@@&P7^ ^7P&@@@G~
|
||||||
|
!P&@@@&B? :: ?B&@@@&P!
|
||||||
|
^75#&&Y :P&&5: 5&&B57^
|
||||||
|
:^^ :P&&5: ^^:
|
||||||
|
^^
|
||||||
|
|
||||||
|
[nullpoint]
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
TANG_SERVERS=(
|
||||||
|
# "https://tang1.example.com your-thumbprint-1"
|
||||||
|
# "https://tang2.example.com your-thumbprint-2"
|
||||||
|
)
|
||||||
|
TPM_PCR_BANK="sha256"
|
||||||
|
TPM_PCR_IDS="0,1,2,3,4,5,6,7,8"
|
||||||
|
FEDORA_VERSION="42"
|
||||||
|
FEDORA_USER="null"
|
||||||
|
ENABLE_MOTD=true
|
||||||
|
SSH_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOkoTn2NreAXMriOUqzyj3YoFW6jMo9B5B+3R5k8yrMi dodox@dodox-ProArt"
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Config End
|
||||||
|
########################################################
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
echo -e "\nStarting installation...\n"
|
||||||
|
|
||||||
|
# Check for TPM
|
||||||
|
echo "Checking for TPM..."
|
||||||
|
if [ ! -d "/sys/class/tpm/tpm0" ]; then
|
||||||
|
echo "WARNING: No TPM detected!"
|
||||||
|
echo "This system will not be able to use TPM-based boot verification."
|
||||||
|
read -p "Continue without TPM? [y/N] " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo "Installation aborted."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Proceeding without TPM..."
|
||||||
|
TPM_ENABLED=false
|
||||||
|
else
|
||||||
|
echo "TPM detected."
|
||||||
|
TPM_ENABLED=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for SSH key
|
||||||
|
if [ -z "${SSH_KEY:-}" ]; then
|
||||||
|
echo "No SSH key provided. Please enter your public SSH key:"
|
||||||
|
read -r SSH_KEY
|
||||||
|
if [ -z "$SSH_KEY" ]; then
|
||||||
|
echo "Error: SSH key is required for installation"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate secure LUKS passphrase
|
||||||
|
echo "Generating secure LUKS passphrase..."
|
||||||
|
LUKS_PASSPHRASE=$(openssl rand -base64 32)
|
||||||
|
USER_PASSWORD=$(openssl rand -base64 12) # Shorter for easier typing
|
||||||
|
echo "Generated LUKS passphrase: ${LUKS_PASSPHRASE}"
|
||||||
|
echo "Generated user password: ${USER_PASSWORD}"
|
||||||
|
echo "Please save these credentials securely. You will need them for recovery."
|
||||||
|
echo "Press Enter to continue..."
|
||||||
|
read
|
||||||
|
|
||||||
|
# Install required packages in Rescue System (Debian)
|
||||||
|
echo "Installing required packages..."
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y cryptsetup btrfs-progs mdadm
|
||||||
|
|
||||||
|
# Wipe disks
|
||||||
|
echo "Wiping disks..."
|
||||||
|
dd if=/dev/zero of=/dev/sda bs=1M count=100
|
||||||
|
dd if=/dev/zero of=/dev/sdb bs=1M count=100
|
||||||
|
sync
|
||||||
|
|
||||||
|
# Create partitions
|
||||||
|
echo "Creating partitions..."
|
||||||
|
# First disk
|
||||||
|
parted /dev/sda mklabel gpt
|
||||||
|
parted /dev/sda mkpart primary 1MiB 1000MiB
|
||||||
|
parted /dev/sda mkpart primary 1000MiB 100%
|
||||||
|
|
||||||
|
# Second disk
|
||||||
|
parted /dev/sdb mklabel gpt
|
||||||
|
parted /dev/sdb mkpart primary 1MiB 1000MiB
|
||||||
|
parted /dev/sdb mkpart primary 1000MiB 100%
|
||||||
|
|
||||||
|
# Create boot RAID1
|
||||||
|
echo "Creating boot RAID1 array..."
|
||||||
|
mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sda1 /dev/sdb1
|
||||||
|
mkfs.ext4 /dev/md0
|
||||||
|
|
||||||
|
# Create LUKS volumes
|
||||||
|
echo "Setting up LUKS encryption..."
|
||||||
|
echo "${LUKS_PASSPHRASE}" | cryptsetup luksFormat /dev/sda2 --type luks2
|
||||||
|
echo "${LUKS_PASSPHRASE}" | cryptsetup luksFormat /dev/sdb2 --type luks2
|
||||||
|
|
||||||
|
# Open LUKS volumes
|
||||||
|
echo "Opening LUKS volumes..."
|
||||||
|
echo "${LUKS_PASSPHRASE}" | cryptsetup luksOpen /dev/sda2 root_a
|
||||||
|
echo "${LUKS_PASSPHRASE}" | cryptsetup luksOpen /dev/sdb2 root_b
|
||||||
|
|
||||||
|
# Create BTRFS RAID1
|
||||||
|
echo "Creating BTRFS RAID1 filesystem..."
|
||||||
|
mkfs.btrfs -f -d raid1 -m raid1 /dev/mapper/root_a /dev/mapper/root_b
|
||||||
|
|
||||||
|
# Create subvolumes
|
||||||
|
echo "Creating BTRFS subvolumes..."
|
||||||
|
mount /dev/mapper/root_a /mnt
|
||||||
|
btrfs subvolume create /mnt/@root
|
||||||
|
btrfs subvolume create /mnt/@home
|
||||||
|
btrfs subvolume create /mnt/@db
|
||||||
|
chattr +C /mnt/@db
|
||||||
|
|
||||||
|
# Download Fedora installer
|
||||||
|
echo "Downloading Fedora installer..."
|
||||||
|
wget "https://download.fedoraproject.org/pub/fedora/linux/releases/${FEDORA_VERSION}/Server/x86_64/iso/Fedora-Server-dvd-x86_64-${FEDORA_VERSION}-1.5.iso"
|
||||||
|
|
||||||
|
# Mount Fedora ISO
|
||||||
|
echo "Mounting Fedora installer..."
|
||||||
|
mkdir -p /mnt/iso
|
||||||
|
mount -o loop "Fedora-Server-dvd-x86_64-${FEDORA_VERSION}-1.5.iso" /mnt/iso
|
||||||
|
|
||||||
|
# Create kickstart file
|
||||||
|
echo "Creating kickstart configuration..."
|
||||||
|
cat > /mnt/ks.cfg << EOF
|
||||||
|
# Fedora Server installation with our secure setup
|
||||||
|
text
|
||||||
|
lang en_US.UTF-8
|
||||||
|
keyboard us
|
||||||
|
timezone --utc Etc/UTC
|
||||||
|
|
||||||
|
# Security settings
|
||||||
|
selinux --enforcing
|
||||||
|
rootpw --lock
|
||||||
|
user --name=${FEDORA_USER} --groups=wheel --shell=/bin/bash --password="${USER_PASSWORD}" --lock
|
||||||
|
|
||||||
|
# SSH setup
|
||||||
|
sshkey --username=${FEDORA_USER} "${SSH_KEY}"
|
||||||
|
|
||||||
|
# Network
|
||||||
|
network --bootproto=dhcp --device=link --activate
|
||||||
|
|
||||||
|
# Bootloader
|
||||||
|
bootloader --timeout=1 --location=mbr --append="no_timer_check console=tty1 console=ttyS0,115200n8"
|
||||||
|
|
||||||
|
# Services
|
||||||
|
services --enabled=sshd,clevis-luks-askpass,dropbear
|
||||||
|
|
||||||
|
# Partitioning
|
||||||
|
clearpart --all --initlabel --disklabel=gpt
|
||||||
|
|
||||||
|
# Boot RAID1
|
||||||
|
part /boot --size=1000 --fstype=ext4 --label=boot
|
||||||
|
raid /boot --level=1 --device=md0 --fstype=ext4 --label=boot /dev/sda1 /dev/sdb1
|
||||||
|
|
||||||
|
# LUKS + BTRFS RAID1
|
||||||
|
part /dev/sda2 --size=2000 --grow --fstype=btrfs --label=root_a
|
||||||
|
part /dev/sdb2 --size=2000 --grow --fstype=btrfs --label=root_b
|
||||||
|
|
||||||
|
# Packages
|
||||||
|
%packages
|
||||||
|
@^server-product-environment
|
||||||
|
clevis
|
||||||
|
clevis-luks
|
||||||
|
clevis-tang
|
||||||
|
clevis-tpm2
|
||||||
|
tpm2-tools
|
||||||
|
tpm2-tss
|
||||||
|
cryptsetup
|
||||||
|
btrfs-progs
|
||||||
|
mdadm
|
||||||
|
dropbear
|
||||||
|
%end
|
||||||
|
|
||||||
|
# Post-installation
|
||||||
|
%post
|
||||||
|
# Create BTRFS subvolumes
|
||||||
|
btrfs subvolume create /@root
|
||||||
|
btrfs subvolume create /@home
|
||||||
|
btrfs subvolume create /@db
|
||||||
|
chattr +C /@db
|
||||||
|
|
||||||
|
# Update fstab
|
||||||
|
cat > /etc/fstab << EOF
|
||||||
|
/dev/md0 /boot ext4 defaults 1 2
|
||||||
|
/dev/mapper/root_a / btrfs subvol=@root,defaults,noatime 0 0
|
||||||
|
/dev/mapper/root_a /home btrfs subvol=@home,defaults,noatime 0 0
|
||||||
|
/dev/mapper/root_a /db btrfs subvol=@db,defaults,noatime,nodatacow 0 0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Save LUKS passphrase
|
||||||
|
echo "${LUKS_PASSPHRASE}" > /root/luks-passphrase.txt
|
||||||
|
chmod 600 /root/luks-passphrase.txt
|
||||||
|
|
||||||
|
# Configure sudoers
|
||||||
|
echo "%wheel ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/wheel
|
||||||
|
|
||||||
|
# Configure SSH
|
||||||
|
cat > /etc/ssh/sshd_config.d/99-custom.conf << EOF
|
||||||
|
PasswordAuthentication no
|
||||||
|
PermitRootLogin no
|
||||||
|
PubkeyAuthentication yes
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Configure dropbear for early SSH access
|
||||||
|
cat > /etc/dropbear-initramfs/config << EOF
|
||||||
|
DROPBEAR_OPTIONS="-I 60 -j -k -p 2222 -s"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Add SSH key to dropbear for early boot access
|
||||||
|
mkdir -p /etc/dropbear-initramfs/authorized_keys
|
||||||
|
echo "${SSH_KEY}" > /etc/dropbear-initramfs/authorized_keys
|
||||||
|
chmod 600 /etc/dropbear-initramfs/authorized_keys
|
||||||
|
|
||||||
|
# Set up MOTD
|
||||||
|
if [ "$ENABLE_MOTD" = true ]; then
|
||||||
|
cat > /etc/motd << EOF
|
||||||
|
${BANNER}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configure Clevis
|
||||||
|
if [ ${#TANG_SERVERS[@]} -gt 0 ] || [ "$TPM_ENABLED" = true ]; then
|
||||||
|
mkdir -p /etc/clevis
|
||||||
|
|
||||||
|
# Build Tang servers JSON array if we have any
|
||||||
|
if [ ${#TANG_SERVERS[@]} -gt 0 ]; then
|
||||||
|
TANG_JSON="["
|
||||||
|
for server in "${TANG_SERVERS[@]}"; do
|
||||||
|
read -r url thumbprint <<< "$server"
|
||||||
|
TANG_JSON+="{\"url\":\"$url\",\"thumbprint\":\"$thumbprint\"},"
|
||||||
|
done
|
||||||
|
TANG_JSON="${TANG_JSON%,}]" # Remove trailing comma and close array
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create Clevis config
|
||||||
|
cat > /etc/clevis/clevis.conf << EOF
|
||||||
|
{
|
||||||
|
"t": 2,
|
||||||
|
"pins": {
|
||||||
|
$([ "$TPM_ENABLED" = true ] && echo "\"tpm2\": {
|
||||||
|
\"pcr_bank\": \"${TPM_PCR_BANK}\",
|
||||||
|
\"pcr_ids\": \"${TPM_PCR_IDS}\"
|
||||||
|
},")
|
||||||
|
$([ ${#TANG_SERVERS[@]} -gt 0 ] && echo "\"tang\": {
|
||||||
|
\"t\": 1,
|
||||||
|
\"tang\": ${TANG_JSON}
|
||||||
|
}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Bind LUKS volumes
|
||||||
|
clevis luks bind -d /dev/sda2 sss -c /etc/clevis/clevis.conf
|
||||||
|
clevis luks bind -d /dev/sdb2 sss -c /etc/clevis/clevis.conf
|
||||||
|
else
|
||||||
|
echo "No Tang servers or TPM available, skipping Clevis setup"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Enable required services
|
||||||
|
systemctl enable clevis-luks-askpass
|
||||||
|
systemctl enable dropbear-initramfs
|
||||||
|
|
||||||
|
# Create TPM update script
|
||||||
|
cat > /root/update-tpm-bindings.py << 'TPMSCRIPT'
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
def run_command(cmd):
|
||||||
|
try:
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
||||||
|
return result.stdout.strip()
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Error running command: {' '.join(cmd)}")
|
||||||
|
print(f"Error: {e.stderr}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def get_pcr_values():
|
||||||
|
print("Current PCR values:")
|
||||||
|
for i in range(0, 9):
|
||||||
|
pcr = run_command(['tpm2_pcrread', f'sha256:{i}'])
|
||||||
|
print(f"PCR {i}: {pcr.split('=')[1].strip()}")
|
||||||
|
|
||||||
|
def update_bindings():
|
||||||
|
print("\nUpdating TPM bindings...")
|
||||||
|
devices = ['/dev/sda2', '/dev/sdb2']
|
||||||
|
|
||||||
|
for device in devices:
|
||||||
|
print(f"\nUpdating bindings for {device}")
|
||||||
|
try:
|
||||||
|
# Remove existing bindings
|
||||||
|
run_command(['clevis', 'luks', 'unbind', '-d', device, '-s', '1'])
|
||||||
|
run_command(['clevis', 'luks', 'unbind', '-d', device, '-s', '2'])
|
||||||
|
|
||||||
|
# Create new bindings
|
||||||
|
run_command(['clevis', 'luks', 'bind', '-d', device, 'sss', '-c', '/etc/clevis/clevis.conf'])
|
||||||
|
|
||||||
|
print(f"Successfully updated bindings for {device}")
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Error updating bindings for {device}: {e.stderr}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
def verify_bindings():
|
||||||
|
print("\nVerifying bindings...")
|
||||||
|
devices = ['/dev/sda2', '/dev/sdb2']
|
||||||
|
|
||||||
|
for device in devices:
|
||||||
|
print(f"\nBindings for {device}:")
|
||||||
|
try:
|
||||||
|
bindings = run_command(['clevis', 'luks', 'list', '-d', device])
|
||||||
|
print(bindings)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Error verifying bindings for {device}: {e.stderr}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if os.geteuid() != 0:
|
||||||
|
print("This script must be run as root")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("TPM Binding Update Script")
|
||||||
|
print("========================")
|
||||||
|
|
||||||
|
get_pcr_values()
|
||||||
|
update_bindings()
|
||||||
|
verify_bindings()
|
||||||
|
|
||||||
|
print("\nUpdate complete. Please reboot to test the new bindings.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
TPMSCRIPT
|
||||||
|
|
||||||
|
chmod +x /root/update-tpm-bindings.py
|
||||||
|
|
||||||
|
# Install additional packages
|
||||||
|
dnf install -y git zsh lsd bat tmux neovim fortune-mod cowsay lolcat xclip python3-pip --skip-unavailable
|
||||||
|
|
||||||
|
# Set zsh as default shell for root and default user
|
||||||
|
chsh -s /bin/zsh root
|
||||||
|
chsh -s /bin/zsh ${FEDORA_USER}
|
||||||
|
|
||||||
|
# Install Oh My Zsh
|
||||||
|
su - ${FEDORA_USER} -c 'sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended'
|
||||||
|
|
||||||
|
# Install Powerlevel10k
|
||||||
|
su - ${FEDORA_USER} -c 'git clone --depth=1 https://github.com/romkatv/powerlevel10k.git "${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k"'
|
||||||
|
|
||||||
|
# Create .zshrc for default user
|
||||||
|
cat > /home/${FEDORA_USER}/.zshrc << 'ZSHRC'
|
||||||
|
USE_OH_MY_ZSH=true
|
||||||
|
|
||||||
|
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
|
||||||
|
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Path to your oh-my-zsh installation.
|
||||||
|
if [[ $USE_OH_MY_ZSH == "true" ]]; then
|
||||||
|
export ZSH="$HOME/.oh-my-zsh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ZSH_THEME="powerlevel10k/powerlevel10k"
|
||||||
|
HIST_STAMPS="dd.mm.yyyy"
|
||||||
|
|
||||||
|
if [[ $USE_OH_MY_ZSH == "true" ]]; then
|
||||||
|
plugins=(git)
|
||||||
|
source $ZSH/oh-my-zsh.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n $SSH_CONNECTION ]]; then
|
||||||
|
export EDITOR='vim'
|
||||||
|
else
|
||||||
|
export EDITOR='nvim'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $TILIX_ID ] || [ $VTE_VERSION ]; then
|
||||||
|
source /etc/profile.d/vte.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# lang
|
||||||
|
alias ptpython="python -m ptpython"
|
||||||
|
alias ptpy="python -m ptpython"
|
||||||
|
alias py13='python3.13'
|
||||||
|
alias py12='python3.12'
|
||||||
|
alias py10='python3.10'
|
||||||
|
alias bpytop="python -m bpytop"
|
||||||
|
|
||||||
|
# python venv
|
||||||
|
alias pvcreate="python -m venv .venv"
|
||||||
|
alias pvactivate="source .venv/bin/activate"
|
||||||
|
alias pvinstall="echo 'Creating Python-venv' && pvcreate && echo 'Entering venv' && pvactivate && echo 'Upgrading pip' && pip install pip --upgrade && echo 'Installing Dependencies' && pip install -r requirements.txt && echo 'Done.'"
|
||||||
|
|
||||||
|
# qol
|
||||||
|
alias cls="clear"
|
||||||
|
alias root="sudo su --shell /bin/zsh"
|
||||||
|
alias open="xdg-open"
|
||||||
|
alias filenum="du -a | cut -d/ -f2 | sort | uniq -c | sort -nr"
|
||||||
|
alias pg="progress"
|
||||||
|
alias hist="history"
|
||||||
|
alias untar="tar -zxvf"
|
||||||
|
notify() {
|
||||||
|
$@ && echo "[DONE] $@" || echo "[ERROR] $@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# grep
|
||||||
|
alias antigrep="grep -v"
|
||||||
|
alias grep2="grep -A 2 -B 2"
|
||||||
|
alias grep4="grep -A 4 -B 4"
|
||||||
|
alias grep8="grep -A 8 -B 8"
|
||||||
|
alias grep16="grep -A 16 -B 16"
|
||||||
|
alias grep32="grep -A 32 -B 32"
|
||||||
|
alias ag="alias | grep"
|
||||||
|
|
||||||
|
# packages
|
||||||
|
alias get="sudo dnf install"
|
||||||
|
alias upd="sudo dnf check-upgrade"
|
||||||
|
alias upg="sudo dnf upgrade"
|
||||||
|
alias upf="sudo flatpak update"
|
||||||
|
alias upp="pip install --upgrade pip setuptools wheel && pip list --outdated --format=freeze | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 pip install -U"
|
||||||
|
|
||||||
|
#clipboard
|
||||||
|
alias setclip="xclip -selection c"
|
||||||
|
alias getclip="xclip -selection c -o"
|
||||||
|
alias pwdclip="pwd | xargs echo -n | xclip -selection c"
|
||||||
|
|
||||||
|
# chars
|
||||||
|
alias c="clear"
|
||||||
|
alias t="bpytop"
|
||||||
|
alias p="ptpy"
|
||||||
|
alias h="history | grep"
|
||||||
|
alias v="nvim"
|
||||||
|
alias n="nano"
|
||||||
|
alias f="nautilus ."
|
||||||
|
alias o="open"
|
||||||
|
alias e="\d"
|
||||||
|
alias ":q"="exit"
|
||||||
|
|
||||||
|
# git
|
||||||
|
alias gs="git status"
|
||||||
|
alias gt="git log --all --graph --decorate --oneline --abbrev-commit"
|
||||||
|
alias gnoc='git shortlog -sn | cat'
|
||||||
|
alias gloc='git ls-files | while read f; do git blame -w -M -C -C --line-porcelain "$f" | grep -I "^author "; done | sort -f | uniq -ic | sort -n --reverse'
|
||||||
|
alias gpa='gaa && gc -m "." && gp -4'
|
||||||
|
|
||||||
|
# extensions
|
||||||
|
alias sudo="sudo "
|
||||||
|
alias watch="watch "
|
||||||
|
alias watch1="watch -n 1 "
|
||||||
|
|
||||||
|
# better ls via lsd
|
||||||
|
alias ls="lsd"
|
||||||
|
alias l="ls -1"
|
||||||
|
alias la="ls -A"
|
||||||
|
alias laa="ls -a"
|
||||||
|
alias lsa="ls -lA"
|
||||||
|
alias lla="ls -lA"
|
||||||
|
alias ltree="ls --tree"
|
||||||
|
alias d0="ls --tree"
|
||||||
|
alias d="ls --depth 1 --tree"
|
||||||
|
alias d1="ls --depth 1 --tree"
|
||||||
|
alias d2="ls --depth 2 --tree"
|
||||||
|
alias d3="ls --depth 3 --tree"
|
||||||
|
alias d4="ls --depth 4 --tree"
|
||||||
|
alias d5="ls --depth 5 --tree"
|
||||||
|
alias d6="ls --depth 6 --tree"
|
||||||
|
|
||||||
|
# more ls
|
||||||
|
alias lo="\ls --color=tty"
|
||||||
|
alias dtree="tree --du -h"
|
||||||
|
alias gtree="tree --du -h -F -C | grep 'G] ' --color=never"
|
||||||
|
|
||||||
|
# better cat via batcat
|
||||||
|
alias bat="bat --pager ''"
|
||||||
|
alias pat="bat --pager '' --plain"
|
||||||
|
alias lat="bat"
|
||||||
|
|
||||||
|
# more fancy batcat stuff
|
||||||
|
alias man="batman"
|
||||||
|
|
||||||
|
# tmux
|
||||||
|
alias s="tmux"
|
||||||
|
alias sa="tmux attach"
|
||||||
|
alias sn="tmux new -s"
|
||||||
|
alias san="tmux attach -t"
|
||||||
|
alias sl="tmux ls"
|
||||||
|
alias sk="tmux kill-session -t"
|
||||||
|
alias ska="tmux kill-session -a"
|
||||||
|
|
||||||
|
# Powerlevel10k initialization
|
||||||
|
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
|
||||||
|
ZSHRC
|
||||||
|
|
||||||
|
# Create .p10k.zsh for default user
|
||||||
|
cat > /home/${FEDORA_USER}/.p10k.zsh << 'P10K'
|
||||||
|
# Temporarily change options.
|
||||||
|
'builtin' 'local' '-a' 'p10k_config_opts'
|
||||||
|
[[ ! -o 'aliases' ]] || p10k_config_opts+=('aliases')
|
||||||
|
[[ ! -o 'sh_glob' ]] || p10k_config_opts+=('sh_glob')
|
||||||
|
[[ ! -o 'no_brace_expand' ]] || p10k_config_opts+=('no_brace_expand')
|
||||||
|
'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand'
|
||||||
|
|
||||||
|
() {
|
||||||
|
emulate -L zsh
|
||||||
|
setopt no_unset extended_glob
|
||||||
|
|
||||||
|
# Unset all configuration options. This allows you to apply configiguration changes without
|
||||||
|
# restarting zsh. Edit ~/.p10k.zsh and type `source ~/.p10k.zsh`.
|
||||||
|
unset -m 'POWERLEVEL9K_*'
|
||||||
|
|
||||||
|
autoload -Uz is-at-least && is-at-least 5.1 || return
|
||||||
|
|
||||||
|
zmodload zsh/langinfo
|
||||||
|
if [[ ${langinfo[CODESET]:-} != (utf|UTF)(-|)8 ]]; then
|
||||||
|
local LC_ALL=${${(@M)$(locale -a):#*.(utf|UTF)(-|)8}[1]:-en_US.UTF-8}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The list of segments shown on the left. Fill it with the most important segments.
|
||||||
|
typeset -g POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(
|
||||||
|
context
|
||||||
|
dir # current directory
|
||||||
|
vcs # git status
|
||||||
|
)
|
||||||
|
|
||||||
|
typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(
|
||||||
|
background_jobs # presence of background jobs
|
||||||
|
direnv # direnv status (https://direnv.net/)
|
||||||
|
virtualenv # python virtual environment (https://docs.python.org/3/library/venv.html)
|
||||||
|
kubecontext # current kubernetes context (https://kubernetes.io/)
|
||||||
|
vim_shell # vim shell indicator (:sh)
|
||||||
|
vi_mode # vi mode (you don't need this if you've enabled prompt_char)
|
||||||
|
disk_usage # disk usage
|
||||||
|
)
|
||||||
|
typeset -g POWERLEVEL9K_VISUAL_IDENTIFIER_EXPANSION='${P9K_VISUAL_IDENTIFIER// }'
|
||||||
|
typeset -g POWERLEVEL9K_MODE=nerdfont-complete
|
||||||
|
typeset -g POWERLEVEL9K_ICON_BEFORE_CONTENT=
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_ADD_NEWLINE=false
|
||||||
|
typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_PREFIX='%242F╭─'
|
||||||
|
typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_PREFIX='%242F├─'
|
||||||
|
typeset -g POWERLEVEL9K_MULTILINE_LAST_PROMPT_PREFIX='%242F╰─'
|
||||||
|
typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_SUFFIX='%242F─╮'
|
||||||
|
typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_SUFFIX='%242F─┤'
|
||||||
|
typeset -g POWERLEVEL9K_MULTILINE_LAST_PROMPT_SUFFIX='%242F─╯'
|
||||||
|
typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR=' '
|
||||||
|
typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_BACKGROUND=
|
||||||
|
if [[ $POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR != ' ' ]]; then
|
||||||
|
typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_FOREGROUND=242
|
||||||
|
typeset -g POWERLEVEL9K_EMPTY_LINE_LEFT_PROMPT_FIRST_SEGMENT_END_SYMBOL='%{%}'
|
||||||
|
typeset -g POWERLEVEL9K_EMPTY_LINE_RIGHT_PROMPT_FIRST_SEGMENT_START_SYMBOL='%{%}'
|
||||||
|
fi
|
||||||
|
|
||||||
|
typeset -g POWERLEVEL9K_LEFT_SUBSEGMENT_SEPARATOR='\uE0B1'
|
||||||
|
typeset -g POWERLEVEL9K_RIGHT_SUBSEGMENT_SEPARATOR='\uE0B3'
|
||||||
|
typeset -g POWERLEVEL9K_LEFT_SEGMENT_SEPARATOR='\uE0B0'
|
||||||
|
typeset -g POWERLEVEL9K_RIGHT_SEGMENT_SEPARATOR='\uE0B2'
|
||||||
|
typeset -g POWERLEVEL9K_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL='\uE0B0'
|
||||||
|
typeset -g POWERLEVEL9K_RIGHT_PROMPT_FIRST_SEGMENT_START_SYMBOL='\uE0B2'
|
||||||
|
typeset -g POWERLEVEL9K_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL=''
|
||||||
|
typeset -g POWERLEVEL9K_RIGHT_PROMPT_LAST_SEGMENT_END_SYMBOL=''
|
||||||
|
typeset -g POWERLEVEL9K_EMPTY_LINE_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL=
|
||||||
|
|
||||||
|
#################################[ os_icon: os identifier ]##################################
|
||||||
|
typeset -g POWERLEVEL9K_OS_ICON_FOREGROUND=232
|
||||||
|
typeset -g POWERLEVEL9K_OS_ICON_BACKGROUND=7
|
||||||
|
typeset -g POWERLEVEL9K_OS_ICON_CONTENT_EXPANSION='%B${P9K_CONTENT// }'
|
||||||
|
|
||||||
|
################################[ prompt_char: prompt symbol ]################################
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_BACKGROUND=
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_OK_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=76
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_ERROR_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=196
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIINS_CONTENT_EXPANSION=' ' #'❯'
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VICMD_CONTENT_EXPANSION=' ' #'❮'
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIVIS_CONTENT_EXPANSION=' ' #'Ⅴ'
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIOWR_CONTENT_EXPANSION=' ' #'▶'
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_OVERWRITE_STATE=true
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL=
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL=
|
||||||
|
typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_{LEFT,RIGHT}_WHITESPACE=
|
||||||
|
|
||||||
|
##################################[ dir: current directory ]##################################
|
||||||
|
typeset -g POWERLEVEL9K_DIR_BACKGROUND=234
|
||||||
|
typeset -g POWERLEVEL9K_DIR_FOREGROUND=39
|
||||||
|
typeset -g POWERLEVEL9K_SHORTEN_STRATEGY=truncate_to_unique
|
||||||
|
typeset -g POWERLEVEL9K_SHORTEN_DELIMITER=
|
||||||
|
typeset -g POWERLEVEL9K_DIR_SHORTENED_FOREGROUND=103
|
||||||
|
typeset -g POWERLEVEL9K_DIR_ANCHOR_FOREGROUND=39
|
||||||
|
typeset -g POWERLEVEL9K_DIR_ANCHOR_BOLD=false
|
||||||
|
local anchor_files=(
|
||||||
|
.bzr
|
||||||
|
.citc
|
||||||
|
.git
|
||||||
|
.hg
|
||||||
|
.node-version
|
||||||
|
.python-version
|
||||||
|
.ruby-version
|
||||||
|
.shorten_folder_marker
|
||||||
|
.svn
|
||||||
|
.terraform
|
||||||
|
CVS
|
||||||
|
Cargo.toml
|
||||||
|
composer.json
|
||||||
|
go.mod
|
||||||
|
package.json
|
||||||
|
)
|
||||||
|
typeset -g POWERLEVEL9K_SHORTEN_FOLDER_MARKER="(${(j:|:)anchor_files})"
|
||||||
|
typeset -g POWERLEVEL9K_SHORTEN_DIR_LENGTH=1
|
||||||
|
typeset -g POWERLEVEL9K_DIR_MAX_LENGTH=80
|
||||||
|
typeset -g POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS=40
|
||||||
|
typeset -g POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT=50
|
||||||
|
typeset -g POWERLEVEL9K_DIR_HYPERLINK=false
|
||||||
|
typeset -g POWERLEVEL9K_DIR_SHOW_WRITABLE=true
|
||||||
|
typeset -g POWERLEVEL9K_DIR_CLASSES=()
|
||||||
|
|
||||||
|
#####################################[ vcs: git status ]######################################
|
||||||
|
# Version control system colors.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_CLEAN_FOREGROUND=10
|
||||||
|
typeset -g POWERLEVEL9K_VCS_CLEAN_BACKGROUND=235 #2
|
||||||
|
typeset -g POWERLEVEL9K_VCS_MODIFIED_FOREGROUND=10
|
||||||
|
typeset -g POWERLEVEL9K_VCS_MODIFIED_BACKGROUND=235 #3
|
||||||
|
typeset -g POWERLEVEL9K_VCS_UNTRACKED_FOREGROUND=10
|
||||||
|
typeset -g POWERLEVEL9K_VCS_UNTRACKED_BACKGROUND=235 #2
|
||||||
|
typeset -g POWERLEVEL9K_VCS_CONFLICTED_FOREGROUND=9
|
||||||
|
typeset -g POWERLEVEL9K_VCS_CONFLICTED_BACKGROUND=235 #3
|
||||||
|
typeset -g POWERLEVEL9K_VCS_LOADING_FOREGROUND=15
|
||||||
|
typeset -g POWERLEVEL9K_VCS_LOADING_BACKGROUND=255
|
||||||
|
|
||||||
|
# Branch icon. Set this parameter to '\uF126 ' for the popular Powerline branch icon. Disabled because bug
|
||||||
|
typeset -g POWERLEVEL9K_VCS_BRANCH_ICON='\uF126 '
|
||||||
|
POWERLEVEL9K_VCS_BRANCH_ICON=${(g::)POWERLEVEL9K_VCS_BRANCH_ICON}
|
||||||
|
|
||||||
|
# Untracked files icon. It's really a question mark, your font isn't broken.
|
||||||
|
# Change the value of this parameter to show a different icon.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_UNTRACKED_ICON='?'
|
||||||
|
POWERLEVEL9K_VCS_UNTRACKED_ICON=${(g::)POWERLEVEL9K_VCS_UNTRACKED_ICON}
|
||||||
|
|
||||||
|
# Formatter for Git status.
|
||||||
|
#
|
||||||
|
# Example output: master ⇣42⇡42 *42 merge ~42 +42 !42 ?42.
|
||||||
|
#
|
||||||
|
# You can edit the function to customize how Git status looks.
|
||||||
|
#
|
||||||
|
# VCS_STATUS_* parameters are set by gitstatus plugin. See reference:
|
||||||
|
# https://github.com/romkatv/gitstatus/blob/master/gitstatus.plugin.zsh.
|
||||||
|
function my_git_formatter() {
|
||||||
|
emulate -L zsh
|
||||||
|
|
||||||
|
if [[ -n $P9K_CONTENT ]]; then
|
||||||
|
# If P9K_CONTENT is not empty, use it. It's either "loading" or from vcs_info (not from
|
||||||
|
# gitstatus plugin). VCS_STATUS_* parameters are not available in this case.
|
||||||
|
typeset -g my_git_format=$P9K_CONTENT
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Styling for different parts of Git status.
|
||||||
|
local meta='' #'%7F' # white foreground
|
||||||
|
local clean='' #'%0F' # black foreground
|
||||||
|
local modified='' #'%0F' # black foreground
|
||||||
|
local untracked='' #'%0F' # black foreground
|
||||||
|
local conflicted='' #'%1F' # red foreground
|
||||||
|
|
||||||
|
local res
|
||||||
|
local where # branch or tag
|
||||||
|
if [[ -n $VCS_STATUS_LOCAL_BRANCH ]]; then
|
||||||
|
res+="${clean}${POWERLEVEL9K_VCS_BRANCH_ICON}"
|
||||||
|
where=${(V)VCS_STATUS_LOCAL_BRANCH}
|
||||||
|
elif [[ -n $VCS_STATUS_TAG ]]; then
|
||||||
|
res+="${meta}#"
|
||||||
|
where=${(V)VCS_STATUS_TAG}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If local branch name or tag is at most 32 characters long, show it in full.
|
||||||
|
# Otherwise show the first 12 … the last 12.
|
||||||
|
(( $#where > 32 )) && where[13,-13]="…"
|
||||||
|
res+="${clean}${where//\%/%%}" # escape %
|
||||||
|
|
||||||
|
# Display the current Git commit if there is no branch or tag.
|
||||||
|
# Tip: To always display current Git commit, remove `[[ -z $where ]] &&` from the next line.
|
||||||
|
[[ -z $where ]] && res+="${meta}@${clean}${VCS_STATUS_COMMIT[1,8]}"
|
||||||
|
|
||||||
|
# Show tracking branch name if it differs from local branch.
|
||||||
|
if [[ -n ${VCS_STATUS_REMOTE_BRANCH:#$VCS_STATUS_LOCAL_BRANCH} ]]; then
|
||||||
|
res+="${meta}:${clean}${(V)VCS_STATUS_REMOTE_BRANCH//\%/%%}" # escape %
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ⇣42 if behind the remote.
|
||||||
|
(( VCS_STATUS_COMMITS_BEHIND )) && res+=" ${clean}⇣${VCS_STATUS_COMMITS_BEHIND}"
|
||||||
|
# ⇡42 if ahead of the remote; no leading space if also behind the remote: ⇣42⇡42.
|
||||||
|
(( VCS_STATUS_COMMITS_AHEAD && !VCS_STATUS_COMMITS_BEHIND )) && res+=" "
|
||||||
|
(( VCS_STATUS_COMMITS_AHEAD )) && res+="${clean}⇡${VCS_STATUS_COMMITS_AHEAD}"
|
||||||
|
# *42 if have stashes.
|
||||||
|
(( VCS_STATUS_STASHES )) && res+=" ${clean}*${VCS_STATUS_STASHES}"
|
||||||
|
# 'merge' if the repo is in an unusual state.
|
||||||
|
[[ -n $VCS_STATUS_ACTION ]] && res+=" ${conflicted}${VCS_STATUS_ACTION}"
|
||||||
|
# ~42 if have merge conflicts.
|
||||||
|
(( VCS_STATUS_NUM_CONFLICTED )) && res+=" ${conflicted}~${VCS_STATUS_NUM_CONFLICTED}"
|
||||||
|
# +42 if have staged changes.
|
||||||
|
(( VCS_STATUS_NUM_STAGED )) && res+=" ${modified}+${VCS_STATUS_NUM_STAGED}"
|
||||||
|
# !42 if have unstaged changes.
|
||||||
|
(( VCS_STATUS_NUM_UNSTAGED )) && res+=" ${modified}!${VCS_STATUS_NUM_UNSTAGED}"
|
||||||
|
# ?42 if have untracked files. It's really a question mark, your font isn't broken.
|
||||||
|
# See POWERLEVEL9K_VCS_UNTRACKED_ICON above if you want to use a different icon.
|
||||||
|
# Remove the next line if you don't want to see untracked files at all.
|
||||||
|
(( VCS_STATUS_NUM_UNTRACKED )) && res+=" ${untracked}${POWERLEVEL9K_VCS_UNTRACKED_ICON}${VCS_STATUS_NUM_UNTRACKED}"
|
||||||
|
|
||||||
|
typeset -g my_git_format=$res
|
||||||
|
}
|
||||||
|
functions -M my_git_formatter 2>/dev/null
|
||||||
|
|
||||||
|
# Disable the default Git status formatting.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_DISABLE_GITSTATUS_FORMATTING=true
|
||||||
|
# Install our own Git status formatter.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_CONTENT_EXPANSION='${$((my_git_formatter()))+${my_git_format}}'
|
||||||
|
# Enable counters for staged, unstaged, etc.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_{STAGED,UNSTAGED,UNTRACKED,CONFLICTED,COMMITS_AHEAD,COMMITS_BEHIND}_MAX_NUM=-1
|
||||||
|
|
||||||
|
# Custom icon.
|
||||||
|
# typeset -g POWERLEVEL9K_VCS_VISUAL_IDENTIFIER_EXPANSION='⭐'
|
||||||
|
# Custom prefix.
|
||||||
|
# typeset -g POWERLEVEL9K_VCS_PREFIX='on '
|
||||||
|
|
||||||
|
# Show status of repositories of these types. You can add svn and/or hg if you are
|
||||||
|
# using them. If you do, your prompt may become slow even when your current directory
|
||||||
|
# isn't in an svn or hg reposotiry.
|
||||||
|
typeset -g POWERLEVEL9K_VCS_BACKENDS=(git)
|
||||||
|
|
||||||
|
##################################[ disk_usgae: disk usage ]##################################
|
||||||
|
typeset -g POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL=95
|
||||||
|
typeset -g POWERLEVEL9K_DISK_USAGE_CRITICAL_LEVEL=98
|
||||||
|
typeset -g POWERLEVEL9K_DISK_USAGE_ONLY_WARNING=true
|
||||||
|
|
||||||
|
###########[ vi_mode: vi mode (you don't need this if you've enabled prompt_char) ]###########
|
||||||
|
typeset -g POWERLEVEL9K_VI_MODE_FOREGROUND=0
|
||||||
|
typeset -g POWERLEVEL9K_VI_COMMAND_MODE_STRING=NORMAL
|
||||||
|
typeset -g POWERLEVEL9K_VI_MODE_NORMAL_BACKGROUND=2
|
||||||
|
typeset -g POWERLEVEL9K_VI_VISUAL_MODE_STRING=VISUAL
|
||||||
|
typeset -g POWERLEVEL9K_VI_MODE_VISUAL_BACKGROUND=4
|
||||||
|
typeset -g POWERLEVEL9K_VI_OVERWRITE_MODE_STRING=OVERTYPE
|
||||||
|
typeset -g POWERLEVEL9K_VI_MODE_OVERWRITE_BACKGROUND=3
|
||||||
|
typeset -g POWERLEVEL9K_VI_INSERT_MODE_STRING=
|
||||||
|
typeset -g POWERLEVEL9K_VI_MODE_INSERT_FOREGROUND=8
|
||||||
|
|
||||||
|
######################################[ ram: free RAM ]#######################################
|
||||||
|
# RAM color.
|
||||||
|
# typeset -g POWERLEVEL9K_RAM_FOREGROUND=0
|
||||||
|
# typeset -g POWERLEVEL9K_RAM_BACKGROUND=3
|
||||||
|
# Custom icon.
|
||||||
|
# typeset -g POWERLEVEL9K_RAM_VISUAL_IDENTIFIER_EXPANSION='⭐'
|
||||||
|
|
||||||
|
#####################################[ swap: used swap ]######################################
|
||||||
|
# Swap color.
|
||||||
|
# typeset -g POWERLEVEL9K_SWAP_FOREGROUND=0
|
||||||
|
# typeset -g POWERLEVEL9K_SWAP_BACKGROUND=3
|
||||||
|
# Custom icon.
|
||||||
|
# typeset -g POWERLEVEL9K_SWAP_VISUAL_IDENTIFIER_EXPANSION='⭐'
|
||||||
|
|
||||||
|
######################################[ load: CPU load ]######################################
|
||||||
|
typeset -g POWERLEVEL9K_LOAD_WHICH=5
|
||||||
|
|
||||||
|
##################################[ context: user@hostname ]##################################
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_ROOT_FOREGROUND=1
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_ROOT_BACKGROUND=0
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_FOREGROUND=3
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_BACKGROUND=0
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_FOREGROUND=3
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_BACKGROUND=0
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_ROOT_TEMPLATE='%n@%m'
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_TEMPLATE='%n@%m'
|
||||||
|
typeset -g POWERLEVEL9K_CONTEXT_TEMPLATE='%n'
|
||||||
|
|
||||||
|
###[ virtualenv: python virtual environment (https://docs.python.org/3/library/venv.html) ]###
|
||||||
|
typeset -g POWERLEVEL9K_VIRTUALENV_SHOW_PYTHON_VERSION=false
|
||||||
|
typeset -g POWERLEVEL9K_VIRTUALENV_{LEFT,RIGHT}_DELIMITER=
|
||||||
|
|
||||||
|
#############[ kubecontext: current kubernetes context (https://kubernetes.io/) ]#############
|
||||||
|
typeset -g POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|helm|kubens|kubectx|oc'
|
||||||
|
typeset -g POWERLEVEL9K_KUBECONTEXT_CLASSES=(
|
||||||
|
# '*prod*' PROD # These values are examples that are unlikely
|
||||||
|
# '*test*' TEST # to match your needs. Customize them as needed.
|
||||||
|
'*' DEFAULT)
|
||||||
|
typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_FOREGROUND=7
|
||||||
|
typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_BACKGROUND=5
|
||||||
|
typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION=
|
||||||
|
POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION+='${P9K_KUBECONTEXT_CLOUD_CLUSTER:-${P9K_KUBECONTEXT_NAME}}'
|
||||||
|
POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION+='${${:-/$P9K_KUBECONTEXT_NAMESPACE}:#/default}'
|
||||||
|
|
||||||
|
####################################[ time: current time ]####################################
|
||||||
|
typeset -g POWERLEVEL9K_TIME_FORMAT='%D{%H:%M:%S}'
|
||||||
|
typeset -g POWERLEVEL9K_TIME_UPDATE_ON_COMMAND=false
|
||||||
|
|
||||||
|
typeset -g POWERLEVEL9K_TRANSIENT_PROMPT=off
|
||||||
|
typeset -g POWERLEVEL9K_INSTANT_PROMPT=verbose
|
||||||
|
typeset -g POWERLEVEL9K_DISABLE_HOT_RELOAD=true
|
||||||
|
(( ! $+functions[p10k] )) || p10k reload
|
||||||
|
}
|
||||||
|
|
||||||
|
(( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]}
|
||||||
|
'builtin' 'unset' 'p10k_config_opts'
|
||||||
|
P10K
|
||||||
|
|
||||||
|
# Set correct permissions
|
||||||
|
chown -R ${FEDORA_USER}:${FEDORA_USER} /home/${FEDORA_USER}/.oh-my-zsh
|
||||||
|
chown ${FEDORA_USER}:${FEDORA_USER} /home/${FEDORA_USER}/.zshrc
|
||||||
|
chown ${FEDORA_USER}:${FEDORA_USER} /home/${FEDORA_USER}/.p10k.zsh
|
||||||
|
|
||||||
|
# Install Python packages
|
||||||
|
pip3 install --user ptpython bpytop
|
||||||
|
|
||||||
|
%end
|
||||||
|
|
||||||
|
reboot
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Start Fedora installation
|
||||||
|
echo "Starting Fedora installation..."
|
||||||
|
echo "This will take some time. Please wait..."
|
||||||
|
/mnt/iso/isolinux/vmlinuz initrd=/mnt/iso/isolinux/initrd.img inst.ks=file:///mnt/ks.cfg inst.stage2=hd:LABEL=Fedora-S-42-1-5-x86_64
|
||||||
|
echo -e "\nInstallation started! Please wait for completion and reboot."
|
@ -1 +0,0 @@
|
|||||||
pyyaml>=6.0.1
|
|
Loading…
Reference in New Issue
Block a user