Device to Realm mappings?

45 views
Skip to first unread message

greg cox

unread,
Jan 27, 2014, 1:01:50 AM1/27/14
to trigge...@googlegroups.com
From reading about realms, it seems as though it's possible to map a device to a Realm, but I can't seem to find any way to do it.  I've seen references to get_device_password, and update_credentials that references a "device or realm" portion, but that seems to be per device or to define a realm, not a way to do a many to one mapping of devices to realm.

My issues is I have 3 groups of devices that each use different authentication systems.

Like Realm's, Corp/Backbone/Edge, it would seem like I would be able to map devices to realms to allow me to update the realm(user/password), and then be able to gong to any device mapped to that realm.

I would greatly appreciate any help, or pointing me in the direction.

Thanks

Greg Cox


Jathan McCollum

unread,
Feb 13, 2014, 12:49:15 PM2/13/14
to trigge...@googlegroups.com
Hi Greg-

My apologies on the delayed response. 

You are correct that it is possible to map to a realm but there is currently not any built-in support for storing and retrieving custom per-device realm mappings, with one exception:

Inside of the under-pinnings for connecting to NetScreen firewall devices (See: trigger.twister.pty_connect() or trigger.twister.execute_netscreen()), that's where the call to tacacsrc.get_device_password() is being used to store/retrieve creds for a "realm" based on the device's hostname.

This is because of a legacy requirement from when Trigger was originally developed at AOL.

Until we add support into the Trigger core to be able to more easily specify which credentials to use, this is not possible using "gong", since it uses the defaults. 

For methods that allow you to execute commands, you may pass explicit credentials, but the connect method currently does not. This is an oversight. I've submitted a feature request on your behalf!

Track it here:

Now, if you can't wait you COULD cobble together a solution by duplicating trigger.twister.connect and modifying it to support the creds= argument in the near term.

def myconnect(
def myconnect(device, init_commands=None, output_logger=None, login_errback=None,
            reconnect_handler=None, creds=None):

Then change this line:


Then specifying which credentials to use, IS possible to explicitly specify the credentials that you would like to use when connecting to devices.

First, it would require you to manually instantiate trigger.tacacsrc.Tacacsrc yourself and retrieve the credentials for the desired realm, e.g. "edge":

from trigger import tacacsrc

# Fetch the creds or populate them if they don't exist
edge_creds = tacacsrc.get_device_password('edge')

# Or just explicitly fetch them without trying to populate them:
# tcrc = tacacsrc.Tacacsrc()
# edge_creds = tcrc.creds['edge']

You could then lookup a device object explicitly, call the .connect() method, and pass the credentials using the creds argument:

from trigger.netdevices import NetDevices

nd = NetDevices()
device = nd['edge1.device']

# Pass the explicit credentials to .connect()
edge_creds = tacacsrc.get_device_password('edge')



--
You received this message because you are subscribed to the Google Groups "Trigger" group.
To unsubscribe from this group and stop receiving emails from it, send an email to trigger-user...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Jathan.
--

Jathan McCollum

unread,
Feb 13, 2014, 12:50:07 PM2/13/14
to trigge...@googlegroups.com
I didn't mean to send that. It's probably just confusing. Let me know if you want to risk defining you're own connect and I'll help you out!

I'm planning to add support for this in the next Trigger release.
--
Jathan.
--

greg cox

unread,
May 25, 2014, 11:34:52 PM5/25/14
to trigge...@googlegroups.com
No I totally understand about taking a long time, I was just able to get back to this myself today.

I think I get it, but let me know if I'm off base.

Assuming I have 3 different realms defined in my .tacacsrc(backbone/distro/edge).  I like the idea of adding a key/value, realm='edge', for each device in netdevices.  Then just update everyplace that calls "tacacsrc.py" and tacacsrc.py itself, to use that realm instead of "settings.DEFAULT_REALM" below.  Wouldn't that be pretty universal and allow all the methods to have the multi realm functionality, it can still "DEFAULT" to the DEFAULT_REALM, but if specific is defined it would work :-)  ?   Obviously still using your old method, not GPG.

tacacsrc.py ~line=284-286(below).

             "else:
                self.creds[settings.DEFAULT_REALM] = prompt_credentials(device='tacacsrc')
                self.write()
             "

greg cox

unread,
Jun 2, 2014, 9:19:11 PM6/2/14
to trigge...@googlegroups.com, jat...@gmail.com
it looks as though I only have to update tacacsrc.py, and maybe twister.py to pass the "device".  So this might be much easier then expected, but I think I'm missing something.  Then call netdevices inside of tacacsrc to return the "realm".

I already have the 3 different realms in my .tacacsrc, and the realms defined in my netdevices.json, and can pull out the realm per device, but any help you can offer in which functions need the update would be great?  I'm thinking it's either wherever the "default realm" is referenced, or anywhere creds is originated.

If I figure it out, I will send a patch if you are open to including it.

Trying either way.

Thanks,

Greg

greg cox

unread,
Jun 3, 2014, 2:40:53 AM6/3/14
to trigge...@googlegroups.com, jat...@gmail.com
isn't tacacsrc.py _parse_old the only place that actually decodes the .tacacsrc and if it was passed the "realm" when called, it would only "decode" and return that "realm" ?

greg cox

unread,
Jun 4, 2014, 6:45:09 PM6/4/14
to trigge...@googlegroups.com, Jathan McCollum
Maybe not the prettiest, but seems to be working :-)

