From 20d5bf55b72427a98f0196c7ceb3f6abdaeea42f Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Mon, 20 Sep 2021 21:28:27 +0530 Subject: [PATCH] server: Add support to encrypt https.keystore.password in server.properties (#5459) * Add support to encrypt https.keystore.password in server.properties * address comments * address comments --- client/conf/server.properties.in | 4 ++ .../org/apache/cloudstack/ServerDaemon.java | 8 ++- .../crypt/EncryptionSecretKeyChecker.java | 6 +- .../java/com/cloud/utils/db/DbProperties.java | 5 +- .../cloud/utils/server/ServerProperties.java | 63 +++++++++++++++++++ .../EncryptionSecretKeyCheckerTest.java | 2 +- 6 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 utils/src/main/java/com/cloud/utils/server/ServerProperties.java diff --git a/client/conf/server.properties.in b/client/conf/server.properties.in index 7846df16f1c..42d98a6eb29 100644 --- a/client/conf/server.properties.in +++ b/client/conf/server.properties.in @@ -38,7 +38,11 @@ https.port=8443 # The keystore and manager passwords are assumed to be same. https.keystore=/etc/cloudstack/management/cloud.jks +# If you want to encrypt the password follow the steps mentioned at: +# http://docs.cloudstack.apache.org/projects/archived-cloudstack-administration/en/latest/management.html?highlight=jasypt#changing-the-database-password https.keystore.password=vmops.com +# If an encrypted password is used, specify the encryption type - valid types: file, env (set environment variable CLOUD_SECRET_KEY), web +# password.encryption.type=none # The path to webapp directory webapp.dir=/usr/share/cloudstack-management/webapp diff --git a/client/src/main/java/org/apache/cloudstack/ServerDaemon.java b/client/src/main/java/org/apache/cloudstack/ServerDaemon.java index b4cbb62e667..1b8e2f8cf93 100644 --- a/client/src/main/java/org/apache/cloudstack/ServerDaemon.java +++ b/client/src/main/java/org/apache/cloudstack/ServerDaemon.java @@ -19,12 +19,15 @@ package org.apache.cloudstack; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.lang.management.ManagementFactory; import java.net.URL; import java.util.Properties; import com.cloud.utils.Pair; +import com.cloud.utils.server.ServerProperties; import org.apache.commons.daemon.Daemon; import org.apache.commons.daemon.DaemonContext; import org.eclipse.jetty.jmx.MBeanContainer; @@ -116,7 +119,8 @@ public class ServerDaemon implements Daemon { LOG.info("Server configuration file found: " + confFile.getAbsolutePath()); try { - final Properties properties = PropertiesUtil.loadFromFile(confFile); + InputStream is = new FileInputStream(confFile); + final Properties properties = ServerProperties.getServerProperties(is); if (properties == null) { return; } @@ -132,7 +136,7 @@ public class ServerDaemon implements Daemon { setAccessLogFile(properties.getProperty(ACCESS_LOG, "access.log")); setSessionTimeout(Integer.valueOf(properties.getProperty(SESSION_TIMEOUT, "30"))); } catch (final IOException e) { - LOG.warn("Failed to load configuration from server.properties file", e); + LOG.warn("Failed to read configuration from server.properties file", e); } finally { // make sure that at least HTTP is enabled if both of them are set to false (misconfiguration) if (!httpEnable && !httpsEnable) { diff --git a/utils/src/main/java/com/cloud/utils/crypt/EncryptionSecretKeyChecker.java b/utils/src/main/java/com/cloud/utils/crypt/EncryptionSecretKeyChecker.java index 65249878bde..ef17f7b5e75 100644 --- a/utils/src/main/java/com/cloud/utils/crypt/EncryptionSecretKeyChecker.java +++ b/utils/src/main/java/com/cloud/utils/crypt/EncryptionSecretKeyChecker.java @@ -55,8 +55,8 @@ public class EncryptionSecretKeyChecker { DbProperties.getDbProperties(); } - public void check(Properties dbProps) throws IOException { - String encryptionType = dbProps.getProperty("db.cloud.encryption.type"); + public void check(Properties properties, String property) throws IOException { + String encryptionType = properties.getProperty(property); s_logger.debug("Encryption Type: " + encryptionType); @@ -116,7 +116,7 @@ public class EncryptionSecretKeyChecker { throw new CloudRuntimeException("Accept failed on " + port); } } catch (IOException ioex) { - throw new CloudRuntimeException("Error initializing secret key reciever", ioex); + throw new CloudRuntimeException("Error initializing secret key receiver", ioex); } } else { throw new CloudRuntimeException("Invalid encryption type: " + encryptionType); diff --git a/utils/src/main/java/com/cloud/utils/db/DbProperties.java b/utils/src/main/java/com/cloud/utils/db/DbProperties.java index 84206146e64..d99e6c011be 100644 --- a/utils/src/main/java/com/cloud/utils/db/DbProperties.java +++ b/utils/src/main/java/com/cloud/utils/db/DbProperties.java @@ -39,10 +39,11 @@ public class DbProperties { private static Properties properties = new Properties(); private static boolean loaded = false; + public static final String dbEncryptionType = "db.cloud.encryption.type"; protected static Properties wrapEncryption(Properties dbProps) throws IOException { EncryptionSecretKeyChecker checker = new EncryptionSecretKeyChecker(); - checker.check(dbProps); + checker.check(dbProps, dbEncryptionType); if (EncryptionSecretKeyChecker.useEncryption()) { return dbProps; @@ -77,7 +78,7 @@ public class DbProperties { } EncryptionSecretKeyChecker checker = new EncryptionSecretKeyChecker(); - checker.check(dbProps); + checker.check(dbProps, dbEncryptionType); if (EncryptionSecretKeyChecker.useEncryption()) { StandardPBEStringEncryptor encryptor = EncryptionSecretKeyChecker.getEncryptor(); diff --git a/utils/src/main/java/com/cloud/utils/server/ServerProperties.java b/utils/src/main/java/com/cloud/utils/server/ServerProperties.java new file mode 100644 index 00000000000..4eabc5f99f7 --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/server/ServerProperties.java @@ -0,0 +1,63 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.utils.server; + +import com.cloud.utils.crypt.EncryptionSecretKeyChecker; +import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; +import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; +import org.jasypt.properties.EncryptableProperties; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class ServerProperties { + private static final Logger LOG = Logger.getLogger(ServerProperties.class); + + private static Properties properties = new Properties(); + private static boolean loaded = false; + public static final String passwordEncryptionType = "password.encryption.type"; + + public synchronized static Properties getServerProperties(InputStream inputStream) { + if (!loaded) { + Properties serverProps = new Properties(); + try { + serverProps.load(inputStream); + + EncryptionSecretKeyChecker checker = new EncryptionSecretKeyChecker(); + checker.check(serverProps, passwordEncryptionType); + + if (EncryptionSecretKeyChecker.useEncryption()) { + StandardPBEStringEncryptor encryptor = EncryptionSecretKeyChecker.getEncryptor(); + EncryptableProperties encrServerProps = new EncryptableProperties(encryptor); + encrServerProps.putAll(serverProps); + serverProps = encrServerProps; + } + } catch (IOException e) { + throw new IllegalStateException("Failed to load server.properties", e); + } finally { + IOUtils.closeQuietly(inputStream); + } + + properties = serverProps; + loaded = true; + } + + return properties; + } +} diff --git a/utils/src/test/java/com/cloud/utils/crypto/EncryptionSecretKeyCheckerTest.java b/utils/src/test/java/com/cloud/utils/crypto/EncryptionSecretKeyCheckerTest.java index 0f3f0587590..bd926009e98 100644 --- a/utils/src/test/java/com/cloud/utils/crypto/EncryptionSecretKeyCheckerTest.java +++ b/utils/src/test/java/com/cloud/utils/crypto/EncryptionSecretKeyCheckerTest.java @@ -39,7 +39,7 @@ public class EncryptionSecretKeyCheckerTest { Assert.assertNotNull(checker); Properties properties = DbProperties.getDbProperties(); properties.setProperty("db.cloud.encryption.type", "file"); - checker.check(properties); + checker.check(properties, DbProperties.dbEncryptionType); } } \ No newline at end of file