创建AWS IoT“事物”随时了解政策和证书 [英] Creating AWS IoT "things" with policies and certificates on-the-fly

查看:168
本文介绍了创建AWS IoT“事物”随时了解政策和证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用NodeJS以及



并且lambda看起来像:

  var AWS = require('aws-sdk'); 

exports.handler = function(event,context,callback){

var region =us-east-1;

var accountId = event.awsAccountId.toString()。trim();

var iot = new AWS.Iot({
'region':region,
apiVersion:'2015-05-28'
});
var certificateId = event.certificateId.toString()。trim();

var certificateARN =`arn:aws:iot:$ {region}:$ {accountId}:cert / $ {certificateId}`;
var policyName =<政策名称> ;
//将物联网政策签署为证书
iot.attachPrincipalPolicy({
policyName:policyName,
principal:certificateARN
},(错误,数据)=> {
if(err&&(!err.code || err.code!=='ResourceAlreadyExistsException')){
callback(err,data);
return;
}
//激活证书
iot.updateCertificate({
certificateId:certificateId,
newStatus:'ACTIVE'
},(错误,数据)=> ; {
if(err)callback(err,data);
else iot.createThing(params,function(err,data){//为此证书创建一个东西
if(err) )callback(err,null);
else {
var params = {
principal:certificateARN,
thingName:< NAME>
};
//将证书附加到此东西
iot.attachThingPrincipal(params,funct ion(err,data){
if(err)callback(err,null);
else回调(null,SUCCESS);
});
}
});
});
});
}

这就是全部。设备第一次尝试连接时会失败,但会在lambda中运行此脚本,一旦设备尝试连接成功完成,它应该可以工作,因为证书已注册并处于活动状态。



使用SDK和Lambda。



如果您没有批量生产设备,我建议使用SDK和Lambda这样做,lambda代码是这样的:

  var AWS = require('aws-sdk'); 

exports.handler = function(event,context,callback){

const region =us-east-1;
const accountId =<您的帐户ID> ;
const BUCKET =<你的桶> ;

var certificateARN;

var iot = new AWS.Iot({
'region':region,
apiVersion:'2015-05-28'
});

event.data.id = getId();
iot.createKeysAndCertificate({
setAsActive:true
},function(err,data){
if(err)callback(err,null);
else {
certificateARN =`arn:aws:iot:$ {region}:$ {accountId}:cert / $ {data.certificateId}`;
uploadCertificatesToS3(event.data.id,data);
iot.attachPrincipalPolicy({
policyName:<你的IOT政策名称>,
本金:certificateARN
},(错误,数据)=> {
if(错误)回调(错误,数据);
else {
var thingName = event.data.id;
iot.createThing({
thingName:thingName,
attributePayload :{
attributes:{},
merge:false
}
},function(err,data){
if(err)callback(err,null) ;
else {
iot.attachThingPrincipal({
principal:certificateARN,
thingName:thingName
},function(err,data){
if(err)callback(err,null);
else callback(null,event.data);
});
}
});
}
});
}
});

函数getId(){
返回Math.trunc(new Date()。getTime()/ 1000)+' - '+ Math.floor((1 + Math.random() )* 0x10000).toString(16).substring(1);
}

函数uploadCertificatesToS3(deviceId,certsData){
返回Promise.all([
新Promise(函数(解析,拒绝){
var base64data = new Buffer(certsData.certificatePem,'binary');
var s3 = new AWS.S3();
s3.putObject({
Bucket:BUCKET,
Key :`$ {event.data.project} / devices-certificates / $ {deviceId} / $ {deviceId} .crt`,
正文:base64data
},函数(错误,数据){
if(err)console.log(Error S3,deviceId);
});
}),
new Promise(function(resolve,reject){
var base64data = new Buffer(certsData.keyPair.PrivateKey,'binary');
var s3 = new AWS.S3();
s3.putObject({
Bucket:BUCKET,
键:`$ {event.data.project} / devices-certificates / $ {deviceId} / $ {deviceId} .key`,
正文:base64data
},函数(错误,数据){
if(错误)console.log(错误S3,deviceId);
});
}),
新Promise(函数(解析,拒绝){
var base64data = new Buffer(certsData.keyPair.PublicKey,'binary');
var s3 = new AWS.S3();
s3.putObject({
Bucket:BUCKET,
Key:`$ {event.data.project} / devices-certificates / $ {deviceId} / $ { deviceId} .public.key`,
正文:base64data
},函数(错误,数据){
if(err)console.log(Error S3,deviceId);
});
})
]);
}
}

这将使用AWS rootCA创建证书,保存他们在s3中,创建事物,将策略附加到证书并将证书附加到事物上,所有这些都只在一个lambda函数中完成。您可以使用以下内容调用此lambda:

  var AWS = require(aws-sdk); 
AWS.config.update({
region:us-east-1
});

新AWS.Lambda()。invoke({
FunctionName:'createDevice',
InvocationType:RequestResponse,
LogType:Tail,
Payload:JSON.stringify({
data:{
name:< NAME> ;,
description:< DESCRIPTION> ;,
project:< PROJECT> ;
}
})
},函数(错误,数据){
if(err)console.log(err);
else console.log(JSON) .parse(data.Payload));
});

在RequestResponselambda执行模式下,当您调用回调函数时,将执行回调lambda,您可以从该lambda接收数据。



建议
您应该创建有限制的IoT策略并使用所有元素我在这里描述你需要配置正确的权限。



问候,


I am using NodeJS along with AWS JS SDK and AWS IoT Device JS SDK in order to automatically create a new thing and assign certificates and policies to it once it connects to my server.

I was following "Just-in-Time Registration" article in order to create, register and activate my CA certificate. As far as I can tell, the CA certificate is successfully added to AWS IoT, activated and enabled for auto-registration.

What I don't understand is how is this step performed (quote from mentioned article):

When a device attempts to connect with an X.509 certificate that is not known to AWS IoT but was signed by a CA that was registered with AWS IoT, the device certificate will be auto-registered by AWS IoT in a new PENDING_ACTIVATION state.

How do I make an "attempt" to connect? Since I was using aws-iot-device-sdk-js SDK, with manually created certificates, I was usually connecting my device like this:

const device = deviceModule.device({
  host: 'myendpoint.iot.us-east-1.amazonaws.com',
  region: 'us-east-1',
  keyPath: `certs/${deviceID}.key`,
  certPath: `certs/${deviceID}.pem`,
  caPath: 'certs/rootCA.pem',
  clientId: deviceID,
  baseReconnectTimeMs: 4000,
  keepalive: 30,
  protocol: 'mqtts',
});

But now I don't have certificate and key to include in keyPath and certPath and I cannot instantiate my device without it.

I tried to create certificates myself, using createKeysAndCertificate() from AWS SDK, saving them to disk, attaching a policy manually, attaching a principal manually even tried to mark certificate as "active" manually, something along these lines:

iot.createThing({ thingName: deviceID }, (err, d) => {
  if (err) {
    console.log(err);
  } else {
    allThings[d.thingName] = d;
    iot.createKeysAndCertificate({ setAsActive: true }, (e, c) => {
      if (e) {
        console.log(e);
      } else {
        fs.writeFile(`certs/${deviceID}.pem`, c.certificatePem, (ef, f) => {
          if (ef) throw ef;
        });
        fs.writeFile(`certs/${deviceID}.key`, c.keyPair.PrivateKey, (ef, f) => {
          if (ef) throw ef;
        });
        iot.attachPrincipalPolicy({
          policyName: 'my-testing-policy',
          principal: c.certificateArn,
        }, (ee, cc) => {
          if (ee) {
            console.log(ee);
          } else {
            iot.attachThingPrincipal({
              principal: c.certificateArn,
              thingName: deviceID,
            }, (prerr, prdata) => {
              if (prerr) {
                console.log(prerr);
              } else {
                iot.acceptCertificateTransfer({
                  certificateId: c.certificateId,
                  setAsActive: true,
                }, (ce, cd) => {
                  if (err) {
                    console.log(err);
                  } else {
                    console.log('cert activated.');
                  }
                });
              }
            });
          }
        });
      }
    });
  }
});

But after all this, when I try to publish something I am presented with an error:

Error: unable to get local issuer certificate
    at Error (native)
    at TLSSocket.<anonymous> (_tls_wrap.js:1092:38)
    at emitNone (events.js:86:13)
    at TLSSocket.emit (events.js:185:7)
    at TLSSocket._finishInit (_tls_wrap.js:610:8)
    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:440:38)

I also tried to subscribe to specific topic, as mentioned in the same article above, aws/events/certificates/registered/e3f0a30... but I've never seen a single message on that topic...

What am I missing here? How do I trigger device certificate and private key generation properly just by using my Just-in-Time certificate?

解决方案

when you want to use your own CA you need to create the certificates with this CA and using openssl. It cant be made by using AWS SDK because you need to use your private rootCA key and AWS has not this main element and aws shouldnt have it. Using your own CA is meaned for mass production, otheway you could use the AWS SDK to create certs with AWS' rootCA.

Using just in time registration

How Just in time registration works?

  1. You need to create your own private rootCA key and only you should have it. You must to protect it due security. You create a cert of this private Key and it is AWS IoT use to identify the ccerts created by your private rootCA.
  2. Since you need to use openssl to create certs for your devices you should use OS instructions or find a library that can do this on NodeJS level. Here is the sample to create your certs by using OS bash script:

    mkdir /iot/certsTemp cd /iot/certsTemp openssl genrsa -out $1.key 2048 openssl req -new -key $1.key -out $1.csr -subj "/C=MX/ST=CDMX/L=CDMX/O=CompanyX/OU=IoT/CN=IoT" openssl x509 -req -in $1.csr -CA /iot/CACerts/CACertificate.pem -CAkey /iot/CACerts/CACertificate.key -CAcreateserial -out $1.crt -days 1850 -sha256 cat $1.crt /iot/CACerts/CACertificate.pem > $1-CA.crt cat $1.crt

And this instructions can be invoked in NodeJs by using something like this:

var sh = spawn('sh', ['bash/generateDeviceCerts.sh', deviceId]);
var pem;
sh.stdout.on('data', (data) => {
    if (data.indexOf('-----BEGIN CERTIFICATE-----') == 0) {
        pem = data.toString();
    }
});
sh.stderr.on('data', (data) => {
    //console.log(`cert stderr: ${data}`);
});
sh.on('close', (code) => {
    if (code == 0) {
        me.uploadCertificatesToS3(deviceId);
    }
});

  1. Once you have this certs you can use them just 1 pair per device. The first time the device try to connect, AWS detects the certs were created by using the rootCA of the user and you can catch this event with IoT Rule engine listen to a topic and invoking a Lambda. The last part of the topic is your rootCA cert id in the AWS IoT

And the lambda looks like:

var AWS = require('aws-sdk');

exports.handler = function(event, context, callback) {

var region = "us-east-1";

var accountId = event.awsAccountId.toString().trim();

var iot = new AWS.Iot({
    'region': region,
    apiVersion: '2015-05-28'
});
var certificateId = event.certificateId.toString().trim();

var certificateARN = `arn:aws:iot:${region}:${accountId}:cert/${certificateId}`;
var policyName = < Policy name > ;
//Asign IoT Policy to certificate
iot.attachPrincipalPolicy({
    policyName: policyName,
    principal: certificateARN
}, (err, data) => {
    if (err && (!err.code || err.code !== 'ResourceAlreadyExistsException')) {
        callback(err, data);
        return;
    }
    //Active the certificate
    iot.updateCertificate({
        certificateId: certificateId,
        newStatus: 'ACTIVE'
    }, (err, data) => {
        if (err) callback(err, data);
        else iot.createThing(params, function(err, data) {//Create a thing for this certificate
            if (err) callback(err, null);
            else {
                var params = {
                    principal: certificateARN,
                    thingName: <NAME>
                };
                //Attach certificate to this thing
                iot.attachThingPrincipal(params, function(err, data) {
                    if (err) callback(err, null);
                    else callback(null, "SUCCESS");
                });
            }
        });
    });
});
}

And this is all. The first time the device try to connect it will fail but will run this script in lambda, once it finish successfully the next time the device try to connect it should work because the certificate is registered and active.

Using SDK and Lambda.

If you dont have a mass production devices i recommend to use SDK and Lambda to do this, the lambda code is something like this:

var AWS = require('aws-sdk');

exports.handler = function(event, context, callback) {

const region = "us-east-1";
const accountId = < YOUR ACCOUNT ID > ;
const BUCKET = < YOUR BUCKET > ;

var certificateARN;

var iot = new AWS.Iot({
    'region': region,
    apiVersion: '2015-05-28'
});

event.data.id = getId();
iot.createKeysAndCertificate({
    setAsActive: true
}, function(err, data) {
    if (err) callback(err, null);
    else {
        certificateARN = `arn:aws:iot:${region}:${accountId}:cert/${data.certificateId}`;
        uploadCertificatesToS3(event.data.id, data);
        iot.attachPrincipalPolicy({
            policyName: < YOUR IOT POLICY NAME > ,
            principal: certificateARN
        }, (err, data) => {
            if (err) callback(err, data);
            else {
                var thingName = event.data.id;
                iot.createThing({
                    thingName: thingName,
                    attributePayload: {
                        attributes: {},
                        merge: false
                    }
                }, function(err, data) {
                    if (err) callback(err, null);
                    else {
                        iot.attachThingPrincipal({
                            principal: certificateARN,
                            thingName: thingName
                        }, function(err, data) {
                            if (err) callback(err, null);
                            else callback(null, event.data);
                        });
                    }
                });
            }
        });
    }
});

function getId() {
    return Math.trunc(new Date().getTime() / 1000) + '-' + Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}

function uploadCertificatesToS3(deviceId, certsData) {
    return Promise.all([
        new Promise(function(resolve, reject) {
            var base64data = new Buffer(certsData.certificatePem, 'binary');
            var s3 = new AWS.S3();
            s3.putObject({
                Bucket: BUCKET,
                Key: `${event.data.project}/devices-certificates/${deviceId}/${deviceId}.crt`,
                Body: base64data
            }, function(err, data) {
                if (err) console.log("Error S3", deviceId);
            });
        }),
        new Promise(function(resolve, reject) {
            var base64data = new Buffer(certsData.keyPair.PrivateKey, 'binary');
            var s3 = new AWS.S3();
            s3.putObject({
                Bucket: BUCKET,
                Key: `${event.data.project}/devices-certificates/${deviceId}/${deviceId}.key`,
                Body: base64data
            }, function(err, data) {
                if (err) console.log("Error S3", deviceId);
            });
        }),
        new Promise(function(resolve, reject) {
            var base64data = new Buffer(certsData.keyPair.PublicKey, 'binary');
            var s3 = new AWS.S3();
            s3.putObject({
                Bucket: BUCKET,
                Key: `${event.data.project}/devices-certificates/${deviceId}/${deviceId}.public.key`,
                Body: base64data
            }, function(err, data) {
                if (err) console.log("Error S3", deviceId);
            });
        })
    ]);
}
}

This will create the certs using the AWS rootCA, save them in s3, create the thing, attach policy to certs and attach certs to the thing, all in just one lambda function. You can invoke this lambda by using somthing like this:

var AWS = require("aws-sdk");
AWS.config.update({
   region: "us-east-1"
});

new AWS.Lambda().invoke({
    FunctionName: 'createDevice',
    InvocationType: "RequestResponse",
    LogType: "Tail",
    Payload: JSON.stringify({
        data: {
            name: < NAME > ,
            description: < DESCRIPTION > ,
            project: < PROJECT >
        }
    })
}, function(err, data) {
    if (err) console.log(err);
    else console.log(JSON.parse(data.Payload));
});

In" RequestResponse" lambda execution mode the callback will be executed when you call "callback" function in the lambda and you can receive data from that lambda.

Suggestions You shoul create IoT policies with restrictions and to use all the elements I have described here you need to configure the correct permissions.

Regards,

这篇关于创建AWS IoT“事物”随时了解政策和证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