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.
Comments are closed