-
Notifications
You must be signed in to change notification settings - Fork 8
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
Authorization gateway - basic features #138
Conversation
…or all resource repositories
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.
Is it possible to implement the policy resource abstraction in a layer above the ResourceRepository? I think it adds complexity to something that should be "stupid" storage.
queries?: QueriesResults; | ||
}; | ||
|
||
export type QueriesResults = { |
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.
Maybe QueryDefinition
instead of QueryResults
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.
This contains the results of all the queries associated with a specific directive execution, not the definition (which is why the schema here is not strict, since we don't know how the results look like).
The query definition with the strict schema is defined here
const params: any = { | ||
Bucket: this.config.bucketName, | ||
MaxKeys: 1000, | ||
Prefix: this.config.policyAttachmentsKeyPrefix, | ||
}; | ||
if (continuationToken) params['ContinuationToken'] = continuationToken; |
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.
const params: any = { | |
Bucket: this.config.bucketName, | |
MaxKeys: 1000, | |
Prefix: this.config.policyAttachmentsKeyPrefix, | |
}; | |
if (continuationToken) params['ContinuationToken'] = continuationToken; | |
const params: AWS.S3.Types.ListObjectsV2Request = { | |
Bucket: this.config.bucketName, | |
MaxKeys: 1000, | |
Prefix: this.config.policyAttachmentsKeyPrefix, | |
}; | |
if (continuationToken) params.ContinuationToken = continuationToken; |
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.
👌
this.policyAttachmentsRefreshedAt = newRefreshedAt; | ||
} | ||
|
||
private shouldRefreshPolicyAttachment({filename, updatedAt}: {filename: string; updatedAt: Date}) { |
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.
Export {filename: string; updatedAt: Date}
as type
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.
👌
const policies = this.args.policies; | ||
|
||
field.resolve = async (parent: any, args: any, context: RequestContext, info: GraphQLResolveInfo) => { | ||
const executor = new PolicyExecutor(policies, parent, args, context, info); |
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.
I think that PolicyExecutor can be stateless class with static methods
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.
In the current situation I would agree, but it's a WIP that should possibly later contain shared execution context for the current request, for optimizations and memoization of query results and other things. I eventually removed the optimizations from it for now, and delayed their implementation to be done separately as a different task.
If we end up implementing the optimizations in another way that does not use this class for it, we can convert it later
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.
I agree, but actually it can be just function in the current state. I think if we'll need to make it more complex we'll do it then.
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.
Looking at the code now, if we change it to a stateless class we would have to pass around a lot of arguments between functions. It will probably be annoying enough to do, that some code that could be split to functions would remain as bigger functions that are harder to work with and test, in order to avoid having to pass all that context around
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.
It's 4-5 parameters at most. On other side it encourages you to write pure functional code where it can be done.
policyArgs[policyArgName] = policyArgValue; | ||
return policyArgs; |
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.
policyArgs[policyArgName] = policyArgValue; | |
return policyArgs; | |
return { ... policyArgs, [policyArgName]: policyArgValue }; |
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.
Since this code will run on every field with a policy directive, it can potentially run very often.
Changing to your suggestion means that each iteration of the reduce loop would create a new "result"/accumulator object, and the old one would have to be garbage collected.
If I keep the code as is and re-use the same object for the entire loop, that object would be garbage collected only once when the loop ends instead of for every iteration.
It's a very small optimization, but it builds up when there are a lot of them in hot code paths
I generally agree, it was that way initially, but after discussing it with Aviv we decided to make the change for practical reasons. For example, S3 supports listing files along with the details for each file (notably It makes sense that the repository itself would be aware of the implementation with the best performance rather than the abstraction layer intimately knowing the internals of each of the repositories. |
Since this component is not performance-critical (it's control layer), I think it's better to use straight forward storage abstractions (for example, in the fs example, in general, the cost of these reads should be really low). Be glad to discuss it more. In general, I think that:
Is using higher-level abstraction than storage, there shouldn't be an implementation of fs/s3 for these methods, they should implement lower-level abstraction. Even from OOP perspective, this interface has too many reasons to change, and it behaves more like a header interface rather than a role. Since we already have two implementations, I think it's possible to extract the shared code from both implementations to make sure we use the right abstractions. Also, the original D2C service had support for loading files and CRDs using the same abstractions and it was quite simple. In projects like gloo/sqoop that use similar concepts of a control plane, storage is usually abstracted away (even if there aren't many implementations). |
The problematic part is actually in the gateway, so performance does matter. It happens continuously in the background and not in a specific request, so the performance is not critical, but it should be reasonably good. That said, I think we can probably do better, likely even with having basic abstractions over each repository type and then an abstraction over it to manage the resources. |
We can open issue :), it's definitely not a blocker. |
There is actually no parsing involved (except the resource groups, but that is only one file), it's WASM files so we keep the data as it is read in a Buffer (and provide it to OPA this way). |
Correct me if I'm wrong, and I might be, but it seems like the authorization subsytem basically doesn't work the same as the rest of the system, when it comes to resource updates. |
I saw what you mention being used for updating the graphql server with schema changes, however the graphql server is not directly using the Policies (like it is using the schema) or their attachments. Why would we want to apply this same logic to them? |
Discussed this with Aviv, I will make some changes to move this data into the RequestContext instead, and change the policy updates to be tied into the other resource updates. |
13de708
to
3474a52
Compare
* Authorization - fully implemented registry part (#133) This includes: Create/update policy resource Attachments support for policy resource (with support for writing the attachment to both s3 and fs repositories) Opa policy type implementation, including compiling rego code to wasm and adding that to the policy as an attachment * Authorization gateway - basic features (#138) implemented full flow with basic features Implement local policy attachment caching for all resource repositories * Add policy definitions and attachments to request context, change pol… (#141) * Add policy definitions and attachments to request context, change policy executor to use them from context instead of directly from repo * PR comments * allow jwt in param injection (policy authorization can use it through args) (#144) * Support for policy query (#143) * Policy directive - accept only a single policy (#146) * change policy directive to accept only a single policy * Refactored PolicyExecutor API to only expose static methods Co-authored-by: Tomer Eskenazi <tomeresk@gmail.com>
implemented full flow with basic features Implement local policy attachment caching for all resource repositories
Implemented:
opa
policy types, with support for args with param injectionNot yet implemented (Planned for future PRs, not this one):
opa.ts
andpolicy-executor.ts
in the policy directive folderAnd
vsOr
). Currently it always requires all mentioned policies to pass (And
).