How can I get certificate_id and client_id in AWS IoT Lambda? - amazon-web-services

I am using AWS IoT Core. I've created client side certificate for the device following https://aws.amazon.com/blogs/iot/just-in-time-registration-of-device-certificates-on-aws-iot/. Everything went fine. Problem is that now I want to save client certificate_id and client_id in same table to make a relation between them, but I could not get certificate_id and client_id in one lambda invokation.
for example:
when device make first time conection with its client certificate to IoT server, lambda gets certificate_id but does not get client_id
{
"client_id":"N/A",
"certificateId":"",
"caCertificateId":"",
"timestamp":"",
"certificateStatus":"PENDING_ACTIVATION",
"awsAccountId":"",
"certificateRegistrationTimestamp":""
}
afterwards on publishing any topic I can get client_id but does not get certificate_id
I've tried to get client_id by this rule when first time client make connection to IoT.
SELECT clientId() as client_id , * FROM '$aws/events/certificates/registered/111111111111111'
On Lambda I print event:
{
client_id: 'N/A',
certificateId: '222222',
caCertificateId: '111111111111111',
timestamp: 3333,
certificateStatus: 'PENDING_ACTIVATION',
awsAccountId: '44444',
certificateRegistrationTimestamp: '55555'
}
here "1111.." is my CA certificate.
I want to get certificate_id so that I can active or deactive device using boto3 iot function
response = client.update_certificate(
certificateId='string',
newStatus='ACTIVE'|'INACTIVE'
)
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iot.html#IoT.Client.update_certificate

You can subscribe to connect events on the topic
$aws/events/presence/connected/+
This will allow you to correlate client Id to principal id (certificate).
See https://docs.aws.amazon.com/iot/latest/developerguide/life-cycle-events.html

Related

How can I change websocket connection IDs in AWS API Gateway?

I am curious how does AWS Websocket ApiGateway generate connectionIDs and if it is possible to customize how they are generated?
$context.connectionId = A unique ID for the connection that can be
used to make a callback to the client.
For example, I would like the connection ID to always have the same value (the user ID in my DB) whenever he is connected.
If user ID = 1 then connection ID should also = 1 and it is the client app responsibility to enforce uniqueness.
No, it is not possible to modify the auto-generated connection ID.
When a WebSocket client requests a new connection, API Gateway assigns an auto-generated connection ID e.g. AjKdsJDkDJfgmDJ= to that session and invokes your $connect Lambda function with the ID in the event payload (event.requestContext.connectionId).
You can't answer How is the connection ID generated? as it's not a GUID nor a number but it's definitely a random value generated by something.
You can use this connection ID to send a message directly back to the client in the same function invocation.
If you want to also be able to send a message later on, store the connection ID in a data store - DynamoDB for example - along with a mapping to your user IDs.
This way, you can look up your table by the user ID & then obtain the connection ID for interacting with them and vice-versa.

AWS - SNS (India Text Message) Not sending via Local Routes

Am Using the Java API to try to send SMS to India Numbers.
I have a valid Entity ID and Template ID registered using JIO DLT (https://trueconnect.jio.com/#/)
I am setting Messaage Attributes as following
AWS.SNS.SMS.SMSType - Transactional
AWS.SNS.SMS.SenderID - <My Registered Sender ID>
AWS.MM.SMS.EntityId - <DLT provided Entity ID>
AWS.MM.SMS.TemplateId - <Template ID of the message i want to send>
Am using software.amazon.awssdk.services.sns.SnsClient to send the Request as below...
PublishRequest pb = PublishRequest.builder()
.message(message)
.phoneNumber(snsDefaultCountryCode+to)
.messageAttributes(smsAttributes).build();
PublishResponse result = snsClient.publish(pb);
I do receive the SMS, but via ILDO with international charges. I was expecting the message to go via local routes or at least a response with error 'Entity ID is invalid' or 'Template ID is invalid' etc.
Are there any other steps to do before sending SMS to india using the AWS services?
I believe you need to register the DLT sender id with AWS using a service limit support request on Pinpoint SMS Service.
After AWS support team approves your request, which may take upto 24 hours your SMS will get routed via India with sender id
Please find the reference link for the same here

Google Cloud IoT - Single MQTT client instance for all devices in a registry

I am able to publish events to a device in my Cloud IOT Registry via an MQTT client created this way (using paho python):
self.__client = mqtt.Client(client_id='projects/{}/locations/{}/registries/{}/devices/{}'.format(project_id,
cloud_region,
registry_id,
device_id))
Now I'm wondering if I can create an MQTT client being able to publish events to multiple devices by setting the client id at registry level (i.e. not specifying the device id):
self.__client = mqtt.Client(client_id='projects/{}/locations/{}/registries/{}'.format(project_id,
cloud_region,
registry_id))
This client is not able to connect even if I've added a CA Certificate to the registry.
My question is: can a single MQTT Client instance publish events to a set of devices defined in a registry?
Should I use a gateway instead?
No, you can't send messages to a registry like this.
The way you'd want to do this is either 1) Use a gateway like you say, send one message then spread it to the devices locally. Or 2) Grab the list of devices in the registry using the DeviceManagerClient(), and iterate over them each sending each device the message in a loop.
Check out this: https://cloud.google.com/iot/docs/samples/device-manager-samples#list_devices_in_a_registry
For fetching the list of devices in a registry. Snippet for python:
# project_id = 'YOUR_PROJECT_ID'
# cloud_region = 'us-central1'
# registry_id = 'your-registry-id'
print("Listing devices")
client = iot_v1.DeviceManagerClient()
registry_path = client.registry_path(project_id, cloud_region, registry_id)
devices = list(client.list_devices(request={"parent": registry_path}))
for device in devices:
print("Device: {} : {}".format(device.num_id, device.id))
return devices
So in that for device in devices loop you can call your code to get the MQTT client and send the message you want to the specified device.

AWS SES: Can't send emails from any one of the new regions

I have the problem that i can't send emails from the new aws ses environments, which were introduced a month ago.
All the old ones are working fine (e.g. us-east-1, us-west-2, eu-west-1).
But if I want to send a mail from one of the new environments, e.g. eu-central-1, I just get the error message:
The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
But this can't be the case, because all the old ones are working fine with the same keys.
Therefore I would really appreciate it if sb else could test the sample code with their account to check if they have the same issue.
The new environments are eu-central-1, ap-south-1 and ap-southeast-2. Endpoint Urls
Sample Code:
var ses = require('node-ses');
var client = ses.createClient({ key: '', secret: '', amazon: 'https://email.eu-central-1.amazonaws.com'});
async function sendMessage() {
let options = {};
options.from = "test#aol.com";
options.to = "test2#aol.com";
options.subject = "TestMail";
options.message = "Test";
console.log("Try to sendMessage");
client.sendEmail(options, function (err, data, res) {
console.log("Error: " + JSON.stringify(err));
console.log("Data: " + data);
console.log("res: " + res);
});
}
sendMessage();
The sample code uses the node-ses npm package and you just need to enter aws iam user credentials, which have ses access.
If you want to check different regions, you have to change url in the createClient constructor.
Dont worry, the sample code does not send an email!!!
If the region is working, it should throw an error message similar to this: Email address is not verified. The following identities failed the check in region EU-WEST-1: test#aol.com, test2#aol.com"
Otherwise the error will be the one described above.
I also have to mention that I am currently still in sandbox mode, so maybe the new regions are blocked for sandbox users?
It's because you must be creating the SES credentials from the IAM console . You should instead create the credentials using the SES interface/console.
Follow this article to create smtp credentials using SES interface:
http://docs.amazonwebservices.com/ses/latest/GettingStartedGuide/GetAccessIDs.html.

AWS Lambda for Client to Client Push Notifications

Thanks to this community I've learned that is possible to send AWS SNS Push notifications via Lambda with node.js (as a result of Parse migration). I am still struggling with the following:
Can this be done client to client x likes y's z. Where x is user 1, y is user 2 and z is the object being liked? If so, it seems like Cognito is not required that it can read directly from the database but is that accurate?
Does anyone have an example of how this was implemented?
Again, we don't want to broadcast to all users on a schedule but rather when a client performs an action.
Thanks so much in advance!
Let's say you have Device1 which creates a piece of content. That is distributed to a number of users. Device2 receives this content and "likes" it.
Assumption:
you have registered for push notifications on the device, and created a SNS endpoint on AWS. You have stored that endpoint ARN in your database, and associated it with either the Cognito Id, or the content Id. If your data is normalized, then you'd typically have the SNS endpoint associated with the device.
Your Lambda will need to have access to that data source and look up that SNS endpoint to send push notifications to. This will depend on what sort of data store you are using (RDS, DynamoDB, something else). What sort of access that is, and how you secure it is a whole other topic.
From your Lambda, you fetch the ARN to send the push notification to. If you pass in the content Id from the Like, and have the Cognito Id from the device that Liked it, you can then look up the information you need. You then construct a SNS payload (I'm assuming APNS in this example), then send it off to SNS.
var message = {
"default": "New Like!",
"APNS": {
"aps": {
"alert": "New Like!"
}
}
};
var deviceParams = {
Message: JSON.stringify(message),
Subject: "New Like",
TargetArn: targetArn,
MessageStructure: "json"
};
self.sns.publish(deviceParams, function (err) {
if (err) {
console.error("Error sending SNS: ", err);
}
});
It's not all done for you like it might be with Parse. You need to work a lot harder on AWS, but you have near unlimited power to do what you want.
If this is a bit too much, you may want to consider Google's newly updated Firebase platform. It's very Parse-like: https://firebase.google.com/
Hope that helps you move forward a bit.
Further reading:
http://docs.aws.amazon.com/sns/latest/dg/mobile-push-apns.html
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SNS.html