 Thanks for coming. So this talk is called Understanding and Configuring Envoy Filters, a Practical Guide. My name is Peter Yaušović. I'm a principal platform advocate, and I work at Solo. I'm also on Twitter, or X. And if you have questions, I'll be here for the duration of the conference. So feel free to stop by and ask me questions on Envoy, or SDO at any time. All right. So before I go into the actual topic and the filters, I want to do a quick overview of Envoy concepts first, just to make sure we're all on the same page. So starting from the left on the image, we have the listeners. And Envoy, we can configure one or more listeners that listen on actually expose a port to which the applications can connect to and send requests to. Once the request is received, the request will flow through the different filter chains, and it's going to end up in the routes, in the routing rules. And in this routing rules, routing rules will decide where the request will end up on. So if we send a request from example.com slash API, and in the routing, we match on that host, and you match on that path, the routes will select a cluster, in this case, example.com cluster. So what are clusters? Clusters are a logical grouping of one or more endpoints, so just a collection of upstream Envoy services. Basically, Envoy can route the traffic to. If we do a comparison here to, let's say, pods and services and Kubernetes, we could say in a way that services or clusters and Envoy are similar to services and Kubernetes, and then endpoints and Envoy are similar to pods and pod IPs and Envoy and Kubernetes and Envoy. So to summarize, traffic flows from the downstream through the listeners, through the routes, ends up on a cluster, ends up on the upstream endpoint where the request is being sent to. So when the request is received on a listener, it has to be processed in some sort of a way, and the way that happens is using filters. The most basic filters in Envoy are network filters that operate on the stream of bytes, and if we have multiple filters, all of them can be changed together, and we call that a filter chain. Now, out of the box, Envoy comes with numerous network filters you can configure and use, so filters like MongoDB, Redis, Kafka, HTTP Connection Manager filter, and so on. So one of the most common network filters, and this is kind of a topic of my talk today, is the HTTP Connection Manager filter. So the HTTP Connection Manager filter, or HCM, is responsible for abstracting away the details of converting the stream of bytes into HTTP headers, body, and trailers for HTTP-based protocols. So the HTTP Connection Manager will handle HTTP requests, and this is where you can do and implement things, such as access logging. You can do request retries. You can manipulate headers, and so on. So the HTTP Connection Manager also has the filter-based architecture, and this allows us to build up and configure the HTTP filters into a chain of filters that operate on an HTTP request. Some of the examples of HTTP filters are course filters, course filter, rate limiter filter, external auth, Lua, RBAC, TAP, router, bosom, and so on. So there's a lot of them. Typically, the last filter in the filter chain of the HCM is a terminal filter, and typically that's a router filter. Now, when we talk about extending Envoy, what are some of the ways and options that we have if we want to extend Envoy? So there's multiple different options. You could decide to write your Envoy filters in C++. I'm not a very versed with C++, so that's definitely not an option for me, but you can build it in C++, and then you can package and build your custom filter together with Envoy, so you can create your own Envoy custom version. This is, by the way, what Istio does. So Istio has a custom build of Envoy that includes different filters. There's also an external processing filter, and this filter allows you, when configured, it allows you to make a call to an external service, and then that service goes and processes the traffic in some way, and it returns back, and it continues the processing in the filter chain. There's also LuaScript, LuaScript filter. This filter is self-explanatory in a way. It allows you to include a LuaScript in your filter, and that that LuaScript gets executed or can't get executed on either request or response flow or both. There's also the Wasm filter, HTTP Wasm filter, and this is where you would build your filter using Wasm. You would create a Wasm library, and then Envoy knows how to load the Wasm filter and or that binary and execute it as part of the flow. So this is all from the Envoy side. I'm more coming from the Istio side. So the question is, how can I do this if I'm using Istio or from the Istio side? And if we know, we know that Istio uses Envoy for its data plane, so it's all about Envoy's there, and basically all the options that I mentioned on the previous slides, they actually work in this Istio realm as well. You can use a custom-built Envoy proxy. You can use a LuaScript. You can use Wasm. The question is, how do you configure these filters if you're using Istio? Now, one way to do this, and a great example here is the Wasm plugin. So there is a dedicated API, Istio, called Wasm plugin, which allows you to deploy and configure, well, configure a Wasm plugin in Istio, but through this high-level CRD. There are other features of Envoy that are configurable through Istio CRD, so through resources like virtual services and destination rules. However, they're not dedicated to one specific feature or one specific filter in Envoy. Like, for example, destination rule can be used to configure multiple things. One of those things could be outlier detection or circuit breaking. Now, even with this, this leaves out a lot of features that are in Envoy that don't have a dedicated resource or CRD. So things like Lua filter, top filter, or pretty much majority of other filters that are available in Envoy. Now, to configure those features, there is a resource, a generic CRD, called Envoy Filter. And you can some sort of think about the Envoy Filter as a way to configure existing filters in Envoy, but also a way to patch the configuration that Istio generates. So how does an Envoy filter looks like? So there are a couple of things that you need to know before you go and start implementing and creating this. So first one is you have to answer the question of, which workloads or which proxies do I want to apply this specific patch to? So this can either be provided through a workload selector if you want to target specific workloads, or you can apply it namespace wide, or you can apply it mesh-wide as well. So once you have that, then you have to figure out, where in the Envoy configuration do you want to apply that patch? So for example, are you applying the patch to the clusters? Are you applying the patch to the listeners, to an HTTP filter, and so on? And then in addition to knowing this general area of configuration, you can also be more specific. So you can say, I want to apply this specific patch to all the listeners. But typically, you're going to say, I want to apply this patch to a listener on this board and with this name. So you have to configure or define more specific match conditions where you want to place your patch. So once you've located, once you have that pointer on the configuration, you'll have to pick out the operation, or how do you want to apply this patch? So there's multiple options. You can add configuration. You can remove it. You can merge it. Or you can use operations as insert before, insert after, insert first in case you're configuring something like an HTTP filter where order matters. In that case, you're going to say, I want to insert my filter before this other filter or insert it first at the top. Finally, maybe the most important part, you have to configure what the patch is. You have to know what the patch is. There's a lot of things to think about, a lot of configuration to set, a lot of moving pieces. But it also requires you, or the operator of the mesh in this case, to know the underlying Envoy Proxy architecture, know the concepts and how everything works, needs to know how to read the configuration in order to be able to use this resource. Sometimes call Envoy filter also used to say that it's like a scalpel, because it's very sharp, and you can cut yourself really badly with it. You can mess things up easily. So here's an example of an Envoy filter. This one is for configuring a listener filter. Because I don't have a explicit workload selector defined, I am applying this configuration to the namespace, meaning to the workloads, actually the proxies that are running next to those workloads, in that namespace. The next section is telling us to where to apply this. We're applying it to a listener filter. But then additionally, we're also specifying in the match conditions. We're saying that we're applying this for sidecar inbound traffic. And then we're also specifying the details of the listeners we want to match. So we're matching specifically the listener with port 15006 and with that specific filter name. Next section is the operation. We're saying we want to insert the configuration before whatever the previous section is pointing to. And then lastly, we're actually configuring the filter where we specify the name and the type to config. So how do you go and configure an HTTP filter? So I've extracted a couple of things from that previous example. I'm going to talk about HTTP filters specifically, but the steps and ideas are very similar for listener filters as well. Now the first thing that's not on the slide because it's the easiest thing to figure out is where are you applying the filter? Are you applying it to specific workloads, namespace, or mesh? So I have left it out. That's fairly easy to figure out. The next one is to figure out the direction. So do you want the filter to process the requests at the gateways, at the Ingress gateway, or Egress gateway in the mesh? At the sidecars, or both, then if your decision is sidecars, then you have to decide whether it's for the inbound or for the outbound flow from the sidecars. Once you have that, then you have to be specific to define order. So you have to ask yourself, does it matter where in the list of HTTP filters is my filter placed in? If it matters, you have to make sure that you point to the correct section in the configuration. And this also tells you how to write that match portion. So if you want to run the filter as the first one in the chain, you would say insert start, or insert first rather. And then if you wanted to run it last, or before the terminal filter, you would point to the terminal filter and say insert before that one. And then finally, the filter again. And there are three things that you have to know here. These are the filter name, filter type URL, and then the actual filter configuration. So you have to know how the filter configuration looks like and all the different things that you can configure. All right, so I have a demo, but I don't know how I'm going to do this demo with holding a mic. So this is going to be interesting. I'll try to type with one hand. And before I do that, I might have Matt come over and he's going to be very nice and he's going to hold the microphone for me. I'm trying to stall a little bit now because I want to mirror the screen. Is it mirrored? It is, right? Perfect, all right, so I'm going to go here. And actually, I'm going to go here. So let me show you an example of how to configure the IP tagging filter. I figured this one is a simple enough to configure. And one note on the Envoy documentation, it's great, there's a lot of it, but it can be sometimes, for me, not an Envoy person, very hard to navigate. But anyway, I'll show you a way that you can extract the information that you need to configure your filters. So first thing that we said, we need filter name, we need filter type URL, and then we need the filter configuration. So reading about the filter, what this filter is about, you can get this on the actual filter page. And this filter page will also typically tell you the type URL that you need to know in order to configure this. So I'll just copy this. I'll place it here. I already have the full configuration set up because I'm not that confident in my abilities. And then in the v3 API reference, in the API reference page, this is going to take you to a new page. This is the page that will actually tell you the different fields that you can set for this specific filter. And additionally, it will also tell you the qualified name of this filter, which is another thing that you need. So I'll copy this one as well. I'll just paste it here. And then it'll magically transform into a YAML that's working. And then the other stuff here, this is the actual meat of the filter configuration. This is where you would go to figure out, oh, I need to figure out what this request type is. OK, so it's a type of request. And this is what I mean when I said the documentation is complex, because if I click here, it's going to drop me down on the page somewhere. So I have to figure out where I am. So I lose my original place. So OK, so this one has a default value. It's both for internal and external requests that I want to tag. So let me scroll back up. And then I have to set the IP tags. This is a required one. I have to set the IP tag name and the IP list. So this is a string. This is a cider range. So let me click here. This takes me to a completely different page. But anyway, maybe I'm over exaggerating here. But typically, what I do when I have to configure any filters, I open tabs for each specific link that I click. So I typically end up with 15 tabs open for one filter. And then I have trouble figuring out where I am and where I should go. But it's something that I was planning to do in the Envoy configuration. It would be so much nicer if every filter page had the name of the filter, had the type URL, but also an example that shows me, here's the basics of the basic configuration just to get you started. And then if you're typically going to have to go and dig deeper, but it will just make it easier. So anyway, so I have all these things. And I'm going to magically switch back to my created configuration already. So I'm calling this filter IP tagging. It is an HTTP filter. I'm applying it to Sidecar Inbound. I'm matching the port number 80, because that's where my HTTP bin pod is listening on. And then I'm specifying a filter chain. I'm specifying HCM, HTTP Connection Manager. And then I'm specifying a subfilter. So I'm saying, well, within that HTTP Connection Manager points to this last filter in the chain. So router is the terminal filter. And then I'm saying, I want to insert something before that filter. So how do I do that? I use that name that I copy pasted. I specify the type URL down here. And then under the values, I'm actually pasting and we're specifying the configuration for that filter, which is very simple. And it's saying, my IP tag name is helloonvoycon. And I'm going to apply it to all the IP addresses. And what is this? Are you OK? Bless you. So what this filter does is it will set a header called exonvoyiptags with the string, with the helloonvoycon. So let's do this. I have a Kubernetes cluster running. I've installed this here already. Everything is here. I don't have to pull any images anymore. So I'll just apply this filter. So this was created. And if I curl to my HTTP bin service, if I curl again. There you go. So we should see the exonvoyiptags, helloonvoyapplied, meaning I successfully applied my envoy filter. So this was a quick demo. And then I'll switch to, what's my time? Five minutes. Perfect. Perfect. If I can find my slides. There you go. And I can hold my mic. Thank you very much. So it's Matt. Thanks, Matt. All right, so last, I have one last slide. And this is just a collection of different, I guess, tips, maybe, what things to keep in mind while you're configuring filters or if you're configuring filters. I've mentioned the extensive documentation. Everything is out there. Like everything is documented, more or less. It just requires 15 plus tabs and a lot of clicking and then figuring out how to pull everything together. Another tip, especially coming from Istio, is just to minimize the moving pieces. Pull down the Docker image for the Envoy proxy. Configure the filter directly in that Envoy proxy for that. Write the configuration. It's like 80% the same as your Envoy filter is going to be. But you take out the moving pieces of the Envoy filter and Istio. Third one, I'm pretty sure at least 90% of you were bit by this at some point, the indentation and YAML. So tip here is you can use JSON as well. That makes it maybe easier to read and you're probably not going to mess up the indentation. Also, for some of the filters I've mentioned, there's no examples necessarily on how to configure them. My trick is to, first off, try the docs if the examples are not there. Go to GitHub and search for that type URL. I would say in a lot of cases, someone else has done the great work of configuring that filter for you and they decided to share it publicly. So you can take a look at their configuration and use that as your starting point. Also, Envoy proxy unit tests. There's a lot of stuff in there as well if you're having trouble with that. Next one is specific to Istio. Not all filters are included in Istio's proxy build. So before you go and try, be all excited about the geotagging or geolocation filter that I found in Envoy. And I was like, I'm going to configure this in Istio. And it's like, well, it's not included. So it's not included in Istio's build, so make sure you check that. Next one is Istio CLI, specifically the proxy config sub-command. If you're working with Istio and if you're doing any Envoy filter stuff, or just in general, if you want to look at the configuration, proxy config followed by bootstrap, clusters, routes, listeners, or all will give you a nice table view of the configuration and all the configured values. Or you can also get the YAML or JSON, if you want, and dig through the configuration like that. And then lastly, one of my colleagues wrote this tool. It's an online tool you can go to, envoyui.solid.io. And it's just a nice way to, if you have a full Envoy config dump, you can upload the file, and it's going to show it in a much easier to read way versus sifting through it in NBS code. Thank you very much. This was my talk. If you're interested, if you have any questions, I don't know how we are on time, but I'll be around here for the whole conference. Stop by, ping me, contact me. Cool. We've got a few minutes now. If anybody wants to ask a burning question, bonus points if you use the question mic. Should I go closer to the door here or no? Thank you, sir. There's a question. I've had recent experience writing Envoy YAML, and I found that GitHub Co-Pilot is pretty good at writing boilerplate, so it'll take a lot of pain out of that. That's a, yeah. It won't get it right, but it'll get it close enough, but then you go read the docs. Yes. That's having to start. That's a good point. So GitHub Co-Pilot, really good at YAML and replacing you searching the GitHub and figuring out the thing. Yeah, that's a good one. Awesome. Well, thank you very much. Hope you have a great rest of the day and the conference. Thank you, Peter.