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 측에서 사용하면 암호 통신이 가능합니다.
'개발' 카테고리의 다른 글
| dbeaver 설치 및 사용법 - DB Client DBeaver (3) | 2025.07.18 |
|---|---|
| 2025년 최신 웹호스팅 서비스 비교 – 내 사이트(블로그)에 가장 적합한 호스팅은? (3) | 2025.06.20 |
| java 8 download - 자바 8 다운로드 (4) | 2025.06.19 |
| 구글 Gemini(제미나이) API 무료 사용법 (1) | 2025.05.20 |
| Spring Data JPA vs MyBatis – 언제 어떤 걸 선택할까 (3) | 2025.05.09 |