사전 AWS IoT Core
구현체

AWS IoT Core

gabury1고친 사람 github-actions[bot]

AWS IoT Core 는 흩어진 기기들이 붙어 오는 연결을 아마존이 대신 받아 줍니다. 기기는 내 서버가 아니라 이 서비스에 붙어 메시지를 올립니다. 서비스는 그 메시지를 받아 보겠다고 걸어 둔 쪽과 미리 정해 둔 다른 서비스로 넘깁니다.

쉽고 빠른 이해
  • 무슨 일을 하나 — 기기가 붙는 곳을 내 서버 대신 맡습니다. 온도를 재는 작은 기기가 값을 올리면, 그 값을 받는 곳이 내 서버가 아니라 이 서비스입니다.
  • 왜 이렇게 하나 — 기기 연결을 받는 서버를 내가 띄우고 고치지 않아도 됩니다. 기기가 꺼져 있는 동안 온 메시지도 조건이 맞으면 서비스가 잠깐 맡아 두었다가 다시 붙을 때 건넵니다.
  • 어떻게 도나
    1. 기기는 먼저 자기를 밝히고 붙습니다. 미리 등록해 둔 인증서를 내미는 것이 그 한 방법입니다.
    2. 메시지마다 토픽이라는 이름표를 붙여 올립니다.
    3. 서비스는 그 토픽을 구독한 쪽에 메시지를 다시 보냅니다. 규칙에 적어 둔 다른 서비스로도 넘깁니다.
  • 대가 — 같은 메시지가 두 번 닿을 수 있습니다. 순서도 약속하지 않습니다. 메시지 하나는 128킬로바이트를 못 넘습니다. 요금은 붙어 있던 시간과 메시지 수로 셉니다.

상세

기기 한 대가 AWS IoT Core 에 붙어 메시지 하나를 올리기까지를 따라갑니다. 기기가 어느 주소로 붙나, 올린 메시지가 어디로 가나, 무엇으로 자기를 밝히고 무엇을 해도 되나, 어떤 방식으로 붙나를 차례로 봅니다.

AWS IoT Core 는 AWS(Amazon Web Services, 아마존 웹 서비스)가 운영하는 관리형 서비스입니다. 관리형 서비스는 내려받아 설치하는 프로그램이 아니라, 업체가 띄워 둔 서버에 붙어서 쓰는 서비스입니다. 이름의 IoT 는 Internet of Things, 곧 사물인터넷입니다. 사람이 앞에 앉아 쓰는 컴퓨터가 아니라 기계에 붙은 작은 컴퓨터가 네트워크로 데이터를 주고받는 것을 가리킵니다.

이 서비스가 맡는 일은 기기를 다른 기기와 AWS 클라우드 서비스에 잇는 것입니다. 기기가 이 서비스에 붙을 수만 있으면 그 뒤의 AWS 서비스까지는 이 서비스가 이어 줍니다. 이것이 없으면 기기 연결을 받는 쪽을 내가 띄우고 고쳐야 합니다.

계정마다 받는 엔드포인트

기기가 붙는 곳은 내 서버의 주소가 아니라 내 AWS 계정에 딸린 주소입니다. 이 주소를 엔드포인트라고 부릅니다. 계정마다 따로 나옵니다. 생김새는 이렇습니다.

account-specific-prefix.iot.aws-region.amazonaws.com

앞머리는 계정마다 다릅니다. 가운데에는 리전이 들어갑니다. 리전은 AWS 가 자원을 나눠 두는 지리적 구역입니다.

엔드포인트는 aws iot describe-endpoint 명령으로 얻습니다. 한 번 만들어진 엔드포인트는 바뀌지 않습니다. 그래서 기기에 적어 두고 써도 됩니다. 기기를 새로 붙일 때마다 다시 물을 필요가 없습니다.

기기가 데이터를 주고받는 엔드포인트는 모든 계정에 둘 있습니다. iot:Data-ATS 와 iot:Data 입니다. 둘 가운데 더 새로운 iot:Data-ATS 를 쓰라고 강하게 권합니다. 시만텍 인증 기관을 못 믿겠다는 흐름이 널리 퍼져서 생기는 문제를 피하려는 것입니다.

메시지 브로커와 토픽

기기가 붙는 상대는 메시지 브로커입니다. 메시지 브로커는 보내는 쪽과 받는 쪽 사이에서 메시지를 받아 나눠 주는 프로그램입니다. 기기와 내 애플리케이션은 둘 다 브로커에 붙습니다. 서로 직접 만나지는 않습니다.

메시지에는 토픽이라는 이름이 붙습니다. 토픽 이름은 애플리케이션이 정합니다. sensor/temperature/room1 처럼 빗금으로 층을 나눈 문자열입니다.

보내는 쪽은 받을 상대를 지정하지 않고 토픽만 붙여 올립니다. 이것이 발행입니다. 받고 싶은 쪽은 받을 토픽을 미리 걸어 둡니다. 이것이 구독입니다. 브로커는 메시지를 받으면 그 토픽을 구독한 기기와 클라이언트에 다시 발행합니다. 이렇게 서로를 모른 채 토픽으로만 만나는 방식을 발행-구독이라고 부릅니다.

