클라우드/[AWS] AWS IoT Core

AWS IoT Core Fleet Provisioning을 구현해보자

고웅 2024. 9. 24. 14:05

AWS IoT Core를 실무에서 적용하게 되는 경우 IoT 기기를 생산하는 단계에서 해당 기기에 AWS IoT Core와 연결을 할 수 있는 인증서 등 관련 정보를 주입한 상태에서 기기를 생산해야 한다. 이번 글에서는 생산 단계에서 적용을 할 수 있는 방법 중 하나인 Fleet Provisioning에 대해 알아보겠다.

AWS IoT Core Fleet Provisioning

AWS IoT Core Fleet Provisioning

1. Device Provisioning

2. Fleet Provisioning을 사용하는 이유

3. Fleet Provisioning 적용해 보기

4. 정리

추천글

1. Device Provisioning

이 전까지 AWS IoT Core와 관련된 포스트를 보면 IoT 기기의 AWS IoT Core와의 연결이나 Device Shadow, IoT Core Custom Authorizer와 같이 기기와 AWS IoT Core와의 연결하는 방법에 대해 주로 다룬다. AWS IoT를 이용하는 기기가 되지 않는 다면 이렇게 수동으로 AWS IoT Core 콘솔을 이용해서 하나씩 등록하는 방법이 있을 수 있다. 하지만 수동으로 등록할 수 있을 정도의 IoT 기기를 관리하는 경우라면 AWS IoT를 이용한 서비스를 기획하는 것은 오히려 오버 테크놀로지가 아닐까? 싶다. 우리가 IoT Core를 이용하려는 이유는 공장에서 생산되는 모든 기기를 IoT Core에 등록하고 IoT Core를 이용해 데이터를 처리하는 등 AWS 서비스들과의 연동을 위해 IoT Core를 사용하는 것이 아닐까? 그러니 수동으로 등록하는 방법이 아닌 자동으로 대량의 기기를 IoT Core에 등록하고 이에 맞는 정책을 지정하는 것이 실제 IoT Core를 사용하려는 주된 이유가 될 수 있을 것이다.

AWS에서는 방법으로 AWS IoT Core에 기기를 대량으로 등록하는 방법을 제공하고 있다.

  • Bulk Registration
    • 등록 파일 (Registration File) : 디바이스 정보를 포함한 CSV 파일을 이용한다. 이 파일에는 디바이스의 고유한 정보가 포함되어 파일을 AWS IoT Core로 업로드하여 대량 등록 프로세스를 시작한다.
    • Fleet Provisioning by Template : 템플릿을 사용하여 다수의 디바이스를 등록하는 방법 템플릿은 디바이스가 프로비저닝 될 때 적용될 정책, 인증서, 사물(Thing) 속성 등을 정의한다.
    • Fleet Provisioning by Claim : 클레임 인증서를 사용하여 초기 연결을 수행한 후, 개별 디바이스가 자체적인 인증서와 IoT 정책을 획득한다. 이를 통해 초기 프로비저닝이 간소화되고, 나중에 디바이스가 개별 인증서와 정책으로 관리된다.
  • Just-In-Time Registration(JITR) : 사전에 등록되지 않은 디바이스가 처음 연결될 때 인증서를 통해 자동으로 등록하는 방식. 인증서가 수 있는 CA로 서명된 경우, 디바이스는 자동으로 등록되고 사용할 수 있다.
  • Just-In-Time Provisioning(JITP) :  JITR과 유사하지만, 디바이스가 등록될 때 인증서와 IoT 정책도 함께 자동으로 생성되는 방식
  • 사용자 정의 프로비저닝 : Lambda 함수를 이용해 사용자 정의 로직을 포함한 프로비저닝을 구현할 수 있다.

2. Fleet Provisioning을 사용하는 이유

이 포스트에는 소개만 했던 JITP 방식을 초기에 경험이 있다. 이때 인증을 위해 CA를 커스텀으로 등록을 해야 했다 즉 CA를 만들어서 추가를 했어야 하는 것이었다. 하지만 CA를 생성하고 관리하는 등의 수고가 추가되는 것이 부담이었다. 특히 개발자 인력이 부족한 작은 부서에서 이를 적용한다는 것은 어떤 문제를 일으킬지 모르기 때문에 Fleet Provisioning을 적용하는 방법을 검토했다.

 

Fleet Provisioning for Embedded Linux Devices with AWS IoT Greengrass

Introduction Managing a large fleet of embedded devices can be complex and challenging,...

