 So let's get started. Thank you all for coming to this talk on fine-grain authorization in the containerized world. I'm Ash Narkar. I am a software engineer at Styro. And we are the makers of the Open Policy Agent project. Just a quick show of hands. How many of you have heard about the Open Policy Agent? OK, cool. And I'm also a core contributor to the Open Policy Agent. So in this presentation, we will talk about security, especially around authorization in a world where microservices are being adopted by increasingly a number of companies. Then we will see the Open Policy Agent, talk about its communities, features, integrations. And then we will dive down into a use case around Kubernetes Admission Control. So I hope after this talk, we can make it easy to enforce fine-grain authorization in all your systems. So let's get started. So today, lots of companies are using microservices to build and deploy their applications. And for good reason, microservices allow applications to scale independently. They decompose them into smaller parts, which can be reused. And they can increase the productivity of development teams. And so you have your microservices, and you can take its dependencies and all its configuration and package them in a container, which can then be deployed onto different hosts. In the real world, though, any production app will have a number of containers and will probably be deployed across multiple hosts. So managing all these containers is going to get really complicated, really fast. So enter Kubernetes. Kubernetes is going to help you to manage and deploy these containers across multiple clusters. And it will also take care of stuff like service discovery, resource management, container scaling, container health, and so on. And so what we see today is that companies are using Kubernetes in production. So it becomes really important to make sure that all the security compliance rules, as well as any other rules related to security, are actually getting enforced inside your cluster. And so in this talk, we will focus on the security around the Kubernetes API server. Kubernetes has what you call an intent-based API. Now, so what do I mean by an intent-based API? When a Kubernetes user makes an API call, he is telling Kubernetes what the desired state of the system should be. He is telling Kubernetes what the system should look like. He does not care how Kubernetes attains that desired state. So for example, if the user has an application which requires persistent storage with encryption and the connection to the internet, he will just tell Kubernetes that he wants these things, and then Kubernetes has to figure out how to configure the network to allow the internet connection or how to turn on encryption. So this intent-based API is something different than what we are normally used to, which is an action-based API. In the sense, you don't have a slash open port endpoint, which you can just call, and then your code just opens up a port for your application. So that's why we have an intent-based API in Kubernetes, which is different than what we know about an action-based API. You focus on the what rather than how. Secondly, if a user wants to define a desired state for the cluster, he will define it in a YAML file. So for example, this is, say, the desired state for an nginx workload. Now, what the user will do is take this file and do something like a kubectl apply and send this over to Kubernetes for it to do its job. Now say, for example, I wanted to update the nginx version, or if I wanted to add some configuration parameters to this deployment, I would simply update this file and just do a kubectl apply again. And Kubernetes will just take care of the rest. So my point here is, I don't have to define an endpoint like update nginx version for me to update this version. I can just update the file and then let kubectl do its magic. And so given this intent-based API and given that you can have desired state defined in a YAML file, you can imagine some of the security policies that you may want to enforce in your cluster. For example, you do not want your pods to pull images from Docker Hub. You want your images to come from your trusted repos. You don't want your containers to have unlimited CPU memory. You want them to specify certain CPU and memory requirements. You don't want to use latest tags on your images. Or you don't want to deploy your workloads on master nodes. So the question now is, who is going to enforce these kind of policies in your cluster? And I think the answer is pretty clear here. It's RBAC, right? Role-based access control. With RBAC, you can restrict users' group service accounts to perform certain actions on certain resources. And so RBAC is going to help you enforce all these policies in your Kubernetes cluster, or can it? Do you think given the intent-based API and given that you can change a certain section of the YAML to change the desired state of your cluster, is RBAC enough to enforce these kind of security policies in your cluster? Unfortunately, the answer is no. RBAC is not enough. RBAC is not expressive enough. RBAC is too coarse-grained for use cases like these. Because RBAC cannot analyze arbitrary YAML documents and make a decision from them. So RBAC, even though very valuable, is not suited for these kinds of policies which are fine-grained and require something which is much more expressive. And so we need a solution which is not just expressive, but also does not compromise on speed and performance. And these are some of the challenges that the open policy agent was created to solve. And so what is OPA? OPA is an open-source, general-purpose policy engine. You can take OPA and you can use it at any layer of the stack in any system. When you use OPA, you are decoupling policy enforcement from decision-making so your application can offload policy decisions to OPA by executing queries. So before we go deep into this, I just wanted to talk about the community around OPA. So the project was started in 2016 at Styra, where I work. And the goal of the project has been to unify policy enforcement across the stack. One of the earliest adopters of OPA was Netflix. And they use OPA across their stack for authorization over HTTP and GRPC APIs. You have companies like Medallia which use OPA for risk management in Terraform. You have banks like State Street, ABN Amro, and companies like Intuit and Pinterest who are using OPA for use cases like admission control, authorization, data protection, risk management, and so on. OPA is a CNCF project. And it was recently promoted to the incubating level. It has more than 70 contributors on Git and a healthy Slack community of more than 1,100 people. And just to give you some context around these numbers, at the beginning of the year, we had around 400 people in OPA Slack. So it's great to see OPA grow, people using OPA. And that's why it has more than 2,400 stars on GitHub. OPA is integrated with more than 20 of the most famous open source projects out there. And we will talk about these integrations later. So let's talk about why OPA is a general purpose policy engine. So let's say you have a service. And this service can be anything. It can be your own custom service. It can be a Kubernetes API server. It can be Kafka anything at all. So when your service gets a request, it's going to ask OPA whether that request is allowed or not by executing a query. And this query can be absolutely any JSON value. OPA is going to evaluate this query based on the policies and the data it has access to and send a decision back to your service where it gets enforced. And again, this decision can be any JSON value. So what we have done here, we have decoupled the policy enforcement from the policy decision making. And as far as OPA is concerned, you give it any JSON value. And if you write policies which make sense for that data you give it, OPA will send you a decision back. And that's why we say OPA is a general purpose policy engine. Let's look at some of OPA's features. At the core of OPA is a high level declarative language called as Rego. And with Rego, you can answer questions like, can user do operation Y on resource Z? Or which fields is a user allowed to see? So with Rego, you not only get Boolean decisions like allow, deny, through, false, yes, no, but you can express decisions that are collection of values. OPA is written in Go. And you can deploy it as a sidecar, a host-level demon, or you can embed it as a library. It's designed to be as lightweight as possible. So all the policies and data it needs for evaluation is stored in memory. You can think of OPA as a host-level cache for your policy decisions. It does not have any runtime dependencies, so it does not need to talk to any external servers to make a policy decision. You can, however, extend OPA so that it talks to an external service, but that is completely optional. It also gives you some management APIs with which you can download policies and data from your remote HTTP servers. It can upload its status to remote servers, and it can also upload decision logs to the remote HTTP servers which you can use for debugging your policies and for offline auditing. Along with the core policy engine, OPA has a rich set of tooling which you can use to write unit test policies which you can use to author policies using integrations with Git and VS code. And it also has a tracing functionality which you can use to see the steps involved in the evaluation. So these are some of OPA's features, a high-level declarative language, multiple deployment models, management APIs, and a rich tooling set. Now, like I said before, OPA is integrated with more than 20 of the most famous open source projects out there, and these are the sum of them. One of the hottest use cases for OPA is admission control in Kubernetes. OPA is also integrated with service mesh projects like Istio, Envoy to provide API authorization. With OPA and Linux PAM, you can have fine-grained authorization over SSH and Pseudo. It's also integrated with Kafka and Chef to protect the data which is stored in these systems. In the Kafka example, you can use OPA. There are some topics which have high fan out, and you want to prevent corrupt data from being written on those topics because it will be read by many consumers. So with OPA, you can authorize which users are allowed to write on such high fan out topics. One of the newer use cases for OPA is around data filtering. And in this use case, instead of OPA returning to you a decision, like an allow or deny, OPA returns to you a set of conditions which can then be translated into elastic search or SQL queries and then implemented on the database itself. So these are some of OPA's integrations. And the cool thing here is you can start using OPA right now to enforce custom policies with any of these integrations out of the box without having to write a single line of code. So how does OPA actually work? So we've seen this figure before. Your service gets a request. Your service asks OPA for a decision. OPA uses the policies and data it has access to to send a decision back to your service for enforcement. Now let's say you have a salary service which provides information about salaries of employees in a company. And the policy you want to enforce in English says that employees can read their own salary and the salary of anyone they manage. So let's see how we can take this policy in English and implement it in OPA. So like I said, your service needs to provide some kind of input to OPA to make a decision. In this case, your service may provide the method, the path, and the authenticated user making the request. So one thing I need to make clear here is that OPA does authorization and not authentication. So OPA is not trying to solve the problem. Who is Bob? OPA is trying to solve the problem. What can Bob do? So now let's take this policy and let's implement this in Rego. So to do that, to make it easy to write policies in Rego, to experiment with Rego, we recently released a Rego Playground. And the Rego Playground is this awesome online tool which you can use to write Rego policies. So it's available at play.openpolicyagent.org. And if you go to the Playground, it looks something like this. So you can see the syntax highlighting for Rego code which makes it easy to debug and write Rego. And the way you read this policy is allow is through if input.method is get and input.path is salary employee ID and input.user is employee ID. And the cool thing about this policy is that the employee ID variable on line seven and eight will be bound to a value from the input. And so the way you can give an input to this policy is simply by clicking the input button. And so what I'm saying here, my method is get, my path is salary Bob and my user is Bob. So the question I'm asking here is can Bob see his own salary? So let's find out the answer which you can get by clicking on the output button. Allow is through which means Bob can see his own salary. And so what happened here is that the employee ID variable got bound to Bob and all these expressions were through and as a result, the policy returned a result which is through which means Bob can see his own salary. One of the other things you can do with the playground is you can evaluate particular sections of the policy. So for example, you can just select this allow rule and just evaluate that which is through in this case. Now let's say Alice was curious about Bob's salary and she wanted to see Bob's salary. So the question here is can Alice see Bob's salary? And so if we evaluate this policy again, you're gonna get a false, which means Alice cannot see Bob's salary, which is what we want. The second part of our policy said that a manager should be able to see the salary of their employees. So now let's say Alice gets a promotion and she becomes Bob's manager. So we need to tell OPA this new information. So you can imagine this information being stored in your LDAP server somewhere and OPA can fetch that information and use it to make a decision. For the purposes of this demo, let's hard code this information in the policy itself. So we can have a manager's object and we can say Bob's manager is Alice and Fred and let's say Alice's manager is Fred. And so now we need to extend our policy to make use of this new information. So the user can now also be a manager of the person he's trying to view the salary of. So if I have typed correctly, the question we ask again is Alice, who is Bob's manager, can she see his salary? And if you evaluate the allow rule now, hopefully the answer should be true, which means Alice can now see Bob's salary, which is what we wanted in our original example. So you can see here that you've taken a policy in English and converted it into a simple policy by writing some rego. And so now that you have written your first policy, you can share this policy with your friends, your family and the entire world by simply clicking on this share button, which will give you this beautiful link which you can copy and share it with anyone you want to. But before you share this link, let's check out what's inside the link. So there you go. You can see the policy which you wrote, which is always good, but there's more. If you click on the input, you will also get the input that you had provided to your policy, which means if you evaluate it again, you're gonna get the result which was true like before. So I hope you guys experiment with rego policies by using the playground and share your policies with the whole world. Let's look at some of OPA's use cases. So like I said before, it's a general purpose policy engine. You can use it at different layers of the stack with all of these systems. And that's what we're trying to enforce in this figure. So now let's look at a specific use case around Kubernetes Admission Control. So what is an Admission Controller? An Admission Controller is a piece of code that intercepts requests to the Kubernetes API server before that object is persisted into HCD. So you can leverage Admission Control to increase the security profile of your Kubernetes cluster. And you can enforce policies like images can only be pulled from internal registries, like the ones we saw before. You want your containers to have CPU and memory requests and limits. So you can have these fine-grained policies which can be enforced using Admission Control. And the way this works is whenever like an event happens, say you did a creation of a pod, a post request gets sent to OPA with an input which is the entire pod manifest which is this deeply nested structure that you see here. And so OPA is supposed to evaluate that query by taking into account this deeply nested structure as well as any policies and data it may have access to, form a decision and send it back for enforcement. So the theme is again common here. You are trying to decouple the policy enforcement from the policy decision making. So let's see Admission Control, how OPA can be deployed as an Admission Controller and used as an Admission Controller. The policy we are trying to enforce in English says that two ingresses in different namespaces must not have the same host name. Now you guys may know that an ingress object is something that controls external access to your services in the cluster. And so we want to take this policy and we want to implement it with OPA as an Admission Controller. To set up this demo, we are going to take a demo application and deploy it in the prod namespace. This demo application is going to create an ingress resource which says something like any request coming from huli.com should be forwarded to the demo app in the prod namespace. Then we will deploy Alice's version of the demo app in her dev namespace. And even this demo app in the dev namespace is creating an ingress object which says something like route all incoming traffic to the test app in the dev namespace. So you can kind of imagine the unintended consequences of deploying Alice's app in your cluster. Because you can now have a scenario wherein live production traffic gets sent to a test or development app and worse, if some malicious user is in control of this app, he or she now has access to the entire life sensitive data which they can use in any way that they want to. So this is clearly a disaster situation which you need to avoid at all costs. So let's see how we can do that. So to make this demo a bit interactive so that you guys can go and try this later, we are going to use a tool called CataCoda wherein you can go through this demo step-by-step yourself after the talk. So we are gonna start the demo. And so what we are gonna do is we are going to, we are going to create a prod namespace and deploy the demo app in that namespace. Okay, I think I need to refresh it. I'm kind of refreshing the environment. In the meantime, this gets created. Any questions so far that I can answer? So OPPA has this feature called bundles and it can periodically download policies and data. You just point it to your external HTTP servers and it will periodically download policies and data as a tarball and then load it and use that for policy evaluation. So that's one way to get from external sources. Any other question in the meantime? Right. So the enforcement happens at your service. So for example, you've written an API server, right? And you get a request saying, okay, show me the pets endpoint, show me all the pets in your clinic, right? So you can ask OPPA, should I allow this or not? OPPA just tells you, okay, stop this, block this. Then you can just return like a four or three or something like that to deny that. So you do the enforcement, but you don't need to work on the decision making itself. So if you had like a really complicated input given to you in the admission control use case, instead of you figuring out all these steps, you just delegate it to OPPA. So let's see if this scenario has been created. Okay. So we are going to create, deploy the demo app in a broad namespace. So we created the namespace, we deployed the app. We just have to wait for all the containers to be created, which could take a few minutes or it could happen sooner, depending it's a live demo. Okay, so in the meantime, let's take one more, any more questions here on anything around OPPA. Yeah, go ahead. So all the policies and data are all stored in memory for evaluation, but you can save your policies in GitHub. For example, you can version control those policies, you can unit test those policies, and then you can feed those policies to some kind of a pipeline to OPPA itself. But then by evaluation, OPPA stores everything in memory. So it depends how you do it. For example, in Kubernetes, you can define policies as config maps and OPPA will pick and then you can just volume mount them inside the OPPA container or use bundles if you want to get them from external sources. So multiple options for you to try out. Okay, so while this thing comes up, which we have to wait for, unfortunately, can I answer any more questions? Okay, just let's just wait for this to come up. So something I really encourage you guys to do is try to use the Rego Playground. It's an online tool which you can try your Rego policies with and you can experiment with Rego using that. So that we found that to be really useful to try out Rego and to just start learning the Rego language. So I would definitely recommend that. And okay, this is taking time. It should be up in like few minutes in few seconds now, hopefully. So what we are doing just to recap is we have created a broad namespace and we are trying to deploy a demo app in this namespace. So we just have one more and that's it. Okay, we're done here. So we've deployed this app, all the pods are up and so now let's go to our app, oh man. All right, so this demo is definitely live. So, okay. So we've now hit our demo app which is basically showing Bob here and his employee details. So the next step is to deploy Alice's version of the demo app in her own dev namespace. So we created the namespace, we deploy Alice's version of the demo app and now we wait for all the pods to come up which they are. And so now if you refresh the page, let's see what happens. So this is not Bob, which means something really bad has happened here and which needs to be stopped at any point from happening in the future. So we kind of have an idea why this happened because Alice's app created an ingress resource which kind of has redirected traffic to this demo app. And so the question now is how are we gonna stop this disaster from happening ever again in the future? And so what we have, we have OPA to the rescue. We are going to deploy OPA as an admission controller and we are going to load a policy inside of OPA which is going to prevent two ingresses in different namespaces from having the same hostname. And so the policy got loaded successfully inside of OPA and so now if I redeploy Alice's app the admission control should kick in and it should prevent ingress resource from being created. There you go. So OPA prevented that ingress resource from being created. And so now if you refresh everything is back to normal. OPA has saved the world. So you guys can go home easy today and sleep peacefully knowing that OPA is deployed as an admission controller somewhere out there in this universe. And so that's how you can take OPA as an admission controller to enforce fine-grain policies like these and prevent the ingresses from being created in different namespaces having the same hostname. So this was our containerized world and how OPA can enforce fine-grain authorization in that world by being a general purpose policy engine which decouples policy enforcement from decision-making. If you want to know more about OPA, check out the website. Join us on Slack for any questions or use cases that you may have and check out the project on GitHub. And if you like the project, please start the project. Again, thank you so much for attending. I really appreciate it. And if you have any questions, I'm here. Thank you.