구독할 때 거는 것은 토픽 이름 하나가 아니라 토픽 필터입니다. 토픽 필터는 어느 토픽의 메시지를 받을지 가리는 문자열입니다. 와일드카드 문자를 넣으면 여러 토픽이 한 번에 걸립니다. # 를 쓰면 그 층과 그 아래의 모든 토픽이 걸립니다. sensor/# 로 구독하면 sensor/ 와 sensor/temperature 와 sensor/temperature/room1 이 걸립니다. 한 층 위의 sensor 는 안 걸립니다.

기기와 브로커가 발행과 구독을 주고받는 말은 주로 MQTT(Message Queuing and Telemetry Transport)입니다. 작은 기기를 염두에 둔 발행-구독 프로토콜입니다. AWS IoT Core 의 MQTT 는 3.1.1 판과 5.0 판 규격을 바탕으로 합니다. 다만 규격과 다른 점이 있습니다. 그 다른 점은 「포기한 것」 절에서 봅니다.

브로커는 받은 메시지를 규칙 엔진으로도 넘깁니다. 규칙 엔진은 메시지 내용을 보고 다른 AWS 서비스로 보내는 부품입니다. 값을 쌓아 두거나 더 처리하는 일은 거기서 이어집니다.

flowchart TD
    D["기기"] -->|"토픽을 붙여 발행"| B["메시지 브로커 · 계정의 엔드포인트"]
    B -->|"그 토픽을 구독한 쪽에 다시 발행"| S["다른 기기 · 내 애플리케이션"]
    B -->|"넘긴다"| R["규칙 엔진"]
    R -->|"규칙 액션"| A["Amazon DynamoDB · AWS Lambda · Amazon S3"]

기기는 받을 쪽을 모른 채 브로커에 한 번 올립니다. 그 한 번이 구독한 쪽과 규칙 엔진 두 길로 나뉩니다. 받는 쪽이 하나 더 늘어도 기기 쪽 코드는 바뀌지 않습니다.

기기가 자기를 밝히는 X.509 인증서

기기가 자기를 밝히는 방법은 다섯 가지입니다. 그중 하나가 X.509 인증서입니다. X.509 는 인증서를 적는 표준 형식입니다. 기기가 내미는 X.509 인증서를 클라이언트 인증서라고 부릅니다. AWS IoT Core 는 이 인증서를 확인해 기기를 인증합니다. 이 방법은 TLS(Transport Layer Security, 전송 계층 보안)로 감싼 MQTT 와 HTTPS(Hypertext Transfer Protocol Secure)에서 씁니다.

연결은 TLS 로 암호화됩니다. 판은 1.2 와 1.3 입니다. 보통의 TLS 연결에서는 서버만 인증서를 내밉니다. AWS IoT Core 에서는 기기도 내밉니다. 양쪽이 서로 확인하는 이 방식을 상호 TLS 라고 부릅니다.

클라이언트 인증서는 먼저 AWS IoT Core 에 등록해야 합니다. 등록 전에는 그 인증서로 통신할 수 없습니다. 기기마다 인증서를 따로 주기를 권합니다. 그래야 인증서 폐기 같은 관리를 기기 하나 단위로 할 수 있습니다. 인증서는 만료되므로 기기는 인증서를 새것으로 바꿔 끼우는 일도 지원해야 합니다.

앞에서 본 엔드포인트 둘은 둘 다 X.509 인증서로 클라이언트를 인증합니다. 옛 iot:Data 엔드포인트가 남아 있는 까닭은 하위 호환입니다. VeriSign 인증서를 쓰는 옛 엔드포인트에서 데이터를 가져가는 기기가 있어서입니다.

무엇을 해도 되는지 정하는 정책

인증서는 누구인지만 밝힙니다. 무엇을 해도 되는지는 정책이 정합니다.

정책은 JSON(JavaScript Object Notation) 문서입니다. AWS 의 권한 체계인 IAM(Identity and Access Management)의 정책과 같은 규칙으로 적습니다. 정책이 허락하거나 막는 일은 브로커에 붙기, MQTT 메시지 보내고 받기, 기기 상태 문서인 디바이스 섀도우를 읽고 고치기입니다.

정책은 X.509 인증서, Amazon Cognito 자격 증명, 사물 그룹에 붙입니다. 사물은 기기 하나를 AWS IoT Core 레지스트리에 등록한 항목입니다.

평가 규칙도 IAM 과 같습니다. 기본은 전부 거부입니다. 어느 정책에서든 명시적으로 허용하면 그 기본을 넘어섭니다. 명시적 거부는 어떤 허용보다 앞섭니다.

붙는 방식

여기까지 본 것을 기기 쪽에서 묶으면 셋을 고르게 됩니다. 어떤 프로토콜로, 어느 포트에, 무엇으로 자기를 밝히며 붙나입니다. 받는 프로토콜은 MQTT, 웹소켓 위에 얹은 MQTT, HTTPS, LoRaWAN(Long Range Wide Area Network) 넷입니다. 앞의 셋은 조합이 정해져 있습니다.