tacacsrc.py patch >

+from trigger.netdevices import NetDevices
+
+def get_realm(device):
+    nd = NetDevices()
+    dev = nd[device]
+    return dev.realm
+
@@ -122,7 +135,7 @@
     if tcrc.creds_updated:
         return None

-    mycreds = tcrc.creds.get(device, tcrc.creds[settings.DEFAULT_REALM])
+    mycreds = tcrc.creds.get(device, tcrc.creds[get_realm(device)])
     if username is None:
         username = mycreds.username

@@ -131,7 +144,7 @@

     return True

-def validate_credentials(creds=None):
+def validate_credentials(creds=None, device=None):
     """
     Given a set of credentials, try to return a `~trigger.tacacsrc.Credentials`
     object.
@@ -146,7 +159,11 @@
         A tuple of credentials.

     """
-    realm = settings.DEFAULT_REALM
+    device = device.nodeName
+    if device:
+        realm = get_realm(device)
+    else:
+        realm = settings.DEFAULT_REALM


twister.py patch >
@@ -629,9 +629,9 @@
     """
     Factory for all clients. Subclass me.
     """
-    def __init__(self, deferred, creds=None, init_commands=None):
+    def __init__(self, deferred, creds=None, device=None, init_commands=None):
         self.d = deferred
-        self.creds = tacacsrc.validate_credentials(creds)
+        self.creds = tacacsrc.validate_credentials(creds, device)
         self.results = []
         self.err = None

@@ -714,7 +714,7 @@
         self.prompt = re.compile(prompt_pattern)
         self.device = device
         self.connection_class = connection_class
-        TriggerClientFactory.__init__(self, deferred, creds)
+        TriggerClientFactory.__init__(self, deferred, creds, device)

     def buildProtocol(self, addr):
         self.protocol = self.protocol()
@@ -739,7 +739,7 @@
         self.connection_class = TriggerSSHConnection
         self.commands = []
         self.command_interval = 0
-        TriggerClientFactory.__init__(self, deferred, creds, init_commands)
+        TriggerClientFactory.__init__(self, deferred, creds, device, init_commands)

 #==================
 # SSH Basics
@@ -1492,7 +1492,7 @@
         self.enablepw = os.getenv('TRIGGER_ENABLEPW', enablepw)
         self.device = device
         self.action.factory = self
-        TriggerClientFactory.__init__(self, deferred, creds, init_commands)
+        TriggerClientFactory.__init__(self, deferred, creds, device, init_commands)




Jathan McCollum

unread,
Jul 1, 2014, 7:13:51 PM7/1/14
to greg cox, trigge...@googlegroups.com
Hey Greg-

I'm really sorry it's taken me this long to get back to you. I'm obviously no good with email. I'm happy to see it looks like in my silence you were able to figure it out on your own! :)

If I'm understanding the intent here, it looks like what you've done is added a custom "realm" attribute that you're defining on NetDevice objects. I actually quite like this, as it's pretty clever, and if .realm can't be found, it would just fallback to the default realm.

There's also a request in the backlog in to allow for explicit per-device credentials as well, so this would in fact greatly improve the logical way that credentials are managed and stored using Trigger!

I went ahead and created a ticket on the Trigger backlog with your idea, and I hope to work on it very soon! Here is the ticket:



--
Jathan.
--

greg cox

unread,
Jul 3, 2014, 1:59:46 AM7/3/14
to Jathan McCollum, trigge...@googlegroups.com
Not a problem, I understand.  I believe the previous request was mine also, but this allows exactly that functionality, so it allows for device specific mapping to "realms" ultimately allowing for 1 to 1, if that many realms exist, and your right defaults back to a default realm :-)


Reply all
Reply to author
Forward
0 new messages