Certificate creation for radmind

radmind iconRadmind supports the use of OpenSSL certificates as a means of identifying clients and for encrypting communications between client and server. I don’t really care about the encryption, but using certificates to identify clients allows laptops to run radmind no matter what network they use to connect to my radmind server – Ethernet, wireless, or VPN from home.

Setting up certificate support on a radmind server is a bit of a pain. I used the “Using TLS with Radmind” document available here.

But adding and removing certificates involves a lot of steps, and therefore is tedious and error-prone. And I wanted to be able to let several people at my organization be able to do this. When faced with repetitive, tedious, error-prone tasks, the lazy admin will write a script to do most of the work for him/her. So that’s what I did.

First up, my makecert script. Here’s what it does:
1. Given a hostname, it verifies it is a valid hostname, and that there is no existing cert for that hostname.
1. It creates a cert for the hostname without user input
1. It copies the cert to /var/radmind/special for radmind to manage.

My radmind config file has two entries for each laptop:


macbookpro                             greg_neagle.K
macbookpro.fas.fa.disney.com           greg_neagle.K

This allows the machine to get the correct command file (and correct cert) if it is identified by cert or by DNS name.

So additionally, the script creates a symlink from /var/radmind/special/hostname to /var/radmind/special/hostname.fas.fa.disney.com so that the special file is available no matter which way the machine connects to the radmind server.

Here’s the makecert script (WordPress may cut off the ends of some lines on display, but you can copy and paste the whole thing into a text editor):


#!/usr/bin/perl -w

# makecert
#
# A script to automate the creation of openssl certificates
# for use with radmind.
# Must be run as root.
# usage is:  makecert hostname
#
# Greg Neagle, Walt Disney Feature Animation

use strict;

# some things specific to your environment
# set $domain to "" if you don't have your hostnames in DNS
my $domain = ".fas.fa.disney.com";
# to automate things, we have to supply the CAkey passphrase.
# This could be a security issue in your environment.
my $ca_password = "(INSERT CA KEY PASSPHRASE HERE)";

my $hostname = $ARGV[0];
if ($hostname) {
   my @hostparts = split /\\./, $hostname;
   #get the short version of the hostname
   my $hostname = $hostparts[0];
   if ($hostname =~ /^d+$/) {
      print "Please use a host name, not an IP address.\\n";
      exit 0;
   }

   # check to see if this is a valid hostname in local DNS
   # again, you should set $domain to "" if you don't have
   # your hostnames in DNS
   if ($domain ne "") {
      my $hostresult = `host $hostname`;
      if ($hostresult =~ /not found/) {
         print "$hostname doesn't appear to be a valid hostname.\\n";
         print "Do you want to create a certificate anyway (y/n)? ";
         my $response = <STDIN>;
         unless ($response =~ m/^y/i) { exit 0; }
      }
   }

   # check to see if there's already a cert for this host in /var/radmind/special
   my $special_dir = "/var/radmind/special";
    if (-d "$special_dir/$hostname" ) {
      print "It looks like there's already a certificate for $hostname.\\n";
      exit 0;
   }

   print "Creating certificate for $hostname...\\n";

   my $ca_dir = "/var/radmind/CA";
   # generate a config file that will tell openssl req 
   # how to construct the cert without prompting us
   writeConfigFile($hostname);

   # Create a certificate request and an unencrypted private key.
   # Note I make the cert valid for 3650 days, since I don't want
   # to worry about expired certs any time soon.
   `openssl req -batch -new -keyout $ca_dir/key.pem -out $ca_dir/req.pem -days 3650 -config /tmp/openssl/$hostname.cfg -nodes`;

   if ($? == 0) {
   # Sign the certificate request with the CA’s certificate and private key
      `cat $ca_dir/req.pem $ca_dir/key.pem > $ca_dir/new-req.pem`;
      `openssl ca -batch -policy policy_match -key $ca_password -out $ca_dir/out.pem -config $ca_dir/openssl.cnf -infiles $ca_dir/new-req.pem`;

      if ($? == 0) {
      # Combine the certificate and key into one file
         `cat $ca_dir/out.pem $ca_dir/key.pem > $ca_dir/$hostname-cert.pem`;
      }
   }

   # Remove temporary files
   `rm -f $ca_dir/req.pem $ca_dir/new-req.pem $ca_dir/out.pem`;

   # Make the directories radmind needs to store the cert and copy them there.
   # You will need to modify to match your environment.
   `mkdir -p /var/radmind/special/$hostname/private/var/radmind/cert/`;
   `mv $ca_dir/$hostname-cert.pem /var/radmind/special/$hostname/private/var/radmind/cert/cert.pem`;
   if ($domain ne "") {
      `ln -s /var/radmind/special/$hostname /var/radmind/special/$hostname$domain`;
   }
} else {
   print "Need a hostname!\\n";
}