프로토콜 할 수 있는 일 자기를 밝히는 법 포트
MQTT 발행 · 구독 X.509 클라이언트 인증서 8883 · 443
MQTT 발행 · 구독 사용자 지정 인증 443
웹소켓 위의 MQTT 발행 · 구독 Signature Version 4 · 사용자 지정 인증 443
HTTPS 발행만 X.509 클라이언트 인증서 8443 · 443
HTTPS 발행만 Signature Version 4 · 사용자 지정 인증 443

표의 「자기를 밝히는 법」 칸에는 X.509 클라이언트 인증서 말고 둘이 더 나옵니다. 사용자 지정 인증은 AWS IoT Core 안의 사용자 지정 인증 서비스가 맡는 방식입니다. 예시 절의 Tasmota 가 이 방식으로 붙습니다. 거기서는 인증서 대신 비밀번호를 실어 보냅니다. Signature Version 4 와, 정책이 붙는 대상으로 앞에 나온 Amazon Cognito 자격 증명이 각각 무엇을 보고 기기를 가리는지는 확인하지 못했습니다(미확인).

443 포트에 여러 방식이 몰려 있습니다. 기본 설정에서는 서비스가 프로토콜과 포트, 그리고 ALPN(Application Layer Protocol Negotiation) 값을 보고 인증 방식을 가립니다. ALPN 은 TLS 연결을 맺는 첫 인사에 「이 연결로 무슨 프로토콜을 쓸지」를 실어 보내는 확장입니다. 기본 설정에서 443 포트로 X.509 인증서를 내밀며 붙는 MQTT 기기는 ALPN 이름 x-amzn-mqtt-ca 를 실어 보내야 합니다.

MQTT 와 HTTPS 는 할 수 있는 일이 다릅니다. 어느 쪽을 고를지는 아래 표가 가릅니다. 표에 나오는 클라이언트 ID 는 기기가 붙을 때 실어 보내는 이름입니다.

MQTT HTTPS
발행과 구독 둘 다 발행만
꺼져 있던 동안 놓친 메시지를 받나 받는다 못 받는다
클라이언트 ID 쓴다 안 쓴다
기기가 끊긴 것을 알아채나 알아챈다 못 알아챈다
프로토콜 부담 · 전력 소모 적다 많다

올리기만 하는 기기라면 HTTPS 로도 됩니다. 메시지를 받아야 하거나 끊김을 알아야 하면 MQTT 입니다.

포기한 것

AWS IoT Core 가 안 하기로 한 것 셋을 봅니다. 대상은 이 서비스의 브로커가 MQTT 규격과 어긋나거나 일을 덜어 낸 대목입니다. 셋마다 무엇을 내주고 그 대신 무엇이 달라지는지를 짝으로 적습니다. 셋 가운데 하나라도 받아들일 수 없으면 그 일에는 이 서비스가 안 맞습니다. 메시지가 한 번만 닿아야 하는 일, 닿는 순서가 중요한 일, 브로커가 메시지를 오래 들고 있어야 하는 일이 그렇습니다.

정확히 한 번과 순서를 약속하지 않는 전달

MQTT 는 전달을 얼마나 보장할지를 QoS(Quality of Service, 서비스 품질) 단계로 고릅니다. 규격에는 0 · 1 · 2 세 단계가 있습니다. 1단계는 받는 쪽이 PUBACK 패킷으로 받았다고 답할 때까지 다시 보냅니다. 2단계는 PUBREC · PUBREL · PUBCOMP 세 패킷을 더 주고받아 메시지가 한 번만 닿게 맞춥니다.

AWS IoT Core 는 0단계와 1단계만 받습니다. 2단계로는 발행도 구독도 못 합니다. 2단계를 요청하면 브로커가 PUBACK 도 SUBACK 도 보내지 않습니다. SUBACK 은 구독 요청을 받았다고 답하는 패킷입니다. 2단계에 쓰는 세 패킷도 받지 않습니다.

내준 것은 메시지가 한 번만 닿는다는 약속과 닿는 순서입니다. 그 대신 브로커와 기기가 주고받는 패킷에서 2단계용 세 패킷이 빠집니다. 2단계를 안 받기로 한 까닭은 확인하지 못했습니다(미확인). 중복과 순서는 받는 쪽이 떠안습니다.

어긋나는 대목 AWS IoT Core 의 동작
QoS 0 으로 구독 메시지가 0번 이상 닿습니다. 한 번 넘게 닿을 수도 있습니다
다시 보낸 메시지 드물게 같은 메시지를 다른 패킷 ID 로 다시 보냅니다
DUP 플래그 지원하지 않습니다. 다시 보낸 메시지에도 안 붙습니다
순서 메시지와 확인 응답이 닿는 순서를 보장하지 않습니다

표의 패킷 ID 는 브로커와 클라이언트가 패킷 하나를 가리키려고 붙이는 번호입니다. 받는 쪽은 같은 메시지를 두 번 받을 수 있습니다. 다시 보낸 것인지를 DUP 플래그로 알 수도 없습니다. 한 번만 처리해야 하는 일이라면 받는 쪽에서 중복을 걸러야 합니다.

