cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
757
Views
0
Helpful
9
Replies
tcragg1
Cisco Employee

Encrypt strings in python MAAPI

I am working on a service template part of which will generate random strings and store them in an NSO container as tailf:aes-cfb-128-encrypted-string leafs. Is there a simple way inside of python MAAPI to generate the encrypted passwords? When I just pass string values to these leafs it fails with an "item has a bad/wrong type" error.

 

I know that to work with items that are already in ConfDB as tailf:aes-cfb-128-encrypted-string leafs I can use the _ncs.decrypt() function, but I couldn't see an equivalent _ncs.encrypt() function in the docs. Is there a way to encrypt a string directly within python MAAPI to pass to a tailf:aes-cfb-128-encrypted-string leaf, or do we have to use a separate python crypto module to encrypt the string and then send it to the tailf:aes-cfb-128-encrypted-string leaf?

1 ACCEPTED SOLUTION

Accepted Solutions

I realized that another workaround could be to use a small template just for setting the password. 

View solution in original post

9 REPLIES 9
vleijon
Cisco Employee

You should be allowed to just pass the string directly into maapi. If you want to be certain you can prepend $0$ to the string as you set it to indicate that what follows is an unencrypted string.

It appears to work if I run it through a maapi script, but not from directly inside the cb_create method of the python service. The following maapi script works:

 

import random
import string
import ncs
from ncs import _ncs

with ncs.maapi.Maapi() as m:
    with ncs.maapi.Session(m, 'admin', 'python'):
        with m.start_write_trans() as t:
            root = ncs.maagic.get_root(t)
            letters_and_digits = string.ascii_letters + string.digits
            aes_pass = ''.join((random.choice(letters_and_digits) for i in range(8)))
            root.wxc_vpn_snmp.wxc_vpn_customer.create('maapi')
            root.wxc_vpn_snmp.wxc_vpn_customer['maapi'].snmp_aes = aes_pass
            t.apply()

But the following code inside the cb_create method of the service gives me the bad type error:

if not root.wxc_vpn_snmp.wxc_vpn_customer[vrf_name].snmp_aes:
    letters_and_digits = string.ascii_letters + string.digits
    aes_pass = ''.join((random.choice(letters_and_digits) for i in range(8)))
    root.wxc_vpn_snmp.wxc_vpn_customer[vrf_name].snmp_aes = aes_pass

Any idea why this does not work?

Not sure, they ought to work exactly the same way.

It could be a python2 vs python3 difference if the external script is run with python2. Python3 has a tendency to create Iterator-objects instead of collapsing them immediately which can cause trouble. You can try using str() and/or list() to coerce things to the correct type.

I was running the maapi script through python3, and I am using python3 for NSO, so I don't think that can be the issue. I added some extra logging statements in the service and it definitely looks like the aes_pass var is being generated correctly as a string type. Below is the updated code:

if not root.wxc_vpn_snmp.wxc_vpn_customer[vrf_name].snmp_aes:
    letters_and_digits = string.ascii_letters + string.digits
    aes_pass = str(''.join((random.choice(letters_and_digits) for i in range(8))))
    self.log.info('AES pass ', aes_pass, ', type ', type(aes_pass))
    encoded_pass = '$0$' + aes_pass
    self.log.info('encoded pass ', encoded_pass, ', type ', type(encoded_pass))
    root.wxc_vpn_snmp.wxc_vpn_customer[vrf_name].snmp_aes = encoded_pass

 

This results in the following log messaging when attempting a commit dry-run:

 

 

