AWS 기술 블로그

AWS IoT 자격 증명 공급자로 안전하게 IoT 디바이스에서 Amazon S3로 파일 업로드 하기

사물인터넷(IoT)의 발전이 눈부시게 진행되면서, 우리 주변에 연결된 기기들은 빠르게 증가하고 이로 인해 생성되는 데이터 또한 폭발적으로 늘어나고 있습니다. 이런 데이터의 바다 속에서 비즈니스적 가치를 찾기 위해서는 안정적으로 원하는 데이터를 취득하는 것이 중요합니다. IoT 디바이스는 수많은 형태의 데이터를 생성해 내고 있으며, AWS 에서는 AWS IoT Core를 통해 이러한 다양한 센서와 기기 정보 데이터의 안정적이고 보안적인 수집을 지원 하고 있습니다.

AWS IoT Core에서 사용하는 MQTT는 불안전한 네트워크 환경의 경량 통신을 위해 설계 되었으며, 주로 텍스트 기반의 메시지를 효율적으로 전송하는 데 적합한 프로토콜입니다. 그렇기에 대용량의 이미지나 동영상, 방대한 로그 파일등을 AWS상에 업로드 한다면 다른 방법을 활용해야 합니다.

디바이스에서 Amazon S3 API를 호출해서 직접적으로 S3에 업로드 하는 방법이 그 예시입니다. 다만Amazon S3와 같은 AWS 서비스를 호출하는 경우에는 access key ID와 secret access key 기반의 SigV4 인증으로 인증을 해야 서비스 접근이 가능합니다. (AWS IoT X.509인증서로는 AWS IoT이외의 서비스에 대해 직접적인 호출이 불가능 합니다.)
이를 위해서는 IoT 디바이스 별로 IoT Core용 인증서 이외에, 액세스 키를 관리해야 하기에 보안적인 위험이나 운영적인 번거로움이 발생 하게 됩니다.

이번 게시글에서는 AWS IoT 자격 증명 공급자(AWS IoT Credentials Provider) 를 활용해서 이러한 문제를 해결하는 과정을 소개 합니다.

참고: 이 게시물에서는 AWS IoT, AWS CLI 및 IAM에 익숙하다고 가정합니다.

AWS IoT 자격 증명 공급자로 인증서 발급 절차

AWS IoT 자격 증명 공급자는 IoT Core에서 제공하는 기능으로 기기의 인증에 사용되는 X.509 인증서를 통해 임시적으로 Amazon S3와 같은 AWS 서비스에 접근 할 수 있는 보안 토큰을 발급해 주는 기능입니다. 이러한 토큰을 활용하면 access key ID와 secret access key를 기기에 별도 저장하여 관리하며 갱신해 줄 필요가 없습니다.

그러면 조금 더 구체적인 방법을 그림으로 알아보겠습니다.

  1. AWS IoT 디바이스는 AWS SDK나 사용자 정의 클라이언트를 통해, AWS IoT 자격 증명 공급자에게 HTTPS를 이용한 보안 토큰 요청을 보냅니다. 이 때, 사용자가 의도한 디바이스가 요청한 것 임을 인증하기 위해 X.509 형식의 장치 인증서가 포함됩니다.
  2. AWS IoT 자격 증명 공급자는 받은 요청을 AWS IoT Core의 인증 및 권한 부여 모듈로 넘깁니다. 이 모듈은 인증서와 보안 토큰 요청 권한을 검증합니다.
  3. 만약 인증서가 유효하고 인증서와 연결된 정책에서 보안 토큰을 요청할 수 있는 권한이 확인된다면, AWS IoT 인증 및 권한 부여 모듈은 검증 성공 사실을 반환합니다. 그렇지 않은 경우 실패를 반환하며, 이에 대한 상세 정보를 함께 장치에게 알려줍니다.
  4. 검증이 성공적으로 이루어지면, AWS IoT 자격 증명 공급자는 AWS STS(AWS Security Token Service)를 호출하여 미리 설정해둔 IAM 역할(IAM Role)을 요청하게 됩니다.(여기서는 Amazon S3 접근 권한이 됩니다.)
  5. 역할 수행이 성공적으로 이루어지면, AWS STS는 제한된 권한을 가진 임시 보안 토큰을 AWS IoT 자격 증명 공급자에게 반환합니다.
  6. AWS IoT 자격 증명 공급자는 받은 보안 토큰을 다시 디바이스에 전달합니다.
  7. 장치 내의 AWS SDK는 이 보안 토큰을 AWS SigV4로 서명하는데 사용하며, 이를 통해 Amazon S3 업로드를 진행 합니다.