저장과 가공을 규칙 엔진에 넘기는 브로커

브로커가 받은 메시지로 하는 일은 둘입니다. 하나는 그 토픽을 구독한 쪽에 다시 발행하는 것입니다. 다른 하나는 규칙 엔진으로 넘기는 것입니다.

저장과 추가 처리는 규칙 엔진이 다른 AWS 서비스로 이어 줍니다. 쌓아 두고 나중에 꺼내 보려면 그 서비스를 따로 엮어야 합니다. 그 대신 저장소를 규칙마다 고릅니다. 같은 메시지를 Amazon DynamoDB 테이블에 넣을지, Amazon S3 버킷에 둘지, Amazon Kinesis Data Streams 로 흘릴지를 규칙이 정합니다.

브로커가 메시지를 맡아 두는 때도 둘 있습니다. 둘 다 조건이 붙습니다.

지속 세션은 끊겼다 다시 붙는 클라이언트를 위해 브로커가 세션을 들고 있는 것입니다. 들고 있는 것은 구독 목록과, 클라이언트가 아직 받았다고 답하지 않은 QoS 1 메시지입니다. 다시 붙으면 구독이 되살아납니다. 밀린 메시지도 건너갑니다. 만료 전에 다시 안 붙으면 세션이 끝납니다. 맡아 둔 메시지는 버려집니다. 연결할 때 cleanSession 플래그를 1로 두면 브로커는 끊긴 뒤 세션 상태를 아무것도 안 남깁니다.

stateDiagram-v2
    state "붙어 있음" as C
    state "세션 보관 · 만료 시계가 돈다" as S
    state "세션 끝 · 맡아 둔 메시지 버림" as X
    state "남기는 것 없음" as N
    [*] --> C
    C --> S: 끊김 · 지속 세션
    C --> N: 끊김 · cleanSession 1
    S --> C: 만료 전 다시 붙음 · 구독 되살아남
    S --> X: 만료

맡아 두는 일은 끊긴 뒤의 한 구간에서만 일어납니다. 그 구간의 길이가 만료 시간입니다. 기본값과 늘리는 방법은 「운영」 절에 값으로 적었습니다.

retained 메시지는 발행하는 쪽이 RETAIN 플래그를 달아 올린 메시지입니다. AWS IoT Core 는 이 메시지를 저장해 둡니다. 나중에 구독하는 쪽에도 보낼 수 있습니다. GetRetainedMessage 호출로 꺼내 볼 수도 있습니다.

맡아 두는 것 얼마나
지속 세션 구독 목록 · 확인받지 못한 QoS 1 메시지 MQTT 3 에서는 기본 1시간. 늘릴 수 있습니다
retained 메시지 RETAIN 플래그를 단 메시지 토픽마다 한 개. MQTT 3 에서는 바뀌거나 지워질 때까지

표와 아래에서 MQTT 3 이라고 적은 것은 상세에서 본 3.1.1 판입니다.

retained 메시지에는 제약이 하나 더 있습니다. 와일드카드 문자를 넣은 토픽 필터로 구독하면 retained 메시지를 못 받습니다. 받으려면 그 메시지의 토픽과 글자 하나 다르지 않은 필터로 구독해야 합니다. MQTT 5 에서는 정해 둔 메시지 만료 간격(Message Expiry Interval)이 지나면 retained 메시지도 만료됩니다.

클라이언트 ID 하나에 연결 하나

브로커는 클라이언트 ID 로 클라이언트를 가립니다. 클라이언트 ID 는 상세에서 본 대로 기기가 MQTT 로 붙을 때 실어 보내는 이름입니다.

같은 클라이언트 ID 로 두 클라이언트가 동시에 붙어 있을 수 없습니다. 이미 쓰는 ID 로 새 연결이 오면 브로커는 새 연결을 받습니다. 그리고 먼저 붙어 있던 연결을 끊습니다.

내준 것은 한 ID 를 여러 연결이 나눠 쓰는 길입니다. 그 대신 ID 하나가 클라이언트 하나를 가리킵니다. 붙고 끊길 때 나오는 알림 토픽이 이 ID 를 이름에 씁니다. 붙어도 되는 클라이언트를 정하는 정책도 이 ID 로 적습니다. 값은 기기 두 대에 같은 ID 를 넣었을 때 치릅니다. 나중에 붙은 쪽이 먼저 붙어 있던 쪽을 끊습니다.

예시

실물 넷입니다. 앞의 둘은 기기 쪽 소프트웨어가 AWS IoT Core 에 어떻게 붙나입니다. 뒤의 둘은 이 서비스 안에 적어 넣는 규칙과 정책입니다.

Tasmota 의 AWS IoT 연결

Tasmota 는 ESP8266 과 ESP32(Espressif 의 마이크로컨트롤러) 칩에 올리는 펌웨어입니다. 이 펌웨어에는 AWS IoT Core 에 바로 붙는 기능이 있습니다. 붙고 나면 클라우드와 기기가 TLS 로 암호화한 MQTT 로 양쪽 방향 다 주고받습니다.

