 Now, welcome to Cloud Native Live today for Wednesday, March 6th. I'm Taylor Thomas and I'll be the host today. At Cloud Native Live, we take the opportunity to bring in multiple people and technologies from the Cloud Native space and give them the chance to show how Cloud Native works and how you can use it in your setups and in your problem solving that you have to do. As a normal reminder here, this is a Cloud Native or a CNCF sponsored event and as such it is governed by the CNCF code of conduct which boils down to be nice and respectful people. So please do not put anything in the comments or in any other form that would be disrespectful to other people. So with that said, I'm going to go ahead and hand things off to Alex who is from Serbas and he's going to talk a lot about a bunch of really interesting things around authorization and authentication and all those kind of things we hit. So Alex, I'll let you go ahead and introduce yourself and go ahead and share everything. Great, thanks Taylor. Hey everyone, I'm Alex Levier. I'm one of the founders of the company behind the open source project Serbas and we are in the authorization space which I will go into much more detail on but today we're really going to be talking about the nitty gritty of what it takes to actually implement a scalable authorization solution inside of your environment via Cloud Native or otherwise for how you can define roles and permissions actually enforce those and all your different microservices. So just to kick it off, just to make sure we're all on the same page. So unfortunately, authentication and authorization are two words that sound extremely similar, especially when they're reduced down to orth and an orth C as you may have seen. And so just to make sure we're aligned, authentication in the side of the system is the bit you're doing inside of your application. A request comes in, you bounce a user off to go and authenticate where they have to present some sort of credential, username, password, a single sign-on type, type, workflow, a login with Google, a login with GitHub that those kind of flows are all used to. And then you get back some sort of verified credential. You now know who that user is and that flows sometimes very much coupled as well with kind of your user directory information. So this person will have a role or a group or a scope and these kind of typical ideas around identity and ultimately kind of the active management piece of thing. Authorization is kind of the next step. So once you know who someone is, you know what group they belong to, you know what team they have, know what role they have, these kind of information, is how do you actually then go down to your application level and actually authorize a particular request? So can this user with this role call this particular method or call this particular API endpoint? And just to be clear, we're talking about the application level here. So you probably all used to are back inside of your Kubernetes cluster which controls access to resources and namespace and those kind of things. So we're now talking about the next level up. So actually the applications you build and deploy in those clusters or in all your different environments, they also need a level of kind of permissioning. So you're building, if you look at a typical service user, you're building an application, it's made up a number of microservices, you're running it in Kubernetes, you've got some sort of gateway in front of it, you've got some end user application via a web app or mobile app or something that's hitting the API, making requests. And now in the application inside of your web of microservices, via in a service mesh or not, you need to actually decide where their particular requests should be allowed or should be authorized or not. And where we're going to be looking at today is how to kind of scalably manage that in an environment, particularly when you've got a disparate web of microservices and those services can be in different languages and frameworks and binaries and it's a very kind of heterogeneous environment where you need to kind of scalably go and actually implement and define this logic across the application architecture. So to keep things off, don't worry, I'm going to go into code now, I'm not going to show any more content. I have my machine here, a small Kubernetes cluster running, using Minikube if you're interested. And basically the architecture of this is we have the end users, they make requests to our cluster, inside of our cluster we're running Istio, so we've got an Envoy proxy running. And behind that service is we have, behind that, sorry, that gateway, we have three services. We have a report service, we have an expensive service and a user service. And what is kind of typical of kind of transformation projects or kind of evolving application architectures is each of these services can actually be in different languages. So you might have one in Python, one in JavaScript, one in Go, one in Ruby, you might have some .NET thing, et cetera, et cetera. And because we're now in a nice world of containers and Kubernetes to orchestrate that, it's very easy to actually spin up these services and actually have them stand alone and kind of manage everything themselves. And it's kind of irrelevant what language they're all written in, if they all just expose a REST API, a GWC API, for example. And that's kind of exactly what we've got here. So just to give you a kind of a quick idea, if you're going to look at our Python service, each of these services basically exposes a REST API. This one has, each of the services in this demo has basically one endpoint where we can go and request some resource. So basically, this one is a typical fast API application. We've got some data, you make a request, we then go and look up that particular request by ID from our dummy database and then return that as JSON. So if I actually go and hit kind of that endpoint in my dummy application, here I've actually got reports and I'm getting a response back. So this request is coming into my cluster, Istio is managing where to route that request through. It's ultimately hitting a pod that's running, in this case, my Python application and returning that data. And then the same thing for my expenses track application, except this one is in Node. So I have an express application, has some endpoint where you give it some ID. It goes and queries the database for a record by that ID and either returns a four or four or returns the actual expense data. So here's, I can now finally enough do that same call and run to be get that kind of response back. And the third one we have is our user service, which is in this case in Go. We have our kind of like dummy database here, which is just a map for now. And then here we're using Gorilla as the HTTP kind of server. We've defined some endpoints and again, we have this endpoint where you give it an ID and in this case, it's like our user database. And this is kind of a very common service. You might have an application where you want all your other services to go and fetch data about your users and look up a user profile, for example, as a common service that your other services call. That's exactly what we've got set up here. So in this case, we're going query out our database by that ID and return that record back. So at the moment, these services have no kind of authorization in them. So we are kind of like using dummy authentication where we're just passing in this header of a user ID. In reality, you'd want to actually have this as a job token or some sort of actually verified credential in this dummy application, which is passing as a header. And at the moment, I can go and actually look up different records. So here I'm looking at expenses. I'm making this request as an admin and I can get the response back for this particular record here that's owned by Sally. If I go and look at it again, I've got an expense ID number two. This is again querying from our node service. And this one's actually owned by Martin. And I'm actually now going to make this request as a different user. And here I can actually get a result back for a record that I don't own. And this is where typically you'd start writing some authorization kind of logic. So if we're going to kind of define what's our basic authorization requirements. Let's go and actually go and implement some basic checks and applications. So we have three different resource types and two different user roles in this setup. So we have admin and we have a user. So your identity provider ultimately will hold the role that user has in your system, are they an admin or are they a user? And then we basically need to apply this matrix of permissions to decide whether an action should be allowed or denied. So in our expenses service, we have some actions, create, read, update, delete. We're just going to focus on read from this example. And we're saying, okay, to read a record, to read a record, if you're an app, if you have the role of admin, should be allowed. But if you have the role of user, you're only allowed to read that record if you own that record, for example. And we have the same kind of logic for our reports as well. So as you're going to implement this, let's go and do kind of the simple check inside of our application. So we have our request, request comes in. We have our middleware in here that just kind of does our authentication. So we go and request the user's profile, which basically gives us back that user ID that could be extracted from your JW2, for example. And now we want to do some permission checks. So where you may sometimes feel like start is like, okay, well, let's go and define some check, which says, okay, allowed by default should be false. And now let's go and implement that logic. So in our request, we have some middleware, which is doing this authentication. And we're going to go and get the principle. So who's made the request? And we're going to go and actually write this logic, which says, okay, there's an array called roles. And we're going to see whether the roles of that principle contain admin. And if that user an admin, our business rules said that that should be allowed. It's like, great, cool, true. So our second rule says, okay, if the user is an, if the request or the principle in the request is a user, they should only be allowed if they are the owner of the resource. So this is where an example where you kind of migrate from role-based access control to attribute-based access control, our back to A-back. So now in this case, okay, we need to do the same check as before. Let's go and check the roles. Let's see if we make sure this person is a, this time user. But we also want to check that rule that says, is this person the owner of the resource? So, now we have to do another check in here. So now when this person is a user, we want to go and check whether the ID of the person making the request, so we call it the principle ID, is equal to the owner of this expense resource that we've already created out of the database. And if they are, the action should be allowed. So now this is where we've done a check for if our user is an admin, if the person is a user, and then what we want to say is, okay, we don't want to return any results if the action is not allowed. So in this case, we're just going to do something very basic and we'll say, let's go and return an error message saying like unauthorized and we can set the status as well to Aga 403. And you would then go and basically go and, sorry, 401.403, basically go and set our response and kind of return that and that way on our APIs is ultimately protected based on that business role we have where we're checking the roles that the person makes as a request for it. So that's a node, we're happy, we've got logic implemented, we've hard coded all this and we are returning a relevant error. And this would be our kind of first use case of setting these basic rules. So now we also want to have the same business logic for our report service. So I would then have to now go into my Python application, go to my request handler and basically re-implement the same logic to support this particular use case. So in the world of Python, we are going to go and say, okay, we've got the request, we've got the request. We've kind of got, in this case, the report from the database. Now we need to go and do, we basically re-implement the same logic. So we're going to create our boolean again. So this time we're going to go, is admin in the principal roles? So it's doing the same logic as in our node application. So we're now saying if you're an admin, great. Now let's do the same logic if you're just a user. So now this time we're saying you're a user in the roles. But we also need to do that additional check we said where we want to check the owner. So now we need to do, okay, if the report owner ID attribute is equal to the principal ID, then the action should be allowed. And then if it's not allowed, it's the exact same kind of form as before. In this case, I'm just going to go and copy my snippet, save all the typing. We then go and return, in this case, we return an exception. So now we say, okay, the logical check says the action should be allowed. So let's go and return some sort of error. So now we've got our logic set up, our business logic set up as it should do in our Python application. And then, okay, now we just want to do the same thing in our Go application. And I'll spare you kind of the copy and pasting, but we end up basically implementing this logic. So we sell these variables, we go and, we then go and fetch our logic. And then if the action is not allowed, then we go and return some sort of error. So now we're going to successfully implement our logic based on business requirements, and our API is now up to date and serving and our application is sort of deployed and we can go and now make kind of requests against these different endpoints. And finally enough, if I now go and make a request as before, where I'm pretending to be user Sally trying to request a resource owned by Martin, I'm going to go and get that 401 on authorized response with some sort of kind of error message returned. So it's not great, it's amazing, we've kind of hit our requirements and we can go and live happy lives and never have to think about it again. Reality, as you build applications, as you evolve application services and you're asking your business requirements change, what commonly, what happened is like, okay, we now want to introduce a more fine-grained permissioning model. So now we want to go and add this concept of like a manager role. So we need a more fine-grained role. We can no longer just divide up people between admin and users. We often now want to have this kind of higher, we want to have this more granular role of like a manager. So now for a manager, our logic now says, okay, if the user's an admin, should always be allowed, user has the user role. They should only be allowed if they are the owner for reading. But if they're a manager, we say, okay, they don't have to be the owner, but they have to be able to access the results that's in the same region that they are a manager of. So all of our expenses and all of our reports in our kind of database has a field called region, which dictates which region that particular results belongs to and each user that we have also has a region associated and we can actually go and look at those user roles here. So here are different users. We have an admin, they have the role of admin and user. They have attributes name and department of region. Sally here has the role of user, again, named department region. And then our resources also have a similar model where we have a region associated with it. So I've now kind of got my new requirements. I need now to go back into all my application code. Again, three different services, three different languages. I may know enough JavaScript to go and implement the node one. I might know just enough Python to go and hat my way through the Python limitation and I'm just going to be blind guessing for go because that's just not my day-to-day job or my first language, I'd say. So we basically, this is going to take time. You're going to have to do more testing. You're going to have to go and redeploy the application services of that logic, et cetera. And hopefully you can now kind of get an idea of what pain can might be involved is as these requirements keep changing that you have a new feature, you have a new product, you have a new user role, you want to enable more access and more fine-grained access, you're going to have to go and keep touching this application code over and over and over. So there is a better approach here, which is implementing what we call decoupled authorization in kind of the term that's used for these days. So I still want to have my single entry point. So my user is authenticated, a request comes in, hits my service mesh, and that request then gets rooted through our application. But now rather than having each application hard code all this business logic, that's actually decoupled that logic out into a standalone service. So this, in a kind of formal specification term, is referred to as a policy decision point. And a policy decision point takes a request of, here's this user or principal trying to do this particular action on this particular resource. It evaluates that request against some policy and then simply returns back the application and allow it to make a decision. So let's go and do kind of exactly that. So here I have my service policies. This is, again, just YAML definitions. Hopefully, we were talking CNCF Kubernetes world here. Everyone's happy with, well, OK. Everyone knows YAML. They're saying maybe not everyone's necessarily happy with the YAML. But you're all familiar with it. We've all got tooling. We've got IDEs that give you nice auto-complete, etc, etc. So this is the service policy that's going to sit behind our expense for our expenses system. And we have one for our reports. And we have one for our user service as well. And each of these policies defines the different resource types in our application. And for each of those resource types, we define the different actions. So here we have create, read, update, delete as kind of the ones we've been talking about. And we're going to focus on this kind of read example. And then for each of these actions, we have different rules that define when those actions should be allowed or denied. So for example, here we have a read rule that says, the action should be allowed if the user has a role of user. And then this expression, oh, this condition must also be true. So this replicates that same logic we were doing in our application code, but in a much more agnostic way, in a declarative way, as these policy files rather than having to card card our logic. But we still essentially do the same thing. We're looking at the request, we're looking at the resource, we're looking at the owner ID, and we're just seeing whether that ID is equal to the ID of the person making the request. And for this new manager role, we have this new manager role defined. And then we're now we're doing that check we're talking about where we're checking with the region to the resource is equal to the region of the manager making that particular request. So here we're defining this logic centrally, same thing for the report, same thing for our users. And now we need to actually kind of go and force this. So our first step is actually to deploy these policies into our environment. So I'm using Helm here to deploy into our application. So I have a deployment. I'm deploying a new service into our cluster. And this cluster and this deployment then deploys the service container. And the service then container has into it loaded in those policies. So that's now all deploying. We can see down here that our service container is starting up. It's great. It's all up and running. We could go and actually go and get the logs from that. Looks just for those servers. So that's now from running. The policy is actually already loaded into it. In this case, it's kind of bait the policies into the container itself. We do recommend much more of a kind of a get up style approach so you can actually point servers to load those policies from a GitHub repo or any Git repo. And you can point them to like a storage bucket, a cloud storage bucket, or even to a database. For this example, we're just loading it from disk. Both of these policies are now loaded into our decision point. So this policy decision point is now up and running in our cluster. Now we need to actually go and update all our application services to point to that. So if we start off with node, before we handle this if-else hard coded logic, we can get rid of all this. We will then go and connect up our policy decision point. So here we're using the service SDK. And the way the service SDK works is you basically pull it into your application and you point it to an endpoint. So you've deployed the service container inside your cluster. It's all local. It's all environment environment. You completely add a gap at even source as well. So you can go for the repo if you want to have your own copy of it, et cetera. But we're basically pointing our SDK to where that service is running. And in this case, we're just passing an environment variable, which points to, in this case, servers.demo.cluster.service.local. So it's all running inside the environment. And we're actually using the GRPC SDK in this case. And then in our application code, before where we were doing all this FL style logic, we are going to replace that with a call to the service using SDK. So all this disappears and we replace it with this call. So here we've got our expensive object kind of from a database. We've got our principle, which is the same object we were checking before. And then rather than hardcoding all that FLs ourselves, we then just call out the service SDK. And there's a method called isAllowed. We pass in the principle, we pass in the resource, and we pass in what action must be required. This is now in our code. And what we get back is a simple binary, well, Boolean. Is this action allowed or not? So this method behind the scenes, the SDK is making a request to that service instance inside of the cluster. It's saying, here's my principle, here's my resource, here's my action. That decision point, that service container running alongside the application, is going to make a decision based purely on those inputs. So the service itself is completely stateless. The only thing in there is policy. And this kind of decoupled approach is very scalable because you can then just horizontally scale your decision points. And with the case of service, we recommend running it as a side cast. There's one inside of every pod. So you're not going to do any off node hops, et cetera. But that request goes over principle resource action. What comes back is a Boolean allow or deny. And so our same logic as before, which was simply, if it's not allowed, return an error, if not, returns all sort of return the actual data. That still works. So that's now set in the world of Python. Funnily enough, we do the exact same thing. So I'm going to take out all the logic we hard coded. We've already pulled in the SDK as before. We have this variable. We have this variable. And then we do the same call out. So here we're calling our service SDK. We do the exact same thing where we pass through the principle and the resource we're currently accessing. And then if the response is allowed, then we do that. If the result is not allowed, then we're raising exception. And if it is allowed, then we are going to go and just return kind of that data. And funnily enough, and the exact same thing works in our Go application. So we are going to take out all the logic of it before. I'm going to just go and enable the service SDK, which I will show you what that looks like, but we have this basically create client method where we go and grab the configuration. Again, for the environment variable, we create a new connection to that service decision point. And then in our application code, we then go and do the API call out to go and check the permissions, passing in that principle resource and action. And then what comes back again is that same billion. So that's actually now all up and deployed and running. And our application is authorizing requests as they come through. So if I go and make the same call, we're actually getting that access denied type logic again. But now if I go and pretend to be a manager, for the correct region. So here I've changed my identity, my principle to a manager and our business rules that says, if the manager is from the same region as the resource, then the action should be allowed. That's now implemented. This response now comes back successfully. What if I go back to being a user that say, we're getting the correct access denied message? So what this all now means is all our authorization logic is now abstracted out. So we can actually then go and completely go and evolve all of our authorization logic simply in these policies. So from now on, when we get that new requirement from users or the business or such, where we want to add a new role, tweak the logic, et cetera, I no longer have to touch all my individual application services. I don't have to go and remember how to write JavaScript. I don't have to remember how to go and write path, I don't have to remember how to write go. I can only keep so much of my head in three languages, it's more than enough. I don't have to worry about that. Once the SDK implementation is done, once the service is running inside of the cluster, or the only place where I have to go and touch more authorization logic is inside of these policy files. So I can go and change this logic. I can make that change. And then the container will pick up that logic and all my application codes that are calling out to the service containers or the service instances inside the cluster will start serving based on that new authorization logic with no extra work required. That is the core of authorization and de-coupled authorization at that. In these heterogeneous environments that we seem to be building more and more these days, decoupling all this out into a standalone system and into standalone service and to standalone policy language just opens up way more flexibility and scalability in terms of how you architect and build systems. I'm sure many of you are going through these big still migrations, maybe monoliths into microservices. One of the first things you have to worry about when you start breaking big monoliths down into separate services is how you handle common functionalities like authentication and authorization, logging metrics, all these sort of things. SerbOS is a solution for the authorization piece and it is a completely open source. We are a very proud CNCF member. We built all the tooling, again, all in the open. You can find out more about this at serbOS.dev. Hit us up on github.com slash serbOS. We're all open for contribution and collaboration and hopefully this has given you a bit of a flavor and a bit of an idea of how decoupled authorization works. You can find out a lot more on our website and up on our repos and also documentation. We have things like full CICD integrations you can write unit tests against authorization policy which is something which is quite hard to do if everything's hard coded into your application by abstracting out. It gives you all these nice benefits to test and isolation and such. And with that, I would like to say thank you for your time. Please go and check us out and hit us up on Twitter slash ex. We have a very active Slack community and we always love to speak to you. You can see right on our homepage where they speak to an engineer button you can actually book in and get some time with myself or one of the other team where we can actually help you get up and running ASAP with your application and with your policies. And we can do this actually through an interactive IDE we have available just a place of service up there so you can test things right in the browser down to spin up a whole cluster as well. Awesome, that was great, Alex. So for those on the stream if you have any questions, please feel free to submit those and I'll make sure those are displayed and sent over to Alex here. But I also wanted to ask just a couple of questions that came up that I think might be interesting for a lot of people. So you mentioned about there's different ways of managing policies. So what tools do you have to manage like your different policies? And then like I know you'd mentioned get ops and databases but when you see your users doing most often what do they use to manage those? Cause that's a common problem as these things continue to expand and as you get more complex logic. Yeah, absolutely. So we are big fans of the whole get ops approach as I'm sure many of you are as well. Being able to actually write your policies statically and commit those into a repository which are versionable, auditable, manageable more than the thing else is kind of what we see most. We have a very pluggable storage back end but the get repo obviously is the one that we see the most usage of because of all the usual benefits we get in terms of get ops, et cetera. And I mentioned earlier that kind of we've also released again as part of the open source project the CI tooling as well. So as well as defining your actual policies you then define fixtures for your principles and your resources and then you can define a full test suite of what your expected permission should be and then through your in your existing CI pipelines you just run the Serbos test command ultimately point it to where your policies and tests are and then it will evaluate everything that you've defined and give you kind of the usual test output if things aren't as they should or give you an all clear to then move on with your environment. We're using very much like a branch base or tag based approach as you're probably already using for how you actually deploy your application. It's also what's recommended. So when you deploy a Serbos container if you use the open source project you can actually point it directly to your repo and say, okay, pull in this tag or this branch. We also have Serbos hub which is our managed control plan that sits on top of the open source project which allows you to do much more of a managed CI style environment that coordinates rollouts as well. We're awesome, that's great. We also have a question from YouTube. I'll show that on the screen too. How does this integrate with JWT access tokens? Great question, great question. So Serbos is completely agnostic to any particular authentication provider. I hope you kind of saw in some of those code snippets that basically it's down to the application to pass the identity through where you will send from your application to a particular identity. Now, given that most authentication providers today are basically issuing JSON web tokens, JWTs, Jots, pick your pronunciation of choice. Serbos natively supports those. So when you deploy a container you can also point it to your JSON key set. JWKS, that one again. I don't know what the standardize pronunciation is these days for that but you point it to your key set and then you basically have two options inside of your Serbos decision point. You can say, just validate the token and pass the data into the policy or you can actually set it to verify the token as well. So it will actually using your key set validate the actual token before passing it into the application and you can actually set your Serbos instance either. Reject the request of the token as invalid or just log a warning. And what this now means is any data that's inside of your token be it scopes or any other kind of data you're setting inside of your token from your identity provider can then be used inside of your authorization policy. So checking a user's scope value or maybe checking some custom attribute based on maybe what department that so user belongs to all that information that is generally inside of your IDP system. You can then just pass directly into Serbos without having to do any kind of data manipulation. You can just pass the full token through and have Serbos actually consume that token and make it available. So what that now means inside of your policies is you can then check any fields and such inside of the token and get very specific and reuse your existing and maybe author authentication tooling also authorization mechanisms with authorization with Serbos site. Thank you. One more question from YouTube as well and that's how can you write if or can you write complex policies with code? So one of the kind of earlier design decisions we made with Serbos because we've been working this project for about three years now is actually if you really look at where the requirements for authorization sit it's not, it's not you as the developer it's not you as the implementer it's gonna be with inside of the company at least it's gonna be with like the business mind on the business side of things. So be it the product to manage the product owner we've seen examples where actually it's like the sales team room the supporting kind of dictate and control permissions to users accounts and those sort of things. So what we started with Serbos early on was we didn't want to have it as code in the sense of go JavaScript, et cetera because we wanted something a bit more kind of agnostic and maybe it's a bit more readable to maybe someone that isn't a day in day out dev. So we landed on YAML just because there's a very rich ecosystem of tooling around it there's nice visualization tools we do things like publish the schemas for those so you can light up your IDE to give you full intelligence also complete style things, a feedback as well and what we've actually seen through the adoption of the project over the years is actually we get feedback like, oh, I'm the product manager I'm the C-Sone for the first time I've actually understood what the authorization logic is in my application because all I'm looking at is these policy files I don't have to go and understand Java or Go or in other language to actually really understand how things are implemented because we believe it's better for the person that actually has the holes requirements to really understand what's going on and using YAML, which has a rich ecosystem of tooling around it kind of is a bit of a level effort for everyone and we have plans as part of our commercial offering on top and to make that much easier to use even further but the approach of decoupled in something that's agnostic you know, the schema is very simple those conditions are showing you like checking the owner ID, et cetera are hopefully very readable to you they're using cell common expression language which again is a Google open source project it's used inside of Kubernetes as well and so if you're familiar with that you can get up and running very, very quickly but yeah, the whole philosophy is even the kind of complex policies should be in something that's readable without necessary understanding or knowing a particular programming language Great, thank you So another question from my side after watching all the things you were showing is a question around is it possible to extend the policy engine so can you extend it with some other like either plug-ins or whatever to be able to do something more complex this is kind of related to the code kind of thing but on a different level so is there support for that or is that more of like no, we consider that kind of out of scope Yeah, so we're trying to keep the designer service as simple as possible and not because you know, we're being lazy but because when you really get down to authorization this is in the blocking path of every single request to your application so you need the authorization decisions to be as instantaneous as possible and this is why we actually made the very early decision to make the service policy decision point stateless and so at no point did I mention anything about having to synchronize information about your users or your roles or your resources into some sort of authorization service the only thing that's loaded into those service containers is the actual policy files all the other contexts then provide a request time yeah, the downsides of maybe having system having to synchronize state if we go with that first is you now end up with like eventual consistency cache misses, latency type issues of getting updates about resources or users to your authorization layer that's gonna actually result in people trying to make calls to your API and getting incorrect authorization results because the data isn't being refreshed yet the second thing around this as well is there are what you also don't wanna do is because your policies can change based on your business rules independently of your application code if you were to have your authorization layer kind of going out and fetching state like doing some lookups or kind of plugins that way what you could end up doing is what may seem like a small change in your authorization logic could actually result in unexpected load in other parts of your system because now it's have to go out and fetch other state from maybe a different service or application or database that isn't ready for that load or in ready for that scale and I come from a background of building high throughput load latency talking like 50 billion requests a day type systems and I've made every mistake possible at that kind of scale and one of those was trying to push state or do like arbitrary lookups and things at request time for every single request and that's when you run into all sorts of these issues so going back to authorization being in a blocking path every design should remain so far with services with that in mind to make sure the lookups are as instantaneous as possible that's why we say like run as a side car use GRPC API rather than the HTTP one keeping the state outside and passing in a request time always use the latest data, et cetera keeps everything as performant as possible while still getting all the benefits of this decoupled approach. Okay, thank you. The other question I have around this topic is when we've seen people use this before and I know like from my personal experience working with people implementing these kinds of things there's always a need for audit logs or policy decision logs what kind of support does service have for that and what does it look like to enable or to consume? Absolutely, so I hadn't touched much on kind of the decision point side in this talk but one of the big, big advantages is in this example we have three services we had the one in Python, one in Go, one in Node all doing permission checks ultimately and if each service was doing its own checks itself each service is gonna have its own implementation of how it does logs so you might just log out adjacent line one might just do a clear text one might just be no logging at all even and if you were to then try and understand all the decisions and all the access controls and such that were happening inside of your application in the kind of that model you're then gonna have to go and basically fetch logs from multiple different services and try and get them into a similar form access or such one of the big advantages of all decoupled authorization approaches not just service is that there is a central service where all these decisions are being made so all again all these requests are going through that central service and horizontally scales central service and thus every request A can be captured and every decision made by a service decision point produces an audit log and that audit log is a JSON structure and it's timestamp so at this time this principle with this ID these attributes is trying to do this particular action on this particular resource with attributes, et cetera and the resulting decision was either allow or deny that allow or deny was matched by this particular policy from this particular commit hash and that is a standardized log so regardless of which service is doing permission checks where in your architecture that permission checks being done from that log will always be generated before a decision is returned back to the application now those audit logs you can configure where they're sent so by default service will just log into standard outs and then you'll generally plug in your existing log collection system so if you've got Fluent D or something running inside of your cluster you can pick up those logs and send them anywhere if you're running in like a cloud infrastructure you might have cloud logging or cloud watch and those kind of things that will pick up those logs quite happily and but you can also configure it so you can run into a file and we actually had a big contribution from one of our community members that wrote a Kafka sync for it so actually take those audit logs put them onto a Kafka or point to a Kafka broker and then those are now in a queue which you can version et cetera et cetera but it's a plugable backend it's extremely flexible by default that's standard out it gives you extreme flexibility to use any tooling to push it into anywhere be it a self-hosted like low key type thing or a commercial product data dog those sort of things it's extremely flexible but the key thing here is every decision that goes through decision point gets that audit log that's in a stable format and in a consistent format and always guaranteed to be produced in the same way for every decision made inside of the stack. Great thank you I also saw some comments come in from Twitter about how audit logs are important and I think you really tackle those things of being able to ship it wherever you want to hot tiers, cold tiers like whatever you need to do it exposes it for that so that's great. Another one that I think is a practical thing given how many languages are used across different companies what languages do you have SDK support for? Yeah so the core servers is really go that's given us a project go and have a poke around if you so wish and the interface that exposes itself if you don't want to use an SDK the server decision point exposes a GRPC by default but also an HTTP version that sits on top of the GRPC interface and we've actually then gone and co-gened SDKs for pretty much every language now from that using the Protobufs so we have pretty much every language that's commonly used we now have an SDK for and if you're using some esteric language or one that maybe hasn't got the functionality you need just yet you can just fall back to using directly the REST or the GRPC API as well and but you can find all these if you just go to the ecosystem page on server.dev and it takes you off to all the different SDKs that we have produced and again we've had a few community contributed SDKs as well which we're very thankful for and always open for more. Awesome well with that I'm out of my questions and I'm not seeing it haven't seen any more come in from the live stream so I think we're probably at a pretty good stopping place was there any other calls to action or things you wanted to close with Alex before we close out here? Yeah I would just say please go give it a try it's a complete open source project server.dev has all the relevant links and we are more than happy to go and jump in a call with any of you and kind of walk you through getting up and running and help you even write your first policies in our playground but please don't reinvent the wheel of authorization will be my main takeaway it takes too long it's not worth the effort and there's already solutions off the shelf that will do it for free as well Awesome well thank you so much Alex for the presentation walking through everything and showing how this all works if you're interested please visit any of the links we've been sharing throughout the stream and we hope to all see you at the next Cloud Native Live Thanks everyone see