Closed johnnybubonic closed 1 year ago
So it's not actually broken right now, it could just be better?
No, it's absolutely broken in cross-platform environments.
Though your method makes sense, we can't change the way we're creating the fingerprint as it would break existing installations.
Shoot, that's gonna bug me; Salt is the only software I know of that fingerprints against PEM instead of DER/BER. But fair enough on the breakage (though it should be noted that by fixing the fingerprint calculation for Windows, those minions will break with the linked PR if they were using master_finger regardless).
Maybe earmark that method to implement if Salt public keygen is overhauled/broken/vuln in the future and installations would require rekeying anyways? That would let external tools properly generate/parse Salt keypairs/fingerprints as well.
(Sorry, same guy as OP to clarify, this is my work GH)
Description This is essentially a re-open of https://github.com/saltstack/salt/issues/14593 but with a proposed cross-platform solution (that is, it should be noted, a more "proper" way of fingerprinting a key).
Setup 1.) Set
hash_type
tosha512
on both a Linux master and Windows minion (this is probably unnecessary, as the same code should be used on both.) 2.) Setmaster_finger
in the Windows minion's config file to the output ofsalt-key -f master.pub
on the Linux master. 3.) Get the following (critical) error:Steps to Reproduce the behavior See above,
Expected behavior The Windows minion should properly fingerprint the Master's key.
Versions Report
salt --versions-report
(Provided by running salt --versions-report. Please also mention any differences in master/minion versions.) Master: ```yaml Salt Version: Salt: 3005.1 Dependency Versions: cffi: 1.14.6 cherrypy: unknown dateutil: 2.8.1 docker-py: Not Installed gitdb: Not Installed gitpython: Not Installed Jinja2: 3.1.0 libgit2: 1.5.0 M2Crypto: Not Installed Mako: Not Installed msgpack: 1.0.2 msgpack-pure: Not Installed mysql-python: Not Installed pycparser: 2.21 pycrypto: Not Installed pycryptodome: 3.9.8 pygit2: 1.11.1 Python: 3.9.16 (main, Jan 6 2023, 22:52:19) python-gnupg: 0.4.8 PyYAML: 5.4.1 PyZMQ: 23.2.0 smmap: Not Installed timelib: 0.2.4 Tornado: 4.5.3 ZMQ: 4.3.4 System Versions: dist: almalinux 8.7 Stone Smilodon locale: utf-8 machine: x86_64 release: 4.18.0-425.10.1.el8_7.x86_64 system: Linux version: AlmaLinux 8.7 Stone Smilodon ``` Minion: ```yaml Salt Version: Salt: 3005.1 Dependency Versions: cffi: 1.14.6 cherrypy: unknown dateutil: 2.8.1 docker-py: Not Installed gitdb: 4.0.7 gitpython: Not Installed Jinja2: 3.1.0 libgit2: Not Installed M2Crypto: Not Installed Mako: 1.1.4 msgpack: 1.0.2 msgpack-pure: Not Installed mysql-python: Not Installed pycparser: 2.21 pycrypto: Not Installed pycryptodome: 3.10.1 pygit2: Not Installed Python: 3.8.16 (tags/v3.8.16:1e3d2d5, Dec 9 2022, 17:48:54) [MSC v.1916 64 bit (AMD64)] python-gnupg: 0.4.8 PyYAML: 5.4.1 PyZMQ: 22.0.3 smmap: 4.0.0 timelib: 0.2.4 Tornado: 4.5.3 ZMQ: 4.3.4 System Versions: dist: locale: cp1252 machine: AMD64 release: 2022Server system: Windows version: 2022Server 10.0.20348 SP0 Multiprocessor Free ```Additional context ROOT CAUSE: This is due to twofold problems:
1.) Window performing the hashing in
pem_finger
(salt/utils/crypt.py
) against a CRLF-line-terminated (\r\n
) file (master_minion.pem
), whereas Linux master (and Linux minions) performing hashing against the (much more sane, of course) LF-terminated (\n
) file (eithermaster.pub
orminion_master.pub
depending on context).2.) A very silly way of calculating a key's fingerprint.
1 is inexcusable. There is no reason a minion's platform should need a different checksum for its master's finger. This is bad design.
THE PROPER SOLUTION:
But thankfully, a more sane approach to 2 also simultaneously completely fixes 1, and with no code porting across platforms or checks thereof - it's completely cross-platform.
So, let's take an example Master pubkey. (This is generated explicitly for the purpose of demonstration.)
(The key was generated with
hash_type: sha512
andkey_size: 4096
on the master, configured before first-run. Now would be a good time to mention that specifying a 4096-bit key in the config does not properly generate a 4096-bit master key and instead only generates a 2048-bit key... but that's a bug for another day.)This is a PEM-encoded 2048-bit RSA public key, using PKIX format.
And, as per PEM encoding specifications, the block contained between the start label (and headers, not present) and end label is Base64-Encoded ASN.1.
Which means that a more proper fingerprinting (aside from encoding as an actual ASN.1 field itself, which is a bit of a hassle) would be to base64-DECODE the PEM block, and hash that.
A nice feature of Python's stdlib base64 library is that it is newline-agnostic. It doesn't care if there are newlines in base64 or not. It doesn't care if they're line-terminated with LF or CRLF.