좀더 직관적인 이해를 돕기 위한 애니메이션은 아래와 같습니다.

구현 절차

AWS 환경에서 실제로 이를 구현해 보도록 하겠습니다.

  • 구현 환경: Raspberry pi 4, (AWS의 클라우드 IDE인 Cloud9 등으로 대체 해서 구현 가능합니다.)

1. 사물 생성하기

AWS IoT의 사물은 보안을 위해 사물-인증서-정책이 함께 연결되어야 합니다.
AWS 콘솔에서 AWS IoT Core 대시보드에 접속 후 “디바이스 연결하기”를 클릭하여 이러한 과정을 한번에 진행 할 수 있습니다.

camera-device-id1으로 사물 이름을 지정합니다.

디바이스 플랫폼 운영체제는 Linux/macOS 선택 후 SDK는 Python으로 선택합니다.

2. 디바이스에서 AWS IoT에 연결하기 위해 필요한 연결 키트 다운로드

3. AWS IoT SDK로 X.509인증서 연결 가능 확인하기

디바이스 연결 키트를 다운로드 받은 후 데이터를 전송하려는 디바이스에 연결 키트를 저장하고 압축을 해제 합니다.

  • 명령어: unzip connect_device_package.zip

unzip을 해보면 인증서들이 함께 들어있는 것을 확인 할 수 있습니다. 이를 사용하기 위해 실행 권한을 추가합니다.

  • 명령어: chmod +x start.sh

그 후에 콘솔에 있는 설명 그대로 start.sh를 실행 가능하게 변경하고 실행해 주시면 됩니다.

  • 명령어: ./start.sh

스크립트 실행시 사진 처럼 “Hello World!” 문자열이 보이면서 IoT 디바이스가 MQTT 통신으로 AWS IoT Core와 연결됨을 확인 할 수 있습니다. 이때 통신은 IoT Core의 X.509 인증서로 진행이 됩니다. Ctrl/Cmd+C를 눌러서 프로그램을 중지 시킵니다.

인증서를 통해 IoT Core와 연결됨을 확인 했으니 이제 인증서를 통해 AWS 다른 서비스에 접근이 가능한 토큰을 발급 받을 수 있도록 해보겠습니다.

4. IAM Role 생성하기

(1) 이미지를 업로드할 Amazon S3 버킷을 생성합니다. 버킷명은 camera-image-{계정아이디}로 지정합니다.
(2) 버킷에 업로드 할 수 있는 권한을 가진 정책을 생성합니다.

이때 정책은 AWS IoT 자격 증명 공급자 변수를 통해 지정된 AWS S3 버킷의 특정 폴더에만 업로드 할 수 있도록 권한을 지정해 보겠습니다.

아래 정책은 지정된 버킷/사물이름의 위치에만 저장 할 수 있는 정책입니다.
${credentials-iot:ThingName}과 같은 정책 변수를 통해 사물 이름 등으로 권한 관리가 가능합니다.

AWS IoT 자격 증명 공급자에서 제공하는 정책 변수는 ThingName, ThingTypeName, AwsCertificateId가 있습니다. (ThingName: 사물이름, ThingTypeName: 사물 종류이름, AwsCertificateId: 인증서 ID)

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "AllowS3BucketAccess",
			"Effect": "Allow",
			"Action": ["s3:Putobject"],
			"Resource": ["arn:aws:s3:::camera-image-<계정 아이디로 수정>/${credentials-iot:ThingName}"]
		}
	]
}
JSON

정책명은 IoTCoreDeviceS3UploadPolicy로 지정 합니다.

(3) 정책을 연결할 IAM Role을 생성합니다.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": {
                "Service": "credentials.iot.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
JSON

