Thermostat/SecurityConsiderations
From IcedTea
Contents |
1 Thermostat Security Considerations
The preferred way to set up Thermostat securely is to use the web service (a.k.a. using https:// URLs). In order to use the web storage, we advise our users to deploy the Thermostat web application (web archive) in their favorite servlet container and connect agents and clients (gui/shell/other) to it rather than to mongodb directly. In fact, it is recommended to make mongodb:// not accessible to other components other than the web service. Note that the thermostat web archive has been tested with Jetty 8, Tomcat 6, Tomcat 7, JBoss AS 7 final.
1.1 Basic Security Related Features and Best Practices
What follows is list of features in Thermostat which were designed to make Thermostat more secure. Again, in this document we assume that thermostat is set up such that only http(s) style URLs get exposed to agents and clients.
- Reads and writes are prepared. Thermostat's PreparedStatement work very similar to Java's PreparedStatement.
- ACLs guard web storage servlet entry points (stop-gap).
- Thermostat queries get filtered based on ACLs.
- All channels should run on top of TLS with host-name-verification turned on.
- Securing third-party plug-ins
- Categories - think DB tables - which are being used at Thermostat runtime need to be registered at boot-time of the Thermostat web application endpoint.
- Plug-in supplied model classes and Categories should be supplied by a separate OSGi bundle. The web service will need to "know" them for JSON serialization purposes.
- DAOs and model classes should pass a security review prior installing the jar(s) in the thermostat web application. No unnecessary jars/classes should be on the webapp's classpath.
- Prepared statement string descriptors need to be registered with the web service at Thermostat web application boot-time.
1.2 Enabling TLS/SSL on all communication channels
For production deployments enabling transport layer security for thermostat communication channels is strongly advised. These channels are: client/agent => web service link, web service => backing storage link (mongodb) and the client => agent command-channel link.
1.2.1 Enabling SSL for mongodb communication
In order to enable SSL for mongodb communication, the mongod process needs to be configured to enable SSL on its default port, 27518 in the Thermostat case. In order to do this modify $THERMOSTAT_HOME/etc/db.properties as follows:
PORT=27518 BIND=127.0.0.1 SSL_ENABLE=true SSL_PEM_FILE=/path/to/mongo-ssl.pem SSL_KEY_PASSWORD=<mongod-server-key-passphrase>
See http://docs.mongodb.org/manual/administration/ssl/ for more information on how to create the mong-ssl-pem file.
(Re)Start thermostat storage:
$ ./bin/thermostat storage --start
Next, we need to communicate to agent, client and/or web service components that mongodb expects an SSL handshake before a connection can be made. In order to do so, we modify $THERMOSTAT_HOME/etc/ssl.properties as follows:
BACKING_STORAGE_CONNECTION_USE_SSL=true
The next time a connection to a mongodb:// URL is made from a client component, this channel will use SSL. A client component can be an agent, a client or web service.
1.2.2 Enabling SSL for Web Storage channels
Steps are as follows:
- Make sure your servlet container where the Thermostat web archive is deployed is configured to support https://
- Use https:// as the connection URL for both remaining thermostat components, agent and client.
See also section on using a custom keystore configuration.
1.2.3 Enabling SSL for Command channel
In order to enable SSL for the command channel an appropriate Thermostat keystore needs to be set up which contains the key material for the server component. I.e. the keystore needs to contain the certificate and the key for the agent to use. The key material which should be used by thermostat for the server component of the command channel must have the alias 'thermostat'. The file to this keystore is specified in $THERMOSTAT_HOME/etc/ssl.properties. It should look something like the following in order to enable SSL for the command channel:
KEYSTORE_FILE=/path/to/java/keystore/with/keymaterial.keystore KEYSTORE_PASSWORD=secrit-password COMMAND_CHANNEL_USE_SSL=true
Then make sure to restart the thermostat agents. The next time command channel interactions occur the communication will be encrypted.
1.3 Thermostat Access Control
See also: Access Control Development Page
The only supported secure configuration of using Thermostat is to use its Web service feature. In this setup the web service acts as storage endpoint for Thermostat clients and agents. This also means that thermostat will require some configuration (usually done by a system administrator) before it can be used meaningfully. By default, Thermostat's ACLs can be configured via two plain-text properties files located in $THERMOSTAT_HOME/etc/ These two files are thermostat-users.properties and thermostat-roles.properties. The former file defines valid thermostat users and their corresponding password. The latter file defines to which roles each user is a member of. By changing the ThermostatJAASDelegate configuration so that it points to a different Java JAAS login module, Thermostat may be configured to use a different means to log in users and assigning them roles. Using LDAP and an appropriate JAAS login module would be one such example.
An important property to ensure while configuring roles for agent and client users is to make sure that command channel roles are set up correctly. For example, agent users should only have the thermostat-cmdc-verify role while client users should only have the thermostat-cmdc-generate role. It is not recommended to grant any one agent or client user both roles.
With that said, Thermostat agent users will require a certain set of basic role memberships. At this point this set of roles for agent users is:
thermostat-prepare-statement thermostat-write thermostat-save-file thermostat-purge thermostat-register-category thermostat-cmdc-verify, thermostat-login thermostat-realm
Similarly, client users will require the following set of basic role memberships (thermostat grant roles are explained below):
thermostat-realm thermostat-login thermostat-query thermostat-prepare-statement thermostat-cmdc-generate thermostat-load-file thermostat-register-category
In addition to the above roles, client users will likely need some of the following roles granted:
thermostat-agents-grant-read-agentId-* thermostat-hosts-grant-read-hostname-* thermostat-vms-grant-read-vmId-* thermostat-vms-grant-read-username-* thermostat-cmdc-grant-garbage-collect thermostat-cmdc-grant-dump-heap thermostat-cmdc-grant-thread-harvester thermostat-cmdc-grant-killvm thermostat-cmdc-grant-ping thermostat-cmdc-grant-jmx-toggle-notifications thermostat-files-grant-read-filename-* thermostat-files-grant-write-filename-* thermostat-grant-read-ALL
The first 4 roles grant read permission for a specific agent ID, hostname, vmId and username-as-which-the-vm-runs-as respectively. If the suffix is ALL it will grant the user permission to read ALL agent IDs, hostnames, vmIds and usernames, respectively. Example: Membership of role thermostat-agents-grant-read-agentId-ALL grants the user privileges to read all agent IDs (and records pertaining to any agent IDs) available in the DB. Membership of role thermostat-agents-grant-read-agentId-cb8c2172-489d-458f-896a-a9ad132eb421 would grant the user to see agent with ID cb8c2172-489d-458f-896a-a9ad132eb421 (and records pertaining to this agent ID). Agent, host, and both vms grant roles are required. If any of the 4 roles is missing the user will not be allowed to see any records.
thermostat-cmdc-grant-* roles grant a user to perform the given command-channel action. For example role thermostat-cmdc-grant-dump-heap grants a user to perform heap dumps via the agent on a remote machine.
If you want to grant a user read permissions across agents, hosts, vmids and vmusernames you can grant this user role thermostat-grant-read-ALL.
thermostat-files-grant-read-filename-* and thermostat-files-grant-write-filename-* roles grant a user to read and write the given filename respectively. For example role thermostat-files-grant-read-filename-foo grants a user to read filename foo from storage. For those roles corresponding -ALL roles exist as well to grant a user to read/write any file name from/to storage.
1.4 Configuration Reference
1.4.1 Properties for Use in Configuration Files
- SSL_ENABLE
- boolean If set to
truethermostat storage will start the mongodb process with SSL enabled. - SSL_PEM_FILE
- String Absolute path to a PEM encoded file containing the server key and certificate. See http://docs.mongodb.org/manual/administration/ssl/ for more information.
- SSL_KEY_PASSWORD
- String The password for the server key should it be encrypted. If the server key was not encrypted any non-empty password will work.
- BACKING_STORAGE_CONNECTION_USE_SSL
- boolean Whether or not to initiate an SSL handshake if a connection to a backing storage implementation is made. Applies to agent, client, web service.
- KEYSTORE_FILE
- String The absolute path to the Java keystore file. If present, key material in it will also be used during validation of self-signed certificates. E.g. if an agent tries to connect to a https:// URL and the server uses a self-signed certificate.
- KEYSTORE_PASSWORD
- String The password for the Java keystore as specified with KEYSTORE_FILE
- COMMAND_CHANNEL_USE_SSL
- boolean If set to true, command channel communication will be encrypted. Requires a valid KEYSTORE_FILE to be set up as well, since there would not be any key material which the agent could use during the SSL handshake.
- DISABLE_HOSTNAME_VERIFICATION
- boolean If set to true, host name verification will not be performed during SSL handshakes. In particular, during handshakes with the backing storage implementation or the command channel.
1.4.2 Thermostat ACL Roles Reference
- thermostat-prepare-statement
- Role granting a user to prepare statements. Required for reading/writing data.
- thermostat-write
- Role granting a user to write data to storage. "thermostat-purge" and "thermostat-save-file" are also write operations, but are not covered by this role. This role covers basic record writes such as inserts, updates and deletes.
- thermostat-save-file
- Role granting a user to save (a.k.a. write) files in storage.
- thermostat-purge
- Role granting a user to remove data from storage. This role should get granted scarcely.
- thermostat-register-category
- Role granting a user to register categories (a.k.a. tables) with storage. Required for reading/writing data.
- thermostat-cmdc-verify
- Role granting a user to verify a provided command-channel auth-token. This should usually be granted to agent users only.
- thermostat-login
- Role granting a user to log in. The web storage endpoint exposes a login endpoint which can be used for basic functionality testing of configured ACLs. Every thermostat user will need this role.
- thermostat-realm
- Role used for restricting the thermostat security realm. Any user who is a member of this role will be able to authenticate with the thermostat storage realm.
- thermostat-query
- Role granting a user to query thermostat storage. See thermostat-{agents,hosts,vms}-grant-read-* roles for more fine grained record read access control.
- thermostat-cmdc-generate
- Role granting a user command-channel authentication token generate privileges.
- thermostat-load-file
- Role granting a user to load files from storage.
- thermostat-agents-grant-read-agentId-*
- Role granting a user read permissions for records pertaining to specific agent IDs. This role is part of the default read filter chain. A special agent ID,
ALL, that is rolethermostat-agents-grant-read-agentId-ALL, grants a user to read records which was written by any agent. - thermostat-hosts-grant-read-hostname-*
- Role granting a user read permissions for records pertaining to specific host names. This role is part of the default read filter chain. A special host name,
ALL, that is rolethermostat-hosts-grant-read-hostname-ALL, grants a user to read records pertaining to any host name. - thermostat-vms-grant-read-vmId-*
- Role granting a user read permissions for records pertaining to specific JVM IDs. This role is part of the default read filter chain. A special JVM ID,
ALL, that is rolethermostat-vms-grant-read-vmId-ALL, grants a user to read records pertaining to any JVM ID. - thermostat-vms-grant-read-username-*
- Role granting a user read permissions for records pertaining to specific JVMs. In particular, to grant a user to see all records of JVM which run as user
tomcat, granting that user rolethermostat-vms-grant-read-username-tomcatwould be appropriate. This role is part of the default read filter chain. A special JVM username,ALL, that is rolethermostat-vms-grant-read-username-ALL, grants a user to read records pertaining to any JVM username. - thermostat-grant-read-ALL
- Role granting a user to read any records from storage. Granting a user this role essentially disables the read filter chain.
- thermostat-cmdc-grant-garbage-collect
- Role granting a user to remotely performing garbage collection actions for any JVM.
- thermostat-cmdc-grant-dump-heap
- Role granting a user permission for remotely performing heap dumps for any JVM.
- thermostat-cmdc-grant-thread-harvester
- Role granting a user permission for remotely toggling thread recording for any JVM.
- thermostat-cmdc-grant-killvm
- Role granting a user permission for remotely killing any JVM.
- thermostat-cmdc-grant-ping
- Role granting a user permission for pinging any agent. The ping action is useful for testing if the command channel is functional.
- thermostat-cmdc-grant-jmx-toggle-notifications
- Role granting a user permission for remotely toggling JMX notifications.
- thermostat-cmdc-grant-profile-vm
- Role granting a user permission for remotely starting/stopping JVM profiling runs.
- thermostat-files-grant-read-filename-*
- Role granting a user to read a file with the given filename from storage. That is, role
thermostat-files-grant-read-filename-FOO, grants a user to read file,FOOfrom storage. The special role,thermostat-files-grant-read-filename-ALLpermits a user to read any file from storage. Note that heap dump files are stored in storage as files. - thermostat-files-grant-write-filename-*
- Role granting a user to write a file with the given file name from storage. That is, role
thermostat-files-grant-write-filename-FOO, grants a user to write file,FOOto storage. The special role,thermostat-files-grant-write-filename-ALLpermits a user to write any file to storage. Note that heap dump files are stored in storage as files.
1.5 Example Using Custom Thermostat Keystore + TLS on ALL Channels
This examples describes how you can set up Thermostat to work with your self-signed certificates (signed by your custom CA, henceforth called custom_ca). This example is a walk-through for generating this CA's certificate which we'll use for signing cerfificates for use by mongod and agent. Moreover we'll use openssl commands for the most part. Similar things can be achieved by using the keytool utility provided by the JVM. In fact, we'll use it for part of this walk-through ;-)
1.5.1 Setting up our Custom CA
First, we generate an unencrypted 4096 bit RSA key for our custom CA:
openssl genrsa -out custom_ca.key 4096
File custom_ca.key is the private key of this CA. THIS FILE NEEDS TO BE KEPT SECRET.
Next, we create an unsigned cerfificate for our custom CA. We'll use this as our "root" certificate in order to establish trust in certificates offered by the thermostat agent (for the server component of the command channel) and for the cert offered by mongod. This cert will be valid for 5 years.
openssl req -new -x509 -days 1826 -key custom_ca.key -out custom_ca.crt
File custom_ca.crt is the root certificate we'll use (together with the private key) for signing our agent/mongod server certificates. We'll also import this "trusted" certificate into our keystore so as to indicate that we trust certificates signed by our custom CA for thermostat purposes.
1.5.2 Creating a Key/Certificate for mongod
Mongod uses a PEM encoded file which has the server's private key in it as well as the server's certificate. Here are the steps to create them. If in doubt, use instructions found at: http://docs.mongodb.org/manual/administration/ssl/
Let's generate a 3DES encrypted server key first. Encrypting the server key is optional, of course.
openssl genrsa -des3 -out mongod_server.key 4096
This will prompt for a passphrase. Take note of this passphrase as you'll need to specify it in Thermostat's storage configuration, namely in $USER_THERMOSTAT_HOME/etc/db.properties. If you omit the '-des3' option the server key won't be encrypted and any non-empty passphrase in $THERMOSTAT_HOME/storage/db.properties will do in order for thermostat storage to work.
Next, we'll generate a certificate request, which we'll later sign with our custom_ca. Note that this will prompt for some information. What's most important is to set the common name (CN) appropriately, since thermostat uses host name verification by default. I.e. the common name should be set to "match" the host name/domain the mongod process will be ultimately running on. The following command will also prompt for the passphrase of mongod_server.key. You can leave challenge password and company name empty (it will ask about these last).
openssl req -new -key mongod_server.key -out mongod_server.csr
Next, we sign our certificate request mongod_server.csr with our custom CA. This will produce the mongod server certificate as output.
openssl x509 -req -days 730 -in mongod_server.csr -CA custom_ca.crt -CAkey custom_ca.key -CAcreateserial -CAserial custom_ca.signing.serial -out mongod_server.crt
File mongod_server.crt is the signed certificate, valid for two years. custom_ca.signing.serial a file containing the serial number of signing requests. It solely contains a number which gets incremented with each signing of a certificate request.
Finally, we concatenate the certificate and the server key and call the resulting file mongod_keymaterial.pem. We'll later specify the path to that file in $USER_THERMOSTAT_HOME/etc/db.properties.
cat mongod_server.crt mongod_server.key > mongod_keymaterial.pem
1.5.3 Creating a Java Keystore File for the Thermostat Agent
First, we'll generate a new agent server key, a corresponding signing request for a certificate and sign that request with our custom CA:
openssl genrsa -out agent1_server.key 4096 openssl req -new -key agent1_server.key -out agent1_server.csr openssl x509 -req -days 730 -in agent1_server.csr -CA custom_ca.crt -CAkey custom_ca.key -CAserial custom_ca.signing.serial -out agent1_server.crt
File agent1_server.key is the server's key and agent1_server.crt the self-signed certificate which the thermostat agent will both use.
Next, we'll convert agent1_server.key and agent1_server.crt to a PKS12 keystore. This we subsequently convert to a Java keystore. Note: This will prompt for an export password. I.e. the keystore will be password protected. It is recommended to use a password of 6 characters or more since the keytool utility requires for keystore passwords to be at least 6 characters. Moreover, we suggest to use the same password for the pkcs12 keystore as for the Java keystore.
openssl pkcs12 -export -in agent1_server.crt -inkey agent1_server.key -out agent1_keystore.pkcs12
File agent1_keystore.pkcs12 is the converted keystore. We now use keytool in order to import this keystore and export it as a JKS formatted Java keystore:
keytool -importkeystore -srckeystore agent1_keystore.pkcs12 -destkeystore agent1.keystore -srcstoretype pkcs12
This produces file agent1.keystore which is the keystore file which we'll tell Thermostat about in $THERMOSTAT_HOME/etc/ssl.properties. Take note of the export password for this keystore file as it needs to be specified in that file as well. We can list the contents of this keystore file with:
keytool -list -v -keystore agent1.keystore
Note that this keystore only contains one entry and should contain output similar to the following:
[...] Alias name: 1 Creation date: Apr 3, 2013 Entry type: PrivateKeyEntry Certificate chain length: 1 Certificate[1]: [...]
The important part is "Alias name: 1". In order for this key material to work properly with thermostat we need to change the alias to "thermostat". We can do this via the following command:
keytool -changealias -alias 1 -destalias thermostat -keystore agent1.keystore
With this file agent1.keystore is ready to be used with thermostat.
1.5.4 Adding custom_ca.crt to the Thermostat Keystore File
In order to tell Thermostat that certificates signed by our custom CA are trusted, we'll import the CA's certificate into the thermostat keystore file. In this case we use the already existent agent1.keystore file as produced earlier. Alternatively, the certificate can be imported into the cacerts keystore file provided by the JVM.
keytool -import -alias weTrustCustomCA -file custom_ca.crt -keystore agent1.keystore
1.5.5 Configuring Thermostat
For security considerations it is recommended to service mongodb storage from one host, have thermostat web storage run on another host with fast interconnect to the mongodb host, and thermostat agents/clients run on yet other hosts.
Since we've already created mongod_keymaterial.pem and agent1.keystore files in earlier sections, all that's left to do is to tell Thermostat about these files and to enable TLS on all channels. In order to do so we need to modify db.properties and ssl.properties files. The $USER_THERMOSTAT_HOME/etc/db.properties file looks as follows:
PORT=27518 BIND=mongod_server.example.com SSL_ENABLE=true SSL_PEM_FILE=/path/to/mongod_keymaterial.pem SSL_KEY_PASSWORD=<mongod-server-key-passphrase-as-used-earlier>
The bind address should be a host name matching the common name as specified in the section above when we created it. Otherwise host name verification will fail when attempting to connect to mongodb storage. The value for SSL_KEY_PASSWORD is the passphrase used for encrypting the server key (or any non-empty string for keys which aren't encrypted).
Next, we'll need to configure the Thermostat web service so as to use appropriate connection URLs. The web.xml file of the thermostat webapp (a.k.a. web storage/service) should contain the following:
<!-- ... -->
<!-- Username to use for connecting to mongod storage -->
<init-param>
<param-name>storage.username</param-name>
<param-value>thermostat-webservice1</param-value>
</init-param>
<!-- Password to use for connecting to mongod storage
implementation -->
<init-param>
<param-name>storage.password</param-name>
<param-value>supersecrit</param-value>
</init-param>
<init-param>
<param-name>storage.endpoint</param-name>
<!-- host name should match what was used for the SSL certificate -->
<param-value>mongodb://mongod_server.example.com:27518</param-value>
</init-param>
<!-- ... -->
Then, we need to configure $USER_THERMOSTAT_HOME/etc/agent.properties so as to use https://. Again, the host name for the webservice needs to match what's the CN in the certificate the webservice is using:
# The listen address needs to match the common name of the # certificate created above. CONFIG_LISTEN_ADDRESS=agent1.example.com:12000 DB_URL=https://webservice1.example.com:8443/thermostat/storage
Note that the config listen address is the address/port combination which is going to be used for Thermostat command channel traffic.
Finally, in $USER_THERMOSTAT_HOME/etc/ssl.properties we have the following configuration:
KEYSTORE_FILE=/path/to/agent1.keystore KEYSTORE_PASSWORD=my-secrit-password COMMAND_CHANNEL_USE_SSL=true BACKING_STORAGE_CONNECTION_USE_SSL=true
That's it. In this configuration all Thermostat communication channels will use SSL. Moreover, since agent1.keystore contains the certificate for our custom CA, it will be used in order to establish that certificates used by mongod, by the agent and by the webservice are trusted (yet self-signed).

