acs_admin::check_expired_certificates (private)

 acs_admin::check_expired_certificates [ -api api ] \
    [ -key_type key_type ]

Defined in packages/acs-admin/tcl/acs-admin-procs.tcl

Check expire-dates of certificates and send warning emails to the admin. In case HTTPS is not configured via the "nsssl" driver, or the command line tool "openssl" is not installed, the proc does nothing.

Switches:
-api (optional, defaults to "production")
possible values: "production" or "staging". In case the certificate is expired, use this type of letsencrypt environment to obtain a fresh certificate.
-key_type (optional, defaults to "ecdsa")
possible values: "rsa" or "ecdsa".
Returns:
boolean telling whether expired certificates existed (true) or not (false)

Partial Call Graph (max 5 caller/called nodes):
%3 test_acs_admin_check_expired_certificates acs_admin_check_expired_certificates (test acs-admin) acs_admin::check_expired_certificates acs_admin::check_expired_certificates test_acs_admin_check_expired_certificates->acs_admin::check_expired_certificates acs_mail_lite::send acs_mail_lite::send (public) acs_admin::check_expired_certificates->acs_mail_lite::send ad_host_administrator ad_host_administrator (public) acs_admin::check_expired_certificates->ad_host_administrator ad_html_to_text ad_html_to_text (public) acs_admin::check_expired_certificates->ad_html_to_text ad_parameter_cache ad_parameter_cache (public) acs_admin::check_expired_certificates->ad_parameter_cache ad_system_name ad_system_name (public) acs_admin::check_expired_certificates->ad_system_name

Testcases:
acs_admin_check_expired_certificates
Source code:
        set openssl [util::which openssl]
        if {[namespace which ns_driver] ne "" && $openssl ne ""} {
            #
            # Get certificates to check expire dates
            #
            set critCertInfo {}
            foreach entry [ns_driver info] {
                set module [dict get $entry module]
                if {[dict get $entry type] eq "nsssl"} {
                    set server [dict get $entry server]
                    if {$server ne ""} {
                        set certfile [ns_config ns/server/$server/module/$module certificate]
                    } else {
                        set certfile [ns_config ns/module/$module certificate]
                    }
                    if {![info exists processed($certfile)]} {
                        #
                        # Check expiration of the certificate using the
                        # "openssl" command line tool.
                        #
                        set notAfter [exec $openssl x509 -enddate -noout -in $certfile]
                        regexp {notAfter=(.*)$} $notAfter . date
                        set days [expr {([clock scan $date] - [clock seconds])/(60*60*24.0)}]
                        set info "Certificate $certfile will expire in [format %.1f $days] days"
                        ns_log notice "ssl: $info"
                        set warnInDays [parameter::get_from_package_key  -package_key "acs-admin"  -parameter ExpireCertificateWarningPeriod  -default 30]
#set warnInDays 86
                        if {$warnInDays > -1 && $days < $warnInDays} {
                            lappend critCertInfo $info
                        }
                        set processed($certfile) 1
                    }
                }
            }

            if {[llength $critCertInfo] > 0} {
                set to_addr [parameter::get_from_package_key  -package_key "acs-admin"  -parameter ExpireCertificateEmail  -default ""]
                if {$to_addr eq ""} {
                    set to_addr [ad_host_administrator]
                }
                if {$to_addr ne ""} {
                    set mailSubject "Certificate of [ad_system_name] expires soon"
                    set report ""
                    if {[info commands ::letsencrypt::Client] ne ""} {

                        #
                        # Make sure, UseCanonicalLocation is NOT set,
                        # since otherwise the requests from
                        # letsencrypt will be redirected. One could
                        # think about other solution, such ignoring
                        # mapping to the canonical location for
                        # letsencryp URLs.
                        #
                        set param_exists [db_0or1row check_params {
                            select 1 from apm_parameters
                            where package_key = 'acs-kernel'
                            and parameter_name = 'UseCanonicalLocation'
                        }]
                        if {!$param_exists} {
                            catch {apm_parameter_register UseCanonicalLocation "Use Canonical Location" acs-kernel 0 number }
                        }
                        ad_parameter_cache -delete $::acs::kernel_id UseCanonicalLocation
                        set oldValue [parameter::get  -package_id $::acs::kernel_id  -parameter UseCanonicalLocation  -default 0]
                        parameter::set_value  -package_id $::acs::kernel_id  -parameter UseCanonicalLocation  -value 0

                        #
                        # Now we are all set to create and start the ACME client
                        #
                        #set api staging ;# can be activated for testing purposes
                        set report "Report of automated certificate renewal:\n[string repeat = 72]\n"

                        try {
                            #
                            # We do not specify "-domains" here, so
                            # get the values from the NaviServer
                            # configuration file from section:
                            # (ns_section ns/server/${server}/module/letsencrypt)
                            #
                            if {[::letsencrypt::Client info lookup parameters  create key_type] ne ""} {
                                set key_type_parameter "-key_type $key_type"
                            } else {
                                set key_type_parameter ""
                            }
                            set c [::letsencrypt::Client new  -API $api  {*}$key_type_parameter  -background  -domains {}  ]
                            ns_log notice "ssl: call getCertificate"
                            $c getCertificate
                            ns_log notice "ssl: call getCertificate DONE"
                            append report \n[ad_html_to_text [$c cget -log]]\n
                            $c destroy

                        } on ok {result} {
                            ns_log notice "letsencrypt: automated renew request succeeded: $result"
                            set success "success"
                        } on error {errorMsg} {
                            append report "Error: $errorMsg\nConsider upgrading to letsencrypt 0.6\n"
                            ns_log notice "letsencrypt: automated renew request failed: $errorMsg"
                            set success "error"
                        }

                        parameter::set_value  -package_id $::acs::kernel_id  -parameter UseCanonicalLocation  -value $oldValue
                        set mailSubject "Certificate of [ad_system_name] renewal ($success)"
                    }
                    append report \n[string repeat = 72]\n

                    set certLabel [expr {[llength $critCertInfo] > 1 ? "certificates" : "certificate"}]
                    set body [ns_trim -delimiter | {
                        |Dear Webmaster of [ad_system_name],
                        |
                        |The following $certLabel of your site will expire soon:
                        |
                        | - [join $critCertInfo "\n- "]
                        |
                        |${report}Your friendly daemon
                    }]
                    #set to_addr neumann@wu.ac.at ;# can be activated for testing purposes
                    acs_mail_lite::send -send_immediately  -to_addr $to_addr  -from_addr [ad_system_owner]  -subject $mailSubject  -body [subst $body]
                }
            }

            return [expr {[llength $critCertInfo] > 0}]
        }
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: