Sucede todo el tiempo, a las empresas más grandes. Un certificado importante no se renueva y los servicios se vuelven inaccesibles. Le sucedió a Microsoft Teams a principios de febrero de 2020. La situación incómoda sucedió justo después del lanzamiento de una importante campaña de televisión que lo promociona como un competidor de Slack. Por vergonzoso que sea, seguramente le sucederá a alguien más en el futuro.
En la web moderna, los certificados caducados pueden crear problemas importantes para los sitios web. Desde usuarios descontentos que no pueden conectarse a un sitio hasta amenazas de seguridad por parte de ciberdelincuentes. Estos últimos se pueden aprovechar de la falta de renovación de un certificado.
ssl-on-demand es un conjunto de scripts SSL para ayudar a los propietarios de sitios a administrar certificados. Se utiliza para la generación y validación de certificados bajo demanda. Asimismo, puede crear solicitudes de firma de certificados (CSR) y predecir el vencimiento de los certificados existentes.
Automatizar comprobaciones de vencimiento de SSL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
USAGE: SSLexpiryPredictions.sh -[cdewh] DESCRIPTION: This script predicts the expiring SSL certificates based on the end date. OPTIONS: -c| sets the value for configuration file which has server:port or host:port details. -d| sets the value of directory containing the certificate files in crt or pem format. -e| sets the value of certificate extention, e.g crt, pem, cert. crt: default [to be used with -d, if certificate file extention is other than .crt] -w| sets the value for writing the script output to a file. -h| prints this help and exit. |
Ejemplos:
Para crear un archivo con una lista de todos los servidores y sus números de puerto para hacer un protocolo de enlace SSL, debes usar:
1 2 3 4 5 6 7 |
cat > servers.list server1:port1 server2:port2 server3:port3 (ctrl+d) $ ./SSLexpiryPredictions.sh -c server.list |
Debes ejecutar el script proporcionando la ubicación y extensión del certificado (en caso de que no sea .crt):
1 |
$ ./SSLexpiryPredictions.sh -d /path/to/certificates/dir -e pem |
Automatizar CSR y creación de claves privadas
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
Usage: genSSLcsr.sh [options] -[cdmshx] [-c (common name)] [-d (domain name)] [-s (SSL certificate subject)] [-p (password)] [-m (email address)] *(Experimental) [-r (remove pasphrase) default:true] [-h (help)] [-x (optional)] [OPTIONS] -c| Sets the value for common name. A valid common name is something that ends with 'xyz.com' -d| Sets the domain name. -s| Sets the subject to be applied to the certificates. '/C=country/ST=state/L=locality/O=organization/OU=organizationalunit/emailAddress=email' -p| Sets the password for private key. -r| Sets the value of remove passphrase. true:[default] passphrase will be removed from key. false: passphrase will not be removed and key wont get printed. -m| Sets the mailing capability to the script. (Experimental at this time and requires a lot of work) -x| Creates the certificate request and key but do not print on screen. To be used when script is used just to create the key and CSR with no need + to generate the certficate on the go. -h| Displays the usage. No further functions are performed. Example: genSSLcsr.sh -c mywebsite.xyz.com -m myemail@mydomain.com |
Los scripts
1. SSLexpiryPredictions.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
#!/bin/bash ############################################## # # PURPOSE: The script to predict expiring SSL certificates. # # AUTHOR: 'Abhishek.Tamrakar' # # VERSION: 0.0.1 # # COMPANY: Self # # EMAIL: abhishek.tamrakar08@gmail.com # # GENERATED: on 2018-05-20 # # LICENSE: Copyright (C) 2018 Abhishek Tamrakar # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ############################################## #your Variables go here script=${0##/} exitcode='' WRITEFILE=0 CONFIG=0 DIR=0 # functions here usage() { cat <<EOF USAGE: $script -[cdewh]" DESCRIPTION: This script predicts the expiring SSL certificates based on the end date. OPTIONS: -c| sets the value for configuration file which has server:port or host:port details. -d| sets the value of directory containing the certificate files in crt or pem format. -e| sets the value of certificate extention, e.g crt, pem, cert. crt: default -w| sets the value for writing the script output to a file. -h| prints this help and exit. EOF exit 1 } # print info messages info() { printf '\n%s: %6s\n' "INFO" "$@" } # print error messages error() { printf '\n%s: %6s\n' "ERROR" "$@" exit 1 } # print warning messages warn() { printf '\n%s: %6s\n' "WARN" "$@" } # get expiry for the certificates getExpiry() { local expdate=$1 local certname=$2 today=$(date +%s) timetoexpire=$(( ($expdate - $today)/(60*60*24) )) expcerts=( ${expcerts[@]} "${certname}:$timetoexpire" ) } # print all expiry that was found, typically if there is any. printExpiry() { local args=$# i=0 if [[ $args -ne 0 ]]; then #statements printf '%s\n' "---------------------------------------------" printf '%s\n' "List of expiring SSL certificates" printf '%s\n' "---------------------------------------------" printf '%s\n' "$@" | \ sort -t':' -g -k2 | \ column -s: -t | \ awk '{printf "%d.\t%s\n", NR, $0}' printf '%s\n' "---------------------------------------------" fi } # calculate the end date for the certificates first, finally to compare and predict when they are going to expire. calcEndDate() { sslcmd=$(which openssl) if [[ x$sslcmd = x ]]; then #statements error "$sslcmd command not found!" fi # when cert dir is given if [[ $DIR -eq 1 ]]; then #statements checkcertexists=$(ls -A $TARGETDIR| egrep "*.$EXT$") if [[ -z ${checkcertexists} ]]; then #statements error "no certificate files at $TARGETDIR with extention $EXT" fi for file in $TARGETDIR/*.${EXT:-crt} do expdate=$($sslcmd x509 -in $file -noout -enddate) expepoch=$(date -d "${expdate##*=}" +%s) certificatename=${file##*/} getExpiry $expepoch ${certificatename%.*} done elif [[ $CONFIG -eq 1 ]]; then #statements while read line do if echo "$line" | \ egrep -q '^[a-zA-Z0-9.]+:[0-9]+|^[a-zA-Z0-9]+_.*:[0-9]+'; then expdate=$(echo | \ openssl s_client -connect $line 2>/dev/null | \ openssl x509 -noout -enddate 2>/dev/null); if [[ $expdate = '' ]]; then #statements warn "[error:0906D06C] Cannot fetch certificates for $line" else expepoch=$(date -d "${expdate##*=}" +%s); certificatename=${line%:*}; getExpiry $expepoch ${certificatename}; fi else warn "[format error] $line is not in required format!" fi done < $CONFIGFILE fi } # your script goes here while getopts ":c:d:w:e:h" options do case $options in c ) CONFIG=1 CONFIGFILE="$OPTARG" if [[ ! -e $CONFIGFILE ]] || [[ ! -s $CONFIGFILE ]]; then #statements error "$CONFIGFILE does not exist or empty!" fi ;; e ) EXT="$OPTARG" case $EXT in crt|pem|cert ) info "Extention check complete." ;; * ) error "invalid certificate extention $EXT!" ;; esac ;; d ) DIR=1 TARGETDIR="$OPTARG" [ $TARGETDIR = '' ] && error "$TARGETDIR empty variable!" ;; w ) WRITEFILE=1 OUTFILE="$OPTARG" ;; h ) usage ;; \? ) usage ;; : ) fatal "Argument required !!! see \'-h\' for help" ;; esac done shift $(($OPTIND - 1)) # calcEndDate #finally print the list if [[ $WRITEFILE -eq 0 ]]; then #statements printExpiry ${expcerts[@]} else printExpiry ${expcerts[@]} > $OUTFILE fi |
2. genSSLcsr.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
#!/bin/bash - #=============================================================================== # # FILE: genSSLcsr.sh # # USAGE: ./genSSLcsr.sh [options] # # DESCRIPTION: ++++version 1.0.2 # Fixed few bugs from previous script # +Removing passphrase after CSR generation # Extended use of functions # Checks for valid common name # ++++1.0.3 # Fixed line breaks # Work directory to be created at the start # Used getopts for better code arrangements # ++++1.0.4 # Added mail feature (experimental at this time and needs # a mail server running locally.) # Added domain input and certificate subject inputs # # OPTIONS: --- # REQUIREMENTS: openssl, mailx # BUGS: --- # NOTES: --- # AUTHOR: Abhishek Tamrakar (), abhishek.tamrakar08@gmail.com # ORGANIZATION: Self # CREATED: 6/24/2016 # REVISION: 4 # COPYRIGHT AND # LICENSE: Copyright (C) 2016 Abhishek Tamrakar # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #=============================================================================== #variables ges here #set basename to scriptname SCRIPT=${0##*/} #set flags TFOUND=0 CFOUND=0 MFOUND=0 XFOUND=0 SFOUND=0 logdir=/var/log # edit these below values to replace with yours homedir='' yourdomain='' country=IN state=Maharashtra locality=Pune organization="your_organization" organizationalunit="your_organizational_unit" email=your_email@your_domain password=your_ssl_password # OS is declared and will be used in its next version OS=$(egrep -io 'Redhat|centos|fedora|ubuntu' /etc/issue) ### function declarations ### info() { printf '\n%s\t%s\t' "INFO" "$@" } #exit on error with a custom error message #the extra function was removed and replaced withonly one. #using FAILED\n\e<message> is a way but not necessarily required. # fatal() { printf '\n%s\t%s\n' "ERROR" "$@" exit 1 } checkperms() { if [[ -z ${homedir} ]]; then homedir=$(pwd) fi if [[ -w ${homedir} ]]; then info "Permissions acquired for ${SCRIPT} on ${homedir}." else fatal "InSufficient permissions to run the ${SCRIPT}." fi } checkDomain() { info "Initializing Domain ${cn} check ? " if [[ ! -z ${yourdomain} ]]; then workdir=${homedir}/${yourdomain} echo -e "${cn}"|grep -E -i -q "${yourdomain}$" && echo -n "[OK]" || fatal "InValid domain in ${cn}" else workdir=${homedir}/${cn#*.} echo -n "[NULL]" info "WARNING: No domain declared to check." confirmUserAction fi } # end function checkDomain usage() { cat << EOF Usage: $SCRIPT [options] -[cdmshx] [-c (common name)] [-d (domain name)] [-s (SSL certificate subject)] [-p (password)] [-m (email address)] *(Experimental) [-r (remove pasphrase) default:true] [-h (help)] [-x (optional)] [OPTIONS] -c| Sets the value for common name. A valid common name is something that ends with 'xyz.com' -d| Sets the domain name. -s| Sets the subject to be applied to the certificates. '/C=country/ST=state/L=locality/O=organization/OU=organizationalunit/emailAddress=email' -p| Sets the password for private key. -r| Sets the value of remove passphrase. true:[default] passphrase will be removed from key. false: passphrase will not be removed and key wont get printed. -m| Sets the mailing capability to the script. (Experimental at this time and requires a lot of work) -x| Creates the certificate request and key but do not print on screen. To be used when script is used just to create the key and CSR with no need + to generate the certficate on the go. -h| Displays the usage. No further functions are performed. Example: $SCRIPT -c mywebsite.xyz.com -m myemail@mydomain.com EOF exit 1 } # end usage confirmUserAction() { while true; do read -p "Do you wish to continue? ans: " yn case $yn in [Yy]* ) info "Initiating the process"; break;; [Nn]* ) exit 1;; * ) info "Please answer yes or no.";; esac done } # end function confirmUserAction parseSubject() { local subject="$1" parsedsubject=$(echo $subject|sed 's/\// /g;s/^ //g') for i in ${parsedsubject}; do case ${i%=*} in 'C' ) country=${i##*=} ;; 'ST' ) state=${i##*=} ;; 'L' ) locality=${i##*=} ;; 'O' ) organization=${i##*=} ;; 'OU' ) organizationalunit=${i##*=} ;; 'emailAddress' ) email=${i##*=} ;; esac done } sendMail() { mailcmd=$(which mailx) if [[ x"$mailcmd" = "x" ]]; then fatal "Cannot send email! please install mailutils for linux" else echo "SSL CSR attached." | $mailcmd -s "SSL certificate request" \ -t $email $ccemail -A ${workdir}/${cn}.csr \ && info "mail sent" \ || fatal "error in sending mail." fi } genCSRfile() { info "Creating signed key request for ${cn}" #Generate a key openssl genrsa -des3 -passout pass:$password -out ${workdir}/${cn}.key 4096 -noout 2>/dev/null && echo -n "[DONE]" || fatal "unable to generate key" #Create the request info "Creating Certificate request for ${cn}" openssl req -new -key ${workdir}/${cn}.key -passin pass:$password -sha1 -nodes \ -subj "/C=$country/ST=$state/L=$locality/O=$organization/OU=$organizationalunit/CN=$cn/emailAddress=$email" \ -out ${workdir}/${cn}.csr && echo -n "[DONE]" || fatal "unable to create request" if [[ "${REMOVEPASSPHRASE:-true}" = 'true' ]]; then #statements #Remove passphrase from the key. Comment the line out to keep the passphrase info "Removing passphrase from ${cn}.key" openssl rsa -in ${workdir}/${cn}.key \ -passin pass:$password \ -out ${workdir}/${cn}.insecure 2>/dev/null \ && echo -n "[DONE]" || fatal "unable to remove passphrase" #swap the filenames info "Swapping the ${cn}.key to secure" mv ${workdir}/${cn}.key ${workdir}/${cn}.secure \ && echo -n "[DONE]" || fatal "unable to perfom move" info "Swapping insecure key to ${cn}.key" mv ${workdir}/${cn}.insecure ${workdir}/${cn}.key \ && echo -n "[DONE]" || fatal "unable to perform move" else info "Flag '-r' is set, passphrase will not be removed." fi } printCSR() { if [[ -e ${workdir}/${cn}.csr ]] && [[ -e ${workdir}/${cn}.key ]] then echo -e "\n\n----------------------------CSR-----------------------------" cat ${workdir}/${cn}.csr echo -e "\n----------------------------KEY-----------------------------" cat ${workdir}/${cn}.key echo -e "------------------------------------------------------------\n" else fatal "CSR or KEY generation failed !!" fi } ### END Functions ### #Check the number of arguments. If none are passed, print help and exit. NUMARGS=$# if [ $NUMARGS -eq 0 ]; then fatal "$NUMARGS Arguments provided !!!! See usage with '-h'" fi #Organisational details while getopts ":c:d:s:m:p:rhx" atype do case $atype in c ) CFOUND=1 cn="$OPTARG" ;; d ) yourdomain="$OPTARG" ;; s ) SFOUND=1 subj="$OPTARG" ;; p ) password="$OPTARG" ;; r ) REMOVEPASSPHRASE='false' ;; m ) MFOUND=1 ccemail="$OPTARG" ;; x ) XFOUND=1 ;; h ) usage ;; \? ) usage ;; : ) fatal "Argument required !!! see \'-h\' for help" ;; esac done shift $(($OPTIND - 1)) #### END CASE #### START MAIN #### if [ $CFOUND -eq 1 ] then # take current dir as homedir by default. checkperms ${homedir} checkDomain if [[ ! -d ${workdir} ]] then mkdir ${workdir:-${cn#*.}} 2>/dev/null && info "${workdir} created." else info "${workdir} exists." fi # end workdir check parseSubject "$subj" genCSRfile if [ $XFOUND -eq 0 ] then sleep 2 printCSR fi # end x check if [[ $MFOUND -eq 1 ]]; then sendMail fi else fatal "Nothing to do!" fi # end common name check ##### END MAIN ##### |