​​ ActiveMQ - ssl + MQTT 설정하기
본문 바로가기
개발

ActiveMQ - ssl + MQTT 설정하기

by 컴밥 2025. 6. 20.

 

ActiveMQ를 이용하여  MQTT 브로커 설치 시 SSL을 적용하는 방법을 알아봅니다.

테스트용 인증서로 구축합니다. 상용 인증서 사용 시 1번 항목은 패스하면 됩니다.

 

1. 인증서 생성

순서대로 아래 커맨드를 이용해 셀프 Signed 인증서를 생성합니다.

 

# 서버 keystore 생성

keytool -genkey -keyalg RSA -alias amq-server -keystore amq-server.jks -storepass @Tldtmxhfl! -validity 3650 -keysize 2048 -dname "CN=씨엔이름, OU=OU, O=O L=장소, S=장소, C=국가" -ext "san=ip:아이피 입력

# 서버 CA 생성

keytool -exportcert -alias amq-server -keystore amq-server.jks -rfc -file amq-server.pem -storepass 비밀번호

# 클라이언트 key 생성

openssl genrsa -out amq-client-key.pem 2048

# 위에서 생성한 key로 클라이언트 certificate 생성

openssl req -new -x509 -key amq-client-key.pem -out amq-client-cert.pem -days 3650

# 위에서 생성한 certificate로 der 형태로 변환

openssl x509 -outform der -in amq-client-cert.pem -out amq-client-cert.crt

# 위에서 변환된 파일로 서버 truststore 생성

keytool -import -file amq-client-cert.crt -alias client -keystore amq-server-trust-store.jks -storepass 비밀번호

 

이제  jks가 생성 되었습니다.

 

2. ActiveMQ conf/activemq.xml 설정

포트 8883으로 설정하고, 위에서 생성한 인증서와 키스토어를 설정해 줍니다.

<sslContext>

<sslContext keyStore="file:${activemq.conf}/amq-server.jks" keyStorePassword="비밀번호"

trustStore="file:${activemq.conf}/amq-server-trust-store.jks" trustStorePassword="비밀번호"/>

</sslContext>


<transportConnectors>

<!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->

<transportConnector name="mqtt" uri="mqtt+ssl://0.0.0.0:8883?maximumConnections=1000&wireFormat.maxFrameSize=104857600&needClientAuth=true"/>

</transportConnectors>

 

3. JAVA Client 설정

maven dependency에 아래 라이브러리를 추가해 줍니다.

<!-- mqtt client-->
<dependency>
	<groupId>org.eclipse.paho</groupId>
	<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
	<version>1.2.5</version>
</dependency>


<!-- ssl support -->
<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId>bcpkix-jdk15on</artifactId>
	<version>1.64</version>
</dependency>

 

 

4. 인증서를 읽어오는 메소드 작성

public static SSLSocketFactory getSocketFactory(final String caCrtFile, final String crtFile, final String keyFile,
		final String password) throws Exception {
	Security.addProvider(new BouncyCastleProvider());

	// load CA certificate
	X509Certificate caCert = null;

	FileInputStream fis = new FileInputStream(caCrtFile);
	BufferedInputStream bis = new BufferedInputStream(fis);
	CertificateFactory cf = CertificateFactory.getInstance("X.509");

	while (bis.available() > 0) {
		caCert = (X509Certificate) cf.generateCertificate(bis);
		// System.out.println(caCert.toString());
	}

	// load client certificate
	bis = new BufferedInputStream(new FileInputStream(crtFile));
	X509Certificate cert = null;
	while (bis.available() > 0) {
		cert = (X509Certificate) cf.generateCertificate(bis);
		// System.out.println(caCert.toString());
	}

	// load client private key
	PEMParser pemParser = new PEMParser(new FileReader(keyFile));
	Object object = pemParser.readObject();
	PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
	JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
	KeyPair key;
	if (object instanceof PEMEncryptedKeyPair) {
		System.out.println("Encrypted key - we will use provided password");
		key = converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv));
	} else {
		System.out.println("Unencrypted key - no password needed");
		key = converter.getKeyPair((PEMKeyPair) object);
	}
	pemParser.close();

	// CA certificate is used to authenticate server
	KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
	caKs.load(null, null);
	caKs.setCertificateEntry("ca-certificate", caCert);
	TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
	tmf.init(caKs);

	// client key and certificates are sent to server so it can authenticate
	// us
	KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
	ks.load(null, null);
	ks.setCertificateEntry("certificate", cert);
	ks.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(),
			new java.security.cert.Certificate[] { cert });
	KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
	kmf.init(ks, password.toCharArray());

	// finally, create SSL socket factory
	SSLContext context = SSLContext.getInstance("TLSv1.2");
	context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

	return context.getSocketFactory();
}

 

 

이렇게 하면 mqtt + ssl 통신을 할 수 있습니다. 

위에서 생성한 pem 파일들을 client 측에서 사용하면 암호 통신이 가능합니다.