이 기능이 내세우는 이점은 로컬 게이트웨이가 필요 없다는 점입니다. 라즈베리 파이 같은 로컬 게이트웨이에 Domoticz 같은 오픈소스 소프트웨어를 올려서도 같은 일을 할 수 있습니다. 클라우드에서 전부 하면 그 게이트웨이를 관리하고 갱신하는 수고가 없습니다.

이 기능은 ESP8266 용 미리 빌드한 바이너리에는 tasmota-zbbridge 말고는 안 들어 있습니다. ESP32 빌드에는 모두 들어 있습니다. 쓰려면 직접 빌드해야 합니다. 빌드할 때 user_config_override.h 에 이렇게 적습니다.

C
#ifndef USE_MQTT_TLS
#define USE_MQTT_TLS
#define USE_MQTT_TLS_CA_CERT // Optional but highly recommended
#endif
#ifndef USE_MQTT_AWS_IOT_LIGHT
#define USE_MQTT_AWS_IOT_LIGHT
#endif

Tasmota 8.5.0.1 부터는 기기마다 개인 키와 인증서를 심지 않아도 됩니다. AWS_IOT_LIGHT 가 비밀번호 기반 인증을 씁니다. 설정 한 줄은 이렇습니다.

BackLog SetOption3 1; SetOption103 1; MqttHost a............u-ats.iot.eu-central-1.amazonaws.com; MqttPort 443; MqttUser tasmota?x-amz-customauthorizer-name=TasmotaAuth; MqttPassword YknLuSd2tBY2HodwI/7RqA==

MqttHost 가 상세에서 본 계정 엔드포인트입니다. -ats 로 끝나는 쪽입니다. 리전은 eu-central-1 입니다. 포트는 443 입니다. MqttUser 에는 x-amz-customauthorizer-name=TasmotaAuth 가 실려 있습니다. MqttPassword 에는 비밀번호가 들어 있습니다. 앞의 두 SetOption 이 무엇을 켜는지는 확인하지 못했습니다(미확인).

작은 칩이 치르는 값도 숫자로 나옵니다. 연결은 TLS 1.2 로 암호화됩니다. 평소에 필요한 메모리는 적게는 6.0k 입니다. 연결할 때는 TLS 핸드셰이크 동안 6.6k 가 더 듭니다. 핸드셰이크 동안에는 4.8k 짜리 보조 스택을 힙에 따로 잡습니다. 핸드셰이크가 끝나면 그 스택을 풉니다.

이렇게 큰 덩어리를 잡는 것은 힙 조각화가 너무 심해지면 탈을 낼 수 있습니다. 남은 메모리가 15KB 밑으로 내려가면 크래시가 날 수 있습니다. 핸드셰이크는 80MHz 로 도는 ESP8266 에서 1.2초쯤 걸립니다. 전원이 받쳐 주면 160MHz 로 올려 0.7초쯤으로 줄일 수 있습니다.

esp-aws-iot 의 인증서 내장

Espressif 의 esp-aws-iot 는 ESP32 기반 기기를 AWS IoT Core 에 잇는 SDK(Software Development Kit, 소프트웨어 개발 도구 모음)입니다. AWS IoT Device Embedded C SDK 의 라이브러리를 씁니다.

esp-aws-iot 는 인증서와 키를 안전하게 보관하는 방법을 여럿 지원합니다. 기본은 예제마다 certs/ 폴더의 인증서를 바이너리에 박아 넣는 방식입니다.

Tasmota 는 비밀번호로 붙습니다. esp-aws-iot 는 인증서로 붙습니다. 상세의 표에 있던 두 인증 방식이 두 소프트웨어에서 갈립니다.

규칙 SQL 한 줄

규칙은 SQL(Structured Query Language) 비슷한 문법으로 적습니다.

SQL
SELECT color AS rgb FROM 'topic/subtopic' WHERE temperature > 50

FROM 뒤가 토픽 필터입니다. 이 필터에 맞는 토픽으로 메시지가 올 때마다 규칙이 돕니다. topic/subtopic 토픽에 아래 메시지가 올라왔다고 합시다.

JSON
{
 "color":"red",
 "temperature":100
}

temperature 가 50 보다 크므로 규칙이 걸립니다. 규칙은 color 값만 뽑습니다. AS 가 그 이름을 rgb 로 바꿉니다. 나오는 결과는 이렇습니다.

JSON
{
 "rgb":"red"
}

이 결과가 규칙의 액션으로 넘어가 다음 처리를 받습니다.

클라이언트 ID 에 묶은 정책

사물로 등록하지 않은 기기에 거는 정책 한 덩이입니다.

JSON
{
 "Version":"2012-10-17",
 "Statement": [
 {
 "Effect": "Allow",
 "Action": [
 "iot:Publish"
 ],
 "Resource": [
 "arn:aws:iot:us-east-1:123456789012:topic/${iot:ClientId}"
 ]
 },
 {
 "Effect": "Allow",
 "Action": [
 "iot:Connect"
 ],
 "Resource": [
 "arn:aws:iot:us-east-1:123456789012:client/client1"
 ]
 }
 ]
}

