All Apps and Add-ons
Highlighted

Get all imported_roles for a role

New Member

Hello,

I am trying to discover all the roles a specified role is build on. For example, say I have a role heirarchy that looks like:

user -> power -> power-a -> power-b

In my scenario, when I do | rest /services/authentication/current-context it returns power-b. I want to know all the other roles power-b inherits.

It seems that | rest /services/authorization/roles/power-b would get me what I what via the "imported_roles" column, but it only goes up the inheritance 1 level at a time, giving me power-a.

What do I need to do to get everything: user, power, and power-a?

0 Karma
Highlighted

Re: Get all imported_roles for a role

Esteemed Legend

You cannot; you have to walk each level. But given that any admin at any time can change the composition of any inherited role, why do you care to map them? Why isn't the list of capabilities enough?

0 Karma
Highlighted

Re: Get all imported_roles for a role

New Member

The real reason is because I want to join the list of roles returned from | rest /services/authentication/current-context with the list of roles supplied in the "eai:acl.perms.write" column of | rest /services/apps/local but in the "eai:acl.perms.write" I see "power" instead of "power-b". Since power-b has all the permissions of power, I want that join to be successful, but I only know that power-b has all of power because I went and looked it up. I'm hoping to find a way to automatically gather all the inheritances so I don't have make any assumptions.

0 Karma
Highlighted

Re: Get all imported_roles for a role

Esteemed Legend

Why? Who cares about inheritances unless you are planning to modify them? What is important are capabilities, right?

0 Karma
Highlighted

Re: Get all imported_roles for a role

Builder

In a corporate environment, documentation can be and should be required for who is capable of what (and updated on a regular automated basis). Further, that documentation may be needed to play into your point, and demonstrate the need for modifications from time to time. I don't know the OP's needs, but there are reasons to care.

###

If this reply helps you, an upvote would be appreciated.
Highlighted

Re: Get all imported_roles for a role

Influencer

I was running into this same problem recently... and while I feel like this should be easier, it got the job done for me, to get all imports of all roles. I'll walk you through the development (I'm on 7.2.9.1), and then give one that you should be able to just drop in and use yourself...

Let's call our current search string S

Initially set S to the following:

| rest /services/authorization/roles splunk_server=local f=imported_roles f=title 
| fields title imported_roles | rename imported_roles -> imported
| eval delta=coalesce(mvcount(imported),0)
| fillnull value=NIL imported

This sets up our base state, where title is the name of each role, imported is the set of roles that we currently know each role imports, NIL if a role imports no roles (this is important so we keep these roles as we iterate...), and delta is the number of imported roles that we previously didn't know about.

Now we iterate:
First we check our ending condition:

S | stats sum(delta)

If the number returned here is 0, then we are finished and the current state of S will give us all roles with all imports for our current installation (see below). If this sum is >0 we iterate and update the value of S as follows:

S | fields - delta 
| mvexpand imported 
| appendpipe [ where imported!="NIL" | eval imported1=imported,imported=title,title=null()]
| eventstats values(imported1) as imported1 by imported 
| stats values(imported*) as imported* by title 
| eval imported1=mvdedup(mvappend(imported,imported1)),delta=mvcount(imported1)-mvcount(imported),imported=imported1 
| fields - imported1

What we do here is we get rid of the delta from the previous iteration, we expand our list to be one pair of role -> imported role each, we duplicate our results to also have the full set of imported role -> next imported role (for those that have an imported role), we use eventstats to gather up the next imported roles for each imported role, and we use stats to gather up for each role, all the known imported roles, and the next imported roles. Now that we're back to one result, we merge our found next imports into our known imports, and calculate the number that we didd not know about previously.

Repeat the loop!

At the end, you could clean up the now all 0s delta field by updating S to be:

S | fields - delta

but otherwise you now have a lookup of role -> all other roles, and can use standard search / where terms on it...


So a fun aspect about this, each iteration is idempotent as soon as we know all imported roles for each role, and each loop we gather information about double the number of layers of imports deep... (assuming I'm correctly remembering some of my algorithmic principles...)

So, getting rid of the delta tracking, and running this together... this search should find the full import stack for all roles in your environment, provided that no role has more than 256 layers of imported roles deep... (e.g. a imports b which imports c and so on for more than 256 times...) this search will get you the full mapping of role -> all imported roles)... and if you need up to 512, copy and tack on to the end another | mvexpand ... fields line:

| rest /services/authorization/roles splunk_server=local f=imported_roles f=title | fields title imported_roles | rename imported_roles -> imported | fillnull value=NIL imported
| mvexpand imported | appendpipe [where imported!="NIL" | eval imported1=imported,imported=title,title=null()] | eventstats values(imported1) as imported1 by imported | stats values(imported*) as imported* by title | eval imported=mvdedup(mvappend(imported,imported1)) | fields - imported1
| mvexpand imported | appendpipe [where imported!="NIL" | eval imported1=imported,imported=title,title=null()] | eventstats values(imported1) as imported1 by imported | stats values(imported*) as imported* by title | eval imported=mvdedup(mvappend(imported,imported1)) | fields - imported1
| mvexpand imported | appendpipe [where imported!="NIL" | eval imported1=imported,imported=title,title=null()] | eventstats values(imported1) as imported1 by imported | stats values(imported*) as imported* by title | eval imported=mvdedup(mvappend(imported,imported1)) | fields - imported1
| mvexpand imported | appendpipe [where imported!="NIL" | eval imported1=imported,imported=title,title=null()] | eventstats values(imported1) as imported1 by imported | stats values(imported*) as imported* by title | eval imported=mvdedup(mvappend(imported,imported1)) | fields - imported1
| mvexpand imported | appendpipe [where imported!="NIL" | eval imported1=imported,imported=title,title=null()] | eventstats values(imported1) as imported1 by imported | stats values(imported*) as imported* by title | eval imported=mvdedup(mvappend(imported,imported1)) | fields - imported1
| mvexpand imported | appendpipe [where imported!="NIL" | eval imported1=imported,imported=title,title=null()] | eventstats values(imported1) as imported1 by imported | stats values(imported*) as imported* by title | eval imported=mvdedup(mvappend(imported,imported1)) | fields - imported1
| mvexpand imported | appendpipe [where imported!="NIL" | eval imported1=imported,imported=title,title=null()] | eventstats values(imported1) as imported1 by imported | stats values(imported*) as imported* by title | eval imported=mvdedup(mvappend(imported,imported1)) | fields - imported1
| mvexpand imported | appendpipe [where imported!="NIL" | eval imported1=imported,imported=title,title=null()] | eventstats values(imported1) as imported1 by imported | stats values(imported*) as imported* by title | eval imported=mvdedup(mvappend(imported,imported1)) | fields - imported1

Hopefully this helps you too?

0 Karma