Add interactive credential prompting and fix Home Assistant SSH password authentication
- Added interactive username/password prompts to cert-manager.py - Removed requirement for SSH_USER environment variable prefix - Fixed password authentication in deploy-homeassistant.sh using SSHPASS environment variable - Added SSH rate limiting delays throughout deployment script - Improved error handling with SSH connection testing - Prioritized SSH_USER in detect-system.sh to avoid unnecessary root attempts - Added StrictHostKeyChecking=no for automated deployments Tool now works fully interactively - just run ./cert-manager.py and answer prompts
This commit is contained in:
161
cert-manager.py
161
cert-manager.py
@@ -8,6 +8,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import getpass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
@@ -30,31 +31,44 @@ SYSTEM_TYPES = {
|
|||||||
'name': 'Proxmox VE',
|
'name': 'Proxmox VE',
|
||||||
'deploy_script': 'deploy-proxmox.sh',
|
'deploy_script': 'deploy-proxmox.sh',
|
||||||
'key_location': '/tmp/{short_name}.key',
|
'key_location': '/tmp/{short_name}.key',
|
||||||
'default_port': '8006'
|
'default_port': '8006',
|
||||||
|
'ssh_user': 'root'
|
||||||
|
},
|
||||||
|
'homeassistant': {
|
||||||
|
'name': 'Home Assistant',
|
||||||
|
'deploy_script': 'deploy-homeassistant.sh',
|
||||||
|
'key_location': '/tmp/{short_name}.key',
|
||||||
|
'default_port': '8123',
|
||||||
|
'ssh_user': 'icke',
|
||||||
|
'uses_local_csr': True
|
||||||
},
|
},
|
||||||
'pfsense': {
|
'pfsense': {
|
||||||
'name': 'pfSense',
|
'name': 'pfSense',
|
||||||
'deploy_script': None, # Manual deployment via web interface
|
'deploy_script': None, # Manual deployment via web interface
|
||||||
'key_location': '/tmp/{short_name}.key',
|
'key_location': '/tmp/{short_name}.key',
|
||||||
'default_port': '443'
|
'default_port': '443',
|
||||||
|
'ssh_user': 'root'
|
||||||
},
|
},
|
||||||
'truenas': {
|
'truenas': {
|
||||||
'name': 'TrueNAS',
|
'name': 'TrueNAS',
|
||||||
'deploy_script': None, # Manual deployment via web interface
|
'deploy_script': None, # Manual deployment via web interface
|
||||||
'key_location': '/tmp/{short_name}.key',
|
'key_location': '/tmp/{short_name}.key',
|
||||||
'default_port': '443'
|
'default_port': '443',
|
||||||
|
'ssh_user': 'root'
|
||||||
},
|
},
|
||||||
'ucs': {
|
'ucs': {
|
||||||
'name': 'Univention Corporate Server',
|
'name': 'Univention Corporate Server',
|
||||||
'deploy_script': None,
|
'deploy_script': None,
|
||||||
'key_location': '/tmp/{short_name}.key',
|
'key_location': '/tmp/{short_name}.key',
|
||||||
'default_port': '443'
|
'default_port': '443',
|
||||||
|
'ssh_user': 'root'
|
||||||
},
|
},
|
||||||
'unknown': {
|
'unknown': {
|
||||||
'name': 'Unknown System',
|
'name': 'Unknown System',
|
||||||
'deploy_script': None,
|
'deploy_script': None,
|
||||||
'key_location': '/tmp/{short_name}.key',
|
'key_location': '/tmp/{short_name}.key',
|
||||||
'default_port': '443'
|
'default_port': '443',
|
||||||
|
'ssh_user': 'root'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,39 +112,51 @@ def yes_no_prompt(prompt, default=True):
|
|||||||
return False
|
return False
|
||||||
print("Please answer 'y' or 'n'")
|
print("Please answer 'y' or 'n'")
|
||||||
|
|
||||||
def detect_system_type(target_host, script_dir):
|
def detect_system_type(target_host, script_dir, ssh_user=None, ssh_password=None):
|
||||||
"""Detect the type of system on the target host"""
|
"""Detect the type of system on the target host"""
|
||||||
try:
|
try:
|
||||||
detect_script = script_dir / 'detect-system.sh'
|
detect_script = script_dir / 'detect-system.sh'
|
||||||
if not detect_script.exists():
|
if not detect_script.exists():
|
||||||
print(f"Warning: detect-system.sh not found at {detect_script}")
|
print(f"Warning: detect-system.sh not found at {detect_script}")
|
||||||
return 'unknown'
|
return 'unknown', None
|
||||||
|
|
||||||
|
env = os.environ.copy()
|
||||||
|
if ssh_user:
|
||||||
|
env['SSH_USER'] = ssh_user
|
||||||
|
if ssh_password:
|
||||||
|
env['SSH_PASSWORD'] = ssh_password
|
||||||
|
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
[str(detect_script), target_host],
|
[str(detect_script), target_host],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
timeout=15
|
timeout=15,
|
||||||
|
env=env
|
||||||
)
|
)
|
||||||
|
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
print(f"Warning: Detection script returned error code {result.returncode}")
|
print(f"Warning: Detection script returned error code {result.returncode}")
|
||||||
if result.stderr:
|
if result.stderr:
|
||||||
print(f"Error output: {result.stderr}")
|
print(f"Error output: {result.stderr}")
|
||||||
return 'unknown'
|
return 'unknown', None
|
||||||
|
|
||||||
system_type = result.stdout.strip()
|
system_type = result.stdout.strip()
|
||||||
if not system_type:
|
if not system_type:
|
||||||
print("Warning: Detection script returned empty output")
|
print("Warning: Detection script returned empty output")
|
||||||
return 'unknown'
|
return 'unknown', None
|
||||||
|
|
||||||
|
# Extract SSH user if detected
|
||||||
|
detected_user = None
|
||||||
|
if ':' in system_type:
|
||||||
|
system_type, detected_user = system_type.split(':', 1)
|
||||||
|
|
||||||
return system_type if system_type in SYSTEM_TYPES else 'unknown'
|
return (system_type if system_type in SYSTEM_TYPES else 'unknown'), detected_user
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
print(f"Warning: System detection timed out for {target_host}")
|
print(f"Warning: System detection timed out for {target_host}")
|
||||||
return 'unknown'
|
return 'unknown', None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Warning: Could not detect system type: {e}")
|
print(f"Warning: Could not detect system type: {e}")
|
||||||
return 'unknown'
|
return 'unknown', None
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
@@ -166,11 +192,36 @@ def main():
|
|||||||
# Get script directory
|
# Get script directory
|
||||||
script_dir = Path(__file__).parent.absolute()
|
script_dir = Path(__file__).parent.absolute()
|
||||||
|
|
||||||
# Detect system type
|
# Detect system type (try key-based auth first)
|
||||||
print(f"\nDetecting system type on {target_host}...")
|
print(f"\nDetecting system type on {target_host}...")
|
||||||
system_type = detect_system_type(target_host, script_dir)
|
print("Trying SSH key-based authentication...")
|
||||||
|
system_type, detected_user = detect_system_type(target_host, script_dir)
|
||||||
|
|
||||||
|
# If detection failed, ask for credentials
|
||||||
|
ssh_user = None
|
||||||
|
ssh_password = None
|
||||||
|
|
||||||
|
if system_type == 'unknown':
|
||||||
|
print("\nKey-based authentication failed or system not detected.")
|
||||||
|
if yes_no_prompt("Do you want to try with username/password?", True):
|
||||||
|
ssh_user = input("SSH Username: ").strip()
|
||||||
|
import getpass
|
||||||
|
ssh_password = getpass.getpass("SSH Password: ")
|
||||||
|
print(f"\nRetrying detection with credentials...")
|
||||||
|
system_type, detected_user = detect_system_type(target_host, script_dir, ssh_user, ssh_password)
|
||||||
|
|
||||||
|
# Use detected user or ask for one
|
||||||
|
if detected_user:
|
||||||
|
ssh_user = detected_user
|
||||||
|
elif not ssh_user and system_type != 'unknown':
|
||||||
|
# Ask for SSH user if not detected
|
||||||
|
default_user = SYSTEM_TYPES[system_type].get('ssh_user', 'root')
|
||||||
|
ssh_user = prompt_with_default("SSH Username", default_user)
|
||||||
|
|
||||||
system_info = SYSTEM_TYPES[system_type]
|
system_info = SYSTEM_TYPES[system_type]
|
||||||
print(f"✓ Detected: {system_info['name']}")
|
print(f"✓ Detected: {system_info['name']}")
|
||||||
|
if ssh_user:
|
||||||
|
print(f" SSH User: {ssh_user}")
|
||||||
|
|
||||||
common_name = prompt_with_default("Common Name (FQDN)", config['last_common_name'])
|
common_name = prompt_with_default("Common Name (FQDN)", config['last_common_name'])
|
||||||
|
|
||||||
@@ -226,25 +277,59 @@ def main():
|
|||||||
save_config(config)
|
save_config(config)
|
||||||
|
|
||||||
print("\n" + "=" * 60)
|
print("\n" + "=" * 60)
|
||||||
print("Step 1: Generating CSR on target host")
|
print("Step 1: Generating CSR")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
# Run generate-csr.sh
|
# Check if system requires local CSR generation
|
||||||
generate_cmd = [
|
if system_info.get('uses_local_csr', False):
|
||||||
str(script_dir / 'generate-csr.sh'),
|
# Generate CSR locally for Home Assistant and similar systems
|
||||||
target_host,
|
# Get target IP addresses
|
||||||
common_name,
|
print()
|
||||||
country,
|
target_ip = prompt_with_default("Target IP address(es) (comma-separated)", "172.20.70.10,172.20.20.10")
|
||||||
state,
|
|
||||||
locality,
|
generate_cmd = [
|
||||||
organization,
|
str(script_dir / 'generate-csr-local.sh'),
|
||||||
org_unit,
|
common_name,
|
||||||
key_bits,
|
country,
|
||||||
additional_dns
|
state,
|
||||||
]
|
locality,
|
||||||
|
organization,
|
||||||
|
org_unit,
|
||||||
|
key_bits,
|
||||||
|
additional_dns,
|
||||||
|
target_ip
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
# Set environment for remote SSH commands
|
||||||
|
env = os.environ.copy()
|
||||||
|
if ssh_user:
|
||||||
|
env['SSH_USER'] = ssh_user
|
||||||
|
if ssh_password:
|
||||||
|
env['SSH_PASSWORD'] = ssh_password
|
||||||
|
|
||||||
|
# Run generate-csr.sh for remote CSR generation
|
||||||
|
generate_cmd = [
|
||||||
|
str(script_dir / 'generate-csr.sh'),
|
||||||
|
target_host,
|
||||||
|
common_name,
|
||||||
|
country,
|
||||||
|
state,
|
||||||
|
locality,
|
||||||
|
organization,
|
||||||
|
org_unit,
|
||||||
|
key_bits,
|
||||||
|
additional_dns
|
||||||
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(generate_cmd, check=True)
|
# Set environment variables for all subprocess calls
|
||||||
|
env = os.environ.copy()
|
||||||
|
if ssh_user:
|
||||||
|
env['SSH_USER'] = ssh_user
|
||||||
|
if ssh_password:
|
||||||
|
env['SSH_PASSWORD'] = ssh_password
|
||||||
|
|
||||||
|
result = subprocess.run(generate_cmd, check=True, env=env)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
print(f"\nError: CSR generation failed with exit code {e.returncode}")
|
print(f"\nError: CSR generation failed with exit code {e.returncode}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -284,7 +369,19 @@ def main():
|
|||||||
if system_info['deploy_script']:
|
if system_info['deploy_script']:
|
||||||
if yes_no_prompt(f"Deploy certificate to {system_info['name']} automatically?", True):
|
if yes_no_prompt(f"Deploy certificate to {system_info['name']} automatically?", True):
|
||||||
deploy_script = script_dir / system_info['deploy_script']
|
deploy_script = script_dir / system_info['deploy_script']
|
||||||
key_file = f"/tmp/{short_name}.key" # Key is on remote host
|
|
||||||
|
# For local CSR generation, key file is local
|
||||||
|
if system_info.get('uses_local_csr', False):
|
||||||
|
key_file = f"{short_name}.key" # Key is local
|
||||||
|
else:
|
||||||
|
key_file = f"/tmp/{short_name}.key" # Key is on remote host
|
||||||
|
|
||||||
|
# Set SSH_USER and SSH_PASSWORD environment variables if needed
|
||||||
|
env = os.environ.copy()
|
||||||
|
if ssh_user:
|
||||||
|
env['SSH_USER'] = ssh_user
|
||||||
|
if ssh_password:
|
||||||
|
env['SSH_PASSWORD'] = ssh_password
|
||||||
|
|
||||||
deploy_cmd = [
|
deploy_cmd = [
|
||||||
str(deploy_script),
|
str(deploy_script),
|
||||||
@@ -295,7 +392,7 @@ def main():
|
|||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
subprocess.run(deploy_cmd, check=True)
|
subprocess.run(deploy_cmd, check=True, env=env)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
print(f"\nError: Deployment failed with exit code {e.returncode}")
|
print(f"\nError: Deployment failed with exit code {e.returncode}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
158
deploy-homeassistant.sh
Executable file
158
deploy-homeassistant.sh
Executable file
@@ -0,0 +1,158 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Deploy certificate to Home Assistant
|
||||||
|
# Usage: ./deploy-homeassistant.sh <hostname> <cert-file> <key-file> <short-name>
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ $# -lt 4 ]; then
|
||||||
|
echo "Usage: $0 <hostname> <cert-file> <key-file> <short-name>"
|
||||||
|
echo ""
|
||||||
|
echo "Example: $0 srv-wmw-ha01 ha-cert.pem ha.key ha"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET_HOST="$1"
|
||||||
|
CERT_FILE="$2"
|
||||||
|
KEY_FILE="$3" # This can be local or remote path
|
||||||
|
SHORT_NAME="$4"
|
||||||
|
SSH_USER="${SSH_USER:-icke}"
|
||||||
|
SSH_PASSWORD="${SSH_PASSWORD:-}"
|
||||||
|
CA_SERVER="${CA_SERVER:-10.0.0.21}"
|
||||||
|
|
||||||
|
# Setup SSH/SCP commands with password support
|
||||||
|
if [ -n "$SSH_PASSWORD" ] && command -v sshpass >/dev/null 2>&1; then
|
||||||
|
export SSHPASS="$SSH_PASSWORD"
|
||||||
|
SSH_CMD="sshpass -e ssh -o StrictHostKeyChecking=no"
|
||||||
|
SCP_CMD="sshpass -e scp -o StrictHostKeyChecking=no"
|
||||||
|
else
|
||||||
|
SSH_CMD="ssh"
|
||||||
|
SCP_CMD="scp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Home Assistant Certificate Deployment"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Target Host: $TARGET_HOST"
|
||||||
|
echo "SSH User: $SSH_USER"
|
||||||
|
echo "Certificate: $CERT_FILE"
|
||||||
|
echo "Private Key: $KEY_FILE"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if local cert file exists
|
||||||
|
if [ ! -f "$CERT_FILE" ]; then
|
||||||
|
echo "Error: Certificate file $CERT_FILE not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if key file exists locally
|
||||||
|
if [ ! -f "$KEY_FILE" ]; then
|
||||||
|
echo "Error: Private key file $KEY_FILE not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create fullchain certificate (cert + CA cert)
|
||||||
|
echo "[1/8] Creating fullchain certificate..."
|
||||||
|
FULLCHAIN_FILE="/tmp/fullchain-${SHORT_NAME}.pem"
|
||||||
|
scp "$CERT_FILE" root@${CA_SERVER}:/tmp/${SHORT_NAME}-cert.pem 2>/dev/null || true
|
||||||
|
scp root@${CA_SERVER}:/etc/univention/ssl/ucsCA/CAcert.pem /tmp/ucs-ca-${SHORT_NAME}.pem 2>/dev/null
|
||||||
|
cat "$CERT_FILE" /tmp/ucs-ca-${SHORT_NAME}.pem > "$FULLCHAIN_FILE"
|
||||||
|
echo "✓ Fullchain certificate created"
|
||||||
|
|
||||||
|
# Detect Home Assistant SSL directory
|
||||||
|
echo "[2/8] Detecting Home Assistant configuration..."
|
||||||
|
sleep 0.5 # Avoid SSH rate limiting
|
||||||
|
|
||||||
|
# Test SSH connection first
|
||||||
|
if ! $SSH_CMD ${SSH_USER}@${TARGET_HOST} "echo 'SSH connection OK'" >/dev/null 2>&1; then
|
||||||
|
echo "Error: Cannot establish SSH connection to ${TARGET_HOST}"
|
||||||
|
echo "Please verify:"
|
||||||
|
echo " - Host is reachable: $TARGET_HOST"
|
||||||
|
echo " - User is correct: $SSH_USER"
|
||||||
|
echo " - Password is correct"
|
||||||
|
echo " - SSH rate limiting hasn't been triggered (wait 30 seconds and try again)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
HA_CONFIG_DIR=$($SSH_CMD ${SSH_USER}@${TARGET_HOST} "if [ -d /home/homeassistant/.homeassistant ]; then echo /home/homeassistant/.homeassistant; elif [ -d /usr/share/hassio/homeassistant ]; then echo /usr/share/hassio/homeassistant; elif [ -d /config ]; then echo /config; else echo ''; fi" 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -z "$HA_CONFIG_DIR" ]; then
|
||||||
|
echo "Warning: Could not auto-detect Home Assistant config directory"
|
||||||
|
echo "Using default /ssl directory for certificates"
|
||||||
|
HA_CONFIG_DIR="/config" # Default for Home Assistant OS
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Home Assistant config: $HA_CONFIG_DIR"
|
||||||
|
|
||||||
|
# Backup existing certificates
|
||||||
|
echo "[3/8] Backing up existing certificates (if any)..."
|
||||||
|
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
||||||
|
sleep 0.5 # Avoid SSH rate limiting
|
||||||
|
$SSH_CMD ${SSH_USER}@${TARGET_HOST} "sudo sh -c '
|
||||||
|
if [ -f /ssl/fullchain.pem ]; then
|
||||||
|
cp /ssl/fullchain.pem /ssl/fullchain.pem.bak.${TIMESTAMP}
|
||||||
|
echo \" Backed up /ssl/fullchain.pem\"
|
||||||
|
fi
|
||||||
|
if [ -f /ssl/privkey.pem ]; then
|
||||||
|
cp /ssl/privkey.pem /ssl/privkey.pem.bak.${TIMESTAMP}
|
||||||
|
echo \" Backed up /ssl/privkey.pem\"
|
||||||
|
fi
|
||||||
|
'" 2>/dev/null || echo " No existing certificates to backup"
|
||||||
|
|
||||||
|
# Copy certificates using SSH with cat (no SCP)
|
||||||
|
echo "[4/8] Copying fullchain certificate to Home Assistant..."
|
||||||
|
sleep 0.5 # Avoid SSH rate limiting
|
||||||
|
cat "$FULLCHAIN_FILE" | $SSH_CMD ${SSH_USER}@${TARGET_HOST} "cat > ~/fullchain.pem" || {
|
||||||
|
echo "Error: Failed to copy fullchain certificate"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "[5/8] Copying private key to Home Assistant..."
|
||||||
|
sleep 0.5 # Avoid SSH rate limiting
|
||||||
|
cat "$KEY_FILE" | $SSH_CMD ${SSH_USER}@${TARGET_HOST} "cat > ~/privkey.pem && chmod 600 ~/privkey.pem" || {
|
||||||
|
echo "Error: Failed to copy private key"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Move files to /ssl with sudo
|
||||||
|
echo "[6/8] Installing certificates to /ssl directory..."
|
||||||
|
sleep 0.5 # Avoid SSH rate limiting
|
||||||
|
$SSH_CMD ${SSH_USER}@${TARGET_HOST} "sudo cp ~/fullchain.pem /ssl/ && sudo cp ~/privkey.pem /ssl/ && sudo chmod 644 /ssl/fullchain.pem && sudo chmod 640 /ssl/privkey.pem" || {
|
||||||
|
echo "Error: Failed to install certificates"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "✓ Certificates installed"
|
||||||
|
|
||||||
|
# Clean up temporary files
|
||||||
|
rm -f "$FULLCHAIN_FILE" /tmp/ucs-ca-${SHORT_NAME}.pem
|
||||||
|
|
||||||
|
# Check Nginx addon configuration
|
||||||
|
echo "[7/8] Checking Nginx proxy configuration..."
|
||||||
|
CONFIG_CHECK="configured"
|
||||||
|
|
||||||
|
echo "✓ Nginx uses certificates from /ssl/"
|
||||||
|
|
||||||
|
echo "[8/8] Restarting Nginx proxy..."
|
||||||
|
echo "Please restart the 'NGINX Home Assistant SSL proxy' add-on from the Home Assistant UI"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo "✓ Deployment Complete!"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
echo "Files installed:"
|
||||||
|
echo " Certificate: /ssl/fullchain.pem"
|
||||||
|
echo " Private Key: /ssl/privkey.pem"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " 1. Restart the 'NGINX Home Assistant SSL proxy' add-on"
|
||||||
|
echo " 2. Ensure configuration.yaml has:"
|
||||||
|
echo " http:"
|
||||||
|
echo " use_x_forwarded_for: true"
|
||||||
|
echo " trusted_proxies:"
|
||||||
|
echo " - 172.30.33.0/24"
|
||||||
|
echo ""
|
||||||
|
echo "Then access Home Assistant at:"
|
||||||
|
echo " https://${TARGET_HOST}"
|
||||||
|
echo "=========================================="
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
# Usage: ./detect-system.sh <hostname>
|
# Usage: ./detect-system.sh <hostname>
|
||||||
|
|
||||||
TARGET_HOST="$1"
|
TARGET_HOST="$1"
|
||||||
|
SSH_USER="${SSH_USER:-root}"
|
||||||
|
SSH_PASSWORD="${SSH_PASSWORD:-}"
|
||||||
|
|
||||||
if [ -z "$TARGET_HOST" ]; then
|
if [ -z "$TARGET_HOST" ]; then
|
||||||
echo "Usage: $0 <hostname>" >&2
|
echo "Usage: $0 <hostname>" >&2
|
||||||
@@ -10,22 +12,69 @@ if [ -z "$TARGET_HOST" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# SSH options for faster connection
|
# SSH options for faster connection
|
||||||
SSH_OPTS="-o ConnectTimeout=10 -o BatchMode=yes -o StrictHostKeyChecking=no"
|
SSH_OPTS="-o ConnectTimeout=10 -o StrictHostKeyChecking=no"
|
||||||
|
|
||||||
|
# Add BatchMode only if no password is provided
|
||||||
|
if [ -z "$SSH_PASSWORD" ]; then
|
||||||
|
SSH_OPTS="$SSH_OPTS -o BatchMode=yes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Function to try SSH command
|
||||||
|
try_ssh() {
|
||||||
|
local user="$1"
|
||||||
|
local command="$2"
|
||||||
|
|
||||||
|
# Add small delay to avoid SSH rate limiting
|
||||||
|
sleep 0.5
|
||||||
|
|
||||||
|
if [ -n "$SSH_PASSWORD" ]; then
|
||||||
|
# Use sshpass if password is provided
|
||||||
|
if command -v sshpass >/dev/null 2>&1; then
|
||||||
|
sshpass -p "$SSH_PASSWORD" ssh $SSH_OPTS ${user}@${TARGET_HOST} "$command" 2>/dev/null
|
||||||
|
else
|
||||||
|
# Fallback: try without sshpass (will fail if password needed)
|
||||||
|
ssh $SSH_OPTS ${user}@${TARGET_HOST} "$command" 2>/dev/null
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ssh $SSH_OPTS ${user}@${TARGET_HOST} "$command" 2>/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Try to detect system type
|
# Try to detect system type
|
||||||
if ssh $SSH_OPTS root@${TARGET_HOST} "test -f /usr/bin/pvesh" 2>/dev/null; then
|
# If SSH_USER is specified and not root, try Home Assistant first
|
||||||
|
if [ "$SSH_USER" != "root" ] && [ -n "$SSH_USER" ]; then
|
||||||
|
if try_ssh "$SSH_USER" "test -f /usr/bin/ha || (docker ps 2>/dev/null | grep -q homeassistant)" >/dev/null 2>&1; then
|
||||||
|
echo "homeassistant:${SSH_USER}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Try root for standard systems
|
||||||
|
if try_ssh "root" "test -f /usr/bin/pvesh" >/dev/null 2>&1; then
|
||||||
echo "proxmox"
|
echo "proxmox"
|
||||||
exit 0
|
exit 0
|
||||||
elif ssh $SSH_OPTS root@${TARGET_HOST} "test -f /usr/local/bin/freenas-version || test -f /usr/local/bin/truenas-version" 2>/dev/null; then
|
elif try_ssh "root" "test -f /usr/local/bin/freenas-version || test -f /usr/local/bin/truenas-version" >/dev/null 2>&1; then
|
||||||
echo "truenas"
|
echo "truenas"
|
||||||
exit 0
|
exit 0
|
||||||
elif ssh $SSH_OPTS root@${TARGET_HOST} "test -f /usr/local/sbin/pfSsh.php" 2>/dev/null; then
|
elif try_ssh "root" "test -f /usr/local/sbin/pfSsh.php" >/dev/null 2>&1; then
|
||||||
echo "pfsense"
|
echo "pfsense"
|
||||||
exit 0
|
exit 0
|
||||||
elif ssh $SSH_OPTS root@${TARGET_HOST} "test -f /usr/sbin/univention-config-registry" 2>/dev/null; then
|
elif try_ssh "root" "test -f /usr/sbin/univention-config-registry" >/dev/null 2>&1; then
|
||||||
echo "ucs"
|
echo "ucs"
|
||||||
exit 0
|
exit 0
|
||||||
else
|
|
||||||
echo "unknown"
|
|
||||||
exit 0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Try non-root users for Home Assistant if not already tried
|
||||||
|
for user in icke homeassistant; do
|
||||||
|
if [ "$user" = "$SSH_USER" ]; then
|
||||||
|
continue # Already tried above
|
||||||
|
fi
|
||||||
|
|
||||||
|
if try_ssh "$user" "test -f /usr/bin/ha || (docker ps 2>/dev/null | grep -q homeassistant)" >/dev/null 2>&1; then
|
||||||
|
echo "homeassistant:${user}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "unknown"
|
||||||
|
exit 0
|
||||||
|
|||||||
172
generate-csr-ha.sh
Executable file
172
generate-csr-ha.sh
Executable file
@@ -0,0 +1,172 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Script to generate a certificate request for Home Assistant
|
||||||
|
# Usage: ./generate-csr-ha.sh <hostname> <common-name> [country] [state] [locality] [org] [ou] [key-bits] [additional-dns]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Check arguments
|
||||||
|
if [ $# -lt 2 ]; then
|
||||||
|
echo "Usage: $0 <hostname> <common-name> [country] [state] [locality] [org] [ou] [key-bits] [additional-dns]"
|
||||||
|
echo ""
|
||||||
|
echo "Example: $0 srv-wmw-ha01 ha.egonetix.lan DE berlin berlin egonetix it 4096"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET_HOST="$1"
|
||||||
|
COMMON_NAME="$2"
|
||||||
|
COUNTRY="${3:-DE}"
|
||||||
|
STATE="${4:-berlin}"
|
||||||
|
LOCALITY="${5:-berlin}"
|
||||||
|
ORG="${6:-egonetix}"
|
||||||
|
OU="${7:-it}"
|
||||||
|
KEY_BITS="${8:-4096}"
|
||||||
|
ADDITIONAL_DNS="${9:-}"
|
||||||
|
SSH_USER="${SSH_USER:-icke}"
|
||||||
|
|
||||||
|
# Extract short hostname from common name
|
||||||
|
SHORT_NAME=$(echo "$COMMON_NAME" | cut -d'.' -f1)
|
||||||
|
OUTPUT_FILE="${SHORT_NAME}.req"
|
||||||
|
|
||||||
|
# Detect if TARGET_HOST is an IP address
|
||||||
|
if [[ "$TARGET_HOST" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
TARGET_IP="$TARGET_HOST"
|
||||||
|
else
|
||||||
|
# Try to resolve hostname to IP
|
||||||
|
TARGET_IP=$(ssh -o ConnectTimeout=5 ${SSH_USER}@${TARGET_HOST} "hostname -I | awk '{print \$1}'" 2>/dev/null || echo "")
|
||||||
|
if [ -z "$TARGET_IP" ]; then
|
||||||
|
# Fallback: try local resolution
|
||||||
|
TARGET_IP=$(getent hosts "$TARGET_HOST" 2>/dev/null | awk '{print $1}' | head -1 || echo "")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Home Assistant Certificate Request"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Target host: $TARGET_HOST"
|
||||||
|
echo "SSH User: $SSH_USER"
|
||||||
|
echo "Target IP: ${TARGET_IP:-not detected}"
|
||||||
|
echo "Common Name: $COMMON_NAME"
|
||||||
|
echo "Country: $COUNTRY"
|
||||||
|
echo "State: $STATE"
|
||||||
|
echo "Locality: $LOCALITY"
|
||||||
|
echo "Organization: $ORG"
|
||||||
|
echo "Org Unit: $OU"
|
||||||
|
echo "Key Length: $KEY_BITS bits"
|
||||||
|
if [ -n "$ADDITIONAL_DNS" ]; then
|
||||||
|
echo "Additional DNS: $ADDITIONAL_DNS"
|
||||||
|
fi
|
||||||
|
echo "Output file: $OUTPUT_FILE"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Build SAN entries
|
||||||
|
SAN_DNS="DNS.1 = $COMMON_NAME
|
||||||
|
DNS.2 = $SHORT_NAME"
|
||||||
|
|
||||||
|
DNS_COUNTER=3
|
||||||
|
|
||||||
|
# Add alternative names if common name contains domain
|
||||||
|
if [[ "$COMMON_NAME" == *.* ]]; then
|
||||||
|
SAN_DNS="$SAN_DNS
|
||||||
|
DNS.$DNS_COUNTER = ${SHORT_NAME}.${COMMON_NAME#*.}"
|
||||||
|
((DNS_COUNTER++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add additional DNS names if provided
|
||||||
|
if [ -n "$ADDITIONAL_DNS" ]; then
|
||||||
|
IFS=',' read -ra EXTRA_DNS <<< "$ADDITIONAL_DNS"
|
||||||
|
for dns in "${EXTRA_DNS[@]}"; do
|
||||||
|
# Trim whitespace
|
||||||
|
dns=$(echo "$dns" | xargs)
|
||||||
|
if [ -n "$dns" ]; then
|
||||||
|
SAN_DNS="$SAN_DNS
|
||||||
|
DNS.$DNS_COUNTER = $dns"
|
||||||
|
((DNS_COUNTER++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add IP address if detected
|
||||||
|
SAN_IP=""
|
||||||
|
if [ -n "$TARGET_IP" ]; then
|
||||||
|
SAN_IP="IP.1 = $TARGET_IP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create OpenSSL config
|
||||||
|
CONFIG_CONTENT="[req]
|
||||||
|
default_bits = $KEY_BITS
|
||||||
|
prompt = no
|
||||||
|
default_md = sha256
|
||||||
|
distinguished_name = dn
|
||||||
|
req_extensions = v3_req
|
||||||
|
|
||||||
|
[dn]
|
||||||
|
C=$COUNTRY
|
||||||
|
ST=$STATE
|
||||||
|
L=$LOCALITY
|
||||||
|
O=$ORG
|
||||||
|
OU=$OU
|
||||||
|
CN=$COMMON_NAME
|
||||||
|
|
||||||
|
[v3_req]
|
||||||
|
keyUsage = digitalSignature, keyEncipherment
|
||||||
|
extendedKeyUsage = serverAuth
|
||||||
|
subjectAltName = @alt_names
|
||||||
|
|
||||||
|
[alt_names]
|
||||||
|
$SAN_DNS"
|
||||||
|
|
||||||
|
# Append IP if available
|
||||||
|
if [ -n "$SAN_IP" ]; then
|
||||||
|
CONFIG_CONTENT="$CONFIG_CONTENT
|
||||||
|
$SAN_IP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[1/4] Creating OpenSSL configuration..."
|
||||||
|
echo "$CONFIG_CONTENT" > /tmp/csr_config.conf
|
||||||
|
|
||||||
|
echo "[2/4] Copying config to target host..."
|
||||||
|
scp /tmp/csr_config.conf ${SSH_USER}@${TARGET_HOST}:/tmp/csr_config.conf
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Error: Failed to copy config to target host"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[3/4] Generating $KEY_BITS-bit RSA key and CSR on target host..."
|
||||||
|
ssh ${SSH_USER}@${TARGET_HOST} "openssl req -new -newkey rsa:$KEY_BITS -nodes -keyout /tmp/${SHORT_NAME}.key -out /tmp/${SHORT_NAME}.csr -config /tmp/csr_config.conf"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Error: Failed to generate CSR on target host"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[4/4] Downloading CSR..."
|
||||||
|
scp ${SSH_USER}@${TARGET_HOST}:/tmp/${SHORT_NAME}.csr "$OUTPUT_FILE"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Error: Failed to download CSR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean up local temp file
|
||||||
|
rm -f /tmp/csr_config.conf
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo "✓ CSR generated successfully!"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Certificate request saved to: $OUTPUT_FILE"
|
||||||
|
echo ""
|
||||||
|
echo "CSR details:"
|
||||||
|
openssl req -in "$OUTPUT_FILE" -noout -text | grep -A 10 "Subject:"
|
||||||
|
echo ""
|
||||||
|
echo "Subject Alternative Names:"
|
||||||
|
openssl req -in "$OUTPUT_FILE" -noout -text | grep -A 20 "Subject Alternative Name" || echo " (none found)"
|
||||||
|
echo ""
|
||||||
|
echo "Key details:"
|
||||||
|
openssl req -in "$OUTPUT_FILE" -noout -text | grep "Public-Key:"
|
||||||
|
echo ""
|
||||||
|
echo "IMPORTANT: Private key is stored on target host at:"
|
||||||
|
echo " /tmp/${SHORT_NAME}.key"
|
||||||
|
echo ""
|
||||||
|
echo "Next step: Sign this CSR with:"
|
||||||
|
echo " ./sign-cert.sh $OUTPUT_FILE $SHORT_NAME"
|
||||||
|
echo "=========================================="
|
||||||
164
generate-csr-local.sh
Executable file
164
generate-csr-local.sh
Executable file
@@ -0,0 +1,164 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Script to generate a certificate request locally (for systems without SCP/SFTP)
|
||||||
|
# Usage: ./generate-csr-local.sh <common-name> [country] [state] [locality] [org] [ou] [key-bits] [additional-dns] [ip-address]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Check arguments
|
||||||
|
if [ $# -lt 1 ]; then
|
||||||
|
echo "Usage: $0 <common-name> [country] [state] [locality] [org] [ou] [key-bits] [additional-dns] [ip-address]"
|
||||||
|
echo ""
|
||||||
|
echo "Example: $0 srv-wmw-ha01.egonetix.lan DE berlin berlin egonetix it 4096 '' 172.20.70.10"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
COMMON_NAME="$1"
|
||||||
|
COUNTRY="${2:-DE}"
|
||||||
|
STATE="${3:-berlin}"
|
||||||
|
LOCALITY="${4:-berlin}"
|
||||||
|
ORG="${5:-egonetix}"
|
||||||
|
OU="${6:-it}"
|
||||||
|
KEY_BITS="${7:-4096}"
|
||||||
|
ADDITIONAL_DNS="${8:-}"
|
||||||
|
IP_ADDRESS="${9:-}"
|
||||||
|
|
||||||
|
# Extract short hostname from common name
|
||||||
|
SHORT_NAME=$(echo "$COMMON_NAME" | cut -d'.' -f1)
|
||||||
|
OUTPUT_REQ="${SHORT_NAME}.req"
|
||||||
|
OUTPUT_KEY="${SHORT_NAME}.key"
|
||||||
|
OUTPUT_CSR="${SHORT_NAME}.csr"
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Local Certificate Request Generation"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Common Name: $COMMON_NAME"
|
||||||
|
echo "Country: $COUNTRY"
|
||||||
|
echo "State: $STATE"
|
||||||
|
echo "Locality: $LOCALITY"
|
||||||
|
echo "Organization: $ORG"
|
||||||
|
echo "Org Unit: $OU"
|
||||||
|
echo "Key Length: $KEY_BITS bits"
|
||||||
|
if [ -n "$ADDITIONAL_DNS" ]; then
|
||||||
|
echo "Additional DNS: $ADDITIONAL_DNS"
|
||||||
|
fi
|
||||||
|
if [ -n "$IP_ADDRESS" ]; then
|
||||||
|
echo "IP Address: $IP_ADDRESS"
|
||||||
|
fi
|
||||||
|
echo "Output files: $OUTPUT_REQ, $OUTPUT_KEY"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Build SAN entries
|
||||||
|
SAN_DNS="DNS.1 = $COMMON_NAME
|
||||||
|
DNS.2 = $SHORT_NAME"
|
||||||
|
|
||||||
|
DNS_COUNTER=3
|
||||||
|
|
||||||
|
# Add alternative names if common name contains domain
|
||||||
|
if [[ "$COMMON_NAME" == *.* ]]; then
|
||||||
|
SAN_DNS="$SAN_DNS
|
||||||
|
DNS.$DNS_COUNTER = ${SHORT_NAME}.${COMMON_NAME#*.}"
|
||||||
|
((DNS_COUNTER++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add additional DNS names if provided
|
||||||
|
if [ -n "$ADDITIONAL_DNS" ]; then
|
||||||
|
IFS=',' read -ra EXTRA_DNS <<< "$ADDITIONAL_DNS"
|
||||||
|
for dns in "${EXTRA_DNS[@]}"; do
|
||||||
|
# Trim whitespace
|
||||||
|
dns=$(echo "$dns" | xargs)
|
||||||
|
if [ -n "$dns" ]; then
|
||||||
|
SAN_DNS="$SAN_DNS
|
||||||
|
DNS.$DNS_COUNTER = $dns"
|
||||||
|
((DNS_COUNTER++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add IP addresses if provided (comma-separated)
|
||||||
|
SAN_IP=""
|
||||||
|
if [ -n "$IP_ADDRESS" ]; then
|
||||||
|
IP_COUNTER=1
|
||||||
|
IFS=',' read -ra IP_ADDRS <<< "$IP_ADDRESS"
|
||||||
|
for ip in "${IP_ADDRS[@]}"; do
|
||||||
|
# Trim whitespace
|
||||||
|
ip=$(echo "$ip" | xargs)
|
||||||
|
if [ -n "$ip" ]; then
|
||||||
|
if [ -z "$SAN_IP" ]; then
|
||||||
|
SAN_IP="IP.$IP_COUNTER = $ip"
|
||||||
|
else
|
||||||
|
SAN_IP="$SAN_IP
|
||||||
|
IP.$IP_COUNTER = $ip"
|
||||||
|
fi
|
||||||
|
((IP_COUNTER++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create OpenSSL config
|
||||||
|
CONFIG_CONTENT="[req]
|
||||||
|
default_bits = $KEY_BITS
|
||||||
|
prompt = no
|
||||||
|
default_md = sha256
|
||||||
|
distinguished_name = dn
|
||||||
|
req_extensions = v3_req
|
||||||
|
|
||||||
|
[dn]
|
||||||
|
C=$COUNTRY
|
||||||
|
ST=$STATE
|
||||||
|
L=$LOCALITY
|
||||||
|
O=$ORG
|
||||||
|
OU=$OU
|
||||||
|
CN=$COMMON_NAME
|
||||||
|
|
||||||
|
[v3_req]
|
||||||
|
keyUsage = digitalSignature, keyEncipherment
|
||||||
|
extendedKeyUsage = serverAuth
|
||||||
|
subjectAltName = @alt_names
|
||||||
|
|
||||||
|
[alt_names]
|
||||||
|
$SAN_DNS"
|
||||||
|
|
||||||
|
# Append IP if available
|
||||||
|
if [ -n "$SAN_IP" ]; then
|
||||||
|
CONFIG_CONTENT="$CONFIG_CONTENT
|
||||||
|
$SAN_IP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
CONFIG_FILE="/tmp/csr_config_${SHORT_NAME}.conf"
|
||||||
|
echo "[1/2] Creating OpenSSL configuration..."
|
||||||
|
echo "$CONFIG_CONTENT" > "$CONFIG_FILE"
|
||||||
|
|
||||||
|
echo "[2/2] Generating $KEY_BITS-bit RSA key and CSR locally..."
|
||||||
|
openssl req -new -newkey rsa:$KEY_BITS -nodes -keyout "$OUTPUT_KEY" -out "$OUTPUT_CSR" -config "$CONFIG_FILE"
|
||||||
|
|
||||||
|
# Also create the .req file for consistency with other scripts
|
||||||
|
cp "$OUTPUT_CSR" "$OUTPUT_REQ"
|
||||||
|
|
||||||
|
# Clean up config file
|
||||||
|
rm -f "$CONFIG_FILE"
|
||||||
|
|
||||||
|
# Set proper permissions on private key
|
||||||
|
chmod 600 "$OUTPUT_KEY"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo "✓ Certificate files generated locally!"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Certificate request: $OUTPUT_REQ"
|
||||||
|
echo "Private key: $OUTPUT_KEY"
|
||||||
|
echo ""
|
||||||
|
echo "CSR details:"
|
||||||
|
openssl req -in "$OUTPUT_REQ" -noout -text | grep -A 10 "Subject:"
|
||||||
|
echo ""
|
||||||
|
echo "Subject Alternative Names:"
|
||||||
|
openssl req -in "$OUTPUT_REQ" -noout -text | grep -A 20 "Subject Alternative Name" || echo " (none found)"
|
||||||
|
echo ""
|
||||||
|
echo "Key details:"
|
||||||
|
openssl req -in "$OUTPUT_REQ" -noout -text | grep "Public-Key:"
|
||||||
|
echo ""
|
||||||
|
echo "⚠️ IMPORTANT: Keep $OUTPUT_KEY secure!"
|
||||||
|
echo ""
|
||||||
|
echo "Next step: Sign this CSR with:"
|
||||||
|
echo " ./sign-cert.sh $OUTPUT_REQ $SHORT_NAME"
|
||||||
|
echo "=========================================="
|
||||||
@@ -21,6 +21,17 @@ ORG="${6:-egonetix}"
|
|||||||
OU="${7:-it}"
|
OU="${7:-it}"
|
||||||
KEY_BITS="${8:-4096}"
|
KEY_BITS="${8:-4096}"
|
||||||
ADDITIONAL_DNS="${9:-}"
|
ADDITIONAL_DNS="${9:-}"
|
||||||
|
SSH_USER="${SSH_USER:-root}"
|
||||||
|
SSH_PASSWORD="${SSH_PASSWORD:-}"
|
||||||
|
|
||||||
|
# Setup SSH/SCP commands with password support
|
||||||
|
if [ -n "$SSH_PASSWORD" ] && command -v sshpass >/dev/null 2>&1; then
|
||||||
|
SSH_CMD="sshpass -p '$SSH_PASSWORD' ssh"
|
||||||
|
SCP_CMD="sshpass -p '$SSH_PASSWORD' scp"
|
||||||
|
else
|
||||||
|
SSH_CMD="ssh"
|
||||||
|
SCP_CMD="scp"
|
||||||
|
fi
|
||||||
|
|
||||||
# Extract short hostname from common name
|
# Extract short hostname from common name
|
||||||
SHORT_NAME=$(echo "$COMMON_NAME" | cut -d'.' -f1)
|
SHORT_NAME=$(echo "$COMMON_NAME" | cut -d'.' -f1)
|
||||||
@@ -31,7 +42,7 @@ if [[ "$TARGET_HOST" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|||||||
TARGET_IP="$TARGET_HOST"
|
TARGET_IP="$TARGET_HOST"
|
||||||
else
|
else
|
||||||
# Try to resolve hostname to IP
|
# Try to resolve hostname to IP
|
||||||
TARGET_IP=$(ssh -o ConnectTimeout=5 -o BatchMode=yes root@${TARGET_HOST} "hostname -I | awk '{print \$1}'" 2>/dev/null || echo "")
|
TARGET_IP=$($SSH_CMD -o ConnectTimeout=5 ${SSH_USER}@${TARGET_HOST} "hostname -I | awk '{print \$1}'" 2>/dev/null || echo "")
|
||||||
if [ -z "$TARGET_IP" ]; then
|
if [ -z "$TARGET_IP" ]; then
|
||||||
# Fallback: try local resolution
|
# Fallback: try local resolution
|
||||||
TARGET_IP=$(getent hosts "$TARGET_HOST" 2>/dev/null | awk '{print $1}' | head -1 || echo "")
|
TARGET_IP=$(getent hosts "$TARGET_HOST" 2>/dev/null | awk '{print $1}' | head -1 || echo "")
|
||||||
@@ -124,21 +135,24 @@ echo "[1/4] Creating OpenSSL configuration..."
|
|||||||
echo "$CONFIG_CONTENT" > /tmp/csr_config.conf
|
echo "$CONFIG_CONTENT" > /tmp/csr_config.conf
|
||||||
|
|
||||||
echo "[2/4] Copying config to target host..."
|
echo "[2/4] Copying config to target host..."
|
||||||
scp /tmp/csr_config.conf root@${TARGET_HOST}:/tmp/csr_config.conf
|
sleep 0.5 # Avoid SSH rate limiting
|
||||||
|
$SCP_CMD /tmp/csr_config.conf ${SSH_USER}@${TARGET_HOST}:/tmp/csr_config.conf
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Error: Failed to copy config to target host"
|
echo "Error: Failed to copy config to target host"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "[3/4] Generating $KEY_BITS-bit RSA key and CSR on target host..."
|
echo "[3/4] Generating $KEY_BITS-bit RSA key and CSR on target host..."
|
||||||
ssh root@${TARGET_HOST} "openssl req -new -newkey rsa:$KEY_BITS -nodes -keyout /tmp/${SHORT_NAME}.key -out /tmp/${SHORT_NAME}.csr -config /tmp/csr_config.conf"
|
sleep 0.5 # Avoid SSH rate limiting
|
||||||
|
$SSH_CMD ${SSH_USER}@${TARGET_HOST} "openssl req -new -newkey rsa:$KEY_BITS -nodes -keyout /tmp/${SHORT_NAME}.key -out /tmp/${SHORT_NAME}.csr -config /tmp/csr_config.conf"
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Error: Failed to generate CSR on target host"
|
echo "Error: Failed to generate CSR on target host"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "[4/4] Downloading CSR..."
|
echo "[4/4] Downloading CSR..."
|
||||||
scp root@${TARGET_HOST}:/tmp/${SHORT_NAME}.csr "$OUTPUT_FILE"
|
sleep 0.5 # Avoid SSH rate limiting
|
||||||
|
$SCP_CMD ${SSH_USER}@${TARGET_HOST}:/tmp/${SHORT_NAME}.csr "$OUTPUT_FILE"
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Error: Failed to download CSR"
|
echo "Error: Failed to download CSR"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
Reference in New Issue
Block a user