About this video
What You'll Learn
- Use OPA as a policy engine to offload decision logic for authorization and Kubernetes admission control.
- Write Rego policies with rules, inputs, and iteration patterns for label, resource, and image validation.
- Build reproducible policy CI loops using opa run, opa eval, and rego test workflows with local bundles.
Torin Sandall walks through Open Policy Agent end-to-end: Rego basics in the OPA Playground, Kubernetes admission policies for label and image-source validation using iteration, running OPA locally with bundles and the REPL, and writing unit tests for Rego policies.
Jump to a chapter
- 0:00 Holding screen
- 1:11 Host Welcome and Sponsor Thanks
- 2:01 Introducing OPA and Guest Torin Sando
- 2:34 What Problem Does OPA Solve?
- 4:00 Introductions
- 5:47 OPA's History and Cloud Native Context
- 8:40 OPA's Core: The Rego Language
- 9:47 Exploring Rego in the OPA Playground
- 10:00 Introduction to Rego, the policy language
- 10:33 Rego Basics: Rules, Input, and Evaluation
- 12:20 Rego as a Query Language (Datalog based)
- 13:45 Our first Rego policy
- 15:44 Rego Packages and Kubernetes Example (Labels)
- 23:40 Simple Kubernetes policy - label validation
- 23:42 Kubernetes Example: Image Safety (Iteration with `some`)
- 31:00 Complex Kubernetes policy - image source validation
- 33:00 Deep Dive into Rego Iteration
- 38:30 OPA Local Development Workflow
- 38:40 Running Open Policy Agent (OPA) locally with CLI and VSCode
- 39:14 Running OPA Server Locally with Bundles
- 42:20 OPA CLI: `opa run` and the REPL
- 43:34 OPA Data and Input Documents
- 47:02 OPA CLI: `opa eval` for Command Line Execution
- 48:53 ConfTest for CI/CD Policy Validation
- 50:51 Interactive Evaluation and VS Code Extension
- 56:44 Writing Tests for Rego Policies
- 57:58 Rego Test Syntax and Running Tests
- 1:02:36 Troubleshooting Rego Test Logic
- 1:12:56 Conclusion and Thanks
Full transcript
Generated from the English captions. Timestamps jump the player to that moment.
Read the full transcript
1:11 Host Welcome and Sponsor Thanks
1:11 Hello. And welcome to today's episode of Rawkode live. I'm your host, Rawkode. Before we get started, I just wanna take ten seconds to say thank you to Equinix Metal. They are my employer and they allow me to do this as my job mostly every day. I get to produce materials that help us all learn all these awesome cool cloud native projects. Now you can also try Equinix metal by using the code Rawkode live. You can spin up really small boxes which will get you around a hundred hours of compute time, but I prefer the more fun
1:41 approach, is to spin up the beefy boxes with almost 400 gigabyte of RAM and spend that much more unwisely. Yeah. There we go. So check it out. If you wanna join the chat, we have a discord where you can come and ask questions or suggest future episodes. I please encourage you to subscribe and thumbs up this video. Now today, we're gonna take a look at the Open Policy Agent. And to do that, I am joined by no other than the VP of Open Source for Styra and co creator of the project, Torin Sando. Hello, Torin. Hey, David. Thanks for having me.
2:01 Introducing OPA and Guest Torin Sando
2:14 No. My pleasure. It's gonna be really good. I'm I'm really looking forward to to playing with Opal and learn more about it. And I'm really glad that you're here to be able to help you do that as well. So Yeah. I'm excited. Would you like to just then take a moment? You can tell us a little bit about yourself, about Open and Sarah, and how that all comes together, and then we'll we'll talk a little bit more about Open in more detail. Yeah. Yeah. For sure. Yes. I'm I'm I'm Toran. I'm one of the co creators of
2:34 What Problem Does OPA Solve?
2:38 the Open Policy Agent Project or OPA, as we like to call it. So I I joined Styro almost five years ago to kinda get the project off the like, start the project and get it off the ground. And so I spent spent the last five years, you know, developing the project, working on the core, you know, parts of the project as well as, like, integrations, taking it and and talking about it at conferences and writing blog posts. And and more recently, I've been spending a lot of time, you know, talking to users and talking to our customers from start and
3:09 helping them just be successful generally. So that's what I've up to lately. I've spent most of my career as a as a software developer working on kind of different kinds of distributed systems projects to deal with policy and and and orchestration. So, yeah, that's just a little bit about me. Nice. Yeah. So can we try and then summarize what problem does is OPA trying to solve? Yeah. Yeah. So OPA is is a is a policy engine. So what that means is that it it gives you a way of offloading policy decision making from your software,
3:46 And and that's really it at a high level. So Open is intended to be very general purpose and very, very flexible. So it's really the way to think about it is it's sort of like a building block that lets you, you know, enforce policies in in like, across the stack, across various kinds of services, various systems, various layers, and and and so on. So there's there's a whole bunch of different use cases for it. A lot of the time, it's applied to problems around authorization. Right? So controlling who can do what at different parts of the stack. Right? So
4:00 Introductions
4:18 in Kubernetes, you know, there's there's role based access control, and then there's also admission control. Right? So in Kubernetes, there's this problem of just putting down kind of safeguards or guardrails on your Kubernetes cluster to prevent bad things from happening, to prevent, you know, the wrong container images from running, to prevent workloads from using too much RAM or CPU, to prevent developers from accidentally creating ingresses or or, you know, load balancers on the public Internet and and and all kinds of things. Right? So there's this general public admission control in Kubernetes that Open helps solve.
4:52 But you can also use Open in other contexts. So we see tons of people using Open for microservice API authorization, for for application level authorization, for enforcing all kinds of config validation use cases in CICD pipelines. Even some people even use it to control SSH and pseudo access at the host level. So it's it's it's intended to be very kind of flexible in general purpose. And and so the core of the project is completely domain agnostic, but then you can kinda take it and plug it into different places to solve all sorts of interesting policy related
5:27 problems. Nice. Okay. So I I I I was looking at the documentation earlier, and I've seen that it it had use cases, I said, at Kubernetes. And some of them you've just mentioned there, and we'll build the documentation up shortly. But I'm curious, was the first use case that you had for Open when you were building Kubernetes based, or was it something else altogether? Yes. We we started the project in, like, late twenty fifteen, early '20 '16. And at the time, yeah, Kubernetes wasn't, like, the de facto standard for for for container orchestration or just general
5:47 OPA's History and Cloud Native Context
5:58 kind of, like, config orchestration. You know, there there were lots of other competitors at the time, like, and and so on. And and and it wasn't clear, like, who was gonna win. But what was clear was that, like and then cloud native wasn't even a term at the time. Right? Like or if if it was, people no one was really using it. So but but there was this obvious shift happening where people were adopting, you know, cloud and and kind of distributed systems at least are becoming the norm. Right? People are moving to microservices. People are moving to cloud. They're
6:30 automating more and more. You know, environments are becoming more and more dynamic and kind of ephemeral. And so there was a clear need for a new way of kind of enforcing policies in the in these sort of modern environments. And so we we kinda created OPA with that in mind. So OPA was sort of designed from the beginning to be a good fit for distributed policy enforcement, like being able to take a policy, a high level policy that says who could do what or who can access what, and to then break that down and distribute
7:01 it throughout the system and have it kind of run and execute and be enforced next piece of software that needs it. That just happens to be a good fit for for environments like Kubernetes. So it you know, we we we played around a lot of different use cases early on. In the early days, as you know, we we could, like, go look at projects and we go into the issue tracker, and, you know, you type in the word policy and you'd, like, see what would come back. Right? If you did that in Kubernetes, you get, like, hundreds of issues. Like, oh,
7:30 you know, we wanna we wanna make sure that our users always supply resource requests and limits. Right? Or we wanna make sure that, you know, that that they're not using privileged, like, kernel capabilities in the in the containers and stuff like that. Right? And there's just this long, long list of of what kind of use cases that we found in Kubernetes, and so we started to focus our efforts a little bit there. Also, at the time, there was no, like, dynamic way of extending Kubernetes with custom admission controllers. Like, in order to in order to implement an admission controller, you
7:58 had to write code and then vendor it into Kubernetes, basically, and then recompile Kubernetes. Right? So, like, if you're a Kubernetes administrator, like, maybe you're comfortable doing that, but you probably don't wanna be doing that at the very least, right, on a regular basis. So there wasn't really a great solution, but kinda came along and and it provided a great solution because it allows you to just drop in policies on the fly, have them reloaded without any kind of restart, have them applied automatically. So we, you know, we worked with Kubernetes, like, upstream community, and
8:26 and, eventually, webhooks got added, and and we just integrate nicely into that that ecosystem. And, yeah, it just sort of became, like, a little bit of a standard there. So something you said there was that at the core of it, it's agnostic. Right? It could be used for multiple things. Is when you say core, do you mean the DSL, the language, or is that in reference to something else? Yeah. I just mean I just mean the the kind of, like, the the fundamental, like, concepts around Open. So the the fundamental thing that it provides you is
8:40 OPA's Core: The Rego Language
8:58 this this this high level declarative language called Rego that you can use to write your policies in and then the the the the runtime for those for that for that language. And then around that, we build integrations for all kinds of different systems. So, like, for example, Gatekeeper is the kind of, like, integration between OPA and Kubernetes. We have integrations with Envoy. We have integrations with PAM. We have integrations with all kinds of things. There's there's a tool called CoffTest that's part of the OPA project, which is really useful for validating config files inside development environments or inside c I CICD
9:32 pipelines. So so yeah. So we have the the core language and runtime, and then around that, there's there's integrations that that make you actually do something in the world. Okay. Well, I mean, if we had five hours, I'd say we'd look at all of that. But maybe we should narrow the scope a little bit. So I've got the homepage here, which should now be visible to everybody. And we're just gonna click on the documentation. In fact, there's the playground first. Should we start there? Or do you wanna go for should we go for the docs first?
10:00 Introduction to Rego, the policy language
10:06 We I I'm I'm fine with either. The the playground's a really nice way to just kinda click around and and see stuff happen. But but, yeah, it's it's really I'll I'll leave it in your hands here. Alright. Okay. I've opened the playground. I think we'll we'll use that. We'll we'll kick the tires on a little bit, and then we'll see how things are going. If they're going well, maybe we'll we'll we'll try and deploy gatekeeper or something. But maybe we should take a look first Regal, the the the language. So this is this how, you know, some a developer's coming along and
10:33 Rego Basics: Rules, Input, and Evaluation
10:37 they wanna be able to start using this to say they don't want any containers to run as root and say that the Kubernetes environment. The first thing they're gonna have to do would be write something in this language that that that provided that policy. Is my understanding that correct? Yeah. Yeah. Yeah. That's right. Yeah. So the the model that that Open kind of, like, exposes is is this kind of this, like, offloading model. So software can query OPA when it needs to make a policy decision, and then and then OPA will will render a policy decision by evaluating the policies you've
11:08 given it and send it send the decision back to the software to be enforced. So, like, in the case of Kubernetes, the API server queries over. It sends across the wire this big JSON payload that has the sort of the full extent of your in, like, a pod or deployment or or whatever the object is that you've configured to go through the webhook. And then the policy will look at that JSON, and it'll make it it'll it'll generate an answer to that policy query that says, like, deny with this reason. So what you're doing when you're when you're writing these policies
11:39 is you're writing down basically, like, assertions over or structured data, right, over over JSON or over YAML, basically. And so the language gives you a bunch of primitives to do that. The language is is is it's declarative, so there's a little bit of a learning curve with it. But at the high level, what it what it really lets you do is just write down if then statements. You say, you know, deny is true if these conditions hold or allow is true if those conditions hold it and and and so on. So it's really just about writing
12:09 down these if then statements, essentially, that that that look at and kinda, like, analyze structured data. Okay. I mean, I can having a look at this here, I I kinda see, like, this combination of a little bit of goal with the sustainment operator, but then a little bit of JSON JavaScript on the right hand side. So it does feel pretty familiar on a on a first pass at it. So and then I can see here it's got scalars and strength and composite values. Like, is it a programming language, or is it a DSL? Was that a fair distinction to
12:20 Rego as a Query Language (Datalog based)
12:44 try and make? Yeah. I guess, like, I think DSLs the the term DSL can mean a lot of different things. OPA is it's it's a query language, actually. Like, I don't know. It it follows kinda like query semantics. So it's almost closer to, SQL, essentially, in that you write you write down statements that express, like, predicates over over structured data, but that then generate values. And so, you know, you can you can express all the kinds of things you would expect in a query language. Like, you can express ands and ors. You can express search operations.
13:25 So, like, for example, if you had you know, in a pod, there's, a list of containers. Right? And so you might wanna search over that list and see if any of the containers specify image from a registry that you don't want, right, or or or from, like, a registry that's not allowed. Right? And so the language has these these kind of, like, concepts baked into it to allow you to do those kinda, like, search operations. And then there's a bunch of other kind of features that that come into play that are policy related, like the ability to compose and delegate and
13:45 Our first Rego policy
13:57 and so on. Okay. I'm assuming the language didn't come before any sort of proof of concept. Open anything like that. Was there an actual version YAML, and you maybe had some constraints there that you had to break it out into Rego? Or, like, how how did that come about? Yeah. I I think there's like, someone is at some point, someone said, like, you know, the best advice around DSLs is, like, don't create them or, you know, don't don't start because it's a it's a big project. Right? You you need to you need to come up with, like, a
14:26 well defined semantics for the language. You need to implement a runtime for that, and you need build all the tooling around it. It's it's it's it's a lot of work. And so, like, early on, we actually, you know, experimented with a lot of things. We we even we we tried to use SQL, for example, as as as the language for expressing these policies. And we just ran into a lot of like, we ran into issues, especially around dealing with, like, structured or, like like, nested hierarchical data like JSON. Right? And since JSON is just sort of or JSON
14:58 or YAML or any kind of, like, hierarchical structured data is so prevalent in modern systems. Right? Like, we use it configuration. We represent all of our API objects with it. Right? It just it was it was like, it necessitated something something new. The the actual, like, language and ethics behind Open and Riga are are based on this thing called Datalog, which are which is, like, well kind of very well understood. And we sort of layered the ability to deal with JSON or structured data or hierarchical structure data on top of that. Alright. Thanks. So we have our first comment from Moz
15:32 who says, the regular language is very complicated. Please share some hints or tips. Well, we're gonna do our best to kinda break that down just now and today. So we'll be taking a look at some examples and and hopefully that helps you, Moz. So we have this Regal playground, has loads of examples that we can dive into. But this let me zoom in on that a little bit. There you go. And the documentation here, I mean, this looks pretty good. So this is just a hello world. See if I can work this one out. So the default value for low is false.
15:44 Rego Packages and Kubernetes Example (Labels)
16:10 We pass some input and m equals world. No. Alright. I don't think I understand what this is. Do you wanna maybe just give me a little bit of understanding here? Help me work this for that. Yeah. For sure. So here, why don't just just to well, first, just click evaluate on the top right. Alright. Alright. So the so the output from this was hello is true. The reason why hello is true is that when the policy was evaluated, the statements on line twenty four and twenty five were were satisfied by the inputs. You can see on
16:54 the top right, the input is a JSON object that has a key message and a value world. And then in that rule, on line 23, we basically assigned a message to an intermediate variable m, and then we've checked if m is equal to world. And so, you know, if you just kind of, like, look at that and then look at the input, you'd realize, yes. Okay. Those those statements on the in that rule are true. What's going on here is is there's a little bit of implicit behavior. So, like, on line 23, right after hello, if you wrote equals true
17:23 right after hello, that would mean exactly the same thing. So so that way you just the way you change the policy hasn't changed the meaning of the policy at all. You can click evaluate, and it'll it'll it'll give you the same output. We allow you to just omit equals true from the head of a rule because it's so common, basically. So when you leave out the value there, it just means true. It just says, hello is true if the conditions in the body are are true. So hello is true if m can be assigned to input dot message and
18:01 m equals world. So the it it that's why I said it's basically all just a bunch of if then statements. You're basically just saying assign a value to a variable if the conditions in the body of the rule are true. There's two parts to a rule. There's a head and a and a body. The head is the assignment, basically, and the body are the conditions that you write inside of the rule. So this is just saying hello is true if input dot message equals equals world, and you can leave that off. And then there's this notion of undefined, which we can
18:33 get into later. But, basically, if for some reason, the value so, like, in this case, if the value mess of message wasn't world, then the question is, well, what should hello be? And that's what default allows you to do. It allows you to assign a default value to a variable when none of the none of the rules with that name match. So, like, if you change the input in this case, if you change world to something else, anything else, and evaluate, now hello is false. Right? Because the statements in that body are no longer satisfied.
19:05 Alright. That helps. There that that immediately helps me because I'm gonna just test I'm gonna change something because I wanna confirm something in my head. So if I since there's to be a string, I want to say, like so by default, hello would be Torin and otherwise, David, and then I change this to world. Now the reason I did that is because I wanted to change the tapes system here because Mhmm. He said this could be a MEDI. And what I actually thought was happening there was this final thing was an expression return in a billion
19:37 value, but it's not the case. What's actually inside of these parentheses is just a number of statements which either true or false dictate how the assignment of this happens. If they're all true, then we make an assignment, and there's an implicit true. But, otherwise, it would be the default value. Yep. So the state so so the way that you can kinda read that, it's it's language is very light on syntax. There's not a lot a lot of syntax. It's very minimal. The way you can kinda read it is, you know, hello is David if and then the the statements inside the body
20:09 of the rule. And the statements inside the body of the rule are anded together. So they all need to be true or basically, like, what we call defined in order for the value to be to be generated. Okay. Cool. And so you can you can actually and so there's a couple couple of things that fall out of that. One is that you can generate any JSON value. So that like, you've generated strings here. We were generating booleans before, but, right, JSON allows you to express objects that contain arrays, that contain objects, and, you know, and so on and
20:37 so forth. Right? So you can generate any JSON value from a from a rule, actually. And you can actually include variables as well. So, like, if you changed David to, like, m in this case and you ran that, it would output world, basically. So you can include variables in the head of the in the head of the rule. You can generate dynamic values this way. Cool. The other thing that's sort of important to notice here is that this rule that we've got is it's called hello. Right? Hello is not baked into OPA in any way. Right? And neither is allow or deny
21:13 or or or permit or or block or anything like that. So all of the c's are these are these kind of variable assignments. Right? And so you can you can actually this is really powerful because it means that you can build up kinda helper rules or abstractions that, like, up level the the problem and and kind of, like, allow you to create your own kind of, like, model for for the for the policy. And so if you look at some of these other examples, you'll you'll see that in action. Okay. Before I do that, let's just finish on
21:44 one thing from this example. The there's a little bit of vocabulary there that I was picking up as as we were talking. So variables are variables. I think that's fine. This hello is a rule. And do we have are these expressions, statements, conditions, predicates? Is there something that we we refer to them as? Yeah. Yeah. So we we so if you select, like, hello all the way down to that closing brace, we call that whole thing a rule, basically. Correct. There are two parts to the rule. There's the head and the body. The head is the assignment portion,
22:19 and the body is the are the conditions. The the or expressions, I should say. So so the each line in the in the body is what we call an expression, but you could call it a condition. It doesn't really really make a difference. Makes sense. So there's there's two parts to it. And and yeah. And then there's a there's different you know, the basically, like, Rego allows you to express there there's JSON types. Right? So strings, numbers, booleans, null, arrays, and objects. And then also, we add sets. So you can actually there's set literals in
22:54 the language. And then it's got that that thing you see on line 24 on the right. That's what we call a reference. So you're actually, like, referring into a JSON document in this case. And you can actually you know, you can do exactly what you'd imagine. Right? It's dot into deeply nested structures. So if this was a, you know, a pod or a deployment, right, you'd have to dot several levels into something in order to look up the value. Yeah. So yeah. Nice. Okay. Is there does it mind about the types? Like, if I set this back to true and we
23:26 return a string, is that perfectly okay? That's perfectly fine. Yeah. Yeah. You can do that. Yeah. Nice. Okay. Let's switch the example then and pick something a little bit more exciting. Shall we dive straight into the some Kubernetes stuff? Sure. Yeah. Yeah. Why don't we? Let's go to the hello world one. Okay. Alright. Alright. So we have some kind of concept of of packages, composability, something I can I can fetch? How how does that work with a regular and an open? Yeah. So all of the all of the rules that you that you write so in this case,
23:42 Kubernetes Example: Image Safety (Iteration with `some`)
24:03 we've got a rule called deny, and I'll get into how that how that's working in a minute. But all of the rules that you write are namespaced inside of a package. So the package basically provides, like, a a grouping or a namespacing of of the rules you write, which means that you can kind of like, you can decompose a policy into a bunch of different namespaces or packages and then delegate ownership to different namespaces. So in this case, we've we've written a rule called deny. We put it inside the namespace of the package. Kubernetes validating label. And so if you wanted to,
24:32 like, look up the value of deny, you would ask for it under that under that package. So this is this is what allows you to kind of have policies from different groups of people brought together and then stitched together and then and then and then ultimately, to produce a single kind of decision. And so this Okay. Yeah. I I was actually just playing around. Obviously, I think it was it was at the start of this week, maybe the end of last week, but there was the whole helm to deprecation and the helm not disappearing and
25:00 the artifact top. And I actually noticed there were open policies available through that as well, which I thought was great. I never thought of it it being packages I could ship so that we only write it once and pass around. So that's Exactly. Yeah. So you can you can use this to to break the policy down into, like, sub policies that then get stitched together. You can also use it to create like, you can you can define functions in Rego as well. So you can define, like, helper functions for for all kinds of things. Like
25:27 like, let's say you want a function that parses a docker tag, right, into the the repo and the registry and the, you know, you know, so on and the and the the version or whatever the tag. You could write that logic in Rego as a function and then ship that around or reuse that inside of your your policies, and all of it is based on this packaging model. Okay. Nice. So let's take a look at this deny then. So we haven't seen these square brackets yet. Is this a function with a variable being passed in?
25:57 Yeah. So this is this is a sort of. So so you can think of it as a function. This is basically this is just another rule. The difference between this rule and the one you saw before is that this is the this is what we call a partial rule, which essentially allows you to assign a set of values to a variable. So instead of assigning a single value to a variable, this allows us to define a set of values, so multiple values under the same variable name. And so the reason why this is useful in the context of Kubernetes
26:28 and the reason why you'll see a lot of these, like, deny rules in Kubernetes or violation rules in Kubernetes that are structured like this is that it means that you can create multiple definitions of deny that all kind of act like, conceptually add into the set. So in this case, we're saying is a set that will contain message, MSG, if the conditions in the body of the rule hold in the and then, like, inside the body of the rule, we're we're basically, like, looking up to see whether the the cost center is there. And if it doesn't start with the right
27:01 string, then we generate an error message and put it into the set. And so if you evaluate the policy, you'll see that deny is is not just a string in this case, but it's it's a it's a set, or we represent sets as JSON arrays when we serialize that. But yeah. Okay. So this is a set of I mean, if if this was goal, this would be true and excuse my typing. And then we just be saying deny message. Yeah. We say there's a set deny. We add into that set or something. Right? Equals blah blah blah. Okay. Right. That makes sense.
27:31 Okay. Yeah. This is checking that the the YAML we pass into it has some sort of certain structure. There's nothing to say what type of YAML this is, but does that mean if I pass in a YAML structure that doesn't have request object metadata, like, say it doesn't have anything below object, was that just an immediate deny, or is that an error? Or It's not an error. No. So it would just be undefined. So, basically, if you refer to a value that doesn't exist, then it then that that reference is just undefined. Right? There's no value there. It's not it's
28:03 not an empty string. It's not an empty object. It's not it's not even null because that's a valid JSON value. It just it's just undefined. It doesn't exist. And when something is undefined or it doesn't exist, then the statement is just not true. Like, it's just not there. Right? So in order for this message to be added into into deny, that field has to exist. That path has to exist in the in the JSON. Okay. Well, I'm I'm getting heckled already to click evaluate. Adrian. I'll get that done now. So we evaluate these rules, and I we'll
28:35 go back over that in a second, and we get deny because it does not contain. Well, no. It does contain a call center, but it's not formatted correctly. Exactly. Yeah. So what this is expecting does that dash have to exist? It's yeah. So that would be that should work. K. That's right. Yes? Yep. Yeah. Yeah. Got you got it. Alright. So now I wanna test the what I was talking about there is if we remove the request and I see a response because I'm a terrible developer. Yeah. There's no error. There's there's a rules just the same. Doesn't happen. The rules don't
29:18 pass and the denies and checked. Exactly. Yeah. If you go to the examples, there's another one that kinda gets into this. So label exists. Let's go to go to that one. This this builds on the what we were just looking at. So so this one this policy this example has two denier rules in it. So there's one denier rule that's checked on the bottom that's checking if the call center label is present and that it has the right format. But we've added another rule on top of above. The order doesn't matter, but we've added another
29:46 rule that's just checking whether that field exists at all, and it's generating a different error message in that case. So if you if you do the same test now, we'll see the output is a little bit different. Every reason. So So this this one doesn't have that that cost center label in it, I think. Yeah. There we go. Yep. Ah, okay. Okay. So the row are the rows executed top to bottom? Is there any sort of ordering semantics there? No. So yeah. So there there is no ordering across across the rules, and there's no ordering
30:18 within the rules either. Right? The the statements the expressions in the rule are just added together. Right? There's no order with with an and. And and what we've done here is we've actually expressed logical or. Right? So we've said deny contains message if not input request yada yada yada or deny contains message if, you know, the value does not start with that code. So, yeah, when you define a rule multiple times with the same name, that's how that's that's an expression of logical or, essentially. We've we've said add this message into the set if or add it into the set if.
30:54 Ah, okay. Alright. It's it's it's starting to get there. I'm I'm learning. So let's move on to this next one then, image safety. Now now that I'm an expert at this, let's see. So no. I did as we were talking at the start, I accidentally clicked on a doc, which happened to reveal what the sum statement was. The universe because I I seen universal quantification. I was like, alright. I need to click on this one. So I know that this means there's gonna be some list of values that we wanna iterate over. And now we're checking if it
31:00 Complex Kubernetes policy - image source validation
31:31 is a pod, and we're checking so we're seeing here that all images must come from hooley.com, if I've read that right. Exactly. Yeah. Yeah. So this this example is saying, let's put a policy in place that says that all container images must come from a corporate registry. Right? And you you could express that. Like, you could invert the logic and say, like, only allow if. But in this case, we've expressed it as a as a deny list. So we've said, if there are any images that don't come from hooley.com, then there's some sort of, like, error or warning that needs to occur.
32:06 Now the interesting thing about this example is that as every as you probably know, the pods can contain multiple containers. And those containers are specified as an array. Right? And so you could write a policy that goes and says, okay. Input request objects that container zero dot image equals or must equal something. And then write another rule that says spec dot containers one and then another one that says spec dot containers two. Right? But that would obviously be painful and and impossible in some cases. Right? If you don't know the number of containers that could possibly exist, then you'd have
32:49 to write an infinitely long list of these these statements, and no one's got time for that. So the way that we get around that in Rego is is by doing iteration. Okay? And so the the this is this is probably the hardest concept in all of Rego is is, like, just understanding iteration because it's not explicit like you might be used to if you're, like, writing Python code or JavaScript code. It's it's more implicit in the same way that it's implicit in, like, SQL. And so what we've what we this this example kinda gets into that. So what we
33:00 Deep Dive into Rego Iteration
33:18 do here is we declare a variable. In in, Regal, you use the keyword some to declare a variable. And so we say for some I, if the input contains a pod and for some I where we u we inject I into that reference. This is like an array index now. For some array index I, containers of array index i.image does not start with hulu.com and generate an error. So this will basically iterate over all of the containers in the pod and check whether any of them are check which ones don't start don't start with that string.
33:59 So if we evaluate this, you can see MySQL is not from Okay. So can I ask a question? Yeah. So can at the end, this can be any JSON object. Right? Or any JSON. Is that would that be correct? So if I were to make this a list Mhmm. And just actually copy it and then had to evaluate, will that check both of those admission reviews? No. No. So so what's happened now is that so so, yeah, you're right that it it could be a JSON value. So the important thing to keep in mind is that
34:33 OPA doesn't know anything about Kubernetes pods or Kubernetes admission control objects. Right? It's just a JSON blob that's been passed to OPA that that the policy is evaluating against. And a policy is what what applies meaning to that JSON data. Right? So Open itself just sees JSON, but the policy looks at that JSON and applies meaning to the to the values in in the in the JSON. And so in this case, you you've changed the input, so you've changed it from an object to an array. And that's that's totally fine. It's just that the the the policy is now kind of,
35:06 like, out of sync with the data that's being passed in. Right? So in this case, we're assuming that the input is an object. We could we could treat it as an array. And so, yeah, we can make the change. So if we chain we Can I try and let me see if I can do this in June? Yeah. Yeah. Yeah. I'm gonna define a second sum. I'm gonna make my where does that live here? Request. I don't know if it'd be input or request. I'll let you fix that in a second and then change this to j just
35:31 so it's an order. Is that pretty close? It it it's close. Yeah. So there's just two things to two things to observe here. Right? So one is that we've got two statements in this in this rule that are referring to input. Right? So there's line 25 or that are referring to that JSON data. There's line 25 and line 26. Right? So we want that we'd want both of those to be the same. The other thing to observe here is that in this case, like, I think the way you change the input data, like, you just
35:58 made the top level input value an array. You scroll up in the input field. Yeah. So we just oh, yeah. Yeah. There we go. So the way that you refer to the to the JSON data is exactly the same as the structure of the JSON data. Right? So in this case, like, would we we now I'll flip it around and ask you a question. Do we wanna iterate over request, or do we wanna iterate over input? Yeah. There you go. Alright. Yeah. So I was thinking that when I was typing that. Was like, well, it'll
36:26 a better request with input. But yeah. So what's this work? It did. Yep. Nice. And so now if you had if you I mean, you can copy that that JSON object if you want, and and you'll see multiple answers come back. How do you mean? Sorry? In the input. So if you just take the input, the object oh, you did. Okay. I thought, yes. There should be oh, but I assume Role is broken, so I'm assuming. So change the second one. How about you change the second one to be a different image, like, engine? Ah, okay. So, yeah, let's set to
36:56 MariaDB. Sure. There we go. K. Yeah. Nice. Yeah. So now we're searching over all the vision objects in this array, and then we're searching all over all of the containers. So it it's pretty powerful. Right? Like, we've just expressed, like, a nested for loop here just by putting variables into those into those references. I mean, I can reference any other variable here too. And could I just say that this came from image button name? Oh, no. That would just be name. Right? So Yep. But you can refer to the container name if you wanted to.
37:35 You could you could either assign it to a yeah. You can run that. Okay. So now this this now we've an error back. It's telling us, woah. Wait wait a second. Right? So it's saying that the variable name is unsafe. All that means is that name hasn't been assigned anywhere, basically. Right? And so that's that's not good. So we need to assign name to some value if we wanna use it. Ah, okay. So down here, I would just say this is equal to input. I'll just copy that. We don't need to watch me type that.
38:10 Name. Oh, alright. And then we have image my SQL. Okay. I didn't really make it proper English sentence. But we now have the container image name and the container name. So nice. Like, I can see how you can start to put all these things together. So that's great. Okay. So we have one more Kubernetes example, but maybe we could just go through the steps of like the playground is great. But what would my developer local machine kinda workflow look like? Or and Yeah. I mean, I'm assuming I can run this on my own machine. I don't need
38:40 Running Open Policy Agent (OPA) locally with CLI and VSCode
38:43 to copy and paste all of my my JSON or YAML to Yeah. Totally. But this is actually a great opportunity to try something out from the playground, which is to click publish on the top right. I did look at that button, and I was like, I wonder what that means. So Okay. So when you when you publish a policy in the playground, it just gives you a shareable link. So this is a great way, like, if you're experimenting with something and you wanna give it to somebody and for them to look at or you're filing an
39:08 issue against OPA or you have a question, you know, put in the playground, share the link, give it to us. We can we can look at it there. But we also give you the steps to take this and run it locally on your local OPA. And so we can go through this right now if you want, but this this allows you to basically run OPA locally. And then what it'll do actually is it'll download the policy from the playground, and then it'll let you interact with it locally. You obviously do all this development locally, but
39:14 Running OPA Server Locally with Bundles
39:33 I just thought I'd kinda highlight this, which is a a neat feature, I think, of of the playground. Okay. So are these two separate options? One of them is to run an open server locally Mhmm. Point to search resource. And then this one is just to actually download the policy. The yeah. The first one, it will run OPA, and it'll basically configure it to use what we call bundles in OPA. So bundles are the way that you kinda distribute policies and data down to the OPA. So what it's gonna do is it's run OPA. It's
40:02 gonna configure it to pull the policy from the playground. And then the second thing there is showing you how you can exercise the o like, the policy locally on your machine via the OPA that's gonna be running there on your on your laptop or on your on your desktop here. Okay. So I should just copy this link here then. Yep. You can just run that. Here we go. So Open's running. It's downloaded the policy from the playground. In this case, you can the the bundle API is very simple. You can just serve bundles on NGINX or on s three or
40:34 on any HTTP server, and they're just g ZIP tarballs that contain policy and data files. So it's very HTTP friendly. And then, yeah, and then you can just run that. That's gonna be the playground will serve the input data that's that's that's there. So if you it's just doing some some curl magic, but it's basically just downloading the input data from the playground and then sending it to the local. Didn't it like that? Oh, it's just me trying to pave it through Oh, no. No. Yeah. JQ. Just give give JQ wait. Why didn't it? Does that not work? What is it? Parse
41:18 it. ZSH parse error in here. It's just the lane to endings. Maybe. Yeah. Yeah. I think so. We go. Yeah. So now you're getting a response from the local OPA on your machine. Okay. So so just so that I understand that correctly, when I run this OPA server command here, the only policies is aware of is a bundle that has been served by the playground. That's right. So I can just throw any JSON data at this most local server at the data endpoint, and that's gonna run those policies against it. Exactly. Locally on your machine.
41:58 Right. Okay. Cool. That's a that's a neat feature. Especially, could see, you know, if people are struggling to get their policies to work or to test them or whatever, you know, been able to just throw them up there and pass them around. I can see definitely a lot of value in that for sure. So let's so do I always have to run an open server? No. So you can you can use OPA in a few different ways. So now that you have OPA on your machine, maybe this is a good opportunity to just kinda, like, play around with it locally.
42:20 OPA CLI: `opa run` and the REPL
42:31 So if you just run OPA, it'll it'll do the standard thing of showing you the different commands that are available. OPA kinda like say, like, embodies the idea of policy as code. So it gives you a a kind of like a a tool chain that you can use to interact with the policies locally on your machine on the command line. So there's there's tooling to, like, parse the policies, check them, build up bun those bundles that I was talking about, as well as just run the policies. So if you just type overrun, what it'll do is drop you into a
43:00 a local shell or, like, a what we call a repo or read about print loop. So this allows you to just run arbitrary statements inside the policy language and then and then see the output of them. So you can go and define, like yeah. Exactly. You can find a rule called hello, and then you can ask for hello if you just type hello now. It'll it'll print the value of hello. Right? So this is just what we call the REPL. It's a sort of a low level way of of interacting with the policies. You can
43:29 if you do overrun and you you can pass in files, it'll load those up, and then you can query them. You can interact with them. And is that just a fail with, like, a policy statement like here? Yeah. Yeah. So grab like, why don't you grab this one and just dump that into a a dot rego file on your machine? Call it man. Is this Versus code, by the way? Yeah. Is. Yeah. Okay. There we go. Nice. Perfect. Alright. There we go. That's what I wanted to test. Need those colors for sure. Yeah. It gives you colors and a little
43:34 OPA Data and Input Documents
44:06 bit more, actually. So it gives you all the same stuff that you saw on the playground. So that ability to, like, evaluate the policy, you get that inside of the SQL. Yeah. It's looking much better now. There we go. There we go. That's beautiful. So now yeah. Let's exit the rep. So now that I have our main dot rego there, I'm assuming I can just do open run and then I'll just do help. Oh, it's quite a lot though. Okay. So so you just pass it fails. Perfect. So if I type show oh, no. So yeah. When you type show in the
44:42 in the REPL, what it does is it any rules you've defined inside the the REPL. The cool thing about the REPL is that you're just writing queries. So okay. Guess one thing we didn't talk about before is that all the rules that you write and all the data that you load into OPA is is namespaced under what we call the data documents. There there are two, what we call, documents in in OPA. There's the input document which you're interacting with before. That contains the value that the software occurring OPA wants to send across. And then there's
45:12 the data document, which represents it's basically all of the decisions and all of the raw data that's cached inside of Open that are loaded into Open. So if you just type data, it'll show you the value of all of the rules that you've got inside of the inside of the policy. And so you can see that it's opening this hierarchy. That hierarchy might look familiar if you if you think back to what was in the policy in that package statement. So the package defines the location in the data document where your rules will appear. And so in this case,
45:42 the package is Kubernetes dot validating dot images. So that means that denial will show up under Kubernetes validating images inside of the data document. Okay. So how do I actually validate a document then with this rule that we've we've run over with? So right now, the the inside the Ruffle, we don't have an input document defined. So when you run the policy, it's not matching anything. So we can define an input document in the Repl package just by typing input, like, colon equals some value. Now you'll need to paste in that thing from the from the playground in
46:16 order for this to to do the right thing, and that should work, hopefully. Yep. Okay. So now if you now now we've defined a rule called input, and there's a a convention in the around input, like, order to how you define it. So just trust me that it's defined without input document. If you run data again, you'll you'll see Oh, there we go. Oh, sorry. It's dumping both the input value. So type, like, data dot Kubernetes for example. Okay. So Yeah. There you go. Yeah. Yeah. So what it's doing when you when you run that is it's internally grabbing the value
46:51 of the input document to use, and then it's running that that query against the input value. Okay. Very cool. Now what about from a CI perspective? Let's assume maybe this isn't the way that it works, but let me try and see what I've got in my head. I can imagine I have a project that has some Kubernetes YAML things. And let's just say there's a rules folder with the rules Regal files and then there's a manifest folder with the manifests on it. And I want my CI system to run the rules against the manifest. Is is there a workflow for doing
47:02 OPA CLI: `opa eval` for Command Line Execution
47:24 that? Yeah. So there's there's different ways you can do it. On the command line with OPA, we have this thing called OPA eval, which lets you just run like, it's it's basically like running the REPL, but just on the command line. So you can you can run a policy query against against a bunch of data and and and policy files. But it's a bit it's kinda low level. I I can show you. So if you just go back to the command line Yep. And you type open eval. So this is similar to to what you
47:56 just did, but if you do dash d, so for for data or policy, and you pass in main dot Rego, and then dash I for input, so now we can give it oh, we didn't save that file to this. I did. I got it. I'm sorry. You got it. Alright. Perfect. And then you do and and now you can give it a query. So now if you run data, just just type data. If you run that, it'll yeah. Exactly. It'll it'll return the output. Right. So you can you can run the policies locally using using Open Eval.
48:32 Again, that's sort of like a Swiss army knife for evaluating your policies. So there's all kinds of options that it supports for, like, doing tracing and profiling and and other things. But it's really meant to be just like a Swiss army knife. And you can build you could build, like, scripts around that that would do what you want in your CICD pipeline. But it's it's a low level tool. And so this is where, like, the CONF test subproject comes in. So conf test provides, like, a more opinionated way of, like, loading and and running your your policies on the command
48:53 ConfTest for CI/CD Policy Validation
49:03 line. And so with conf test, you would just say, I think, conf test test, and then you pass in the manifest. So it would automatically load up the data the policy files and then run them against your your your your manifest. So it it's a much more kind of, like, developer friendly, I would say. So using contest, does that provide a sort of workflow where, you know, say it's maybe like a a a standard company set up with us, an operations team that defined the policies in the central location, and then the developers wanna run contest locally to see if
49:33 it passes? That's that would enable that kind of workflow where I could say, hey. Go and test my stuff against those rules. Yep. So so a lot of the time, what people will do is they'll have it run as, a pre merge hook in in Git or as part of, you know, as part of CI. Right? So after the manifest merged or even before, they'll have contest run against against all the manifests in in the Git repo. Right? And so they'll the leader store the policies in the same repo, or you can also pull them from
50:00 another another place. And so contest supports, like, pulling from Git, pulling from OCI registries, as well as well as other options. So it's it's pretty flexible in terms of how it obtains the policies. And then and then it'll it'll run them against whatever files you've you've fed into it. So it's a really nice way of of doing kind of, like, CICD time validation. And then, yeah, if you wanna try it out locally on your laptop, you can do that because it's it's portal. That's one of the things that we spent a lot of time ensuring early on in, like, development of Open
50:32 was that the policies you write ought to be portable. I mean, you can take them and you can, like, run them in your Kubernetes cluster, but you can also run them, you know, inside of a CICD pipeline just as just as well. You can run them offline for, like, audit purposes, for example. So Nice. Okay. So let's see. Does it make sense now? Can should we try and deploy this to our Kubernetes and then do some enforcement, or is there something else that are more another step you think we should take here? No. I think this is this is pretty
50:51 Interactive Evaluation and VS Code Extension
51:05 good. One one one of the features that we didn't exercise, I think, in the playground and that you get in Versus Code that is, I think, really cool is is the interactive evaluation. So you're, like you were clicking actually, you can kinda see it now. I don't know if you've caught it, but that button up there changed. It no longer says evaluate. It says evaluate selection. Ah. And so what that means is that you can actually select parts of the policy. Oh, you've gone straight to the really cool example. Yeah. So yeah. So you could select you could click
51:34 evaluate selection now. And what it does is it prints the values of the variables that are selected inside of that text block. Right? So it's giving us all the values of I and j and name and image, and it's it's reporting that back. So you can select basically any statement inside the policy and and evaluate it and get back the the current value. So, like, if you just select deny, for example, and then evaluate selection, you'll just get back the value of deny. When you run evaluate without selecting anything, what it's doing is it's just basically just asking
52:09 for all the values of all the rules inside the file. But you can just as well ask for a single rule or as you just saw yeah. So if you run that, we've only selected message. Right? And message isn't defined anywhere. Right? So it's it's not safe. But yeah. So there there's some limitations to that. Obviously, you can't just select anything, but you can select any expression, any rule name, any set of expressions inside the same rule. Okay. Yeah. And I was wondering if it would show me the the violation in some way. But You would need to select mess the last
52:43 line in there as well. Yeah. There we go. Nice. Yeah. Yeah. So that that interactive evaluation feature, I think, is is is really powerful. It creates a really tight, like, development loop or a test loop when you're when you're developing a policy or debugging a policy. You can do it in the playground. You can do it inside Versus Code. You're in the rep, but it's a little bit more low level. So yeah. So I can do that in code as well? You can. Yes. You'll need to make sure that you have Open installed in path in the path, but
53:17 the plugin ought to do that for you, actually. Yeah. Just blew up a oh, you're oh, yeah. It may work. It should work. Don't know. It's taking some time. I'm scared. Well, I'm running big, sir. It seems to have slowed everything down. So Oh, really? Oh, there we go. Okay. Alright. Well, I mean, it's thinking about it now. It's consider it's considering whether it's a wide I didn't ask it to go and update all the the history. I just wanted it to install a package, but whatever. Okay. So now we have open our path, means I should be able to do this.
53:56 Yep. Let's see. Do I have some sort of I do. Okay. Evaluate selection, evaluate package. So let's try this evaluate action. So that's interesting that it magically pulled that JSON failure of my project and ran the rules against it. How do you guys do that? So so show me the show me the well, yeah. So you've got this inside of a directory or something. Yeah. I've got an input dot JSON. Oh, there we go. Yeah. Yeah. Yeah. Yeah. Yeah. So the convention in Versus code is that the input document will be pulled from input dot JSON.
54:47 And by default, it'll just load up every Rango file inside the workspace. So, yeah, so it just magically worked. So I just got ridiculously lucky with the name of that failed and for that to actually work. Yeah. I mean, all of our all of our examples say input.JSON, and so when we were The subliminal messaging. Yeah. Yeah. What you wanna call that fail? You were tricked into We didn't prepare this in any way for the records. No. But now I need to rename it because I always have to see it not work before Yeah. Not perfect.
55:17 Alright. No input files. Okay. Okay. There we go. Okay. That it's really cool that I get all of that features as well locally. I can see how is it it could really quick feedback loop. I can just throw in an input dot JSON and make it work. Now does it care about it being JSON if I renamed that to input dot YAML? Are the same rules gonna be applied against that? That's a good question. I don't think Should we just try it? Yeah. Try it. I I think it I think it's gonna fail. We can load input files,
55:52 or we can load files like YAML files through other APIs, but I think this one's not gonna work. We can try, though. Look. We're gonna get a great error message here. I can I can already see it? Well, Arena missed the input too. Yeah. And let's try our evaluate. Alright. Okay. Yeah. No input. It didn't find it. Yeah. But pull requests are always welcome. So if somebody wants to come along to the the Versus Code plugin and give us that, you know, we'd love to take it. Awesome. That's really cool. Really impressed with that plugin, actually. I don't I I don't even
56:30 think that that would be something we've been playing with, but it's kind of really helps work out what my workflow is gonna be when I'm starting to put these policies together on my own machine without having to work from the playground as it would be. Mhmm. Cool. Alright. Is there anything else you wanna wanna cover before we finish up? The only other thing that just occurred to me that we really think is really powerful about over is the ability to test your policies, right, unit tests for your policies. So what we've been doing right now is
56:44 Writing Tests for Rego Policies
57:01 just kinda playing with it. Right? We've been kinda, like, just poking around and and clicking buttons and and kinda seeing what happens, which is a great way to get started. But when we when you when we write down policies and rules, just like code, it's really powerful to be able to write down tests for that for that code. And so OVA comes with, like, a whole test framework that allows you to write unit tests for your rules and then to have those tests run inside of Versus Code or on the command line. And so that's just something else I would
57:29 recommend people kinda take a look at. There's a whole page on the in the documentation that that goes into that. It's it's it's in terms of that, like, fast feedback loop that we've been talking about, it's a really, really powerful way of accelerating development. And, I mean, you get a regression suite out of it automatically by doing this. But yeah. So I highly highly recommend people invest in test driven development when they're working with with regular policies. It it really speeds things up. And because because the language is is a kind of a query language and because values are just
57:58 Rego Test Syntax and Running Tests
58:02 kind of first class, you can you can really quickly get a % coverage, and it really speeds up your your kind of iteration time. So definitely definitely check that out. I mean, I'm gonna try it now. Alright. Let's go. Sure. Sure I could do this in two minutes. We have a a couple of comments as well. So Adrian has said, thank you for this. It reminds me a bit of x and l s t and prologue, but it's been a long time. Yeah. And maybe you just want to integrate Rego into a container registry so you can run
58:33 it on image manifest. Yeah. That's actually a cool idea. I haven't if anybody's brought that up. Yeah, it would be nice to have that kind of same admission control capability on on at the image registry level. Yeah. Some sort of rule where you can see that all images have to be built for ARM 64 or something like that just to yeah. I can see the use case for that. Yeah. Alright. Let's let's see if I can I can write a test? So I'm gonna just butcher the one I copied from that thing. I'll just call it test test dot
59:04 wiggle. Naming is the hardest part of of this whole Well, I wanna I always like to try and pick things that might break stuff just to see what happens. So so I'm gonna test the MySQL is not allowed. And I'm assuming this just has to kind of reflect the JSON that I have in my input. So I'll just steal one of these. And if I remove that oh, that should be I'm assuming I can do a low and not allow. That's the two assertions that the test and framework is gonna make. Is there anything else there?
59:43 So it's so so like other things, OPA, the test framework is very minimal. The only thing you need to do is name the test test underscore something. So when you run OpenTest, it'll just look for all the rules that are called test underscore and then run those. What you put inside of those rules is entirely up to you. So you could you could refer to anything. In this case, we were referring to allow, which is a rule that we defined in a in a in a policy in that example. So what we wanna do in this case is actually
1:00:13 refer to the deny rule that you've got. Right. Okay. However, remember, all rules are namespaced inside of a package. Right? So in order to report to deny, we either have to be inside the same package or we need to yeah. We need to do that. And all rules are names yeah. Oh, there we go. Perfect. Done. Okay. So these, yeah, okay. So these packages have to line up. I can then use this deny with an input. That's the same that everything has to start with Hooley. So what I'm gonna do is this test to say
1:00:42 that this should be denied with Is that right? So it this will run. So why why don't we run this, and and then we can kinda, like, debug it and see kinda what happens. Test test. Yeah. So why don't you just run just do test dash b and then b as in bicycle, and then just do dot. Alright. So all that's going on here is we're saying open test dot, which is just saying the current directory. So it's gonna load all the files in the current directory. And it'll do that recursively, by the way. So all the open tooling kinda works this
1:01:29 way. You can pass in a directory path for any of the the file paths, and it'll load all the files in that directory as well as all the subdirectories and so on. So it'll recursively load all the the Regal and data files that it finds. Dash b, as in bicycle, tells the OpenTooling to follow the, like, bundle layout. So what that means is it'll load all the Rego files that it finds as well as all the files called data dot JSON or data dot YAML. So that's how you can load in, like, raw JSON data if you want. Without
1:01:58 dash b can run it without dash b and just see what happens. Yeah. So what what happened there is it tried to load all the data files as well as all the YAML and JSON files and then load them into data like, into the data keyword in the language. And when it did that, it it ran into some problems. Like, it it tried to merge input dot YAML and input two dot JSON together, and it just couldn't do that because well, because they're arrays, I think. Right? So you can't really, like, merge arrays. So we can we can just kinda, like,
1:02:28 avoid that problem by doing dash b, which will cause it to ignore those those input files. Yeah. I mean, I what make this an array? Does it then do the merge? It will try to merge. However, it's gonna well, it might no. I think it's gonna run into problems with the those arrays in there, but try it out and see what happens. Merge error. Yeah. It's running into a merge error on those on files. But if you if you go to the, like, input YAML and you just put a key at the top level with, like
1:02:36 Troubleshooting Rego Test Logic
1:03:00 just just indent it by one and then yeah. And then yeah. And then perfect. Yeah. Now it'll be totally happy. I'll put the JSON to merger. Well, is that because I've now changed the format of that and not the rules? Got is that an array? I I stopped it being an array. Now it's an array again. If it's an array, it's gonna you can't use an array at that level for data. Okay. Anyway Let's not yeah. I'm gonna rattle on the data. What I'm curious about is, like, this test passed. Right. And that's the that
1:03:44 let's let's finish on this then. So why did this pass when it's not a Hooly container image? So so so the reason why it passed is that, like, deny doesn't mean anything to OPA. Deny is just a set, and it happens to be it's a set. So it's actually gonna always pass regardless of whether or not there's a value inside of that because that, like basically, the statement on line four is it it's it's always true. It's either an empty set or it's a set that contains values. So in order to, like, actually write this
1:04:12 test properly, what we wanna do is assert on the val like, value of deny. So we'd wanna say deny and and, like, these tests are are simpler because allow is like a Boolean value. It's either true or false. And so what we're testing is, like, that it's either true or it's false. And if you just say allow and allow happens to be false, then the test is gonna fail because one of the because the statement in the body of the test is false. Right? So, yeah, so for this deny rule, what we'd wanna do is test the actual
1:04:45 value of that deny set. So we'd wanna say deny is nonempty or deny contains error mess like, error messages. Is that enough? It's in this case, deny is a set. So what you'd wanna do is declare an empty set. So you could just say you you can say set print, like, call set say set, and then, like you would in Python, you'd say set low lowercase set. K. So that failed because we're getting something back from the deny rule, which is that this is not a a hooly image. Right. Wait. Hang on a second. No. Wait. That that that that statement should've
1:05:35 Oh, no. I can't spell. Yeah. Oh, there. Is that No. No. No. There's something wrong with the logic. Hang on. So this should generate an error. So the set should be nonempty. So that should be set as like what happens if you just select that whole I just wanna make sure that we're not missing something here. If you select, like, lines, whatever, three through 29 four through 29, And you evaluate that. Oh, I think I know what's wrong. Okay. So deny is empty. Problem is I renamed the input file. So the task force pattern to be an input
1:06:19 dot JSON. No? No. No. Remember what we did in the policy? We made it so that it expects an array for input. Yep. So in in main dot rego, it's expecting input to be an array, but in the test, we've just specified it as an object. Ah, ah, okay. Gotcha. Gotcha. Gotcha. Oh, yeah. There's nothing to do with the input dot JSON because we're defining the input We're in we're in the Yep. Alright. And if you select that again and run that, does it So evaluate. Why? So it's giving us one result back, and it's saying that deny is empty.
1:07:14 But this says using input dot JSON and not this. Yes. Yeah. Yeah. That one's using input dot JSON. But it shouldn't matter. Like, it should replace it with the the value from inside the query. So what am I what am I missing here? And this yeah. That should still fail. Can you yeah. I mean, if you if you remove the width part, like, width input as and just do that same query, what is it? Yeah. We could use coverage here to see where it's failing. I think that's what we'll end up doing. So just select an eye now.
1:07:57 And then yeah. Okay. So that's that's behaving as we'd expect. K. So put the put the width back. Yeah. So if you select deny the whole thing, and then you can do eval with coverage, and that'll show us what lines. Look for coverage. Select toggle evaluation coverage. Yeah. So now go into main.Rego. Oh, wait. Just why is it not the highlighting is not showing up. Well, that's not good. I'm sure it's something I've done. Yeah. I just can't see the No. I made that hooly image, so that would actually pass anyway. Right? Well, it should be the set should be
1:08:56 nonempty now, I would expect. Can you just just copy this entire file and paste it into the playground? I could just delete it if you want. Up to here? I wanna know why it does or just paste the test below the deny rule in the in the playground. Oh, okay. I guess I'll need to remove that duplicate package. Yeah. Let's go to the package. And then and then select, like, 33 through the bottom of them. Yeah. 258. And then run click coverage and then evaluate. Okay. Now scroll up. Wait a second. Wait. It's different. We we are seeing a
1:10:03 value for deny now. Yeah. We did get And if you if you just if you just evaluate the package, test the test will pass, I think. Basically, it'll be true. Okay. Wait. So it okay. So it's doing the right thing there. I don't understand why and and we've got deny we've got an assertion down below that says deny is non empty. Yeah. Okay. So so that worked. Right? Yeah. So that this this is doing what we expect. Right? Deny is not an empty set when it's evaluated with that input. So if I just set this to hooley.com,
1:10:43 then we should get test my SQL is not allowed as false. Yes. Or it'll be emptively missing. Or I guess it should be an empty set. It should be an empty set, but what is going on? I'm good at breaking stuff. Like, I just had I spend my actual day programming just doing what's going on. And so if you evaluate right now oh, okay. Sorry. This is I I I got caught up in in the details here. We're basically evaluating deny twice so that that we're not assigning the value of deny to a local variable. So the the value
1:11:44 of the in like, so, basically, like, you've asked for deny on line 33, and then you asked for it again on line 60 or whatever it is down below. On line 60, it's being evaluated with the input on the on on the top right in that pane. But on line 33, it's being evaluated with the input that we've defined in line inside the policy. Right. So I have to make I have to assign the result here? Yeah. Sure. Yeah. Yeah. Yeah. That's what you'd wanted. Is that? Yeah. Exactly. Yeah. Sorry. Res. Yeah. Now res is not able to empty
1:12:20 set. Alright. And then I I should be able to break that. Yeah. That's right. There we go. There we go. Okay. Sorry. I was going I was going crazy. I I just wrote down and looked at the look at the actual policy. Yeah. Yeah. Yeah. So Okay. Cool. That that makes sense to me now. Now I know what was going on there. I just assumed some something magic was happening between this and then this So did I. Yeah. Alright. Well, we'll leave it there. That was a fantastic introduction to Open Policy Agent and Rago. And
1:12:56 Conclusion and Thanks
1:13:02 a lot of things clicked for me now just through this conversation and playing with a a really, really impressive tool. I can see so many different applications for this as well. I can see why it's not just being consumed and used by the Kubernetes community, but by so much more. So I I just wanna say thank you for joining me today. That was that was great. And I really appreciate your your input, your time, and especially your patience there as I was kind of breaking things and kicking them over. So thank you for joining me today. Yeah. It's been
1:13:28 a pleasure, David. Thanks a lot. Alright. Well, have a a great afternoon. I'll enjoy my evening, and I will speak to you again soon. Thank you, Taron. Yeah. Cheers. Take care. Bye bye.
Technologies featured
Meet the Cast
Stay ahead in cloud native
Tutorials, deep dives, and curated events. No fluff.
Comments