sub writeConfigFile {
   # this subroutine writes out a temporary openssl config file
   # to be used by openssl req to generate the certificate request
   # it must be modified for your environment

   my $hostname = $_[0];
   unless (-d "/tmp/openssl") { `mkdir "/tmp/openssl"`; }

   open CFG, ">/tmp/openssl/$hostname.cfg";

   print CFG "HOME       = .\\n";
   print CFG "RANDFILE        = \\$ENV::HOME/.rnd\\n";
   print CFG "\\n";
   print CFG "[ req ]\\n";
   print CFG "default_bits    = 1024\\n";
   print CFG "default_keyfile      = privkey.pem\\n";
   print CFG "distinguished_name   = req_distinguished_name\\n";
   print CFG "attributes      = req_attributes\\n";
   print CFG "prompt          = no\\n";
   print CFG "\\n";
   print CFG "[ req_distinguished_name ]\\n";
   # change the next line to reflect your country's 2-letter ISO code
   print CFG "C          = US\\n";
   # change the next line to reflect your state or province
   print CFG "ST         = California\\n";
   # change the next line to reflect your city or locality
   print CFG "L          = Burbank\\n";
   # change the next line to reflect your organization
   print CFG "O          = Disney\\n";
   # change the next line to reflect your organizational unit
   print CFG "OU         = Feature Animation\\n";
   print CFG "CN         = $hostname\\n";
   # change the next line to reflect the appropriate email address
   print CFG "emailAddress    = root\\@fa.disney.com\\n";
   print CFG "\\n";
   print CFG "[ req_attributes ]\\n";

   close CFG;
}

and the removecert script:


#!/usr/bin/perl -w

# removecert
# a script to assist in revoking certs and cleaning up
# the directories for use with radmind
# run it as root
# usage: removecert hostname
#
# Greg Neagle, Walt Disney Feature Animation

use strict;

# you'll need to change $domain to match your environment,
# or set it to "" if you aren't using DNS names with radmind
my $domain = ".fas.fa.disney.com";
my $ca_password = "(INSERT CA KEY PASSPHRASE HERE)";

my $hostname = $ARGV[0];
if ($hostname) {
   my @hostparts = split /\\./, $hostname;
   my $shorthostname = $hostparts[0];

   my $ca_dir = "/var/radmind/CA";
   my $special_dir = "/var/radmind/special";
   
   if (-d "$special_dir/$shorthostname$domain" ) {
      `openssl ca -batch -key $ca_password -config $ca_dir/openssl.cnf -revoke "$special_dir/$shorthostname/private/var/radmind/cert/cert.pem"`;
      `rm -rf "$special_dir/$shorthostname"`;
      if ($domain) {
         `rm -rf "$special_dir/$shorthostname$domain"`;
      }
   } else {
      print "No certificate found for $hostname.\\n";
   }
}

Certificate creation for radmind

2 thoughts on “Certificate creation for radmind

Comments are closed.