Study/AWS_Service

AWS IOT를 사용한 MQTT Broker 서버 구축

YGwan 2025. 2. 17. 17:34

 저희 회사는 IoT 디바이스 간의 통신을 MQTT 프로토콜을 사용해서 처리하고 있습니다. 이 때 사용하는 MQTT Broker는 AWS IoT을 사용하고 있습니다. 이번에 처리할 내용이, 저희가 개발하고 있는 Backend 서버에 이 AWS IoT와의 연동을 처리해야 합니다. 그래서 연동을 처리하는 과정에서 생긴 문제와, AWS IoT Core가 어떤건지, 왜 사용했는지 정리하려고 합니다.

 

MQTT Broker

MQTT Broker는 MQTT 프로토콜을 기반으로 하는 메시지 브로커로, 클라이언트 간의 메시지를 중계하는 서버 역할을 합니다. MQTT Broker에는 여러 종류가 있습니다. 크게 클라우드 기반과 오픈소스 기반의 MQTT Broker를 기준으로 정리하자면,

  • 클라우드 기반 MQTT Broker
    • AWS IoT Core
    • Azure IoT Hub
    • EMQX Cloud
  • 오픈소스 MQTT Broker
    • Eclipse Mosquitto
    • EMQX (EMQ)
    • RabbitMQ (MQTT Plugin 지원)

등이 있습니다. 각각이 다 장점이 존재하지만, AWS IoT Core는 강력한 보안 설정을 자동으로 제공해주고, 권한 & 정책을 효율적으로 분리할 수 있으며 AWS에서 제공하는 다양한 서비스(S3, Lamda) 등과 연결해 사용하기 편하다는 장점이 있습니다. 이러한 장점 + AWS 크레딧 지원 등의 이유로 저희는 AWS IoT Core을 사용해서 현재 MQTT Broker를 관리하고 있습니다.

 


AWS IoT Core

 

AWS IOT란

  • AWS에서 제공하는 사물 인터넷(Iot) 플랫폼 서비스로 IoT 장치와 애플리케이션 간의 연결, 통신 및 보안 관리를 지원한다.
  • AWS IoT Core를 사용해 많은 수의 IoT 장치와 연결하고, 데이터 수집 & 저장 & 처리 및 분석하여 비즈니스 용도로 활용 가능하다.
  • AWS IoT Core는 보안과 데이터 프라이버시를 중요시하여 엄격한 보안 제어를 갖추고 있다.
  • X.509 인증서를 사용하여 인증 진행
  • AWS IOT 정책을 통해 기기가 MQTT Publish & Subscribe와 같은 AWS IOT 작업을 수행할 수 있는 권한 부여

 

AWS Things란

  • AWS IoT에서 "Thing"(AWS IoT Thing)은 IoT Core에 등록된 개별 디바이스(장치) 를 의미한다.
  • 즉, 실제 물리적인 IoT 장치를 AWS에서 관리할 수 있도록 디지털로 표현한 객체를 의미한다.
  • 각 Thing(디바이스)마다 고유한 ID 및 인증 정보를 가짐
  • Thing과 연결된 센서 데이터 모니터링 및 원격 제어 가능
  • AWS IoT Core에서 각 Thing의 상태를 추적하고 동기화 가능 (Device Shadow)

 

AWS IoT Core Policy란

  • IoT 디바이스가 AWS IoT Core에 연결할 수 있는지 제어
  • MQTT 메시지를 발행(Publish) 또는 구독(Subscribe)할 수 있는지 제어
  • AWS IoT의 다른 리소스(S3, Lambda, DynamoDB 등)에 액세스할 수 있도록 권한 부여
  • 정책을 통해 특정 IoT 디바이스의 제한된 액세스를 설정 가능

ex)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:Connect",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Publish",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Subscribe",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Receive",
      "Resource": "*"
    }
  ]
}
  • Effect : Allow(허용), Deny(거부)
  • Action : 허용할 AWS IoT 작업
  • Resource : 허용할 리소스

 


원하는 인프라 구조

AWS IoT에 IoT 기기들과 서버가 별도의 Things로 연결되어 있는 상태

 

이를 구현하기 위해서는 AWS IoT Core의 인증 방식에 대해서 알아야 합니다.

 

AWS IoT Core 인증 방식

AWS IoT Core에서는 다음과 같은 3가지 인증 방식을 지원함

  • X.509 인증서 인증
  • Amazon Cognito를 통한 인증
  • IAM 인증을 이용한 SigV4 서명 방식

이 중에서 X.509 인증서 인증이 가장 많이 사용됨.

 

크게 AWS IoT Core는 2가지 인증 방식을 사용하고 있습니다.

