salt.states.x509_v2

Manage X.509 certificates

New in version 3006.0: This module represents a complete rewrite of the original x509 modules and is named x509_v2 since it introduces breaking changes.

depends:

cryptography

Note

All parameters that take a public key, private key, certificate, CSR or CRL can be specified either as a PEM/hex/base64 string or a path to a local file encoded in all supported formats for the type.

Configuration instructions and general remarks are documented in the execution module docs.

For the list of breaking changes versus the previous x509 modules, please also refer to the execution module docs.

About

This module can enable managing a complete PKI infrastructure, including creating private keys, CAs, certificates and CRLs. It includes the ability to generate a private key on a server, and have the corresponding public key sent to a remote CA to create a CA signed certificate. This can be done in a secure manner, where private keys are always generated locally and never moved across the network.

Example

Here is a simple example scenario. In this example ca is the ca server, and www is a web server that needs a certificate signed by ca.

Note

Remote signing requires the setup of Peer Communication and signing policies. Please see the execution module docs.

/srv/salt/top.sls

base:
  '*':
    - cert
  'ca':
    - ca
  'www':
    - www

This state creates the CA key, certificate and signing policy. It also publishes the certificate to the mine, where it can be easily retrieved by other minions.

# /srv/salt/ca.sls

Configure the x509 module:
  file.managed:
    - name: /etc/salt/minion.d/x509.conf
    - source: salt://x509.conf

Restart Salt minion:
  cmd.run:
    - name: 'salt-call service.restart salt-minion'
    - bg: true
    - onchanges:
      - file: /etc/salt/minion.d/x509.conf

Ensure PKI directories exist:
  file.directory:
    - name: /etc/pki/issued_certs
    - makedirs: true

Create CA private key:
  x509.private_key_managed:
    - name: /etc/pki/ca.key
    - keysize: 4096
    - backup: true
    - require:
      - file: /etc/pki/issued_certs

Create self-signed CA certificate:
  x509.certificate_managed:
    - name: /etc/pki/ca.crt
    - signing_private_key: /etc/pki/ca.key
    - CN: ca.example.com
    - C: US
    - ST: Utah
    - L: Salt Lake City
    - basicConstraints: "critical, CA:true"
    - keyUsage: "critical, cRLSign, keyCertSign"
    - subjectKeyIdentifier: hash
    - authorityKeyIdentifier: keyid:always,issuer
    - days_valid: 3650
    - days_remaining: 0
    - backup: true
    - require:
      - x509: /etc/pki/ca.key
# /srv/salt/x509.conf

# enable x509_v2
features:
  x509_v2: true

# publish the CA certificate to the mine
mine_functions:
  x509.get_pem_entries: [/etc/pki/ca.crt]

# define at least one signing policy for remote signing
x509_signing_policies:
  www:
    - minions: 'www'
    - signing_private_key: /etc/pki/ca.key
    - signing_cert: /etc/pki/ca.crt
    - C: US
    - ST: Utah
    - L: Salt Lake City
    - basicConstraints: "critical CA:false"
    - keyUsage: "critical keyEncipherment"
    - subjectKeyIdentifier: hash
    - authorityKeyIdentifier: keyid:always,issuer
    - days_valid: 30
    - copypath: /etc/pki/issued_certs/

This example state will instruct all minions to trust certificates signed by our new CA. Mind that this example works for Debian-based OS only. Also note the Jinja call to encode the string to JSON, which will avoid YAML issues with newline characters.

# /srv/salt/cert.sls

Ensure the CA trust bundle exists:
  file.directory:
    - name: /usr/local/share/ca-certificates

Ensure our self-signed CA certificate is included:
  x509.pem_managed:
    - name: /usr/local/share/ca-certificates/myca.crt
    - text: {{ salt["mine.get"]("ca", "x509.get_pem_entries")["ca"]["/etc/pki/ca.crt"] | json }}

This state creates a private key, then requests a certificate signed by our CA according to the www policy.

# /srv/salt/www.sls

Ensure PKI directory exists:
  file.directory:
    - name: /etc/pki

Create private key for the certificate:
  x509.private_key_managed:
    - name: /etc/pki/www.key
    - keysize: 4096
    - backup: true
    - require:
      - file: /etc/pki

Request certificate:
  x509.certificate_managed:
    - name: /etc/pki/www.crt
    - ca_server: ca
    - signing_policy: www
    - private_key: /etc/pki/www.key
    - CN: www.example.com
    - days_remaining: 7
    - backup: true
    - require:
      - x509: /etc/pki/www.key
salt.states.x509_v2.certificate_managed(name, days_remaining=None, ca_server=None, signing_policy=None, encoding='pem', append_certs=None, copypath=None, prepend_cn=False, digest='sha256', signing_private_key=None, signing_private_key_passphrase=None, signing_cert=None, public_key=None, private_key=None, private_key_passphrase=None, csr=None, subject=None, serial_number=None, not_before=None, not_after=None, days_valid=None, pkcs12_passphrase=None, pkcs12_encryption_compat=False, pkcs12_friendlyname=None, **kwargs)

Ensure an X.509 certificate is present as specified.

This function accepts the same arguments as x509.create_certificate, as well as most ones for :py:func:`file.managed <salt.states.file.managed>.

name

The path the certificate should be present at.

days_remaining

The certificate will be recreated once the remaining certificate validity period is less than this number of days. Defaults to 90 (until v3009) or 7 (from v3009 onwards).

ca_server

Request a remotely signed certificate from ca_server. For this to work, a signing_policy must be specified, and that same policy must be configured on the ca_server. Also, the Salt master must permit peers to call the x509.sign_remote_certificate function. See the execution module docs for details.

signing_policy

The name of a configured signing policy. Parameters specified in there are hardcoded and cannot be overridden. This is required for remote signing, otherwise optional.

encoding

Specify the encoding of the resulting certificate. It can be serialized as a pem (or pkcs7_pem) text file or in several binary formats (der, pkcs7_der, pkcs12). Defaults to pem.

append_certs

A list of additional certificates to append to the new one, e.g. to create a CA chain.

Note

Mind that when der encoding is in use, appending certificatees is prohibited.

copypath

Create a copy of the issued certificate in PEM format in this directory. The file will be named <serial_number>.crt if prepend_cn is false.

prepend_cn

When copypath is set, prepend the common name of the certificate to the file name like so: <CN>-<serial_number>.crt. Defaults to false.

digest

The hashing algorithm to use for the signature. Valid values are: sha1, sha224, sha256, sha384, sha512, sha512_224, sha512_256, sha3_224, sha3_256, sha3_384, sha3_512. Defaults to sha256. This will be ignored for ed25519 and ed448 key types.

signing_private_key

The private key corresponding to the public key in signing_cert. Required.

signing_private_key_passphrase

If signing_private_key is encrypted, the passphrase to decrypt it.

signing_cert

The CA certificate to be used for signing the issued certificate.

public_key

The public key the certificate should be issued for. Other ways of passing the required information are private_key and csr. If neither are set, the public key of the signing_private_key will be included, i.e. a self-signed certificate is generated.

private_key

The private key corresponding to the public key the certificate should be issued for. This is one way of specifying the public key that will be included in the certificate, the other ones being public_key and csr.

private_key_passphrase

If private_key is specified and encrypted, the passphrase to decrypt it.

csr

A certificate signing request to use as a base for generating the certificate. The following information will be respected, depending on configuration:

  • public key

  • extensions, if not otherwise specified (arguments, signing_policy)

subject

The subject's distinguished name embedded in the certificate. This is one way of passing this information (see kwargs below for the other). This argument will be preferred and allows to control the order of RDNs in the DN as well as to embed RDNs with multiple attributes. This can be specified as a RFC4514-encoded string (CN=example.com,O=Example Inc,C=US, mind that the rendered order is reversed from what is embedded), a list of RDNs encoded as in RFC4514 (["C=US", "O=Example Inc", "CN=example.com"]) or a dictionary ({"CN": "example.com", "C": "US", "O": "Example Inc"}, default ordering). Multiple name attributes per RDN are concatenated with a +.

Note

Parsing of RFC4514 strings requires at least cryptography release 37.

serial_number

A serial number to be embedded in the certificate. If unspecified, will autogenerate one. This should be an integer, either in decimal or hexadecimal notation.

not_before

Set a specific date the certificate should not be valid before. The format should follow %Y-%m-%d %H:%M:%S and will be interpreted as GMT/UTC. Defaults to the time of issuance.

not_after

Set a specific date the certificate should not be valid after. The format should follow %Y-%m-%d %H:%M:%S and will be interpreted as GMT/UTC. If unspecified, defaults to the current time plus days_valid days.

days_valid

If not_after is unspecified, the number of days from the time of issuance the certificate should be valid for. Defaults to 365 (until v3009) or 30 (from v3009 onwards).

pkcs12_passphrase

When encoding a certificate as pkcs12, encrypt it with this passphrase.

Note

PKCS12 encryption is very weak and should not be relied on for security.

pkcs12_encryption_compat

OpenSSL 3 and cryptography v37 switched to a much more secure default encryption for PKCS12, which might be incompatible with some systems. This forces the legacy encryption. Defaults to False.

pkcs12_friendlyname

When encoding a certificate as pkcs12, a name for the certificate can be included.

kwargs

Embedded X.509v3 extensions and the subject's distinguished name can be controlled via supplemental keyword arguments. See x509.create_certificate for an overview.

salt.states.x509_v2.crl_managed(name, signing_private_key, revoked, days_remaining=None, signing_cert=None, signing_private_key_passphrase=None, include_expired=False, days_valid=None, digest='sha256', encoding='pem', extensions=None, **kwargs)

Ensure a certificate revocation list is present as specified.

This function accepts the same arguments as x509.create_crl, as well as most ones for :py:func:`file.managed <salt.states.file.managed>.

name

The path the certificate revocation list should be present at.

signing_private_key

Your certificate authority's private key. It will be used to sign the CRL. Required.

revoked

A list of dicts containing all the certificates to revoke. Each dict represents one certificate. A dict must contain either the key serial_number with the value of the serial number to revoke, or certificate with some reference to the certificate to revoke.

The dict can optionally contain the revocation_date key. If this key is omitted, the revocation date will be set to now. It should be a string in the format %Y-%m-%d %H:%M:%S.

The dict can also optionally contain the not_after key. This is redundant if the certificate key is included. If the certificate key is not included, this can be used for the logic behind the include_expired parameter. It should be a string in the format %Y-%m-%d %H:%M:%S.

The dict can also optionally contain the extensions key, which allows to set CRL entry-specific extensions. The following extensions are supported:

certificateIssuer

Identifies the certificate issuer associated with an entry in an indirect CRL. The format is the same as for subjectAltName.

CRLReason

Identifies the reason for certificate revocation. Available choices are unspecified, keyCompromise, CACompromise, affiliationChanged, superseded, cessationOfOperation, certificateHold, privilegeWithdrawn, aACompromise and removeFromCRL.

invalidityDate

Provides the date on which the certificate became invalid. The value should be a string in the same format as revocation_date.

days_remaining

The certificate revocation list will be recreated once the remaining CRL validity period is less than this number of days. Defaults to 30 (until v3009) or 3 (from v3009 onwards). Set to 0 to disable automatic renewal without anything changing.

signing_cert

The CA certificate to be used for signing the issued certificate.

signing_private_key_passphrase

If signing_private_key is encrypted, the passphrase to decrypt it.

include_expired

Also include already expired certificates in the CRL. Defaults to false.

days_valid

The number of days that the CRL should be valid for. This sets the Next Update field in the CRL. Defaults to 100 (until v3009) or 7 (from v3009 onwards).

digest

The hashing algorithm to use for the signature. Valid values are: sha1, sha224, sha256, sha384, sha512, sha512_224, sha512_256, sha3_224, sha3_256, sha3_384, sha3_512. Defaults to sha256. This will be ignored for ed25519 and ed448 key types.

encoding

Specify the encoding of the resulting certificate revocation list. It can be serialized as a pem text or binary der file. Defaults to pem.

extensions

Add CRL extensions. See x509.create_crl for details.

Note

For cRLNumber, in addition the value auto is supported, which automatically increases the counter every time a new CRL is issued.

Example:

Manage CRL:
  x509.crl_managed:
    - name: /etc/pki/ca.crl
    - signing_private_key: /etc/pki/myca.key
    - signing_cert: /etc/pki/myca.crt
    - revoked:
      - certificate: /etc/pki/certs/badweb.crt
        revocation_date: 2022-11-01 00:00:00
        extensions:
          CRLReason: keyCompromise
      - serial_number: D6:D2:DC:D8:4D:5C:C0:F4
        not_after: 2023-03-14 00:00:00
        revocation_date: 2022-10-25 00:00:00
        extensions:
          CRLReason: cessationOfOperation
    - extensions:
        cRLNumber: auto
salt.states.x509_v2.csr_managed(name, private_key, private_key_passphrase=None, digest='sha256', encoding='pem', subject=None, **kwargs)

Ensure a certificate signing request is present as specified.

This function accepts the same arguments as x509.create_csr, as well as most ones for file.managed.

name

The path the certificate signing request should be present at.

private_key

The private key corresponding to the public key the certificate should be issued for. The CSR will be signed by it. Required.

private_key_passphrase

If private_key is encrypted, the passphrase to decrypt it.

digest

The hashing algorithm to use for the signature. Valid values are: sha1, sha224, sha256, sha384, sha512, sha512_224, sha512_256, sha3_224, sha3_256, sha3_384, sha3_512. Defaults to sha256. This will be ignored for ed25519 and ed448 key types.

encoding

Specify the encoding of the resulting certificate revocation list. It can be serialized as a pem text or binary der file. Defaults to pem.

kwargs

Embedded X.509v3 extensions and the subject's distinguished name can be controlled via supplemental keyword arguments. See x509.create_certificate for an overview. Mind that some extensions are not available for CSR (authorityInfoAccess, authorityKeyIdentifier, issuerAltName, crlDistributionPoints).

salt.states.x509_v2.pem_managed(name, text, **kwargs)

Manage the contents of a PEM file directly with the content in text, ensuring correct formatting.

name

The path to the file to manage.

text

The PEM-formatted text to write.

kwargs

Most arguments supported by file.managed are passed through.

salt.states.x509_v2.private_key_managed(name, algo='rsa', keysize=None, passphrase=None, encoding='pem', new=False, overwrite=False, pkcs12_encryption_compat=False, **kwargs)

Ensure a private key is present as specified.

This function accepts the same arguments as x509.create_private_key, as well as most ones for file.managed.

Note

If mode is unspecified, it will default to 0400.

name

The path the private key should be present at.

algo

The digital signature scheme the private key should be based on. Available: rsa, ec, ed25519, ed448. Defaults to rsa.

keysize

For rsa, specifies the bitlength of the private key (2048, 3072, 4096). For ec, specifies the NIST curve to use (256, 384, 521). Irrelevant for Edwards-curve schemes (ed25519, ed448). Defaults to 2048 for RSA and 256 for EC.

passphrase

If this is specified, the private key will be encrypted using this passphrase. The encryption algorithm cannot be selected, it will be determined automatically as the best available one.

encoding

Specify the encoding of the resulting private key. It can be serialized as a pem text, binary der or pkcs12 file. Defaults to pem.

new

Always create a new key. Defaults to false. Combining new with prereq can allow key rotation whenever a new certificate is generated.

overwrite

Overwrite an existing private key if the provided passphrase cannot decrypt it. Defaults to false.

pkcs12_encryption_compat

Some operating systems are incompatible with the encryption defaults for PKCS12 used since OpenSSL v3. This switch triggers a fallback to PBESv1SHA1And3KeyTripleDESCBC. Please consider the notes on PKCS12 encryption.

Example:

The Jinja templating in this example ensures a new private key is generated if the file does not exist and whenever the associated certificate is to be renewed.

Manage www private key:
  x509.private_key_managed:
    - name: /etc/pki/www.key
    - keysize: 4096
    - new: true
{%- if salt["file.file_exists"]("/etc/pki/www.key") %}
    - prereq:
      - x509: /etc/pki/www.crt
{%- endif %}