dev.to

그중에 이번 실습을 통해 실험할 방식은 Fleet Provisioning by Claim 방식이다.

Claim 인증서를 사용하는 방법은 초기 연결에 Claim인증서를 이용해 인증을 한 후 개별 인증서를 발급받아 적용하기 때문에 보안이 강화된다.

Fleet provisioning 시나리오 예시

위 이미지는 실제 업무에서 사용하기 위한 설명 이미지로 작성되었었다.

소개하자면 공장에서 생산과정에서 사용되는 컴퓨터가 있으며 이 컴퓨터에는 Claim 인증서가 저장되어 있다. 기기의 생산에 있어 최종적으로 해당 컴퓨터를 통해 생산에 문제가 없는지 테스트하는 과정이 있는데 이 과정에서 생산에 있어 문제가 없었다고 판단되면 Claim 인증서를 이용해 AWS IoT Core에 Fleet Provisioning 과정을 진행하게 되고 이때 AWS IoT Core로부터 받은 인증 파일을 IoT 기기 내부에 저장을 하고 생산 공정 컴퓨터 내에서 기기 인증서 정보를 삭제하고 다음 기기의 생산을 진행하는 것이다. 

위 방법은 사실 변형된 Fleet Provisioning일 수 있다. 왜냐하면 IoT 기기 내부에 Claim 인증서가 저장되어 출고된 후 사용자가 IoT 기기의 설정을 진행하고 최초 실행 시 자동으로 고유한 인증서를 받아와서 IoT Core와 연결하는 것이 정석? 일 수 있기 때문이다. 하지만 위 방법은 생산 공정에 위치한 컴퓨터가 생산 과정에서 기기에 저장할 인증서를 받아와서 저장하는 방법이기 때문이다.

위 내용을 처음 구상한 뒤 얼마 지나지 않아 AWS와 미팅을 가졌고 해당 자리에 AWS IoT Specialist 분께서 참석해 주셨고 위 내용이 정석? 이 맞는지 문의를 했고 다음과 같은 답변을 얻었다.

Device Provisioning 과정에서 정석이 없다. 즉 실제 사용 환경에 따라 다 다른 방법을 사용한다 어떤 기업은 API를 사용하여 백엔드에서 기기 등록을 커스텀으로 처리하기도 한다. 문의 준 방법 역시 가능한 방법의 하나이다.

3. Fleet Provisioning 적용해 보기

Bootstrap 인증서 생성

AWS IoT Core 콘솔 - 보안 - 인증서로 이동한 뒤 인증서 생성을 클릭한다.

신규 인증서 자동 생성을 클릭한 뒤 인증서 상태를 활성으로 선택하여 생성을 클릭한 뒤. 이후 인증서와 관련된 Device Certificate, Public Key, Private Key를 다운로드한다.

Fleet Provisioning 용 Lambda 생성

AWS Lambda 콘솔로 이동 후 함수 생성을 클릭한다.

함수 이름은 원하는 이름(Fleet Provisioning 관련 이름 설정)으로 입력하고 Python 3.12를 선택.

Lambda를 생성한 뒤 코드를 작성한다.

import json
from datetime import date

provision_response = {
    'allowProvisioning': False,
    "parameterOverrides": {"CertDate": date.today().strftime("%Y%m%d")}
}


def handler(event, context):

    # Future log Cloudwatch logs
    print("Received event: " + json.dumps(event, indent=2))

    ### Validate the claim with extreme prejudice here against back-end logic and whitelisting.
    ### If good ...
    provision_response["allowProvisioning"] = True

    return provision_response

 

 

automated-iot-fleet-provisioning-by-claim/SubTemplates/IoT/Lambdas/provision_hook/app.py at master · aws-samples/automated-iot-

Contribute to aws-samples/automated-iot-fleet-provisioning-by-claim development by creating an account on GitHub.

github.com

실습 과정에 포함된 위 코드에는 별도의 기기 인증 과정이 포함되지 않았다. 하지만 실제 업무에 적용하는 과정에서는 DB에 연결하는 코드를 추가하여 기기의 Validation을 진행하여 인증된 기기에 대해 Provisioning을 진행하면 될 것이다.

device_serial = event["parameters"]["SerialNumber"]

코드 작성이 완료되면 Lambda 함수를 배포한다.

Fleet Provisioning Template 생성

다시 AWS IoT Core 콘솔에 이동

AWS IoT - 연결 - 여러 디바이스 연결로 이동한다.