역할 생성시 사용자 지정 신뢰 정책을 선택하고 AWS IoT 자격 증명 공급자에서 역할을 부여 할 수 있도록 합니다.

(2)에서 생성한 IoTCoreDeviceS3UploadPolicy를 선택하여 연결합니다.

권한 정책 선택 후 역할이름은 IoTDeviceS3UploadRole로 역할을 생성합니다.

5. AWS IoT 자격 증명 공급자 역할 별칭 생성하기

생성한 역할을 기기에서 바로 호출 할 경우 역할을 새롭게 바꾸고 싶은 경우 기기의 코드를 수정해서 호출 하는 대상을 바꿔야 하는 불편 함이 있습니다. 그렇기에 역할 별칭이라는 개념을 두어서 기기는 지정된 역할 별칭을 호출하고, AWS IoT 자격 증명 공급자에서 역할 별칭을 다른 IAM 역할과 연결해 주면 기기 코드 수정 없이도 역할 변경이 가능해 집니다.

IoTDeviceS3UploadRole 역할을 가리키는 IoTDeviceS3UploadRoleAlias 역할 별칭을 생성해줍니다.

이렇게 생성된 역할 별칭으로 지정된 역할의 임시 보안 토큰(또는 임시 자격 증명)을 AWS STS로부터 발급 받을 수 있습니다.

6. IoT 정책에 AWS IoT 자격 증명 공급자 호출 권한 부여하기

디바이스의 인증서로 AWS IoT 자격 증명 공급자에 설정된 역할 별칭을 호출하기 위해서는 별도의 IoT 정책을 생성하여 호출 권한을 부여 해야합니다.

(1) AWS IoT 자격 증명 공급자 호출을 위한 IoT 디바이스의 정책을 생성합니다. 정책 문서에 사진처럼 호출할 역할 별칭을 기입 합니다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:AssumeRoleWithCertificate",
      "Resource": "arn:aws:iot:<지역>:<계정 아이디로 수정>:rolealias/IoTDeviceS3UploadRoleAlias"
    }
  ]
}
JSON

(2) 생성한 정책을 사물의 인증서와 연결합니다.

처음에 생성한 사물의 인증서를 선택합니다.

AWS IoT>관리>사물>{생성한 사물이름}>인증서>연결된 인증서 ID클릭

인증서를 클릭하면 인증서와 연결된 정책을 확인 할 수 있습니다. 정책 연결을 통해 위에서 생성한 AWS IoT 자격 증명 공급자 호출을 위한 IoT 디바이스 정책을 연결합니다.

이렇게 정책까지 연결하면 IoT X.509인증서를 통해 AWS IoT 자격 증명 공급자에 보안 토큰을 요청하여 발행 받을 수 있습니다.

7. 보안 토큰 요청하기

보안 토큰을 요청할 자격증명 공급자의 앤드포인트를 알기 위해서는 AWS 콘솔에서 AWS CloudShell을 띄워서 아래 명령어를 입력하여 확인 하거나, AWS CLI명령어로 터미널에서 확인이 가능합니다.

aws iot describe-endpoint --endpoint-type iot:CredentialProvider
Bash

이렇게 확인한 endpoint를 복사해서 X.509가 있는 디바이스에서 아래 명령어로 요청을 해봅니다. (ssh로 접속한 상태입니다.)

curl --cert {인증서} --key {비밀키} -H "x-amzn-iot-thingname: {사물이름}" https://{자격증명 공급자 엔드포인트}/role-aliases/{역할 별칭} /credentials
Bash

예시

curl --cert camera-device-id1.cert.pem --key camera-device-id1.private.key -H "x-amzn-iot-thingname: camera-device-id1" https://samplename.credentials.iot.ap-northeast-2.amazonaws.com/role-aliases/IoTDeviceS3UploadRoleAlias/credentials
Bash

아래 그림과 같이 accessKeyId와 secretAccessKey, sessionToken을 확인 하실 수 있습니다.

8.보안 토큰으로 S3에 파일 업로드 하기

이제 파이썬 코드로 인증서를 발급 받아서 사진을 Amazon S3에 업로드를 해보겠습니다.
Boto3를 사용해서 세션을 생성하고 해당 세션으로 지정된 버킷에 촬영한 파일을 업로드 합니다. 이를 위해 먼저 Python용 AWS 공통 런타임 라이브러리를 설치합니다.