Resource 의 긴 문자열은 ARN(Amazon Resource Name)입니다. AWS 자원 하나를 가리키는 이름입니다. 리전 us-east-1 과 계정 번호가 그 안에 들어 있습니다.

아래 문장은 iot:Connect 를 허락합니다. 대상은 client/client1 이라 클라이언트 ID client1 로만 붙을 수 있습니다. 위 문장은 iot:Publish 를 허락합니다. 대상 토픽 이름에 ${iot:ClientId} 가 들어 있어서, 기기는 자기 클라이언트 ID 와 같은 이름의 토픽에만 발행할 수 있습니다.

맞물림

AWS IoT Core 가 받은 메시지는 그다음 같은 AWS 의 형제 서비스로 넘어갑니다. 저장과 추가 처리가 거기서 일어납니다. 아래 다섯 소절은 어느 쪽이 부르고 무엇이 오가는지를 적습니다.

규칙 액션으로 부르는 서비스

메시지가 들어오면 규칙 엔진은 그 메시지에 맞는 규칙이 있는지 봅니다. 있으면 규칙의 SQL 을 평가합니다. 그 결과를 실어 규칙 액션을 부릅니다. 규칙 액션은 규칙이 걸렸을 때 무엇을 할지 적은 것입니다. 부르는 쪽은 AWS IoT Core 입니다. 받는 쪽은 아래 서비스입니다.

규칙 액션 받는 서비스가 하는 일
dynamoDB Amazon DynamoDB 테이블에 메시지를 넣습니다
kinesis Amazon Kinesis Data Streams 로 메시지를 보냅니다
lambda 메시지를 입력으로 AWS Lambda 함수를 부릅니다
s3 Amazon S3 버킷에 메시지를 저장합니다
republish 메시지를 다른 MQTT 토픽으로 다시 발행합니다

붙일 때 치를 값이 둘입니다. 규칙은 대상 자원과 같은 리전에 만들어야 액션이 그 자원에 닿습니다. 액션이 돌면 받는 서비스의 표준 요금이 따로 붙습니다.

규칙이 맡는 IAM 역할

AWS IoT Core 가 내 계정의 다른 서비스를 부르려면 권한이 있어야 합니다. 그 권한은 IAM 역할로 줍니다. IAM 역할은 서비스가 맡아서 그 권한으로 일하는 신분입니다.

규칙을 만들기 전에 필요한 자원에 접근을 허락하는 정책을 단 역할을 먼저 만듭니다. 규칙을 실행할 때 AWS IoT Core 가 이 역할을 맡습니다. 역할에는 신뢰 정책도 붙습니다. 신뢰 정책은 누가 이 역할을 맡아도 되는지 적은 문서입니다. 여기에 iot.amazonaws.com 이 sts:AssumeRole 을 할 수 있다고 적어 둡니다.

권한이 두 쪽으로 갈립니다. 기기가 무엇을 해도 되는지는 상세에서 본 AWS IoT Core 정책이 정합니다. 규칙이 무엇을 부를 수 있는지는 이 IAM 역할이 정합니다.

실패한 액션을 받는 오류 액션

액션이 일시적인 오류로 실패하면 규칙 엔진이 여러 번 다시 시도할 수 있습니다. 전부 실패하면 메시지는 버려집니다. 오류는 CloudWatch Logs 에 남습니다. 실패를 따로 받아 처리하려면 규칙마다 오류 액션을 지정합니다. 오류 액션은 실패가 난 뒤에 불립니다.

규칙에 Amazon S3 버킷 접근 권한이 없을 때가 이런 실패입니다. Amazon DynamoDB 에 미리 잡아 둔 처리량을 넘었을 때도 그렇습니다. 오류 액션이 받는 메시지는 규칙과 메시지 한 쌍마다 하나입니다. 같은 규칙의 액션 둘이 실패하면 두 오류를 함께 담은 메시지 하나가 갑니다.

flowchart TD
    B["메시지 브로커"] --> R["규칙 엔진 · SQL 평가"]
    R -->|"IAM 역할을 맡아 부른다"| A["규칙 액션 · DynamoDB · Kinesis · Lambda · S3"]
    A -->|"다시 시도해도 실패"| X["메시지를 버린다 · 오류는 CloudWatch Logs"]
    A -->|"다시 시도해도 실패 · 지정해 두었으면"| E["오류 액션"]

위에서 아래로 한 메시지가 지나가는 길입니다. 액션까지는 IAM 역할의 권한으로 갑니다. 액션이 끝내 실패하면 메시지는 버려집니다. 오류 액션을 지정해 둔 규칙만 그 실패를 따로 받습니다.

기기와 디바이스 섀도우

디바이스 섀도우는 사물마다 붙는 상태 문서입니다. AWS 가 클라우드에 저장하므로 기기가 붙어 있든 아니든 애플리케이션과 다른 서비스가 그 기기의 상태를 읽고 바꿀 수 있습니다. 섀도우를 붙이고 관리하는 쪽은 디바이스 섀도우 서비스입니다.

