Hi,

we would like to monitor our mail server certificates for tls etc. Any chance to do so? We tried all SSL sensors but they all can not connect correctly. Is there a solution for that problem?


Article Comments

Dear 4itsAdmin

Please contact support@paessler.com. Please state your question again, and include screenshots of one of the SSL Certificate sensors:

  • The sensor overview tab
  • The logs tab
  • The settings tab (multiple screenshots if necessary to cover all settings.)

Aug, 2016 - Permalink

Hello, any solution for this question yet?

I'm also looking for a solution to monitor SMTP certificates. The SSL Certifcate Sensor is only able to monitor HTTP/S, not STARTTLS over SMTP.


Jul, 2018 - Permalink

Dear Cesare,

this is correct. We have this planned, but I cannot say when it gets to implementation. We notice the demand (and please consider your voice counted) but again, there is no ETA yet.


Jul, 2018 - Permalink

Dear Arne,

I would appreciate if you will offer such an sensor ASAP. Today is important to monitor the email-encryption of the MX Servers.


Apr, 2019 - Permalink

Dear NTTITS,

we have such sensor idea, but I cannot say when, or if a STARTTSL option for SSL monitoring will be available, because other sensors are in higher demand. In order to get a good overview of user demands, the knowledge base can be used to describe a feature request.


Apr, 2019 - Permalink

Dear Arne,

is there any news? I have the same request, need to monitor SMTP-TLS-Certifiactes.

Thanks Golo


Jul, 2019 - Permalink

Dear DerGolo,

for the foreseeable future, such sensor is not planned. If you like, you can create a feature request.


Jul, 2019 - Permalink

Solution

Take a Linux/Debian machine and do this:

  • install a Nagios plugin check_smtp which does the real work
  • create a wrapper script for PRTG /var/prtg/scripts/check_smtp_ssl_certificate.pl
  • execute wrapper script from PRTG with the "SSH Script" sensor

Install Nagios plugin on the linux server

# su
# apt-get install monitoring-plugins-basic

Check wether the service works:

/usr/lib/nagios/plugins/check_smtp -H smtp.zirndorf.de -S -D 60

OK - Certificate '*.zirndorf.de' will expire on Thu 15 Apr 2021 04:19:00 PM CEST.

Create wrapper script for PRTG on the linux server

mkdir -p /var/prtg/scripts
chmod 755 /var/prtg/scripts
touch /var/prtg/scripts/check_smtp_ssl_certificate.pl
chmod 755 /var/prtg/scripts/check_smtp_ssl_certificate.pl
vi /var/prtg/scripts/check_smtp_ssl_certificate.pl

This is the file check_smtp_ssl_certificate.pl:

#!/usr/bin/env perl
# v1, 2019-10-31, init, lippmann@zirndorf.de

=head1 SYNOPSIS

Checking fileage for PRTG via ssh

This is /var/prtg/scripts/check_smtp_ssl_certificate.pl

Usage:

/var/prtg/scripts/check_smtp_ssl_certificate.pl --smtp_server=smtp.zirndorf.de --warning_number_of_days=30 --critical_number_of_days=10

=cut

use strict;
use warnings;
use Getopt::Long;

# PRTG-Status from
# https://helpdesk.paessler.com/en/support/solutions/articles/76000063557-is-there-a-shell-script-example-for-the-prtg-ssh-script-sensor
my $prtg_status_ok      = 0;
my $prtg_status_warning = 1;
my $prtg_status_error   = 2;

# Defaults:
my $smtp_server             = '';
my $warning_number_of_days  = 30;
my $critical_number_of_days = 10;

GetOptions(
    "smtp_server=s",             \$smtp_server,
    "warning_number_of_days=s",  \$warning_number_of_days,
    "critical_number_of_days=s", \$critical_number_of_days,
);

# Sanity check of arguments from commandline
if (  !$smtp_server
    || $smtp_server !~ m/^[a-z0-9\-\.]+$/
    || $critical_number_of_days !~ m/^[0-9]+$/
    || $warning_number_of_days !~ m/^[0-9]+$/ )
{
    print
"$prtg_status_error:0:Usage $0 --smtp_server=smtp.zirndorf.de --warning_number_of_days=30 --critical_number_of_days=10\n";
    exit;
}

# Documentation for the nagios check:
# https://www.monitoring-plugins.org/doc/man/check_smtp.html
my $cmd = sprintf '/usr/lib/nagios/plugins/check_smtp -H %s -S -D %d,%d',
    $smtp_server, $warning_number_of_days, $critical_number_of_days;
my $result_from_nagioscheck = `$cmd`;