위와 같은 페이지에서 프로비저닝 템플릿 생성을 클릭한다.

여러 시나리오가 있는데 그중에 클레임 인증서로 디바이스 프로비저닝을 선택한 뒤 다음을 누른다.

프로비저닝 템플릿 상태를 활성으로 체크하고 프로비저닝 템플릿 이름을 작성한다. DemoFleetProvisioning으로 작성했지만 원하는 이름이 있다면 해당 이름을 변경하라

이후 프로비저닝 역할에 새 역할을 생성한다.

역할을 생성한 뒤 적용을 한다. 이다음으로 Claim 인증서가 가질 수 있는 권한을 제한해야 하므로 IoT 정책 생성을 클릭한다.

정책 이름을 설정한다. 나는 DemoFleetProvisioningClaimPolicy로 설정했는데 원하는 이름을 지정하는 것이 좋다.

 

정책 문서를 JSON으로 작성한다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:Connect"
      ],
      "Resource": [
        "*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:Publish",
        "iot:Receive"
      ],
      "Resource": [
        "arn:aws:iot:<aws-region>:<aws-account-id>:topic/$aws/certificates/create/*",
        "arn:aws:iot:<aws-region>:<aws-account-id>:topic/$aws/provisioning-templates/<templateName>/provision/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "iot:Subscribe",
      "Resource": [
        "arn:aws:iot:<aws-region>:<aws-account-id>:topicfilter/$aws/certificates/create/*",
        "arn:aws:iot:<aws-region>:<aws-account-id>:topicfilter/$aws/provisioning-templates/<templateName>/provision/*"
      ]
    }
  ]
}

<templateName> 에는 DemoFleetProvisioning이라고 변경했다. 본인이 설정한 템플릿 이름을 입력하면 된다.

<aws-region>과 <aws-account-id>를 본인의 값으로 변경하는 것을 잊지 말자

이제 생성을 클릭해 정책을 생성한다.

다시 템플릿 생성 화면으로 돌아가서 클레임 인증서 프로비저닝 정책을 방금 생성한 정책의 이름으로 설정한다. 그다음 아래의 클레임 인증서에 제일 처음 생성했던 클레임 인증서 값을 확인하여 활성 상태인지 확인하고 왼쪽 체크 박스를 클릭한다. 이후 다음을 누른다.

다음 프로비저닝 작업 설정에서 이전에 만든 Lambda 함수를 선택한다.

자동 사물 생성은 선택 사항이지만 기기 관리를 위해 설정을 했다. 사물 이름 접두사의 경우 본인은 basestation이라는 실무에서 사용하던 이름을 지정했지만 원하는 값으로 지정해도 된다. 예를 들어 fp_라고 작성할 수 있다.

추가 구성에 사물 유형을 생성하고 등록했다. 이 역시 선택 사항이지만 기기 구분을 위해 설정했다.

다음 버튼을 눌러 디바이스 권한 설정 페이지로 넘어간다. 여기서 Fleet Provisioning에 성공한 기기들에 대한 정책을 정의하게 된다. 정책 생성을 클릭한다.

이 전에 Claim 정책을 생성했듯이 이름을 설정한다. 본인은 FleetPovisioningDevicePolicy로 명명했다. 그다음 정책을 JSON으로 작성한다 아래 정책 예시는 가장 기본 적인 정책인데 현재 실습을 위해 사용하는 정책의 기본형으로 *를 사용해서 모든 동작을 허용한다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:Publish",
        "iot:Subscribe",
        "iot:Connect",
        "iot:Receive"
      ],
      "Resource": [
        "*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:GetThingShadow",
        "iot:UpdateThingShadow",
        "iot:DeleteThingShadow"
      ],
      "Resource": [
        "*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "greengrass:*"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

위의 정책은 실습을 위한 정책이었기 때문에 *를 사용해서 모든 동작을 허용했지만 실제 업무에서는 위와 같은 정책은 위험할 수 있다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:Publish",
        "iot:Receive",
        "iot:PublishRetain"
      ],
      "Resource": [
        "arn:aws:iot:<aws-region>:<aws-account-id>:topic/sensor/data",
        "arn:aws:iot:<aws-region>:<aws-account-id>:topic/device/status",
        "arn:aws:iot:<aws-region>:<aws-account-id>:topic/device/connected"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "iot:Subscribe",
      "Resource": [
        "arn:aws:iot:<aws-region>:<aws-account-id>:topicfilter/sensor/data"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "iot:Connect",
      "Resource": "arn:aws:iot:<aws-region>:<aws-account-id>:client/${iot:Connection.Thing.ThingName}"
    }
  ]
}

