🔏

AWS IoT Coreで独自CAで署名した証明書を使う話

2023/10/15に公開

はじめに

AWS IoT Coreにて、クライアント証明書(デバイス証明書)をIoT Coreが発行した証明書を使うのではなく、自前のCAを使って署名した証明書を使う場合の話[1]

自前のCA証明書をIoT Coreに登録する手順がでてくるので混乱しがちだが、今回はクライアント認証の話であり、IoT Coreのエンドポイント(およびサーバー証明書のCN)は通常通り*.iot.ap-northeast-1.amazonaws.comである。つまり、クライアントがIoT Coreに接続する際にはサーバー証明書のルート証明書はAmazonの AmazonRootCA1.pem を使うことになる。

いろいろとオプションがありそのPro/Conは以下公式の引用の通り。基本的にはモードはSNI_ONLYにしておけばよくて、JITRを使うのであればCAの証明書を登録、そうでなければデバイスの証明書のみを登録という考え方で良いと思う。

JITRは別途やってみたい。

クライアント証明書の登録

クライアントと AWS IoT 間の通信を有効にするには、クライアント証明書を AWS IoT に登録する必要があります。各クライアント証明書を手動で登録するか、クライアントが AWS IoT に初めて接続したときにクライアント証明書が自動的に登録されるように設定できます。

クライアントやデバイスの初回接続時にクライアント証明書を登録させたい場合は、クライアント証明書の署名に使用したCA証明書を使用するリージョンでAWS IoTに登録する必要があります。Amazon Root CA は自動的に AWS IoT に登録されます。

クライアント証明書は、AWS アカウントおよびリージョンで共有できます。クライアント証明書を使用するアカウントおよびリージョンごとに、以下の手順を実行する必要があります。あるアカウントやリージョンでクライアント証明書を登録しても、別のアカウントやリージョンでは自動的に認識されません。

独自のクライアント証明書を作成する

デバイスやクライアントが最初に AWS IoT に接続したときにそのクライアント証明書を登録する (ジャストインタイムのプロビジョニングとも呼ばれます) 場合、AWS IoT に署名用 CA を登録して自動登録を有効にする必要があります。

署名 CA を登録できない場合は、CA なしでクライアント証明書を登録することを選択できます。CA なしで登録されたデバイスの場合、AWS IoT への接続時に Server Name Indication (SNI) を提示する必要があります。

注記 CA を使用してクライアント証明書を登録するには、階層内の他の CA ではなく、AWS IoT に対して署名 CA を登録する必要があります。

注記 CA 証明書は、リージョン内の 1 つのアカウントでのみ DEFAULT モードで登録できます。CA 証明書は、リージョン内の複数のアカウントで SNI_ONLY モードで登録できます。

実際にやってみる

OpenSSLはこんな感じ。

openssl version
OpenSSL 3.1.1 30 May 2023 (Library: OpenSSL 3.1.1 30 May 2023)

CA証明書

何はともあれ、デバイスの証明書に署名するCA証明書が必要。

CAの秘密鍵を作成

openssl genrsa -out ca.key 2048

CA証明書の作成

openssl req -x509 -new -nodes \
    -key ca.key \
    -sha256 -days 1024 \
    -out ca.crt \
    -subj "/CN=MyCA"

CA証明書をIoT Coreに登録する

CERTIFICATE_ID=$(aws iot register-ca-certificate \
    --ca-certificate file://ca.crt \
    --certificate-mode SNI_ONLY \
    --set-as-active \
    --query 'certificateId' \
    --output text)
    
aws iot describe-ca-certificate --certificate-id $CERTIFICATE_ID

登録したCA証明書を確認する

aws iot describe-ca-certificate --certificate-id $CERTIFICATE_ID

デバイス証明書

デバイスの秘密鍵を作る

openssl genrsa -out device.key 2048

デバイスの秘密鍵からCSRを作る

openssl req -new \
    -key device.key \
    -out device.csr \
    -subj "/CN=MyDevice"

CSRにCA証明書で署名してデバイスの証明書を作る

openssl x509 -req \
    -in device.csr \
    -CA ca.crt \
    -CAkey ca.key \
    -CAcreateserial \
    -out device.crt \
    -days 500 -sha256

デバイス証明書をIoT Coreに事前登録

Option1. デバイス証明書に署名したCAがIoT Coreに登録されている場合

CERTIFICATE_ARN=$(aws iot register-certificate \
    --set-as-active \
    --certificate-pem file://device.crt \
    --ca-certificate-pem file://ca.crt \
    --query 'certificateArn' \
    --output text)

echo $CERTIFICATE_ARN

確認する

aws iot list-certificates --query "certificates[?certificateArn=='$CERTIFICATE_ARN']"    

Option2. デバイス証明書に署名したCAをIoT Coreに登録しない場合

CERTIFICATE_ARN=$(aws iot register-certificate-without-ca --status ACTIVE --certificate-pem file://device.crt)
    
echo $CERTIFICATE_ARN

Thingを作る

THING_NAME=$(cat /dev/urandom | LC_ALL=C tr -dc 'a-z0-9' | head -c 8; echo)
echo $THING_NAME

aws iot create-thing --thing-name $THING_NAME

Thingにデバイス証明書をアタッチする

aws iot attach-thing-principal --principal $CERTIFICATE_ARN --thing-name $THING_NAME

デバイス証明書にポリシーをアタッチする。

p1は事前に作成してある。

aws iot attach-policy \
    --target $CERTIFICATE_ARN \
    --policy-name p1

クライアントから接続する

END_POINT=$(aws iot describe-endpoint --endpoint-type iot:Data-ATS --query endpointAddress --output text)

mosquitto_pub --cafile AmazonRootCA1.pem \
  --cert device.crt \
  --key device.key \
  -h $END_POINT \
  -p 8883 \
  -t t1 \
  -d \
  -m '{"id":1}' \
  -i $THING_NAME

mosquitto は -h で指定したホストをSNIとして送信しているはず

その他

証明書の中身を見るコマンド

openssl x509 -in ca.crt -text -noout

ここだけサーバ側の証明書の話になる。実際にTLSでやり取りされているサーバ側の証明書をWiresharkで引っこ抜いて上のコマンドで覗いてみるとIssuerSubjectはこんな感じ。なるほどこういうトラストチェーンになってるのか。

Issuer: C = US, O = "Starfield Technologies, Inc.", OU = Starfield Class 2 Certification Authority
Subject: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Services Root Certificate Authority - G2
Issuer: C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Services Root Certificate Authority - G2
Subject: C = US, O = Amazon, CN = Amazon Root CA 1
Issuer: C = US, O = Amazon, CN = Amazon Root CA 1
Subject: C = US, O = Amazon, CN = Amazon RSA 2048 M01
Issuer: C = US, O = Amazon, CN = Amazon RSA 2048 M01
Subject: CN = *.iot.ap-northeast-1.amazonaws.com

参考にしたサイト

脚注
  1. IoT Coreが署名するデバイス証明書での接続方法については以前に「AWS IoTにRubyのMQTTクライアントから接続」に書いた。 ↩︎

Discussion