<INFO> 31-Jul-2020::04:17:41.712 wxc-vpn-customer MainThread: - Python 3.6.6 (default, Jan 26 2019, 16:53:05) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]
<INFO> 31-Jul-2020::04:17:41.715 wxc-vpn-customer MainThread: - Starting...
<INFO> 31-Jul-2020::04:17:41.716 wxc-vpn-customer MainThread: - Started
<INFO> 31-Jul-2020::04:17:45.336 wxc-vpn-customer ComponentThread:main: - Main RUNNING
<INFO> 31-Jul-2020::04:17:59.960 wxc-vpn-customer ncs-dp-28246-wxc-vpn-customer:main-1-th-1192342: - Service create(service=/ncs:services/wxc-vpn-customer:wxc-vpn-customer{partner1 cust10})
<INFO> 31-Jul-2020::04:17:59.962 wxc-vpn-customer ncs-dp-28246-wxc-vpn-customer:main-1-th-1192342: - AES pass zS71qF3f, type <class 'str'>
<INFO> 31-Jul-2020::04:17:59.962 wxc-vpn-customer ncs-dp-28246-wxc-vpn-customer:main-1-th-1192342: - encoded pass $0$zS71qF3f, type <class 'str'>
<ERROR> 31-Jul-2020::04:17:59.963 wxc-vpn-customer ncs-dp-28246-wxc-vpn-customer:main-1-th-1192342: - item has a bad/wrong type (5): <<"$0$zS71qF3f">> is not a valid value.
<ERROR> 31-Jul-2020::04:17:59.964 wxc-vpn-customer ncs-dp-28246-wxc-vpn-customer:main-1-th-1192342: - Traceback (most recent call last):
File "/home/tcragg/nso-5.2.3.3/src/ncs/pyapi/ncs/application.py", line 399, in wrapper
pl = fn(self, tctx, root, service, proplist)
File "/home/tcragg/ncs52-run/state/packages-in-use/1/wxc-vpn-customer/python/wxc_vpn_customer/main.py", line 36, in cb_create
root.wxc_vpn_snmp.wxc_vpn_customer[vrf_name].snmp_aes = encoded_pass
File "/home/tcragg/nso-5.2.3.3/src/ncs/pyapi/ncs/maagic.py", line 483, in __setattr__
child.set_value(value)
File "/home/tcragg/nso-5.2.3.3/src/ncs/pyapi/ncs/maagic.py", line 956, in set_value
self._backend._set_elem(value, self._path)
File "/home/tcragg/nso-5.2.3.3/src/ncs/pyapi/ncs/maagic.py", line 124, in _set_elem
self.set_elem(value, path)
File "/home/tcragg/nso-5.2.3.3/src/ncs/pyapi/ncs/maapi.py", line 1202, in proxy
return real(self2.maapi, self2.th, *args, **kwargs)
File "/home/tcragg/nso-5.2.3.3/src/ncs/pyapi/ncs/tm.py", line 12, in wrapper
return fn(*args, **kwargs)
File "/home/tcragg/nso-5.2.3.3/src/ncs/pyapi/ncs/maapi.py", line 667, in shared_set_elem
_tm.maapi.shared_set_elem(self.msock, th, value, flags, path)
_ncs.error.Error: item has a bad/wrong type (5): <<"$0$zS71qF3f">> is not a valid value.

From the log messages, it looks like it is just refusing to accept a string value for this leaf.

 

I am running NSO 5.2.3.3 if that makes a difference.

 

Hello,

This seems to be a limitation in maagic, currently.

It seems if you want to use maagic to set the value of an encrypted leaf (in a service callback), you will have to provide the 'already encrypted value' (ie., something that starts with $8$, in this case).

It works outside a service. You can also use plain maapi, and do maapi.shared_set_elem() inside the service callback. You can do something like

        m = maapi.Maapi()
        th = m.attach(tctx)
        th.shared_set_elem('dummypass', '<path_to_encrypted_leaf>')

where 'tctx' is the transaction context you receive as a parameter to your service callback.

It just doesn't work in maagic, as of now.

Please create a support request, so that this can be fixed.

Thanks,

Ram

I realized that another workaround could be to use a small template just for setting the password. 

View solution in original post

Separating the credentials into an XML template appears to allow me to pass the unencrypted credentials correctly, and is also a simpler approach than messing around with directly accessing MAAPI from inside the cb_create() method, so I will use this approach if I need to pass plain text to an encrypted leaf going forward.

Thanks Ram.

 

I am not very familiar with the shared_set_elem command. What format does it expect the path to the element to be in? I assumed it would just be XPATH, but when I try "th.shared_set_elem(aes_pass, "/wxc-vpn-snmp/wxc-vpn-customer[vrf_name='maapi']/snmp-aes")", it gives me a bad path error. This should be a valid XPATH as it is pointing to an existing list entry:

admin_tcragg@ncs# show running-config wxc-vpn-snmp | display xpath
/wxc-vpn-snmp/wxc-vpn-customer[vrf_name='maapi']/snmp-aes $8$DMo1By0HjgSiPRbz3FbBiuLJNe3aN2r5HjKNSutsk+o=

It takes a keypath, that is something like /wxc-vpn-snmp/wxc-vpn-customer{maapi} /snmp-aes