Shell Script

Creating Simple Ubuntu/Debian Packages

Creating static content Debian package

Occasionally there comes a time when you need to create your own Debian packages. Whether it be for deployment or needing to customize an install to your needs or whatever other reason you may have.

Personally, in my work, I deploy configurations of various sorts to hundreds of Ubuntu systems and have found that automating the creation of debian packages to be very useful. It allows me to track revisions, easily install, or remove the packages that I have made with scripting hooks that are all part of the package. In this example, we are going to construct a static debian package. This packages only purpose will be to copy files to the OS, and make any permission changes needed. It will also show a simple example of pre-install and post-install scripting and how/where those scripts go.

First, let's disect a simple debian package. In this example, the package we are going to make will be called 'mypackage'. We'll have a parent directory named 'mypackage' Inside the 'mypackage' directory will be a sub-directory called 'DEBIAN' and also contain a simple OS directory replica of where you want to place the file or files on the OS.

mypackage/
----------/DEBIAN/
----------/etc/mycoolfile

In the above example, we are placing 'mycoolfile' in the /etc directory. The real magic in all of this lies in what is actually in the DEBIAN dir.

mypackage/DEBIAN/
----------------control
----------------postrm
----------------preinst
----------------postinst
----------------prerm

 

Inside mypackage/DEBIAN/ you'll place a file describing your package called 'control', and any scripts that you want to be ran at various points during the installation and/or removal of your package. Here is an example 'control' file

Package: mypackage
Version: 1
Section: base
Priority: optional
Architecture: all
Depends: bash
Maintainer: luke@nerdliness.com
Description: My super cool package

 

Here is a short description of the other files you may find in the mypackage/DEBIAN/ directory.

postrm = postremove
preinst = preinstall postinst = postinstall prerm = preremove

All the scripts are run at the named times, meaning 'preinstall' is run before the contents of your package are installed. Here is an example 'postinst' script. Keep in mind that these could just be very simple shell scripts.

#!/bin/sh

ln -s /etc/mycoolfile /home/user/

If for whatever reason you want your file to be linked into your home directory putting the above into the mypackage/DEBIAN/postinst file would do it. I would definitely experiment and play around with exactly what you can do with these scripts. One thing to keep in mind, you aren't just limited to shell scripting in these scripts. Personally, I've used ruby as well.

Now, the only thing left is to build our package. We're going to use the 'dpkg' command to do this. From the parent directory that your 'mypackage' folder is in run

dpkg --build mypackage ./

Command Breakdown: dpkg is the debian package manager. In this case we are asking it to build a package, hence the --build parameter. The name of our package is 'mypackage' from that name it will also look for a folder in the parent directory called 'mypackage' and decend into that. It will then look for the DEBIAN directory, and parse the 'control' file for the various options. NOTE: if you didn't create the control file in the right fashion, you will receive errors letting you know this. We are also using ./ to tell dpkg too build the package in the present directory.

If all went well with the above command, you should end up with a freshly created package in your working directory called 'mypackage_1_all.deb' and it should be ready to install. This is a very easy process to automate if your content changes. Happy packaging!

SSH with no password

Logging into *nix based OS's with no password prompt

If like me, you have a lot of *nix boxes that you login to from one machine, typing your password over and over can be a pain. Also, if like me, you automate jobs on remote machines, SSH can be a great way to go. However you probably don't want to hang out until 1AM when no one is around to type in the password to execute that job via SSH. It is quite simple to have SSH automatically login for you and run your job, or just log you in so you can work at the console.

I've used this on various *nix platforms and OSX with great success.

The first thing we need to do is setup some keys to use. We're going to generate the public and private key pair for SSH to use on your local machine or the machine you want to initiate the SSH session from.

ssh-keygen -b 1024 -t dsa

Command breakdown: ssh-keygen is the command we are using. The "-b" option specifies the number of bits used in the key. The "-t" option specifies the type of key pair that we are going to create. In this example we are using DSA.

NOTE: There are a variety of different types of key pairs that we could use and there is quite a discussion we could get into about this, but that definitely goes above and beyond the scope of this how-to.

When you run the above command you will receive the following promps:

Generating public/private dsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_dsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:

Pressing "enter" at all the above prompts will work fine. One thing to keep in mind would be that if you do enter a passphrase you will be required to enter that passphrase before you can use your key.

After our keys are generated, use your preferred method of transferring your public key (in this example the public key is called id_dsa.pub and is kept in /home/user/.ssh/) to the remote machine. Rsync, scp, whatever you prefer...

Once the key exists on the remote machine login there and get to a command prompt. We are now going to copy the public key from the orinal machine into a place that lets this machine know that it is an accepted host. Run the following command to do so.

cat id_dsa.pub >> /home/user/.ssh/authorized_keys


Command breakdown: Cat, probably no explanation needed there... In this case, the user needs to be the user you are going to login as and we are appending the contents to the authorized_keys file.

As a final step let's make sure the permissions on this users .ssh directory are correct.

chmod 700 ~/.ssh
chmod 600 ~/.ssh/*


That is it! You should be able to login to this machine from the original with no password prompt and you should also be able to run commands on this machine from the origina via SSH with no password needed.

Coding:

SSH Port Forwarding

SSH Tunnels made easy

SSH is a wonderful tool. Not only does it allow secure remote access to your *nix box console, but it can also allow secure access to any of the services that box has to offer remotely even if the machine you are connecting from is behind a firewall.

First, The basics. Forwarding a port:

ssh -l username -L 9090:localhost:3306 remotemachine

The above command will forward port 3306 (MySQL) on your remote machine to local machine on port 9090 (or whatever random unprivileged port that you choose). You would then be able to login the remote mysql server from your local machine all over SSH.

The command break down is simple. Replace "username" with the username you are going to login to the remote machine with.

The "-L" option specifies that you are forwarding a Local port. In the above example, you are forwarding the port to port 9090 on the localhost.

The machine you are connecting to is "remotemachine" This can be an IP address, or a resolvable domain name.

The above example will open an SSH session on the remote machine and it will stay open until you close it or logout. This can easily be changes to forward your smtp, http, or any other port you choose to over SSH.

This is all great, however scripting an interaction with that remote machine isn't overly pleasant with that SSH session hanging around waiting to be closed by you. In that case, let's have it connect, run our command, then close without us telling it to.

In the example below, we going to update a Debian/Ubuntu based machine over the internet. However the server we are getting our updates from only accepts SSH traffic publicly and all other ports are blocked by a firewall. Debian/Ubuntu repositories are usually served by Apache or another webserver so they tend to answer on port 80 only.

NOTE: I know this sounds like a nutty example, but I have actually been asked this before. Also it provides easy ghetto authentication to your package repository.

ssh -l username -f -L 9090:localhost:80 remotemachine sleep 5
apt-get update
apt-get upgrade
exit 0

The above command/script is broken down like this:
We are connecting to the remote machine as "username."

Instead of having that pesky prompt stay open, we are going to fork this session into the background with "-f". From my experience, this has been the simplest way to get these tunnels to die once your command has completed.

The remainder of the command is the same as above except for the "sleep 5". The Sleep command is being run on the remote machine. This allows our local machine the ability to run the various apt commands in the remainder of the script that require it to interact with the remote machines.

Now for these particular commands to work, you'll need to setup your apt.sources file to update from your local machine instead of the remote machine. This is just an example, and that's another post for another time. Happy tunneling!

Coding:

Subscribe to RSS - Shell Script