Source code for saltext.acme.states.acme

"""
Manage X.509 certificates statefully using Certbot.

.. hint::

    Also see the :py:mod:`execution module documentation <saltext.acme.modules.acme>`.

Example
-------
.. code-block:: yaml

    reload-gitlab:
      cmd.run:
        - name: gitlab-ctl hup

    dev.example.com:
      acme.cert:
        - aliases:
          - gitlab.example.com
        - email: acmemaster@example.com
        - webroot: /opt/gitlab/embedded/service/gitlab-rails/public
        - renew: 14
        - fire_event: acme/dev.example.com
        - onchanges_in:
          - cmd: reload-gitlab

"""

import logging

import salt.utils.dictdiffer

log = logging.getLogger(__name__)


def __virtual__():
    if "acme.cert" in __salt__:
        return True
    return (False, "acme module could not be loaded")


[docs] def cert( name, aliases=None, email=None, webroot=None, test_cert=False, renew=None, keysize=None, server=None, owner="root", group="root", mode="0640", certname=None, preferred_challenges=None, tls_sni_01_port=None, tls_sni_01_address=None, http_01_port=None, http_01_address=None, dns_plugin=None, dns_plugin_credentials=None, manual_auth_hook=None, manual_cleanup_hook=None, ): """ Obtain/renew a certificate from an ACME CA, probably Let's Encrypt. :param name: Common Name of the certificate (DNS name of certificate) :param aliases: subjectAltNames (Additional DNS names on certificate) :param email: e-mail address for interaction with ACME provider :param webroot: True or a full path to webroot. Otherwise use standalone mode :param test_cert: Request a certificate from the Happy Hacker Fake CA (mutually exclusive with 'server') :param renew: True/'force' to force a renewal, or a window of renewal before expiry in days :param keysize: RSA key bits :param server: API endpoint to talk to :param owner: owner of the private key file :param group: group of the private key file :param mode: mode of the private key file :param certname: Name of the certificate to save :param preferred_challenges: A sorted, comma delimited list of the preferred challenge to use during authorization with the most preferred challenge listed first. :param tls_sni_01_port: Port used during tls-sni-01 challenge. This only affects the port Certbot listens on. A conforming ACME server will still attempt to connect on port 443. :param tls_sni_01_address: The address the server listens to during tls-sni-01 challenge. :param http_01_port: Port used in the http-01 challenge. This only affects the port Certbot listens on. A conforming ACME server will still attempt to connect on port 80. :param https_01_address: The address the server listens to during http-01 challenge. :param dns_plugin: Name of a DNS plugin to use (currently only 'cloudflare') :param dns_plugin_credentials: Path to the credentials file if required by the specified DNS plugin :param manual_auth_hook: Path to the authentication hook script. :param manual_cleanup_hook: Path to the cleanup or post-authentication hook script. """ if certname is None: certname = name ret = {"name": certname, "result": "changeme", "comment": [], "changes": {}} action = None current_certificate = {} new_certificate = {} if not __salt__["acme.has"](certname): action = "obtain" elif __salt__["acme.needs_renewal"](certname, renew): action = "renew" current_certificate = __salt__["acme.info"](certname) else: ret["result"] = True ret["comment"].append(f"Certificate {certname} exists and does not need renewal.") if action: if __opts__["test"]: ret["result"] = None ret["comment"].append(f"Certificate {certname} would have been {action}ed.") ret["changes"] = {"old": "current certificate", "new": "new certificate"} else: res = __salt__["acme.cert"]( name, aliases=aliases, email=email, webroot=webroot, certname=certname, test_cert=test_cert, renew=renew, keysize=keysize, server=server, owner=owner, group=group, mode=mode, preferred_challenges=preferred_challenges, tls_sni_01_port=tls_sni_01_port, tls_sni_01_address=tls_sni_01_address, http_01_port=http_01_port, http_01_address=http_01_address, dns_plugin=dns_plugin, dns_plugin_credentials=dns_plugin_credentials, manual_auth_hook=manual_auth_hook, manual_cleanup_hook=manual_cleanup_hook, ) ret["result"] = res["result"] ret["comment"].append(res["comment"]) if ret["result"]: new_certificate = __salt__["acme.info"](certname) ret["changes"] = salt.utils.dictdiffer.deep_diff(current_certificate, new_certificate) return ret