 OK. Good afternoon, everyone. I am Li Mi Wang. I am a tech leader in Istio's security team at Google. And this is Torin. OK. And I'm Torin Sandel. I work for a startup called Stira. I'm the tech lead on the Open Policy Agent project. And I love talking about policy and rules at 4.30 on Friday afternoon. So take it away, Li Min. So today, Torin and I are going to talk about Istio's mixer, policy enforcement with custom adapters. This talk has two parts. In the first part, I am going to give an introduction of Istio and the policies in Istio. And I'm going to talk about how to enforce your custom policy in Istio through mixer's adapt model. In the second part, Torin is going to talk about how this model is used to integrate Open Policy Agent to Istio. And he's going to give a live demo of it. OK. So what is Istio? I'm trying to keep it brief, because we already had a lot of excellent talk on Istio. So Istio is an open platform to connect, manage, and secure microservices. You can find more information on istio.io and github.com slash istio. Istio service mesh can be split into data plane and the control plane. Data plane is composed of a number of annual proxies that are deployed as side cars. And they are mediating and control all the traffic between services. Control plane has three components, pilot, mixer, and Istio-Auth. Pilot is responsible for managing and configuring the envoy proxies to route traffic. Mixer is responsible for enforcing access control policies and usage policies and collecting telemetry data from envoy proxies. Istio-Auth provides service-to-service multi-teriors authentication. And it also provides a built-in identity and a credential management. Istio is a policy-driven system. What are the policies? Policies are the rules that control how the system behave. Istio supports many different kinds of policies. For example, route rules allow you to specify load balancing policy, traffic splitting rule, request timeout, retries, and fault injection. Quota policy provides the fairness between service consumers when they are contending for limited resources. Monitoring policy allows you to specify how the metrics are collected and how the logging and tracing are done. The existing security policy allows you to enable service-to-service multi-teriors authentication for the service mesh. And it also enforces the simple authorization rules like denier request if a certain condition is met, or whitelist or blacklist the service consumers. And we provide an expression language for you to define conditions. We are continuously adding more policies in Istio. Take security policy as an example. We are adding authentication policy, authorization policy, and auditing policy, which we call AAA policies. The upcoming authentication policy will allow you to enable or disable multi-teriors for each service and configure end-user authentication. On authorization side, we are adding row-based access control, which provides the namespace-level, service-level, and method-level access control for services in Istio mesh. I'm going to show an example of how RPEC policy looks like in the next slide. And we are also integrating with Open Policy Agent to address more complicated authorization use cases, which Tori is going to demo next. And in the meanwhile, we are also working on improving the expression language to provide a richer semantics. The auditing policy will allow you to specify when to audit and what to audit. Here is an example of how RPEC policy looks like. On the left side, I define a service-row object. It's called a review product viewer. It allows you to read a review service and read a product service on the path slash books slash books slash star. On the right side, I define a row-binding object, service-row-binding object. It assigns the review product viewer row to a given service account. You can specify other identities, like a user or some joint claims or other attributes to specify the subjects. You can find more information on Istio RPEC design doc, or you can talk to me afterwards if you're interested in RPEC. Now we have a look at all the policies Istio provides. What if you want to support your own policy? Well, it is pretty easy to do that through mixer. Mixer is the central point for policy evaluation, and it is designed for extensibility. Mixer exposes two APIs, check and report. Check allows you to do precondition check, quota check, and report allows you to telemetry reporting, such as logs and metrics. Mixer achieves high extensibility by having a general-purpose plugin model, and the plugins are called adapters. In this picture, I show some example adapters that Mixer supports today. Mixer is an attribute processing and routing machine. The attributes are the pieces of metadata that describe the environment and the traffic. For example, request.pass, source.ip, source.user, destination.service, these are all attributes. Request arrived at Mixer with a set of attributes. Mixer processes these attributes and maps them to adapt the input. We call them instances. Mixer invokes the adapters based on the configuration and passes this input to the adapters. Mixer supports two types of adapters. The standalone adapter, run in Mixer process, they do not have a backend. For example, the main quota adapter and the open policy agent adapter that Tori is going to demo next are standalone adapters. The other type of adapters that interface to a backend system. For example, the stack driver adapter belong to such category. In order to provide a custom adapter, you need to determine several things for your adapter. First, you need to determine your adapter type, whether it's doing a precondition check or doing quota check or telemetry reporting. Second, you need to determine the runtime input for your adapter. In Mixer, we use templates to define the schema for mapping attributes to adapt the input. You can apply multiple templates for a single adapter. You can either use the built-in templates or provide your custom templates. Next, you need to determine how to configure your adapter. What are the parameters your adapter takes? A configured instance of an adapter is called a handler. And lastly, you need to determine the business logic for your adapter to handle the runtime input. You can find more information on adapter developers guide, which this GitHub link points to. Okay, now let's quickly walk through the steps of building a custom adapter using a very simple example. Suppose we need to build an adapter to verify a string is present in a list. So the adapter type is a check. The adapter input is defined by the built-in list entry template. We can take a quick look of the list entry template. It is very simple, as you can see. It only has one value, one stream value, which specifies the entry to verify in the list. The adapter configuration is a list of strings. And at runtime, the adapter looks up the value in a list of strings and return the check result. Okay, so the first step is to write the basic adapter scaling encoder. You can copy it from our online tutorial or any built-in adapters. I highlighted the part that you need to provide the adapter information, including the name of the adapter, the description of the adapter, and the templates the adapter supports. And you can also provide the default configuration for the adapter. In the second step, you need to write the adapter configuration. These are the parameters for the adapter. In this case, it is a list of strings. And in the third step, you need to validate the adapter configuration. In our case, we simply make sure that the list is not empty. And in the last step, you need to write the runtime logic for your adapter. So in our case, we simply check that if the stream value is in the list and return the check result. Okay, now you have built your custom adapter. Let's configure a policy using this adapter. So we want to check that the source version is in a specified version's list. So first you need to create an instance of list entry template called a source version. And the value is mapped from the attribute source.labels.verging. Then you create a handler of the list checker adapter. It's called a version checker. And you provide the parameter which is the list of versions, v1, v2. And then you create a check version policy, which simply passes the source version instance to a version checker handler. And you can also specify the condition when this policy applies. So in this case, the check version policy applies to the ratings application. And now you can apply the policy and it still will enforce the policy at runtime. Okay, now I'm going to hand over this presentation to Torrin to talk about how policy agencies integrate your tools. Okay, so thanks, Li-Man. Li-Man, give a great overview of how you can take mixer and extend it to enforce your own custom policies. And the other thing that we wanted to do in this talk, though, is sort of highlight this ecosystem of integrations that are being built up around Istio. And so to do that, what we thought we would do is show how the open policy agent project has been integrated into Istio and give you guys a sense of what you can do with that. Okay, so I'm going to give everybody a quick overview of what the open policy agent is, how we built the adapter, and then show how you actually use it and how it works. So the open policy agent is an open source general purpose policy engine. And what that means is that you can use it basically in any system, in any layer of the stack to offload policy decisions. And so one of the obvious applications for OPA is API authorization because pretty much every single organization has to be able to control who can do what across their microservice APIs. So OPA, you can use it for things like Kubernetes and Cloud Foundry and Docker and so on, but here we're going to be focusing on Istio and this new integration that's been built. So the core of OPA, though, is this declarative language that lets you codify your policies. And when it gives you these policy languages, let you write rules and answer questions like, is X allowed to call Y on Z? Now when you're actually taking OPA and integrating it or using it, you can take it as a library and embed it into your applications or your services or you can run it next to your service as a sidecar or you can run it on a host and have all your services on that host call into it and ask for policy decisions. Now it's designed to be as lightweight as possible and so we don't have any external dependencies at runtime and so all the policies and the data and so on that it uses to evaluate are all stored in memory. So it doesn't introduce any dependencies onto an external database or an external service or anything like that when you take it and you deploy it. So it's very easy to get up and running and use it. And so the whole goal with the project is to give the community this reusable building block that people can leverage to enforce policies up and down the stack using a unified holistic approach with a language that is suitable for all these different kinds of things. So what we did and what the team at Istio did was take OPA and they integrated into Mixer as an adapter, as a check adapter. And so the way this works is that when Envoy receives incoming traffic, it executes this check RPC call against Mixer. And when it does that, it provides a bunch of attributes that describe the request. So things like the method and the path and the headers and so on. And then when that RPC request arrives at Mixer, Mixer looks at the adapter to run and it dispatches it to the adapter, in this case OPA, which makes a policy decision. So it takes all that input, all those attributes and it decides whether or not that request should be allowed or denied. And then that decision is passed back to Mixer and ultimately back down to Envoy where the request can either be accepted and forwarded or it can be dropped or rejected. Now, when you configure OPA, as an operator, you tell it what inputs you want to provide to the adapter. And so you can basically map any of the Istio attributes, anything in the Istio vocabulary into these collections, these subject and action collections. And so it's very flexible and you as an operator get to decide what data you pass off to the policy engine. Now OPA itself is actually embedded into Mixer as a library, so it's totally standalone and it doesn't have any external dependencies, which means it's nice and easy to deploy. Okay, so when you actually have to configure OPA, the first thing you have to do is create a rule. And so this is an Istio concept and Mixer concept. And so what these rules do is they tell you, or they tell Mixer when to send requests off to adapters. And so in this case, we've just created a single rule that says send all the requests to the OPA handler or OPA adapter. And when you do that, supply the authorization instance data. So then we have to define what the authorization instance data is. And so in this case, we specify values for the subject and action collections and we're mapping Istio attributes into those collections. And so here we've decided to include the user ID and the target namespace, for example, and the target service and the path from the request and the method from the request and so on. And so all of this data is actually loaded into Mixer through the Istio config store, which is, it can be Kubernetes or it can be other backends as well. And so we'll see how this works in a minute. Okay, so then the last thing you have to do after you've configured, you know, when to send requests to adapters and then what to send to adapters, you need to describe what to do when the adapter receives traffic. And so that's what the handler configuration is for. So the handler configuration is always gonna be specific to the handler because it's, in this case, it's saying, okay, first of all, the check method to run inside the policy is authorization.allow. And then we actually take the OPA policy and we embed it directly into the configuration here, just as a string. And so this is just a really simple policy that says, by default, requests should be denied, but if they're performing a read operation, then you can allow them. Okay. All right, so let's see how this actually works. Okay, so what I have here right now is the Istio control plane deployed on top of my laptop or on top of Kubernetes running on top of Minikube on top of my laptop. And I've got this very exciting application called Bookinfo deployed on top of Istio. And that's because Lehman and I are running a bookstore. And then we have our authorization rule here. And so this is just saying, when incoming requests are received by Mixer, they should be forwarded all the time to the OPA handler using the authorization instance data. So then we can take a look at that instance data. And so here we've configured it so that it sends in the source and destination namespace and services, the headers from the request, the method from the request, and the path. And then finally, we've got the OPA handler configured. And right now, this is the same kind of configuration you saw before, but in this case, it's just allowing all the traffic by default. Okay, so I've got the product page here. And great, it loaded. That's exciting. Okay, so what I have right now is the policy on the left and the application, or sorry, the application on the left and then the policy on the right. And I have a script that's watching the policies on my machine and then reloading them in Istio whenever they change. And so right now, we just have a simple policy here that says that by default, requests should be denied. However, if this other service graph policy allows the request, then you should go ahead and allow it. So let's take a look at the service graph policy. So the service graph policy defines the allowed connectivity for applications running on top of Istio right now. And basically these allow rules below here interpret that data structure to decide whether the incoming service is allowed to talk to the destination service. Now, the thing is that right now, the allow rule is defaulting to true, which is probably not good from a best practices point of view. So let's change that to false. And we can see that the policy reloaded hopefully. And now if I refresh the page, it still works, but we don't see the product reviews anymore. And so the reason for that is that the product page is not allowed to talk to the review service. So let's change that. And then once the policy reloads, the reviews show up, which is great. And so this just shows how you can write these high level policies that are very dynamic and can be reloaded on the fly without requiring you to write a bunch of go code and then do a whole software release, especially after upgrade mixer or anything like that. This is all based on configuration. Hopefully that comes back. Okay, great, it's back. Okay, so this is like a relatively simple policy. This is something that you can enforce with Istio without OPA. So let's look at something a little bit more interesting. So I have this organization chart policy and this is an org chart for a bookstore. And this is a weird bookstore because they don't want their people that work on reviews and shelving to be able to see book reviews. And so right now we have this org chart where Alice is a manager and then Bob is a reviewer and he also does some shelving and then Ken is only doing shelving. It's very boring for Ken. And so right now by default, this policy is going to deny all incoming traffic. However, if you're a manager and you're accessing, if you're a manager, you'll be allowed to see everything. But if you're just on shelving, if you're not a manager, then you'll be denied if you're trying to access these sensitive book reviews. Okay, so in order to make that actually take effect, I need to hook it up to the top level here. So I'm gonna say now, basically, deny by default. However, if the service graph policy allows it and the organization chart policy allows it, then go ahead and allow the request. And so if I refresh the page, it still works, but we can't see the reviews because we're not signed in. We're an anonymous user right now. So if we try to sign in as Bob, he's not allowed to see them. But if we sign in as Alice, who is Bob's, or rather who's in management, and the performance reviews show up. And so this shows how you can enforce different kinds of policies with OPA that aren't necessarily coupled to roll the waste access control or just simple expressions. This organization chart data is hardcoded into the policy right now, but there are other ways to get data and so on into OPA that are more efficient. And so this is just here because it allows us to easily change during the demo. Okay, and so then the last thing I wanna show is how you can enforce policies that take into account some kind of context. And so the bookstore has developed a strange idea. They wanna allow reviewers to look at book reviews after 4 p.m. for some reason. And so we can add another policy here. And what it's gonna do is check whether or not the incoming user is on the reviewer team. And then it's gonna check whether the current date and time is between 4 p.m. and midnight. And so because this policy is part of the organization chart package, that answer gets composed with the previous one about sensitive APIs. And so now if I try to sign in as Bob again, we should be able to see the reviews. Okay, so that worked, but if I try to sign in as Ken, the poor guy doing book shelving, he's still unable to see those reviews. So that's the demo. Switch back to the slides. So OPA, it gives everybody this reusable building block that you can use to enforce all kinds of different policies across the stack, but it's particularly useful for enforcing authorization decisions in your microservices. And this is super important because it's not enough to just authenticate users, you need to be able to control what those users can do. Istio is great because it has this fantastic plugin framework that allows you to plug in things like OPA as well as other adapters for authorization and quota and telemetry and so on. And the plugin framework makes it pretty easy to get up and running with this and the documentation's great. So I encourage everybody to check that out. And so finally, if you're interested in security, you're interested in Istio, please come and join the security SIG and check out the projects on GitHub, star them, and yeah, so thank you very much. So we're happy to take questions, of course. Okay, we'll just go front to back, I guess, so in the blue. So is the question about how do you prevent people from changing policy when they're not supposed to? Oh, okay, no, it's about authenticating users and getting that data into OPA. Okay, so for the first question about how you get external data into OPA, so it provides APIs that allow you to push data in, okay? So you can load arbitrary JSON data into OPA and then write policy over it. So if you can get your data out of LDAP or Workday or whatever that describes your organization, you can load that into OPA. The other thing you can do is stick like an authenticating proxy in front of OPA that goes and gets that data and when it does the authentication check and then passes that in. Beyond that, it's sort of up to you to design that part of your system. Yeah, so in the Istio case, the identities are identified using the attributes. So Envoy is going to process the request and get all the attributes. And you can have the combination, any combination of the attributes to identify identity, yeah. And then so then for the second part of your question, so OPA gives you a test framework to write unit tests for your policies in and then it gives you a test runner so you can like execute all of unit tests in your policy code base, if you will. And then yeah, we're looking to improve that to give you things like coverage and profiling and so on. Yeah, okay, next. So the question is how do you log decisions that have been made inside of Istio or OPA? So OPA has a framework that allows you to plug in and figure out when a decision's been made, like the top level decision. So if you're integrating OPA, you can get that and you can send it out however you want. But I think that Li-Man can probably answer how Istio helps you there. Yeah, I think the logging part, we have some logging adapters like the Stackdriver or other StatsD logging adapters. And we are looking to also into providing some auditing policies so that you can audit all the authorization, all the authoritative requests you have done in the past, yeah. Okay, Grace, whatever. Okay, so in the demo, the username is passed in a very secure way through the cookies in the header. And then the policy like parses the cook, I didn't show the policy that parses the cookies, but there's a little helper that's parsing the username out of the headers. But then I think that Istio's got... Yeah, right now Istio is working on, Istio team is working on enabling end user authentication. Yeah, but it's not at this stage yet. Not ready yet. The policies are actually stored in the Istio Convict Store. Actually, currently it's the API server. And the policy can be either enforced on Mixer or on Envoy. So if it's enforced on Mixer, then the policies are pulled by the Mixer. If it's enforced on Envoy, then pilot is going to push all the policies to Envoy policies. Pilot is going to get the configuration from the Istio Convict Store directly. It's not going through Mixer. Yeah, and Opus designed to be as lightweight as possible, so you could run it at the edge, like next to Envoy or something like that. It's being embedded as a library inside of Mixer, but Mixer does a whole bunch of caching, and so does the Envoy filter for Mixer. So, maybe Lin can talk about that a bit more. Yeah, so on Envoy proxy, we have a lot of caching, and the same as on Mixer side. So, yeah, so OPA can be embedded either to a Mixer or on the Envoy side. In this case, we integrated with Mixer because Mixer is more extensible. It's actually designed for extensibility. So, it's easier to integrate any other policy engine to Mixer. Sorry. For Java. So, OPA is written in Go, and you can embed it into your Go services. If you're using Java or any other language, you can use it as a sidecar, and then it has a REST API that you can use to ask policy questions. Yeah, Istio Mixer is written in Go, actually. And the pilot is written in Go as well. Yeah, so the question is whether the decision that OPA makes can be cached. So, I think it's cached in two places. So, it's cached at Envoy in the data plane. And then inside of Mixer, there's a more sophisticated cache strategy where it caches decisions for each of the adapters, basically, that have run. And so, it's got very fine-grained caching in Mixer. So, there's two levels. Yeah. Yeah. Yeah. A question? Probably a better question for Linan. I think on Envoy side, we are caching the request going out, and basically the request going out and the check result. So, Envoy calls Mixer check and the report APIs. So, whatever the check request sending out and the check result, and also the report sending out, it's all being cached. And on the Mixer side, I think in the OPA case, we can cache the authorization results like what are the authorization request and what are the result? And because Mixer is a centralized component, so it can have a centralized cache, and Envoy is caching for the local service, whatever for this service, the request sending out for this service. Mixer is deployed as a single pound. Or what does that mean? Oh, no, no, no. Mixer is a service, yeah. Mixer is, yeah. It's a standalone service. It's... Yeah, DAG is actually the, yeah, technically the Enmixer team. Maybe like one more question. Which API are you talking about? The policies? The authorization, configuration, the rules. Okay, so are you talking about the policies I showed these policies? Is that what they're talking about? Yeah. Yeah, so Rano is 0.3, as Chenliang said. And we are actually going to have monthly release going forward. And yeah, next year in June it will be 1.0. That's it, yeah. That's the plan. Otherwise there's a problem with time. Thank you. Okay, thank you very much. Thank you.