If users will be accessing the OpenNMS web UI across untrusted networks, it is desirable to protect web sessions using HTTPS. This article explains how to configure OpenNMS' built-in Jetty web server to support HTTPS with no dependencies on external software.
Two commands will be used, openssl, and keytool. For further information on running openssl, see its online manual page at http://www.openssl.org/docs/apps/openssl.html, and for keytool, see its online documentation page at http://docs.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html .
For the Impatient
These instructions are not appropriate for production environments
If you want only to see that this feature works, and are not yet concerned with configuring HTTPS for the web UI in a production environment, complete the following steps. You will end up with an HTTPS-enabled version of the OpenNMS web UI that presents a completely bogus SSL certificate.
- Stop OpenNMS
- Set an HTTPS port in the top-level OpenNMS properties file
- Open OPENNMS_HOME/etc/opennms.properties in your favorite editor
- Uncomment the following line:
org.opennms.netmgt.jetty.https-port = 8443
- Start OpenNMS
- In your web browser, visit the following URL: https://127.0.0.1:8443/opennms/. Your browser will warn you that the server's certificate cannot be verified because it is expired and is issued by an untrusted authority. If you opt to continue anyway, you will be presented with the OpenNMS login page.
For the Patient
The following instructions explain how to set up Jetty as a standalone HTTPS server so that it is suitable for use in production environments. You will end up with an HTTPS-enabled version of the OpenNMS web UI that presents an SSL certificate customized for your environment. The path of this section branches to allow you to choose whether to obtain an SSL certificate signed by a trusted certifying authority or to make do with a self-signed SSL certificate.
Create a new Java keystore
Using the keytool utility that ships with Sun's Java distributions, create a new keystore and populate it with a new key. For the first question ("What is your first and last name"), enter the fully-qualified domain name by which people will be accessing your OpenNMS server's web UI. Choose this name correctly, as you will have to start over if you ever need to change it. Answer the remaining questions according to the specifics of your organization and locality.
Be sure to specify an appropriate number of days for the validity parameter. After this number of days elapses, the key you are generating will expire and you may no longer be able to use it to create new certificates. The example below specifies 731 days, which will make the key valid for two years (accounting for a possible leap year).
It is important that you choose good passwords for the keystore and for the key itself. These passwords may be the same or different to each other. Using different and strong passwords here protects your server's private key in the event the keystore file falls into the wrong hands. You should take precautions to keep this from happening, including setting filesystem user and group permissions so that unauthorized individuals with accounts on the OpenNMS server will not have read (or write) access to the keystore.
By default, keytool will create DSA keys, but Jetty requires an RSA key. Make sure you are passing the
-keyalg RSA option to keytool.
$ keytool -alias opennms-jetty -genkey -keyalg RSA -validity 731 -keystore /tmp/propercert/proper.keystore Enter keystore password: aGoodStrongKeystorePassword What is your first and last name? [Unknown]: opennms.example.org What is the name of your organizational unit? [Unknown]: Network Management Division What is the name of your organization? [Unknown]: The Example Organization What is the name of your City or Locality? [Unknown]: Marina del Rey What is the name of your State or Province? [Unknown]: California What is the two-letter country code for this unit? [Unknown]: US Is CN=opennms.example.org, OU=Network Management Division, O=The Example Organization, L=Marina del Rey, ST=California, C=US correct? [no]: yes
Option A: Certificate signed by a trusted CA
Generate a certificate signing request (or CSR) from the key that you created above. The command to do this is straightforward. The filename you specify for the file parameter will contain the CSR after the command completes.
$ keytool -certreq -keystore /tmp/propercert/proper.keystore -file /tmp/propercert/proper.csr Enter keystore password: aGoodStrongKeystorePassword Enter key password for <mykey>anotherGoodStrongPassword
The CSR output file is a text file whose contents will look similar to the following:
-----BEGIN NEW CERTIFICATE REQUEST----- MIICjjCCAkwCAQAwgYkxCzAJBgNVBAYTAlVTMRcwFQYDVQQIEw5Ob3J0aCBDYXJvbGluYTESMBAG A1UEBxMJUGl0dHNib3JvMSAwHgYDVQQKExdUaGUgT3Blbk5NUyBHcm91cCwgSW5jLjEQMA4GA1UE CxMHVW5rbm93bjEZMBcGA1UEAxMQZGVtby5vcGVubm1zLm9yZzCCAbcwggEsBgcqhkjOOAQBMIIB HwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tV bNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQTWhaR MvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yr XDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqL VHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+ z0kqA4GEAAKBgHQVrC0ysQbtmvu3Btjsz1n+6MJIm6mB0Y28fzKFC/azpMB+hultKdUFsnnb13BN fnfuUoULeLTu/cGvAsqFtCpJuAmcAzXxmTp0BTYj4o8jJYi0dLIKnox3Shy4VTr+qJlzn9Y1auWy rpwdD03e6Kq32rKpgU5fwC53L0J8dI6yoAAwCwYHKoZIzjgEAwUAAy8AMCwCFFtHtT6XNS8A/0Xu OfVnTnL+zrTPAhR7QgO0Y3Sd0u39l3uOvhX3G5//zw== -----END NEW CERTIFICATE REQUEST-----
There is no particular need to protect the CSR, as it contains no data that would aid an attacker.
Submit the CSR to the trusted CA
Send the certificate signing request (CSR) that you just generated to a certificate authority (CA) that you trust. This could be a commercial CA whose signatures most or all modern browsers will honor (for discussion, see this Wikipedia article) or a CA that is internal to your organization and whose public key is installed into all browsers on your organization's computers. The specifics of this step are entirely outside the scope of this article.
Import the signed certificate
After you submit the certificate signing request to the CA, and fulfill the CA's requirements for validating your identity and trustworthiness, the CA will send you a certificate file that bears the CA's signature.
The signed certificate consists of the public half of the key that you generated in the first step plus a signature performed using the CA's private key. Therefore, the signed certificate (like the CSR) contains no information that will aid an attacker if it is disclosed.
In order for your OpenNMS server to use the signed certificate, you must import the signed certificate into the keystore that you created in the first step.
$ keytool -import -keystore /tmp/propercert/proper.keystore -file /path/to/signed-cert.txt Enter keystore password: aGoodStrongKeystorePassword
Note: This requires that your keystore already trust the CA that has signed your certificate. If you see the error "keytool error: java.lang.Exception: Public keys in reply and keystore don't match", this indicates that you need to import your certificate authority's CA certificate first:
$ keytool -import -trustcacerts -alias <my-CA-root> -keystore /tmp/propercert/proper.keystore -file /path/to/CA-cert.txt Enter keystore password: aGoodStrongKeystorePassword
Now retry the import of the server cert.
Option B: Self-signed certificate
If you are content with a self-signed certificate, you need to perform just one step to add a signature to your new SSL certificate.
As in the key generation process above, be sure that you specify an appropriate number of days for the validity parameter.
$ keytool -selfcert -validity 721 -keystore /tmp/propercert/proper.keystore Enter keystore password: aGoodStrongKeystorePassword Enter key password for <mykey>anotherGoodStrongPassword
Copy the keystore into place
Now that the keystore you created contains your server's signed SSL certificate, you must copy the keystore to a place where OpenNMS can find it. In the real world, you might want to place the keystore in a different location, perhaps one that is not included in your nightly backups (unless you trust your backup operator completely). In extreme cases it might be desirable to put the keystore on a filesystem that is unmounted except when starting or restarting OpenNMS. For the purposes of this article, we will assume that you copied the keystore to /opt/opennms/etc/jetty.keystore.
Configure the Jetty HTTPS parameters in OpenNMS
In your favorite editor, open the file OPENNMS_HOME/etc/opennms.properties.
Uncomment (or add if not present) the line that sets the property org.opennms.netmgt.jetty.https-keystore, and change the value of this property to the location of the keystore that now contains your server's signed SSL certificate:
org.opennms.netmgt.jetty.https-keystore = /opt/opennms/etc/jetty.keystore
Uncomment (or add if not present) the lines that set the properties org.opennms.netmgt.jetty.https-keystorepassword and org.opennms.netmgt.jetty.https-keypassword, and change the values of each property to match the password you used for the keystore and the key itself in the first step:
org.opennms.netmgt.jetty.https-keystorepassword = aGoodStrongKeystorePassword org.opennms.netmgt.jetty.https-keypassword = anotherGoodStrongPassword
Uncomment (or add if not present) the line that sets the property org.opennms.netmgt.jetty.https-port, and optionally change the value to suit your needs:
org.opennms.netmgt.jetty.https-port = 8443
If you have multiple certificates in the keystore and wish to force Jetty to use a particular certificate, then uncomment or add the following option to specify the alias of the certificate that you would like to use. If this option is not present, Jetty will use the first certificate that it finds in the keystore.
org.opennms.netmgt.jetty.https-cert-alias = myOpennmsCertificate
Restrict access to the plain-HTTP listener
Although the steps you have completed so far have configured OpenNMS to start a Jetty HTTPS listener on port 8443, they have not disabled the plain HTTP listener that is present by default on port 8980. This listener must be present so that the OpenNMS real-time console can update the availability statistics shown in the web UI. Since you have done all the work to enable HTTPS, you probably do not want users using HTTP, so you will need to restrict access to the plain-HTTP listener.
There are two ways to accomplish this task. The first is to tell the plain-HTTP listener to bind only to an interface that is not accessible from any untrusted networks. In a setup where the OpenNMS web UI runs on the same server as the other OpenNMS daemons, it makes sense to use the loopback interface for this purpose. You can restrict the plain-HTTP listener to bind only to the localhost interface (which always has the IP address 127.0.0.1) by uncommenting the line that sets the property org.opennms.netmgt.jetty.host:
org.opennms.netmgt.jetty.host = 127.0.0.1
The second way to restrict access to the plain-HTTP listener is to use firewall rules. These rules may be local to the OpenNMS web UI server (e.g.iptables on Linux or ipf on Solaris) or they may be configured in a discrete firewall external that stands between the OpenNMS web UI server and the rest of the network. Configuring these rules is beyond the scope of this article.
Restrict access to the HTTPS listener
Although HTTPS is considered secure, there are valid reasons to restrict the interfaces on which the OpenNMS Jetty HTTPS listener is reachable. Currently it is possible to bind the HTTPS listener to all interfaces (the default) or to a single interface. To bind the HTTPS listener to a single interface, uncomment the line that sets the property org.opennms.netmgt.jetty.https-host:
org.opennms.netmgt.jetty.https-host = 10.11.12.13
Using a Pre-existing Private Key and Certificate
Many users may already have deployed significant amounts of SSL private keys and certs throughout their networks. In many cases, the system on which ONMS is running may already have a private key and certificate. Consequently, it would be a shame to manage yet another set of keys and certs.
The keytool utility included with JDK 1.6 and newer added the option to import an existing keystore into a new keystore.
openssl pkcs12 -export src.pk12 -in cert.pem -inkey key.pem keytool -importkeystore -srckeystore src.pk12 -srcstoretype PKCS12 \ -destkeystore mycert.jks -deststoretype JKS
Alternatively, you can follow the procedure used on this web page to convert the keystore.
We summarize here just in case this web page goes away. We assume the private key is in key.pem and the cert is in cert.pem (both are in PEM format).
Convert the key and cert from PEM format to DER format using openssl command
Use openssl to convert from PEM to DER format.
openssl pkcs8 -topk8 -nocrypt -in key.pem -inform PEM -out key.der -outform DER openssl x509 -in cert.pem -inform PEM -out cert.der -outform DER
Put key and cert into a new Java Keystore
Use the ImportKey.java class to take the key and cert and place it in a newly constructed JKS keystore. I modified the ImportKey java source to use the keystore password changeit and to use the key alias importkey and to save the resulting keystore in the file jetty.keystore
java ImportKey key.der cert.der
Howto: Create and use a certificate signed by the CAcert community
CAcert is a community that offers "free trust" - free signed certificates. If you are interested in using them, read their website. This howto assumes that you already have an account at CAcert and that you use the Debian package of OpenNMS (or: the path to they keystore is like it is in the debian package).
- Create a fresh keypair in a fresh keystore
keytool -keyalg RSA -genkey -validity 731 -keystore /usr/share/opennms/etc/jetty.keystore
Note: Use your FQDN when you are asked for first and last name!
- Create a certificate signing request (CSR)
keytool -certreq -keystore /usr/share/opennms/etc/jetty.keystore -file /tmp/opennms.services.net-lab.net.csr
- Let a cacert CA sign the CSR
Copy and paste /tmp/opennms.services.net-lab.net.csr into cacert's web UI and save the resulting (signed) certificate into a new file /tmp/opennms.services.net-lab.net.cert
- Import cacert.org root certificate and class3 certficate into your keystore:
wget --no-check-certificate -q -O - https://www.cacert.org/certs/root.crt | keytool -import -noprompt -alias cacertroot -trustcacerts -storepass ***yourpass*** -keystore /usr/share/opennms/etc/jetty.keystore
wget --no-check-certificate -q -O - https://www.cacert.org/certs/class3.crt | keytool -import -noprompt -alias cacertclass3 -trustcacerts -storepass ***yourpass*** -keystore /usr/share/opennms/etc/jetty.keystore
Note: You have to import the CAcert root certificate once into your browser, in order to make your browser trust the CAcert certficates (Some Linux distris already did that, see InclusionStatus )
- Import your cert into the keystore
keytool -import -noprompt -storepass valvoja -keystore /usr/share/opennms/etc/jetty.keystore -file /tmp/opennms.services.net-lab.net.cert
- This feature was added in version 1.3.10