⚡ Secure shell (ssh) client in 80 lines of Go code

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so here we are again uh it's Christmas time we're having a lot of fun coding doing some recreational code but also doing a little bit of work code and one of the requirements I have at work generally speaking is to make a remote connection between one server to another and in this case the server is a pod inside running inside a kubernetes cluster and it needs to be able to make an outbound connection a remote connection to a you know another computer that's actually running batch processing and stuff running machine learning jobs and things and it needs to be able to go out to that system and talk to it and and do something on it to write you know call a command or run a command and the tool if you don't know the tool for doing this since it's a dawn of time has been pretty much the dawn of secure time and before I was telling that right but but for now it's secure shell so what is secure shell secure shell is what allows you to do remote connections you know you can most of you probably familiar with it so you know like SSH into um let me just let me do that over again as SSH into uh as blah I set up an account called Blah over here at localhost so this is a remote connection we'll pretend like my localhost is is a thing now I didn't I didn't tell it what uh secure key to use here and I'm actually going to cheat and I'm gonna try something I I just kind of a fun little thing I think you can actually set the identity and I put a I put a fake identity in my in my test directory temporarily so yeah I previously yes and I committed it to GitHub it doesn't matter because it's just local it's account will be dead after his uh oh no it's a private key file uh has bad permissions so it didn't like that all right well let me try that I don't do this at home don't put private keys in your GitHub unless you absolutely know what you're doing you'll get flagged and stuff the reason I did this is because I was testing the use of a project I wanted people to see what a pen file looks like as a private key so it's very deliberate I don't want anybody to get the wrong idea but just for the sake of this test I wasn't planning this I'm going to go ahead and shut the permissions down on this temporarily to see if I can demonstrate what it means to use a a key file to make a connection um and as you can see I am now connected I mean you can you can imagine that locals in that case was another machine so what I did is I made a remote connection to the same machine and and I told that I wanted to use that identity file that specific identity file now the identity file I'm going to show you the identity file let me say this again do not show people your private key files right I'm doing this for the sake of demonstration with an account that's been locked down and you're fine so so this is what these files look like right so you have this private key oh no you know rewrite that down right so this is my private key this is this is in a format called pem pem I don't even know what Pam stands for what does pem stand for I don't know Pam stands for that's not it let's see Pam stand for crypto and we're not talking we're not talking Bitcoin we're talking like actual crypto uh the pen file what does it stand for someone someone fill me in I cannot remember back his partial invitation message all I've ever heard him call his pen files uh the pen file standard by the way came you know what I know what we can do MGO dock encoding slash Pim yeah there's like an entire Library just for PIM package pem implements the data income motion originally which originated in the Privacy enhanced email really pem stands for privacy enhanced mail I did not know that I learned something today so pimp stands for privacy and Hess Mill which is you know open pgp and and gpg and all that stuff so so that's where Pam came from that's kind of cool I did not know that Jonathan anyway so so so so so that's going to become and become an important thing later um oh no there's my private key again so as I said so this is the traditional way of connecting so you can normally it will try to find your default identity uh when you're using SSH when you said SSH I assume you know a little bit about SSH but this is what we're doing and so then you connect as that user at this target host right and and if I wanted oh that was nice and and so if I oh look old sad man gave me five dollars isn't that awesome so then we could go here we could do we could shmod this uh well we already spotted the file so if we did an SSH into here and we did colon 22 that's the default Port right but normally you would have you don't have to see the port so like if I try to do Port 23 or something it won't do it if I do 422 it'll get there and it'll get in just fine uh that's interesting it doesn't have a port oh no it's not 20 is it 22 it is 22. 100 like 22 it should like it I don't remember let's try it is okay so I I always forget it's not a okay that's that's important so if you're using the command you have to do Dash p you can't specify the port in the target apparently I mean I thought you could I guess not so SSH username report do you have to put ssh in the front oh I didn't know that okay I learned a lot of things here so let's do that let's put ssh in the front we'll put SSH uh in the front of here I this is mostly for my own interests uh I have never done it this way so I want to do it this way so let's say a user at localhost colon 22 how's that is that going to work what all right well I don't ever do that but now you know so so you can actually do that you can actually go connect to it using the SSH URL or you can write it all out you actually can do it this way too you can do Dash U blah that this I know and then Dash p they do that on Mr Robot actually and uh uh I don't know why that's not working that should work do they have to be in the right order this is why I don't like Get Up by the way I do not do not like get up I don't know we're just having fun here what is the you I mean I don't do any of these things usually so this is why I'm doing it this way oh so we're not doing the tunnel the login name oh l l l it's l it's all okay there we go so that should work all right so those are all the different ways to use SSH as a client you know client server kind of thing server you know the client is the thing that connects into something and so so that's that's what we're doing um that's really good we're gonna go ahead and go ahead and do that uh but okay so how do I translate uh this kind of thing into um bin um so how do I translate this sort of thing into go so I don't have to install SSH I can just use it from a container and do all of that stuff right how do you do that how do you do that well this is going to be how I'm going to show you that there's one other thing that we're missing uh and I'm gonna I'm gonna simulate it actually so give me a second to simulate this I want you to see oh we're doing all the things you would normally do from the command line and then we're gonna I'm gonna show you how to do it from go code without the command line okay and what we need to do is get rid of a known High Century for blah uh for localhost so we have a local host entry in here this is this is where all of this stuff gets added and I'm trying to see I think we already have a local host entry in there I don't know I'm trying to trying to figure out where that one is and I don't know the access h command for this but if we were to go in here one of these things has our host ID in here you know what Let's do let's just temporarily move it so if we move that SSH known hosts I mean this isn't going to hurt anything it's just moving into temp get it out of the way now if I try to make that connection again this should bark at me and say I don't know who that host is I've never connected and the way what happens when you do this is it adds a fingerprint which is really not very secure but it's usually everybody always says just yes it's supposed to protect your Yes Man in the middle attacks it means that you've gone in and you've said okay I trust that this connection to this you know our IP address our address over here is the right thing and therefore I'm going to add it into my my known host and then uh yes um it's not my internet so go ahead we go ahead and add it and then it makes a connection right and then we go over here and if we go look at this known host file you'll see it's got uh oh look at that it added an entry for every one of the keys that I have that's interesting I didn't realize it was gonna and I I believe the way to look at that is SSH uh uh which one is a key scan key scan and don't worry this isn't private this is key scan will show you all the all the IDS by which this computer is known right and I mean localhost is known so if we put local lists in here those are all of them right so these are all the local centers this is very important so these are public keys I want to say it again this is not violating my security anyway this is these are these are public keys that are listed in this way using a specific format and you can put these these lines in your authorized underscore uh Keys file or you can put them into your known host file which I learned the other day that is actually the same uh and so so now you've got all this stuff in here right that you can use to connect and and and and that way when you make a connection and this has happened to me before I've changed the IP address of of a machine that I without changing its known host entry and SSH does not let you connect to it it's like oh I'm sorry you can't do that that's uh you know it's invalid because you know it's been changed somebody's messing with you with the IP and you have to go in and explicitly take uh you know those known hosts I'll tell you the line you have to remove and you have to you can do it through a command as well and you have to remove those those lines right so that is that is kind of like a super crash course in SSH now this this video isn't intended to be about SSH but it's really important to understand that what SSH is before we get into it so you have some sense of it and so when we make a when we make it the code that we're going to write is exactly the same as this the only thing different now so in addition to make if I do it by default it will it will dump me into a shell right and that's fine and and we're not gonna do that today what we usually want to do when we're writing middleware or something is we want to actually run a command over there and we want to capture the output of the command and SSH the command actually allows you to put the command on the command line over here and it will just take whatever the remaining arguments are but in this case let's put them all in a thing so we could do ls-l tilde right now this is something I found is interesting is that uh thank you so oh there's nothing there right so let's do ls-l but I want you to see that it actually resolved uh it actually resolved the tilde okay and so this is this is going to be important when we come and write our go code so what it does is it takes this argument and if you if you put a bunch of arguments independently I think it also does the same thing but mostly though it's probably better for you to combine them because otherwise they're going to like run into these arguments right they're going to conflict so this last argument here is the command to run on the server the the target server so it ran that command it made a connection as blot ran the connect as well in fact you can do anything here you could do um you could say like like I don't know Echo dollar user and you see how it's it's quoted so it'll actually resolve user on the target system and you know so this shows this proves it that it's running it as as user blah on after it's made remote connection and it's dumping the standard error and standard output to my terminal having done all the work remotely and then come back and you can actually check uh the return codes uh you see it's a return code is zero because it was true uh if we do stuff like this let's let's try to do something we can't do so let's let's cat Etsy uh Etsy secret which it does not have permissions to do so this will not let it happen and you see that we get we get a one return code because what this is right we get a cat now this this looks like it ran on the same on the local machine but it did it it ran on a remote machine it just we just happened to be emulating a remote Machine by connecting localhost so so it's making the connection right and it's dumping this this is not going to standard error though I'll prove it so if I if I redirect uh the standard error which is two uh to devno that should get us um oops let me try this I don't know if I have to oh wait wait wait wait I have to do it right here yeah to redirect to devnoll remember two the two uh file uh uh descriptor is to have is a standard error and so that as you can see goes away right now if I do something successful it will spill print it to standard standard output instead of standard error so there's two output streams and they mix to get mixed and hard to tell apart but those are the two things that go together and so then we're going to have ls-l on this and we see that oh hey you know it it didn't do actually that sent everything that's interesting huh Why didn't it what did it set to it should it should be oh there's no Etsy secret no such file directory and secrets yeah of course all right so all right now let's let's what no it says the secret why does it say it doesn't exist that is weird it's it definitely exists wait did they move it you guys know that it's your password is the secret right that's weird did I kill it I didn't do anything as rude yet that's very weird to me yeah I I'm having a brain fart or something this is Secrets where the actual passwords get stored and stuff it sounds like they might have got rid of it yeah that's very fascinating that's due to me anyway um did they change it on a budget server when do they get rid of it I mean that's that's been a standard thing forever uh either that or I deleted on accident which is also possible uh and I just snap back I don't I don't I don't I don't think that's the reason I think it might be something related to Pam actually yeah that that's that's got me a little confused yeah I'll go back and look at that but yeah I mean now you know so Etsy passwords just you know there's nothing wrong with me showing you what's an Etsy password right so Etsy password is where all of your accounts are and it used to have it used to have this the secrets in there uh where the x is right um and then they stopped doing that and then they put that on just oh Shadow did I put that you know what it is you know what thank you so much I feel like it's being stupid it says the shadow of course it's I it's the kubernetes has ruined me because everything in kubernetes is a secret secret secret right and it's of course this event that's the Shadow the whole entire time oh my God oh my God my I am so lame I'm lame I'm a lame old dude just like that troll said so it is because of kubernetes uh it's actually shadow okay so there we go so it it shows that it's there and everything but what I was trying to show you is that that output is not standard error right because if I redirect uh to Dev null you'll still see it because it's standard output in a standard error so if you don't know the difference you know look into it but that's going to become important because we're going to write our code it needs to capture so so here's the requirements for the code we're going to write right we need to create a function that basically does this it does that but without installing secure shell that is the goal we want to be able to tell it where the identity file is which is just a pen file that's got a secret in it because the pub key can be implied from the secret the reason we have to have the C the secret in there the private one is because it has to be a signer and it has to be able to sign the content and the connections and everything and so if you have it you can't sign anything without a private key I mean you can sign up with a public key but then only the person with the private key can read it it's a different thing but in this case we need the private key so we have to tell it what identity file so that's the first requirement we need to tell what we want to connect to like this now we we are actually going to end up uh creating something because this kind of kind of convoluted weird way to writer right why don't we write it in the nice happy ways you know using the URL and we just write blah and you can actually put a password if you're doing password we're like okay that's important I say that too so SSH does allow you to password logins but if you do it you're an idiot nobody should ever allow password logins for SSH ever there's never an excuse to do it ever I don't want to hear it I don't want to hear it there's no excuse uh so don't do it so localhost 22. so this that this is what we're connecting to right and this is what we need to recreate and we want it we want to take the standard output and the standard error and the return code and we want to have all of that stuff available to our go code directly without without sub shelling out to call SSH or anything like that so that that's the requirement here right very very very common use case uh and I mean you know and so so so if you want you know the first thing you might do is you're like trying to do this will go is you might wander in you might wander into the go uh crypto uh package right crypto SSH and you'd be like okay let's read this and this can be overwhelming first of all I want people to understand how SSH works in the first place and setting it up just with SSH clients but let alone them but you know then they throw you all this stuff because SSH is much much much more than just a way to run a remote command it's you can do tunneling it can do interactive sessions it can it's just really amazing and and it's the it's pretty much the basis of of of all operations Communications these days that in TLS which is the https stuff so so then um I mean if it's if if you're remotely connecting to a computer these days you're using you're either using one of three things you're using httls which is https you're using which is socketing based encryption you're using SSH which is interactive socket based encryption like we're going to do today or you're using content encryption which is openpgp or gpg and then you're encrypting the content and you don't care how it gets sent around and that's how I do for keg because I don't necessarily want to depend on you know secure protocol tunneling but so those are the three ways to to communicate securely uh in you know 2022-23 so but if you look at this package you might be overwhelmed because you're like my God look at all this stuff here we got user server Keyser algorithms what's our RSA should I use RSA should I use ed2d509 what should I do oh I'm marshalling and I'm marshalling public Keys uh you know there's just so many things it can be really overwhelming so today the goal of today's video is to take away the complexity of this and to create some sensible default assumptions and do you know essentially what we just did with our use case and we're going to be making some some so we're not going to be using password callbacks we're going to be using public keys we're going to make a signer uh and we're going to create a client and then we're going to make our connection so before we get into the code uh uh I I want to write about this a little bit so I think I actually have this in in here um so so so the first thing let's write down the algorithm here okay so the first thing we're going to have to do is we need to get the credentials and stuff right so the first step we need to do is uh get get the user and Target host uh IP and port okay so that's the first thing and then I mean I could do this with I can do this with just one and then a markdown will fix it for me uh so then what after we get that then we need to make we need to dial a connection so uh dial a connection so we actually wait so we need to dial let's see create a client create an SSH client and dial a connection so the word dial is common in the TCP World still it just means that you're made in TCP connection to a thing or UDP or whatever right so we're going to create an SSH client a dial to dial a we're going to use TCP for this you can actually say whether you want gcp or UDP but we're going to use DCP uh how's it going and then so we created an SSH connection we dialed that and now we have a connection now this this is something that as I was doing the research I was really pleased to discover so the SSH Library the SSH client Library once it gets a connection to the Target host it keeps the connection open until you close it which is kind of cool so if you wanted to send multiple commands subsequently you can do that and it's you're not going to have the overhead of dialing up a new connection they even have a way to redirect channels and stuff all of that stuff is really cool but overly complex and confusing to somebody who just wants to run a command on a remote host and so we're going to bypass a lot of that and by using something so once you get a connection in order to run a command uh they have a thing called a session say create a session so a session is not like an HTTP session a session is one execution of a command that's what it is and so you create a session uh uh and Set uh parameters on it so there are some things we're going to have to tell it about we're going to tell it about you know what um you know what what kind of authentication we want what do we want to do with standard input and output does it have any standard input that's right you can actually pipe standard input to an SSH command and in fact let me prove that to you really quick so if I uh let me see if I can find it where was I where's our thing okay so so here we have here here our Command is this let's let's let's change our Command let's change our Command to be cat all right so you know cat the cat command doesn't do anything unless it has standard input right so if I just run cat it will actually hang because it won't have anything to run right unless I give it standard input so let's just I actually want to see it hang let's run it without giving it anything to cat so we're going to run it like that it's like hanging around I don't know what to do we say hello enter and it echoes it back so so the SSH command does some cool things it actually maintains an open connection to the remote server so that's cool and all but for our case of our Command we just want to capture the output right and and it does do some things to save you from blocking like that but if you wanted to to do this I could just pass it in a variable um with I mean any number of ways let's do this so let's say hello there so this will pass in the hello there line and that will run and it it will go into the standard input of cat and Cat will cat it and then we'll see it on our on our output so it's as if we just ran the thing locally right so that is to show you that there are standard input standard error standard out all three streams are involved uh and can be it can be managed and handled okay so create a session and set parameters and stud in if we have it uh uh we might not have set in but if we don't that's why and then what and then we need to uh run we need to run run this session okay we're going to run we're gonna after we get this session all set up then we run it we get it to execute and there's four different ways to run a session and we're going to use the the one of the simpler ways so we're going to run this session or uh to execute uh the command remotely and cap okay and then we're gonna um and then we're gonna uh capture buffer buffer uh buffer the stud out stood air uh into Strings uh and then we're gonna return uh return the uh stud out stud error and exit uh and error if and and errors if any okay so this I mean it seems pretty basic right when I show you the code even though it's only 80 lines it's not there's a couple gotchas in there that I had to Google and search for or whatever I don't Google it um and so we'll go ahead and look for those why isn't that my dictionary that should be in my dictionary for sure so so we're going to add that this is what we're gonna do we're gonna get the user Target host and IPM Port so we have something to connect to we're gonna we're gonna create an SSH client and we're going to dial up a TCP connection to a remote host in this case we'll simulate the remote Hostess being localhost running a server as a different user blah like we were doing and then we're going to create a session that's going to represent um uh you know what it is that we're going to run and that includes the command by the way um and we're gonna like set up all the buffering and everything and then we're going to execute the session we're going to capture the standard output and error we're going to blow that load up into memory and there'll be at least one person out there that's going back that's a bad idea because you're not limiting the amount of memory you're going to be loading up and and I did put a warning on this because this is designed to be the kind of thing you would do for Michelle script no one's going to worry about how much how much you know variable space you're capturing when you load it into a variable when you're writing a bash code right but but when they see go code or something like that they're like oh my God you got to be really careful so we are assuming a trusted source for this so if we run a command we're assuming that the amount of output from that command is is a reasonable a reasonable size that will fit within the memory constraints of the you know local machine that's calling the you know the remote command because it's going to transfer all that data and it's gonna it's gonna buffer it up before it returns it back as a variable there are lots of ways to get around that if we were dealing with like high-end uh you know data and we had a lot of data to deal with and we wanted to open up a concurrent pipe and and and act on it as each line comes in there's tons of ways to deal with that SSH deals with that wonderfully but we don't care about that because as I said the sensible default here is I just want to run the command and get the output and that's like 99 of the people out there they just want to run this SSH command and get whatever its output is and time out within a reasonable amount of time which is kind of a bonus I didn't add that but that might be a bonus that we had uh timeout after a reasonable amount of time and for that we should probably will add a contacts context at some point I don't have that in my code at all yet but it that's I don't know if that necessarily should be a part of the ssh1 command it should probably be outside of the function that we're doing uh if you want to set up your own timeouts and things like that and so you know I'll put it there just for reference in case somebody wants to try that all right so let's let's jump into the code and and start to look at what's required to make this happen uh and directory 50 000 yeah right exactly um I mean and there's definitely ways you could put stuff in there if you wanted to limit the amount of input you could definitely do that and and maybe I need to do that let's actually add an issue um uh let's see add package global for maximum uh size of stud out and stud error buffering uh is it we're not because because this is again this is one step above shell scripting so yeah yes we are we want performance above above a lot of that other stuff but but these are all things they're like the next level you know we don't want to do the whole premature optimization thing so we're just going to write the minimum stuff necessary uh well okay so the I don't want anybody to worry so Ryan's concerned here I don't want anybody to worry because in this situation we have exact control over what is being called I know exactly what's being called so for me this level of security that that y'all are talking about with the buffering and everything is is accomplished by the simply saying if you don't trust the thing you're running then don't use this and that's a perfectly acceptable way to proceed with security it's like it's like the balance between checking for nil values on every single input variable for every call to the command you know you kind of have to have uh yeah uh so Ray we don't want to get into that whole uh stuff um I mean there's people that would be so paranoid about stuff like that that they would check every one of these input variables to see if they were nil before they did anything right uh this that's not a use case though in this case this is the way it's not a use case is we eliminate it as a use case note that there are no limitations on the size of input and output meaning run should only be used when calling remote commands that can be trusted not to produce too much output that that is my optimization by saying if you are doing that you're doing it wrong and rather than do all the accounting and manipulation to try to check the buffer length as we go because I would be putting overhead on it I mean there's other things it's like people people will put locks on maps that don't need it and go and that kind of thing so I'm not attacking anybody I just if you want that you can come back and add it but we need to know what the basic thing is what is the equivalent to writing a shell script SSH remote command and buffering the variables that's what we're doing here we're not writing anything beyond that right uh so this and in fact this there was some discussion whether to implement what I've done and go just as a shell script because you can do all of this with the shell script and just redirect it to a file and and call it a day and then go open up those files and deal with them and delete the files and everything uh which I mean you still have the same consideration because you can fill file system really easily especially if depending on the container and everything so I mean this is just the beginning but if you but this is enough to get you the concepts okay so we have a we have a document here that kind of describes the discovery of all this stuff we take a Target um so the target line here is is this right it's just like SSH line and I thought I thought about maybe forcing the ssh in front of it but I thought what the hell let's just do this and so we have the target which is going to get split up here and it's going to become the user and the address down here and then we have um do we have we have a user key the the private key and then we have the host public key and strangely these things are in a different format because I that's the reason I wanted to show you that private that private key was that U key is uh in pen format and hkey is in authorized Keys format so that means it has the local I mean you cut and paste it out of your like when I did the SSH Dash key scan that that's the kind of line that we're looking for here right so that's what this is going to be and this is going to be the pen file that has a private key in it and these can come from anywhere right they can come from a file they can come from an environment variable if that's your thing I don't like doing that but but container people love that um and you know secrets and pods whatever um and then we have the actual command which is one string not you know args all broken down this is actually a command line that gets passed to the Shell of the user which I found very interesting when I was playing with that uh it does resolve glob Globs and all kinds of stuff which uh yeah I don't know how I feel about that um but it does it does do that and then we have uh the optional input string uh which as standard input now you would see this in and go a lot of times you see this is a byte buffer uh again I'm making an assumption here so we are making a bunch of of I think reasonable assumptions sensible assumptions here to speed things along uh for example um these are almost always going to be loaded from a file so they're already going to be mind slices right uh this kind of stuff if we made it into a bite slice we'd be casting it as a string and all kinds of things and like well what if you want to pass standard input that's not a string and let's say well then use a different function this is not this is a function that's designed for the most common use cases like I wanted to type some things into the command line and have them run and I wanted to send it a text file or something like that right but I couldn't pass in uh like an image is standard input on if I wanted to here because it's a string instead of a bite slice and I could cast it and everything some people you can make the argument that this should have been a bite slice but same with here so the standard out and the standard area there's no there's nothing that says that it has to be a string right but except for the fact that this particular function is making a sensible assumption that this is the equivalent of running SSH from the command line which means I'm going to be getting a string of set out and a string of stud error it could be yaml could be text could be HTML whatever and then I'm just going to parse the thing and and then we have the error which is you'll see later this is this is how the underlying SSH client behaves to return exit codes other than zero so any exit code other than zero is returned here unfortunately and this is this is the only huge flaw I found with this whole approach is that you cannot get the exit value without parsing the error string and if somebody knows how to do that and I haven't found it yet let me know but the exit error type SSH error type does not embed an integer exit value which I found extremely weird it prints it out it prints it out and you can go parse it other but most of the time we really don't care about the exit value we just want to know that something went wrong and it wasn't zero so I'm okay with that again another sensible assumption so here we go we're like parsing we do strings split the target this splits it on the at sign and then T becomes a a length of two we check the length is exactly two and not more that is um uh that's going to keep us from crashing or getting no pointer errors if there's not if they've done this part wrong and um and then we uh you know there's something new I don't do this normally but when you're returning a bunch of stuff uh like if I were returning two strings and I need to disambiguate on the command line here otherwise I don't want to like string comma string comma string right so this is a this is a convention that's popular and go uh and when you do this though every single return value has to have an identifier right and I've combined these two because they're both string types same over here with byte slices some people don't like to do that I love doing that um and by doing that when I return here you'll see here that this is normally a return error right but in this case I just return I set the error without a wireless operator I set the error and I said and I got a return value and that that means that whatever the present value of these which is these are all you know zero value at that point which is empty string then and then error will be returned so error gets set and that gets returned so it does make you know when you have when you have a reasonably large number of return values and there's you know there are a lot of them out there there are a lot of functions that have more than three return values uh this does make your code a little more sensible when you're you're when you're handling returns and you have to have in return no matter what even if it's at the very end okay so so then we we've got our user and our address and then this is the interesting thing so we need to create a signer as I said assigner is um let me show you so assigner is is basically a private key that has the ability to sign you know content in some cases and you can go look at it here here it says so this says parse private key it wants pen bytes as we said it gives you a center and an error it returns a single from the PM encoded private key it supports the same Keys as partial raw private key uh if the private key is encrypted it will return a password missing error so you can you can actually I don't know why it would but you can actually use uh keys with passphrases uh if you did that though you'd have to hard code your passphrase or load your passphrase from some other place and I uh I guess there's some cases where you might need that but in this case you're generally going to be creating a passphraseless key uh to to do the connection and then you're going to be protecting uh that key itself uh pretty strongly like as a as a pod you know as a kubernetes secret or something and so you've taken you know if you to add a passphrase would be you know in that case in that case an unnecessary addition for that I know I use passphrases for my own private keys and SSH and stuff because if somebody gets a hold of your private key it's your only it's your last defense uh against them being able to use it for anything but but for this kind of thing where we're just establishing a connection we don't we don't really need one so we're just going to do Parts private key there is a uh another option for this um that is uh I think it's parse private passphrase key I'm trying to find it here let me see uh uh MDOC s m go doc SSH so uh where is it parse harsh raw harsh raw parse Raw I said I can find it purse oh there's parse parse and there's art node Keys key there it is there it is God look at that big old long C plus plus like name parse private key with passphrase so you can do that if you want but I would suggest that's more for like creating interactive tools and such which you can do I've thought about making my own lightweight SSH Bonsai Branch just to do connections that comes with me in my monolith so I don't have to install SSH on anything that would be kind of nice huh whether it's a back door that I've established or it's you know it's an operation system that I don't want to install SSH on hmm okay so so here we have we we have the we bars the signer out now the uh we're gonna use the signer later that the signer gets used down here in our authentication method so this I'm kind of jumping ahead to the dial thing but we're doing two things at once we're we're we're instantiating a client configuration and we're passing the client configuration SSH client configuration to uh our dial-up connection which is going to return a connection so we're kind of skipping the step of creating the client explicitly uh dial does that it creates a client for us and hands us off a client connection uh if we pass in this stuff over here but the reason we have assigner is because one of the authentication method you can authenticate with no passphrase you can interactively you can you can do host basic thing there's lots of ways to do SSH authentication but the overwhelming industry standard for authentication is to use you know public key and if you're using you know an interactive user system a public key with um uh you know pass phrases on the keys so that means if I were to SSH into something uh it would actually ask me for my password this is how GitHub identifies itself and so you know everything everything works to to do its identification so even though this is a slice and I can put a whole bunch of other authentication methods here I really don't need them right I just want the public Keys one and I have to give it a signer now I could do um comma SSH public Keys comma and I can have multiple public Keys listed here if I wanted to so if I wanted to have that I could but again this signer came from the argument so the goal is to have a single Command right so we're passing in the U key and and that gets that's just a pen private key right file and that gets converted into a signer which we're going to use to do our thing so we didn't have to put it anywhere we didn't have to SSH Keygen or any of that I mean we did at some point much earlier in order to get the pen file before it got passed to the Run thing but but not there all right so then then we have this guy and I got to tell you this this one fried my brain I I was like looking at this and I could I could not get my head around it not to mention the fact that both partha authorized keys and parse uh known hosts both of them work uh I went with parse authorized keys because when you the output of SSH key gen I mean SSH uh scan Keys was it key scan the output of SSH key scan for a given Target is in authorized hosts format by default it's not in known host format and I did some research some preliminary research and it seems like both of them are compatible even though they're different fields and stuff if you've ever look at known hosts we're looking at it it's not nearly as as as informational which is another reason that I like um this way but the the uh the authorized host format for these things for these public Keys uh includes the ability to write a comment it includes uh an optional and optional host up front so so you know when at rest as as text it's it's it tells you what the algorithm is um it's just easier to digest um and manage uh than the the no host format so I went with that now how did I get the key for my target host well I did what I just did I run SSH scan Keys got the key for the one and it took me some time to figure out that the Ed the the ecdc dsa-sha 2 niss p256 was the uh primary key the the that my SSH server is using to identify itself to the client coming in so when the client comes in and says hey I don't know you and he's like oh here I am do you trust me yeah I was like fine okay here's my key and the key and I I might need to look into this a little bit more if you know please put in the comments but the key that it that it said it was okay with it turned out it was this one and so I tried all of the keys that are listed in scan keys and it was this one that was the money one and I had to actually try them all to see which ones would work um so I I have a feeling this has to do with how your SSH server is configured and and right I mean I could have gone through and got the proper command you know the proper line in my configuration to figure out which he was identifying the host from the list and that's in your sshd at the sshd if you want to go find it in there I like the scan Keys command much better it's much easier to do it that way and then I kind of went through during testing and I tried each one until I got a successful connection and this is the one that worked um kind of a hacker approach to figuring it out but um so so so that's what that is that's that's what that's what goes in HQ um what I wasn't expecting and I'm going to put this in there what I was not expecting so if you look at personal authorized Keys all those fields I told you all those wonderful Fields right well they get returned so you get the comments you get any of the potential options uh you get the rest and when I first saw this I was like what the hell and in the air so the one of the things that bit me when I first did this is I I just copied all the I I wrote everything from the scan keys out into a file right I wrote everything out into a file and then I pointed I pointed my test case at the file well and I'll show you that test right now in fact I'll turn it back on right now it's off but I'll turn it on it's one of these ignored example tests so I I pointed I pointed my um I pointed my file at the host Pub Key and I had all of them in there right I had all the scan key stuff out there and it didn't work and then I found out it was like only grabbing the first one and it took me a while to figure out that the command itself is you have to read about it closely but the but the parse authorized Keys file uh only grabs the first one it grabs the first one out of the file it'll continue to read through the different lines of the file and then it when it returns is it Returns the rest variable so the rest variable is all of the bytes that come after that so like you'd have to recursively call this in a loop or something if you wanted to parse every authorized key uh from the file you'd have to run it through a loop and and get everyone but in this case again again sensible defaults we only have the one which means that file that that string that gets passed in is is always only going to have the one file in it and and the reason that it's only going to have the one file in it is because we want to use uh the explicit host key callback uh the host key callback is the thing that does the validation of the host right and there's two of them that they recommend that you can make your own you can write your own extremely elaborate function if you wanted to go out and call out to a service or anything you mean you could you could dynamically maintain all of your authorized you know hosts and some remote service and call into that through security secure method somehow I mean there's so many amazing things to do here or you could just completely ignore it in fact um if you look at this let me show you if you look at um let me see if I can find it so the M dark godoc SSH uh uh I'm trying to find it so there's um okay so here's the other one right so you know most people just say okay I trust you as a host well the equivalent of doing that is setting your host key call back to a callback by the way is a function that's called in order to get the value at the time at runtime that's why it's called a callback because it it it it takes what would otherwise be said as a variable and turns it into something that's evaluated dynamically at runtime that's what a callback is uh people use that for events event callbacks that are you know handlers that are associated with certain things that happen um and so so here we have insecure host key callback so if you set it to this it won't do any host key checking at all so if you are like say you're an internally inside of a kubernetes cluster and you're in an absolutely now there's going to be you know zero trust people they're going to tell me don't do that but if you are in an environment where you are guaranteed to trust every host in the entire system and have no man in the middle attacks you could set this and buy and delete that variable so the H key that I passed in wouldn't even need it at all right the next best step up from that I think is fixed host key which says this specific connection is only to this host that means if you do not know the if you don't have a copy of the public key for that the target host that you're attacking you're trying to connect to it won't work it just won't work it will it will say I'm sorry you've got to provide what hostages that you're trying to connect to and you need to provide proof that that I can run that this is actually the host if you want to get rid of the proof though you can do the ignore thing and and get rid of that okay but the thing that tripped me up the most when I was writing this and and and this was this this this I took a search or two for This was um uh this okay so parse the authorized keys this parses the authorized Keys file that's where we get that format right and you saw what the file looks like right I showed you that already uh you want to look at it again I can show you again so uh if we look at the test data that's why I included these otherwise you know this is what this line Looks like right so this is you know straight out of my scan keys and I just copy and pasted and put it in there so that's what's going into the function so that gets parsed and then that turns that turns into a host key which is a binary the thing that they don't tell you is that it is a binary so it gives you a public key uh and at first you hear public key and you think oh it's going to be another pen file public key right no no no no no no no it's not it's not and so you actually have to Marshal it um and that's what this is about right so and and there's no way I would have known that without searching for it so parse public key parses and SSH public key formatted for use in the SSH wire protocol according to rmc4253 section 6.6 this is a binary thing and and if you tried which I did I tried to pass the host key straight into here and failed miserably because I mean you can guess it right it's it's not the same right so it's not a string at all and and so I could not I tried to put uh the fix host key right here I tried to put the string the pem string for the host key there uh no it just did not work so so so then what did I do I said okay fine um we I did this and then I did parse uh public key and that gives me uh that gives me binary data I don't know if it's a Ascendant one I don't know I I don't know if that's the RFC did you see the link there um but but this step just don't forget this step if you're doing this you you've gotta you parse the authorized key file which is text this is text each key here's text and then you get some binary data this host key that's that's good to go over the network right and then you have to parse that binary data into more binary data all right so now now it's it's it's still binary host Pub is still binary right uh and this is actually where I got in reading about encoding slash pem because if I was like well what if I want to take that public key that I just extracted out of the localhost file and I wanted to save it to a file well you can totally do that by just looking at the file right itself you know you know you know you know if I wanted to do that I could just take this thing and delete it off and put and put public key and put the Pim stands at the header and the tail I've done that before actually and this this this hexadecimal representation would become I could to turn this into a Pim if I wanted to all I'd have to do is take that and put it and I don't need a pen file for that but if if you wanted to go through the conversion through the binary and then into pem you can also do that because you're doing coding pem.code and then print it as a string and it'll be a nice pretty pen string and and I did it it's kind of a waste of time I didn't need to do that um but I I was just curious I was curious to see well what is the format of all this data at every one of these stages and this here uh this host club that comes out of this this it says Marshall right so it is still binary data uh and then it based 64 hash of the message yes um so so then we had so parse public key as it says here is RFC 44253 I don't know if that's ASN asn.1 or not Ryan you might want to look at it for me but I don't know hmm all along the way we're returning errors if we get them and then here's where the actual uh connection the remote part of everything happens so far it's all been setting stuff up and then we actually make a connection we use dial which is um uh you know it takes a network string and it takes the network string is TCP always I always put tcpib there are ERC number uh let me see if I can get it for you again is uh RFC 4253 looks like so um so then we have so it's always TCP you know that's again sensible default uh and then what you have your address string which is regular that comes from net from the TCP of the net TCP um Library I think uh so I mean it comes straight from it and it requires support by the way it Port is not optional you have to put a colon and then a port I think you can probably just put colon and not put the port but I don't know I I went ahead and put it on no matter what anyway and then uh and then you have your configure this is a a pointer to an SSH client config because there's so many things you can put in here and then it Returns the client and then the client is ready to run sessions on and blah blah blah right so uh in fact to be fair I should probably change the name of this it's really not a connection um it's a client let's do that I'm going to change it that's a misnomer that is that is not that is a client that is a client that got returned so that was good to see so so there's our SSH client and slightly different than a connection but whatever and then we pass in the username the string that we parsed earlier that's the thing uh we have the auth method that we put our signer on and then we have our host Cube callback so that's all we need there's so many things that you can put in here right there's the entire config which this is a this is by the way this is embedded from uh the the general SSH config struct which is for all things I mean this is like you can put anything you could a lot of the stuff you can do for the servers and stuff could be put in here as well if you wanted to um we don't need any of that now it might be that I come across and I have to have another sensible default that I add in there but for right now no so there's our user here's our auth methods um and to get an off method you almost always want to run a function that's going to get you an auth method which is a function right an auth method is a function and then we have the host key callback uh that we talked about fix those keys uh it's not always a custom binary did not know thank you for looking that up so so we have the client version uh host key algorithms I mean I guess you could do one or two there the different hoskey algorithms um that's interesting I didn't explicitly set that I think that's I think that's implied because I'm using authorized Keys file which has the algorithm that's used in it that's the name that nist the name of the nist in it I'm pretty sure that's what that is and then the timeout oops um and then we have the timeout which is something I've never used before but I feel like I need to add now that I'm seeing it um it means no time out maximum time for DHCP can actually just that much I need to add a timeout what should we make the timeout uh should we make it like five minutes should we make it five minutes it's gonna be like it's gonna be like a duration you watch is it gonna am I gonna have to do a duration parse I don't know I I yeah that's a little bit easier than using a context though um time doctoration uh UH 60 or 300 with a normal defaults from most clients I like you're talking 300 seconds let's do 300. actually I think the timeout is already set to a default yeah but let's actually set it explicitly timeout um duration timed out duration is a an integer yeah so I have to just cast an integer if I remember right it's been a while but yeah duration it's an N64 elapsed time between two instances and largest representation of 200 the duration represents elapsed time between two instances nanosecond count nanosecond so I think I can do this I think I can say uh timeout let's see yes we could say timeout times uh time this makes it when you do this it turns it into a it turns it into a duration pretty sure uh timeout times time dot second and we'll add a timeout up here as a variable this would be a package of global um I mean I could make that an argument to the Run thing but I mean because this is going to affect everything in the package right this is where having a functional approach versus making a client encapsulate the other client is you know kind of an architectural decision but let's go ahead and say timeout is uh 300 yeah we'll just make it 300. um timeout say time out uh default Tabitha uh timeout is the default a number of seconds to wait uh to complete atcp connection I think it's for the um inbound connection I don't think it's for the entire process of the connection I don't think it I don't think it cuts it up after that I might have to use a context yeah that yeah that's kind of I'm glad we looked that up because that's uh that's the thing I mean this this will be fun to check okay so anyway so so that's handling all of our our connection um I do want to look at that one more time so it said and then a timeout of zero means no time timeout is the maximum amount of time for a TCP connection to establish that means it's the amount of time to wait around uh before it gets to connection this is not uh yeah I'm actually going to change this to be TCP timeout because this is this is not you know the the content has been taking us a long time right uh that's a different thing which I still need to add a context for later we don't need that right now but eventually we'll need that because if I if it takes forever for the content to return I need to definitely cancel that and and let it you know time out on its own uh I think SSH will probably have some time out I think there's probably some built-in timeouts with the session Handler but I don't know and and that's something we won't know until we've been running it for a while in production stuff all right so and so and then here's where the actual work happens so this is a connection so this is you know we have a tcbi connection after this is done we have a TCP connection running through the client and then after this is when we can make a new you know instance of of a command and now those are called sessions so a session equals error we get a new one uh if we have any input we go ahead and attach it uh set in session.studin oh let me show you so session.studin is um so let's go look at a session here um so a session has all the information about the interaction with the command in it so it has set in as an aisle reader it has stood out of his IO writer and the study error as an IO writer and and that's good that it's a writer and reader because then we wouldn't necessarily have to buffer everything up right we could we could we could use non-buffered I O with reader and writer I mean less buffered we'll say is still buffered but and and then and then we could you know put less memory constraint on the running application well if it has a lot of data to process that it's going to be sending over the wire uh and why would I want to do that well right now I don't want to do it because it's just a simple command this is the Run command that I'm making is not for that kind of thing but if I wanted to make my own SCP clone that just added a file as as hexadecimal or something I mean why would you it would take forever to do that but you could right you could do that you could say hey give me this file and then you know put it over here but that would be you would never want to buffer that would be too much data so that might be an opportunity for you to want to go do those other things uh you can combine the output which I think is stupid um I think it's important to keep the output separate um and you can request a subsystem you can do all kinds of cool things there are three commands however that actually execute so start shell which kicks off an interactive shell run the one we're going to use and output output is the same as run the difference is is that it um it Returns the standard output only combined output same thing just Returns the standard output and error combined uh as a big old bite slice but we are going to do run because we want to be more granular about the stuff that we get back we want to get standard error and out and we want to convert it into a string tube because we're going to be doing lots of stuff with strings and again sensible defaults for our version of this so we're going to use the Run command uh and you can go read about that here um see SSH dark session run oh oh I know I've seen that uh uh because was he named our package the same that's okay here we go so um yeah the M thing yeah it's nothing it's that's all that's all it is I did a video on it it's just it just makes it so I don't have to type a pipe at the end of everything all of that uh so anyway um so we've got a a funk here we have run runs the command uh he says you can do Run start shell output or command output return error is nil if the commander runs has no problem copying anything and exits with zero exit status if the if the remote server does not send an exit status or is missing it gives a special error you can look for which we really don't care I mean that's the color of our function is going to want that stuff but I don't care if the command completes unsuccessfully or is it interrupted by a single error of type exit error otherwise types are blah blah now you'll see that the exit error does have a number in it but again as I said you have to parse it out it's kind of annoying so that's next we set up the input the standard input if we have any uh and then I set up a new strings Builder this is by far the most performant way to do buffering of output uh it's far better than bytes buffer if you've ever been using that by pre uh I did some research on this but pre um I think it's 1.15 uh the standard way to build up a writer that was a string would be used by Builder and you see a lot of code out there I need to make a separate video on this that has including my code that has bytes buffer um and you don't want to do that anymore it's not nearly as efficient you want to use strings Builder instead and I think there's a bytes Builder as well instead of instead I don't remember but the strings Builder is the way to go and it it does not do a memory transfer it's like way way way more efficient and so that's something to take note of and so we make these um these little temporary variables and then we uh this we assign them to stud out understood air which are type I O writer so they're not type string right they're type IO writer and then after we get everything all assigned up and everything so that it's behaving as it should I mean this we had to assign an IR writer to study understood error otherwise it wouldn't have bothered it wouldn't have it wouldn't have done anything it would have just still thrown it away and and we actually won and assigned us something so that we capture that output and so that output is going to be captured into these buffers these string buffers and then and then we run it to get our error we use uh we set the error to get the exit error and then we run the command and then we assign uh the dot string which is a variable on the Builder that will give you the accumulated string and and that is the the big old you know full string thing and we're done and now now we have our function that works um um okay bye and so so so there we go um if we go to if we go to the test now uh you can see what this looks like to execute it now I'm using an example test because I defaulted example this all the time they're just so much easier to write and I'm ignoring the output for now just for the sake of this so I'm going to comment this out obviously because you're gonna you'll see that that the the results are about I can ever run this this is not the kind of test that I could run from from uh you know the the playground or the go play around or something like that this but but test testing is always the best way to test execution and example tests in my opinion are the easiest to write for this kind of thing so this is what we did um we're going to read that entire file in we're going to read this file entirely in uh could have pulled it from the environment whatever and then we're going to return standard outstandard error our actual error we're going to run it we're going to pass blah at localhost 22 which as if you saw me doing on the command line is an account on the system uh that is set up to be able to you know to log in and everything uh but I I I you saw that without the dash identity file the dash I when I did it for the command line if you remember back to earlier in the video I failed to make a connection because it didn't know about me and then I gave it a dash I to point it at my private key and and same pen file that I'm passing to this and it worked right so so it is important that you understand how this stuff relates to what would normally be done with the SSH client command on the command line because there is a one-to-one relationship to that kind of stuff so so then we have this pulling in and we have the U key getting past the H key getting passed we have our our cat hello program right and and and that gives you this is me testing standard output and standard input so hello is being sent as standard input a cat is the command we're sending it to and then I went ahead and put these little delimiters here so I could see what was going on so let's go ahead and run that uh go test and see what happens uh oh I didn't like my change that I made time duration uh TCP timeout time centration types mismatch and time iteration well I I made that's what I get for making changes live let's go fix that shall we so uh we should probably make this um I mean let's do it let's say 300 let's actually make it an actual duration 300 times at time dot second how about that TCP yeah then we can just use the TCP timeout that should that should be fine let's try that all right so let's run that and okay so it took a little while because it it made a simulated remote connection to you know not really a remote system localhost but as if it had made a remote connection to it and you can see that my standard ad is hello uh because why because it was a standard input that was sent to the cat command on the remote machine right and there's no errors and there was no errors okay so now let's let's mess with it let's like test it some more and see what we can do to break it so let's uh let's let's not give it any standard input and let's give it ls- uh L D tilde let's see if it resolves artillery for us what's that going to do right we're going to run that and we see oh hey look it got our thing right so that was standard out now let's try to dump the shadow file which I don't have permission to on the remote system right hopefully that would suck if we did so let me try to do that so cat Etsy shadow you know cross your fingers up today this doesn't work right because I don't want to give up my shadow file I mean you could it would it wouldn't be bad anyway but uh but so now when we run it it's actually gonna see you can see where the output went see the output went to standard error this time and here's the error here's the error so we have process exited with status one because why and that and I said that is the only place I know to get the error message and let me show you why so if I do SSH uh exit error this is this is what was was passed right the exit error has a weight message inside of it but it does not have I don't understand why they didn't make an integer uh one of the struct fields for the exiter that I think that's kind of silly um I mean one of the main things that you always want from a command that executes is the return value is the exit value and and we can't get it you can't get it without parsing as far as I know if somebody knows the answer to that please let me know because I that that's something I search for long and hard and cannot find it anywhere so as you can see um you know our test is working uh and you know we can we can play around with different sorts of things um we could you know run it on a different port if we wanted to uh watch what happens if I if I get rid of the key if I can't let's if there's no U key right so if the Yuki can't be parsed let's like break that for a second well it's going to happen there so it's like oh nothing and then we get an actual error SSH no key found right so that's one of the errors up higher in the Stream uh of our higher in our code right uh if I take the host key what if what if we mess with the the host public key uh what would happen I mean this you might want to do more thorough automated testing than I'm doing but this is a good way to get a sense of what's Happening especially when you're trying to figure out whether your keys are bork and everything so if I go through and I like mess with my key let's do that let's put like a cue at the beginning of my private key now what now I should crash right let's try it again uh oh no key found it could not find the key so I gotta get rid of the queue let's see if it works this time go test permission died okay so that way it worked uh what happens if we mess with the the host key right uh what happens if we get rid of this for this is kind of interesting because the first field is optional I found this out the hard way yeah so I can actually delete the first field localhost and it should still work if I remember right uh yeah see it worked you see how it worked so it doesn't need it and I think I can remove this field too here let's copy it so copy test data host host Pub Key to attempt and let's let's just I want to try to break it I like breaking things so let's break this let's I want to get rid of the algorithm now let's see if it still can I think the reason it survives is because because of the known host file I think it does not have to have the algorithm in it I honestly I don't know that for sure but I'm going to test it right now so let's do that so this is just the key this is just the key let's see if it survives no key found okay so nope now I am curious though if if if I change the the parse method I was playing with this the other day if I change the parse method from authorized keys to known hosts I think it that that one that we have right now actually qualifies as a known host so I'm gonna I'm gonna try this just really quick known hosts uh there we go oh no but then I have to change the whole function return signal look at that look at that mess that's like the ugliest return values ever I'm not doing that no no no no no we'll keep it all for my skis so so we learned something there right so copy Tim uh what was it host key Pub back into test data and the the first one is the is the comment ones so uh so we can put okay so there it is back again but as I said you can put your localhost in here as a reminder uh but it's it's completely optional and go test to make sure I didn't break anything but I think you know I think we have a a working program it's it's going out it's doing what it's been asked to do um and you know I'm not gonna leave it catty Etsy Shadow but but we can make it do pretty much anything and and and this includes sudo so um if if if you we one of the things we are doing is we're we're making an agent command that has sudo access to do very specific things uh and that is not in the scope of this what I'm writing but if you could do that you could do sudo whatever and then run run a program as long as the user blah in this case has sudo access to run the command that you're running you can actually run as another user under sudo and this stuff will still get like a translated back to you properly um so so there's some kind of interesting possibilities we you can do there uh LS here we'll just say cat and then put hello here we go back to where I was and that's that's really it um uh would it needed no pass and suitors no uh well yeah that but it would be for that specific command yeah and that's that's what we're gonna do actually we're we have one specific command that is extremely locked down and it will run with permissions and it it does have to do things as the effective user uh and it it's not going to be running set uid but but it will definitely have that so that is a separate piece of our particular thing because we have other you know non-service based API considerations to think about which are like command line API stuff so all our stuff is like you know authorized through user authentication on the machine and so in order to run something on that machine as that user they've already authenticated through oauth even to get to the uh through our apogee Gateway even to get to our middleware so we can trust the username by the time they're they're there we have a token and everything and if we wanted to bolster our security eventually I mean it's a lot of real rights of code we could pass the oauth token uh down and we could have you know our agent uh on the on on our our jump post we could have the agent actually check the token for authenticity before it ran and then we would have more of a zero trust sort of thing going on um you don't know where it works that's fine please don't say where I work if you know um but that but that that they haven't been running that way for over two decades so you know they're they're um for God's sake they've had our login and our shell for a long time too so so so this is this is a step in the right direction because it's going to be less error prone and and it's going to allow them to have you know web front ends and I'll I'll essentially what I mean let's talk about that for a second before we leave this why why on Earth would you do this right well one of the reasons for doing this is because there are a lot of Legacy systems that are designed to run as CGI scripts and you know ancient and we have 18 000 lines of pearl I mean you know there's there's a lot of of crafty code out there that's been designed to run through environmental interaction and setting environment variables and running and and to get to that technical debt stuff so that you can you can you know you can kind of architect your way out of your technical data a little bit you need to create a front-end service interfaces to this stuff so that the the applications become dependent on a standardized front end a very very highly standardized front-end uh API in our case we use apogee and rest for that and and that allows you gives you the freedom to upgrade your your where your your your points of of technical debt and then and you know put modernized things and in this case we're going to be getting rid of a lot of links in fact um it's not I'm pausing because I want to make sure I'm not violating any kind of terms of service with my my company here but in this particular case what we thought was going to be we were going to call so our middleware was going to call other middleware that was running a CGI and then that middleware you know calls PBC uh with its own encapsulation layer and then that finally calls PPC so it's like four hops away from the actual execution um and we found that there was a bunch of crafty old stuff that had been added into the Pearl CGI stuff that prevented the direct run of that's of the of the stuff behind that that could could be run from our jump posts from the command line by our users and so what we ended up doing is bypassing all of that stuff and kind of in an emergency situation not an emergency but we've been you know wanting to get this done and so in order to do an end run around all that Legacy old code when there was already another way to get to that functionality through the command line in our jump hosts or batch processors they we could go we can now execute this same exact command man's verbatim that our end users are using by adding something as simple as this 80 line um you know this 80 line you know SSH client into our middleware combined with a very very controlled uh sudo-enabled agent account uh on our jump posts that can emulate any one of our users on the system and and by doing that we completely went around all of the crafty old Pearl middleware we're not using any of that anymore and there's there's a bunch of I mean there's that's not completely true there's I mean a lot of the the the the you know cue stat stuff that is emulated there's another layer on top of that that is it's it's the stuff right before you get to PVC and so at some point we may even we even get rid of that and go straight to BBC and then and then that will be only like three hops from the from the code um and you know I mean short of writing another microservice on the endpoint but so so why would you care about running SSH because so many things I mean ansible if anything ansible has been a testament to the prevalence of SSH ssh has been used for several decades as the glue between all these disparate systems um so that you can do things on different systems and kind of like you know weasel your way through whether you're a hacker or you're an operations person you're writing middleware or platform engineer you're you're you need to get to these things and knowing how to do it with cessation it all starts with being able to set up a nice easy happy client connection authenticated secure client connection and that's what we've done today so it's a long a little bit longer video than I would like to have made it about an hour into it but but um hopefully this gives you gives you something to work with um let me know I mean in order to make this uh Enterprise robust this is just the client connection you probably want to encapsulate this inside of um some sort of go routine with concurrency you probably also want to have a number of Target hosts so if the first host doesn't respond within a certain amount of time you have two or three other jump posts that you can go try as well for redundancy uh you know those are all things that you would you would architect on top of something like this but having the ability to make a single SSH connection to a specific Target is a specific user is the granular piece of this that that you have to have in order to make all the plumbing work so hopefully that gives you something to think about and play around with
Info
Channel: rwxrob
Views: 2,476
Rating: undefined out of 5
Keywords:
Id: 6mP20OGQAlw
Channel Id: undefined
Length: 81min 57sec (4917 seconds)
Published: Tue Dec 13 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.