пятница, 15 мая 2015 г.

Простой скрипт для управления OpenSSL и создания своего центра сертификации.

Настройка почтового сервера
DOVECOT + POSTFIX + OPENSSL + MySQL

Часть 0. Подготовительная — настройка OpenSSL и генерация сертификатов.

В этой заметке я расскажу о том, как настроить на своем сервере почтовый сервер. Все действия происходят на сервере Ubuntu 10.04 Server, в среде виртуализации под управлением OpenVZ.
За основу я взял статью «SSL HOWTO», и автоматизировал процесс с помощью perl скрипта.
root@poligon:~# lsb_release -d -r -c   
Description: Ubuntu 10.04 LTS
Release: 10.04
Codename: lucid
root@poligon:~# uname -a
Linux poligon 2.6.18-194.8.1.el5.028stab070.2 #1 SMP Tue Jul 6 15:26:41 MSD 2010 i686 GNU/Linux
Я не буду много рассказывать о том, зачем и как пользоваться SSL, частично об этом можно прочитать по ссылке выше. Мною был написан скрипт, который по возможности автоматизирует процесс создания сертификатов на основе этой статьи. Это особенно полезно, если у вас несколько разных доменов, использующих шифрование. Zip-архив со скриптом можно скачать

Файл конфигурации для OpenSSL
 
[ ca ]
 
default_ca       = CA_default     # Название секции, в которой содержатся данные о центре сертификации
 
[ CA_default ]
 
#output_password          = $ENV::KEY_PASS # Поидее, пароль можно тоже передавать через переменные среды, но у меня как то не вышло.
dir       = .       # Рабочая директория
certs   = $dir/certs       # Папка для сертификатов
database  = $dir/index.db    # База Данных для сертификатов
new_certs_dir    = $dir/pemcerts       # Хранилище для pem сертификатов
certificate      = $dir/ca/rootCA.crt      # Путь к корневому сертификату
serial    = $dir/serial.db      # Файл с текущим серийным номером
private_key      = $dir/ca/rootCA.key    # Путь к ключу корневого сертификата
 
default_days     = 3650     # На сколько подписываем сертификаты
default_crl_days = 30      # Время до следующего CRL
default_md       = md5    # Какую md используем
Preserve  = no      # Сохранять ли последовательность DN (Distinguished Name)
policy    = policy_match   # Секция, содержащая политику подписи
 
# For the CA policy
 
[ policy_match ]
countryName  = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName  = supplied
emailAddress  = optional
 
[ req ]
 
default_bits     = 4096 # Сложность шифра
distinguished_name      = req_distinguished_name # Секция,задающая DN получателя сертификата
#output_password         = $ENV::KEY_PASS
 
[ req_distinguished_name ]
 
countryName      = Country Name (2 letter code) # Страна 
countryName_default      = RU    # По умолчанию - Россия
countryName_min   = 2    # 2 минимум
countryName_max   = 2    # 2 максимум
stateOrProvinceName      = State or Province Name (full name) # Страна или штат, полное название 
stateOrProvinceName_default = Russia   # Россия
localityName     = Locality Name (eg, city)  # Расположение (например, город)
localityName_default     = Moscow   # Дефолт сити
organizationName       = Organization Name (eg, company) # Название организации
organizationName_default = ScayTrase Personal  # Поменяйте на свое
organizationalUnitName   = Organizational Unit Name (eg, section) # Подразделение организации
organizationalUnitName_default = Security Team   # Тут тоже поменяйте
commonName       = [Sub]Domain Name  # В commonName надо записать имя домена. Именно его будут сверять при просмотре сертификата, например, браузером.
commonName_default       = $ENV::KEY_COMMON  # Имя домена передаем через переменные среды, через скрипт
commonName_max   = 64    # Максимум 64 символа, у меня длинных доменов не было
emailAddress     = Email Address   # еМыло
emailAddress_default     = pavel.batanov@scaytrase.ru # Поменяйте на свое
emailAddress_max         = 40    # Максимальная длина еМыла
 
[ v3_ca]
 
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
basicConstraints = CA:true
Сам скрипт автоматизации для работы с OpenSSL
#!/usr/bin/perl -w
#########################################
# Павел Батанов (С) 2010 год.  #
# Распространяется как есть, без каких  #
# либо гарантий.   #
# Если у вас есть какие либо пожелания  #
# или предложения по модификации этого  #
# скрипта - пишите    #
# pavel.batanov@scaytrase.ru  #
#########################################
 
