diff --git a/docs/configuration/ssl.md b/docs/configuration/ssl.md index 31d8a080f..8e574562b 100644 --- a/docs/configuration/ssl.md +++ b/docs/configuration/ssl.md @@ -9,6 +9,7 @@ certs:add CRT KEY # Add an ssl endpoint to an app. Can al certs:generate DOMAIN # Generate a key and certificate signing request (and self-signed certificate) certs:info # Show certificate information for an ssl endpoint. certs:remove # Remove an SSL Endpoint from an app. +certs:report [] [] # Displays an ssl report for one or more apps certs:update CRT KEY # Update an SSL Endpoint on an app. Can also import from a tarball on stdin ``` @@ -76,6 +77,60 @@ dokku certs:info node-js-app The `certs:remove` command only works on app-specific certificates. It will `rm` the app-specific tls directory, rebuild the nginx configuration, and reload nginx. +### Displaying ssl reports about an app + +> New as of 0.8.1 + +You can get a report about the apps ssl status using the `certs:report` command: + +```shell +dokku certs:report +``` + +``` +=====> node-js-sample + Ssl dir: /home/dokku/node-js-sample/tls + Ssl enabled: true + Ssl hostnames: *.node-js-sample.org node-js-sample.org + Ssl expires at: Oct 5 23:59:59 2019 GMT + Ssl issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Domain Validation Secure Server CA + Ssl starts at: Oct 5 00:00:00 2016 GMT + Ssl subject: OU=Domain Control Validated; OU=PositiveSSL Wildcard; CN=*.node-js-sample.org + Ssl verified: self signed. +=====> python-sample + Ssl dir: /home/dokku/python-sample/tls + Ssl enabled: false + Ssl hostnames: + Ssl expires at: + Ssl issuer: + Ssl starts at: + Ssl subject: + Ssl verified: +``` + +You can run the command for a specific app also. + +```shell +dokku certs:report node-js-sample +``` + +``` +=====> node-js-sample ssl information + Ssl dir: /home/dokku/node-js-sample/tls + Ssl enabled: true + Ssl hostnames: *.example.org example.org + Ssl expires at: Oct 5 23:59:59 2019 GMT + Ssl issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Domain Validation Secure Server CA + Ssl starts at: Oct 5 00:00:00 2016 GMT + Ssl subject: OU=Domain Control Validated; OU=PositiveSSL Wildcard; CN=*.example.org + Ssl verified: self signed. +``` + +You can pass flags which will output only the value of the specific information you want. For example: + +```shell +dokku certs:report node-js-sample --ssl-enabled +``` ## HSTS Header diff --git a/plugins/certs/commands b/plugins/certs/commands index c34b902c8..550d97f8d 100755 --- a/plugins/certs/commands +++ b/plugins/certs/commands @@ -14,6 +14,7 @@ case "$1" in certs:info , Show certificate information for an ssl endpoint certs:key CRT KEY [KEY ...], [NOT IMPLEMENTED] Print the correct key for the given certificate certs:remove , Remove an SSL Endpoint from an app + certs:report [] [], Displays an ssl report for one or more apps certs:rollback , [NOT IMPLEMENTED] Rollback an SSL Endpoint for an app certs:update CRT KEY, Update an SSL Endpoint on an app. Can also import from a tarball on stdin help_content diff --git a/plugins/certs/subcommands/report b/plugins/certs/subcommands/report new file mode 100755 index 000000000..6f0e59031 --- /dev/null +++ b/plugins/certs/subcommands/report @@ -0,0 +1,136 @@ +#!/usr/bin/env bash +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/certs/functions" + +fn-ssl-enabled() { + declare APP="$1" + local SSL_ENABLED=false + + if is_ssl_enabled "$APP"; then + SSL_ENABLED=true + fi + echo "$SSL_ENABLED" +} + +fn-ssl-expires-at() { + declare APP="$1" + local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" + + if is_ssl_enabled "$APP"; then + echo "$(openssl x509 -in "$APP_SSL_PATH/server.crt" -noout -text | grep "Not After :" | awk -F " : " '{ print $2 }')" + fi +} + +fn-ssl-hostnames() { + declare APP="$1" + + if is_ssl_enabled "$APP"; then + get_ssl_hostnames "$APP" | xargs + fi +} + +fn-ssl-issuer() { + declare APP="$1" + local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" + + if is_ssl_enabled "$APP"; then + echo "$(openssl x509 -in "$APP_SSL_PATH/server.crt" -noout -text | grep "Issuer:" | xargs | sed -e "s/Issuer: //g")" + fi +} + +fn-ssl-starts-at() { + declare APP="$1" + local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" + + if is_ssl_enabled "$APP"; then + echo "$(openssl x509 -in "$APP_SSL_PATH/server.crt" -noout -text | grep "Not Before:" | awk -F ": " '{ print $2 }')" + fi +} + +fn-ssl-subject() { + declare APP="$1" + local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" + + if is_ssl_enabled "$APP"; then + echo "$(openssl x509 -in "$APP_SSL_PATH/server.crt" -noout -subject | sed -e "s:subject= ::g"| sed -e "s:^/::g" | sed -e "s:/:; :g")" + fi +} + +fn-ssl-verified() { + declare APP="$1" + local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls" + local SSL_VERIFY_OUTPUT=false SSL_SELF_SIGNED="self signed" + + if ! is_ssl_enabled "$APP"; then + return + fi + + SSL_VERIFY_OUTPUT="$(openssl verify -verbose -purpose sslserver "$APP_SSL_PATH/server.crt" | awk -F ':' '{ print $2 }' | tail -1 | xargs || true)" + if [[ "$SSL_VERIFY_OUTPUT" == "OK" ]]; then + SSL_SELF_SIGNED="verified by a certificate authority" + fi + + echo "$SSL_SELF_SIGNED" +} + +certs_report_single_app() { + local APP="$1"; local APP_DIR="$DOKKU_ROOT/$APP"; local INFO_FLAG="$2" + if [[ "$INFO_FLAG" == "true" ]]; then + INFO_FLAG="" + fi + verify_app_name "$APP" + local flag_map=( + "--ssl-dir: $APP_DIR/tls" + "--ssl-enabled: $(fn-ssl-enabled "$APP")" + "--ssl-hostnames: $(fn-ssl-hostnames "$APP")" + "--ssl-expires-at: $(fn-ssl-expires-at "$APP")" + "--ssl-issuer: $(fn-ssl-issuer "$APP")" + "--ssl-starts-at: $(fn-ssl-starts-at "$APP")" + "--ssl-subject: $(fn-ssl-subject "$APP")" + "--ssl-verified: $(fn-ssl-verified "$APP")" + ) + + if [[ -z "$INFO_FLAG" ]]; then + dokku_log_info2 "$APP ssl information" + for flag in "${flag_map[@]}"; do + key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" + dokku_log_verbose "$(printf "%-20s %-25s" "${key^}" "${flag#*: }")" + done + else + local match=false; local value_exists=false + for flag in "${flag_map[@]}"; do + valid_flags="${valid_flags} $(echo "$flag" | cut -d':' -f1)" + if [[ "$flag" == "${INFO_FLAG}:"* ]]; then + value=${flag#*: } + size="${#value}" + if [[ "$size" -ne 0 ]]; then + echo "$value" && match=true && value_exists=true + else + match=true + fi + fi + done + if [[ "$match" == "true" ]]; then + [[ "$value_exists" == "true" ]] || dokku_log_fail "not deployed" + else + dokku_log_fail "Invalid flag passed, valid flags:${valid_flags}" + fi + fi +} + +certs_report_cmd() { + declare desc="displays an ssl report for one or more apps" + local cmd="certs:report" + local INSTALLED_APPS=$(dokku_apps); local APP + + if [[ -z $2 ]]; then + for APP in $INSTALLED_APPS; do + certs_report_single_app "$APP" "true" + done + else + certs_report_single_app "$2" "$3" + fi +} + +certs_report_cmd "$@"