# Check result from nagios-check:
# OK - Certificate '*.zirndorf.de' will expire on Thu 15 Apr 2021 04:19:00 PM CEST.
# WARNING - Certificate '*.zirndorf.de' expires in 532 day(s) (Thu 15 Apr 2021 04:19:00 PM CEST).
# CRITICAL - Certificate '*.zirndorf.de' expires in 532 day(s) (Thu 15 Apr 2021 04:19:00 PM CEST).

# Defaults:
my $prtg_status      = $prtg_status_error;
my $prtg_status_text = 'unknown';

# I don't care because I do not get number of days
# of certificate valid on all 3 statuses from Nagios check
my $prtg_number_to_return = 0;

if ($result_from_nagioscheck =~ m/^WARNING/) {
    $prtg_status      = $prtg_status_warning;
    $prtg_status_text = $result_from_nagioscheck;
} elsif ($result_from_nagioscheck =~ m/^CRITICAL/) {
    $prtg_status      = $prtg_status_error;
    $prtg_status_text = $result_from_nagioscheck;
} elsif ($result_from_nagioscheck =~ m/^OK/) {
    $prtg_status      = $prtg_status_ok;
    $prtg_status_text = $result_from_nagioscheck;
}

print join( ':', $prtg_status, $prtg_number_to_return, $prtg_status_text )
  . "\n";

Check the PRTG-check on Linux commandline

/var/prtg/scripts/check_smtp_ssl_certificate.pl --smtp_server=smtp.zirndorf.de --warning_number_of_days=30 --critical_number_of_days=10

0:0:OK - Certificate '*.zirndorf.de' will expire on Thu 15 Apr 2021 04:19:00 PM CEST.

Create PRTG-SSH-Check

You need to create a public and private key for PRTG to reach the linux-server which runs the check

See https://www.paessler.com/manuals/prtg/ssh_script_sensor

Name of the check in PRTG: smtp-ssl-certificate-validtime

Script must be visible from a dropdown list in the user interface webpage from PRTG.

The parameters for the SSH-Scripts are like this:

--smtp_server=smtp.yourdomain.com --warning_number_of_days=30 --critical_number_of_days=10

You will see the output string of the command like this:

Certificate '*.zirndorf.de' will expire on Thu 15 Apr 2021 04:19:00 PM CEST.

as "message" in your PRTG-check.


Oct, 2019 - Permalink

Hey,

Thanks for sharing your work with us.

We appreciate that.


Kind regards,
Birk Guttmann, Tech Support Team


Oct, 2019 - Permalink

I needed something for this too. I don't have the option of deploying Nagios, so wrote something that works for us (we only care about the days remaining and our mail relays). Treat the below as a functional barebones/alpha release as it only started and completed yesterday. Unless it breaks for us, there won't be any changes.

Code is .C# NET CORE 5 console app, but will probably work in older versions. .NET 4.8 is possible, just untested. Download Visual Studio Community Edition 2019+/VS Code to compile it

If you use this, please feel free, but leave the credit line at the top somewhere in your code.

TY

