|
1 | 1 | #!/bin/bash |
| 2 | + |
| 3 | +# Debug configuration |
| 4 | +DEBUG=${DEBUG:-0} # Default to debug off |
| 5 | +[[ $DEBUG -eq 1 ]] && set -x |
| 6 | + |
2 | 7 | # Log to both stdout and /tmp/konductor.log |
3 | 8 | exec > >(tee -a /tmp/konductor.log) 2>&1 |
4 | 9 |
|
| 10 | +################################################################################# |
| 11 | +# Preliminary User Setup |
| 12 | +################################################################################# |
| 13 | +# If running as root, set USER to "ubuntu"; otherwise, default to the current user. |
| 14 | +if [ "$(whoami)" = "root" ]; then |
| 15 | + USER="ubuntu" |
| 16 | +else |
| 17 | + USER="${USER:-$(whoami)}" |
| 18 | +fi |
| 19 | + |
| 20 | +# Determine the user's home directory (using getent when available) |
| 21 | +USER_HOME=$(getent passwd "${USER}" | cut -d: -f6) |
| 22 | +if [ -z "${USER_HOME}" ]; then |
| 23 | + USER_HOME="/home/${USER}" |
| 24 | +fi |
| 25 | + |
5 | 26 | ################################################################################# |
6 | 27 | # Configuration |
7 | 28 | ################################################################################# |
8 | 29 | readonly DIR_PLATFORM=".platform" |
9 | | -readonly USER_HOME="/home/${USER:-ubuntu}" |
10 | 30 | readonly SSH_HOST_IDENTITY_PATH="${USER_HOME}/${DIR_PLATFORM}/secrets/ssh/host" |
11 | 31 | readonly SSH_USER_IDENTITY_PATH="${USER_HOME}/${DIR_PLATFORM}/secrets/ssh/user" |
12 | 32 | readonly ENV_FILE="${USER_HOME}/.env" |
13 | 33 | readonly SSH_KEY_TYPES=("ecdsa" "rsa" "ed25519") |
14 | | -readonly TMUX_CHECK_INTERVAL=5 |
| 34 | +readonly CHECK_INTERVAL=15 |
15 | 35 |
|
16 | 36 | ################################################################################# |
17 | 37 | # Helper Functions |
18 | 38 | ################################################################################# |
19 | 39 |
|
20 | 40 | log() { |
21 | | - echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" |
| 41 | + echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" |
| 42 | +} |
| 43 | + |
| 44 | +debug() { |
| 45 | + [[ $DEBUG -eq 1 ]] && log "DEBUG: $1" |
22 | 46 | } |
23 | 47 |
|
24 | | -# Instead of exiting, log errors and continue. |
25 | 48 | error() { |
26 | | - log "ERROR: $1" |
| 49 | + log "ERROR: $1" |
27 | 50 | } |
28 | 51 |
|
29 | 52 | setup_user() { |
30 | | - # Define USER from various sources in priority order |
31 | | - export USER="${USER:-$(whoami)}" |
32 | | - if [ "$USER" = "root" ]; then |
33 | | - export USER="ubuntu" |
34 | | - fi |
35 | | - |
36 | | - # Validate user setup |
37 | | - if [ -z "${USER}" ]; then |
38 | | - error "USER environment variable not set" |
39 | | - fi |
40 | | - |
41 | | - log "Running as user: $USER (current: $(whoami))" |
| 53 | + # We already set USER and USER_HOME above. Now verify the user exists. |
| 54 | + if [ -z "${USER}" ] || ! id "${USER}" >/dev/null 2>&1; then |
| 55 | + error "User ${USER} not found" |
| 56 | + return 1 |
| 57 | + fi |
| 58 | + |
| 59 | + log "Running as user: ${USER} (current: $(whoami))" |
| 60 | + |
| 61 | + # Ensure tmux directory exists with correct permissions |
| 62 | + local tmux_dir="/tmp/tmux-$(id -u "${USER}")" |
| 63 | + mkdir -p "${tmux_dir}" |
| 64 | + chmod 700 "${tmux_dir}" |
| 65 | + chown "${USER}:${USER}" "${tmux_dir}" |
42 | 66 | } |
43 | 67 |
|
44 | 68 | save_environment() { |
45 | | - log "Saving environment variables to ${ENV_FILE}" |
46 | | - env | grep -Ev '^(_=|PWD=|SHLVL=|SHELL=)' > "${ENV_FILE}" || true |
47 | | - chmod 600 "${ENV_FILE}" || true |
| 69 | + log "Saving environment variables to ${ENV_FILE}" |
| 70 | + mkdir -p "$(dirname "${ENV_FILE}")" |
| 71 | + # Filter out session-specific and potentially sensitive variables |
| 72 | + env | grep -Ev '^(_=|PWD=|SHLVL=|SHELL=|HOME=|SSH_|AWS_|GITHUB_TOKEN)' >"${ENV_FILE}" |
| 73 | + chmod 600 "${ENV_FILE}" |
| 74 | + chown "${USER}:${USER}" "${ENV_FILE}" 2>/dev/null || true |
48 | 75 | } |
49 | 76 |
|
50 | 77 | ################################################################################# |
51 | | -# SSH Setup Functions |
| 78 | +# SSH Functions |
52 | 79 | ################################################################################# |
53 | 80 |
|
54 | 81 | create_ssh_directories() { |
55 | | - log "Creating SSH directories" |
56 | | - mkdir -p "${SSH_HOST_IDENTITY_PATH}" "${SSH_USER_IDENTITY_PATH}" /var/run/sshd || true |
57 | | - sudo chmod -R 0700 "${SSH_HOST_IDENTITY_PATH}" "${SSH_USER_IDENTITY_PATH}" || true |
| 82 | + for dir in "${SSH_HOST_IDENTITY_PATH}" "${SSH_USER_IDENTITY_PATH}" "/var/run/sshd"; do |
| 83 | + mkdir -p "${dir}" |
| 84 | + chmod 0700 "${dir}" 2>/dev/null || true |
| 85 | + done |
58 | 86 | } |
59 | 87 |
|
60 | 88 | generate_ssh_host_key() { |
61 | | - local key_type="$1" |
62 | | - local key_file="${SSH_HOST_IDENTITY_PATH}/ssh_host_${key_type}_key" |
63 | | - log "Generating SSH host key for ${key_type}" |
64 | | - sudo ssh-keygen -q -t "$key_type" -f "$key_file" -C '' -N '' || \ |
65 | | - log "Warning: Failed to generate ${key_type} key" |
| 89 | + local key_type="$1" |
| 90 | + local key_file="${SSH_HOST_IDENTITY_PATH}/ssh_host_${key_type}_key" |
| 91 | + |
| 92 | + if [ ! -f "${key_file}" ]; then |
| 93 | + sudo ssh-keygen -q -t "$key_type" -f "$key_file" -C '' -N '' || true |
| 94 | + fi |
66 | 95 | } |
67 | 96 |
|
68 | 97 | setup_host_ssh_identity() { |
69 | | - log "Setting up SSH host identity" |
70 | | - for key_type in "${SSH_KEY_TYPES[@]}"; do |
71 | | - local key_file="${SSH_HOST_IDENTITY_PATH}/ssh_host_${key_type}_key" |
72 | | - if ! sudo test -f "$key_file"; then |
73 | | - generate_ssh_host_key "$key_type" |
74 | | - fi |
75 | | - done |
76 | | - |
77 | | - # Set permissions on the SSH host identity directory |
78 | | - sudo chmod -R 0600 "${SSH_HOST_IDENTITY_PATH}" || true |
79 | | - sudo chown -R root:root "${SSH_HOST_IDENTITY_PATH}" || true |
80 | | - |
81 | | - # Only copy keys if they exist |
82 | | - if ls "${SSH_HOST_IDENTITY_PATH}"/* 1>/dev/null 2>&1; then |
83 | | - sudo cp -rf "${SSH_HOST_IDENTITY_PATH}"/* /etc/ssh/ || \ |
84 | | - log "Warning: Failed to copy SSH host keys to /etc/ssh/" |
85 | | - else |
86 | | - log "Warning: No SSH host keys found in ${SSH_HOST_IDENTITY_PATH} to copy to /etc/ssh/" |
87 | | - fi |
| 98 | + mkdir -p "${SSH_HOST_IDENTITY_PATH}" |
| 99 | + |
| 100 | + for key_type in "${SSH_KEY_TYPES[@]}"; do |
| 101 | + generate_ssh_host_key "$key_type" |
| 102 | + done |
| 103 | + |
| 104 | + if [ -d "${SSH_HOST_IDENTITY_PATH}" ] && [ "$(ls -A "${SSH_HOST_IDENTITY_PATH}" 2>/dev/null)" ]; then |
| 105 | + sudo cp -rf "${SSH_HOST_IDENTITY_PATH}"/* /etc/ssh/ |
| 106 | + sudo chmod 600 /etc/ssh/ssh_host_*_key |
| 107 | + sudo chmod 644 /etc/ssh/ssh_host_*_key.pub |
| 108 | + fi |
88 | 109 | } |
89 | 110 |
|
90 | 111 | setup_user_ssh() { |
91 | | - local ssh_dir="${USER_HOME}/.ssh" |
92 | | - local ssh_key_file="${ssh_dir}/id_rsa" |
93 | | - |
94 | | - log "Setting up user SSH configuration" |
95 | | - mkdir -p "${ssh_dir}" || true |
96 | | - chmod 700 "${ssh_dir}" || true |
97 | | - |
98 | | - # Generate user SSH key if needed |
99 | | - if [ ! -f "${ssh_key_file}" ]; then |
100 | | - log "Generating new SSH key for user ${USER}" |
101 | | - sudo -u "${USER}" ssh-keygen -t rsa -b 4096 -f "${ssh_key_file}" -q -N "" || \ |
102 | | - log "Warning: Failed to generate user SSH key" |
103 | | - fi |
104 | | - |
105 | | - chmod 600 "${ssh_key_file}" || true |
106 | | - chmod 644 "${ssh_key_file}.pub" || true |
107 | | - |
108 | | - # Setup GitHub keys if configured |
109 | | - if [ -n "${GITHUB_USER:-}" ]; then |
110 | | - log "Fetching SSH keys for GitHub user ${GITHUB_USER}" |
111 | | - if curl -sL "https://github.com/${GITHUB_USER}.keys" > "${ssh_dir}/authorized_keys"; then |
112 | | - chmod 600 "${ssh_dir}/authorized_keys" || true |
113 | | - else |
114 | | - log "Warning: Failed to fetch GitHub keys for ${GITHUB_USER}" |
115 | | - fi |
116 | | - fi |
| 112 | + local ssh_dir="${USER_HOME}/.ssh" |
| 113 | + local ssh_key_file="${ssh_dir}/id_rsa" |
| 114 | + |
| 115 | + mkdir -p "${ssh_dir}" |
| 116 | + chmod 700 "${ssh_dir}" |
| 117 | + chown "${USER}:${USER}" "${ssh_dir}" 2>/dev/null || true |
| 118 | + |
| 119 | + if [ ! -f "${ssh_key_file}" ]; then |
| 120 | + sudo -u "${USER}" ssh-keygen -t rsa -b 4096 -f "${ssh_key_file}" -q -N "" |
| 121 | + chmod 600 "${ssh_key_file}" |
| 122 | + chmod 644 "${ssh_key_file}.pub" |
| 123 | + chown "${USER}:${USER}" "${ssh_key_file}"* 2>/dev/null || true |
| 124 | + fi |
| 125 | + |
| 126 | + if [ -n "${GITHUB_USER:-}" ]; then |
| 127 | + local keys_fetched=false |
| 128 | + for i in {1..3}; do |
| 129 | + if curl -sL --connect-timeout 5 "https://github.com/${GITHUB_USER}.keys" >"${ssh_dir}/authorized_keys"; then |
| 130 | + keys_fetched=true |
| 131 | + break |
| 132 | + fi |
| 133 | + sleep 2 |
| 134 | + done |
| 135 | + if ! $keys_fetched; then |
| 136 | + error "Failed to fetch GitHub keys for ${GITHUB_USER} after 3 attempts" |
| 137 | + fi |
| 138 | + chmod 600 "${ssh_dir}/authorized_keys" |
| 139 | + chown "${USER}:${USER}" "${ssh_dir}/authorized_keys" 2>/dev/null || true |
| 140 | + fi |
117 | 141 | } |
118 | 142 |
|
119 | 143 | ################################################################################# |
120 | | -# Service Management Functions |
| 144 | +# Service Functions |
121 | 145 | ################################################################################# |
122 | 146 |
|
123 | 147 | start_sshd() { |
124 | | - log "Starting SSH daemon" |
125 | | - create_ssh_directories |
126 | | - setup_host_ssh_identity |
127 | | - sudo /usr/sbin/sshd -e -f /etc/ssh/sshd_config || log "Warning: SSHD failed to start" |
| 148 | + create_ssh_directories |
| 149 | + setup_host_ssh_identity |
| 150 | + sudo /usr/sbin/sshd -e -f /etc/ssh/sshd_config || true |
128 | 151 | } |
129 | 152 |
|
130 | 153 | manage_tmux_session() { |
131 | | - local session_name="$1" |
132 | | - |
133 | | - while true; do |
134 | | - if ! tmux has-session -t "$session_name" 2>/dev/null; then |
135 | | - log "Creating new tmux session: $session_name" |
136 | | - tmux new-session -d -s "$session_name" || log "Warning: Failed to create tmux session" |
137 | | - sleep 1 || true |
138 | | - tmux send-keys -t "$session_name" "source ${ENV_FILE}" C-m || \ |
139 | | - log "Warning: Failed to send environment to tmux session" |
140 | | - fi |
141 | | - sleep "${TMUX_CHECK_INTERVAL}" || true |
142 | | - done |
| 154 | + local session_name="${1:-konductor}" |
| 155 | + |
| 156 | + create_tmux_session() { |
| 157 | + log "Creating new tmux session: ${session_name}" |
| 158 | + tmux new-session -d -s "${session_name}" || true |
| 159 | + log "Created tmux session: ${session_name}" |
| 160 | + } |
| 161 | + |
| 162 | + # Ensure the session exists at startup. |
| 163 | + if ! tmux has-session -t "${session_name}" 2>/dev/null; then |
| 164 | + create_tmux_session |
| 165 | + fi |
| 166 | + |
| 167 | + # Loop forever, re‑creating the session if it goes away. |
| 168 | + while :; do |
| 169 | + if ! tmux has-session -t "${session_name}" 2>/dev/null; then |
| 170 | + log "Session ${session_name} is no longer active, recreating." |
| 171 | + create_tmux_session |
| 172 | + else |
| 173 | + debug "Session ${session_name} is still active." |
| 174 | + fi |
| 175 | + sleep "${CHECK_INTERVAL}" || true |
| 176 | + done |
143 | 177 | } |
144 | 178 |
|
145 | 179 | start_ttyd() { |
146 | | - log "Starting TTYD service" |
147 | | - while true; do |
148 | | - if ! pgrep ttyd > /dev/null; then |
149 | | - ( ttyd --writable -t fontFamily="'monospace'" connect 2>/dev/null || \ |
150 | | - log "Warning: Failed to start ttyd" ) & |
151 | | - fi |
152 | | - sleep "${TMUX_CHECK_INTERVAL}" || true |
153 | | - done |
| 180 | + if command -v ttyd >/dev/null 2>&1; then |
| 181 | + while :; do |
| 182 | + if ! pgrep ttyd >/dev/null; then |
| 183 | + ttyd --writable -t fontFamily=monospace connect 2>/dev/null & |
| 184 | + fi |
| 185 | + sleep "${CHECK_INTERVAL}" || true |
| 186 | + done |
| 187 | + fi |
| 188 | +} |
| 189 | + |
| 190 | +cleanup() { |
| 191 | + pkill -P $$ 2>/dev/null || true |
| 192 | + pkill ttyd 2>/dev/null || true |
154 | 193 | } |
155 | 194 |
|
156 | 195 | ################################################################################# |
157 | | -# Main Execution |
| 196 | +# Main |
158 | 197 | ################################################################################# |
159 | 198 |
|
160 | 199 | main() { |
161 | | - # Basic setup |
162 | | - setup_user |
163 | | - save_environment |
164 | | - |
165 | | - # Start SSH and user SSH configuration |
166 | | - start_sshd |
167 | | - setup_user_ssh |
168 | | - |
169 | | - # Launch background services |
170 | | - start_ttyd & |
171 | | - manage_tmux_session "konductor" > /dev/null 2>&1 & |
172 | | - |
173 | | - log "Container initialization complete" |
174 | | - # Keep the container running indefinitely |
175 | | - exec sleep infinity |
| 200 | + trap cleanup EXIT INT TERM |
| 201 | + |
| 202 | + # Core Initialization |
| 203 | + setup_user || true |
| 204 | + save_environment || true |
| 205 | + start_sshd || true |
| 206 | + setup_user_ssh || true |
| 207 | + |
| 208 | + # Start background services. |
| 209 | + start_ttyd & |
| 210 | + manage_tmux_session "konductor" & |
| 211 | + |
| 212 | + log "Container initialization complete." |
| 213 | + |
| 214 | + sleep infinity |
176 | 215 | } |
177 | 216 |
|
178 | 217 | main "$@" |
0 commit comments