항목 AWS IoT 인증서 인증 MQTT 클라이언트 TLS 인증
목적 디바이스의 신원을 증명 안전한 데이터 통신 보장
인증 주체 AWS IoT Core에서 디바이스를 인증 디바이스에서 AWS IoT Core 서버를 인증
구성 요소
  • certificatePem
  • PrivateKey
  • certificatePem
  • PrivateKey
  • AmazonRootCA1.pem
보안 범위 디바이스 수준 네트워크(통신) 수준

 

즉 AWS IoT Core에 서버를 붙이기 위해서는, 디바이스 수준의 인증이 1차적으로 필요하고, 이후에 통신과정에서는 TLS 인증을 통해 통신 수준의 인증을 통해 보안적으로 안전하게 통신합니다.

 

그렇다면, AWS 인증하는 방식에 대해서 설명드리도록 하겠습니다.
기본적으로 AWS CLI을 사용하여 이를 처리하는 방식에 대해서 설명드리겠습니다.

 


AWS 인증서 인증 방법 - AWS IoT 인증서 인증

  • AWS IoT에서 디바이스를 인증하는 방법으로, X.509 인증서 기반으로 동작
  • 각 디바이스는 고유한 인증서를 가지고 있어야 하며, AWS IoT Core는 이 인증서를 통해 디바이스를 신뢰할 수 있는지 확인

 

AWS IoT인증이란?

  • AWS IoT Core에 연결할 때 반드시 사용됨 (IAM 사용자 대신 X.509 인증서를 사용)
  • 각 디바이스마다 고유한 인증서가 필요 (X.509 기반)
  • AWS IoT Core의 보안 정책 (IoT Policy) 를 통해 허용된 디바이스만 접근 가능
  • 디바이스가 AWS IoT Core와 TLS를 통해 보안 연결을 설정할 때 필요

 

X.509 인증서란?

  • X.509 인증서는 공개 키 인프라(PKI, Public Key Infrastructure)**에서 사용되는 표준 인증서 형식으로, 디지털 인증서를 발급하고 관리하는 데 사용된다.
  • 이 인증서는 신뢰할 수 있는 기관(CA, 인증 기관 등)이 발급하며, 사용자의 신원을 확인하고 공개 키를 안전하게 공유하는 역할을 한다.

 

작업 순서

아래 작업은 기본적으로 AWS CLI을 사용하며, AWS Configure에 기본적인 AWS 계정 연동 및 AWS IoT Core 설정을 위한 권한이 있다고 가정한다.

 

1. AmazonCA1 값 생성

curl https://www.amazontrust.com/repository/AmazonRootCA1.pem -o AmazonRootCA1.pem

 

2. 인증서 생성 - AWS IoT에 생성된 Thing과 독립적으로 생성

aws iot create-keys-and-certificate --set-as-active > cert.json

 

※ cert.json 형태

{
    "certificateArn": "arn:aws:iot:...",
    "certificateId": "abcd...",
    "certificatePem": "-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----",
    "keyPair": {
        "PublicKey": "-----BEGIN PUBLIC KEY-----\\n...\\n-----END PUBLIC KEY-----",
        "PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\\n...\\n-----END RSA PRIVATE KEY-----"
    }
}

 

※ 생성되는 key에 대한 설명

  • AWS IoT에서 생성된 키 쌍은 RSA 알고리즘 기반
  • 종류
시작 문자열 형식 설명
-----BEGIN RSA PRIVATE KEY---— PKCS#1
  • RSA 키를 표현하는 오래된 형식
  • AWS IoT에서는 이 형식을 기본으로 사용.
-----BEGIN PRIVATE KEY---— PKCS#8
  • RSA 외에도 여러 알고리즘을 지원하는 최신 표준 형식
  • 예:) EC, DSA 등 포함 가능

 

3. 생성된 인증서 파일에서 값 추출

# 1. certificateArn 저장

# 2. certificateId 저장

# 3. certificate.pem.crt 파일 생성

# 4. private.pem.key 파일 생성

# 5. public.pem.key 파일 생성

# 6. private.pem key(PKCS#1) -> (PKCS#8)

# 7. 권한 설정 (소유자만 읽기/쓰기 가능)

※ 실행 결과

이렇게 관련된 6개의 파일이 생성되는 것을 확인 할 수 있습니다.

 

4. AWS 정책 연결

aws iot attach-policy \
  --policy-name "{정책명}" \
  --target "$(cat certificateArn.txt)"
  • certificateArn.txt 파일에서 인증서 ARN을 읽음.
  • aws iot attach-policy 명령어를 실행하여 해당 인증서에 미리 생성한 정책을 부여함.
  • 이후 해당 인증서를 사용하는 디바이스는 미리 정의된 정책에 해당하는 정의된 권한을 가지게 됨

 

