-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup.sh
More file actions
201 lines (172 loc) · 8.27 KB
/
Copy pathsetup.sh
File metadata and controls
201 lines (172 loc) · 8.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#!/bin/bash
# ==============================================================================
# AUTOMATED & IDEMPOTENT LINUX SERVER BOOTSTRAP SCRIPT (v5 - English Edition)
# ==============================================================================
#
# HOW TO RUN DIRECTLY FROM THE COMMAND LINE WITHOUT DOWNLOADING:
#
# curl -sSL https://raw.githubusercontent.com/pniaps/linux-server-bootstrap/main/setup.sh | bash
#
# OR with predefined variables for headless execution:
# curl -sSL https://raw.githubusercontent.com/pniaps/linux-server-bootstrap/main/setup.sh | GITHUB_USER="gh_user" NEW_USER="pnia" SSH_PORT="4815" HOSTNAME="my-vps" bash
#
# ==============================================================================
set -e
echo "=== Beginning foundational environment setup and initial hardening ==="
# 1. Prompt for GitHub username if not provided via environment variable
if [ -z "$GITHUB_USER" ]; then
read -p "Enter your GitHub username to fetch public keys: " GITHUB_USER
if [ -z "$GITHUB_USER" ]; then
echo "[ERROR] GitHub username is required to safely inject SSH access." >&2
exit 1
fi
fi
# 2. Prompt for Sudoer username if not provided via environment variable
if [ -z "$NEW_USER" ]; then
read -p "Enter the name of the new administrative user (Sudoer): " NEW_USER
if [ -z "$NEW_USER" ]; then
echo "[ERROR] Sudoer username selection is required." >&2
exit 1
fi
fi
# 3. Prompt for SSH Port if not provided via environment variable
if [ -z "$SSH_PORT" ]; then
read -p "Enter the desired SSH port [Default: 22]: " SSH_PORT
SSH_PORT=${SSH_PORT:-22}
fi
# 4. Prompt for Hostname if not provided via environment variable
CURRENT_HOSTNAME=$(hostname)
if [ -z "$HOSTNAME" ]; then
read -p "Enter the desired hostname for this server [Default: ${CURRENT_HOSTNAME}]: " HOSTNAME
HOSTNAME=${HOSTNAME:-$CURRENT_HOSTNAME}
fi
# 5. Configure Hostname if it changed
if [ "$HOSTNAME" != "$CURRENT_HOSTNAME" ]; then
echo "Updating system hostname to '${HOSTNAME}'..."
sudo hostnamectl set-hostname "$HOSTNAME"
# Extract the short name (e.g., if HOSTNAME is vps1.domain.com, SHORT_NAME becomes vps1)
SHORT_NAME=$(echo "$HOSTNAME" | cut -d. -f1)
# Update /etc/hosts cleanly without duplicating rows
# First, we remove old entries assigned to 127.0.1.1 to keep it tidy
sudo sed -i '/^127\.0\.1\.1/d' /etc/hosts
# Append the new clean mapping
echo "127.0.1.1 ${HOSTNAME} ${SHORT_NAME}" | sudo tee -a /etc/hosts > /dev/null
echo "Hostname successfully updated."
else
echo "Keeping current hostname: ${CURRENT_HOSTNAME}"
fi
# 6. Establish System Timezone
echo "Configuring system timezone to Europe/Madrid..."
sudo timedatectl set-timezone Europe/Madrid
echo "Current system time state: $(date)"
# 7. Idempotent Sudoer Account Provisioning
if id "$NEW_USER" >/dev/null 2>&1; then
echo "User '$NEW_USER' already exists. Skipping user provisioning."
else
echo "Creating administrative account '$NEW_USER'..."
sudo useradd -m -s /bin/bash "$NEW_USER"
# Lock the interactive password field (*), demanding cryptographic keys for authentication
sudo usermod -p '*' "$NEW_USER"
# Grant passwordless sudo elevation for smoother configuration tasks
echo "$NEW_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee "/etc/sudoers.d/$NEW_USER" > /dev/null
sudo chmod 0440 "/etc/sudoers.d/$NEW_USER"
fi
# 8. Idempotent Cryptographic Key Injection
USER_HOME=$(eval echo ~$NEW_USER)
SSH_DIR="$USER_HOME/.ssh"
sudo mkdir -p "$SSH_DIR"
sudo chmod 700 "$SSH_DIR"
sudo touch "$SSH_DIR/authorized_keys"
sudo chmod 600 "$SSH_DIR/authorized_keys"
echo "Retrieving public keys from GitHub for profile: '$GITHUB_USER'..."
TMP_KEYS=$(mktemp)
curl -s "https://github.com/${GITHUB_USER}.keys" > "$TMP_KEYS"
if [ ! -s "$TMP_KEYS" ]; then
echo "[WARNING] No public keys found on GitHub for user '$GITHUB_USER' or network connection failed."
else
while IFS= read -r key; do
if ! grep -qF "$key" "$SSH_DIR/authorized_keys"; then
echo "$key" | sudo tee -a "$SSH_DIR/authorized_keys" > /dev/null
echo "Successfully injected key string into $NEW_USER environment."
else
echo "Key signature already present in authorization file. Skipping duplicate."
fi
done < "$TMP_KEYS"
fi
rm -f "$TMP_KEYS"
sudo chown -R "$NEW_USER:$NEW_USER" "$SSH_DIR"
# 9. One-Time SSH Daemon Hardening & Conditional Port Assignment
SSH_CONFIG="/etc/ssh/sshd_config"
SSH_CONFIG_BAK="${SSH_CONFIG}.bak"
if [ -f "$SSH_CONFIG_BAK" ]; then
echo "[SSH] Backup file $SSH_CONFIG_BAK detected. Skipping SSH modification to prevent override loops."
else
echo "[SSH] Reconfiguring service parameters and hardening access..."
sudo cp "$SSH_CONFIG" "$SSH_CONFIG_BAK"
# Swap out defaults for hardened profiles (Password & Root restriction)
sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' $SSH_CONFIG
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' $SSH_CONFIG
sudo sed -i 's/^#\?ChallengeResponseAuthentication.*/ChallengeResponseAuthentication no/' $SSH_CONFIG 2>/dev/null || true
sudo sed -i 's/^#\?KbdInteractiveAuthentication.*/KbdInteractiveAuthentication no/' $SSH_CONFIG 2>/dev/null || true
# Only modify port if a custom one (not 22) was explicitly selected
if [ "$SSH_PORT" != "22" ]; then
echo "[SSH] Changing standard port to $SSH_PORT. Make sure this port is open in your external firewall!"
sudo sed -i "s/^#\?Port.*/Port $SSH_PORT/" $SSH_CONFIG
fi
# Address drop-in override directories (*.conf) standard in modern distributions
SSH_CONFIG_D="/etc/ssh/sshd_config.d"
if [ -d "$SSH_CONFIG_D" ]; then
if [ -f "$SSH_CONFIG_D/50-cloud-init.conf" ]; then
# Build configuration string based on choice
CONF_PAYLOAD="PasswordAuthentication no\nPermitRootLogin no"
if [ "$SSH_PORT" != "22" ]; then
CONF_PAYLOAD="Port $SSH_PORT\n${CONF_PAYLOAD}"
fi
echo -e "$CONF_PAYLOAD" | sudo tee "$SSH_CONFIG_D/50-cloud-init.conf" > /dev/null
fi
fi
echo "Restarting SSH daemon..."
if systemctl is-active --quiet ssh; then
sudo systemctl restart ssh
elif systemctl is-active --quiet sshd; then
sudo systemctl restart sshd
fi
fi
# 10. Activate Automatic Security Patching Engine
echo "Deploying unattended security update triggers..."
if [ -f /usr/bin/apt-get ]; then
sudo apt-get update -y > /dev/null
sudo apt-get install -y unattended-upgrades apt-listchanges > /dev/null
echo "APT::Periodic::Update-Package-Lists \"1\";" | sudo tee /etc/apt/apt.conf.d/20auto-upgrades > /dev/null
echo "APT::Periodic::Unattended-Upgrade \"1\";" | sudo tee -a /etc/apt/apt.conf.d/20auto-upgrades > /dev/null
sudo systemctl restart unattended-upgrades || true
echo "Automated patching infrastructure configured and active."
else
echo "[NOTICE] APT package manager not found. If this is an RHEL/CentOS system, deploy 'dnf-automatic' manually."
fi
# 11. Fetch Public IP for Client Config Hint
SERVER_IP=$(curl -s https://ifconfig.me || curl -s https://api.ipify.org || echo "<SERVER_IP>")
echo "========================================================================"
echo " FOUNDATIONAL BOOTSTRAP PROCESS SUCCESSFUL!"
echo "========================================================================"
echo " "
echo "🖥️ SSH CLIENT CONFIGURATION (LOCAL MACHINE)"
echo "Add the following block to your local '~/.ssh/config' file (Windows/Linux/macOS)"
echo "to connect seamlessly without typing the port or username every time:"
echo " "
echo "------------------------------------------------------------------------"
echo "Host ${HOSTNAME}"
echo " HostName ${SERVER_IP}"
echo " User ${NEW_USER}"
echo " Port ${SSH_PORT}"
echo "------------------------------------------------------------------------"
echo " "
echo "Then, you can simply connect from your local terminal by running:"
echo " ssh ${HOSTNAME}"
echo " "
echo "⚠️ CRITICAL POST-CHECK:"
echo "Open a separate terminal shell locally right now and verify connection using:"
echo " ssh -p ${SSH_PORT} ${NEW_USER}@${SERVER_IP}"
echo " "
echo "DO NOT terminate this active root session until new access is fully confirmed!"
echo "========================================================================"