위 코드는 내가 사용했던 코드의 예시이다. 이 코드에는 Device Shadow 내용을 제거한 버전이다. 정책을 생성한 뒤 다시 템플릿 생성 페이지로 돌아온 뒤 

왼쪽 버튼 즉 새로고침을 진행한 뒤 작성한 기기에 적용할 정책을 선택한 뒤 다음을 눌러 검토 페이지로 이동 후 최종적으로 템플릿 생성을 진행한다.

Fleet Provisioning용 샘플 코드 실행

AWS에서 Fleet Provisioning을 실행하기 위한 예제 코드를 제공하고 있다.

 

GitHub - aws-samples/aws-iot-fleet-provisioning: Edge Reference Client to demonstrate emerging functionality to manage fleet pro

Edge Reference Client to demonstrate emerging functionality to manage fleet provisioning for IoTCore. - aws-samples/aws-iot-fleet-provisioning

github.com

해당 git repo에 있는 코드를 다운로드한다.

해당 프로젝트를 보면 main.py 와 provisioning_handler.py 가 있다. 이 중 현재 실습에서는 provisioning_handler.py 파일을 확인하겠다.

class ProvisioningHandler:

    def __init__(self, file_path):
        """Initializes the provisioning handler
        
        Arguments:
            file_path {string} -- path to your configuration file
        """
        #Logging
        logging.basicConfig(level=logging.ERROR)
        self.logger = logging.getLogger(__name__)
        
        #Load configuration settings from config.ini
        config = Config(file_path)
        self.config_parameters = config.get_section('SETTINGS')
        self.secure_cert_path = self.config_parameters['SECURE_CERT_PATH']
        self.iot_endpoint = self.config_parameters['IOT_ENDPOINT']	
        self.template_name = self.config_parameters['PRODUCTION_TEMPLATE']
        self.rotation_template = self.config_parameters['CERT_ROTATION_TEMPLATE']
        self.claim_cert = self.config_parameters['CLAIM_CERT']
        self.secure_key = self.config_parameters['SECURE_KEY']
        self.root_cert = self.config_parameters['ROOT_CERT']
    
        # Sample Provisioning Template requests a serial number as a 
        # seed to generate Thing names in IoTCore. Simulating here.
        #self.unique_id = str(int(round(time.time() * 1000)))
        self.unique_id = "1234567-abcde-fghij-klmno-1234567abc-TLS350"

많은 코드가 있지만 현재는 실습이기 때문에 일부 코드만 확인하겠다. 

	# Sample Provisioning Template requests a serial number as a 
        # seed to generate Thing names in IoTCore. Simulating here.
        #self.unique_id = str(int(round(time.time() * 1000)))
        self.unique_id = "1234567-abcde-fghij-klmno-1234567abc-TLS350"

이 코드가 현 실습의 중요 포인트인데 이 값을 이용해 샘플 템플릿을 사용한 Thing 이름 생성에 사용된다.

우리가 이 전에 템플릿을 등록할 때 사물 이름 접두사를 입력했는데 위 샘플 코드를 실행하면 사물이름 접두사에 unique_id 값이 추가되어 Thing Name이 된다.

등록 결괴 예시

이제 가장 처음 생성했던 인증 파일들을 업로드한다. certs 폴더 내부에 3개의 인증서 파일을 업로드한다.

이후 터미널 혹은 AWS IoT Core 콘솔 내부에서 IoT Core 엔드포인트를 확인한다.

aws iot describe-endpoint \
    --endpoint-type iot:Data-ATS

엔드포인트를 확인했다면 config.ini 파일을 수정해야 한다.

[SETTINGS]
# Set the path to the location containing your certificates (root, private, claim certificate)
SECURE_CERT_PATH = <certs 폴더 위치>

# Specify the names for the root cert, provisioning claim cert, and the private key.
ROOT_CERT = root.ca.pem
CLAIM_CERT = <pem.crt 파일 이름>
SECURE_KEY = <private.pem.key 파일 이름>

# Set the name of your IoT Endpoint
IOT_ENDPOINT = <AWS IoT Core 엔드포인트>

# Include the name for the provisioning template that was created in IoT Core
PRODUCTION_TEMPLATE = <Fleet Provisioning 템플릿 이름>
CERT_ROTATION_TEMPLATE = cert_rotation

