wvandeun / nornir_netbox

NetBox plugin for Nornir
Apache License 2.0
69 stars 17 forks source link

secrets extension for netbox plugin #24

Closed sjtarik closed 2 years ago

sjtarik commented 3 years ago

any plan adding secrets support embedded in inventory itself? I guess currently this is done with transfer function but then this requires a separate call to netbox with a different library just to pull secrets. I wonder if we can add the part retrieving the secrets and in load function of the plugin we let user handle the matching passwords with devices in the transfer function passed by user. so we saved the user from reimplementing all that gathering secret part.

currently I am doing a hacky way of implementing that with a child class derived from NetBoxInventory2. and in my transfer function I have the matching logic to tie specific passwords to particular devices.

class NetBoxInventoryWSecrets(NetBoxInventory2):
    """
    nr = InitNornir(
        inventory={
            "plugin": "NetBoxInventoryWSecrets",
            #"transform_function" : "my_transfer_function",
            "options": {
                "nb_url": "<NB_URL>>",
                "nb_token": "<NB_TOKEN>",
                "nb_private_key": "<NB_PRIVATE_KEY_FILE>",
            }
        }
    )
    """
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.NETBOX_PRIVATE_KEY_FILE = kwargs.get("nb_private_key", None) or os.environ.get("NB_PRIVATE_KEY")

    def _get_session_key(self):
        self.session.headers.update({'Content-Type': 'application/x-www-form-urlencoded'})
        try:
            with open(self.NETBOX_PRIVATE_KEY_FILE, 'r') as private_key_file:
                private_key = private_key_file.read().strip('\n')
                data = { 'private_key': private_key }
                resp = self.session.post(self.nb_url + '/api/secrets/get-session-key/',
                                         data=data, verify=False)
                logging.info(resp.text)
                if resp.ok:
                    return resp.json()['session_key']
                else:
                    logging.error(resp.text)
        except Exception as e:
            logging.error(e)
        return None

    def _get_secrets(self):
        session_key = self._get_session_key()
        if session_key is None:
            return None

        results = None
        try:
            self.session.headers.update({'Content-Type': 'application/json',
                                         'X-Session-Key': session_key})
            resp = self.session.get(self.nb_url + '/api/secrets/secrets/',
                                    verify=False)
            if resp.ok:
                results = resp.json()['results']
        except Exception as e:
            logging.error(e)
        return results

    def get_secrets(self):
        secret_results = self._get_secrets()
        logging.info(secret_results)
        massaged_results = {}
        for secret_item in secret_results:
            massaged_results[secret_item['name']] = secret_item['plaintext']
        return massaged_results

    def load(self) -> Inventory:
        inv = super().load()
        keys = self.get_secrets()

        #call the transfer function!!!
        return inv

InventoryPluginRegister.register("NetBoxInventoryWSecrets", NetBoxInventoryWSecrets)
sjtarik commented 3 years ago

I think there are a few Ansible netbox plugins handling secret management too.

https://netbox.readthedocs.io/en/stable/core-functionality/secrets/ https://josh-v.com/netbox_ansible_collection/netbox-ansible-lookup-plugin/

wvandeun commented 2 years ago

https://github.com/netbox-community/netbox/releases/tag/v3.0.0 seems to drop support for secrets. Functionality is going to be moved to a plugin, which AFAIK is not yet finished. This mean we cannot offer this feature for all releases of NetBox, hence closing this issue for now. We might revisit this when the plugin is available.