Public key filters

Public key filters #

Let’s say you have stored a private key in your Ansible vault. Do you have to store the public key next to it, or can you generate it from the private key? For crypto systems including SSH and Wireguard, you can generate the public key from the private key, which is especially useful when rotating keys or generating them programmatically.

Here are some filters that accomplish this:

TODO

test the ssh filter

#!/usr/bin/python3


import subprocess
import tempfile
import typing


def ensure_str(input: typing.Union[str, bytes]) -> str:
    """Whether the input is a string or bytes, return a string"""
    try:
        output: str = input.decode()
    except AttributeError:
        output: str = input
    return output


def wireguard_public_key(privkey: typing.Union[str, bytes]) -> str:
    """Given a wireguard private key, return the public key.

    Note that the 'wg' command must be installed.
    """
    privkey_str = ensure_str(privkey)
    wg = subprocess.Popen(
        ["wg", "pubkey"],
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True,
    )
    wgout, wgerr = wg.communicate(privkey_str)
    wg.wait()
    if wg.returncode != 0:
        raise subprocess.CalledProcessError(
            wg.returncode, wg.cmd, output=wgout, stderr=wgerr
        )
    return wgout.strip()


def ssh_public_key(privkey: typing.Union[str, bytes]) -> str:
    """Given an SSH private key, return the public key"""
    privkey_str = ensure_str(privkey)
    # SSH keygen must read the private key from the filesystem
    with tempfile.NamedTemporaryFile(mode="w", encoding="utf8") as privkey_handle:
        privkey_handle.write(privkey)
        sshout = subprocess.check_output(
            ["ssh-keygen", "-y", "-f", privkey_handle.name]
        )
    return sshout.strip()


class FilterModule(object):
    def filters(self):
        return {
            "wireguard_public_key": wireguard_public_key,
            "ssh_public_key": ssh_public_key,
        }

These simple, useful plugins show that a filter plugin is not limited to a colloqual understanding of filtering data. Any programmatic operation that transforms data can be written as a filter plugin.