Skip to main content

Простой скрипт для управления 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
";

Буду рад советам и замечаниям по разделу.
Если кто модифицирует код в сторону повышения качества\функционала — поделитесь обратно, если не жалко.