У pfSense есть забавная штука - экспорт конфигурации OpenVPN, такой штуки нет на Mikrotik. Я бы мог использовать pfSense или openSense, но они мне не нравятся, а в некоторых случаях сложны для настройки. Так как в одном из проектов мне волей-неволей придется создавать новых пользователей openVPN, я решил максимально автоматизировать процесс экспорта конфигурации и описал скрипт. Скрипт:
- запрашивает необходимые данные
- создает пользователя
- создает и подписывает сертификат
- создает структуру папок
- создает все необходимые файлы в этой структуре
- экспортирует сертификат
- формирует и выгружает файл конфигурации
Остается только нажать на каталог правой клавишей - сохранить, скопировать конфиг и структуру каталогов в каталог openVPN (в зависимости от типа либо config, либо config-auto (требуется установка службы))
Да, сам сервер уже должен быть настроен! По-умолчанию в качестве адреса сервера openVPN берется Identity устройства.
Запись из июля 2023 года, скрипт формирует структуру каталогов из-за ограничения переменной в 4096 байта, но я случайно нашел обходной вариант, который позволяет слить файлы в один большой - самый последний пример.
Запись из июля 2023 года, скрипт формирует структуру каталогов из-за ограничения переменной в 4096 байта, но я случайно нашел обходной вариант, который позволяет слить файлы в один большой - самый последний пример.
Скрипт запускается из консоли, сначала идет запрос данных, потом запрос-подтверждение и выполнение
# Pref global env
:global crtCnfpref "crtCnf"
:global crtCnfUserName
:global crtCnfPassword test
:global crtCnfAskPassword
:global crtCnfdaysValid 365
:global crtCnfFullPath ""
#config or config-auto
:global crtCnfNameConfig "config"
:global crtCnfContinue false
:global crtCnfovpnProfile "OVPN"
:global crtCnfServerAddress ([/system identity print as-value]->"name")
:global crtCnfcaName ca
:local NameOrg "DistControl"
:local RouteAddressAdd 10.20.1.254
#\\\\\\\\\\\\\\\\\\\
# BLOCK FUNC BEGIN
#
# Block create folder BEGIN
:global crtCnfCreateFolder do={
:global crtCnfFullPath
if ($crtCnfFullPath="") do={
:set crtCnfFullPath $NewPath
} else={
:set crtCnfFullPath ($crtCnfFullPath."/".$NewPath)
}
if ([:len [/file find where name=$crtCnfFullPath]]=0) do={
do {
/ip smb shares add name=crtCnfCreateFolder directory=$crtCnfFullPath
} on-error={
:put "Create folder failed"
}
/ip smb shares remove [/ip smb shares find where name=crtCnfCreateFolder]
} else={
:put "Path \"$crtCnfFullPath\" is exist"
}
}
:global crtCnfCreateTree do={
:global crtCnfCreateTree
:global crtCnfCreateFolder
if ([:len $1]>0) do={
$crtCnfCreateFolder NewPath=$1
$crtCnfCreateTree $2 $3 $4 $5 $6 $7 $8 $9
}
}
# Block create folder END
# Block create file BEGIN
# Example: $CreateFile FileName=File.ovpn Contents="text"
:local CreateFile do={
[/tool fetch dst-path=$FileName url="http://127.0.0.1/" as-value]
if ([:len [/file find where name=$FileName]]>0) do={
/file set $FileName contents=$Contents
:put ("Success to create file \"$FileName\"")
} else={
:put ("Failed to create file \"$FileName\"")
}
}
# Block create file END
# Example:
# :global UserName ""
# $PromtInput QstUser="\r\nInsert new username" VarName="UserName" DefaultValue=365 LenValue=8
:local PromtInput do={
:global crtCnfEndProgramm
:local readinput do={:return}
if ($LenValue>0) do={
:set $QstUser ("$QstUser. Minimum length $LenValue simbols")
}
if ([:len $DefaultValue]>0) do={
:set $QstUser ("$QstUser. \r\n(default - $DefaultValue)")
}
:put ("$QstUser:")
:local UserPromt [$readinput]
if ([:len $UserPromt]>0) do={
[:parse "global $VarName;:set $VarName $UserPromt"]
if (($LenValue>0) and [:len $UserPromt]<$LenValue) do={
$crtCnfEndProgramm MessageText=("You entered only $[:len $UserPromt] symbols instead of $LenValue minimum required. Stop program")
}
} else={
if ([:len $DefaultValue]>0) do={
[:parse "global $VarName;:set $VarName $DefaultValue"]
} else={
$crtCnfEndProgramm MessageText=("You didn't enter anything. Stop program")
}
}
}
# Block remove all global env BEGIN
:global crtCnfRemoveENV do={
:global crtCnfpref
:foreach var in=[/system script environment print as-value] do={
:local prefVar [:pick ($var->"name") 0 [:len $crtCnfpref]];
:if ($prefVar=$crtCnfpref) do={
/system script environment remove ($var->".id")
}
}
}
# Block remove all global env END
# Block call extensions BEGIN
# Example
# $crtCnfEndProgramm MessageText=("Create \"$crtCnfUserName\" failed. Stop program")
:global crtCnfEndProgramm do={
:global crtCnfRemoveENV
$crtCnfRemoveENV
:error message=$MessageText
}
# Block call extensions END
#
# BLOCK FUNC END
#/////////////////
# Block Promt main Variable BEGIN
# Block select VPN Profiles BEGIN
:local count 0;
:local listProfiles ""
:foreach var in=[/ppp profile print as-value] do={
:set $listProfiles ("$listProfiles \r\n $count $($var->"name")");
:set $count ($count+1)
}
$PromtInput QstUser=("\r\nSelect VPN profiles (enter number): $listProfiles") VarName="crtCnfovpnProfile" DefaultValue=$crtCnfovpnProfile LenValue=0
if ([:typeof $crtCnfovpnProfile] = "num") do={
:set $crtCnfovpnProfile ([/ppp profile get number=$crtCnfovpnProfile value-name=name])
}
:local ServerAddressLocal ([/ppp profile get [/ppp profile find where name=$crtCnfovpnProfile] value-name="local-address"])
:local nameFolderConfLocal $crtCnfovpnProfile
# Block select VPN Profiles END
$PromtInput QstUser=("\r\nInsert type installation (1=config or 2=config-auto)") VarName="crtCnfNameConfig" DefaultValue="1" LenValue=1
if ($crtCnfNameConfig="2") do={
:set $crtCnfNameConfig "config-auto"
} else={
:set $crtCnfNameConfig "config"
}
$PromtInput QstUser=("\r\nInsert external server address") VarName="crtCnfServerAddress" DefaultValue=$crtCnfServerAddress LenValue=0
$PromtInput QstUser=("\r\nInsert new username") VarName="crtCnfUserName" DefaultValue="" LenValue=0
$PromtInput QstUser=("\r\nInsert new password") VarName="crtCnfPassword" DefaultValue="" LenValue=0
# Block select CA BEGIN
:local count 0;
:local listCA ""
:foreach var in=[/certificate print as-value where trusted=yes] do={
:set $listCA ("$listCA \r\n $count $($var->"name")");
:set $count ($count+1)
}
$PromtInput QstUser=("\r\nSelect CA (enter number): $listCA") VarName="crtCnfcaName" DefaultValue=$crtCnfcaName LenValue=0
if ([:typeof $crtCnfcaName] = "num") do={
:set $crtCnfcaName ([/certificate get number=$crtCnfcaName value-name=name])
}
# Block select CA END
$PromtInput QstUser=("\r\nInsert certificate validity period") VarName="crtCnfdaysValid" DefaultValue=$crtCnfdaysValid LenValue=0
$PromtInput QstUser=("\r\nInsert pass-phrase for key") VarName="crtCnfAskPassword" DefaultValue="" LenValue=8
:put "\r\nParam:"
:put ("Type instalation: $crtCnfNameConfig")
:put ("Local folder name: $nameFolderConfLocal")
:put ("External server address:$crtCnfServerAddress")
:put ("VPN profile: $crtCnfovpnProfile")
:put ("Local address: $ServerAddressLocal")
:put ("CA name: $crtCnfcaName")
:put ("User: $crtCnfUserName")
:put ("Password: $crtCnfPassword")
:put ("Pass-phrase: $crtCnfAskPassword")
:put ("Validity period: $crtCnfdaysValid days")
$PromtInput QstUser=("\r\nPlease enter \"y\" for continue or press enter for cancel") VarName="crtCnfContinue" DefaultValue=false LenValue=0
if ($crtCnfContinue=false) do={
$crtCnfEndProgramm MessageText=("You press cancel. Stop program")
}
:put "Run programm"
# Block Promt main Variable END
# Block add user BEGIN
if ([:len [/ppp secret find where name=$crtCnfUserName]]=0) do={
do {
/ppp secret add name=$crtCnfUserName password=$crtCnfPassword profile=$crtCnfovpnProfile service=ovpn
} on-error={
$crtCnfEndProgramm MessageText=$MessageText
}
} else={
$crtCnfEndProgramm MessageText=("User \"$crtCnfUserName\" is exist. Stop program")
}
# Block add user END
# Block create folder tree BEGIN
$crtCnfCreateTree $nameFolderConfLocal $crtCnfUserName $NameOrg;
# File create very quikly, need wait
:delay 1
if ([:len [/file find where name=$crtCnfFullPath]]>0) do={
:put ("Current full path \"".$crtCnfFullPath."\"")
} else={
$crtCnfEndProgramm MessageText=("Full path \"".$crtCnfFullPath."\" is not exist. Stop program")
}
# Block create folder tree END
# Block CERT BEGIN
# Block generate cert BEGIN
if ([:len [/certificate find where name=$crtCnfUserName]]>0) do={
:put ("Cert \"$crtCnfUserName\" is exist.")
} else={
:local CA [/certificate get $crtCnfcaName]
:if ([:typeof $CA]="array" && [:len $CA]>="0") do={
do {
:put $crtCnfUserName
:put $CA
/certificate add name=$crtCnfUserName country=($CA->"country") state=($CA->"state") locality=($CA->"locality") organization=($CA->"organization") unit=($CA->"unit") common-name=$crtCnfUserName key-size=2048 days-valid=$crtCnfdaysValid key-usage=tls-client
/certificate sign $crtCnfUserName ca=$crtCnfcaName
} on-error={
$crtCnfEndProgramm MessageText=("Issue create or sign cert \"$crtCnfUserName\". Stop program")
}
} else={
$crtCnfEndProgramm MessageText=("CA \"$crtCnfcaName\" is not exist. Stop program")
}
}
# Block generate cert END
# Block export cert BEGIN
do {
/certificate export-certificate $crtCnfUserName type=pkcs12 file-name=("$nameFolderConfLocal/$crtCnfUserName/$NameOrg/$crtCnfUserName") export-passphrase=$crtCnfAskPassword
} on-error={
$crtCnfEndProgramm MessageText=("Issue export cert. Stop program")
}
# Block export cert END
# Block CERT END
# Block export config files BEGIN
# Block create oVPN file BEGIN
:local contents
:set contents ($contents."client")
:set contents ($contents."\r\ndev tun")
:set contents ($contents."\r\nproto tcp")
:set contents ($contents."\r\nremote $crtCnfServerAddress")
:set contents ($contents."\r\npersist-key")
:set contents ($contents."\r\npersist-tun")
:set contents ($contents."\r\nauth-nocache")
:set contents ($contents."\r\npkcs12 \"C:\\\\Program Files\\\\OpenVPN\\\\$crtCnfNameConfig\\\\$NameOrg\\\\$crtCnfUserName.p12\"")
:set contents ($contents."\r\naskpass \"C:\\\\Program Files\\\\OpenVPN\\\\$crtCnfNameConfig\\\\$NameOrg\\\\1.cfg\"")
if ($crtCnfNameConfig="config-auto") do={
:set contents ($contents."\r\nauth-user-pass \"C:\\\\Program Files\\\\OpenVPN\\\\$crtCnfNameConfig\\\\$NameOrg\\\\2.cfg\"")
} else={
:set contents ($contents."\r\nauth-user-pass")
}
:set contents ($contents."\r\nlog \"C:\\\\Program Files\\\\OpenVPN\\\\$crtCnfNameConfig\\\\$NameOrg\\\\$NameOrg.log\"")
:set contents ($contents."\r\nremote-cert-tls server")
:set contents ($contents."\r\nroute $RouteAddressAdd 255.255.255.255 $ServerAddressLocal")
:set contents ($contents."\r\ncipher AES-256-CBC")
:put "\r\n______________________"
:put "Config begin"
:put "______________________"
:put $contents
:put "______________________"
:put "Config end"
:put "______________________\r\n"
$CreateFile FileName=("$nameFolderConfLocal/$crtCnfUserName/$NameOrg_$crtCnfUserName.ovpn") Contents=$contents
# Block create oVPN file END
# Block create auth-user-pass file BEGIN
if ($crtCnfNameConfig="config-auto") do={
:set contents ""
:set contents ($contents.$crtCnfUserName)
:set contents ($contents."\r\n$crtCnfPassword")
$CreateFile FileName=("$nameFolderConfLocal/$crtCnfUserName/$NameOrg/2.cfg") Contents=$contents
}
# Block create auth-user-pass file END
# Block create ask-pass file BEGIN
$CreateFile FileName=("$nameFolderConfLocal/$crtCnfUserName/$NameOrg/1.cfg") Contents=$crtCnfAskPassword
# Block create ask-pass file END
# Block export config files END
$crtCnfRemoveENV
:put "END PROGRAMM"
При создании скрипта использовались старые наработки - удаление глобальных переменных, а также новые функции:
В картинках:
Комментариев нет:
Отправить комментарий