다음으로 실행을 위한 라이브러리들을 설치해야 합니다.

sudo pip3 install -r requirements.txt

이제 실제 실습을 진행하기 위해 python 파일을 실행합니다.

python3 main.py

AWS IoT Core Fleet Provisioning

위와 같은 표시가 뜨며 실행이 된다. 본인의 실행 과정에서는 에러로 인해 종료되기는 하지만 결과적으로 보면 등록이 성공하며 인증서 파일이 생성이 되는 것을 확인할 수 있다.

빨간색으로 새로 인증서 파일이 생성된 것을 확인 할 수 있다.
unique_id 를 provisioning_test_1로 실행한 결과

이렇게 새로운 Thing이 IoT Core에 등록이 되었다.

내가 작성한 시나리오에 의하면 생성된 인증서를 기기에 다운로드 진행하고 생산 공장의 컴퓨터에서 Claim 인증서를 제외한 기기의 인증서를 삭제하고 다음 기기의 생산을 진행하면 된다.

만약 Fleet Provisioning을 진행한 기기를 AWS IoT Core와 연결이 되는지 확인하고 싶은 경우

2024.09.20 - [클라우드/[AWS] AWS IoT Core] - AWS IoT Core Device Shadow를 알아보자

 

AWS IoT Core Device Shadow를 알아보자

AWS IoT Core에서 빠질 수 없는 Device Shadow에 대해 알아보고 작성자 본인이 디바이스 섀도를 적용하기 위해 수행했던 각종 경험담과 실습 코드를 통해 디바이스 섀도를 이해해 보겠다. AWS IoT Core Devi

www.gowoong.com

2024.09.03 - [클라우드/[AWS] AWS IoT Core] - AWS IoT Core Custom Authorizer 적용해 보자 1부

 

AWS IoT Core Custom Authorizer 적용해보자 1부

AWS IoT Core와 연결을 진행할 때 인증서가 아닌 사용자 지정 권한부여자를 적용하는 방법과 실제 적용당시 발생했던 문제를 소개하며 그 해결 방법도 안내하겠다. AWS IoT Core Custom Authorier 적용목차

www.gowoong.com

2024.09.03 - [클라우드/[AWS] AWS IoT Core] - AWS IoT Core Custom Authorizer 적용해 보자 2부

 

AWS IoT Core Custom Authorizer 적용해보자 2부

1부에서 AWS IoT Core Custom Authorizer를 생성하는 방법을 주로 다뤘다.2024.09.03 - [클라우드] - AWS IoT Core Custom Authorizer 적용해보자 1부2부에서는 모의기기를 이용해 Custom Authroizer를 이용해 MQTT 토픽에 연

www.gowoong.com

이전 포스트를 통해 생성한 모의 IoT 기기에 Cert 정보를 변경해서 연결을 진행해 보면 될 것이다.

 

4. 정리

실습을 통해 AWS IoT Core Fleet Provisioning을 진행해 보았다. 위에서 언급했듯이 Device Provisioning에 있어서 정석?이라는 것이 정의되지 않았다. 각 기업의 상황에 따라 최적의 방법을 사용하면 될 것이다.

그리고 내가 소개한 Fleet Provisioning by Claim 방법을 적용해 IoT Core에 Device Thing을 대량으로 등록하는 방법을 적용하여 원하는 기능을 구현할 수 있었으면 좋겠다.

 

추천글

https://dev.to/iotbuilders/fleet-provisioning-for-embedded-linux-devices-with-aws-iot-greengrass-4h8b

 

Fleet Provisioning for Embedded Linux Devices with AWS IoT Greengrass

Introduction Managing a large fleet of embedded devices can be complex and challenging,...

dev.to

https://github.com/aws-samples/automated-iot-fleet-provisioning-by-claim/blob/master/SubTemplates/IoT/Lambdas/provision_hook/app.py

 

automated-iot-fleet-provisioning-by-claim/SubTemplates/IoT/Lambdas/provision_hook/app.py at master · aws-samples/automated-iot-

Contribute to aws-samples/automated-iot-fleet-provisioning-by-claim development by creating an account on GitHub.

github.com

https://github.com/aws-samples/aws-iot-fleet-provisioning.git

 

GitHub - aws-samples/aws-iot-fleet-provisioning: Edge Reference Client to demonstrate emerging functionality to manage fleet pro

Edge Reference Client to demonstrate emerging functionality to manage fleet provisioning for IoTCore. - aws-samples/aws-iot-fleet-provisioning

github.com