섀도우에는 기기가 알려 온 상태(reported)와 바라는 상태(desired)가 따로 적힙니다. 둘이 어긋나면 디바이스 섀도우 서비스가 /update/delta 로 끝나는 토픽에 그 차이를 보냅니다.

flowchart TD
    subgraph SH["섀도우 문서 · 사물마다 하나"]
        DE["바라는 상태 · desired"]
        RE["알려 온 상태 · reported"]
    end
    SH -->|"둘이 어긋나면 그 차이를 보낸다"| T["$aws/things/thingName/shadow/update/delta"]

섀도우 한 장에 칸이 둘입니다. 애플리케이션이 섀도우를 고쳐 기기 상태를 바꿔 달라고 하면, 그 바라는 상태가 기기가 알려 온 상태와 어긋납니다. 그 차이가 /update/delta 토픽으로 기기에 갑니다. 기기는 그 메시지를 받아 자기 상태를 맞춥니다. 그리고 맞춘 상태를 발행합니다. 디바이스 섀도우 서비스가 그 상태를 섀도우의 알려 온 상태에 반영합니다.

기기가 꺼져 있는 동안에도 애플리케이션은 섀도우와 주고받습니다. 기기는 다시 붙으면 섀도우에 적힌 내용을 받습니다. 거기에 맞춰 자기 상태를 바꿉니다. 그리고 맞춘 상태를 발행합니다.

sequenceDiagram
    participant 애플리케이션
    participant 섀도우 as 디바이스 섀도우 서비스
    participant 기기
    Note over 기기: 꺼져 있다
    애플리케이션->>섀도우: 바라는 상태를 적는다
    기기->>섀도우: 다시 붙는다
    섀도우->>기기: 섀도우에 적힌 내용을 건넨다
    기기->>섀도우: 맞춘 상태를 발행한다

기기와 섀도우가 주고받는 토픽은 $aws/things/thingName/shadow/update 처럼 $ 로 시작합니다. $ 로 시작하는 토픽은 AWS IoT Core 가 쓰는 예약 토픽입니다. 허락된 만큼 발행하고 구독할 수 있습니다. 새로 만들 수는 없습니다. 허락되지 않은 발행이나 구독을 하면 연결이 끊길 수 있습니다.

붙고 끊길 때 나오는 수명 주기 이벤트

클라이언트가 붙거나 끊기면 AWS IoT Core 가 예약 토픽에 메시지를 발행합니다. 붙을 때는 $aws/events/presence/connected/clientId, 끊길 때는 $aws/events/presence/disconnected/clientId 입니다. 토픽 끝의 clientId 에는 그 클라이언트의 ID 가 들어갑니다.

이 이벤트는 기본으로 켜져 있습니다. 끌 수는 없습니다. 내 애플리케이션은 이 토픽을 구독해 붙고 끊긴 기기를 알 수 있습니다. 치를 값은 순서와 중복입니다. 수명 주기 메시지는 순서가 바뀌어 올 수 있습니다. 같은 것이 두 번 올 수도 있습니다.

운영

AWS IoT Core 를 굴릴 때 부딪히는 값을 봅니다. 대상은 브로커의 할당량, 연결 유지 간격, 지속 세션의 만료, 정책이 반영되는 시간, 요금을 세는 단위입니다. 할당량은 리전마다 따로 걸립니다.

메시지와 연결의 상한

항목 기본값 늘릴 수 있나
발행 요청 하나의 페이로드 크기 128KB 없다
연결 하나의 초당 발행 요청 100 없다
클라이언트 ID 하나의 초당 연결 요청 1 없다
클라이언트 하나가 보내고 아직 확인받지 못한 QoS 1 발행 100 없다
클라이언트 ID 크기 128바이트 없다
토픽 하나의 빗금 수 7 없다
계정의 동시 연결 500,000 · 일부 리전 100,000 있다
계정에 저장된 retained 메시지 500,000 · 일부 리전 100,000 있다

넘었을 때 무슨 일이 생기는지가 항목마다 다릅니다. 128KB 를 넘는 발행과 연결 요청은 거부됩니다. 초당 발행 100 은 들어오는 발행과 나가는 발행을 함께 셉니다. 꺼져 있는 지속 세션 앞으로 쌓이는 메시지도 여기 들어갑니다. 넘는 발행은 버려집니다.

같은 계정과 같은 클라이언트 ID 의 CONNECT 는 초당 한 번으로 제한됩니다. 확인받지 못한 QoS 1 발행이 100 에 닿으면 서버가 PUBACK 을 돌려줄 때까지 그 클라이언트의 새 발행을 안 받습니다. retained 메시지가 상한에 닿으면 새 retained 메시지는 저장되지 않습니다. 그리고 0바이트보다 큰 retained 발행은 스로틀됩니다. 스로틀은 요청을 받지 않고 늦추거나 돌려보내는 것입니다.

킵얼라이브 간격

