<?php /** * ____________________________________________________________________________ * * _____ _____ __ _____ _ _ * | | | | ___ ___ ___| |___ ___|_| |_ ___ ___ * |- -| | | | |__ | .'| . | . | | | | . | | | _| . | _| * |_____|_|_|_|_____| |__,| _| _|_|_|_|___|_|_|_|_| |___|_| * |_| |_| * _ _ _ * ___| |_|___ ___| |_ * | _| | | -_| | _| * |___|_|_|___|_|_|_| * * ____________________________________________________________________________ * * CUSTOM CHECK * * Check expiration of ssl certificate * ____________________________________________________________________________ * * USAGE: * * $oMonitor->addCheck( * [ * "name" => "SSL cert", * "description" => "Check SSL certificate of my domain", * "check" => [ * "function" => "Cert", * "params" => [ * "url" => "https://www.example.com", * "warning" => "30", * ], * ], * ] * ); * ____________________________________________________________________________ * * 2021-10-26 <axel.hahn@iml.unibe.ch> * 2022-05-02 <axel.hahn@iml.unibe.ch> set warning to 21 days (old value was 30); add "critical" param * 2022-05-03 <axel.hahn@iml.unibe.ch> critical limit is a warning only (because app is still functional) * 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables * 2025-03-03 <axel.hahn@unibe.ch> comment block for host check in DND names * 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description */ class checkCert extends appmonitorcheck { /** * Self documentation and validation rules * @var array */ protected array $_aDoc = [ 'name' => 'Plugin Cert', 'description' => 'Check if a SSL certificate is still valid … and does not expire soon.', 'parameters' => [ 'url' => [ 'type' => 'string', 'required' => true, 'description' => 'Url to check https://[server}[:{port}] or ssl://[server}[:{port}]', 'default' => null, 'regex'=>'/^(https|ssl):\/\/[^\s]+/', 'example' => '', ], 'verify' => [ 'type' => 'bool', 'required' => false, 'description' => 'optional: flag verify certificate; default = true', 'default' => true, 'example' => "false", ], 'warning' => [ 'type' => 'int', 'required' => false, 'description' => 'optional: count of days to warn; default=21', 'default' => 21, 'example' => 30, ], 'critical' => [ 'type' => 'int', 'required' => false, 'description' => 'optional: count of days to raise critical; default=5', 'default' => 5, 'example' => "7", ], ], ]; /** * Get default group of this check * @return string */ public function getGroup(): string { return 'security'; } /** * Check SSL certificate * @param array $aParams * [ * "url" optional: url to connect check; default: own protocol + server * "verify" optional: flag for verification of certificate or check for expiration only; default=true (=verification is on) * "warning" optional: count of days to warn; default=21 (=3 weeks) * "critical" optional: count of days to raise critical; default=5 * ] * @return array */ public function run(array $aParams): array { $sUrl = $aParams["url"] ?? 'http' . ($_SERVER['HTTPS'] ? 's' : '') . '://' . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']; $bVerify = isset($aParams["verify"]) ? !!$aParams["verify"] : true; $iWarn = isset($aParams["warning"]) ? (int) ($aParams["warning"]) : 21; $iCrtitcal = isset($aParams["critical"]) ? (int) ($aParams["critical"]) : 5; $sMessage = "Checked url: $sUrl ... "; $certinfo = $this->_certGetInfos($sUrl, $bVerify); if (isset($certinfo['_error'])) { return [ RESULT_ERROR, $certinfo['_error'] . $sMessage ]; } /* unneeded: when verify is true (=default) then it cannot connect with wrong certificate $sDNS = $certinfo['extensions']['subjectAltName'] ?? false; $sHost = parse_url($sUrl, PHP_URL_HOST); if (strstr($sDNS, "DNS:$sHost") === false) { return [ RESULT_ERROR, "Wrong certificate: $sHost is not listed as DNS alias in [$sDNS]. $sMessage" ]; } */ $iDaysleft = round(($certinfo['validTo_time_t'] - date('U')) / 60 / 60 / 24); $sMessage .= 'Issuer: ' . $certinfo['issuer']['O'] . '; valid from: ' . date("Y-m-d H:i", $certinfo['validFrom_time_t']) . ' to ' . date("Y-m-d H:i", $certinfo['validTo_time_t']) . ' ' . ($iDaysleft ? "($iDaysleft days left)" : "expired since " . (-$iDaysleft) . " days.") ; if ($iDaysleft <= 0) { return [ RESULT_ERROR, 'Expired! ' . $sMessage ]; } if ($iDaysleft <= $iWarn) { return [ RESULT_WARNING, ($iDaysleft <= $iCrtitcal ? 'Expires very soon! ' : 'Expires soon. ' ) . $sMessage ]; } // echo '<pre>'; return [ RESULT_OK, 'OK. ' . ($bVerify ? 'Certificate is valid. ' : '(Verification is disabled; Check for expiration only.) ') . $sMessage ]; } }