 So this is the Open Policy Agent Introduction session. So I hope everybody's here for the OPA intro session. If you're not here for this, this is a good time to leave. So before I get started, how many people here have heard about OPA before? OK, a few of you. And is anybody using OPA today? Or have you actually tried it for a POC or an experiment? Anything like that? OK, one person? OK, great. So I think everybody here is in the right place. Hopefully we can help you out a little. So my name is Toran. I'm an engineer at Styra. And I'm one of the co-creators of the Open Policy Agent. Styra is the company that created Open Policy Agent. I'm an engineer there. I work primarily on OPA. If you've been on the OPA Slack, then you'll know me as T. Sandel on there. And on Twitter, my name is Sam Toran. So before I dive into the details, what I'm going to do is just kind of give an overview of OPA and the background. So the project itself was started in the beginning of 2016 at Styra. And the goal of the project when we started it was to basically provide a building block that would help unify policy enforcement across a range of different technology. And over the last year and a half or two years, we've had a lot of growth in terms of the number of end users that are using the project to solve all kinds of different policy use cases in their organizations. So today, companies like Netflix use OPA to enforce access control over internal resources, over internal microservice APIs. Companies like Chef are using OPA to deliver IAM capabilities in their products they ship to their customers. And there are dozens of companies like Medaille and Cloudflare and State Street and more that are all using OPA to enforce all kinds of policies or guardrails or constraints over their platforms, over things like Kubernetes clusters. So today, OPA is being used for a variety of different use cases around admission control and API authorization and more things like risk management. And it's now a CNCF incubating project as well. So as of April, it was promoted up from the sandbox which we joined last year to incubating. And we have about 60 different people that have contributed to the project. We have over 900 people on our Slack organization. We've got over 2,000 stars and we have over 20 integrations with other projects in the cloud-native ecosystem. So just to kind of motivate the problem and kind of explain why OPA exists, imagine you have a large application, right? You have a microservice-based architecture and you have some portal which your customers connect to, right? And maybe they connect to that portal to buy things for their pets or to do all kinds of online shopping or something like that. And that application is implemented by a set of microservices, right? So you have a service that does payments, right? It processes all the payments that the customers are making. You have a service that handles account data. You have a service that deals with promotions, a service that does notifications, that talks to partner APIs. Some of these services talk to internal databases that you're running like MySQL, others talk to external services like S3, right? So this is a very typical kind of architecture from in modern organizations, right? Now the problem is that today, somebody like Alice, a developer, often has complete access to all of the services that make up that application, right? Alice is a developer at the company and so she often has to troubleshoot the services and make up the application. And so she has complete access to the portal and all of the payment services and account services and so on, right? And so this is important because Alice often needs to debug these services and access them and do things with them. But at the same time, it's risky, right? Because if she decides that she wants to look up Bob's credit card number or she wants to look up Bob's private information, she can do that, right? She has a lot of permissions in the system. So to address that, what we want to do is put authorization or access control checks in each one of these locations, right? So we would want to go into the payment service and add API authorization. We want to go into the account service and do the same and so on and so forth, right? And in some cases we might have to deal with external authorization systems like S3, right? Or AWS IAM. The problem though with having to go in and do authorization or access control in every single one of these services is that it raises an number of questions, right? It might be easy to do it in one service on its own but when you look at a large application, you know, in a large organization, there are all kinds of questions that come up when you're thinking about access control and authorization. So for example, you know, what do you do when the information security department comes along and they have new policies for you to enforce? What are you doing? Legal or compliance have the same, right? How do you address this across a large range of services? Moreover, how do you delegate control to your end users, right? How do you give end users the ability to specify the policies that govern access to their data? How do you roll out changes to the policy, right? The policy is going to change at some point. That's just a fact. How do you do that? Do you have to, you know, release a new version of the service? Well, that might be complicated or painful, right? You wanna just make a change to the policy. Moreover, how do you access, you know, how do you write policies that leverage external context, right? A lot of the time, the policies that make sense in large organizations depend on, you know, external databases or external context within the organization. Things like, you know, A-H-R database or an application database and so on, right? So how do you get that kind of data down to the policy engine? How do you get it into the policy engine? How do you make use of it inside of the policies? You know, and also like, how do you render UIs based on policy? How do you test your policies for correctness? How do you know the policies you've got in place are actually doing what you expect them to do, right? And how do you do this, you know, when you have hundreds of services written in dozens of different languages that have all kinds of different, you know, identity protocols that they use to authenticate users that run in different kinds of execution environments like containers and bare metal and so on and so forth, right? But the problem doesn't really stop at the application layer. It also exists at the platform layer, right? So this application happens to run on Kubernetes. And again, Alice has kind of full access to Kubernetes, right? She is responsible for providing configurations to Kubernetes that define, you know, ingresses and pods and she controls network policy for her application and she is responsible for creating persistent volume claims and all that kind of stuff, right? Well, the problem with giving Alice direct access to compute storage network resources is that a lot of things can go wrong, right? Alice can create an ingress that conflicts with another ingress in another namespace. And so suddenly, when she creates that conflicting ingress, traffic is no longer being routed to the right place, right? It's going to her development, her development instance. She can easily run, you know, vulnerable container images with no vulnerabilities, right? There's nothing stopping Alice from just saying, deploy this image from Docker Hub and run it, right? There's nothing stopping Alice from instantiating a network policy that allows outgoing, you know, egress traffic to any IP address in the world, right? There's nothing stopping that. Again, you know, Alice isn't stopped from, or she can instantiate pods that don't put any limits on CPU and memory, right? And so you can have runaway resource usage, right? So there are all kinds of different policy concerns across the stack, right? And so this is why we created the Open Policy Agent at Styra was because we wanted to provide a building block that would help you unify policy enforcement across a wide range of services. So, you know, if you look at different services or technology today, they typically have their own, you know, access control or policy or authorization systems. And the problem is that if you're in a large organization, you have every single one of these components in your system. And so to manage the access control rules becomes very difficult because you have to go into each one of those systems and modify the policy, right? Well, wouldn't it be better if we had one kind of building block, one policy system that could plug into all these different components and that would give you basically a single way, a centralized way of managing policy. So this is why we created OPA. We wanted to basically unify policy enforcement across the stack. And so this is just a picture that we often show. This is an example of, you know, all the different kinds of integrations we have with OPA. Now we have integrations with Kubernetes obviously for admission control. We have integrations with various microservice frameworks and service mesh projects. We have people using OPA to enforce policies on public clouds with things like Forceti and Google Cloud and Terraform. And then we have other integrations for use cases like data protection and data filtering and so on. So what is OPA exactly? Well, OPA is what we say, we call it a general purpose policy engine. And what that means is that it's domain agnostic. But to understand it simply, we can look at a single service. So say, you know, you were responsible for implementing the salary service within your company, right? So this service is responsible for serving salary data for employees, right? So the service exposes an API that allows you to look up the salary for any given employee, right? So you can send a get to the service for slash salary slash Bob and you provide your credentials in the authorization header. And the salary service will return the salary for that employee. But obviously, when you look up an employee's salary, you know, that needs to be authorized, right? You don't want anybody to be able to see your salary. And so that authorization process is a policy decision. And so with OPA, the way this works is that the salary service queries OPA for the policy decision, for the authorization decision. And when it queries OPA for that decision, it supplies a bunch of attributes. And so in this case, it would supply things like the HTTP method from the incoming request, the path from the incoming request, the user that's making the request, and so on, right? And so then OPA will take those attributes and it will evaluate them against policies and data that you've given to OPA to produce a decision, like allow or deny, which it'll send back to the service to be enforced. So the important thing to keep in mind with OPA is that policy, what it does is at a high level, fundamentally, is it decouples policy enforcement from policy decision making. And once you do that, once you've decoupled enforcement from decision making, it opens up a number of interesting opportunities. Now, when we say that OPA is general purpose, we really mean it. When we say it's domain agnostic, we really mean it. So I was talking about the salary service a second ago, but you could substitute salary service for all kinds of different components. It could be an API gateway. It could be a service proxy like Envoy. It could be a custom internal microservice. It could be an SSH dam and it could be an object store like Ceph, right? This is why we call OPA domain agnostic because it can plug into all these different kinds of services. Now, in order to make that work, we made certain design decisions when we started OPA. And one of them was that OPA itself wasn't gonna be coupled to any project or domain-specific data model. So the attributes that you supply to OPA in the policy query can be arbitrary JSON values. You can supply any JSON data you want in the policy query. Method and path and user are not special in any way. They're just JSON data that gets supplied as input to the policy engine. And then similarly, the output from the policy can be any JSON value. So a second ago, I showed true or false being sent back, but you can generate numbers. You can generate strings. You can generate large complex objects that represent your policy decision. So OPA itself basically helps you decouple policy enforcement from policy decision-making. And it does that by remaining domain agnostic. It sees JSON data coming in in the queries. It sees JSON data being evaluated. And it sees JSON data being sent back to the service for enforcement. Now, when you use OPA, the first thing that you encounter is OPA's policy language. And that language is called REGO. And REGO is basically a high-level declarative language that is purpose-built for OPA that is really good at expressing policies or answers to questions like, can user X perform operation Y on resource Z? Or which rules, which invariance would this workload violate if it were to be deployed? Or which records should Bob be allowed to see? So I'm gonna show an example of REGO in a few minutes, but the thing to keep in mind is that it's a high-level declarative language. And it's really good at basically letting you write constraints over large sets of JSON data, large unstructured sets of JSON data. Now, when you actually use OPA, you have different options. So, conceptually, they're all the same, but depending on your use case, some options make more sense than others. So if you're building services in GO, you can actually embed OPA directly as a library inside of your service, just as a GO library. But if you're not building services in GO, then you can run it as a daemon. And we typically recommend that what you do is you run it as a sidecar container, or a sidecar daemon, or a host-level daemon. So the model is very similar. Either it's a library embedded inside of your service, or it's a daemon that's running next to your service, ideally on the same machine. The reason that we recommend that you do this, the reason that we recommend that you take OPA and you run it next to your service, is that it reduces the impact on availability, and it reduces the impact on performance. If every single time your service has to make a policy decision, it has to call out over the network, then there's gonna be a lot of latency introduced into the request path, right? And if you're building microservices, for example, there might be several microservices involved in the handling of a particular application request. And if at every single hop in that chain, you have to call out over the network, then it's gonna blow your SLA. You're not gonna be able to meet your SLA. Similarly, if your service has to call out over the network every time it has to make a decision, then the network might get slow, it might go down, the host that OPA is running on might die, and then your service won't be able to get policy decisions back, and so it's gonna basically fail closed, and you're not gonna be serving traffic, right? So you're gonna have downtime. So OPA from the very beginning was designed with this model of acting as a host local cache for policy decisions. What it does is it enables distributed policy enforcement. You take OPA and you run it next to your service. In order to make that happen, we made certain design decisions again, so the first of which was that all the policy and data that OPA uses to make decisions, all of that is kept in memory. When you ask OPA for a policy decision, it has all the data and the rules it needs to resolve that query and send back an answer. So it's not gonna call out when you ask it for a decision to another service. It's not gonna ask another service for more data on its own. You can extend OPA, you can in your policy, you can do an HTTP call out to get more data, and you can extend OPA by adding a plugin to it to call out to get more data. But on its own, it's not going to do that. On its own, it has all the policy and data it needs to make decisions in memory. Now that obviously begs certain questions, which are where do the policies and data come from? You can't just have the policies and data sitting in memory and hope that it never goes down. So in order to get policy and data down to OPA and in order to control and observe OPA, we have a set of management APIs. So for example, we have the bundle service API which you use to send policy and data down to OPA basically OPA will periodically call out to the bundle service and ask for the latest version of policy and data. And if there's a new version, then it gets downloaded. We have the status service API which you can implement to receive status updates from OPA. Those status updates tell you whether the version of policy and data that OPA has activated that it's currently running with, right? So you can use this to detect, is it up to date, are the app is up to date, or have they encountered errors in trying to activate the most recent bundle of policy and data. And we also have what we call the decision log service API which you can implement to receive audit logs from OPA. So every time OPA makes a policy decision, it keeps a record of that policy decision and then it periodically uploads batches of those decisions to the decision log service. And so that decision log service is useful from an audit perspective because now you have a record of all the policy decisions that have been made by all the OPAs in your system. But it's also useful for capturing data for things like debugging and test purposes. And then in addition to all the management APIs, we have tooling that help you basically build, test, and debug your policies. So we have an interactive shell that you can use on the command line to experiment with policies. We have a test framework so you can actually write unit tests for your custom policies, which is really useful for making sure that your policies are correct, right? Part of the idea behind OPA is that policies should be treated as code. Just like you wanna treat infrastructure as code, OPA basically delivers policy as code. And so we give you a test framework that you can use to write unit tests for your policies. And then we have a bunch of other tools, command line tools that format your policies, do all kinds of semantic checks, as well as IDE integrations. So if you start writing policy for real, I recommend that you check out the VS Code, Visual Studio Code plugin. It's very powerful and it helps you kind of interact with the policies inside of VS Code very nicely. So what I'm gonna do now is run through a quick example of how you would implement policies inside of OPA. And so the policy that I'm gonna implement says that employees should be able to read their own salary as well as the salary of anyone that they manage. And so to do this, I'm going to use the OPA Playground, the Rego Playground. This is a new service that we created earlier this year. And the service has some nice features that I'm gonna kind of run through and explain to you as I go. So this is the policy that you see when you start off and I'm just gonna delete that. And so to implement this policy, remember we want the first rule basically needs to say that employees can access their own salary. And the second policy says that employees can access the salary of people they manage. So to implement the first rule, what I'm gonna do is create a rule called allow. And I'm gonna say that allow is true if the input, actually wait, let's back up a second. In order to test this out, I'm gonna have to define some input data. And so the Playground lets you do that, it lets you put input data in the browser here. And so I'm gonna say that for example, the input method is get. Again, this is just from the slides before. And the path say is salary Bob. So this is a look up for Bob's salary. And I'm gonna say the user making the request is Bob. So to write the rule for the first case, what I'm gonna do is say, I'm gonna say the rule is called allow. And allow is true if input method is get and input path is salary employee ID. And input user is employee ID. So this rule says allow is true if input method matches get and input path matches salary employee ID and input user matches employee ID. So the expressions in the body of the rule are added together. The interesting thing about this rule is this employee ID here. So this employee ID is a variable. And what happens when OPPA evaluates rules is it looks for bindings for those variables, values for the variables that make all of the statements in the body of the rule true. So in this case, in order for allow to be true, all the statements in the body of the rule have to be true. So OPPA is gonna search here to find whether employee ID can match all of these expressions. So one of the powerful things about the playground is that you can evaluate it here. So I just clicked output and it'll take a second. And you can see that today, right now the output is true, right? Because I basically got Bob looking at Bob's own salary. So that should be allow. But if I change this and I say, Alice is looking at Bob's salary, oops. Then it's undefined. The reason it's undefined is because none of the statements in the body of the rule match. So typically what you'll see in OPPA policies is something like this. We'll say default allow is false. So this means that if allow doesn't match, then it'll take this default value on. And now if I go and I evaluate this and we wait for the network, there we go. Now it's false. Okay. Now, one of the powerful things about OPPA is that you can actually evaluate pretty much any part of the policy you want. So if I don't select anything, and I just ask for the output, you can see that basically prints allow is false. So what's happening here is that OPPA is basically telling you the values of all the rules in the body. And right now we only have one rule. It's called allow. But you can actually go further than that. So you can actually select parts of the rule and hit evaluate and it'll print the answer. What do you think's gonna happen when I do this? Now we've got a variable inside the query. Well, it's gonna tell us the value of that variable when the rule got evaluated. And in this case, it got down to Bob. So if I go and I select the last one, it's gonna be undefined because obviously input user does not equal Bob. It doesn't equal employee ID. Okay, so that's the first part of the policy. To implement the second part of the policy, we're gonna need to do a little bit more. So we're gonna need some data in this case to decide whether or not one employee is a manager of the other. And so what I'm gonna do is just to find that data here in the policy. I'm only gonna do this because it makes it easier to kind of show and to interact with in the playground. Typically this kind of data would be loaded into OPPA just as raw JSON. It wouldn't be encoded inside the policy. Or it would be passed as input. So like in this case, the management chain for an employee could just come inside of like a token or something like that. So in this case we'll say that Bob is managed by Alice and Fred and Alice is managed by Fred. So I've defined this as basically a map of strings to sets and so Bob is managed by Alice and Fred and Alice is managed by Fred. Now in order to make use of this data, I'm gonna add another rule and it's gonna just be called allow again. So we're gonna say allow is true if input method is get and input path is salary employee ID. But this time instead of checking whether the input user is the employee ID, I'm gonna check whether the input user is a manager of the employee. And so to do that, we're gonna do a lookup on the managers. So we're gonna say give us the manager or rather the managers for the employee and then we're gonna ask whether the input user is inside of that set. So one of the things that you'll find in Rego that's very frequent are these references we call them. These are basically performing lookups on these JSON documents. And so now if I go back and I refresh the policy decision, now it's true because Alice is a rather the manager of Bob. If I change this to Bob and I tried to get Bob to look up say Fred's salary, that would be rather that'll be denied. So the allow will be false. Now typically if I was doing this for real I wouldn't just test everything with the input data here. What I would do is I would write a bunch of test rules to verify that the behavior is correct. So I would say, for example, allow must be true when given certain input. So for example, when method is get and user is Bob and the path is for Bob's salary. And so then I can go and evaluate that. Oops, it's a parser, sorry, with input as. And so here you can see that test allow is true because the statements in the body were held. And so I would basically build up a bunch of these test cases to ensure that the logic that I just expressed above was correct. So that is it for the demo there. When you go to start using OPA for the first time you might be looking for integrations with existing projects in the ecosystem. And so we have a number of them. I think there are over 20 or 25 now. We have a number of integrations with different projects for doing admission control. That's one of the main use cases that people have for OPA today. They wanna enforce different kinds of policies over their platforms. And so for that we have integrations with Kubernetes. People use OPA with Terraform. We have another integration with Docker that's very similar. And the idea there is you just wanna enforce certain policies over configurations that developers are supplying when they deploy their applications. So you wanna say things like, only container images must come from the corporate image registry. Or you wanna say that all workloads need to have CPU and memory limits supplied when they're deployed. Or you wanna prevent conflicting ingresses from being created, for example. The other main category of use cases we have is around API authorization, typically in microservice environments. And so we have a bunch of different integrations with projects like Istio and Envoy and Kong and Linkerd and Spring and more. And the idea there is that you wanna provide, obviously IAM or access control policies for your internal environments. And so you wanna, for example, deny test scripts from accessing production services. You wanna prevent analysts from accessing sensitive data and so on and so forth. But we have a long list of other integrations. So for example, we have a PAM plugin for OPA where basically you can enforce, you can use OPA to enforce access control policies over SSH and Pseudo. We have one user of OPA where basically they have a policy in place that says that developers are only allowed to SSH into machines that are running applications that that developer works on, right? And there has to be actually an open ticket for that application at that time. Otherwise they can't get on the machines. And that just resolves like a long standing problem in system administration of people getting added to net groups and things like that. And then never getting taken out, right? So this way you have a flexible kind of context-aware method of enforcing policy over SSH and Pseudo. And then we have a bunch of other integrations with projects like SEF and Kafka and Minio for doing different kinds of data protection use cases. You know, a lot of large organizations are building out data lakes internally. And there's definitely a need for fine-grained attribute-based access control there. And OPA really enables that. So what I thought I'd do is just highlight a couple of the users that are running with OPA today in production. We talked about some of this a couple months ago at the CNCF TOC meeting, but I'm just going to kind of highlight them again here. So one of the users of OPA today is Netflix. They were one of the earliest adopters of the project. And today they're basically using OPA to enforce a variety of different access control policies across their internal environments, right? So they have a large microservice-based environment. And they, you know, they developers there use a variety of different languages and frameworks. And they have different kinds of execution environments where the services run. And so the challenge there was to find, you know, a way of expressing policies over this very heterogeneous and ephemeral kind of, you know, environment. And so they looked at OPA and they decided to adopt it and build it into their internal security platform. And what they found was that the ability to, you know, leverage contextual information to load arbitrary context into the policy engine and use that to inform policy decisions, they found that very, very valuable. And they found it very valuable to be able to use a single language, essentially, to express policies across a wide range of different languages and frameworks. And so we have actually a talk from KubeCon Austin 2017. If you're interested to see how they're using it, check that out. Another company that's using OPA today for a similar but different use case is Chef. So it's again, it's an API authorization use case, but it's a little bit different because Chef is obviously a software vendor. They ship software to enterprises and anytime you ship a software product to an enterprise, you have to deliver IAM functionality. You have to deliver authentication and authorization and accounting. And so for Chef, OPA basically provides an engine, a building block that helps them get to market faster. They don't have to go and reinvent this authorization engine from scratch. They can basically take OPA and with a bit of policy in place, they're able to deliver an AWS IAM style policy to their customers inside of their products. And actually today, they're also using some more advanced features in OPA, like partial evaluation. And so if you're interested in this, I would check out, it's actually open source. If you go to Chef Automate on GitHub, you can find examples of that and how they've architected it. And then finally, an example of a company that's using OPA for Kubernetes is Intuit. So Intuit uses OPA as a validating and mutating admission controller in Kubernetes. And they use it to enforce a variety of different security and multi-tenancy and risk management policies across a large set of clusters and a large set of namespaces. For them, they have large multi-tenant workloads deployed on Kubernetes. And it's very important that they're able to put kind of safeguards in place to prevent different applications from interacting with each other in bad ways. And again, we did a talk with them at KubeCon Seattle in 2018. So if you're interested in admission control in Kubernetes and how companies like Intuit and Capital One are using OPA for that, check out that talk. So that's it. We've got about four minutes left for questions. I'll point out that there are two talks later today that are related to policy. So one is the talk on Gatekeeper by Craig Peters at Microsoft. That's at 6.15. If you're interested in how you can use OPA to enforce policies in Kubernetes for admission control, go to that talk. I think it'll be really interesting. There's also the Kubernetes Policy Working Group deep dive session from Howard at Huawei happening at the same time. So you'll have to pick which one you want to go to, but both of those should be great sessions. If you're interested in the code behind the project, check out open policy agent slash OPA on GitHub. And if you have questions or anything like that, feel free to join the Slack organization and post your questions on there. So with that, I'm happy to do some Q&A right now if anybody has questions. Otherwise, thank you very much for coming. Question? They want to record in, so sorry. Hi, do you have any integrations where this can be mapped to OAuth claims? So the claims are given out based on policy? To generate claims or to validate claims? I guess both. Both? There are people looking at using OPA to generate the claims that go into a token. You can definitely do that because that's just JSON, so it's just a different kind of policy decision. We don't have specific examples of that on the website. What we do have though in OPA is a set of built-in functions for doing things like string manipulation and math and all that kind of stuff. But we also have built-in functions for interacting with JSON web tokens. So if you want to basically pass a JSON web token as input to the policy and then inside the policy, verify the signature and validate things like not before and expiring all that, you can easily do that within the policy language. I'm not sure if you know there was another product created by HushCop named Sentry, right? It's also a product related to policy as code. Can you do a quick comparison between OPA and Sentry? So the question is, how does OPA open policy agent compare to Sentinel, which is a HashiCorp's policy as code project? And the answer is that they're both similar. They both aim to allow you to express policy as code. I guess the main difference at a very high level is that Sentinel is, it's a closed source proprietary feature of their enterprise HashiCorp products, right? So it's not open source. And it's really, I think, focused at those kinds of policies that you apply to the platform, right? To HashiCorp projects, right? Like Vault and Terraform and so on. So OPA is a little bit more general purpose in that you can kind of use it as a building block, a library for all kinds of different policies at different levels of the stack. At the language level, there are some differences. OPA is a little bit more declarative, whereas the Sentinel language is a little bit more imperative. It's more like JavaScript, which has pros and cons associated with it. So I'm happy to chat about that more offline if you're interested, but it's a fairly long answer, I think. Okay, thank you. Yeah. I think there were a couple of questions at the back. Hi, just a quick question. If I'm to embed OPA into embedded device with a relatively constrained memory, do you have any idea about the size of the OPA codebase or the binary or the image? So the binary is about 20 megabytes in size. So the memory usage is fairly low. It's about 20 megabytes if you're just running it without anything inside of it. Obviously the amount of memory that it's gonna consume at runtime depends on how much policy and data you load into it. So it kind of depend on the types of policies you need to express, but it is fairly lightweight. We don't have very many dependencies in the project itself. It's written in Go, so I don't know how that would work for your environment, but that's one thing to keep in mind. I will mention that one of the things that we're working on that's more speculative and more long-term is support for taking the OPA policies and compiling them into web assembly. And so with that, I think we might be able to deliver like an even smaller memory footprint for the policy evaluation. So a question, you had an example on how to implement policies across the enterprise where you can look salaries just for the people you manage. And then you said that some organizational structure can be imported into OPA using a JSON structure. Yeah. Would that require some reboot, some restart of the service or it's all seamless from the application perspective? So it can be hitless. So there are two ways of loading policy and data into OPA. One is through the bundle service API that I mentioned. Basically OPA will periodically download policy and data from a remote service and reload it on the fly without affecting policy queries. The other is that you can push policy and data into OPA. It has an API that allows you to just push policy and data in through an HTTP API. That works. It's a little bit more complicated, I think though, to design that into your system in a way that's reliable and correct. So we generally recommend people start with the bundle service model and then if they need push kind of capabilities later on, they can always add that. And the other question would be, do you push all the policies to all microservices or you can push just the policies that relate to that microservice to that OPA? That's a good question. So OPA itself is just the decision engine. All it does is it just says given the policies that you give it, answer questions, right? It doesn't decide which policies go down to OPA, right? So that's sort of up to you as the implementer of the control plane around OPA. That's sort of the challenge that we don't tackle within OPA itself. Thank you very much. Cool. One more question. Okay, I think we're a little bit over time. I'm happy to answer offline. So it's giving us making a lot of decisions in the organization. So it can be facing a lot of volume. So it has to be quick or very fast. So do you have a general idea about performance? Like how long does it take to make a decision? So we sort of have two profiles for OPA policies. One profile is kind of what we call the linear time profile or linear time fragment of OPA. And that's sort of targeted at API authorization policies. If you do write your policies in a way that falls into that fragment, then OPA will index the rules for you. And it can answer policy queries in like under 100 microseconds in a lot of cases or under a millisecond is usually our budget. That's the number that we got from Netflix. The other category of use cases is like more around platform kind of policies over say a Kubernetes cluster. And in that case, you often have to do a large search over like the state of the cluster in order to make the decision. And so there the budget for latency is a little bit higher because of that search operation, right? So it depends on the use case, but typically under a millisecond for API authorization. Okay, thank you.