[OpenVPN] Criar usuários e certificados usando Easy-RSA

Se você mantém um servidor OpenVPN e deseja automatizar a criação de usuários com certificados de longa validade, este script é a solução definitiva. Ele:

✅ Gera senhas seguras com histórico de uso
✅ Gera certificados válidos por 10 anos
✅ Permite regenerar senha e certificado de um único usuário
✅ Executa em modo totalmente automático ou por usuário específico
✅ Armazena histórico de senhas em diretório seguro


📂 Estrutura de diretórios

Este script considera os seguintes caminhos padrões:

  • Easy-RSA: /usr/share/easy-rsa/
  • Exportação de certificados: /etc/openvpn/clients/
  • Arquivo com senhas dos usuários: /etc/openvpn/usuarios_senhas.txt
  • Histórico de senhas por usuário: /etc/openvpn/user_password_history/

🧠 Lógica inteligente

  • Se o script for executado sem parâmetros, ele cria usuários client2 até client254 automaticamente.
  • Se for passado o nome de um usuário específico, o script perguntará se deseja substituir a senha e certificado.
  • Senhas repetidas ou fracas são automaticamente evitadas com base em regras simples e histórico.

⚙️ Script completo (gerenciar_usuarios_openvpn.sh)

#!/bin/bash

# Diretórios
EASYRSA_DIR="/usr/share/easy-rsa"
EASYRSA_VARS="$EASYRSA_DIR/vars"
EXPORT_BASE="/etc/openvpn/clients"
PASSWORD_FILE="/etc/openvpn/usuarios_senhas.txt"
PASSWORD_HISTORY_DIR="/etc/openvpn/user_password_history"

mkdir -p "$PASSWORD_HISTORY_DIR"
mkdir -p "$EXPORT_BASE"

# Validade dos certificados (10 anos = 3650 dias)
export EASYRSA_CERT_EXPIRE=3650

# Captura a quantidade de argumentos passados ao script
SCRIPT_PARAM_COUNT=$#

# Inicializa Easy-RSA (caso seja a primeira vez)
init_easyrsa_if_needed() {
    cd "$EASYRSA_DIR" || { echo "❌ Easy-RSA não encontrado em $EASYRSA_DIR"; exit 1; }

    if [[ ! -d "pki" ]]; then
        echo "📦 Inicializando Easy-RSA (primeira vez)..."
        ./easyrsa init-pki
    fi

    if [[ ! -f "pki/ca.crt" ]]; then
        echo "🔐 Criando autoridade certificadora (Root CA)..."
        ./easyrsa --batch build-ca nopass
    fi
}

# Gerador de senha forte
generate_password() {
    while true; do
        upper=$(openssl rand -base64 12 | tr -dc 'A-Z' | head -c4)
        lower=$(openssl rand -base64 12 | tr -dc 'a-z' | head -c4)
        digits=$(openssl rand -base64 12 | tr -dc '0-9' | head -c4)
        symbols=$(echo '!@#$%^&*()-_=+[{]}|;:,.<>?' | fold -w1 | shuf | head -n4 | tr -d '\n')
        password="${upper}${lower}${digits}${symbols}"
        password=$(echo "$password" | fold -w1 | shuf | tr -d '\n')

        [[ "$password" =~ ([0-9]{3,}) ]] && continue
        [[ "$password" =~ (client|CLIENT) ]] && continue
        [[ "$password" =~ (.)\1{2,} ]] && continue

        echo "$password"
        return
    done
}

check_password_history() {
    local user="$1" password="$2"
    local hist_file="$PASSWORD_HISTORY_DIR/${user}.history"
    [[ -f "$hist_file" ]] && grep -Fxq "$password" "$hist_file" && return 1
    return 0
}

save_password_history() {
    local user="$1" password="$2"
    local hist_file="$PASSWORD_HISTORY_DIR/${user}.history"
    echo "$password" >> "$hist_file"
    tail -n 60 "$hist_file" > "${hist_file}.tmp" && mv "${hist_file}.tmp" "$hist_file"
}

