-
Notifications
You must be signed in to change notification settings - Fork 350
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Opal Intel module #1411
base: master
Are you sure you want to change the base?
Opal Intel module #1411
Conversation
…ss to and who can automatically and manually approve themselves to those resources.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for putting this together, I'm excited. Left some comments about using the data model to represent some of the OpalResource relationships, and how we'd need to add some read_transaction() functions to grab lists of IDs from the graph to make that possible.
I think it's also worth adding in a "fake tenant" node for the OpalResource so that we can automatically clean up the OpalResources -- this is done with the LastPass sync here: #1083.
Happy to get on a call if there's things that don't make sense, also happy to help with making these changes too, just let me know.
UNWIND $auto_approved_access AS access | ||
MATCH (opal_resource:OpalResource {id: access.resource_id}) | ||
MATCH (okta_group:OktaGroup {id: access.okta_group_id}) | ||
MERGE (okta_group)-[r:CAN_AUTO_APPROVE_ACCESS]->(opal_resource) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same idea like with (:OpalResource)-[:PROVIDES_ACCESS_TO]->(:AWSRole)
: let's refactor to use a rel schema with make_target_node_matcher so that the OpalResource looks for an OktaGroup with the group id we need. We should use read_transaction() to get those OktaGroups.
It's a bit of a performance hit to do it this way because of the data moving back and forth, but I think it's worth it to get the automatic cleanups and data model benefits.
(aws_role:AWSRole)<-[:ASSIGNED_TO_ROLE]- | ||
(aws_permset:AWSPermissionSet {arn: resource.remote_id}) | ||
MATCH (opal_resource:OpalResource {id: resource.resource_id}) | ||
MERGE (opal_resource)-[r:PROVIDES_ACCESS_TO]->(aws_role) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use the OpalResource model that you created.
We can refactor to use rel schema with make_target_node_matcher
. To do this, have a separate function query for the AWS role names that we need to grab from the given permission set. That separate function should use read_transaction for auto retries like in
cartography/cartography/intel/okta/awssaml.py
Lines 126 to 137 in 1401ca5
def get_awssso_okta_groups(neo4j_session: neo4j.Session, okta_org_id: str) -> list[OktaGroup]: | |
""" | |
Return list of all Okta group ids in the current Okta organization tied to Okta Applications with name | |
"amazon_aws_sso". | |
""" | |
query = """ | |
MATCH (g:OktaGroup)-[:APPLICATION]->(a:OktaApplication{name:"amazon_aws_sso"}) | |
<-[:RESOURCE]-(:OktaOrganization{id: $okta_org_id}) | |
RETURN g.id as group_id, g.name as group_name | |
""" | |
result = neo4j_session.read_transaction(read_list_of_dicts_tx, query, okta_org_id=okta_org_id) | |
return [OktaGroup(group_name=og['group_name'], group_id=og['group_id']) for og in result] |
return opal_to_okta_map | ||
|
||
|
||
def get_owner_ids_to_okta_groups_map( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to move this and get_opal_groups_to_okta_groups_map to opal_okta.py?
return group | ||
|
||
|
||
def get_all_groups(client: opal.api.GroupsApi) -> List[Dict[str, Any]]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move this to opal_common.py? I'm thinking this file should pretty much only have the start_* and other orchestration functions.
return owner_ids_to_okta_groups_map | ||
|
||
|
||
def cleanup(neo4j_session: neo4j.Session, common_job_parameters: Dict[str, Any]) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move this to opal_aws.py?
{ | ||
"statements": [ | ||
{ | ||
"query": "MATCH (n:OpalResource) WHERE n.lastupdated <> $UPDATE_TAG WITH n LIMIT $LIMIT_SIZE DETACH DELETE n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use the OpalResource model that you created so that we can remove this manual cleanup job. To do this we can introduce a fake "tenant" like in this LastPass PR: https://github.com/cartography-cncf/cartography/pull/1083/files#diff-3b2215e87b2aaf55796fc63a223403d163b97d5bcbb6931d5886802a1f554cd8.
UNWIND $manual_approved_access AS access | ||
MATCH (g:OktaGroup {id: access.okta_group_id}) | ||
MATCH (r:OpalResource {id: access.resource_id}) | ||
MERGE (g)-[rel:CAN_MANUALLY_APPROVE_ACCESS]->(r) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here about making this a rel schema defined on the OpalResource model and then using a read_transaction function to get a list of the IDs you need.
Intel module to map in Opal Resource, what those resources grant access, and map who can automatically and manually approve themselves to those resources.
Summary
Related issues or links
Checklist
Provide proof that this works (this makes reviews move faster). Please perform one or more of the following:
If you are changing a node or relationship:
If you are implementing a new intel module: