AWS IoTのコード署名を作成してみた
はじめに
サーバーレス開発部@大阪の岩田です。 前回のブログでAWS IoTのジョブ機能を試してみました。
この手順でもソフトウェアの配布自体は可能ですが、本来はソフトウェアが改竄されていないことを保証するためにコードファイルに署名することが推奨されます。 AWS IoTの開発者ガイドでも下記のように紹介されています。
コードをデバイスに送信する場合、ベストプラクティスはコードファイルに署名することです。これにより、デバイスでコードが転送中に変更されているかどうかを検出できます。
このブログでは実際にコード署名を作成する手順についてご紹介します。
やってみる
順を追って進めていきます。
CA証明書の作成
後ほど作成する証明書に署名するためオレオレCA証明書を作成します。 AWS IoTのコード署名では署名アルゴリズムにSHA256WITHECDSAを使う必要があるため、各オプションを適切に設定します。
$ openssl ecparam -genkey -name prime256v1 -out ca.key $ openssl req -x509 -sha256 -new -nodes -key ca.key -days 3650 -out ca.crt You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) []:JP State or Province Name (full name) []:Osaka Locality Name (eg, city) []:Osaka Organization Name (eg, company) []:Classmethod Organizational Unit Name (eg, section) []:Serverless Common Name (eg, fully qualified host name) []:CM-Iwata CA Email Address []:
証明書の作成
作成したオレオレCA証明書を使ってオレオレ証明書を作成します。
$ openssl ecparam -genkey -name prime256v1 -noout -out server.key $ openssl req -new -sha256 -key server.key > server.csr You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) []:JP State or Province Name (full name) []:Osaka Locality Name (eg, city) []:Osaka Organization Name (eg, company) []:Classmethod Organizational Unit Name (eg, section) []:Serverless Common Name (eg, fully qualified host name) []:iwata.classmethod.local Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: $ openssl x509 -req -sha256 -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
ACMに証明書をインポート
作成した証明書をACMにインポートします。
$ aws acm import-certificate --certificate file://server.crt --private-key file://server.key --certificate-chain file://ca.crt
インポートが成功したら署名アルゴリズムがSHA256WITHECDSAとなっていることを確認しARNを控えておきます。
署名用プロファイルの作成
次に署名用のプロファイルを作成します。 まず下記の要領でJSONファイルを用意します。
{ "profileName": "<適当なプロファイル名>", "signingMaterial": { "certificateArn": "<先ほどACMにインポートした証明書のARN>" }, "platformId": "AWSIoTDeviceManagement-SHA256-ECDSA" }
作成したJSONファイルを使って署名用プロファイルを作成します。
$ aws signer put-signing-profile --cli-input-json file://profile.json { "arn": "arn:aws:signer::xxxxxxxxxxxx:/signing-profiles/test_profile" }
バージョニングを有効にしたS3バケットの作成
コード署名にはバージョニングを有効にしたS3バケットが必要になります。 下記のコマンドで作成します。
$ aws s3 mb s3://<適当なバケット名> $ aws s3api put-bucket-versioning --versioning-configuration Status=Enabled --bucket <作成したバケット名>
バケットが作成できたら署名対象となるコードをS3にアップしてバージョンを確認します
$ aws s3 cp <署名対象のファイル> s3://<作成したバケット名> $ aws s3api list-object-versions --bucket <作成したバケット名> --query 'Versions[?Key==`<署名対象のファイル>`]'
コード署名
準備ができたのでコード署名のジョブを実行します。 下記のようなJSONファイルを準備します。
{ "source": { "s3": { "bucketName": "<作成したS3バケット>", "key": "<署名対象のコード>", "version": "<先ほど確認した署名対象コードのバージョンID>" } }, "destination": { "s3": { "bucketName": "<作成したS3バケット>", "prefix": "<署名結果のS3オブジェクトに付与する適当なプレフィックス>" } }, "profileName": "<作成した署名用プロファイルの名前>" }
作成したJSONファイルを使ってコード署名のジョブを開始します。
$ aws signer start-signing-job --cli-input-json file://sign.json { "jobId": "xxxxxxxxxxxxxxxxxx" }
ジョブIDが出力されるので、ジョブの実行状況を確認します。
$ aws signer describe-signing-job --job-id <出力されたジョブID> { "jobId": "xxxxxxxxxxxxxxxxxx", "source": { "s3": { "bucketName": "<作成したS3バケット>", "key": "<署名対象のコード>", "version": "<署名対象コードのバージョンID>" } }, "signingMaterial": { "certificateArn": "<ACMにインポートした証明書のARN>" }, "platformId": "AWSIoTDeviceManagement-SHA256-ECDSA", "profileName": "署名に使用したプロファイル名", "createdAt": 1549621529, "completedAt": 1549621530, "requestedBy": "ジョブを開始したIAMユーザー", "status": "Succeeded", "statusReason": "Signing Succeeded", "signedObject": { "s3": { "bucketName": "<作成したS3バケット>", "key": "<署名結果のオブジェクトキー>" } } }
statusがSucceededになっていれば成功です。 署名結果のオブジェクトキーが出力されているので、適当にDLして中身を確認してみましょう。
$ aws s3 cp s3://<作成したS3バケット>/<署名結果のオブジェクトキー> sign_result.json $ jq . < sign_result.json { "rawPayloadSize": 6610, "signature": "署名", "signatureAlgorithm": "SHA256withECDSA", "payloadLocation": { "s3": { "bucketName": "<作成したS3バケット>", "key": "<署名対象のコード>", "version": "<署名対象コードのバージョンID>" } } }
無事に署名成功です!!
まとめ
初めてAWS IoTのコード署名を作成してみたのですが、コード署名周りはかなり情報が少ない印象でした。 誰かのお役にたてば幸いです。