Add ssl_mgmt script
This commit is contained in:
parent
6c5525185c
commit
2b6d07e80b
|
@ -0,0 +1,70 @@
|
||||||
|
ssl_mgmt is a helper to manage ssl certificate: creation, renewal and removal.
|
||||||
|
So far, only renewal is supported.
|
||||||
|
|
||||||
|
ssl_mgmt refers to certificates through the service they are associated with.
|
||||||
|
|
||||||
|
*** EXAMPLES ***
|
||||||
|
|
||||||
|
To renew the certificate associated to https, the command line is:
|
||||||
|
ssl_mgmt renew https
|
||||||
|
|
||||||
|
If you want to renew certificates of all services, you should do:
|
||||||
|
ssl_mgmt renew all
|
||||||
|
|
||||||
|
Note: This suppose that
|
||||||
|
* all services are listed in /root/homemade_certs;
|
||||||
|
* directories have special rights so that newly created certificates
|
||||||
|
automatically get proper rights;
|
||||||
|
* Root CA is already created
|
||||||
|
* openssl.cnf.in is copied at the root of the CA hierarchy
|
||||||
|
|
||||||
|
The file system hierarchy assumed is:
|
||||||
|
lrwxrwxrwx 1 root root 14 6 janv. 2010 certs -> /etc/ssl/certs
|
||||||
|
drws--S---+ 2 root ssl-cert 4096 23 janv. 2011 csr
|
||||||
|
-rw------- 1 root ssl-cert 1937 20 févr. 16:38 index.txt
|
||||||
|
-rw------- 1 root ssl-cert 20 20 févr. 16:38 index.txt.attr
|
||||||
|
drwSr-Sr--+ 2 root ssl-cert 4096 20 févr. 16:38 newcerts
|
||||||
|
drwSr-S---+ 2 root ssl-cert 4096 20 févr. 16:38 newkeys
|
||||||
|
-rw-r--r-- 1 root ssl-cert 1546 20 févr. 14:24 openssl.cnf.in
|
||||||
|
lrwxrwxrwx 1 root root 16 6 janv. 2010 private -> /etc/ssl/private
|
||||||
|
-rw------- 1 root ssl-cert 3 20 févr. 16:38 serial
|
||||||
|
|
||||||
|
About csr, newcerts and newkeys:
|
||||||
|
|
||||||
|
# file: usr/lib/ssl/CA/csr
|
||||||
|
# owner: root
|
||||||
|
# group: ssl-cert
|
||||||
|
# flags: ss-
|
||||||
|
user::rwx
|
||||||
|
group::---
|
||||||
|
other::---
|
||||||
|
default:user::rw-
|
||||||
|
default:group::r--
|
||||||
|
default:other::---
|
||||||
|
|
||||||
|
# file: usr/lib/ssl/CA/newcerts
|
||||||
|
# owner: root
|
||||||
|
# group: ssl-cert
|
||||||
|
# flags: ss-
|
||||||
|
user::rw-
|
||||||
|
group::r--
|
||||||
|
other::r--
|
||||||
|
default:user::rw-
|
||||||
|
default:group::r--
|
||||||
|
default:other::r--
|
||||||
|
|
||||||
|
# file: usr/lib/ssl/CA/newkeys
|
||||||
|
# owner: root
|
||||||
|
# group: ssl-cert
|
||||||
|
# flags: ss-
|
||||||
|
user::rw-
|
||||||
|
group::r--
|
||||||
|
other::---
|
||||||
|
default:user::rw-
|
||||||
|
default:group::r--
|
||||||
|
default:other::---
|
||||||
|
|
||||||
|
To use this script, you have to be root, or to be able to execute
|
||||||
|
commands with root privileges through sudo.
|
||||||
|
You should install it in a directory within the PATH of the root user,
|
||||||
|
such as /usr/local/sbin.
|
|
@ -0,0 +1,62 @@
|
||||||
|
#
|
||||||
|
# OpenSSL configuration file.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Establish working directory
|
||||||
|
dir = .
|
||||||
|
|
||||||
|
[ ca ]
|
||||||
|
default_ca = CA_Default
|
||||||
|
|
||||||
|
[ CA_Default ]
|
||||||
|
serial = $dir/serial
|
||||||
|
database = $dir/index.txt
|
||||||
|
new_certs_dir = $dir/newcerts
|
||||||
|
certificate = $dir/certs/ca-cert.pem
|
||||||
|
private_key = $dir/private/ca-key.pem
|
||||||
|
default_days = #LENGTH# # Certificates are signed for default_days days
|
||||||
|
default_md = md5
|
||||||
|
preserve = no
|
||||||
|
email_in_dn = no
|
||||||
|
nameopt = default_ca
|
||||||
|
certopt = default_ca
|
||||||
|
policy = policy_match
|
||||||
|
copy_extensions = copy
|
||||||
|
|
||||||
|
[ policy_match ]
|
||||||
|
countryName = match
|
||||||
|
stateOrProvinceName = match
|
||||||
|
organizationName = match
|
||||||
|
organizationalUnitName = optional
|
||||||
|
commonName = supplied
|
||||||
|
emailAddress = optional
|
||||||
|
|
||||||
|
[ req ]
|
||||||
|
default_bits = 2048 # Taille des clés
|
||||||
|
default_keyfile = newkeys/key.pem # Nom de la clé généré (à spécifier en ligne de commande si différent)
|
||||||
|
default_md = md5 # Algorithme de résumé (hash)
|
||||||
|
string_mask = nombstr # Caractères authorisés
|
||||||
|
prompt = no
|
||||||
|
distinguished_name = req_distinguished_name
|
||||||
|
req_extensions = v3_req
|
||||||
|
# On ne veut ces extensions que pour générer les certificats racines
|
||||||
|
# donc on le spécifie sur la ligne de commande
|
||||||
|
x509_extensions = v3_ca
|
||||||
|
|
||||||
|
[ req_distinguished_name ]
|
||||||
|
organizationName = #ORG#
|
||||||
|
organizationalUnitName = #ORGUNIT#
|
||||||
|
localityName = #LOCALITY#
|
||||||
|
stateOrProvinceName = #STATE#
|
||||||
|
countryName = #COUNTRY#
|
||||||
|
commonName = #COMMONNAME#
|
||||||
|
|
||||||
|
[ v3_ca ]
|
||||||
|
basicConstraints = CA:TRUE
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
authorityKeyIdentifier = keyid:always,issuer:always
|
||||||
|
|
||||||
|
[ v3_req ]
|
||||||
|
basicConstraints = CA:FALSE
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
subjectAltName = #ALTNAME#
|
|
@ -0,0 +1,253 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# ssl_mgmt, Copyright © 2012 Thomas Preud'homme
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# email_account is a helper to create e-mail accounts in a configuration
|
||||||
|
# using Postfix mail transport agent with vhosts and Cyrus IMAP server,
|
||||||
|
# in a Debian environment.
|
||||||
|
|
||||||
|
set -u
|
||||||
|
|
||||||
|
confFile=openssl.cnf
|
||||||
|
|
||||||
|
# Display usage.
|
||||||
|
usage ()
|
||||||
|
{
|
||||||
|
local - progname
|
||||||
|
progname=$1
|
||||||
|
echo "Usage :"
|
||||||
|
echo
|
||||||
|
echo "$progname renew <service>"
|
||||||
|
echo "$progname -h"
|
||||||
|
echo
|
||||||
|
echo "First form renew the certificate of the given service"
|
||||||
|
echo
|
||||||
|
echo "Second form prints this help."
|
||||||
|
}
|
||||||
|
|
||||||
|
# @param question Question to ask
|
||||||
|
# @return 0 if answer is positive, 1 else
|
||||||
|
#
|
||||||
|
# Ask question to the user with a default choice set to no.
|
||||||
|
ask_user_default_no ()
|
||||||
|
{
|
||||||
|
local - answer
|
||||||
|
answer="unset"
|
||||||
|
echo -n "$1 [y/N] "
|
||||||
|
while [ -n "$answer" -a "$answer" != "y" -a "$answer" != "Y" -a "$answer" != "n" -a "$answer" != "N" ]
|
||||||
|
do
|
||||||
|
read answer
|
||||||
|
if [ -z "$answer" -o "$answer" = "n" -o "$answer" = "N" ]
|
||||||
|
then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ "$answer" = "y" -o "$answer" = "Y" ]
|
||||||
|
then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo -n "$2 [y/N] "
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test number of argument is correct and their value are correct also.
|
||||||
|
test_args ()
|
||||||
|
{
|
||||||
|
local - user domain
|
||||||
|
while getopts "h" opt
|
||||||
|
do
|
||||||
|
case $opt in
|
||||||
|
"h")
|
||||||
|
if [ $# -gt 1 ]
|
||||||
|
then
|
||||||
|
echo "Error! Too many arguments." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
usage $(basename "$0")
|
||||||
|
exit 0 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
if [ $# -ne 2 -o "$1" != "renew" ]
|
||||||
|
then
|
||||||
|
usage $(basename "$0")
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
eval service="\$$((OPTIND+1))"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Are we root?
|
||||||
|
must_sudo ()
|
||||||
|
{
|
||||||
|
uid="$(id -u)"
|
||||||
|
[ ! $uid -eq 0 ]
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# This function tries to become root with sudo and execute this script.
|
||||||
|
# NB: This function doesn't return.
|
||||||
|
try_sudo ()
|
||||||
|
{
|
||||||
|
local - ret
|
||||||
|
echo "You aren't root. Trying to use sudo to become root…"
|
||||||
|
sudo $0 "$@" # Try to execute the script with sudo
|
||||||
|
ret=$?
|
||||||
|
if [ ! $ret -eq 0 ]
|
||||||
|
then
|
||||||
|
echo "Error! You must be root or being able to become root by sudo without password to create an email account or add an email alias." >&2
|
||||||
|
fi
|
||||||
|
exit $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
get_field_from_line ()
|
||||||
|
{
|
||||||
|
local - line field result
|
||||||
|
|
||||||
|
line="$1"
|
||||||
|
field="$2"
|
||||||
|
result="${line#*$field=}"
|
||||||
|
echo "${result%%/*}"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_cert_params ()
|
||||||
|
{
|
||||||
|
local - subject issuer dates ext fromDate toDate
|
||||||
|
|
||||||
|
certFile="/etc/ssl/certs/${service}-cert.pem"
|
||||||
|
subject="$(openssl x509 -in "$certFile" -noout -subject)"
|
||||||
|
dates="$(openssl x509 -in "$certFile" -noout -dates)"
|
||||||
|
exclNoExt="-certopt no_header,no_version,no_serial,no_signame"
|
||||||
|
exclNoExt="$exclNoExt,no_validity,no_subject,no_issuer,no_pubkey"
|
||||||
|
exclNoExt="$exclNoExt,no_sigdump,no_aux"
|
||||||
|
altName="$(openssl x509 -in "$certFile" -text $exclNoExt | while read ext
|
||||||
|
do
|
||||||
|
if [ "$ext" = "X509v3 Subject Alternative Name:" ]
|
||||||
|
then
|
||||||
|
read altName
|
||||||
|
echo $altName
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done)"
|
||||||
|
country=$(get_field_from_line "$subject" "C")
|
||||||
|
state=$(get_field_from_line "$subject" "ST")
|
||||||
|
city=$(get_field_from_line "$subject" "L")
|
||||||
|
organization=$(get_field_from_line "$subject" "O")
|
||||||
|
unit=$(get_field_from_line "$subject" "OU")
|
||||||
|
commonName=$(get_field_from_line "$subject" "CN")
|
||||||
|
fromDate=${dates#*notBefore=}
|
||||||
|
fromDate=${fromDate%notAfter*}
|
||||||
|
fromDate=$(date -d "$fromDate" "+%s")
|
||||||
|
toDate=${dates#*notAfter=}
|
||||||
|
toDate=$(date -d "$toDate" "+%s")
|
||||||
|
days=$(($toDate-$fromDate))
|
||||||
|
days=$(($days/86400))
|
||||||
|
}
|
||||||
|
|
||||||
|
add_to_replace_cmd ()
|
||||||
|
{
|
||||||
|
local - replaceCmd key value
|
||||||
|
|
||||||
|
replaceCmd="$1"
|
||||||
|
key="$2"
|
||||||
|
value="$3"
|
||||||
|
if [ -n "$value" ]
|
||||||
|
then
|
||||||
|
echo "$replaceCmd${replaceCmd:+;}s/$key/$value/"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_config ()
|
||||||
|
{
|
||||||
|
local - replaceCmd cnfTmpFile
|
||||||
|
|
||||||
|
replaceCmd="$(add_to_replace_cmd "${replaceCmd:-}" "#LENGTH#" "${days:-}")"
|
||||||
|
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#ORG#" "${organization:-}")"
|
||||||
|
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#ORGUNIT#" "${unit:-}")"
|
||||||
|
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#LOCALITY#" "${city:-}")"
|
||||||
|
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#STATE#" "${state:-}")"
|
||||||
|
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#COUNTRY#" "${country:-}")"
|
||||||
|
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#COMMONNAME#" "${commonName:-}")"
|
||||||
|
replaceCmd="$(add_to_replace_cmd "$replaceCmd" "#ALTNAME#" "${altName:-}")"
|
||||||
|
sed "$replaceCmd" $confFile.in > $confFile
|
||||||
|
if ask_user_default_no "Do you want to edit the openssl configuration file?"
|
||||||
|
then
|
||||||
|
if [ -z "${EDITOR:-}" ]
|
||||||
|
then
|
||||||
|
$EDITOR $confFile
|
||||||
|
else
|
||||||
|
editor $confFile
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
cnfTmpFile="$(mktemp --tmpdir=. openssl.cnf.XXXXXXXXXX)"
|
||||||
|
mv $confFile $cnfTmpFile
|
||||||
|
grep -v "#[A-Z]\+#" $cnfTmpFile > $confFile
|
||||||
|
rm $cnfTmpFile
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_cert ()
|
||||||
|
{
|
||||||
|
openssl req -new -nodes -out csr/${service}-req.pem -keyout newkeys/${service}-key.pem -config $confFile
|
||||||
|
openssl req -in csr/${service}-req.pem -text -verify -noout
|
||||||
|
if ! ask_user_default_no "Is the Certificate Signing Request correct?"
|
||||||
|
then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
mv newkeys/${service}-key.pem private
|
||||||
|
openssl ca -batch -out newcerts/${service}-cert.pem -config $confFile -passin file:/root/passwords/root_ca -infiles csr/${service}-req.pem
|
||||||
|
mv newcerts/${service}-cert.pem certs
|
||||||
|
cat private/${service}-key.pem certs/${service}-cert.pem > private/${service}-keycert.pem
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
local - ret servicesok
|
||||||
|
ret=0
|
||||||
|
test_args "$@"
|
||||||
|
# This test should be useless if rights on this file are corrects
|
||||||
|
# (that is 770 for root:gt owner)
|
||||||
|
if must_sudo
|
||||||
|
then
|
||||||
|
try_sudo "$@"
|
||||||
|
fi
|
||||||
|
cd /usr/lib/ssl/CA/
|
||||||
|
if [ "${service}" = "all" ]
|
||||||
|
then
|
||||||
|
services=""
|
||||||
|
while read service
|
||||||
|
do
|
||||||
|
services="$services $service"
|
||||||
|
done </root/homemade-certs
|
||||||
|
else
|
||||||
|
services=${service}
|
||||||
|
fi
|
||||||
|
for service in $services
|
||||||
|
do
|
||||||
|
servicesok=""
|
||||||
|
get_cert_params
|
||||||
|
generate_config
|
||||||
|
if ! generate_cert
|
||||||
|
then
|
||||||
|
ret=1
|
||||||
|
else
|
||||||
|
servicesok="$servicesok${servicesok:+ }$service"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "You should restart the following services: $servicesok"
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
main "${@:-""}"
|
||||||
|
exit $?
|
Loading…
Reference in New Issue