Source code for saltext.vcf.clients.vim_host_ssl_thumbprint
"""Fetch and validate ESXi SSL certificate thumbprints.
``fetch`` opens a raw TLS connection (no SOAP); ``current`` reads the
thumbprint vCenter knows about; ``validate`` compares them.
"""
import socket
import ssl
from pyVmomi import vim
from saltext.vcf.utils import vim as soap
def _host(opts, host_id_or_name, profile=None):
content = soap.content(opts, profile=profile)
container = content.viewManager.CreateContainerView(content.rootFolder, [vim.HostSystem], True)
try:
for host in container.view:
if host_id_or_name in (host._moId, host.name): # noqa: SLF001
return host
finally:
container.Destroy()
raise LookupError(f"host {host_id_or_name!r} not found")
[docs]
def fetch(hostname, port=443, timeout=10):
"""Return the SHA-1 thumbprint of *hostname:port*'s SSL certificate, colon-separated.
No SOAP required. Used for pre-vCenter-add validation and drift checks.
"""
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
with socket.create_connection((hostname, port), timeout=timeout) as sock:
with ctx.wrap_socket(sock, server_hostname=hostname) as ssock:
der = ssock.getpeercert(binary_form=True)
import hashlib
digest = hashlib.sha1(der, usedforsecurity=False).hexdigest().upper() # nosec B324
return ":".join(digest[i : i + 2] for i in range(0, len(digest), 2))
[docs]
def current(opts, host, profile=None):
"""Return the thumbprint vCenter has cached for *host*."""
h = _host(opts, host, profile=profile)
info = getattr(h.summary.config, "sslThumbprint", None)
return info
[docs]
def validate(opts, host, profile=None):
"""Fetch the live thumbprint and compare against the one vCenter knows.
Returns ``{current, live, match}``. If the host's management address is
unreachable, ``live`` is ``None`` and ``match`` is ``False``.
"""
h = _host(opts, host, profile=profile)
cur = getattr(h.summary.config, "sslThumbprint", None)
address = h.name
try:
live = fetch(address)
except OSError:
live = None
return {"current": cur, "live": live, "match": bool(cur and live and cur == live)}