pip install awscrt

업로드 코드는 아래와 같습니다.

import boto3
from awscrt import io, auth

# 1. X.509 파일 경로 & IoT Credential Provider 정보
ACCOUNT_ID = "<account-id>"
REGION = "ap-northeast-2"
DEVICE_CERT_PATH = "camera-device-id1.cert.pem"
DEVICE_KEY_PATH = "camera-device-id1.private.key"
CA_PATH = "root-CA.crt"
IOT_CREDENTIAL_PROVIDER_ENDPOINT = f"<endpoint>.credentials.iot.{REGION}.amazonaws.com"
ROLE_ALIAS_NAME = "IoTDeviceS3UploadRoleAlias"
THING_NAME = "camera-device-id1"
BUCKET_NAME = f"camera-image-{ACCOUNT_ID}"
LOCAL_FILE_PATH = "image.jpg"
S3_FILE_NAME = "image.jpg"

# 2. TLS 컨텍스트 생성
tls_options = io.TlsContextOptions.create_client_with_mtls_from_path(
    DEVICE_CERT_PATH, DEVICE_KEY_PATH
)
tls_options.ca_dirpath = CA_PATH
tls_context = io.ClientTlsContext(tls_options)

# 3. X.509 임시 자격 증명 공급자 생성
x509_provider = auth.AwsCredentialsProvider.new_x509(
    endpoint=IOT_CREDENTIAL_PROVIDER_ENDPOINT,
    thing_name=THING_NAME,
    role_alias=ROLE_ALIAS_NAME,
    tls_ctx=tls_context,
)

# 4. S3 업로드 함수
def upload_image_s3(image_path, bucket, key, region=REGION):
    creds_future = x509_provider.get_credentials()
    creds = creds_future.result(timeout=10)  # 임시 자격증명 획득

    session = boto3.Session(
        aws_access_key_id=creds.access_key_id,
        aws_secret_access_key=creds.secret_access_key,
        aws_session_token=creds.session_token,
        region_name=region,
    )
    s3 = session.client("s3")
    s3.upload_file(image_path, bucket, key)
    print(f"Uploaded to s3://{bucket}/{key}")

# 5. 실행
if __name__ == "__main__":
    upload_image_s3(
        image_path=LOCAL_FILE_PATH,
        bucket=BUCKET_NAME,
        key=f"{THING_NAME}/{S3_FILE_NAME}",
    )
Python

코드를 실행해 보면 Amazon S3에 라즈베리 파이로 촬영한 사진이 업로드 된 것을 볼 수 있습니다.

결론

지금까지 X.509 인증서와 AWS IoT 자격 증명 공급자를 활용하여 이러한 문제를 해결하는 과정을 소개 합니다.통해 AWS에 접근 가능한 임시 보안 토큰을 발급 받고, 로그 파일이나 이미지 파일등을 Amazon S3에 업로드 가능합니다.

이 외에 IoT 장치에서 인증서로 발급 받은 보안 토큰을 활용 하는 예는 아래와 같습니다.

  • 보안 토큰으로 Kinesis Video Stream와 연결하여 실시간 스트리밍 데이터 전송
  • 디바이스의 로그데이터 Amazon CloudWatch로 전송
  • 대용량 데이터 스트리밍 전송시 Kinesis Data Stream로 전송
  • 디바이스에서 AWS Lambda를 직접적으로 호출 하는 경우
Juheon Choi

Juheon Choi

최주헌 솔루션즈 아키텍트는 IoT 및 데이터 분석 경험을 바탕으로고객이 클라우드를 통한 비즈니스의 가치 창출을 달성 할 수 있도록고객과 함께 효율적인 아키텍처를 구성하는 역할을 수행하고 있습니다.

Jinseon Lee

Jinseon Lee

이진선 IoT Solutions Architect는 IoT 및 Robotics 서비스 담당 SA로서 다양한 산업군 고객들의 Workload에 맞는 IoT 서비스들을 소개하고 IoT 서비스들을 적용한 최적의 아키텍쳐를 구성하도록 기술적인 도움을 제공해드리고 있습니다.