※ 정책이 없을 경우

  • AWS → IoT Core → Security → Policies 에서 Create Policy로 정책 생성 후 연결

 

5. 생성된 파일들을 서버의 특정 경로에 위치시켜 서버 내에서 MqttConfig 설정 시 사용

# applicaton.yml

aws-iot:
  keystore:
    Amazon-CA1: "~/AmazonRootCA1.pem"
    certificate-pem: "~/certificate.pem.crt"
    private-key: "~/private_pkcs8.pem"

 

이렇게 생성한 파일들 (Amazon-CA1, certificate-pem, private-key)을 서버에 등록하는 이유는,
아래에서 처리할 MQTT 클라이언트 TLS 설정에 해당 파일들이 사용되기 때문입니다.

 

PS) 제대로 인증서가 등록되었는지 확인

aws iot describe-certificate --certificate-id "$(cat certificateId.txt)"

 

※ 만약 등록되어있지 않다면,

aws iot update-certificate \
--certificate-id "$(cat certificateId.txt)" \
--new-status ACTIVE

이 명령어를 통해 등록하면 된다.

 

이렇게 X.509 방식을 통한 인증서 인증 방식에 대해서 설명드렸습니다.
그렇다면, 이제부터 MQTT 클라이언트 TLS 설정이 어떤 식으로 동작하는지 설명드리도록 하겠습니다.

 


AWS 인증서 인증 방법 - MQTT 클라이언트 TLS 설정

  • MQTT 클라이언트가 AWS IoT Core 또는 다른 MQTT 브로커와 안전하게 통신할 수 있도록 설정하는 보안 프로토콜
  • AWS IoT Core는 TLS 1.2 이상을 사용하여 모든 MQTT 연결을 암호화해야 합니다.

 

MQTT 클라이언트 TLS 설정

  • TLS (Transport Layer Security) 프로토콜을 사용하여 데이터 암호화
  • AWS IoT Core는 TLS 1.2 이상을 강제 적용하여 보안 유지
  • MQTT 클라이언트는 AWS IoT Core에 접속할 때 TLS 인증서를 사용하여 암호화된 연결을 설정해야 함
  • AWS IoT Root CA 인증서를 필요로 함

 

AWS IoT에서 TLS 사용 이유

  • 기밀성(Confidentiality)
    • TLS는 데이터를 암호화하여 송신자와 수신자 외에는 데이터를 읽을 수 없도록 보호합니다.
  • 무결성(Integrity):
    • TLS는 데이터가 전송 중에 변조되지 않았음을 보장합니다.
  • 인증(Authentication)
    • TLS는 클라이언트와 AWS IoT Core 브로커 간의 상호 인증을 제공합니다.
    • AWS IoT는 디바이스를 인증하기 위해 X.509 인증서를 사용합니다.
※ 서버에서 필요한 작업
- TLS 설정을 위한 certificatePem, PrivateKey, AmazonRootCA1.pem 키 발급

 

MQTT TLS 설정 과정

  1. 클라이언트에서 AWS IoT Core와 TCP 연결을 생성
  2. TLS 핸드셰이크 수행 (AWS IoT Core의 Root CA를 사용하여 신뢰성 검증)
  3. 클라이언트 인증서(X.509)를 사용하여 AWS IoT Core에서 장치 검증
  4. 인증이 성공하면 MQTT 메시지를 안전하게 송수신 가능
이때, AWS IoT 인증과정에서 생성한 certificatePem과 privateKey을 MQTT TLS 인증에서도 그대로 사용한다.
그 이유는,

※ AWS IoT Core는 Mutual TLS(쌍방 TLS) 방식을 사용하기 때문
- 디바이스가 AWS IoT Core를 신뢰하는지 확인 → AmazonRootCA1.pem 사용
- AWS IoT Core가 디바이스를 신뢰하는지 확인 → certificatePem & PrivateKey 사용

즉, AWS IoT Core에 등록한 X.509 인증서를 TLS 연결에서도 그대로 활용

이러한 방식을 통해 TLS 인증 처리가 진행됩니다.

 

이렇게해서 기본적인 연결을 위한 준비가 완료됐습니다.
그렇다면, 지금부터 코드를 통해 이러한 파일을 사용하는 방법을 알려드리도록 하겠습니다.

 


기본적인 MQTT 연결 설정은 아래의 제가 정리한 글에서 확인할 수 있습니다. 저는 위에서 설정한 키 값들을 기준으로 어떻게 TLS 설정을 하는지에 대해 설명드리도록 하겠습니다.

 

IoT 데이터 통신 프로토콜 : MQTT

