TLS Check
Synopsis
Director connects to one service from where it runs, asks it to start TLS where its protocol begins in the clear, makes the TLS handshake, and writes the result of every check itself as an ECS document: the TLS version and cipher agreed, the service's certificate, whether it verifies and the days it has left, and the state the service is in — up or down, since when, and after how many checks. After the handshake it sends no request and does not sign in. Nothing is installed on the service.
It is for the TLS services that are no web page, which an HTTP Check already asks: a mail server, LDAPS, a database listener, syslog over TLS, a VPN portal.
The TLS Check is one of six service check devices, each checking one service: a Website, an HTTP Check, a TCP Check, a DNS Check, an ICMP Check, and a TLS Check.
One device, one service. A device checks one service, so every service checked has a row of its own in the fleet list, and the device's connection state says whether that service is up.
The results are the device's own. Every check writes a result, up or down, with no dataset assigned. A TLS Check has no datasets: every result carries the service's certificate and the certificate of its chain that expires first. See Service Check Datasets.
The device dials the service and binds nothing, so service checks never collide on a port, and none blocks a listener on it. One Director owns each device.
The TLS Check device needs Director 2.3.1 or later. The other service check devices need 2.2.3.
Schema
- id: <numeric>
name: <string>
description: <string>
type: tls_check
tags: <string[]>
status: <boolean>
properties:
address: <string>
protocol: <string>
port: <numeric>
tls:
insecure_skip_verify: <boolean>
ca_name: <string>
server_name: <string>
min_tls_version: <string>
max_tls_version: <string>
cert_name: <string>
key_name: <string>
passphrase: <string>
interval: <numeric>
timeout: <numeric>
pipelines: <pipeline[]>
Configuration
The following fields are used to define the device:
Device
| Field | Required | Default | Description |
|---|---|---|---|
id | Y | - | Unique numeric identifier |
name | Y | - | Device name |
description | N | - | Optional description |
type | Y | - | Must be tls_check |
tags | N | - | Optional tags |
status | N | true | Enable/disable the device |
Target
| Field | Required | Default | Description |
|---|---|---|---|
address | Y | - | A host name or an IP address, without a scheme, a port, or a path — not a wildcard. An IPv6 address as it is, or in one pair of brackets |
protocol | N | tls | What the check says before its handshake. tls says nothing: the service starts in TLS (LDAPS, IMAPS, SMTPS, a database or a syslog listener). dtls says nothing either, and makes the DTLS 1.2 handshake over UDP — see DTLS. smtp, imap, pop3, ftp, ldap, and postgres make that protocol's request to start TLS — see The Request to Start TLS |
port | N | the protocol's | From 1 to 65535. Left out, it is 443 for tls, 25 for smtp, 143 for imap, 110 for pop3, 21 for ftp, 389 for ldap, and 5432 for postgres. Required for dtls, which has no port of its own (syslog over DTLS 6514, CoAP 5684, RADIUS 2083) |
TLS
| Field | Required | Default | Description |
|---|---|---|---|
tls.insecure_skip_verify | N | false | true makes the handshake with any certificate. The service is then up, and the result still says whether the certificate verifies. Pin the CA instead where you can |
tls.ca_name | N | - | A CA to verify the certificate against instead of the operating system's trust store: a path under the service root, or inline PEM |
tls.server_name | N | the address | The name the handshake sends, and the certificate is verified for |
tls.min_tls_version | N | tls1.2 | tls1.0 to tls1.3. With dtls, at most tls1.2 |
tls.max_tls_version | N | - | No cap. With dtls, at least tls1.2 when set |
tls.cert_name | N | - | A client certificate presented to a service that asks for one, and to no other. Needs tls.key_name. See A Client Certificate |
tls.key_name | N | - | Its private key. Needs tls.cert_name. Withheld from the API's device reads |
tls.passphrase | N | - | Decrypts an encrypted key (PKCS#8 or legacy PEM): plain text, ${ENV_VAR}, or $secret{...}. Withheld from the API's device reads |
TLS material fields (cert_name, key_name, ca_name, client_ca_name) accept any of the following:
- File name — resolved relative to the service root directory. Nested paths such as
certs/prod/server.pemare supported. - Absolute path — honored only if it resolves inside the service root. Any path that escapes the root is refused.
- Inline PEM content — used verbatim when the value contains
-----BEGIN. - Environment variable —
${ENV_VAR}. - Vault reference —
$secret{id=...}or$secret{store=...,ref=...}.
tls.status is not read: the check is a handshake.
Verification. The certificate is verified against the operating system's trust store, or tls.ca_name, for tls.server_name, and for the address when that is not set: a name by the names the certificate holds, an address by its addresses. So a service checked by address whose certificate names it by name needs tls.server_name.
A certificate that does not verify fails the check with Certificate error, and is still written: its dates, its names, and its days left. With tls.insecure_skip_verify the handshake is made with any certificate, the service is up, and the result says whether the certificate verifies (service_check.tls.certificate.verified) and why not (unverified), by the same trust store and for the same name.
Pipeline
The device takes at most one pre-processing pipeline of its own: the device's pipeline picker in the console, pipelines: in a configuration file. Its results go through it, and through none when the device has none.
Datasets
A TLS Check has no datasets: it writes its results directly. Every result carries the service's certificate under tls.server.x509.*, its days left, and the certificate of its chain that expires first (see Results and State), so the TLS Check Certificates dataset is retired; and Traceroute is a website's dataset alone. A dataset still assigned to the device is left out with a warning in the device's log — see Retired Datasets.
Advanced Configuration
| Field | Required | Default | Description |
|---|---|---|---|
interval | N | 60 | Seconds between checks: a result every interval. At least 10 |
timeout | N | 10 | Seconds the check may take whole — the name resolved, the connect, the request to start TLS, and the handshake — from 1 to 120 |
A configuration error — no address, a CA that cannot be read, an interval under its floor, a certificate without its key or a key without its certificate, a dtls check with no port or with versions that leave out TLS 1.2, material that cannot be read, a key the passphrase does not decrypt — stops the device with Configuration error. The message names the property, never its value. A number is read whole: a fraction, an infinity, or one no 32-bit integer holds is refused, never converted.
How a Check Works
Every check dials a connection of its own: the Director resolves the host, connects, asks the service to start TLS where its protocol begins in the clear, and makes the handshake. Once the handshake is made, it sends no request and does not sign in: it ends the session with a close_notify and closes the connection, so a service that logs a connection dropped without one as an error has none to log at every check.
The Request to Start TLS
protocol | What the check does | The yes it waits for |
|---|---|---|
smtp | Reads the greeting (220), sends EHLO with the Director's host name, then STARTTLS | 220 |
imap | Reads the greeting (* OK), sends STARTTLS | The tagged OK |
pop3 | Reads the greeting (+OK), sends STLS | +OK |
ftp | Reads the greeting (220), sends AUTH TLS | 234 |
ldap | Sends the StartTLS extended request | Result code 0 |
postgres | Sends SSLRequest | S |
A service that refuses the request, answers as another protocol's would, or goes on in the clear after its yes is down with error.type starttls, and the message quotes what it answered: the mail server refused STARTTLS: 502 5.5.1 Command not implemented. What a service may say before its handshake is bounded: a line of 2048 bytes, an answer of 64 lines.
Up and Down
The check is up when the handshake was made and the certificate verifies, or when tls.insecure_skip_verify is set, and a TLS 1.3 service that asked for a client certificate did not refuse the session after it. Otherwise it is down, and error.type says why:
error.type | When |
|---|---|
dns | The address does not resolve |
connection | The connection failed. For dtls, also a host that reported the port unreachable (ICMP port unreachable) |
timeout | The check did not finish within timeout. For dtls, also a handshake no answer came to |
starttls | The service did not take the request to start TLS |
certificate | The certificate does not verify |
client_certificate | The service refused the check's client certificate, or the lack of one |
handshake | The handshake failed for another reason. For dtls, also a port that answered with what is no DTLS |
A handshake that fails after the certificates still writes them. A service that refuses the check's client certificate, or the lack of one, has presented its own first, so the result has its certificate and days left.
Not included: DTLS 1.0 and 1.3, and a TLS 1.3 service's request for a client certificate after the handshake.
DTLS
protocol: dtls makes the DTLS 1.2 handshake with the service's UDP port, and the result says what a TLS handshake's says, with tls.version_protocol dtls and network.transport udp. Its port is required, and its versions must let TLS 1.2 through.
- A silent port is down with
timeoutwhen the timeout ends: a handshake that gets no answer is what a closed UDP port looks like, and a firewall that drops its datagrams looks the same. - A port the host reports closed (ICMP port unreachable) is down with
connectionat once. Windows reports none, so there it is atimeout. - A port that answers with what is no DTLS is down with
handshakeonce the timeout ends. - Lost datagrams are sent again after 1, 2, and 4 seconds, within the timeout.
The certificate is verified as over TLS, and a client certificate is presented and refused within the handshake, as under TLS 1.2.
A Client Certificate
With tls.cert_name and tls.key_name, the check presents the certificate to a service that asks for one, and to no other; without them it presents none. The certificate is read when the device starts, and one in a file again when the file changes.
A service that refuses the certificate, or the lack of one, is down with error.type client_certificate and the device's state is Authentication error, under TLS 1.2 and 1.3. The message ends with the alert the service sent: the service refused the check's client certificate: unknown certificate authority.
Under TLS 1.2 a service refuses the certificate within the handshake; under TLS 1.3 after it. So after a TLS 1.3 handshake whose service asked for a certificate, the check reads once for its verdict:
- an alert, or a session the service ended unasked, is the session refused: the check is down;
- a session ticket, or the service speaking first (an SMTPS or IMAPS greeting), is a yes, and the check is up at once;
- silence through the wait is a service that waits for the client to speak first: the check is up.
The wait is a second, or twice as long as the handshake took when that is longer, within the timeout. Nothing is read after a TLS 1.2 handshake, or a TLS 1.3 one whose service did not ask for a certificate.
Results and State
Every check writes one result, with event.dataset tls_check and definition id 12155, to the metric table:
destination.address,ip,port;network.transport(tcp, orudpfordtls),protocol(the device'sprotocol).tls.established(falsetoo for a session refused after a TLS 1.3 handshake),version,version_protocol(tlsordtls),cipher;tls.server.x509.*(the service's own certificate, verified or not) andtls.server.hash.sha256(its fingerprint), as an HTTP Check's.service_check.tls.protocol,server_name, andrtt.dns(the name's lookup),connect(none fordtls),starttls,tls_handshake,total(the parts the check finished).service_check.tls.certificate.verified,certificate.unverified(why not),certificate.days_left, andcertificate.chain.length,days_left,position,common_name,sha256, as an HTTP Check's: the certificate of the chain that expires first, and its days left.service_check.tls.client_certificate.requested(trueonce the service asked for a client certificate;falseafter a handshake made without its asking; left out when the check ended before it could tell) andclient_certificate.presented(whether the check presentedtls.cert_name).
A check that failed before any certificate came has no tls and no certificate.
Every result carries the state the service is in, under state.*, and every service check writes the same fields. For the state's fields, how to alert on it, and the fields every record carries, see Results and State.
Connection States
The device's connection state follows the service checked, and the fleet list shows it:
| State | When |
|---|---|
| Connected | The service is up |
| Connection error | It does not answer, or its name does not resolve |
| Certificate error | Its certificate does not verify |
| Authentication error | It refused the check's client certificate, or required one the device does not name |
| Error | It did not take the request to start TLS, or its handshake failed for another reason than its certificate |
| Configuration error | A configuration that does not validate |
The message says what the check ran into (db01.example.com:5432 is down: connect: connection refused), in words that stay the same while the failure does, so the state moves only when the service's does.
Console
In the console, go to
General settings , as on every device, with the device's pre-processing pipeline.Check settings :Address ,Port , andProtocol —TLS ,DTLS (over UDP) ,SMTP (STARTTLS) ,IMAP (STARTTLS) ,POP3 (STLS) ,FTP (AUTH TLS) ,LDAP (StartTLS) , orPostgreSQL (SSLRequest) . The port follows the protocol while it is still the protocol's own: choosingSMTP (STARTTLS) turns443into25. A port you entered stays. DTLS has no port of its own: choosing it empties a port that was the protocol's. A DTLS check with no port is refused, as are versions that leave out TLS 1.2. Then theTLS settings :Skip certificate verification ,CA certificate ,Server name (Optional) , and the minimum and maximum TLS version. The CA certificate stays while verification is skipped, since the result still says by it whether the certificate verifies. Then theClient certificate :Certificate (Optional) ,Private key (Optional) , andPassphrase (Optional) , on every protocol; the certificate and key go together. The review shows only whether one is set.Advanced settings :Interval andTimeout .Review and create .
There is no
With no Director or cluster at version 2.3.1 or later selected, the wizard shows TLS Check devices are unavailable on directors or clusters below version 2.3.1, and the device cannot be created.
Simulation
The TLS Check is not simulated. What it writes is what its check finds, with the state the service is in, which one generic sample cannot stand in for.
Examples
Mail Submission with STARTTLS
Checking a mail submission port every five minutes over SMTP's STARTTLS. Every result carries the certificate it presents and the certificate of its chain that expires first... | |
LDAPS with a Private CA
Checking an LDAPS service, which starts in TLS, against the organization's own CA. The port is the service's, since | |
Database Listener by Address
Checking a PostgreSQL listener by its address on the protocol's own port, | |
Syslog over DTLS with a Client Certificate
Checking a syslog receiver over DTLS that takes only the senders whose certificate its authority issued, so the check presents the Director's. DTLS has no port of its own, so the port is named. The result's | |