221 lines
No EOL
7.4 KiB
Markdown
221 lines
No EOL
7.4 KiB
Markdown
# Unified First-Boot Server Setup Script
|
|
A complete, self-contained provisioning script for automated server deployment that combines both **Ripcord** and **SYNterloper** with system hardening tasks (user creation, SSH setup, sudoers) in one idempotent user-data script.
|
|
|
|
---
|
|
|
|
## 🔧 Purpose
|
|
This script automates the following tasks on first boot:
|
|
- Creates a non-root user with SSH access and sudo privileges
|
|
- Installs Ansible-ready Python packages
|
|
- Deploys **Ripcord** (emergency disk space reserve)
|
|
- Deploys **SYNterloper** (rolling SSH connection logger)
|
|
- Validates each step with `.flag` files
|
|
- Leaves all components ready for manual management
|
|
|
|
➡️ **For tool-specific details, see individual READMEs**:
|
|
- [Ripcord README](./ripcord/README.md)
|
|
- [SYNterloper README](./synterloper/README.md)
|
|
|
|
---
|
|
|
|
## 📦 Repository Structure
|
|
```
|
|
.
|
|
├── user-data.sh # This script
|
|
├── ripcord/
|
|
│ ├── ripcord.sh
|
|
│ └── README.md
|
|
├── synterloper/
|
|
│ ├── synterloper.sh
|
|
│ └── README.md
|
|
└── README.md # You are here
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 Installation
|
|
Paste this script into your cloud provider's **User Data** field during instance creation:
|
|
```bash
|
|
#!/bin/bash
|
|
set -e # Exit on any error
|
|
|
|
# Define user and flag locations
|
|
USRNAME=fastsoul
|
|
FLAG_DIR=/var/lib/cloud/scripts/user
|
|
mkdir -p "$FLAG_DIR"
|
|
|
|
# --- Step 1: Create user ---
|
|
if [ ! -f "$FLAG_DIR/.user_created.flag" ]; then
|
|
echo "Creating user: $USRNAME"
|
|
if ! id "$USRNAME" &>/dev/null; then
|
|
useradd "$USRNAME" -s /bin/bash -d /home/"$USRNAME" -m || { echo "User creation failed"; exit 1; }
|
|
chown -R "$USRNAME":"$USRNAME" /home/"$USRNAME"
|
|
else
|
|
echo "User $USRNAME already exists. Skipping creation."
|
|
fi
|
|
touch "$FLAG_DIR/.user_created.flag"
|
|
fi
|
|
|
|
# --- Step 2: Create SSH directory and authorized_keys file ---
|
|
if [ ! -f "$FLAG_DIR/.ssh_setup.flag" ]; then
|
|
echo "Setting up SSH for $USRNAME"
|
|
mkdir -p "/home/$USRNAME/.ssh"
|
|
touch "/home/$USRNAME/.ssh/authorized_keys"
|
|
chown -R "$USRNAME":"$USRNAME" "/home/$USRNAME/.ssh"
|
|
chmod 700 "/home/$USRNAME/.ssh"
|
|
chmod 600 "/home/$USRNAME/.ssh/authorized_keys"
|
|
touch "$FLAG_DIR/.ssh_setup.flag"
|
|
fi
|
|
|
|
# --- Step 3: Add SSH keys to authorized_keys ---
|
|
if [ ! -f "$FLAG_DIR/.ssh_keys_added.flag" ]; then
|
|
echo "Adding SSH keys to authorized_keys"
|
|
cat << EOF >> /home/$USRNAME/.ssh/authorized_keys
|
|
cert-authority ssh-rsa AAAAB3NzaXXXX== user@example.com
|
|
|
|
ssh-rsa AAAAB3NzaYYYYYYYYYYYYYYYYYYYYYYYYYYYYQ==
|
|
|
|
ssh-rsa AAAAB3NzaXXXXXXXXXXXXXXXXXXXXXXXXXXXXQ==
|
|
EOF
|
|
|
|
if [ $? -eq 0 ]; then
|
|
chown -R "$USRNAME":"$USRNAME" "/home/$USRNAME/.ssh/authorized_keys"
|
|
touch "$FLAG_DIR/.ssh_keys_added.flag"
|
|
else
|
|
echo "Failed to write SSH keys to authorized_keys"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# --- Step 4: Set NOPASSWD sudoers ---
|
|
if [ ! -f "$FLAG_DIR/.sudoers_set.flag" ]; then
|
|
echo "Setting up NOPASSWD sudo for $USRNAME"
|
|
echo "$USRNAME ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/"$USRNAME" || { echo "Failed to write sudoers file"; exit 1; }
|
|
touch "$FLAG_DIR/.sudoers_set.flag"
|
|
fi
|
|
|
|
# --- Step 5: Install python3-apt for Ansible support ---
|
|
if [ ! -f "$FLAG_DIR/.python_installed.flag" ]; then
|
|
echo "Updating APT and installing python3-apt"
|
|
apt update -y || { echo "APT update failed"; exit 1; }
|
|
apt install -y python3-apt || { echo "Failed to install python3-apt"; exit 1; }
|
|
touch "$FLAG_DIR/.python_installed.flag"
|
|
fi
|
|
|
|
# --- Step 6: Download Ripcord and SYNterloper from Git ---
|
|
if [ ! -f "$FLAG_DIR/.scripts_downloaded.flag" ]; then
|
|
echo "Downloading Ripcord and SYNterloper scripts"
|
|
curl -fsSL -o /usr/local/sbin/ripcord.sh https://git.r21.io/primemover/user-data/raw/branch/master/ripcord/ripcord.sh || { echo "Ripcord download failed"; exit 1; }
|
|
curl -fsSL -o /usr/local/sbin/synterloper.sh https://git.r21.io/primemover/user-data/raw/branch/master/synterloper/synterloper.sh || { echo "SYNterloper download failed"; exit 1; }
|
|
chmod +x /usr/local/sbin/ripcord.sh /usr/local/sbin/synterloper.sh || { echo "chmod failed"; exit 1; }
|
|
touch "$FLAG_DIR/.scripts_downloaded.flag"
|
|
fi
|
|
|
|
# --- Step 7: Setup Ripcord systemd service ---
|
|
if [ ! -f "$FLAG_DIR/.ripcord_setup.flag" ]; then
|
|
echo "Setting up Ripcord systemd service"
|
|
cat << EOF | sudo tee /etc/systemd/system/ripcord.service
|
|
[Unit]
|
|
Description=Ripcord Emergency Disk Space Reserve
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=/usr/local/sbin/ripcord.sh
|
|
ExecStartPost=/bin/sh -c "systemctl disable ripcord.service"
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl enable ripcord.service || { echo "Failed to enable Ripcord service"; exit 1; }
|
|
touch "$FLAG_DIR/.ripcord_setup.flag"
|
|
fi
|
|
|
|
# --- Step 8: Install SYNterloper ---
|
|
if [ ! -f "$FLAG_DIR/.synterloper_installed.flag" ]; then
|
|
echo "Installing SYNterloper"
|
|
/usr/local/sbin/synterloper.sh install || { echo "SYNterloper install failed"; exit 1; }
|
|
touch "$FLAG_DIR/.synterloper_installed.flag"
|
|
fi
|
|
|
|
# --- Final Step: Mark completion ---
|
|
if [ ! -f "$FLAG_DIR/.user_data_complete.flag" ]; then
|
|
echo "Marking user-data completion"
|
|
touch /root/user_data_completed.txt
|
|
touch "$FLAG_DIR/.user_data_complete.flag"
|
|
fi
|
|
|
|
echo "All steps completed successfully."
|
|
exit 0
|
|
```
|
|
|
|
### ✅ What Gets Installed
|
|
| Component | Purpose | Validation Flag |
|
|
|-------------------|----------------------------------|-------------------------------------|
|
|
| User: `fastsoul` | Primary admin account | `/var/lib/cloud/scripts/user/.user_created.flag` |
|
|
| SSH Keys | Cert-authority and/or deployment keys | `/var/lib/cloud/scripts/user/.ssh_keys_added.flag` |
|
|
| Sudoers | NOPASSWD:ALL access | `/var/lib/cloud/scripts/user/.sudoers_set.flag` |
|
|
| Python 3-apt | Ansible dependency | `/var/lib/cloud/scripts/user/.python_installed.flag` |
|
|
| Ripcord.sh | Emergency disk ballast | `/var/lib/cloud/scripts/user/.ripcord_setup.flag` |
|
|
| Synterloper.sh | Rolling SSH connection logger | `/var/lib/cloud/scripts/user/.synterloper_installed.flag` |
|
|
|
|
---
|
|
|
|
## ⚙️ Configuration
|
|
Edit these variables at the top of the script to customize:
|
|
```bash
|
|
# Change these to match your needs
|
|
USRNAME=fastsoul
|
|
SSH_KEYS="
|
|
cert-authority ssh-rsa AAAAB3NzaXXXXXXXXXXXXXXXXXX...user@example.com
|
|
ssh-rsa AAAAB3NzaYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYQ==
|
|
ssh-rsa AAAAB3NzaXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXQ==
|
|
```
|
|
|
|
---
|
|
|
|
## 🔍 Validation
|
|
All steps are validated with `.flag` files in `/var/lib/cloud/scripts/user/`:
|
|
```bash
|
|
ls -la /var/lib/cloud/scripts/user/
|
|
```
|
|
Expected output:
|
|
```
|
|
.user_created.flag
|
|
.ssh_keys_added.flag
|
|
.sudoers_set.flag
|
|
.python_installed.flag
|
|
.scripts_downloaded.flag
|
|
.ripcord_setup.flag
|
|
.synterloper_installed.flag
|
|
.user_data_complete.flag
|
|
```
|
|
|
|
---
|
|
|
|
## 🧹 Re-running
|
|
To re-run the script (e.g., for testing):
|
|
1. Delete specific `.flag` files:
|
|
```bash
|
|
rm /var/lib/cloud/scripts/user/.sudoers_set.flag
|
|
```
|
|
2. Re-run the script:
|
|
```bash
|
|
sudo /var/lib/cloud/scripts/user/user-data.sh
|
|
```
|
|
|
|
---
|
|
|
|
## ⚠️ Known Limitations
|
|
- **Debian/Ubuntu only** (FreeBSD support would require separate logic)
|
|
- **Root access required** (must be run via cloud-init)
|
|
- **Hardcoded SSH keys** (rotate credentials for production use)
|
|
|
|
---
|
|
|
|
## 📚 For More Details
|
|
- [Ripcord README](./ripcord/README.md)
|
|
- [SYNterloper README](./synterloper/README.md)
|
|
|
|
---
|
|
|
|
## 📄 License
|
|
This script is released under the **MIT License**. See `LICENSE` for details. |