회사에서 IoT 간의 데이터 통신 시스템을 구축할 필요성이 있다고 해 서버에 적용할 필요가 있었습니다. 현재 IoT 데이터는 MQTT라는 프로토콜을 통해 MQTT Broker(AWS IoT)와 연결되어 통신하고 있으며,

swmobenz.tistory.com

 

MqttConnectOptions

  • MqttConnectOptions는 MQTT 클라이언트가 브로커(AWS IoT Core, Mosquitto 등)와 연결할 때 설정하는 옵션 객체이다.
  • 이 옵션을 통해 보안 설정, 인증 정보, 연결 유지 시간, 자동 재연결 등 다양한 매개변수를 지정할 수 있다.

즉, MqttConnectOptions가 제공하는 많은 옵션 중 보안 설정을 위한 socketFactory를 설정했습니다.

 

※ socketFactory()란

  • socketFactory()는 MQTT 클라이언트가 TLS(SSL) 연결을 설정할 때 사용하는 메서드이다.
  • 특히 AWS IoT Core 또는 보안이 필요한 MQTT 브로커에 연결할 때 사용된다.
  • TLS/SSL을 활성화하여 MQTT 연결을 암호화
  • 클라이언트 인증서(X.509)를 사용하여 AWS IoT와 보안 연결 설정
  • MQTT 클라이언트가 프라이빗 키와 CA 인증서를 사용해 신뢰할 수 있는 연결을 구성
private fun mqttConnectOptions(): MqttConnectOptions {
	val options = MqttConnectOptions().apply {
    	...
    	socketFactory = sslSocketFactory()
	}
	return options
}

private fun sslSocketFactory(): SSLSocketFactory = mqttKeyConfig.createSSLSocketFactory()

 

※ createSSLSocketFactory()

    fun createSSLSocketFactory(): SSLSocketFactory {
        // amazonCA1, certificationPem, privateKey 값 읽기

        // 위에서 읽은 키 값들을 사용해서 KeyStore 객체 생성 (java.security.KeyStore)

        // SSLContext 객체 생성 (javax.net.ssl.SSLContext) -> 이때, 버전은 TLSv1.2이다.

        // KeyManagerFactory를 생성하여 KeyStore 기반 인증 설정 후 초기화

        // SSLContext에 KeyManagerFactory 등록

        // SSLSocketFactory 반환
    }
  • 위에서 생성한 파일들 (AmazonCA1, certificatePem, privateKey)을 읽어 SSLSocketFactory을 생성해 반환하는 코드입니다.
  • CA 값(CA 인증서)과 CertificateKey(디바이스 인증서)는 X.509 PEM 형식이며, Private Key(개인 키)는 RSA 방식으로 암호화되어 있습니다. 따라서, 이를 적절히 디코딩하여 파일을 읽어야 합니다.
이때 주의할 점은, 기본적으로 생성한 private key 값은 PKCS#1 값입니다. 이 파일 자체를 읽어도 되지만 java에서는 기본적으로 해당 파일을 읽을 수 없기 때문에 추가적인 라이브러리가 필요합니다. 하지만 PKCS#8의 경우 기본적으로 java에서 제공하는 라이브러리를 통해 읽을 수 있습니다. 따라서 저는 이 파일 자체를 PKCS#8로 변환하는 작업을 위에서 진행한 후 파일을 업로드 했기 때문에 이 추가적인 라이브러리 추가 없이 파일을 읽을 수 있었습니다.

# 변환 명령어
openssl pkcs8 -topk8 -inform PEM -outform PEM -in private.pem.key -out private_pkcs8.pem -nocrypt

 


※ 정리

AWS IoT Core 관련 블로그들을 많이 봤습니다. 하지만, 제가 연결하는데 그렇게 도움이 되는 블로그들은 사실 많이 없었습니다. (Eclipse Mosquitto 내용이 더 많았습니다.) 그래서 AWS IoT Core에 관한 AWS 공식 문서를 처음부터 끝까지 다 읽었고 그 과정에서 의미 있는 정보들을 많이 얻을 수 있었습니다. 학생 때는 제가 한 경험을 다른 사람들도 많이 해서 여러 블로그를 찾아가면서 개발을 해도 충분히 커버가 가능했습니다. 하지만, 회사를 다니다보니 이제는 블로그들보다 공식 문서를 볼 일들이 더 많은 것 같습니다. 아무래도 일반 사람들이 쓴 블로그보다는 공식 문서가 더 신뢰성이 높고 의미 있는 내용들이 많기 때문입니다. 공식 문서 보는 법을 계속 연습하고 시아를 더 넓게 가져갈 수 있는 개발자가 되어야 될 것 같다는 생각을 매번 하는 것 같습니다.

 

※ 출처