 Hello everyone, welcome to the next session about the streams and services from zero to hero. My name is Val de Marqueredo, working at Cynadia Communications. And my name is Jaime Pena, and I also work at Cynadia Communications. And in this talk, we're going to give a quick intro into what is next and so the things that we can do with next. And also give you a fun and demo of NET's chat application where we're using some of the latest features like WebSockets and decentralized authentication and a lot of YAML examples to deploy on a Kubernetes cluster on DigitalOcean. So what is NET? NET's 10-year-old project actually it became the first commit was in October, 10 years ago. It is a cloud-native messaging system originally for cloud foundry that has as its rates is that it aims to be very performant, very simple and secure and provide an always available dial tone. It has over 30 client language implementations. The clients are the protocol has not changed a lot in this decade. It has almost stayed the same just in this year there are a couple of new additions actually, but has been very stable protocol. We say that it is lightweight because it is a simple binary that has no extra dependencies. It's a very small Docker image, it's written in Go. It doesn't take a lot of configuration to just have it running out of the box. And NET's client only requires to be able to present the credentials and a single URL or to which from a NET server that it can connect to. And after that it will discover the topology of the whole cluster and I will be able to do that reconnect or failover to other clusters. And has a very simple API that we're going to cover in this talk. Has many clients, unlike with other projects, most of these are maintained by the official maintainers for NETs. So all of these NETs.go, which is the main implementation for NETs, NETs.ruby, which was the original one, are all maintained by the core team. So NETs in a nutshell is about streams and services. What is a stream? We say that a stream is essentially a flow of data, some sequence of events that you either want to replay or consume the last, the most up-to-date information. But not only can you do streams with NETs, you can also use services similar to how you are used to using HTTP endpoints or gRPC endpoints for receiving and sending requests and sending out responses. You can do that one-to-one communication with NETs as well. But thanks to the pop-up DNA from the project, you can also, for example, get a single request and expect multiple responses. So you have multiple communication patterns when using NETs. And you also have load balancing. So you don't need, I don't know who needs to hear this, but you don't need an extra service mesh to get load balancing for making the request responses and distributing work. And when using NETs, you're always interacting with subjects. Something very simple, like a fuller weather subjects where you can express different interests, for example, using wildcards like food.bar. And you can also make a match on food.wildcard that will match anything on that level of the subject namespace. Or you also have the greater-than-wildcard that will tap into the traffic and receive all the events that you are allowed to receive, because you can also have defined the permissions of what streams are you are able to consume. So those features on NETs translate into service, streams and services. In terms of the API from the clients, you can say that we're using, whenever you're using request and response, those are, we're talking about services. Those are usually load balanced using the Q-subscriptions. But you can use a Q-subscription for either services or streams, actually. And whenever we do a regular pop-up, publishing and broadcasting a message or having a stream of messages, we're, of course, talking about streams. Publish, as I mentioned, you can broadcast messages, in this case, publish on food, anyone that is connected to NETs and receiving, subscribe to food, we receive that message. With request and response internally, all this is all pops up. So we're using unique inboxes to announce that you want to, you're expecting a single response on your client inbox. So that's, you can get one-to-one communication that way. And you can also do load balancing by just the Q-subscriptions, by defining, for example, like a worker group. So these set of subscribers are going to be able to load balance the work amongst them. And so those were features that have been since the beginning with NETs V1. In NETs V2, the project took a leap, where we're not only talking about being the NETs within a single silo. Now you are, we're considering NETs as part of like a much larger, part of a much larger system of connected devices and also workloads, for example. Now it has NETs V2, it's a multi-tenant, a multi-region, you can place clusters of clusters or just clusters, nodes in the edge. And so it is a multi-tenant because each one of the services or streams will belong to an account. And all of them will have different subject namespace that will not overlap to each other so that it makes it very flexible to have, for example, give different teams their own namespace or account for sending messages and then discuss among them which services or streams they want to expose to other accounts. So in this case, have the Acme and CNCF, they are exporting and importing services from each other. And if you subscribe from imports greater than, you can receive all the messages that it is exporting from Acme account. And the same with streams, so those services from, let's say, Acme account can be imported and mounted as an API within your own subject namespace and interact in your own local account with the service from another place. So there's many data sharing features, parts of the NETs V2 deploying. So, launch. And also very interesting from NETs is that we have more available network topologies. Also, now you can have very complex network topologies using NETs gateway connections for creating clusters of clusters. So you have like a hybrid, make a hybrid, set up a multi-region super NETs cluster with different Kubernetes, let's say in different regions. You can also have and leave notes connected to, with edge connections to any part of those larger supercluster. And these can have its own off mechanisms that are different from the ones that are part of the supercluster. And they can be a basic chain. So you can have map, better, not supposedly to how it fits your organization. So this has become consolidated into a pattern that we now call the NETs adaptive architecture. So we have seen something regularly. You have a NET supercluster that tends to be in the cloud, for example. Or in this case, one very cool demo that we saw is that it's using the ground as the main cluster and then satellites have a leave note connections connected to the ground and be able to, through the leave note connections, exchange messages to each other. But all of them are different Kubernetes clusters, different network domains, but just the NETs connections makes it forward and routes, makes the routing possible between those different clients. So the rest of this talk, we're going to go over how some of the internals of NETs.chat application. This is like the third iteration that we have gone through this demo. And we're using some of the latest features for NETs. You found me with some of the previous thoughts from NETs. Maybe you have seen the CLI UI that you can just be able to talk to the other users. We're using some of the latest features from NETs to do the same, but with web sockets. So you have a web socket, a single page application that is going to give you a UI for able to send messages, and these are all streams. Each one of these, the users will have its own credentials provision to them on the fly. They're able to publish messages on one of the general rooms and also have its own DMs, and we're using the unique public key for each one of the users to be able to get those and send some basic hardware events for receiving the messages. We also have a service to be able to get those credentials. In this case, it's going to be chat.rec.access. So whenever you go to NETs.chat, which is going to be a service that is available at the time of the conference as well, if you want to try it. So you pass a username to this chat and under the hood where it's going to happen is that it's going to make a request through the web socket to connection to NETs and expecting some credentials, for this cluster that are going to be coupled to your username. And the way we have done this is by creating two different accounts. So actually all the users are going to be within this KubeCon account, essentially the chat account. So any user that we create is going to be part of this account. And there's another account that is going to have the logic and the permissions to do the creation from users that belong to this account. I'm going to show what I mean by this. But the API itself is under the admin account being imported for the chat account and be able to make requests through from account to account via imports. And also we will show how we added an admin UI where you can do some dynamic revoking of users. So let's get into the demo and show how to get this done. There is a read me within the Natsaio KubeCon 2020 repo that you can follow to be able to have a similar setup as we're showing this. In this case we have a single Kubernetes cluster that is running in digital ocean. The first step that we need to do is install NSC. So NSC is the tool that you used to be able to create accounts and users in Nats. In this case we have already created a couple of accounts. One of the admin and the other the chat account. We have a simple installer for NSC here. There's another script able to get some initial setup of accounts. I have a directory tree on the new folder. But we're actually not using those accounts. We have created a chat account and an admin account in this case. You can use NSC to describe the permissions. In this case we can see that the chat account is able to... It is exporting chat.QubeCon online stream. This is mostly for the UI to be able to display which users are connected. And for later revoking. And Jaime is going to cover that in a bit. You also have importing the chat.red.access service to be able to create credentials for themselves. And as for the Nats admin, we have basically the reverse. We have the exports and imports to the other account. And something you can see from this output is that we have... Something that starts with an A, it's an account. And in this case we have another signing key. Which is used in case you don't want to be coupled on a single pair of keys. You can have multiple signing keys and revoke them as you want. To be able to encase one of them and get leaked. Then you revoke that signing key, remove it from the JWT definition. And do the upload to the NAT server and that way you can purge that signing key. And using NSC we can create users. In this case we only have users as part of the admin account. Because we need a couple of one to be able to make those requests. And mostly for the UI to get updates as well. And the very simple credentials that you can use to make requests. So these are credentials that you can do almost anything with them. The only thing you can do is to get credentials. So other than that they are very useless credentials. And does not get in the way from the other users. So we do those in person exports. And then following the rhythm you can how to do it on your own. And once we have all that set up we're going to create a configuration for the resolver. In this case we're going to be an embedded NAT account server within NATs. And we're going to upload this configuration to Kubernetes. So that all the NAT servers can act as a decentralized authority of the JWTs. So now as for running this on Kubernetes we maintain hand charts for the deploy. And to be able to have external connectivity. We're first going to have to set up a domain in this case where you see an sfo.net.chat. And have a single IP mapped currently. So the way this works is by using external DNS component. Bitnami maintains a very good chart for doing this. For managing external DNS. And it's very simple to use. In case of digital ocean you just point your DNS servers towards your digital ocean account. And then deploy it with your API token. And now you can map NAT servers to a public IP. And of course we have opened the firewall for this. And we are also going to be creating a WebSockets load balancer. So one of the things with NAT is that the TLS doesn't work with most load balancers unless they are L4 load balancers. Because of the way that the TLS operate happens. But with WebSockets now that's no longer a problem. Because WebSockets you can have a fronted load balancer, load balancer to the multiple NAT servers, the WebSocket port. And it should just work. Because it doesn't follow the same protocol issues. So we have uploaded the NATs account. We set up a couple of NATs, let's encrypt certificates. And do the upload of some of these credentials that we are going to be using to be able to provision the clusters. Do the upload of the... We need to do the upload to feed to the NAT server what is the latest state for some of the generalities. So to save some time I really have done some of these. So I can show you how it works. So if I try to do a telnet to sfo-nats.chat. Right now I should get initial info line to which I can start NAT's connections. And if I do the same to the NAT's WebSocket port, in this case 433, I will get a similar info line, but not just for the WebSockets. And expecting for me to send the credentials so it's going to disconnect me. So I'm going to show you a little bit of the code of how we are issuing the credentials. It's actually quite straight forward in terms of the NAT's API. So we are just exposing a Q-scription to the subject to be able to get those requests. So let's try that real quick. Let's make some credentials to be able to use the NAT's chat application. So I'm going to have a, let's say, 23. I'm going to create some credentials. And whenever I make a request to using those bootstrapping credentials, I'm going to get a new set of credentials that I can then use to log into the chat. So now I'm going to log into the chat. I'm using this new credentials, my credits. So I'm connecting to the system. And that's it. So this part of the provision there is creating the username, generating new credentials that have just used dynamically to be able to connect to the system and announce the revoker later on that there's a heartbeat from someone connected. But even cooler, it's going to be that UI that Jaime is going to show in a bit. So this is NAT's chat. And I'm going to be able to interact with Jaime from the CLI, but he's going to be doing the same through the WebSocket connection. So while he just showed us the CLI version of NAT's chat, I'm going to give you guys a walkthrough of the, what the front end application looks like. So just a quick demo of what the front end looks like. So when you hit NATS.chat, you'll be taken to this welcome page and you can register a username. And so I'll go ahead and do that. And then you get taken into this place, into this chat room, and you can send messages here. So how did we do this? Well, let's go look at the code now. So to start off, there is a NATS WebSocket library that you can use in your projects. NATS.chat is a React app. So that's what I'm using here. The imports, there's just three imports, one used to connect. The string codec is just used to translate between the JavaScript string and a JavaScript uint array. And then you have the credentials authenticator. So what does it look like when someone registers? So I have this register callback gets invoked when you click the register button. So the first thing we do is use the restricted creds that Wally had mentioned earlier. And these creds can only ask for full creds. So these are bootstrap creds. So, and we're connecting to the NATS server, which Wally mentioned before. So once we have the initial bootstrap connection, we're going to ask a NATS server service, the provisioner that Wally had mentioned earlier, we're going to say, hey, can I get some creds for this username? And if that all works, then we get a message back and then the message contains the upgraded or full user creds. We're also closing the previous connection just because we're done with it and we don't need it anymore. And finally, once we have our new full user creds, we call connect again, but this time with our real user creds. And this will authenticate us with the NATS server. So then if we were able to get into this then call, that means we were able to authenticate the new credentials work. And we are, we can access the real chat room area. And we're saving the creds, for example, here in local storage, but you might be able to store them somewhere else. Also, I'm using the like promise syntax, but the NATS WebSocket library fully supports async and await in case anyone was curious about that. So that's how we got here to this to this area. So now when we get to the chat room, what happens next? Well, the very first thing that happens is this is like when the page loads, if you're not familiar with React JavaScript, basically we connect again. So using the full creds that we got from the welcome page. And then here's where we set up some streams while I had mentioned these earlier as well. So we have a couple of different streams. We have a stream of messages for the KubeCon channel. It's this channel right here. We also have the NATS channel and the general channel. And additionally, we have the online status. So every user when they log into the app will send us heartbeats and that's how we know who's online. As you can see here, WallyQS2 is online and he sent a message. Yeah, cool. So and then finally the last stream that we set up with the WebSockets is the DMs stream. So this is where we can receive messages. Wally can send messages to my public key and the public key is taken from the credentials file that the NetServe, that the provisioner gave to us. And that's where I can receive streams. The heartbeats, this is happened here. So it's just a simple publish on an online topic and then I'm just sending people my info, my public key and stuff like that. The interesting part when that Wally is going to show in a bit is how we handle revoking is here. So we're going to be connected to the application and as soon as Wally hits the revoke button, this callback will be invoked, which will mean that we've been revoked. So when a user is revoked from the system, they receive a notification and the application can handle that. So in our case, we're just throwing away the credits because they've been revoked and they're no good. And then we get redirected back to the welcome page from before. Wally does a revoking is also a UI that we've made. And so that's a special path here that is accessible, but you won't be able to revoke anyone unless you have the right credentials and Wally's going to show that in a bit. But how that works is, I mean, pretty much the same as we've seen so far. We connect using the credentials while we will show that. And again, we have a stream, we set up a stream to receive updates for provisioned users. And that way the screen gets populated with, you know, the current users that the system knows. And then we have another math service, where we just ask the system. This is one of the page loads. We'll ask the system, you know, hey, tell me everyone you know about right now. And then we just save that data. And yeah, that's that's pretty much it for the code. It's not too difficult. Or nothing too complex. It's just connect. And then you can set up your streams, or you can do your services. And that's it. So I think Wally is going to show us how to do revoking next. So I'll hand it back to him. So let's see, make hosts. So I'm going to show because I have the credentials, Jaime doesn't have the credentials. I'm going to do the disconnect by run to drag and drop some of the credentials here. And I'll get an event of the currently active users. We have included connected here on the console. Send a message to Jaime reply back. I'm going to. Then I'm going to. This is going to have my first. And also yourself. And I saw this connect. And that's going to give me a user authentication revoked error. And the left side of the screen and showing you can see that what what is happening essentially is that we're making a request to another subject under the admin account that is able to respond to these actions. And using the system credentials, the provisioning is able to use some of the special APIs for Nats to able to make a lookup of JW the latest state for the JWT. So we're getting the latest state for the JWT. And also, adding. Inspecting the current to the with the JWT and adding padding padding with a user public key that is not going to be longer used. And then I make work using issuing another request. To be able to update this JWT and we encode it using the. So we make that update because we're using the latest NAT server that now hasn't embedded NAT account server. We don't need extra components. Everything's going to happen in the NATs node and it's going to be shared the latest state of that generality. And that's it for the demo. And we'll be standing by. This server is going to be alive during the KubeCon as well. So if you feel to try it, we'll stand by for the Q&A. Thank you.