($#ARGV > -1) || die 
"Usage:\n
 --rs <DOMAIN> Request and sign domain.crt using rootCA.crt created with --ca option or other way.\n
 --ca   Request and sign rootCA.crt - root certificate for signing other.\n
 --prepare Create neccessary folders.\n
 --usage  Display text about how to use this scripit.\n
";
 
# Подпись сертификата 
if ($ARGV[0] =~ /--rs/)
{
 ($#ARGV > 0) || die "Provide Domain Name"; # Завершить работу, если не был передн домен на подпись
 $domain_name = $ARGV[1]; # Используем второй параметр, как имя домена. Здесь нет проверок и защиты от дурака, только кавычки в вызове функции
 $request_config = "./config.ini"; # Путь к конфигурационному файлу с настройками
 $ENV{'KEY_COMMON'} = $domain_name; # Передача параметра домена в конфигурационный файл через переменные среды ( Посмотрите конф. файл )
 # Команда запроса сертификата на подпись 
 $request = "openssl req -new -nodes -out \"$domain_name.csr\" -keyout \"$domain_name.key\" -config $request_config"; 
 system($request) && die ("\nCertificate $domain_name request failed"); # Попытка выполнить команду
 # Команад подписи запроса с помощью коренвого сертификата
 $sign = "openssl ca -batch -out \"$domain_name.crt\" -config $request_config -infiles \"$domain_name.csr\" ";
 # Попытка подписать запрос
 system($sign) && die ("\nCertificate $domain_name sign failed");
 # В случае успеха перемещаем результаты по папкам
 system("mv $domain_name.crt certs/"); # Сам сертификат, публичная информация, можно передавать другим лицам
 system("mv $domain_name.csr csr/");  # Файл запроса сертификата. Нужен, когда время действия сертификата или корневого сертификата истечет, 
      # и надо будет снова подписать запрос.
 system("mv $domain_name.key keys/"); # Ключ сертификата. Приватная информация, в отличие от самого файла сертификата
 exit(0);
}
 
# Генерация корневого сертификата
if ($ARGV[0] =~ /--ca/)
{
 $ca_config = "./config.ini"; # Конфигурационный файл
 $days = "3650"; # Создаем сертификат на 3650 дней
 $ENV{'KEY_COMMON'} = 'poligon.scaytrase.ru'; # Общее имя для сертификата. Я указал тут имя своего главного домена. Можно указать название организации. Это имя будет отображаться в программах, как организация, подписавшая сертификат.
 # Команда генерации корневого сертификата
 $ca = "openssl req -new -x509 -extensions v3_ca -keyout ca/rootCA.key -out ca/rootCA.crt -days $days -config $ca_config";
 system($ca) && die ("CA request failed"); # Попытка выполнить команду
 exit(0);
}
 
# Создание необходимых файлов и директорий
if ($ARGV[0] =~ /--prepare/)
{
 system ("mkdir ./ca"); # Директория корневого сертификата
 system ("mkdir ./certs"); # Директория готовых сертификатов
 system ("mkdir ./pemcerts"); # Директория для сертификатов в формате pem
 system ("mkdir ./keys"); # Директория для ключей сертификатов
 system ("mkdir ./csr"); # Директория для файлов запроса
 system ("touch index.db"); # Индексный файл. Своеобразная база данных.
 system ("touch serial.db"); # Файл с последним номером
 system ("echo \"01\" > serial.db"); # Первый сертификат будет иметь номер 01
 exit(0);
}
 
# Переподписывание сертификатов
#if ($ARGV[0] =~ /--resign/)
#{
# ($#ARGV > 0) || die "Provide Domain Name"; # Завершить работу, если не был передн домен на подпись
# $domain_name = $ARGV[1]; # Используем второй параметр, как имя домена. Здесь нет проверок и защиты от дурака, только кавычки в вызове функции
# $request_config = "./config.ini"; # Путь к конфигурационному файлу с настройками
# $ENV{'KEY_COMMON'} = $domain_name; # Передача параметра домена в конфигурационный файл через переменные среды ( Посмотрите конф. файл )
 
# $sign = "openssl ca -batch -out \"$domain_name.crt\" -config ./$request_config -infiles \"csr/$domain_name.csr\" ";
 # Попытка подписать запрос
# system($sign) && die ("\nCertificate $domain_name sign failed");
 # В случае успеха перемещаем результаты по папкам
# system("mv $domain_name.crt certs/"); # Сам сертификат, публичная информация, можно передавать другим лицам
# system("mv $domain_name.csr csr/");  # Файл запроса сертификата. Нужен, когда время действия сертификата или корневого сертификата истечет, 
      # и надо будет снова подписать запрос.
# system("mv $domain_name.key keys/"); # Ключ сертификата. Приватная информация, в отличие от самого файла сертификата
# exit(0);
#}
 
# Хелп по вызову
if ($ARGV[0] =~ /--usage/)
{
 print STDOUT "\nЭтот скрипт автоматизирует процесс запроса, генерации и подписи сертификатов на основе самоподписанного корневого сертификата, который можно сгенерировать им же. Используйте вызов --prepare для того чтобы подготовить нужные файлы и папки для генерации, затем --ca для создания главного коренвого сертификата. После этого вы можете создать сертификат для каждого уникального домена (CommonName) с помощью опции --rs <domainname>";
 print STDOUT "\n";
 exit(0);
}
 
die 
"Usage:\n
 --rs <DOMAIN> Request and sign domain.crt using rootCA.crt created with --ca option or other way.\n
 --ca   Request and sign rootCA.crt - root certificate for signing other.\n
 --prepare Create neccessary folders.\n
 --usage  Display text about how to use this scripit.\n
";
Буду рад советам и замечаниям по разделу.
Если кто модифицирует код в сторону повышения качества\функционала — поделитесь обратно, если не жалко.


Автор: