Чи може Tomcat перезавантажити свій сертифікат SSL без перезавантаження?


11

У мене є фоновий процес, який може оновлювати сховище ключів, яке Tomcat використовує для своїх облікових даних SSL. Мені б хотілося, щоб Tomcat перезавантажував це автоматично, не потребуючи ручного перезавантаження.

Чи можливо змусити Tomcat перезавантажити це без перезавантаження, чи є програмний спосіб, щоб це можна було зробити замість цього?

Відповіді:


6

Я не вірю, що існує спосіб зробити це автоматично, хоча ваш фоновий процес може автоматично перезапустити tomcat. Зберігання клавіш читається лише один раз при ініціалізації jvm. Можливо, буде рішення, якби ви написали власного обробника, який періодично повторно перевіряє сховище ключів, але я особисто не знайшов прикладів цього в Інтернеті.


8

Ви можете перезапустити окремий роз'єм Tomcat, тобто перезапуск порту, як 8443 можливий після зміни файлу jssecacert.

Ось повний код / ​​метод, який я використовую для перезавантаження з'єднувачів tomcat після додавання / видалення сертифікатів.

// Stop and restart the SSL connection so that the tomcat server will
// re-read the certificates from the truststore file.
public void refreshTrustStore() throws Exception 
{
    try 
    {
        //following line should be replaced based on where you get your port number. You may pass in as argument to this method
        String httpsPort = configurationManager.getHttpsPort();
        String objectString = "*:type=Connector,port=" + httpsPort + ",*";

        final ObjectName objectNameQuery = new ObjectName(objectString); 

        for (final MBeanServer server: MBeanServerFactory.findMBeanServer(null))
        {
            if (!server.queryNames(objectNameQuery, null).isEmpty())
            {
                MBeanServer mbeanServer = server;
                ObjectName objectName = (ObjectName) server.queryNames(objectNameQuery, null).toArray()[0];

                mbeanServer.invoke(objectName, "stop", null, null);

                // Polling sleep to reduce delay to safe minimum.
                // Use currentTimeMillis() over nanoTime() to avoid issues
                // with migrating threads across sleep() calls.
                long start = System.currentTimeMillis();
                // Maximum of 6 seconds, 3x time required on an idle system.
                long max_duration = 6000L;
                long duration = 0L;
                do
                {
                    try
                    {
                        Thread.sleep(100);
                    }
                    catch (InterruptedException e)
                    {
                        Thread.currentThread().interrupt();
                    }

                    duration = (System.currentTimeMillis() - start);
                } while (duration < max_duration &&
                        server.queryNames(objectNameQuery, null).size() > 0);

                // Use below to get more accurate metrics.
                String message = "TrustStoreManager TrustStore Stop: took " + duration + "milliseconds";
                logger.information(message);

                mbeanServer.invoke(objectName, "start", null, null);

                break;
            }
        }
    } 
    catch (Exception exception) 
    {
        // Log and throw exception
            throw exception
    }
}

1
Це буде працювати лише в тому випадку, якщо роз'єм налаштовано з bindOnInit="false"опцією.
анілех

4

Зараз є спосіб зробити це, починаючи з tomcat v8.5.24.

Вони запровадили 2 методи з назвою:

  1. reloadSslHostConfig (String hostName) - для перезавантаження конкретного хоста
  2. reloadSslHostConfigs () - перезавантажити всі

Їх можна викликати різними способами:

  1. Використання jmx
  2. Використання служби менеджера (у tomcat v9.xx)
  3. Складаючи нестандартний протокол - я знайшов такий спосіб під час своїх досліджень

Деталі про спосіб 1 і 2 легко доступні в документах tomcat.

Детальніше про те, як рухатись шляхом використання способу 3:

  1. Складіть клас, розширюючи обраний протокол, наприклад, Http11NioProtocol
  2. Перевизначте потрібні методи та просто зателефонуйте їм супер, щоб зберегти поведінку за замовчуванням
  3. Створіть нитку в цьому класі, щоб час від часу викликати метод reloadSslHostConfigs
  4. Упакуйте цей клас у банку і покладіть його в папку lib tomcat
  5. Відредагуйте протокол у роз'ємі на сервері server.xml, щоб використовувати цей визначений спеціальний протокол

Знайдіть зразок коду нижче:

Основний клас протоколу:

package com.myown.connector;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentMap;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.net.ssl.SSLSessionContext;

import org.apache.coyote.http11.Http11NioProtocol;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.net.AbstractJsseEndpoint;
import org.apache.tomcat.util.net.GetSslConfig;
import org.apache.tomcat.util.net.SSLContext;
import org.apache.tomcat.util.net.SSLHostConfig;
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
import org.apache.tomcat.util.net.SSLImplementation;
import org.apache.tomcat.util.net.SSLUtil;

public class ReloadProtocol extends Http11NioProtocol {

    private static final Log log = LogFactory.getLog(Http12ProtocolSSL.class);

    public ReloadProtocol() {
        super();
        RefreshSslConfigThread refresher = new 
              RefreshSslConfigThread(this.getEndpoint(), this);
        refresher.start();
    }

    @Override
    public void setKeystorePass(String s) {
        super.setKeystorePass(s);
    }

    @Override
    public void setKeyPass(String s) {
        super.setKeyPass(s);
    }

    @Override
    public void setTruststorePass(String p) {
        super.setTruststorePass(p);
    }

    class RefreshSslConfigThread extends Thread {

        AbstractJsseEndpoint<?> abstractJsseEndpoint = null;
        Http11NioProtocol protocol = null;

        public RefreshSslConfigThread(AbstractJsseEndpoint<?> abstractJsseEndpoint, Http11NioProtocol protocol) {
            this.abstractJsseEndpoint = abstractJsseEndpoint;
            this.protocol = protocol;
        }

        public void run() {
            int timeBetweenRefreshesInt = 1000000; // time in milli-seconds
            while (true) {
                try {
                        abstractJsseEndpoint.reloadSslHostConfigs();
                        System.out.println("Config Updated");
                } catch (Exception e) {
                    System.out.println("Problem while reloading.");
                }
                try {
                    Thread.sleep(timeBetweenRefreshesInt);
                } catch (InterruptedException e) {
                    System.out.println("Error while sleeping");
                }
            }
        }
   }
}

Connector в server.xml повинен згадувати це як протокол:

<Connector protocol="com.myown.connector.ReloadProtocol"
 ..........

Сподіваюсь, це допомагає.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.