233 lines
7.2 KiB
Org Mode
233 lines
7.2 KiB
Org Mode
:PROPERTIES:
|
|
:ID: 13070c29-3c00-43f2-a73d-dedc056fb503
|
|
:END:
|
|
#+title: Custom Roles
|
|
#+subtitle: XDR IROH
|
|
#+Author: Yann Esposito
|
|
#+Date: [2023-10-03 Tue 15:30]
|
|
#+Options: toc:nil tags:t
|
|
#+tags: :cisco:xdr:
|
|
#+HTML_HEAD: <style>code {opacity:80%; font-size: 75%; background-color: rgba(127,127,127,0.3);body{font-family:"CMU Typewriter"} :root {--r-heading-font: Futura,sans-serif; --r-main-font-size: 36px; --r-main-font: Futura,sans-serif;}</style>
|
|
|
|
* Current state
|
|
** Listing Roles (already by org)
|
|
|
|
=GET /iroh/profile/roles=
|
|
|
|
Provide a data structure with describing all roles for an Org:
|
|
|
|
- 3 roles for XDR (admin, user, sat)
|
|
- 2 roles for SX (admin, user)
|
|
|
|
** ⚠ Role ≠ Permissions
|
|
|
|
The role associated to a user do not necessarily matches the user permission.
|
|
|
|
The role is only one of the component to use to determine a token or even a user permissions.
|
|
The permissions are represented by /scopes/ which are computed using:
|
|
|
|
- the user role
|
|
- the org properties (activated or not, XDR or not etc…)
|
|
- entitlements (not in use but will probably be the case in the future)
|
|
|
|
** ⚠ Role ≠ Permissions (Tokens)
|
|
|
|
- the user scopes
|
|
- as well as the client scopes
|
|
- as well as the scopes requested during the OAuth2 authorization flow
|
|
|
|
** Current response for an XDR-enabled org
|
|
|
|
#+REVEAL_HTML: <div style="font-size: 60%;">
|
|
#+BEGIN_SRC clojure
|
|
GET /iroh/profile/roles
|
|
{:admin {:english {:only-role-name "administrator",
|
|
:adjective "an",
|
|
:only-role-name-capitalized "Administrator",
|
|
:english-role-name "an administrator"},
|
|
:role-name "Administrator",
|
|
:role-id "admin",
|
|
:role-description "An admin of users.",
|
|
:visibility "public"},
|
|
:sat {:english {:only-role-name "security analyst",
|
|
:adjective "a",
|
|
:only-role-name-capitalized "Security Analyst",
|
|
:english-role-name "a security analyst"},
|
|
:role-name "Security Analyst",
|
|
:role-id "sat",
|
|
:role-description
|
|
"No account admin. SXO read only + run existing workflows.",
|
|
:visibility "public"},
|
|
:user {:english {:only-role-name "incident responder",
|
|
:adjective "an",
|
|
:only-role-name-capitalized "Incident Responder",
|
|
:english-role-name "an incident responder"},
|
|
:role-name "Incident Responder",
|
|
:role-id "user",
|
|
:role-description
|
|
"This is the closest to current user role:- no account administration- cannot create/change modules- SXO read only, but can run and edit workflows",
|
|
:visibility "public"}}
|
|
#+END_SRC
|
|
#+REVEAL_HTML: </div>
|
|
|
|
** Current response for an SX-only org
|
|
|
|
#+REVEAL_HTML: <div style="font-size: 60%;">
|
|
#+begin_src clojure
|
|
GET /iroh/profile/roles
|
|
{:admin {:english {:only-role-name "admin",
|
|
:adjective "an",
|
|
:only-role-name-capitalized "Admin",
|
|
:english-role-name "an admin"},
|
|
:role-name "Admin",
|
|
:role-id "admin",
|
|
:role-description "An admin of users.",
|
|
:visibility "public"},
|
|
:user {:english {:only-role-name "user",
|
|
:adjective "a",
|
|
:only-role-name-capitalized "User",
|
|
:english-role-name "a user"},
|
|
:role-name "User",
|
|
:role-id "user",
|
|
:role-description "A standard user.",
|
|
:visibility "public"}}
|
|
#+end_src
|
|
#+REVEAL_HTML: </div>
|
|
** What the API already support
|
|
|
|
|
|
- list all roles for every Org
|
|
- change the role of a user
|
|
- support roles during invitation and Org access request
|
|
- expose a permissions endpoint to check permission access independently of the role
|
|
- read/write access restriction
|
|
- fine grained /resource/ target in the scopes ~enrich~ → ~enrich/observables/observe:write~
|
|
|
|
** What the API does not support
|
|
|
|
- No support for create+update but not delete.
|
|
- No support for multiple roles
|
|
- No support for custom role creation (obviously)
|
|
- No scopes API for roles
|
|
|
|
* Expected Changes
|
|
** New API: (exhaustive scopes list)
|
|
|
|
Exhaustive list of scopes as a forest structure
|
|
|
|
#+begin_src clojure
|
|
[{:scope "global-intel"
|
|
(optional :description) ,,,
|
|
:accessors ["read"]
|
|
:sub-scopes [{:scope "global-intel/incident"
|
|
:accessors ["read"]}
|
|
{:scope "global-intel/sighting"
|
|
:accessors ["read"]}
|
|
,,,]}
|
|
{:scope "private-intel"
|
|
(optional :description) ,,,
|
|
:accessors ["rw","read","write"]
|
|
:sub-scopes [{,,,}]}]
|
|
#+end_src
|
|
|
|
** New API (maybe?)
|
|
|
|
Expose only a subset of scopes aliases pre-negociated with UX/UI/Doc team:
|
|
|
|
#+begin_src clojure
|
|
[{:scope-alias "threat-hunt"
|
|
:scopes ["enrich/observables/observe:read","inspect","investigation"]
|
|
:description ,,,,}
|
|
{:scope-alias "incidents"
|
|
:scopes ["private-intel","global-intel:read"]
|
|
:description ,,,}
|
|
,,, ]
|
|
#+end_src
|
|
|
|
** New API: CRUD+Search
|
|
|
|
API to manage new custom roles
|
|
|
|
#+begin_src clojure
|
|
(s/defschema NewRole
|
|
{:role-name s/Str
|
|
:role-description s/Str
|
|
:provided-scopes Scopes})
|
|
|
|
(s/defschema Role
|
|
(st/merge NewRole
|
|
{:id s/Str
|
|
:created-at Date
|
|
:updated-at Date}))
|
|
#+end_src
|
|
|
|
** Existing APIs
|
|
|
|
The =GET /iroh/profile/roles= will look like today + added the new custom roles
|
|
that will look like:
|
|
|
|
#+REVEAL_HTML: <div style="font-size: 60%;">
|
|
#+BEGIN_SRC clojure
|
|
{:admin ...
|
|
:sat ...
|
|
:user ...
|
|
:role-d394db9e-613f-11ee-aff9-325096b39f47
|
|
{:role-name "My Company Custom Role"
|
|
:role-description "This is a role that is read only except for workflows"
|
|
:role-id :role-d394db9e-613f-11ee-aff9-325096b39f47
|
|
:visibility "org"
|
|
:associated-scopes #{"inspect:read" "ao" "insights:read" "profile:read"}}
|
|
|
|
:role-8891b9f4-6140-11ee-8e1a-325096b39f47
|
|
{:role-name "Manager"
|
|
:role-description "Only for Sam who manage this team but should not directly act"
|
|
:role-id :role-8891b9f4-6140-11ee-8e1a-325096b39f47
|
|
:visibility "org"
|
|
:associated-scopes #{"inspect:read" "ao:read" "insights:read" "profile:read" "users" "profile"}}}
|
|
#+END_SRC
|
|
#+REVEAL_HTML: </div>
|
|
|
|
- ~visibility~; ~org~ for custom, ~public~ for global.
|
|
- ~associated-scopes~; only for role management UI
|
|
|
|
** Introduce sub-accessors (maybe?)
|
|
|
|
Today: ~read~, ~write~
|
|
|
|
#+begin_src
|
|
inspect = inspect:rw
|
|
= inspect:read + inspect:write.
|
|
#+end_src
|
|
|
|
Tomorrow: introduce ~read:get~, ~read:search~, ~write:create~, ~write:update~,
|
|
~write:delete~, ~write:execute~.
|
|
|
|
*** Equivalence of new accessors
|
|
|
|
#+begin_src python
|
|
rw = read + write
|
|
|
|
read = read:get # GET by id
|
|
+ read:search # GET/POST search entities
|
|
write = write:create # POST create new entity
|
|
+ write:update # PUT/PATCH
|
|
+ write:delete # DELETE
|
|
+ write:execute # POST to trigger action
|
|
#+end_src
|
|
|
|
* Most important points
|
|
|
|
- Dynamic role ~ids~. *Must use the API*
|
|
- when you call =/iroh/profile/whoami=
|
|
- when you look into the JWT
|
|
- *note*: potentially a list of roles!
|
|
- ~associated-scopes~ field only useful for the Role Management UI.
|
|
- Use =/iroh/profile/permissions=
|
|
- can also use ~scopes~ claim if present
|
|
|
|
** Multiple Roles
|
|
|
|
Expect the role to be a sorted comma separated role ids like;
|
|
~admin,role-344,sat,user~ (which would be equivalent to ~admin~ here) in the tokens
|
|
and not a list to prevent breaking changes.
|
|
But it will probably be a list in the ~/whoami~ response.
|