Last active
October 5, 2020 05:25
-
-
Save ThinGuy/44b5cc260ebf4aa539d2b53393c32e3a to your computer and use it in GitHub Desktop.
Self Signed Cert Script - multi-host, multi-ip, multi-domain, and wilcard certs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# vim: set et ts=2 sw=2 filetype=bash : | |
# | |
# Copyright (C) 2020 Craig Bender | |
# | |
# Author(s): Craig Bender <[email protected]> | |
# | |
# 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, version 3 of the License. | |
# | |
# 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. | |
# | |
# If you did not receive a copy of the GNU General Public License | |
# along with this program, see <http://www.gnu.org/licenses/>. | |
# | |
## Updated 4 Oct 2020: | |
# - Change file name in help/examples to reflect actual filename | |
# - Start of work to include Online Certificate Status Protocol (OCSP) capabilities | |
# - Start of work to include Certificate Revocation Lists (CRLs) capabilities | |
## Updated 17 Sep 2020: | |
# - Create a wildcard cert that does not have an * in the CN, rather | |
# put all wildcard entries in the SAN list | |
# - Add new option to manually set the host cert's CN ( --subject-name ) | |
# for more control over wildcard certs | |
# - Remove mandatory sudo rights requirement | |
# only -a, --auto-add requires running with superuser access | |
## Updated 29 Jan 2020: | |
# - Fix missing getopt args for custom issuers/subjects | |
## Updated 29 Dec 2019: | |
# - Added extendedKeyUsage=serverAuth,clientAuth directives to v3_req and usr_cert sections | |
# - Added keyUsage = nonRepudiation, digitalSignature, keyEncipherment to usr_cert section | |
# - Added -a,--auto-add option to copy files to common locations (e.g. /usr/local/share/ca-certificates/, /etc/ssl/certs/, and /etc/ssl/private/) | |
# - Added -P,--prefix option to give created files a given prefix rather than the default of CN | |
# - Create README with useful information about the certs created | |
# - Create sample cloud-init yaml files for use with MAAS, Juju, and LXD | |
## Updated 27 Dec 2019: | |
# - Fixed missing default ISSUER_* and SUBJ_* parameters which caused | |
# the following SSL error: "SSL: couldn't get X509-issuer name!" | |
## Updated 3 Dec 2019: | |
# - Added -l,--localhost option so localhost, 127.0.0.1, and 127.0.1.1 are willfully added | |
# - Added -p,--private option for private top-level-domain namespaces (.corp .home .internal .intranet .lan .private .test) | |
# - Fixed logic for conflicting options | |
# - Fixed wildcard domain handling | |
# - Fixed single-label domain name handling | |
# - Added more information while script is processing. | |
## Updated 10 Oct 2019: | |
# - Root CA/Key now kept so it can be used for future csr/cert/key signing | |
# - Clean up of wildcard domains | |
# - Added localhost addresses (127.0.0.1 127.0.1.1) to DNS based SANs (was only in IP SANs before) | |
# - Options for for custom issuers/subjects | |
# - Cleaned up usage to (mostly) fit in 80 char terminal | |
export PROG=${0##*/} PROG_PATH="$(cd $(dirname ${0}) && pwd)/$(echo -n ${0##*/})" | |
DESC="\n\e[1m${0##*/}\e[0m - Create CA certs, host certs, and RSA keys for\n\e[23GMulti-Hostname and Multi-Domain self-signed SSL\n\e[23Gcertificates, including wildcard certs\n" | |
[[ $1 = '--desc' ]] && { printf "${DESC}";return; } | |
Usage() { | |
printf -- "${DESC}\n" | |
printf -- "Usage: ${PROG_PATH} -s <FQDN> [ OPTIONS ]\n\e[0m" | |
printf -- "\nOptions:\n\n\e[0m" | |
printf -- " -s --site \e[21GPrimary FQDN that this ssl cert should be valid for\n\n" | |
printf -- " -n, --names \e[21GSpace or comma separated list of all FQDNs that this\n\e[21Gssl cert should be valid for (enclose space eparated\n\e[21Gslist in quotes)\n\n" | |
printf -- " -i, --ips \e[21GSpace or comma separated list of IP addresses to\n\e[21Ginclude as a Subject Alternative Name (SAN) (enclose space\n\e[21Gseparated list in quotes)\n\n" | |
printf -- " -d, --domains \e[21GSpace or comma separated list of domain names to\n\e[21Ginclude as a wildcard entry in Subject Alternative\n\e[21GName (SAN) (enclose space separate list in quotes)\n\n" | |
printf -- " -l, --local \e[21GInclude DNS and IP entries for localhost, 127.0.0,1, and\n\e[21G127.0.1.1\n\n" | |
printf -- " -w, --wildcard \e[21GCreate wildcard entries for the domains of the\n\e[21GFQDNs provided with the -n,--names option\n\n" | |
printf -- " -p, --private \e[21GInclude Private DNS Namespaces for top-level domains\n\e[21G(.corp .home .internal .intranet .lan .private .test)\n\e[21GSee: https://tools.ietf.org/html/rfc6762#appendix-G\n\n" | |
printf -- " -P, --prefix \e[21GPrefix to give to certs,keys, etc.\n\e[21GDefault: site name given with -s,--site option\n\n" | |
printf -- " \e[0;38;2;255;200;0m-a\e[0m, \e[0;38;2;255;200;0m--auto-add\e[0m\e[21GAutomatically copy CA Cert to local CA store, host cert\n\e[21Gto /etc/ssl/certs/, and host key to /etc/ssl/private/\n\e[21G\e[1m*** \e[0;38;2;255;200;0mThis option requires root, run ${PROG} via sudo. \e[0;1m***\e[0m\n\n" | |
printf -- " --nohosts \e[21GOnly include wildcard entries in Subject Alternative Name\n\e[21G(SAN), i.e. each SAN entry would be *.example.org vs host.example.org\n\n" | |
printf -- " --san-only \e[21GDo not wildcard the host cert CN name\n\e[21Gi.e. CN for the host cert will be exactly as entered with the -s or --subject-name options instead *.example.org\n\n" | |
printf -- " --issuer-country \e[21GIssuer (CA) Country Name (2 Letter Code) \n\e[21GDefault: GB\n\n" | |
printf -- " --issuer-state \e[21GIssuer (CA) State or Province Name (Full Name) \n\e[21GDefault: England\n\n" | |
printf -- " --issuer-locality \e[21GIssuer (CA) Locality Name (i.e. City)\n\e[21GDefault: London\n\n" | |
printf -- " --issuer-org \e[21GIssuer (CA) Organization Name (i.e. Company) \n\e[21GDefault: Canonical Ltd.\n\n" | |
printf -- " --issuer-unit \e[21GIssuer (CA) Organizational Unit (i.e. Section)\n\e[21GDefault: Data Center Field Engineering\n\n" | |
printf -- " --issuer-name \e[21GIssuer (CA) Common Name (Your name or FQDN)\n\e[21GDefault: Canonical AIR stack\n\n" | |
printf -- " --subject-country \e[21GSubject (Host) Country Name (2 Letter Code) \n\e[21GDefault: GB\n\n" | |
printf -- " --subject-state \e[21GSubject (Host) State or Province Name (Full Name) \n\e[21GDefault: England\n\n" | |
printf -- " --subject-locality \e[21GSubject (Host) Locality Name (i.e. City)\n\e[21GDefault: London\n\n" | |
printf -- " --subject-org \e[21GSubject (Host) Organization Name (i.e. Company) \n\e[21GDefault: Canonical Ltd.\n\n" | |
printf -- " --subject-unit \e[21GSubject (Host) Organizational Unit (i.e. Section)\n\e[21GDefault: Data Center Field Engineering\n\n" | |
printf -- " --subject-name \e[21GSubject (Host) Common Name (Your name or FQDN)\n\e[21GDefault: FQDN provided with -s,--site arg\n\e[21Gor \*.DN of -s,--site arg\n\n\e[21G\e[1mNote\e[0m: If -s,--site is null, and no alternate\n\e[21Gnames are provided (-n, -i, -d args), the\n\e[21G--subject-name argument must start with an '*'\n" | |
printf -- "\nEx:\n\n" | |
printf -- "${PROG_PATH} \\ \n-w \\ \n-s image-server.orangebox.me \\ \n-n maas-images.orangebox.me,juju-images.orangebox.me,lxd-images.orangebox.me \\ \n-d maas.io,images.linuxcontainers.org,linuxcontainers.org \\ \n-i 172.27.20.1,172.27.20.2,172.27.20.3,172.27.20.4,172.27.20.5,172.27.20.6\n\n" | |
printf -- "\nNotes:\n\n" | |
printf -- " - Be careful of subdomains with wildcard enabled certs:\n\n\e[6GFQDN:\e[14Gserver.example.com\n\e[6GHOST:\e[14Gserver\n\e[6GDOMAIN:\e[14Gexample.com\n\n\e[6GFQDN:\e[14Gus.server.example.com\n\e[6GHOST:\e[14Gus\n\e[6GDOMAIN:\e[14Gserver.example.com\n\n\e[3m\e[6GTo ensure wildcards cover both, add example.com AND server.example.com\n\e[6Gto the -d,--domain option\e[0m\n\n" | |
printf -- " - How to use self-signed certs, testing tips, and configuration examples\n\e[4Gprovided upon completion\n\n" | |
printf -- " - Log file will be located in \${HOME}/ssl/<domain name of site>/<site>.log \n\n\e[0m" | |
printf -- " - The --nohosts option assumes -w,--wildcard \n\n\e[0m" | |
printf -- " - You can use -d,--domain with -w.--wildcard, however only unique entries will\n\e[4Gbe listed in the SAN field\n\n\e[0m" | |
} | |
tstatus() { | |
RETCODE=$(echo $?) | |
[[ $RETCODE -eq 0 ]] && printf '\e['$(($(tput cols)-10))'G [ \e[32mOK\e[0m ]\n' | |
[[ $RETCODE -eq 1 ]] && printf '\e['$(($(tput cols)-10))'G [\e[31mFAIL\e[0m]\n' | |
return $RETCODE | |
} | |
export PRIVATE=false | |
export WILDCARD=false | |
export SAN_ONLY_WC=false | |
export NOHOSTS=false | |
export LOCALHOST=false | |
export AUTOADD=false | |
unset ALT_NAMES ALT_DNS ALT_IPS ALT_DOMS WC_DOMS PREFIX README | |
unset ISSUER_C ISSUER_ST ISSUER_L ISSUER_O ISSUER_OU ISSUER_CN SUBJ_C SUBJ_ST SUBJ_L SUBJ_O SUBJ_OU | |
ARGS=`getopt -o s:n:i:d:P:awlph --long issuer-country:,issuer-state:,issuer-locality:,issuer-org:,issuer-unit:,issuer-name:,subject-country:,subject-state:,subject-locality:,subject-org:,subject-unit:,subject-name:,site:,names:,ips:,domains:,prefix:,auto-add,wildcard,localhost,private,nohosts,san-only,help -- "$@"` | |
eval set -- "$ARGS" | |
while true ; do | |
case "$1" in | |
-s|--site) export SITE="${2,,}";shift 2;; | |
-n|--names) declare -ag ALT_DNS=($(printf "%s\n" "${2//,/ }"));shift 2;; | |
-i|--ips) declare -ag ALT_IPS=($(printf "%s\n" "${2//,/ }"));shift 2;; | |
-d|--domains) declare -ag ALT_DOMS=($(printf "%s\n" "${2//,/ }"));shift 2;; | |
-l|--localhost) export LOCALHOST=true;shift 1;; | |
-p|--private) export PRIVATE=true;shift 1;; | |
-w|--wildcard) export WILDCARD=true;shift 1;; | |
-P|--prefix) export PREFIX="${2,,}";shift 2;; | |
-a|--auto-add) export AUTOADD=true;shift 1;; | |
--nohosts) export NOHOSTS=true;export WILDCARD=true;shift 1;; | |
--san-only) export SAN_ONLY_WC=true;shift 1;; | |
--issuer-country) export ISSUER_C="${2}";shift 2;; | |
--issuer-state) export ISSUER_ST="${2}";shift 2;; | |
--issuer-locality) export ISSUER_L="${2}";shift 2;; | |
--issuer-org) export ISSUER_O="${2}";shift 2;; | |
--issuer-unit) export ISSUER_OU="${2}";shift 2;; | |
--issuer-name) export ISSUER_CN="${2}";shift 2;; | |
--subject-country) export SUBJ_C="${2}";shift 2;; | |
--subject-state) export SUBJ_ST="${2}";shift 2;; | |
--subject-locality) export SUBJ_L="${2}";shift 2;; | |
--subject-org) export SUBJ_O="${2}";shift 2;; | |
--subject-unit) export SUBJ_OU="${2}";shift 2;; | |
--subject-name) export SUBJ_CN="${2}";shift 2;; | |
-h|--help) Usage;exit 0;; | |
*/?) Usage;exit 0;; | |
--) shift;break;; | |
esac | |
done | |
# Root Check | |
#[[ $EUID -ne 0 ]] && { printf 'This script requires super-user access. Please run via sudo\n\n';exit 1; } | |
# Validate that a site was given | |
[[ -z ${SITE} && -z ${SUBJ_CN} ]] && { printf 'Please provide primary site name with the -s,--site or --subject-name args\n\n';exit 1; } | |
# Set Default Subject/Issuer Fields if not provided | |
[[ -n ${ISSUER_C} ]] || export ISSUER_C='GB' | |
[[ -n ${ISSUER_ST} ]] || export ISSUER_ST='England' | |
[[ -n ${ISSUER_L} ]] || export ISSUER_L='London' | |
[[ -n ${ISSUER_O} ]] || export ISSUER_O='Canonical Ltd.' | |
[[ -n ${ISSUER_OU} ]] || export ISSUER_OU='Data Center Field Engineering' | |
[[ -n ${ISSUER_CN} ]] || export ISSUER_CN='Canonical AIR stack' | |
[[ -n ${SUBJ_C} ]] || export SUBJ_C='GB' | |
[[ -n ${SUBJ_ST} ]] || export SUBJ_ST='England' | |
[[ -n ${SUBJ_L} ]] || export SUBJ_L='London' | |
[[ -n ${SUBJ_O} ]] || export SUBJ_O='Canonical Ltd.' | |
[[ -n ${SUBJ_OU} ]] || export SUBJ_OU='Data Center Field Engineering' | |
[[ -z ${SITE} ]] && export SITE_DERIVED=true | |
[[ -n ${SUBJ_CN} ]] && export SUBJ_CN_DERIVED=false | |
[[ -n ${SITE} && -z ${SUBJ_CN} ]] && export SUBJ_CN_DERIVED=true | |
[[ ${WILDCARD} = true && ${NOHOSTS} = false ]] && { export WC_DERIVED=false WCSTR='Wildcard option selected'; } | |
[[ ${NOHOSTS} = true ]] && { export WC_DERIVED=true NHST='No hosts options selected' WCSTR='Wildcard option auto-selected (--nohosts)'; } | |
[[ ${WILDCARD} = true && ${WC_DERIVED} = true ]] && export WC_SEL_STR='Enabled via --nohosts option' | |
[[ ${WILDCARD} = true && ${WC_DERIVED} = false ]] && export WC_SEL_STR='Enabled via -w,--wildcard option' | |
SAN_VALUE=$((${#ALT_DOMS[@]}+${#ALT_IPS[@]}+${#ALT_DNS[@]})) | |
[[ ${LOCALHOST} = true ]] && SAN_VALUE=$((${SAN_VALUE}+3)) | |
[[ ${PRIVATE} = true ]] && SAN_VALUE=$((${SAN_VALUE}+6)) | |
declare -a SUBJCN_ISSUES SITE_ISSUES | |
[[ -n ${SUBJ_CN} && ${SUBJ_CN} =~ " " && ${SUBJ_CN_DERIVED} = false ]] && SUBJCN_ISSUES+=('Spaces in provided host subject name (--subject-name)') | |
[[ -n ${SUBJ_CN} && ! ${SUBJ_CN} =~ . && ${SUBJ_CN_DERIVED} = false ]] && SUBJCN_ISSUES+=('No periods to determine top-level domain in provided host subject name (--subject-name)') | |
[[ -n ${SITE} && ${SITE} =~ " " && ${SITE_DERIVED} = false ]] && SITE_ISSUES+=('Spaces in provided site name (-s,--site)') | |
[[ -n ${SITE} && ! ${SITE} =~ "\." && ${SITE_DERIVED} = false ]] && SITE_ISSUES+=('No periods in provided site name to determine top-level domain (-s,--site)') | |
[[ -z ${SITE} && ${SUBJ_CN} =~ " " && ${SITE_DERIVED} = true ]] && SITE_ISSUES+=('Spaces in derived site name') | |
[[ -z ${SITE} && ! ${SUBJ_CN} =~ "\." && ${SITE_DERIVED} = true ]] && SITE_ISSUES+=('No periods in derived site name to determine top-level domain') | |
[[ -z ${SITE} && -n ${SUBJ_CN} ]] && export SITE="${SUBJ_CN}" | |
[[ ${WILDCARD} = true && ${SAN_ONLY_WC} = false && ${SITE_DERIVED} = true && ${SAN_VALUE} -ge 1 ]] && export WC_SITE="*.${SUBJ_CN#*.}" | |
[[ ${WILDCARD} = true && ${SAN_ONLY_WC} = false && ${SITE_DERIVED} = false && ${SAN_VALUE} -ge 1 ]] && export WC_SITE="*.${SITE#*.}" | |
[[ ${WILDCARD} = true && ${SAN_ONLY_WC} = false && ${SITE_DERIVED} = true && ${SAN_VALUE} -eq 0 ]] && export WC_SITE="*.${SUBJ_CN}" | |
[[ ${WILDCARD} = true && ${SAN_ONLY_WC} = false && ${SITE_DERIVED} = false && ${SAN_VALUE} -eq 0 ]] && export WC_SITE="*.${SITE}" | |
[[ ${WILDCARD} = true && ${SAN_ONLY_WC} = true && ${SITE_DERIVED} = true ]] && export WC_SITE="${SUBJ_CN}" | |
[[ ${WILDCARD} = true && ${SAN_ONLY_WC} = true && ${SITE_DERIVED} = false ]] && export WC_SITE="${SITE}" | |
[[ ${WILDCARD} = true && ${SAN_ONLY_WC} = true && ${SITE_DERIVED} = true ]] && export WC_SITE="${SUBJ_CN}" | |
[[ ${WILDCARD} = true && ${SAN_ONLY_WC} = true && ${SITE_DERIVED} = false ]] && export WC_SITE="${SITE}" | |
[[ ${SAN_VALUE} -le 1 ]] && { | |
[[ ${SUBJ_CN} =~ " " || ${SITE} =~ " " ]] && { | |
printf "\n\e[2G\e[1m*** \e[0;38;2;255;200;0mWARNING \e[0;1m***\e[0m \e[0;38;2;255;200;0mWARNING \e[0;1m***\e[0m \e[0;38;2;255;200;0mWARNING \e[0;1m***\e[0m\n\n\e[2GThe selected option combinations of:\n\n\e[2G - Site (-s,--site): ${SITE:-null}\n\n\e[2G - Host Subject Name (--subject-name): ${SUBJ_CN}\n\n\e[2G - Wildcard (-w,--wildcard): \e[3m${WC_SEL_STR}\e[0m\n\n\e[2G - Subject Alternate Names (SAN):\n\n\e[4G - Hosts (-n,--names): ${#ALT_DNS[@]} \e[3mcount\e[0m\n\e[4G - Domain Names (-d,--domains): ${#ALT_DOMS[@]} \e[3mcount\e[0m\n\e[4G - IP Addresses (-i,--ips) ${#ALT_IPS[@]} \e[3mcount\e[0m\n\n\e[2Gwill result in a SUBJECT CN on the ${TXT:-$([[ ${WILDCARD} = true ]] && echo -n wildcard)} host certificates of \x27*.${SUBJ_CN#*.}\x27\n\e[2Gwhich may be unusable.\n\n" | |
}; } | |
# Set the working directory | |
if [[ -n ${PREFIX} ]];then | |
export CDIR=${HOME}/ssl/${PREFIX} | |
else | |
export CDIR=${HOME}/ssl/${SITE#*.} | |
fi | |
[[ ${WILDCARD} = false ]] && printf "\n\e[1mCreating a self-signed SSL certificate\e[0m\n\n" || printf "\n\e[1mCreating a self-signed Wildcard SSL certificate\e[0m\n\n" | |
printf "\e[2G- Working directory: ${CDIR}\e[0m\n\n" | |
[[ ${#ALT_DOMS[@]} -ge 1 ]] && printf "\e[2G- Domain list provided\e[0m\n\n" | |
[[ ${LOCALHOST} = true ]] && printf "\e[2G- localhost option selected\n\n\e[4G- - Adding localhost, 127.0.0.1, and 127.0.1.1 to SAN list\e[0m\n\n" | |
if [[ ${LOCALHOST} = true ]];then | |
ALT_DNS+=( localhost ) | |
ALT_IPS+=( 127.0.0.1 127.0.1.1 ) | |
fi | |
[[ ${PRIVATE} = true ]] && printf "\e[2G- private option selected\n\n\e[4G- - Adding .corp .home .internal .intranet .lan .private .test to domain list\e[0m\n\n" | |
[[ ${PRIVATE} = true ]] && ALT_DOMS+=(corp home internal intranet lan private test) | |
[[ ${NOHOSTS} = true && ${LOCALHOST} = true ]] && { printf "\e[2G- Note: --nohosts and --localhost are conflicting options.\n\n\e[4G- - Ignoring --nohosts.\e[0m\n\n"; export NOHOSTS=false; } | |
[[ ${WILDCARD} = true ]] && printf "\e[2G- ${WCSTR}\e[0m\n\n" | |
[[ ${NOHOSTS} = true ]] && printf "\e[2G- ${NHSTR}\e[0m\n\n" | |
[[ ${NOHOSTS} = true && ${#ALT_DOMS[@]} -ge 1 && ${#ALT_IP[@]} -lt 1 && ${LOCALHOST} = false ]] && printf "\e[2G- Note: Selected options will result in a wildcard only certificate\e[0m\n\n" | |
if [[ ${NOHOSTS} = true ]];then | |
#Grab domains from list of FQDNs provided | |
printf "\e[4G- - Creating wildcard SAN entries from site and name list...\e[0m\n" | |
declare -ag WC_DOMS=($(printf "%s\n" ${SITE} ${ALT_DNS[@],,}|sed -r 's/^[^\.]*\./*./g;/^$|:$/d'|sort -uV)) | |
[[ ${#ALT_DOMS[@]} -ge 1 ]] && { printf "\e[4G- - Adding wildcard entries from domain list...\e[0m\n";while IFS= read -r D;do WC_DOMS+=( "$D" );done < <(printf "*.%s\n" ${ALT_DOMS[@],,}|sort -uV); } | |
declare -ag ALT_DOMS=() | |
elif [[ ${NOHOSTS} = false && ${#ALT_DOMS[@]} -ge 1 ]];then | |
printf "\e[4G- - Creating SAN wildcard entries from domain list...\e[0m\n"; | |
declare -ag WC_DOMS=($(printf "*.%s\n" ${ALT_DOMS[@]}|sort -uV)) | |
declare -ag ALT_DOMS=() | |
fi | |
[[ ${AUTOADD} = true ]] && printf -- "\e[2G- Auto-add option selected\e[0m\n\n\e[4G- - Will copy certs to proper locations on this host only\e[0m\n\n" | |
[[ ${WILDCARD} = true && ${NOHOSTS} = false ]] && WC_DOMS+=( "*.${SITE#*.}" ) | |
#if --nohosts was selected, clear the FQDN list as it should have been processed | |
[[ ${NOHOSTS} = true ]] && declare -ag ALT_DNS=() | |
[[ ${SAN_ONLY_WC} = false ]] && declare -ag ALT_NAMES=($(printf "%s\n" ${SITE,,} ${ALT_DNS[@],,}|sort -uV)) | |
[[ ${SAN_ONLY_WC} = false ]] && declare -ag ALT_DNS=($(printf "DNS:%s\n" ${SITE,,} ${ALT_DNS[@],,} ${ALT_IPS[@]} ${ALT_DOMS[@]} ${WC_DOMS[@],,}|sort -uV)) | |
[[ ${SAN_ONLY_WC} = true ]] && declare -ag ALT_NAMES=($(printf "%s\n" ${ALT_DNS[@],,}|sort -uV)) | |
[[ ${SAN_ONLY_WC} = true ]] && declare -ag ALT_DNS=($(printf "DNS:%s\n" ${ALT_DNS[@],,} ${ALT_IPS[@]} ${ALT_DOMS[@]} ${WC_DOMS[@],,}|sort -uV)) | |
[[ ${#ALT_IPS[@]} -ge 1 ]] && declare -ag ALT_IPS=($(printf "IP:%s\n" ${ALT_IPS[@]}|sort -uV)) | |
SAN_LIST=$(printf "%s\n" ${ALT_DNS[@]} ${ALT_IPS[@]}|sort -uV|paste -sd",") | |
# Make directory if needed | |
[[ -d ${CDIR} ]] || mkdir -p ${CDIR} | |
# Create README File | |
[[ -n ${PREFIX} ]] && export README=${CDIR}/README.${PREFIX}.txt || export README=${CDIR}/README.${SITE#*.}.txt | |
[[ -f ${README} ]] && { rm -f ${README};touch ${README}; } || touch ${README} | |
if [[ -n ${PREFIX} ]];then | |
export CNF="${CDIR}/${PREFIX}.openssl.cnf" | |
export LOG="${CDIR}/${PREFIX}.log" | |
export CA_SEC_KEY="${CDIR}/${PREFIX}.ca.secure.key" | |
export CA_KEY="${CDIR}/${PREFIX}.ca.key" | |
export CA_CRT="${CDIR}/${PREFIX}.ca.crt" | |
if [[ ${WILDCARD} = false ]];then | |
export PEM="${CDIR}/${PREFIX}.host.pem" | |
export SEC_KEY="${CDIR}/${PREFIX}.host.secure.key" | |
export KEY="${CDIR}/${PREFIX}.host.key" | |
export CSR=${CDIR}/${PREFIX}.csr | |
else | |
export PEM="${CDIR}/${PREFIX}.wc.host.pem" | |
export SEC_KEY="${CDIR}/${PREFIX}.wc.host.secure.key" | |
export KEY="${CDIR}/${PREFIX}.wc.host.key" | |
export CSR="${CDIR}/${PREFIX}.wc.csr" | |
fi | |
else | |
export CNF="${CDIR}/${SITE#*.}.openssl.cnf" | |
export LOG="${CDIR}/${SITE#*.}.log" | |
export CA_SEC_KEY="${CDIR}/${SITE#*.}.ca.secure.key" | |
export CA_KEY="${CDIR}/${SITE#*.}.ca.key" | |
export CA_CRT="${CDIR}/${SITE#*.}.ca.crt" | |
if [[ ${WILDCARD} = false ]];then | |
export PEM="${CDIR}/${SITE}.host.pem" | |
export SEC_KEY="${CDIR}/${SITE}.host.secure.key" | |
export KEY="${CDIR}/${SITE}.host.key" | |
export CSR=${CDIR}/${SITE}.csr | |
else | |
export PEM="${CDIR}/${SITE#*.}.wc.host.pem" | |
export SEC_KEY="${CDIR}/${SITE#*.}.wc.host.secure.key" | |
export KEY="${CDIR}/${SITE#*.}.wc.host.key" | |
export CSR="${CDIR}/${SITE#*.}.wc.csr" | |
fi | |
fi | |
# Write information out to README | |
printf "\nScript: ${0}\n\n"|tee 1>/dev/null ${README} | |
printf "Executed on: $(date)\n\n"|tee 1>/dev/null -a ${README} | |
printf "Options Selected:\n-----------------\n"|tee 1>/dev/null -a ${README} | |
(echo ${ARGS};echo)|sed -r 's/ -| --/\n&/g'|sed 's/^.*$/ &/g'|sed '1s/^.*$/ &/;s/--$//g'|tee 1>/dev/null -a ${README} | |
printf "\nFile locations:\n---------------\n CA Certificate: ${CA_CRT}\n\n CA RSA Key: ${CA_KEY}\n\n Host SSL Certificate (PEM format): ${PEM}\n\n HOST RSA Key: ${KEY}\n\n OpenSSL Conf: ${CNF}\n\n Certificate Signing Request: ${CSR}\n\n LOG: ${LOG}\n\n"|tee 1>/dev/null -a ${README} | |
# Display Issuer/Subject/and SAN details | |
if [[ ${WILDCARD} = false ]];then | |
printf "\n\e[3G\e[1mThis SSL cert will have the following Issuer and Subject Lines:\e[0m\n\n"|tee -a ${README} | |
printf "\e[5G Issuer: C = ${ISSUER_C}, ST = ${ISSUER_ST}, L = ${ISSUER_L}, O = ${ISSUER_O}, OU = ${ISSUER_OU}, CN = ${ISSUER_CN}\n"|tee -a ${README} | |
printf "\e[5G Subject: C = ${SUBJ_C}, ST = ${SUBJ_ST}, L = ${SUBJ_L}, O = ${SUBJ_O}, OU = ${SUBJ_OU}, CN = ${SITE}\n"|tee -a ${README} | |
printf "\n\e[3G\e[1mThis SSL cert will be valid for the following names/addresses:\e[0m\n\n"|tee -a ${README} | |
printf "\e[5G -- %s\n" ${ALT_DNS[@]} ${ALT_IPS[@]}|sort -uV|tee -a ${README} | |
else | |
printf "\n\e[3G\e[1mThis Wildcard SSL cert will have the following Issuer and Subject Lines:\e[0m\n\n"|tee -a ${README} | |
printf "\e[5G Issuer: C = ${ISSUER_C}, ST = ${ISSUER_ST}, L = ${ISSUER_L}, O = ${ISSUER_O}, OU = ${ISSUER_OU}, CN = ${ISSUER_CN}\n"|tee -a ${README} | |
printf "\e[5G Subject: C = ${SUBJ_C}, ST = ${SUBJ_ST}, L = ${SUBJ_L}, O = ${SUBJ_O}, OU = ${SUBJ_OU}, CN = ${SITE}\n"|tee -a ${README} | |
printf "\n\e[3G\e[1mThis Wildcard SSL cert will be valid for the following names/addresses:\e[0m\n\n"|tee -a ${README} | |
printf "\e[5G -- %s\n" ${ALT_DNS[@]} ${ALT_IPS[@]}|sort -uV|tee -a ${README} | |
fi | |
# Create openssl configuration file | |
[[ ${WILDCARD} = false ]] && printf "\n\e[2G - Creating openssl.cnf for ${SITE#*.}" || printf "\n\e[2G - Creating openssl.cnf for ${WC_SITE}" | |
cp /etc/ssl/openssl.cnf ${CNF} | |
sed -i \ | |
-e 's|.*\(req_extensions =\)|\1|' \ | |
-e "s|\[ v3_req \]|\0\nsubjectAltName = ${SAN_LIST}\nextendedKeyUsage=serverAuth,clientAuth|" \ | |
-e "s|\[ usr_cert \]|\0\nsubjectAltName = ${SAN_LIST}\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment\nextendedKeyUsage=serverAuth,clientAuth|" \ | |
-e "/^RAND/d" \ | |
-e "/^nsComment/d" \ | |
${CNF} >> ${LOG} 2>&1;tstatus | |
# Create RSA Key for CA - Use existing Key if one exists | |
if [[ ! -f ${CA_KEY} ]];then | |
printf "\e[2G - Creating Root CA Key" | |
openssl genrsa -des3 -passout pass:1234 -out ${CA_SEC_KEY} >> ${LOG} 2>&1;tstatus | |
[[ $? -eq 0 ]] || { printf "\e[4G\e[1;31m - A critical error has occurred! \n\e[7GPlease check ${LOG}.\n\e[0m\n";exit 1; } | |
sleep 1 | |
# Remove passphrase from CA RSA key | |
printf "\e[2G - Removing passphrase from Root CA Key" | |
openssl rsa -in ${CA_SEC_KEY} -passin pass:1234 -out ${CA_KEY} >> ${LOG} 2>&1;tstatus | |
[[ $? -eq 0 ]] || exit 1 | |
sleep 1 | |
[[ -f ${CA_SEC_KEY} ]] && rm -f ${CA_SEC_KEY} | |
else | |
printf "\e[2G - Using existing Root CA Key: ${CA_KEY}\n"|tee -a ${README} | |
fi | |
# Validate non-passphrased CA RSA Key | |
printf "\e[2G - Validating Root CA Key" | |
CAKEYCHECK=$(openssl rsa -noout -in ${CA_KEY} -check) | |
[[ ${CAKEYCHECK} = "RSA key ok" ]] && { true;tstatus; } || { false;tstatus;printf '\e[1;31m\e[4G - Error validating Root CA Key! Exiting.\e[0m\n';exit 1; } | |
# Create CA Certificate - Use existing CRT if one exists | |
if [[ ! -f ${CA_CRT} ]];then | |
printf "\e[2G - Creating Root CA certificate" | |
openssl req -x509 -new -nodes -subj "/C=${ISSUER_C}/ST=${ISSUER_ST}/L=${ISSUER_L}/O=${ISSUER_O}/OU=${ISSUER_OU}/CN=${ISSUER_CN}" -extensions v3_ca -config ${CNF} -key ${CA_KEY} -sha256 -days 11499 -out ${CA_CRT} >> ${LOG} 2>&1;tstatus | |
[[ $? -eq 0 ]] || { printf "\e[4G\e[1;31m - A critical error has occurred! \n\e[7GPlease check ${LOG}.\n\e[0m\n";exit 1; } | |
else | |
printf "\e[2G - Using existing Root CA certificate: ${CA_CRT}\n"|tee -a ${README} | |
fi | |
# Create RSA Key for Host | |
[[ ${WILDCARD} = false ]] && printf "\e[2G - Creating RSA Host Key for ${SITE}" || printf "\e[2G - Creating RSA Host Key for *.${SITE#*.}" | |
openssl genrsa -des3 -passout pass:1234 -out ${SEC_KEY} >> ${LOG} 2>&1;tstatus | |
[[ $? -eq 0 ]] || { printf "\e[4G\e[1;31m - A critical error has occurred! \n\e[7GPlease check ${LOG}.\n\e[0m\n";exit 1; } | |
sleep 1 | |
# Remove passphrase from Host RSA key | |
printf "\e[2G - Removing passphrase from Host RSA key" | |
openssl rsa -in ${SEC_KEY} -passin pass:1234 -out ${KEY} >> ${LOG} 2>&1;tstatus | |
sleep 1 | |
# Validate non-passphrased Host RSA Key | |
printf "\e[2G - Validating non-passphrased Host RSA Key" | |
KEYCHECK=$(openssl rsa -noout -in ${KEY} -check) | |
[[ ${KEYCHECK} = "RSA key ok" ]] && { true;tstatus; } || { false;tstatus;printf '\e[1;31m\e[4G - Error validating RSA Key! Exiting.\e[0m\n';exit 1; } | |
[[ -f ${SEC_KEY} ]] && { rm -f ${SEC_KEY} >> ${LOG} 2>&1; } | |
# Generate Certificate Signing Request | |
if [[ ${WILDCARD} = false ]];then | |
printf "\e[2G - Generating a multihost CSR" | |
export CSR=${CDIR}/${SITE}.csr | |
openssl req -new -key ${KEY} -subj "/C=${SUBJ_C}/ST=${SUBJ_ST}/L=${SUBJ_L}/O=${SUBJ_O}/OU=${SUBJ_OU}/CN=${SITE}" -extensions usr_cert -config ${CNF} -out ${CSR} >> ${LOG} 2>&1;tstatus | |
[[ $? -eq 0 ]] || { printf "\e[4G\e[1;31m - A critical error has occurred! \n\e[7GPlease check ${LOG}.\n\e[0m\n";exit 1; } | |
else | |
printf "\e[2G - Generating a multihost wildcard CSR" | |
openssl req -new -key ${KEY} -subj "/C=${SUBJ_C}/ST=${SUBJ_ST}/L=${SUBJ_L}/O=${SUBJ_O}/OU=${SUBJ_OU}/CN=${WC_SITE}" -extensions usr_cert -config ${CNF} -out ${CSR} >> ${LOG} 2>&1;tstatus | |
[[ $? -eq 0 ]] || { printf "\e[4G\e[1;31m - A critical error has occurred! \n\e[7GPlease check ${LOG}.\n\e[0m\n";exit 1; } | |
fi | |
# Validate Certificate Signing Request | |
printf "\e[2G - Validating that ${CSR##*/} was signed by\n\e[5G${KEY##*/}" | |
CSRMD5=$(openssl req -noout -modulus -in ${CSR}|openssl md5|awk '{print $2}') | |
KEYMD5=$(openssl rsa -noout -modulus -in ${KEY}|openssl md5|awk '{print $2}') | |
[[ ${CSRMD5} = ${KEYMD5} ]] && { true;tstatus; } || { false;tstatus;printf '\n\e[1;31m\e[4G - Error validating csr! Exiting.\e[0m\n';exit 1; } | |
# Create Host SSL Cert | |
if [[ ${WILDCARD} = false ]];then | |
printf "\e[2G - Generating Multihost SSL Certificate for ${SITE}" | |
(cd ${CDIR} && openssl x509 -req -in ${CSR} -CA ${CA_CRT} -CAkey ${CA_KEY} -CAcreateserial -extensions usr_cert -extfile ${CNF} -out ${PEM} -days 11499 -sha256) >> ${LOG} 2>&1;tstatus | |
[[ $? -eq 0 ]] || { printf "\e[4G\e[1;31m - A critical error has occurred! \n\e[7GPlease check ${LOG}.\n\e[0m\n";exit 1; } | |
else | |
printf "\e[2G - Generating Multihost Wildcard SSL Certificate for ${WC_SITE}" | |
(cd ${CDIR} && openssl x509 -req -in ${CSR} -CA ${CA_CRT} -CAkey ${CA_KEY} -CAcreateserial -extensions usr_cert -extfile ${CNF} -out ${PEM} -days 11499 -sha256) >> ${LOG} 2>&1;tstatus | |
[[ $? -eq 0 ]] || { printf "\e[4G\e[1;31m - A critical error has occurred! \n\e[7GPlease check ${LOG}.\n\e[0m\n";exit 1; } | |
fi | |
# Create copy of openssl.conf | |
[[ -f ${CNF} ]] && { mv ${CNF} ${CNF}.last; } | |
# Validate Host SSL Certificate | |
printf "\e[2G - Validating that ${PEM##*/} was signed by\n\e[5G${KEY##*/}" | |
CRTMD5=$(openssl x509 -noout -modulus -in ${PEM}|openssl md5|awk '{print $2}') | |
KEYMD5=$(openssl rsa -noout -modulus -in ${KEY}|openssl md5|awk '{print $2}') | |
[[ ${CRTMD5} = ${KEYMD5} ]] && { true;tstatus; } || { false;tstatus;printf '\e[1;31m\e[4G - Error validating cert! Exiting.\e[0m\n';exit 1; } | |
# Copy certs and keys to proper locations if -a,--auto-add option was given | |
if [[ ${AUTOADD} = true ]];then | |
printf "\n\e[2G- Executing auto-add option:\n" | |
printf "\e[4G- Copying ${CA_CRT##*/} to\n\e[8G/usr/local/share/ca-certificates/${CA_CRT##*/}..." | |
cp -a ${CA_CRT} /usr/local/share/ca-certificates/${CA_CRT##*/};tstatus | |
printf "\e[4G- Running 'update-ca-certificates --fresh'..." | |
update-ca-certificates --fresh >> ${LOG} 2>&1;tstatus | |
printf "\e[4G- Copying ${PEM##*/} to \n\e[8G/etc/ssl/certs/${PEM##*/}..." | |
cp -a ${PEM} /etc/ssl/certs/${PEM##*/};tstatus | |
printf "\e[4G- Copying ${KEY##*/} to \n\e[8G/etc/ssl/private/${KEY##*/}..." | |
cp -a ${KEY} /etc/ssl/private/${KEY##*/};tstatus | |
printf "\e[4G- Changing permissions to '0640' for\n\e[8G/etc/ssl/private/${KEY##*/}..." | |
chmod 0640 /etc/ssl/private/${KEY##*/};tstatus | |
fi | |
# Print completion message and tips | |
sp() { printf "%0.0s " $(seq 1 $1); } | |
printf "\n\e[2G\e[1;32mComplete! \e[0m\e[38;2;255;255;255;3mCerts, Keys, and Logs are located in ${CDIR}\e[0m\n" | |
(printf "\n\e[5G\e[38;2;255;255;255mTo Use Self-Signed Certs:\e[0m\n" | |
printf "\n\e[6G\e[35;4mOn Client Machines:\e[0m\n\n\e[6G(\e[3mNote: You will need to copy ${CA_CRT##*/} any client that needs to validate ${PEM##*/})\n\n\e[7G1) \e[38;2;255;255;255;3msudo cp ${CA_CRT} /usr/local/share/ca-certificates/${CA_CRT##*/}\e[0m\n" | |
printf "\e[7G2) \e[38;2;255;255;255;3msudo update-ca-certificates --fresh --verbose\n\e[0m" | |
printf "\n\e[6G\e[35;4mOn SSL Enabled Servers:\e[0m\n\n\e[6G(\e[3mNote: You may need to copy ${PEM##*/} and ${KEY##*/} to other hosts)\e[0m\n\n\e[7G1) \e[38;2;255;255;255;3msudo cp ${PEM} /etc/ssl/certs/${PEM##*/}\e[0m\n" | |
printf "\e[7G2) \e[38;2;255;255;255;3msudo cp ${KEY} /etc/ssl/private/${KEY##*/}\e[0m\n" | |
printf "\e[7G3) \e[38;2;255;255;255mAdd host certs/keys to applications \e[0m\n" | |
printf "\e[0m\n\e[5G\e[38;2;255;255;255mTips:\e[0m\n" | |
if [[ ${WILDCARD} = true ]];then | |
printf "\n\e[4G - To read the Wildcard SSL Cert, type:\n\e[7G\e[38;2;255;255;255;3mopenssl x509 -in ${PEM} -text -noout\n\e[0m" | |
printf "\n\e[4G - To see if a hostname would be covered by this Wildcard SSL Cert, type:\n\e[7G\e[38;2;255;255;255;3mopenssl x509 -in ${PEM} -noout -checkhost <fqdn>\n\e[0m" | |
printf "\n\e[4G - To see if an IP address would be covered by this Wildcard SSL Cert, type:\n\e[7G\e[38;2;255;255;255;3mopenssl x509 -in ${PEM} -noout -checkip <IP Address>\n\e[0m" | |
fi | |
if [[ ${WILDCARD} = false ]];then | |
printf "\n\e[4G - To read the Host SSL cert, type:\n\e[7G\e[38;2;255;255;255;3mopenssl x509 -in ${PEM} -text -noout\n\e[0m" | |
printf "\n\e[4G - To see if a hostname would be covered by this Host SSL cert, type:\n\e[7G\e[38;2;255;255;255;3mopenssl x509 -in ${PEM} -noout -checkhost <fqdn>\n\e[0m" | |
printf "\n\e[4G - To see if an IP address would be covered by this Host SSL cert, type:\n\e[7G\e[38;2;255;255;255;3mopenssl x509 -in ${PEM} -noout -checkip <IP Address>\n\e[0m" | |
fi | |
printf "\n\e[4G - To read the Root CA cert, type:\n\e[7G\e[38;2;255;255;255;3mopenssl x509 -in ${CA_CRT} -text -noout\n\e[0m")|tee -a ${README} | |
printf "\n\n\e[2G\e[38;2;255;255;255mAll of the above information and more is contained in the readme file\n\e[2Glocated @ ${README}\n\e[0m\n\n" | |
printf "\e[2G\e[38;2;255;255;255mSample Cloud-Init implementations for MAAS, juju and LXD that use these SSL \n\e[2Gcertificates can be found in: ${CDIR}/\n\e[0m\n\n" | |
# Dump Host and CA cert into README | |
printf "\n\nCA Certificate Details:\n-----------------------\n"|tee 1>/dev/null -a ${README} | |
openssl x509 -in ${CA_CRT} -text -noout|tee 1>/dev/null -a ${README} | |
printf "\n\nHost Certificate Details:\n-------------------------\n"|tee 1>/dev/null -a ${README} | |
openssl x509 -in ${PEM} -text -noout|tee 1>/dev/null -a ${README} | |
# Remove ansi sequences from README | |
[[ -f ${README} ]] && sudo sed 2>/dev/null -i 's/\x1b\[[0-9;]*[a-zA-Z]//g' ${README} | |
# Create sample cloud-init yaml files for MAAS, Juju, and LXD | |
cat <<EOF|sudo tee 1>/dev/null ${CDIR}/standard-cloud-init-with-certs.example.yaml | |
##### This is a sample standard cloud-init with relevant certificate/file sections | |
##### This would be relevant for MAAS or other standard Cloud-Init implementations but | |
##### not Juju or LXD as cloud-init is embedded in other files | |
##### With MAAS cloud-init is passed as a deployment time option of --user-data="\$(base64 -w0 /path/to/cloud-init.yaml)" | |
##### This is NOT a full cloud-init file, but the included sections are valid | |
##### All certs in the example are valid from the last run of ${0##*/} | |
#cloud-config | |
final_message: 'Standard Cloud-Init Has Completed' | |
timezone: 'America/Los_Angeles' | |
locale: 'en_US.UTF-8' | |
write_files: | |
- encoding: b64 | |
content: $(base64 -w0 ${PEM}) | |
path: /etc/ssl/certs/${PEM##*/} | |
permissions: '0644' | |
- encoding: b64 | |
content: $(base64 -w0 ${KEY}) | |
path: /etc/ssl/private/${KEY##*/} | |
permissions: '0640' | |
ca-certs: | |
trusted: | | |
$(cat ${CA_CRT}|sed 's/^.*$/ &/g') | |
EOF | |
cat <<EOF|sudo tee 1>/dev/null ${CDIR}/juju-cloud-init-with-certs.example.yaml | |
##### This is a sample juju model-default/model-config file with relevant certificate/file sections | |
##### With Juju, cloud-init is embedded in model-default or model-config yaml files | |
##### This is NOT a full juju model configuration file, but the included sections are valid | |
##### All certs in the example are valid from the last run of ${0##*/} | |
container-inherit-properties: 'ca-certs, apt-primary, apt-security, apt-sources' | |
enable-os-refresh-update: true | |
enable-os-upgrade: true | |
cloudinit-userdata: | | |
#cloud-config | |
final_message: 'Juju Cloud-Init Has Completed' | |
timezone: 'America/Los_Angeles' | |
locale: 'en_US.UTF-8' | |
write_files: | |
- encoding: b64 | |
content: $(base64 -w0 ${PEM}) | |
path: /etc/ssl/certs/${PEM##*/} | |
permissions: '0644' | |
- encoding: b64 | |
content: $(base64 -w0 ${KEY}) | |
path: /etc/ssl/private/${KEY##*/} | |
permissions: '0640' | |
ca-certs: | |
trusted: | | |
$(cat ${CA_CRT}|sed 's/^.*$/ &/g') | |
EOF | |
cat <<EOF|sudo tee 1>/dev/null ${CDIR}/lxd-cloud-init-with-certs.example.yaml | |
##### This is a sample LXD profile with relevant certificate/file sections | |
##### With LXD, cloud-init is embedded in a container profile or machine configuration | |
##### This is NOT a full LXD profile, but the included sections are valid | |
##### All certs in the example are valid from the last run of ${0##*/} | |
config: | |
boot.autostart: "true" | |
security.privileged: 'true' | |
security.nesting: "true" | |
user.user-data: | | |
#cloud-config | |
final_message: 'LXD Cloud-Init Has Completed' | |
timezone: 'America/Los_Angeles' | |
locale: 'en_US.UTF-8' | |
write_files: | |
- encoding: b64 | |
content: $(base64 -w0 ${PEM}) | |
path: /etc/ssl/certs/${PEM##*/} | |
permissions: '0644' | |
- encoding: b64 | |
content: $(base64 -w0 ${KEY}) | |
path: /etc/ssl/private/${KEY##*/} | |
permissions: '0640' | |
ca-certs: | |
trusted: | | |
$(cat ${CA_CRT}|sed 's/^.*$/ &/g') | |
EOF | |
# If we got here, cleanly exit | |
exit 0 | |
Author
ThinGuy
commented
Oct 7, 2019
•
$ openssl x509 -in /home/ubuntu/ssl/airstack/airstack.host.wildcard.pem -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
6a:52:d4:a0:87:f6:49:28:03:b5:d2:1e:e9:fc:95:54:0e:15:a8:7b
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = GB, ST = England, L = London, O = Canonical Ltd., OU = Data Center Field Engineering, CN = Canonical AIR stack
Validity
Not Before: Dec 30 03:12:47 2019 GMT
Not After : Jun 24 03:12:47 2051 GMT
Subject: C = GB, ST = England, L = London, O = Canonical Ltd., OU = Data Center Field Engineering, CN = *.orangebox.me
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:b1:e2:cc:aa:36:c0:12:55:84:59:0a:bd:31:6d:
6c:2e:11:92:95:8a:a0:03:ca:ef:fc:5b:9b:09:2b:
25:e3:51:f1:2c:14:e5:bf:f5:17:04:43:2f:a5:1e:
32:6b:a3:b9:c3:55:12:3a:c7:59:e0:f8:60:48:f1:
45:cb:7f:f1:e2:18:7d:e9:8f:2a:b0:70:65:3a:ca:
eb:72:61:70:d7:ec:8d:a9:00:ad:19:36:0f:be:07:
7d:c1:8c:d2:74:13:44:e2:9c:0f:12:66:7f:92:f0:
92:48:00:da:e8:17:f9:48:0f:07:c2:bc:7f:b3:73:
1a:16:6f:82:b0:a8:96:8b:11:2e:db:0b:a1:5b:0c:
dc:94:86:65:5b:83:6d:f4:76:24:37:e3:a4:dd:64:
c9:c9:d4:90:48:24:04:4f:83:ad:c2:3f:d6:8a:d9:
bc:a4:28:f2:31:24:7b:7c:9d:d7:8b:3a:5a:da:ff:
44:2e:c3:f9:bc:41:18:17:ad:5e:07:88:2e:a8:08:
70:ba:74:6d:84:f6:65:bd:9b:36:c0:81:a7:36:59:
a3:8d:19:1a:9c:e5:a0:cc:57:d3:ad:15:57:30:45:
a3:8f:ae:e3:da:89:9a:34:1a:c8:e6:21:90:fb:3b:
00:42:82:b1:8c:a9:ae:80:29:18:ac:7f:fc:6c:31:
4c:9d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:127.0.0.1, DNS:127.0.1.1, DNS:canonical-archive.orangebox.me, DNS:cloud-archive.orangebox.me, DNS:cloud-images.orangebox.me, DNS:elastic-archive.orangebox.me, DNS:fce.orangebox.me, DNS:grafana-archive.orangebox.me, DNS:jaas.ai, DNS:juju-controller.orangebox.me, DNS:juju-images.orangebox.me, DNS:key-server.orangebox.me, DNS:localhost, DNS:maas.io, DNS:maas-images.orangebox.me, DNS:nvidia-archive.orangebox.me, DNS:orangebox20.orangebox.me, DNS:ppa-archive.orangebox.me, DNS:private-ppa.orangebox.me, DNS:rocks.canonical.com, DNS:security-archive.orangebox.me, DNS:snap-proxy.orangebox.me, DNS:streams-archive.orangebox.me, DNS:ubuntu-archive.orangebox.me, DNS:us.cloud-images.ubuntu.com, DNS:*.apps.ubuntu.com, DNS:*.archive.canonical.com, DNS:*.archive.ubuntu.com, DNS:*.canonical.com, DNS:*.corp, DNS:*.developer.ubuntu.com, DNS:*.download.nvidia.com, DNS:*.elastic.co, DNS:*.github.com, DNS:*.grafana.com, DNS:*.home, DNS:*.images.linuxcontainers.org, DNS:*.internal, DNS:*.intranet, DNS:*.jaas.ai, DNS:*.jujucharms.com, DNS:*.lan, DNS:*.launchpad.net, DNS:*.linuxcontainers.org, DNS:*.maas, DNS:*.maas.io, DNS:*.orangebox.me, DNS:*.private, DNS:*.test, DNS:*.ubuntu.com, DNS:*.cloud-images.ubuntu.com, IP Address:127.0.0.1, IP Address:127.0.1.1
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints:
CA:FALSE
X509v3 Subject Key Identifier:
1E:22:54:B3:12:D1:58:66:A2:9F:FE:A7:AA:BA:41:64:A5:69:22:63
X509v3 Authority Key Identifier:
keyid:F7:FE:C4:89:77:06:3F:D8:80:9F:04:B5:DA:18:42:D2:BF:EE:07:8F
Signature Algorithm: sha256WithRSAEncryption
39:cf:6e:49:64:62:06:a8:25:50:c3:60:ab:ec:4b:a7:15:40:
a0:c0:47:d5:32:ad:ee:27:71:60:76:34:b6:08:bd:18:5f:b3:
0d:75:e7:ba:0f:69:ac:09:64:23:bd:f8:8c:39:73:84:51:e2:
32:00:13:08:5b:a7:cc:38:25:28:6f:e1:b3:90:16:1f:df:68:
9f:92:ad:05:28:71:57:d2:f8:66:49:b5:0a:5f:85:70:88:33:
70:58:f1:29:c5:50:e0:7b:6c:d7:af:71:f9:5f:0b:e5:59:d7:
e7:0e:d8:e1:f4:9a:f0:75:18:0e:bd:7b:eb:6d:e9:e3:08:64:
ae:4b:14:0f:1c:e9:09:31:de:54:6f:62:74:5f:23:b9:90:c4:
2e:f9:76:cc:cf:78:6b:f9:2b:f2:28:7c:fa:f7:60:d5:6b:66:
49:62:d3:7a:f2:f6:5e:8a:5b:e7:4d:d3:cf:d2:84:2e:cf:2d:
41:ce:a1:5f:ca:b1:f4:44:49:c3:74:0a:20:3e:f0:5f:c9:73:
99:be:0c:ee:04:e9:4a:0f:ce:c4:b6:7b:a5:7d:51:cf:20:ca:
5a:e7:b0:0b:7f:dc:02:27:d2:57:9c:cc:15:9c:70:cc:76:9b:
f8:af:7c:3c:3d:7a:ae:5e:81:d8:46:6c:c8:a3:05:b5:ca:1a:
76:b1:10:f6
$ openssl x509 -in /home/ubuntu/ssl/airstack/airstack.ca.crt -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
61:f1:7e:81:b0:7f:72:88:5d:58:44:68:f3:68:b4:47:8b:9d:2a:f2
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = GB, ST = England, L = London, O = Canonical Ltd., OU = Data Center Field Engineering, CN = Canonical AIR stack
Validity
Not Before: Dec 30 03:12:45 2019 GMT
Not After : Jun 24 03:12:45 2051 GMT
Subject: C = GB, ST = England, L = London, O = Canonical Ltd., OU = Data Center Field Engineering, CN = Canonical AIR stack
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:a6:88:9d:a2:2f:c5:4f:29:73:27:2f:6d:26:ab:
fd:75:82:c9:87:5f:45:07:e9:b7:7b:41:b8:bd:d2:
1f:93:e1:f0:4d:b7:37:5f:40:6a:fc:3f:91:58:be:
25:54:34:c5:4b:0a:46:66:00:f2:92:e0:5a:84:89:
40:ee:dc:40:b7:2d:ce:f4:ee:03:d3:1b:26:25:e6:
08:83:d4:48:4d:35:7b:7a:54:a6:ca:79:da:f8:cd:
49:35:95:51:91:18:19:9e:67:a1:6f:32:52:c6:ba:
d1:cd:eb:b7:bc:1e:93:1c:a4:60:a6:01:c2:39:2c:
65:ba:43:28:88:97:c1:af:f3:f7:d1:79:f7:82:24:
29:aa:c5:24:79:a2:90:bc:3d:b6:31:fc:c1:92:7d:
2b:fa:17:e7:fb:e7:1b:af:09:de:e3:39:ac:af:b8:
7c:c6:b2:3e:b9:99:cd:62:4f:b2:56:71:6a:1a:81:
2c:59:ab:06:df:67:8d:de:4e:6a:93:6b:6a:e1:aa:
79:24:88:67:49:96:2b:19:2d:03:f7:43:9f:62:4e:
d1:bc:42:1a:32:09:bf:52:94:f2:b2:35:c7:fe:7b:
98:ac:59:81:d6:66:0c:21:85:63:39:3c:0f:07:35:
b8:79:89:09:e1:48:82:74:09:c3:f1:12:87:1c:39:
27:db
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
F7:FE:C4:89:77:06:3F:D8:80:9F:04:B5:DA:18:42:D2:BF:EE:07:8F
X509v3 Authority Key Identifier:
keyid:F7:FE:C4:89:77:06:3F:D8:80:9F:04:B5:DA:18:42:D2:BF:EE:07:8F
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
41:a2:60:f1:0a:34:47:9e:48:78:ea:97:72:f0:60:16:5c:f7:
67:f9:29:94:24:aa:34:96:ce:fe:33:4e:bd:b4:34:34:33:ee:
95:c6:39:f3:f8:ab:bb:fe:6a:33:1e:77:f3:38:5b:38:97:34:
41:fc:85:55:bb:78:a0:e7:22:92:1c:f4:3e:90:0e:0a:75:a0:
88:44:80:b8:cc:49:3e:7e:68:29:0f:bf:c8:36:e2:41:7e:b3:
dc:d5:f2:39:5e:43:39:04:58:c7:0e:e6:65:88:5b:d1:03:49:
f1:88:cc:79:81:56:e6:ea:90:75:15:1b:68:8b:50:71:95:f7:
c2:0e:2b:20:58:68:8e:34:02:db:4c:4a:ec:29:cf:ed:cf:f8:
dd:cd:a1:b8:b6:e0:3c:9a:e7:26:9e:1f:fa:ef:b0:9b:68:fd:
f1:1a:16:0c:47:4d:ee:39:ce:e6:df:84:68:e2:10:b0:b7:14:
a7:27:f2:22:4c:76:af:06:fb:03:5e:bd:93:ef:f4:69:36:05:
cf:f3:2a:9e:c5:64:40:2e:c1:2b:fe:b6:fd:7b:da:fc:47:57:
cf:ef:f0:24:23:a9:cf:71:73:4e:2e:ab:fd:2b:0a:ba:8e:7d:
e9:08:2d:a3:6a:3e:74:7e:23:3d:66:3e:53:fb:98:63:c7:14:
f8:68:03:79
$ ./multihost-wc-ssl.sh -h
multihost-wc-ssl.sh - Create CA certs, host certs, and RSA keys for
Multi-Hostname and Multi-Domain self-signed SSL
certificates, including wildcard certs
Usage: sudo ./multihost-wc-ssl.sh -s <FQDN> [ OPTIONS ]
Options:
-s --site Primary FQDN that this ssl cert should be valid for
-n, --names Space or comma separated list of all FQDNs that this
ssl cert should be valid for (enclose space eparated
slist in quotes)
-i, --ips Space or comma separated list of IP addresses to
include as a Subject Alternative Name (SAN) (enclose space
separated list in quotes)
-d, --domains Space or comma separated list of domain names to
include as a wildcard entry in Subject Alternative
Name (SAN) (enclose space separate list in quotes)
-l, --local Include DNS and IP entries for localhost, 127.0.0,1, and
127.0.1.1
-w, --wildcard Create wildcard entries for the domains of the
FQDNs provided with the -n,--names option
-p, --private Include Private DNS Namespaces for top-level domains
(.corp .home .internal .intranet .lan .private .test)
See: https://tools.ietf.org/html/rfc6762#appendix-G
-P, --prefix Prefix to give to certs,keys, etc.
Default: site name given with -s,--site option
-a, --auto-add Automatically copy CA Cert to local CA store, host cert
to /etc/ssl/certs/, and host key to /etc/ssl/private/
--nohosts Only include wildcard entries in Subject Alternative Name
(SAN), not host entries
--issuer-country Issuer (CA) Country Name (2 Letter Code)
Default: GB
--issuer-state Issuer (CA) State or Province Name (Full Name)
Default: England
--issuer-locality Issuer (CA) Locality Name (i.e. City)
Default: London
--issuer-org Issuer (CA) Organization Name (i.e. Company)
Default: Canonical Ltd.
--issuer-unit Issuer (CA) Organizational Unit (i.e. Section)
Default: Data Center Field Engineering
--issuer-name Issuer (CA) Common Name (Your name or FQDN)
Default: Canonical AIR stack
--subject-country Subject (Host) Country Name (2 Letter Code)
Default: GB
--subject-state Subject (Host) State or Province Name (Full Name)
Default: England
--subject-locality Subject (Host) Locality Name (i.e. City)
Default: London
--subject-org Subject (Host) Organization Name (i.e. Company)
Default: Canonical Ltd.
--subject-unit Subject (Host) Organizational Unit (i.e. Section)
Default: Data Center Field Engineering
Note: Subject CN is determined by -s,--site or
-P,--prefix args and wildcard options
Ex:
sudo ./multihost-wc-ssl.sh \
-w \
-s image-server.orangebox.me \
-n maas-images.orangebox.me,juju-images.orangebox.me,lxd-images.orangebox.me \
-d maas.io,images.linuxcontainers.org,linuxcontainers.org \
-i 172.27.20.1,172.27.20.2,172.27.20.3,172.27.20.4,172.27.20.5,172.27.20.6
Notes:
- Be careful of subdomains with wildcard enabled certs:
FQDN: server.example.com
HOST: server
DOMAIN: example.com
FQDN: us.server.example.com
HOST: us
DOMAIN: server.example.com
To ensure wildcards cover both, add example.com AND server.example.com
to the -d,--domain option
- How to use self-signed certs, testing tips, and configuration examples
provided upon completion
- Log file will be located in ${HOME}/ssl/<domain name of site>/<site>.log
- The --nohosts option assumes -w,--wildcard
- You can use -d,--domain with -w.--wildcard, however only unique entries will
be listed in the SAN field
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment