Skip to content

Commit

Permalink
Merge pull request #56372 from jdsieci/master-x509_fixes
Browse files Browse the repository at this point in the history
Fix for #41858
  • Loading branch information
dwoz authored May 7, 2020
2 parents a6b63cb + 20c7d3a commit 42dccb8
Show file tree
Hide file tree
Showing 8 changed files with 296 additions and 12 deletions.
49 changes: 37 additions & 12 deletions salt/modules/x509.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,23 @@ def _make_regex(pem_type):
)


def _valid_pem(pem, pem_type=None):
pem_type = "[0-9A-Z ]+" if pem_type is None else pem_type
_dregex = _make_regex(pem_type)
for _match in _dregex.finditer(pem):
if _match:
return _match
return None


def _match_minions(test, minion):
if "@" in test:
match = __salt__["publish.publish"](tgt=minion, fun="match.compound", arg=test)
return match.get(minion, False)
else:
return __salt__["match.glob"](test, minion)


def get_pem_entry(text, pem_type=None):
"""
Returns a properly formatted PEM string from the input text fixing
Expand All @@ -465,8 +482,6 @@ def get_pem_entry(text, pem_type=None):
# Replace encoded newlines
text = text.replace("\\n", "\n")

_match = None

if (
len(text.splitlines()) == 1
and text.startswith("-----")
Expand All @@ -490,19 +505,16 @@ def get_pem_entry(text, pem_type=None):
pem_temp = pem_temp[pem_temp.index("-") :]
text = "\n".join(pem_fixed)

_dregex = _make_regex("[0-9A-Z ]+")
errmsg = "PEM text not valid:\n{0}".format(text)
if pem_type:
_dregex = _make_regex(pem_type)
errmsg = "PEM does not contain a single entry of type {0}:\n" "{1}".format(
pem_type, text
)

for _match in _dregex.finditer(text):
if _match:
break
_match = _valid_pem(text, pem_type)
if not _match:
raise salt.exceptions.SaltInvocationError(errmsg)

_match_dict = _match.groupdict()
pem_header = _match_dict["pem_header"]
proc_type = _match_dict["proc_type"]
Expand Down Expand Up @@ -785,8 +797,8 @@ def write_pem(text, path, overwrite=True, pem_type=None):
salt '*' x509.write_pem "-----BEGIN CERTIFICATE-----MIIGMzCCBBugA..." path=/etc/pki/mycert.crt
"""
text = get_pem_entry(text, pem_type=pem_type)
with salt.utils.files.set_umask(0o077):
text = get_pem_entry(text, pem_type=pem_type)
_dhparams = ""
_private_key = ""
if (
Expand Down Expand Up @@ -1091,10 +1103,7 @@ def sign_remote_certificate(argdic, **kwargs):
if "minions" in signing_policy:
if "__pub_id" not in kwargs:
return "minion sending this request could not be identified"
matcher = "match.glob"
if "@" in signing_policy["minions"]:
matcher = "match.compound"
if not __salt__[matcher](signing_policy["minions"], kwargs["__pub_id"]):
if not _match_minions(signing_policy["minions"], kwargs["__pub_id"]):
return "{0} not permitted to use signing policy {1}".format(
kwargs["__pub_id"], argdic["signing_policy"]
)
Expand Down Expand Up @@ -1356,6 +1365,19 @@ def create_certificate(path=None, text=False, overwrite=True, ca_server=None, **
``minions`` key is included in the signing policy, only minions
matching that pattern (see match.glob and match.compound) will be
permitted to remotely request certificates from that policy.
In order to ``match.compound`` to work salt master must peers permit
peers to call it.
Example:
/etc/salt/master.d/peer.conf
.. code-block:: yaml
peer:
.*:
- match.compound
Example:
Expand Down Expand Up @@ -1456,6 +1478,9 @@ def create_certificate(path=None, text=False, overwrite=True, ca_server=None, **
)

cert_txt = certs[ca_server]
if isinstance(cert_txt, str):
if not _valid_pem(cert_txt, "CERTIFICATE"):
raise salt.exceptions.SaltInvocationError(cert_txt)

if path:
return write_pem(
Expand Down
1 change: 1 addition & 0 deletions tests/integration/files/conf/master
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ tcp_master_workers: 64515
peer:
'.*':
- '(x509|test).*'
- 'match.*'

ext_pillar:
- ext_pillar_opts:
Expand Down
16 changes: 16 additions & 0 deletions tests/integration/files/file/base/issue-41858/check.sls
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
test_priv_key:
x509.private_key_managed:
- name: {{ pillar['keyfile'] }}
- bits: 4096

test_crt:
x509.certificate_managed:
- name: {{ pillar['crtfile'] }}
- public_key: {{ pillar['keyfile'] }}
- ca_server: minion
- signing_policy: {{ pillar['signing_policy'] }}
- CN: minion
- days_remaining: 30
- backup: True
- require:
- test_priv_key
61 changes: 61 additions & 0 deletions tests/integration/files/file/base/issue-41858/gen_cert.sls
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{% set tmp_dir = pillar['tmp_dir'] %}

{{ tmp_dir }}/pki:
file.directory

{{ tmp_dir }}/pki/issued_certs:
file.directory

{{ tmp_dir }}/pki/ca.key:
x509.private_key_managed:
- bits: 4096
- require:
- file: {{ tmp_dir }}/pki

{{ tmp_dir }}/pki/ca.crt:
x509.certificate_managed:
- signing_private_key: {{ tmp_dir }}/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,issuer:always
- days_valid: 3650
- days_remaining: 0
- backup: True
- managed_private_key:
name: {{ tmp_dir }}/pki/ca.key
bits: 4096
backup: True
- require:
- file: {{ tmp_dir }}/pki
- {{ tmp_dir }}/pki/ca.key

mine.send:
module.run:
- func: x509.get_pem_entries
- kwargs:
glob_path: {{ tmp_dir }}/pki/ca.crt
- onchanges:
- x509: {{ tmp_dir }}/pki/ca.crt

test_priv_key:
x509.private_key_managed:
- name: {{ pillar['keyfile'] }}
- bits: 4096

test_crt:
x509.certificate_managed:
- name: {{ pillar['crtfile'] }}
- public_key: {{ pillar['keyfile'] }}
- ca_server: minion
- signing_policy: ca_policy
- CN: minion
- days_remaining: 30
- backup: True
- require:
- {{ tmp_dir }}/pki/ca.crt
- test_priv_key
16 changes: 16 additions & 0 deletions tests/integration/files/file/base/x509_compound_match/check.sls
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
test_priv_key:
x509.private_key_managed:
- name: {{ pillar['keyfile'] }}
- bits: 4096

test_crt:
x509.certificate_managed:
- name: {{ pillar['crtfile'] }}
- public_key: {{ pillar['keyfile'] }}
- ca_server: minion
- signing_policy: {{ pillar['signing_policy'] }}
- CN: {{ grains.get('id') }}
- days_remaining: 30
- backup: True
- require:
- test_priv_key
43 changes: 43 additions & 0 deletions tests/integration/files/file/base/x509_compound_match/gen_ca.sls
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{% set tmp_dir = pillar['tmp_dir'] %}

{{ tmp_dir }}/pki:
file.directory

{{ tmp_dir }}/pki/issued_certs:
file.directory

{{ tmp_dir }}/pki/ca.key:
x509.private_key_managed:
- bits: 4096
- require:
- file: {{ tmp_dir }}/pki

{{ tmp_dir }}/pki/ca.crt:
x509.certificate_managed:
- signing_private_key: {{ tmp_dir }}/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,issuer:always
- days_valid: 3650
- days_remaining: 0
- backup: True
- managed_private_key:
name: {{ tmp_dir }}/pki/ca.key
bits: 4096
backup: True
- require:
- file: {{ tmp_dir }}/pki
- {{ tmp_dir }}/pki/ca.key

mine.send:
module.run:
- func: x509.get_pem_entries
- kwargs:
glob_path: {{ tmp_dir }}/pki/ca.crt
- onchanges:
- x509: {{ tmp_dir }}/pki/ca.crt
Loading

0 comments on commit 42dccb8

Please sign in to comment.