In this lesson you'll learn how to create a small network of virtual machines that will simulate a company
network.
You'll also learn how to configure S-sh key authentication and execute commands on remote systems via
S-sh.
Well we're going to do here is actually create three virtual machines we're going to name the first
one ad men 0 1.
The next one server's zero one and the third one server zero two.
And I may call those 7:01 and server 2 to be brief.
This type of set up is very common where you'll have one server acting as your main administration server
that will act as the base of operations if you will.
And then several other servers on your network that are used to do the work for the business.
They could be web servers database servers or what have you.
So here I'm on my local system on my terminal open.
I'm going to go to shell class and I'm going to create a new directory for this project I'm going to
create a directory called multi net.
So we're going to be using multiple machines here on this miniature network so I'm just going to call
this multi net change directory and there.
And let's go ahead and initialiser vagrant project vagrant and it and then supply a box name.
Now I just need to edit the bigger file and make some changes.
Going to add some configuration right here below the config that VM box line and what I'm going to do
is say config dot VM define and we're going to define our first server of admin or one and put that
same name here in pipes
give us an IP address and then close our statement for this particular host.
So this will create one virtual machine.
Now let's go ahead and create a standard for next to a virtual machine.
We'll call this one server 0 1
give it the host name of server a one
then we're going to pretty much duplicate this.
But make sure we change the ones to two here.
And also make sure we change this IP address here.
Hey So now we have these three stanzas for three different servers we have Admin a one server or one
and server O2.
So no we're going to do is run a vagrant up.
Now when you're working with a vagrant multi machine set up like this when you run a command it runs
that command against all the systems unless you specify which one of the virtual machines that you're
working with.
So if we run vagrant up it's going to bring up all three of those systems if we run vagrant of admin
or one it's only going to bring up that system for example.
So go ahead and re-invigorate up and let vigorish create all three of those systems.
By the way this is going to take an extra few minutes since we're creating three servers here at once
Ok now that the vigorish up command has been executed we should have three running virtual machines
and we can check that with vagrant status.
If you get an error you Rannveig run up or if you run vagrant status and not all three of your virtual
machines are running you need to check the contents of your vagrant file.
And let me just jump in the vigor for a really quick and talk about a couple of things that I've seen
in the past some little gotchas if you will and how to get around those.
So let's look at our vagrant file here.
And one thing I've seen happen is for example on the IP address line I've seen people accidentally forget
the closing double quote.
So that is a common mistake I see people miss a comma here.
That is a mistake I've seen before.
I've also seen some students do this that they use capital IP instead of lower case IP.
So every little thing you see here every little bit of syntax.
It's not like salt and pepper or some seasoning it is exact and specific and has to be exactly this
way.
It's not therefore a random purpose.
Also another thing I've seen here when someone gets to this third stanza maybe they did like I did and
they copied the first one but they forget to change this.
So they have this situation where they're really trying to define server too.
But in the code block here they're referencing something that does not correspond to that.
So it needs to be the same here as well.
And I've also seen this happen which is people leave off this first bit of information here just use
VM hostname and so on like that and so that is also not going to work.
So again if you run a vagrant status and all three of your machines are up or the vagrant up command
isn't complete successfully These are some things that you can check.
So I jump out of here right now.
And now what I do is run vagrant S-sh.
Now in the past we've just been working with one system and when we run vagrant S-sh we get connected
to that one virtual machine.
Well since we have three virtual machines we run vigor and S-sh vagrant doesn't know which one we're
trying to connect to.
So we have to be very specific and tell it which machine we're going to connect to.
And so what we're going to do is connect here to admen one our administration server and start working
there.
So I'm just going to type in vigor and S-sh admin 0 1 now that we're in this virtual machine I'm going
to see if I can ping those other virtual machines on the network here just to see if they're responding
on our network networks to peeing dash C-3 that means send a count of three packets to ten nine eight
dot 11.
Sure enough are getting responses and that worked to do it to 12.
OK three packets transmitted no packet loss.
That looks good.
So this particular admen virtual machine can communicate over the network to server one and server two.
Now when attempting to resolve a name to an IP address for example if we want to pinging server 0 1
what happens is that the host file is checked first of by default and if no entry is found there then
DNS is queried.
Since the main point of this class is shell scripting we're not going to spend the time to set up a
DNS server for our three little virtual machines here.
We're just going to add our two servers to the hosts file so we can talk to them by name.
Now if we look at the ETSI hosts file you can see that the format of the file is an IP address followed
by a name and then any other additional names that you want to access those systems by.
Since I'm a normal user I'm going to actually use a command called T in conjunction with Sea-Doo to
append some lines to.
So let's look at the command really quick and the command reads from standard input and writes to standard
output and files it pretty much passes anything that it receives out the other direction.
And so what's useful about this is the Dash 8 option which allows you to append to existing files instead
of overwriting.
So how this comes in useful in our situation is that we're going to open to an existing file of ETSI
hosts.
And so we're going to use the Dash 8 option.
Now if you don't append to a file it just overwrites the file it clobbers it if you will.
So the reason why this is important is again where a normal user and what we want to do is do something
like this we're going to echo this 10 9 eight 11 Cerebro one because that's the IP addresses are 1 and
we want to send that to the bottom of the hosts file.
So what happens here is when we execute the command t sends that to standard output and it also appends
it to the hosts file.
So let's do the same thing again here with our server to
now if we can host we can see those two entries are at the bottom of the hosts file.
If you're trying to append some data to a file you may think oh I can just run Sea-Doo echo but it may
not do what you expect it to do.
So let's just try it out really quick on the Sudoku echo test and then try to append that to ETSI hosts.
And it says it's the host permission denied and I get people saying hey I ran that with root permissions.
Why can't I update the host.
Well what happens is you're actually executing the echo command as root with sudo there but the redirection
takes place as you're a normal user and that is why you cannot append to a file so sure you're running
the echo command as root but you're not doing the redirection as root.
So that's why you can use sudo in the way we did there.
Pipe that output to suit you Tiede cache and then that way you can do things like a pin data to files
on the command line without an editor and also without switching to the root user.
OK so that's maybe an interesting aside maybe it was totally boring to you but hopefully you got a little
something out of that.
OK so let's move on.
So now we have entries in the host file.
So in theory that means we can communicate to those systems by name so we can do this paying their C-3
server 0 1 and you can see 10 9 8 not 11 is the IP address that it's communicating with.
And of course that is what is in the ANSI hosts file and that does correspond to server 1.
And we can do the same thing here.
Let's just send one packet to server 2 and sure enough it sends it to 10 that 9.8 dot 12.
As I said earlier we're going to be using this a virtual machine as our main administration server will
be running commands from here that will execute on the other virtual machines on the network.
So I want to S-sh into those other two systems without a password.
And the first thing we need to do is create an S-sh key pair.
If we would like to do that.
So we'll just run S-sh dash region to generate a key and we're just going to accept the default here.
Sure that's a fine place for the key.
We're not going to use a passphrase.
And what this will allow us to do is S-sh without being prompted for a password every time we want to
connect to a server.
So just hit in a couple of times and now R-KY has created.
So the next step is to put the public key on the remote system and there's a handy command that will
help you do that.
It's called S-sh dash copy dash I.D..
So we're going to say to copy I.D. to server 0 1 here we're connecting as the vigourous user over this
age to server 0 1 and it's saying hey here's the fingerprint of that hose.
Do you accept it.
And do you think it's where are you trying to go.
We in theory we could check this key on the other side and confirm but you're were on a test system
I'm sure this is going to be safe.
So we'll just hit yes here.
So here is prompting us for vagrants password and the password for vagrant is vagrant.
It says it added the key over there so let's check it out.
S-sh server 0 1 and you can see that our prompt changed to server 0 1.
So we're on the other V.M. over S-sh.
So now I'm just going to exit out with exit and if I wanted to for example run a command over their
own server or one I could do this S-sh server 0 1 and then specify the command.
So let's run the hostname command over on server 1 So what happens is we connect to server 0 1 then
execute the command and then we're disconnected and we're back to our initial system so it's like we
never connected over there but we really did it was just wasn't an interactive log in.
So we need to do the same thing with server too.
So S-sh copy ID server to accept the key and our password.
And we should be good to go.
It's just test really quick.
S-sh server 0 2.
All right we get the server to prompt where over on that virtual machine and I'll just type exit here.
So now this allows us to do things like this.
Let's create a little for loop right here on the command line.
So I'm going to do 4 in and a 1 and 2 do S-sh 2 server 0 in and then run a command over their host name
and done.
So sure enough what happens in this little simple for loop is the first time around in is assigned the
value of 1.
And of course server zero dollar sign and evaluates to several one.
And then so that's when we S-sh a server or one run the hostname command.
Then the next time around the loop end is set to 2 and we S-sh the server zero in which is actually
server 0 to execute the hostname and then our loop is complete again like a demonstrated above you can
just S-sh into any server and run a command without having to start an interactive shell.
If you supply the command on the S-sh command line there that command to supply gets executed on the
remote system and then you disconnect from the remote system and the output is displayed.
OK so this allows us to do some things like this.
Let's change into our shared folder a vagrant and create a file here called servers.
Notice I used a single redirect operator that created a new file or the first line there if there was
a service while it existed it would have been overwritten and the second time I used double or greater
than signs which appends.
So I added server O2 to the server's file.
So let's check the contents of that really quickly.
Sure enough that file only contains two lines.
Server 0 1 and server 0 2.
So then we can do some things like this for server and servers.
And so remember back that the dollar sign parenthesis command closing parenthesis syntax means take
the output of that command in those parentheses and return it or substitute the output of that command
for the command itself.
So what's going to happen is this statement is really going to read for server and server all one server
O2.
So then we'll do this we'll do it S-sh server run the hostname command again we'll run a socket command
on that server and we'll just do an uptime.
The first we see the hostname output for server one then we see the uptime output for server 1 the loop
repeats and we get the same output for server 2.
By the way if you want to make sure that everything you specify after the host and an S-sh command gets
executed on the remote host put it in quotation marks.
So if we were to do this S-sh server 0 1 hostname semi-colon hostname what's going to happen is the
semi-colon is going to be interpreted as the command separator which it is and the host the first hostname
is going to get executed on server a one via S-sh and then its going to terminate that command because
the colon is a command separator.
Then the second hostname on this command line will actually execute on the local host.
So let's hit enter to prove that here.
Sure enough SSA server one hostname evaluates to several one and then hostname command itself returns
admin Odon because it gets executed on the local host.
So if you want to make sure that everything that occurs on that command line happens on the remote system
you need to put it in quotes.
So let's do this
here what happens is the hostname semi colon hostname command or command group everything in quotes
there gets executed on the remote system on server 0 1 and this particular example.
So whether you're doing a semi colons or pipes or whatever if you want to make that happen on the remote
system just enclose it in quotes.
Of course normal expansion rules apply.
So if you want variables to be expanded You need to use double quotes like this so let's say we're going
to use variables for commands will have command one variable b hostname and the command to variable
b up time.
Now what we can do is this is the same server O.
And then use double quotes because we want Siham do you want to be expanded to hostname and CMT to be
expanded to uptime the command to view the running processes or the process table is p s and a couple
of options that I end up using often our P.S. space dashi E-F which shows every process the dashi and
the dash f represents the full listing so it shows a full listing of every process.
So let's take the output of the command and pipe it to head.
So let's do this S-sh server 0 1 run Stashie half pipe that to head Desch 3 only look at the first couple
of processes here and hit enter.
So it happened with that command.
Is that E-F pipe head dash 3.
All was executed on server 1.
Now we'll get the same output if we do this
USCF had dashed 3 but the difference is this time is that the head command is actually executed on this
server and not the remote server.
In this instance there isn't a difference.
But again it's something to be aware of.
Another thing to keep in mind is that S-sh will exit the exit status of the remote command that was
executed or with 255 if an error occurred with S-sh itself and of course how do I know this well.
I read the man page so let me pull it up for you really quick.
DOUMANIS H.
I'm looking for exit status here.
So here it is S-sh exits with the exit status or the remote command or to 5:5 if an error occurred.
Let me get out of here with queue.
So let's do something like this let's make S-sh error out by giving it a server that doesn't exist.
Here it says it cannot resolve hostname server 0 3.
And if we check the exit status of the S-sh command we get 255.
So if you're writing a script you can check for exit status to 5:5 to distinguish an SS H.E. error from
an error that's coming from a remote command that was just passed on by S-sh.
So if we do this S-sh server go to that exists run up time and then check the exit status we get a zero
which was actually the exit status returned by the UP TIME command.
OK here's yet another important little thing to know when you're executing these remote commands with
S-sh it's actually more accurate to say that S-sh exits with the exit status of the last command executed
remotely or 255.
If an error occurred with S-sh So let me give you a couple of examples.
So there is a command called true that always returns true or an exit of zero.
And there is also a counterpart to that which is called false which always returns 1 which is a nonsuccess
or a false here on the command line.
So if we do this S-sh server 0 1 will execute false and we'll pipe that true which doesn't do anything
practically but it's just to show us about these exit satirises.
So if we do that and then we do this Ecko dollar sign questionmark we get a return value of zero and
that's because the last command that was executed to return to zero exit status.
So let's see this is a state server 0 1.
True.
False.
And then when we look at that exit status we get an exit status of one because the false command returned
the exit status of one.
Let's say you want any non zero exit status has to be returned.
If you are using a pipe on the remote system so the way to accomplish that is to use this.
So when we check the exit status here we get an exit status of one because that occurred during the
pipeline.
Now let's look at this let's look at the Help for set up that less because there's a lot of information
here is going to go down the pipe here.
So if we turn on this pipe fill option the return value of a pipeline is the exit status of the last
command to exit with a non zero exit status or zero if no command exited with a non-zero exit status.
So this is something to keep in mind if you want to make sure that every command in a pipeline was successful
when using S-sh Okay enough about executing commands on remote systems.
Let's read a simple script that checks to see if our servers are reachable via pinging or not.
So in the name this multi net demo one goes without saying we start with the ship being add a little
comment to our script here
so we're going to use a file that contains a list of our hosts here and we just created that command
line.
I we'll just use that and let's put a check in here to make sure that it exists before we try to loop
through it.
In computer speak this says if not exists server file then do something.
Another way to say that is if the file doesn't exist then do something in the thing we're going to do
here is say cannot open a server file for whatever reason and we are going to exit
and go back up here and actually put this in quotation marks.
So the next step here is just a loop through that file so we'll do a for loop.
This time let's use a count of 1.
I'm kind of impatient if it can ping and one will consider it up.
And if we don't get a response with one packet we'll be rather impatient and just assume it's down.
Ping generates some output as we know.
I'm just going to send all this output to dev null because I really don't care about the output.
What I care about is really the return status I want to know if that command succeeded or failed and
of course you know how to check that with this
if the status is not zero then something went wrong.
So we're just going to consider the server down.
Now in the real world if you can't ping a server that doesn't necessarily mean it's down.
It could mean that it's using a firewall that's preventing you from pinging it.
It could mean a lot of different things it doesn't necessarily mean the servers down.
But this simplistic example we're going to assume that it's down or at least that's what we're going
to report anyway.
OK that will finish up our for loop by the way I checked the exit status and said not equals zero then
down you could have done the exact opposite you could have said if the exit status equals zero then
the server was up.
Else it was down.
So you can do that anyway.
That makes sense in your own mind.
That's why I've chosen to do so I'm going to save my changes add some execute permissions on this and
then run this script.
So it says server 1 is up and server 2 is up.
Now let's stop.
One of the servers make it go down and not be available over the network and then try our script again.
There's a few different ways to do this but I'm just going to exit out of admin 1.
Now I'm back on my local machine on my physical computer I'm not in a virtual machine here.
And then what I'm going to do is just halt the server O2.
And by the way if you just run vagrant halt it's going to halt all the systems here that are defined
not just server O2.
So I had to specify that.
So now I'm going to S-sh back into admin A-one
to the vagrant folder and execute our demo script here.
So server wine came up right away.
It's waiting on server to and the ping is going to time out and get a non zero exit status.
And our script reports that server 2 is down.
I have just a couple of notes here before we wrap things up.
First this relationship that we set up between these systems with the S-sh authentication it's a one
way relationship.
We can S-sh into server 0 1 and server 0 2 from admin 0 1 but not the other way around.
You could set it up that way but it's just a common practice to have these one way relationships so
that you can designate an administration server to all your admin work from of course you can set things
up to go the other way but you'll have to do all the steps we did like an HOA centuries generate keys
copy the public keys to where you want to log into and so on.
Also I want to point out a critical distinction when using Sudoku.
Let's look at this command as the same server.
0 1 Sea-Doo ID the S-sh command is executed as the current user and in our case that current user is
vagrant we are then connected to server 0 1 as the vagrant user.
And if we execute the command sudo ID then is being executed as the vagrant user and this particular
example the command sudo ID is executed as the vagrant user on the server.
0 1 virtual machine of course using Sea-Doo gives us root privileges and so our ID that we get back
is the route ID here.
Now if we do this command SU to S-sh server 0 1 ID if we were to actually use this particular command
it would execute S-sh as the root user on our local system and we are running sudi S-sh locally then
we are connecting to server 0 1 as the root user and then executing the uptime command on the remote
system so let me hit enter here and see what happens.
So here its asking us about do you trust the server's key and we can say yes and then you may notice
here at the bottom of your screen we have root at server 0 1 again we're executing pseudo S-sh on the
local system which makes us root first then we're connecting to server old one.
So it's as if we're running S-sh several one as the user.
So here if we want to continue this process we need to enter the root password for server 1 which happens
to be vagrant.
So we get the same output as we did running the command the other way.
But I just want to make sure that you get the distinction running.
To S-sh means we're connecting as root to server 0 1.
And to do that we have to give root's password for server 0 1 if you want to do this without a password
then you have to generate S-sh keys for the root user and copy the public key to the destination server
like we did before with the vagrant user.
Now some Linux systems are configured such that route log into aren't allowed.
So you have to connect as a normal user and then run you inside the virtual machine instead of connecting
as root.
Anyway I wanted to point out this is very subtle but very important difference.
And with that that brings us to the end of this lesson and now we have a private network of three virtual
machines configured in running.
If you followed along and built your own private network with me here today that's great and if not
we'll that's fine too because you'll get a chance to do that in the exercise that follows.