create_cert() {
    local user="$1"
    local export_dir="${EXPORT_BASE}/${user}"
    mkdir -p "$export_dir"

    if [[ ! -f "$EASYRSA_DIR/pki/private/${user}.key" ]]; then
        echo "🔐 Gerando certificado para $user"
        cd "$EASYRSA_DIR" || exit 1
        ./easyrsa --batch gen-req "$user" nopass
        ./easyrsa --batch sign-req client "$user"
    else
        echo "📄 Certificado de $user já existe, reutilizando..."
    fi

    cp "$EASYRSA_DIR/pki/issued/${user}.crt" "$export_dir/"
    cp "$EASYRSA_DIR/pki/private/${user}.key" "$export_dir/"
    echo "📁 Arquivos exportados para: $export_dir/"
}

# Verifica se o usuário já existe e pergunta se deseja substituir
check_and_ask_replace() {
    local user="$1"
    local export_dir="${EXPORT_BASE}/${user}"

    if [[ "$SCRIPT_PARAM_COUNT" -eq 0 ]]; then
        # Modo automático, não perguntar
        return 0
    fi

    if id "$user" &>/dev/null; then
        echo "⚠️  Usuário $user já existe."
        read -p "Você quer substituir a senha e certificado de $user? (s/n): " answer
        if [[ "$answer" != "s" ]]; then
            echo "Ignorando usuário $user."
            return 1
        fi
    fi

    if [[ -f "$export_dir/${user}.crt" ]]; then
        echo "⚠️  Certificado de $user já existe."
        read -p "Você quer substituir o certificado e senha de $user? (s/n): " answer
        if [[ "$answer" != "s" ]]; then
            echo "Ignorando certificado de $user."
            return 1
        fi
    fi

    return 0
}

create_users() {
    for i in $(seq 2 254); do
        user="client$i"
        echo "👤 Criando usuário: $user"

        check_and_ask_replace "$user" || continue

        password=$(generate_password)
        while ! check_password_history "$user" "$password"; do
            password=$(generate_password)
        done

        useradd -M -s /sbin/nologin "$user" 2>/dev/null || true
        echo "$user:$password" | chpasswd
        echo "$user:$password" >> "$PASSWORD_FILE"
        save_password_history "$user" "$password"
        create_cert "$user"

        echo "✅ Usuário $user criado com senha e certificado."
    done
}

reset_password() {
    local user="$1"
    if ! id "$user" &>/dev/null; then
        echo "❌ Usuário $user não existe."
        exit 1
    fi

    password=$(generate_password)
    while ! check_password_history "$user" "$password"; do
        password=$(generate_password)
    done

    echo "$user:$password" | chpasswd
    sed -i "/^$user:/d" "$PASSWORD_FILE"
    echo "$user:$password" >> "$PASSWORD_FILE"
    save_password_history "$user" "$password"
    echo "🔁 Senha atualizada para $user: $password"
}

### Ponto de entrada ###
init_easyrsa_if_needed

if [[ $SCRIPT_PARAM_COUNT -eq 0 ]]; then
    create_users
elif [[ $SCRIPT_PARAM_COUNT -eq 1 ]]; then
    reset_password "$1"
else
    echo "Uso: $0 [usuario]"
    echo " - Sem parâmetro: cria todos os usuários e certificados"
    echo " - Com parâmetro: redefine senha do usuário"
    exit 1
fi

💡 Dicas de uso

# Criar todos os usuários do client2 ao client254
./gerenciar_usuarios_openvpn.sh

# Criar/atualizar apenas um usuário
./gerenciar_usuarios_openvpn.sh client83

🔐 Segurança

  • As senhas são complexas e diferentes entre os usuários.
  • O script evita reutilização de senhas através do histórico individual.
  • Os certificados são válidos por 10 anos, ideais para ambientes estáveis.

CATEGORIES:

Software Livre

Comments are closed