#!/bin/bash # TLS/HTTPS Setup Script for BotServer # This script sets up a complete TLS infrastructure with internal CA and certificates for all services set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration CERT_DIR="./certs" CA_DIR="$CERT_DIR/ca" VALIDITY_DAYS=365 COUNTRY="BR" STATE="SP" LOCALITY="São Paulo" ORGANIZATION="BotServer" COMMON_NAME_SUFFIX="botserver.local" # Services that need certificates SERVICES=( "api:8443:localhost,api.botserver.local,127.0.0.1" "llm:8444:localhost,llm.botserver.local,127.0.0.1" "embedding:8445:localhost,embedding.botserver.local,127.0.0.1" "qdrant:6334:localhost,qdrant.botserver.local,127.0.0.1" "redis:6380:localhost,redis.botserver.local,127.0.0.1" "postgres:5433:localhost,postgres.botserver.local,127.0.0.1" "minio:9001:localhost,minio.botserver.local,127.0.0.1" "directory:8446:localhost,directory.botserver.local,127.0.0.1" "email:465:localhost,email.botserver.local,127.0.0.1" "meet:7881:localhost,meet.botserver.local,127.0.0.1" ) echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}BotServer TLS/HTTPS Setup${NC}" echo -e "${BLUE}========================================${NC}" # Function to check if OpenSSL is installed check_openssl() { if ! command -v openssl &> /dev/null; then echo -e "${RED}OpenSSL is not installed. Please install it first.${NC}" exit 1 fi echo -e "${GREEN}✓ OpenSSL found${NC}" } # Function to create directory structure create_directories() { echo -e "${YELLOW}Creating certificate directories...${NC}" mkdir -p "$CA_DIR" mkdir -p "$CA_DIR/private" mkdir -p "$CA_DIR/certs" mkdir -p "$CA_DIR/crl" mkdir -p "$CA_DIR/newcerts" # Create directories for each service for service_config in "${SERVICES[@]}"; do IFS=':' read -r service port sans <<< "$service_config" mkdir -p "$CERT_DIR/$service" done # Create CA database files touch "$CA_DIR/index.txt" echo "1000" > "$CA_DIR/serial" echo "1000" > "$CA_DIR/crlnumber" echo -e "${GREEN}✓ Directories created${NC}" } # Function to create CA configuration create_ca_config() { echo -e "${YELLOW}Creating CA configuration...${NC}" cat > "$CA_DIR/ca.conf" << EOF [ ca ] default_ca = CA_default [ CA_default ] dir = $CA_DIR certs = \$dir/certs crl_dir = \$dir/crl new_certs_dir = \$dir/newcerts database = \$dir/index.txt serial = \$dir/serial crlnumber = \$dir/crlnumber crl = \$dir/crl.pem certificate = \$dir/ca.crt private_key = \$dir/private/ca.key RANDFILE = \$dir/private/.rand x509_extensions = usr_cert name_opt = ca_default cert_opt = ca_default default_days = $VALIDITY_DAYS default_crl_days = 30 default_md = sha256 preserve = no policy = policy_loose [ policy_loose ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ req ] default_bits = 4096 default_keyfile = privkey.pem distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca string_mask = utf8only default_md = sha256 [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = $COUNTRY stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = $STATE localityName = Locality Name (eg, city) localityName_default = $LOCALITY organizationName = Organization Name (eg, company) organizationName_default = $ORGANIZATION organizationalUnitName = Organizational Unit Name (eg, section) commonName = Common Name (e.g. server FQDN or YOUR name) emailAddress = Email Address [ req_attributes ] challengePassword = A challenge password challengePassword_min = 4 challengePassword_max = 20 unstructuredName = An optional company name [ v3_ca ] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical,CA:true keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ v3_intermediate_ca ] subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ usr_cert ] basicConstraints = CA:FALSE nsCertType = client, email nsComment = "OpenSSL Generated Client Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth, emailProtection [ server_cert ] basicConstraints = CA:FALSE nsCertType = server nsComment = "OpenSSL Generated Server Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth EOF echo -e "${GREEN}✓ CA configuration created${NC}" } # Function to generate Root CA generate_root_ca() { echo -e "${YELLOW}Generating Root CA...${NC}" if [ -f "$CA_DIR/ca.crt" ] && [ -f "$CA_DIR/private/ca.key" ]; then echo -e "${YELLOW}Root CA already exists, skipping...${NC}" return fi # Generate Root CA private key openssl genrsa -out "$CA_DIR/private/ca.key" 4096 chmod 400 "$CA_DIR/private/ca.key" # Generate Root CA certificate openssl req -config "$CA_DIR/ca.conf" \ -key "$CA_DIR/private/ca.key" \ -new -x509 -days 7300 -sha256 -extensions v3_ca \ -out "$CA_DIR/ca.crt" \ -subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORGANIZATION/CN=BotServer Root CA" # Copy CA cert to main cert directory for easy access cp "$CA_DIR/ca.crt" "$CERT_DIR/ca.crt" echo -e "${GREEN}✓ Root CA generated${NC}" } # Function to generate Intermediate CA generate_intermediate_ca() { echo -e "${YELLOW}Generating Intermediate CA...${NC}" if [ -f "$CA_DIR/intermediate.crt" ] && [ -f "$CA_DIR/private/intermediate.key" ]; then echo -e "${YELLOW}Intermediate CA already exists, skipping...${NC}" return fi # Generate Intermediate CA private key openssl genrsa -out "$CA_DIR/private/intermediate.key" 4096 chmod 400 "$CA_DIR/private/intermediate.key" # Generate Intermediate CA CSR openssl req -config "$CA_DIR/ca.conf" \ -new -sha256 \ -key "$CA_DIR/private/intermediate.key" \ -out "$CA_DIR/intermediate.csr" \ -subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORGANIZATION/CN=BotServer Intermediate CA" # Sign Intermediate CA certificate with Root CA openssl ca -config "$CA_DIR/ca.conf" \ -extensions v3_intermediate_ca \ -days 3650 -notext -md sha256 \ -in "$CA_DIR/intermediate.csr" \ -out "$CA_DIR/intermediate.crt" \ -batch chmod 444 "$CA_DIR/intermediate.crt" # Create certificate chain cat "$CA_DIR/intermediate.crt" "$CA_DIR/ca.crt" > "$CA_DIR/ca-chain.crt" echo -e "${GREEN}✓ Intermediate CA generated${NC}" } # Function to generate service certificate generate_service_cert() { local service=$1 local port=$2 local sans=$3 echo -e "${YELLOW}Generating certificates for $service...${NC}" local cert_dir="$CERT_DIR/$service" # Create SAN configuration cat > "$cert_dir/san.conf" << EOF [req] distinguished_name = req_distinguished_name req_extensions = v3_req [req_distinguished_name] [v3_req] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [alt_names] EOF # Add SANs IFS=',' read -ra SAN_ARRAY <<< "$sans" local san_index=1 for san in "${SAN_ARRAY[@]}"; do if [[ $san =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo "IP.$san_index = $san" >> "$cert_dir/san.conf" else echo "DNS.$san_index = $san" >> "$cert_dir/san.conf" fi ((san_index++)) done # Generate server private key openssl genrsa -out "$cert_dir/server.key" 2048 chmod 400 "$cert_dir/server.key" # Generate server CSR openssl req -new -sha256 \ -key "$cert_dir/server.key" \ -out "$cert_dir/server.csr" \ -config "$cert_dir/san.conf" \ -subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORGANIZATION/CN=$service.$COMMON_NAME_SUFFIX" # Sign server certificate with CA openssl x509 -req -in "$cert_dir/server.csr" \ -CA "$CA_DIR/ca.crt" \ -CAkey "$CA_DIR/private/ca.key" \ -CAcreateserial \ -out "$cert_dir/server.crt" \ -days $VALIDITY_DAYS \ -sha256 \ -extensions v3_req \ -extfile "$cert_dir/san.conf" # Generate client certificate for mTLS openssl genrsa -out "$cert_dir/client.key" 2048 chmod 400 "$cert_dir/client.key" openssl req -new -sha256 \ -key "$cert_dir/client.key" \ -out "$cert_dir/client.csr" \ -subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORGANIZATION/CN=$service-client.$COMMON_NAME_SUFFIX" openssl x509 -req -in "$cert_dir/client.csr" \ -CA "$CA_DIR/ca.crt" \ -CAkey "$CA_DIR/private/ca.key" \ -CAcreateserial \ -out "$cert_dir/client.crt" \ -days $VALIDITY_DAYS \ -sha256 # Copy CA certificate to service directory cp "$CA_DIR/ca.crt" "$cert_dir/ca.crt" # Create full chain certificate cat "$cert_dir/server.crt" "$CA_DIR/ca.crt" > "$cert_dir/fullchain.crt" # Clean up CSR files rm -f "$cert_dir/server.csr" "$cert_dir/client.csr" "$cert_dir/san.conf" echo -e "${GREEN}✓ Certificates generated for $service (port $port)${NC}" } # Function to generate all service certificates generate_all_service_certs() { echo -e "${BLUE}Generating certificates for all services...${NC}" for service_config in "${SERVICES[@]}"; do IFS=':' read -r service port sans <<< "$service_config" generate_service_cert "$service" "$port" "$sans" done echo -e "${GREEN}✓ All service certificates generated${NC}" } # Function to create TLS configuration file create_tls_config() { echo -e "${YELLOW}Creating TLS configuration file...${NC}" cat > "$CERT_DIR/tls-config.toml" << EOF # TLS Configuration for BotServer # Generated on $(date) [tls] enabled = true mtls_enabled = true auto_generate_certs = true renewal_threshold_days = 30 [ca] ca_cert_path = "$CA_DIR/ca.crt" ca_key_path = "$CA_DIR/private/ca.key" intermediate_cert_path = "$CA_DIR/intermediate.crt" intermediate_key_path = "$CA_DIR/private/intermediate.key" validity_days = $VALIDITY_DAYS organization = "$ORGANIZATION" country = "$COUNTRY" state = "$STATE" locality = "$LOCALITY" # Service configurations EOF for service_config in "${SERVICES[@]}"; do IFS=':' read -r service port sans <<< "$service_config" cat >> "$CERT_DIR/tls-config.toml" << EOF [[services]] name = "$service" port = $port cert_path = "$CERT_DIR/$service/server.crt" key_path = "$CERT_DIR/$service/server.key" client_cert_path = "$CERT_DIR/$service/client.crt" client_key_path = "$CERT_DIR/$service/client.key" ca_cert_path = "$CERT_DIR/$service/ca.crt" sans = "$sans" EOF done echo -e "${GREEN}✓ TLS configuration file created${NC}" } # Function to display certificate information display_cert_info() { echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}Certificate Information${NC}" echo -e "${BLUE}========================================${NC}" echo -e "${YELLOW}Root CA:${NC}" openssl x509 -in "$CA_DIR/ca.crt" -noout -subject -dates echo "" echo -e "${YELLOW}Service Certificates:${NC}" for service_config in "${SERVICES[@]}"; do IFS=':' read -r service port sans <<< "$service_config" echo -e "${GREEN}$service (port $port):${NC}" openssl x509 -in "$CERT_DIR/$service/server.crt" -noout -subject -dates done } # Function to create environment variables file create_env_vars() { echo -e "${YELLOW}Creating environment variables file...${NC}" cat > "$CERT_DIR/tls.env" << EOF # TLS Environment Variables for BotServer # Source this file to set TLS environment variables export TLS_ENABLED=true export MTLS_ENABLED=true export CA_CERT_PATH="$CA_DIR/ca.crt" export CA_KEY_PATH="$CA_DIR/private/ca.key" # Service-specific TLS settings export API_TLS_PORT=8443 export API_CERT_PATH="$CERT_DIR/api/server.crt" export API_KEY_PATH="$CERT_DIR/api/server.key" export LLM_TLS_PORT=8444 export LLM_CERT_PATH="$CERT_DIR/llm/server.crt" export LLM_KEY_PATH="$CERT_DIR/llm/server.key" export EMBEDDING_TLS_PORT=8445 export EMBEDDING_CERT_PATH="$CERT_DIR/embedding/server.crt" export EMBEDDING_KEY_PATH="$CERT_DIR/embedding/server.key" export QDRANT_TLS_PORT=6334 export QDRANT_CERT_PATH="$CERT_DIR/qdrant/server.crt" export QDRANT_KEY_PATH="$CERT_DIR/qdrant/server.key" export REDIS_TLS_PORT=6380 export REDIS_CERT_PATH="$CERT_DIR/redis/server.crt" export REDIS_KEY_PATH="$CERT_DIR/redis/server.key" export POSTGRES_TLS_PORT=5433 export POSTGRES_CERT_PATH="$CERT_DIR/postgres/server.crt" export POSTGRES_KEY_PATH="$CERT_DIR/postgres/server.key" export MINIO_TLS_PORT=9001 export MINIO_CERT_PATH="$CERT_DIR/minio/server.crt" export MINIO_KEY_PATH="$CERT_DIR/minio/server.key" EOF echo -e "${GREEN}✓ Environment variables file created${NC}" } # Function to test certificate validity test_certificates() { echo -e "${BLUE}Testing certificate validity...${NC}" local all_valid=true for service_config in "${SERVICES[@]}"; do IFS=':' read -r service port sans <<< "$service_config" # Verify certificate chain if openssl verify -CAfile "$CA_DIR/ca.crt" "$CERT_DIR/$service/server.crt" > /dev/null 2>&1; then echo -e "${GREEN}✓ $service server certificate is valid${NC}" else echo -e "${RED}✗ $service server certificate is invalid${NC}" all_valid=false fi if openssl verify -CAfile "$CA_DIR/ca.crt" "$CERT_DIR/$service/client.crt" > /dev/null 2>&1; then echo -e "${GREEN}✓ $service client certificate is valid${NC}" else echo -e "${RED}✗ $service client certificate is invalid${NC}" all_valid=false fi done if $all_valid; then echo -e "${GREEN}✓ All certificates are valid${NC}" else echo -e "${RED}Some certificates failed validation${NC}" exit 1 fi } # Main execution main() { check_openssl create_directories create_ca_config generate_root_ca # Intermediate CA is optional but recommended # generate_intermediate_ca generate_all_service_certs create_tls_config create_env_vars test_certificates display_cert_info echo "" echo -e "${GREEN}========================================${NC}" echo -e "${GREEN}TLS Setup Complete!${NC}" echo -e "${GREEN}========================================${NC}" echo "" echo -e "${YELLOW}Next steps:${NC}" echo "1. Source the environment variables: source $CERT_DIR/tls.env" echo "2. Update your service configurations to use HTTPS/TLS" echo "3. Restart all services with TLS enabled" echo "" echo -e "${YELLOW}Important files:${NC}" echo " CA Certificate: $CA_DIR/ca.crt" echo " TLS Config: $CERT_DIR/tls-config.toml" echo " Environment Variables: $CERT_DIR/tls.env" echo "" echo -e "${YELLOW}To trust the CA certificate on your system:${NC}" echo " Ubuntu/Debian: sudo cp $CA_DIR/ca.crt /usr/local/share/ca-certificates/botserver-ca.crt && sudo update-ca-certificates" echo " RHEL/CentOS: sudo cp $CA_DIR/ca.crt /etc/pki/ca-trust/source/anchors/ && sudo update-ca-trust" echo " macOS: sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain $CA_DIR/ca.crt" } # Run main function main