킵얼라이브는 오가는 메시지가 없을 때도 연결이 살아 있는지 확인하려고 기기가 정하는 간격입니다. AWS IoT Core 는 30초에서 1200초 사이만 받습니다. 바꿀 수 없는 값입니다.

기기가 요청한 간격 서버가 쓰는 간격
0 · 1200초 초과 1200초
0 보다 크고 30초 미만 30초
30초 ~ 1200초 요청한 값

지속 세션의 만료

지속 세션이 끊기면 만료 시계가 돕니다. 기본은 3600초, 곧 1시간입니다. 만료되면 브로커가 세션을 끝냅니다. 쌓아 둔 메시지는 모두 버립니다.

MQTT 3 에서는 이 1시간이 계정의 모든 세션에 걸립니다. 할당량 증액 절차로 늘릴 수 있습니다. MQTT 5 에서는 세션마다 연결과 끊김 패킷에 만료 간격을 적어 정할 수 있습니다.

늘리면 요금이 오를 수 있습니다. 꺼진 기기 앞으로 더 오래 메시지가 쌓입니다. 그 메시지도 보통 메시지 요금으로 셉니다. 만료 시각은 대략입니다. 세션이 계정 한도보다 최대 30분 더 남을 수 있습니다. 한도보다 짧아지지는 않습니다.

정책이 반영되기까지

정책을 고치면 반영되기까지 6분에서 8분이 걸릴 수 있습니다. AWS IoT Core 가 정책 문서를 캐시해 두기 때문입니다. 방금 권한을 준 자원에 몇 분 동안 못 닿을 수 있습니다. 권한을 거둔 자원에도 몇 분 동안 닿을 수 있습니다.

요금을 세는 단위

금액은 리전과 시점에 따라 바뀌므로 세는 단위만 적습니다.

붙는 대상 세는 단위 계산 예
연결 붙어 있던 시간을 1분 단위로 —
메시지 5KB 단위 8KB 메시지는 둘로 셉니다
디바이스 섀도우 · 레지스트리 작업 레코드 크기 1KB 단위 1.5KB 섀도우 갱신은 작업 둘입니다
규칙과 액션 메시지 크기 5KB 단위 8KB 메시지에 액션 둘을 걸면 규칙 2회분 · 액션 4회분입니다

기기가 아무것도 안 보내도 붙어 있는 동안은 연결 요금이 쌓입니다. 메시지는 크기를 5KB 로 나눠 올림한 수만큼 셉니다.

관련 항목

AWS IoT Core 를 이루는 구성 요소

메시지 브로커 · 토픽 · 엔드포인트 · 규칙 엔진 · AWS IoT 규칙 · 규칙 액션 · 오류 액션 · AWS IoT 정책 · 디바이스 섀도우 · 사물 레지스트리 · 예약 토픽 · 수명 주기 이벤트 · 사용자 지정 인증

AWS IoT Core 가 속하는 상위 분류

AWS · 사물인터넷 · 관리형 서비스 · 클라우드 컴퓨팅 · 메시징 서비스

기기가 AWS IoT Core 에 붙을 때 쓰는 프로토콜

MQTT · MQTT 5 · 웹소켓 · HTTPS · TLS · ALPN · TCP · LoRaWAN

AWS IoT Core 가 규격과 다르게 다루는 MQTT 기능

QoS · 지속 세션 · retained 메시지 · 클라이언트 ID · 킵얼라이브 · 와일드카드 구독 · 클린 세션

기기의 신원을 확인하는 수단

인증서 · X.509 · 클라이언트 인증서 · 공개키 · 상호 TLS · 인증 기관 · 프로비저닝 · Signature Version 4 · Amazon Cognito

기기와 규칙의 권한을 정하는 체계

IAM · IAM 역할 · ARN · 정책 변수 · 명시적 거부

AWS IoT Core 가 메시지를 넘기는 서비스

Amazon S3 · Amazon SQS · Amazon SNS · AWS Lambda · Amazon DynamoDB · Amazon Kinesis Data Streams · Amazon CloudWatch · CloudWatch Logs

AWS IoT Core 와 함께 AWS IoT 를 이루는 서비스

AWS IoT Greengrass · AWS IoT Device Management · AWS IoT Device Defender · AWS IoT Core for LoRaWAN · AWS IoT Device SDK

상시 연결을 직접 감당할 때 걸리는 문제

파일 디스크립터 · 하트비트 · 타임아웃 · 지수 백오프 · 썬더링 허드 · 재접속 · 스로틀링

같은 역할을 두고 겨루는 다른 브로커

Eclipse Mosquitto · EMQX · HiveMQ · RabbitMQ · Azure IoT Hub

AWS IoT Core 에 붙는 기기 쪽 기술

임베디드 · 펌웨어 · 센서 · 엣지 컴퓨팅 · 게이트웨이 · OTA 업데이트 · Tasmota · ESP32 · ESP8266 · esp-aws-iot · 라즈베리 파이

AWS IoT Core 가 따르는 메시지 전달 방식

발행-구독 · 메시지 큐 · 이벤트 기반 모델 · 비동기 · 메시지

다른 이름: IoT Core · aws iot core · 아이오티 코어