Tomcat을 다시 시작하지 않고 SSL 인증서를 다시로드 할 수 있습니까?


11

Tomcat이 SSL 자격 증명에 사용하는 키 저장소를 업데이트 할 수있는 백그라운드 프로세스가 있습니다. 수동으로 다시 시작하지 않고도 Tomcat이 자동으로 다시로드하도록하고 싶습니다.

다시 시작하지 않고 Tomcat을 다시로드 할 수 있습니까? 아니면 프로그래밍 방식으로 대신 수행 할 수 있습니까?

답변:


6

백그라운드 프로세스가 Tomcat을 자동으로 다시 시작할 수는 있지만 자동으로 수행 할 수있는 방법이 없다고 생각합니다. 키 저장소는 jvm이 초기화 될 때 한 번만 읽습니다. 주기적으로 키 저장소를 다시 확인하는 자체 처리기를 작성하는 경우 해결책이있을 수 있지만 개인적으로 인터넷에서 이에 대한 예를 찾지 못했습니다.


8

jssecacert 파일을 변경 한 후 개별 Tomcat 커넥터를 다시 시작할 수 있습니다. 즉 8443과 같은 포트 다시 시작이 가능합니다.

다음은 인증서를 추가 / 삭제 한 후 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"옵션 으로 구성된 경우에만 작동합니다 .
anilech

4

이제 Tomcat v8.5.24부터이 작업을 수행 할 수있는 방법이 있습니다.

그들은 다음과 같은 두 가지 방법을 도입했습니다.

  1. reloadSslHostConfig (String hostName)-특정 호스트를 다시로드
  2. reloadSslHostConfigs ()-모두 다시로드

다양한 방법으로 호출 할 수 있습니다.

  1. jmx 사용
  2. 관리자 서비스 사용 (Tomcat v9.xx)
  3. 맞춤형 프로토콜을 만들어서-연구하는 동안이 방법을 찾았습니다

방법 1과 방법 2의 세부 사항은 Tomcat 문서에서 쉽게 사용할 수 있습니다.

방법 3을 사용하는 방법에 대한 세부 사항 :

  1. 예를 들어 원하는 프로토콜을 확장하는 수업을 만드십시오. Http11NioProtocol
  2. 필요한 메소드를 무시하고 super를 호출하여 기본 동작을 유지하십시오.
  3. 이 클래스에서 스레드를 작성하여 reloadSslHostConfigs 메소드를 호출하십시오.
  4. 이 클래스를 jar에 패키지하고 해당 jar을 tomcat의 lib 폴더에 넣으십시오.
  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");
                }
            }
        }
   }
}

server.xml의 커넥터는이를 프로토콜로 언급해야합니다.

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

도움이 되었기를 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.