//Author: Wayne Evans
//Date: 2021-10-07
//URL: https://helpdesk.paessler.com/en/support/solutions/articles/70942-how-can-we-monitor-smtp-ssl-certificates

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace MailrelayCertificates
{
    public class certInfo
    {
        public int DaysToExpiration { get; set; }
        public string Issuer { get; set; }
        public DateTime NotAfter { get; set; }
        public DateTime NotBefore { get; set; }
        public string SerialNumber { get; set; }
        public string Subject { get; set; }
        public string Thumbprint { get; set; }
        public int PublicKeyLength { get; set; }
        public int SelfSign { get; set; }
    }

    public class root
    {
        public prtg prtg { get; set; }
    }

    public class prtg
    {
        public List<result> result { get; set; }
        public string text { get; set; }
    }

    public class result
    {
        public string channel { get; set; }
        public string value { get; set; }
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
        public string valuelookup { get; set; }
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
        public int LimitMinWarning { get; set; }
        [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
        public int LimitMinError { get; set; }
    }



    class Program
    {
        private static certInfo extractedCertificate;

        static void Main(string[] args)
        {
            if ((args.Count() == 0) || (args.Count() > 2))
            {
                Console.WriteLine("Mandatory Argument 1 should be the server or load balancer name, e.g. myinternalmailserver.internal.com");
                Console.WriteLine("Optional Argument 2 port number to test against.  Defaults to port 25");
            }

            string server = args[0];
            int port = 25;

            if (args.Count() == 2)
            {
                try
                {
                    port = Convert.ToInt32(args[1]);
                }
                catch
                {
                    Console.WriteLine("Second arguement needs to be a number for the port number");
                }
            }

            System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(RemoteServerCertificateValidationCallback);

            using (System.Net.Mail.SmtpClient S = new System.Net.Mail.SmtpClient(server, port))
            {
                S.EnableSsl = true;
                using (System.Net.Mail.MailMessage M = new System.Net.Mail.MailMessage("deadAccountGoesNowhere@superfakedomain20211007.com", "deadAccountGoesNowhere@superfakedomain20211007.com", "Certification Validataion Test", "Certification Validataion Test"))
                {
                    try
                    {
                        S.Send(M);
                    }
                    catch (Exception ex)
                    {
                        //return;
                    }


                }
            }

            root output = new root();
            output.prtg = new prtg();
            output.prtg.result = new List<result>();
            output.prtg.result.Add(new result() { channel = "Days to Expiration", value = extractedCertificate.DaysToExpiration.ToString(), LimitMinError = 4, LimitMinWarning = 14 });
            output.prtg.result.Add(new result() { channel = "Public Key Length", value = extractedCertificate.PublicKeyLength.ToString(), valuelookup = "prtg.standardlookups.sslcertificatesensor.publickey" });
            output.prtg.result.Add(new result() { channel = "Self-Signed", value = extractedCertificate.SelfSign.ToString(), valuelookup = "prtg.standardlookups.sslcertificatesensor.selfsigned" });
            output.prtg.text = "Certificate Issuer: " + extractedCertificate.Issuer + " - Certificate Thumbprint: " + extractedCertificate.Thumbprint;

            Console.WriteLine(JsonSerializer.Serialize(output));

        }

        private static bool RemoteServerCertificateValidationCallback(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
        {
            //Console.WriteLine(certificate);
            extractedCertificate = new certInfo()
            {
                Issuer = ((System.Security.Cryptography.X509Certificates.X509Certificate2)certificate).Issuer,
                NotAfter = ((System.Security.Cryptography.X509Certificates.X509Certificate2)certificate).NotAfter,
                NotBefore = ((System.Security.Cryptography.X509Certificates.X509Certificate2)certificate).NotBefore,
                PublicKeyLength = ((System.Security.Cryptography.X509Certificates.X509Certificate2)certificate).PublicKey.Key.KeySize,
                SerialNumber = ((System.Security.Cryptography.X509Certificates.X509Certificate2)certificate).SerialNumber,
                SelfSign = IsSelfSigned(new X509Certificate2(certificate)),
                Subject = ((System.Security.Cryptography.X509Certificates.X509Certificate2)certificate).Subject,
                Thumbprint = ((System.Security.Cryptography.X509Certificates.X509Certificate2)certificate).Thumbprint
            };

            TimeSpan remainingUntilExpiry = ((System.Security.Cryptography.X509Certificates.X509Certificate2)certificate).NotAfter.Subtract(DateTime.UtcNow);
            extractedCertificate.DaysToExpiration = (int)remainingUntilExpiry.TotalDays;

            //I don't think we have a full cert path deployed.  Looks like an CA cert deploy, so can't test.  Leaving commented out

            //// You can alter how the chain is built/validated.
            //chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
            //chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreWrongUsage;

            //// Do the preliminary validation.
            //var primaryCert = new X509Certificate2(certificate);
            //if (!chain.Build(primaryCert))
            //    return false;

            //// Make sure we have the same number of elements.
            //if (chain.ChainElements.Count != chain.ChainPolicy.ExtraStore.Count + 1)
            //    return false;

            //// Make sure all the thumbprints of the CAs match up.
            //// The first one should be 'primaryCert', leading up to the root CA.
            //for (var i = 1; i < chain.ChainElements.Count; i++)
            //{
            //    if (chain.ChainElements[i].Certificate.Thumbprint != chain.ChainPolicy.ExtraStore[i - 1].Thumbprint)
            //        return false;
            //}

            return true;
        }

        //https://stackoverflow.com/questions/34174435/how-can-i-check-if-a-certificate-is-self-signed
        public static int IsSelfSigned(X509Certificate2 cert)
        {
            if (cert.SubjectName.RawData.SequenceEqual(cert.IssuerName.RawData))
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }

    }
}

Oct, 2021 - Permalink

Hey,

Thanks for sharing your work as well. We really appreciate that.


Kind regards,
Birk Guttmann, Tech Support Team


Oct, 2021 - Permalink

I really want this feature.. been wanting it for 6 years or so and still not implemented.


Apr, 2022 - Permalink

@Wayne;

Just what I've been looking for! How do you create a PRTG sensor to pass the site's https: address to your C# code??


Aug, 2022 - Permalink

Really, in the 2023 the only way to monitor a super common piece of infrastructure, like the certificate issued with STARTTLS by a SMTP relay, is to use a custom script or nagios?


Aug, 2023 - Permalink

Hello Dear customer,

Thank you for your interest! Our dedicated development team is actively working on implementing various features, including the one you mentioned. While we're committed to delivering the best experience, we currently don't have a specific estimated timeframe for when this feature will be fully implemented. We appreciate your patience and will keep you updated on our progress.

Regards


Aug, 2023 - Permalink