Wednesday, March 19, 2008

CA signed SSL certs in glassfish, for lazy admins

So setting up CA signed SSL in Glassfish sucked, until I finally found the process for doing so. John Yeary outlines the process, but it's still manual and annoying.

Never do more than twice anything you can script, and so here we go. The script below is designed to work with certificates. Save it to your local system and run it as a user who has access to write to the Glassfish installation.

# Copyright 2008 Jeff Rodriguez []
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# See the License for the specific language governing permissions and
# limitations under the License.

/bin/echo "This script was designed to work with"
/bin/echo "It may work with other sites, YMMV."
/bin/echo "USE AT YOUR OWN RISK."
/bin/echo -e "\n\n"

read -rp "SSL domain name [`hostname`]: " DOMAIN
if [ -z "$DOMAIN" ]; then DOMAIN="`hostname`"; fi

read -rp "AppServer domain directory [/home/`whoami`/SUNWappserver/domains/domain1]: " DIR
if [ -z "$DIR" ]; then DIR="/home/`whoami`/SUNWappserver/domains/domain1"; fi

read -rp "Keystore password [changeit]: " KSPASS
if [ -z "$KSPASS" ]; then KSPASS="changeit"; fi

# Make sure the domain directory is correct
if [ ! -e "$KS" -a ! -w "$KS" ]; then
/bin/echo "Your keystore ($KS) is not writable."
exit 1

# Handy alias
KSCMD="keytool -keystore $KS -storepass $KSPASS"

# Generate the key
if ( ! $KSCMD -genkey -keyalg RSA -alias $DOMAIN -keypass $KSPASS -noprompt -validity 365 -dname "cn=$DOMAIN"); then
/bin/echo "Failed to generate key."
exit 1
/bin/echo -e "\n\nA private key has been created in your app server's keystore."
/bin/echo "If this script fails at any point, and you wish to start over, you must delete this private key with the command: "
/bin/echo "$KSCMD -delete -alias $DOMAIN"
read -sp "Press enter to continue." REPLY
/bin/echo -e "\n\n"

# Create the CSR
if ( ! $KSCMD -certreq -v -alias $DOMAIN -file /tmp/$DOMAIN.csr); then
/bin/echo "Failed to create certificate signing request."
exit 1

/bin/echo "Below is your Certificate Signing Request (CSR)."
/bin/echo "On the website, go to Server Certificates -> New. Paste the text below into the form and submit it."
cat /tmp/$DOMAIN.csr
rm -f /tmp/$DOMAIN.csr

# Get the certificate
/bin/echo -e "\n\nCACert will generate a signed certificate. Paste it here, finish with EOF (CTRL+D)."
cat > /tmp/$DOMAIN.crt

# Fetch the CACert certificates
/bin/echo "Before you can use your certificate, it has to be imported to the app server keystore. To do that, we first have to import the certificates."
read -rp "Would you like the script to automatically download the certificates? [y|N]: " DLCERTS

if [ $DLCERTS = 'Y' -o $DLCERTS = 'y' ]; then
wget -q --no-check-certificate -O /tmp/cacert_root.crt ""
wget -q --no-check-certificate -O /tmp/cacert_class3.crt ""
/bin/echo "You have chosen not to automatically download the certificates. To do this manually,"
/bin/echo "Go to"
/bin/echo "Save the Class 1 PKI Key Root Certificate (PEM Format) as /tmp/cacert_root.crt"
/bin/echo "Save the Class 3 PKI Key Root Certificate (PEM Format) as /tmp/cacert_class3.crt"
read -sp "Press enter to continue." REPLY

if [ ! -e /tmp/cacert_root.crt -o ! -e /tmp/cacert_class3.crt ]; then
/bin/echo "CACert certificates weren't found in /tmp. Either automatic download failed or you have not manually downloaded the certificates properly."
exit 1

# Import the certificates
if ( ! $KSCMD -import -v -alias cacert -trustcacerts -noprompt -file /tmp/cacert_root.crt); then
/bin/echo "Failed to import CACert root certificate."
exit 1
if ( ! $KSCMD -import -v -alias cacert3 -trustcacerts -noprompt -file /tmp/cacert_class3.crt); then
/bin/echo "Failed to import CACert class 3 certificate."
exit 1
if ( ! $KSCMD -import -v -alias $DOMAIN -trustcacerts -noprompt -file /tmp/$DOMAIN.crt); then
/bin/echo "Failed to import domain certificate."
exit 1

# Cleanup
rm -f /tmp/cacert_root.crt
rm -f /tmp/cacert_class3.crt
rm -f /tmp/$DOMAIN.crt
$KSCMD -delete -alias cacert
$KSCMD -delete -alias cacert3

# Final instructions for the user
/bin/echo -e "\n\n"
/bin/echo "The certificate has been imported into your app server keystore."
/bin/echo "To use the certificate follow these last steps:"
/bin/echo " 1. Go to your Admin Console (http://$DOMAIN:4848), Configuration, HTTP Service, HTTP Listeners, http-listener-2 (or whatever your SSL listener is)."
/bin/echo " 2. On the SSL tab, set your Certificate Nickname to $DOMAIN, and click save."
/bin/echo " 3. Restart the app server."
/bin/echo "NOTE: Your certificate will expire in 1 year, you must update the certificate before then or browsers will receive SSL warnings; other programs may fail entirely."
/bin/echo "Mark your calendar. No, really."
/bin/echo -e "\n\n"
/bin/echo "If something went, or goes wrong, it could prevent your app server from starting. One possible remedy is to locate your SSL http listener in $DIR/config/domain.xml and disable it."

Though supposedly, it's technically possible to use an existing private key and certificate, you'll shoot yourself in the face before you finish. Cut your losses and just start over with a new private key and cert. You'll have to pardon me if the script is a bit rough around the edges. Send patches my way if you like.


John Yeary said...

Very nice work Jeff! I am glad that my blog helped you, but this is uber cool.

Pedro Morais said...

It looks greate but, sorry for the basic question, how can I run it with my Glassfish installed in a Windows 2003 Server ?

Anonymous said...

Not sure I really agree with SSL certs that don't have an authentic certification authority. But still better some security than no security. Keep posting.