Google Cloud IOT, block communication via API - google-cloud-platform

I'd like to block communication with a device in a registry in Google Cloud IOT.
The gcloud command that is used to block communication: https://cloud.google.com/iot/docs/gcloud-examples#block_or_allow_communication_from_a_device
The Patch API doesn't make it clear how one can block communication of a device using the API
So how is this achieved?

There is an example snippet for patching a device available that may be helpful for you.
Instead of sending a EC value in the patch body, you could update the device to have communication blocked.
In Python, you would do this as:
client = get_client(service_account_json)
registry_path = 'projects/{}/locations/{}/registries/{}'.format(
project_id, cloud_region, registry_id)
patch = {
'blocked': 'True'
}
device_name = '{}/devices/{}'.format(registry_path, device_id)
return client.projects().locations().registries().devices().patch(
name=device_name, updateMask='blocked', body=patch).execute()

Related

Reset a Managed Chrome Device with SDK using Google Apps Script

I'm attempting to create a dashboard for admins to allow them to reset a chrome device managed by GoogleAdmin using google apps script.
I don't see any way to perform a reset using Admin SDK API. Can this be done?
If you want to deprovision and/or disable a ChromeOS device
The supported actions when using the Directory API, according to the documentation here are:
deprovision: Remove a device from management that is no longer active, being resold, or is being submitted for return / repair, use the deprovision action to dissociate it from management.
disable: If you believe a device in your organization has been lost or stolen, you can disable the device so that no one else can use it. When a device is disabled, all the user can see when turning on the Chrome device is a screen telling them that it’s been disabled, and your desired contact information of where to return the device.
Taking this into account, this is how the request would look like:
POST https://admin.googleapis.com/admin/directory/v1/customer/{customerId}/devices/chromeos/{resourceId}/action
If you want to reboot and/or remote powerwash a ChromeOS device
However, if you simply plan on doing a powerwash or a reboot, you can make use of the below information:
REBOOT: Reboot the device. Can only be issued to Kiosk and managed guest session devices.
REMOTE_POWERWASH: Wipes the device by performing a power wash. Executing this command in the device will remove all data including user policies, device policies and enrollment policies.
Warning: This will revert the device back to a factory state with no enrollment unless the device is subject to forced or auto enrollment. Use with caution, as this is an irreversible action!
Taking this into account, this is how the request would look like:
POST https://admin.googleapis.com/admin/directory/v1/customer/{customerId}/devices/chromeos/{deviceId}:issueCommand
Apps Script
As for applying any of these in Apps Script, you will have to add the Admin SDK API advanced service and choose the directory _v1 version and simulate any of the above requests.
Code
Assuming you want to remote powerwash a device, you will have to write something similar to this:
let resource = {
YOUR_RESOURCE_HERE;
"commandType": "REMOTE_POWERWASH"
};
let customerId = 'CUSTOMER_ID';
let deviceId = 'DEVICE_ID';
AdminDirectory.Customer.Devices.Chromeos.issueCommand(resource, customerId, deviceId);
Not what you are looking for?
You can simply create a feature request on Google's Issue Tracker and provide the details with regards to your task by filling in the form here.
Reference
Directory API Manage ChromeOS Devices.

Google Cloud IoT core upload images [duplicate]

I need the system to be secure.
I tired to encode the image with base64 and sending the string via MQTT to Iot Core. Then decode the string with a cloud function and finally storage the decoded image in Google Cloud Storage. The problem is the limited size of a message in MQTT.
Using a Cloud Function and then storage in Google Cloud Storage is not really secure, anyone could hit that url and I loos control of all the ESP32CAM comunication.
Am I missing something? is there a really secure way to send files to Google Cloud Storage from to IoT Core?
Thanks
IoT Core should not be used to transfer big blobs.
However, you can take advantage of the secure connection between IoT Core and the device to send credentials to the device to access GCS securely.
Create a service account with write only access to your GCS bucket.
Pass a key for that service account to the device through IoT Core(via configuration change, for example)
The device then can use that key to connect securely to GCS and upload the image.
Depending on your preferences and the particular use case you can rotate the keys to access GCS whenever you want, or be as granular as you want with the permissions (one key for all the devices, one key per device, ...)
The way I've done it is to break the image up into 256K packages (well, 255K-ish with a header of 8 bytes that's an int which represents the order it should be reassembled on the other end since Pub/Sub isn't guaranteed ordering).
#rbarbero's answer is another good one, where you send down creds to talk to GCS directly.
Another way to do it would be to have the device talk to something local that's more powerful which has that service credential directly to GCS and just bypass IoT Core entirely.
No need to base64 encode it and the pubsub MQTT buffer can be resized.
I use:
#include <PubSubClient.h>
...
void setup() {
...
boolean res = mqttClient.setBufferSize(50*1024); // ok for 640*480
if (res) Serial.println("Buffer resized."); else Serial.println("Buffer resizing failed");
...
}
void sendPic() {
...
if (fb->len) // send only images with size >0
if (mqttClient.beginPublish("test_loc/esp32-cam/pic_ms", fb->len + sizeof(long), false))
{
// send image data + millis()
unsigned long m = millis();
int noBytes;
noBytes = mqttClient.write(fb->buf, fb->len);
noBytes = mqttClient.write((byte *) &m, sizeof(long));
if (!mqttClient.endPublish())
{
// error!
Serial.println("\nError sending data.");
}
}
...
}
Here I send 640*480 image and append current millis() value at the end for stitching it back to video through ffmpeg.

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.

Connection to Google IoT with Hive MQTT client instead of Paho

I have working code similar to this connecting to google IoT with the paho client.
Since I am in a spring boot reactive application, I would like to use Hive MQTT Client, but I can't find the right setup, I keep having the following error message :
com.hivemq.client.mqtt.exceptions.ConnectionClosedException: Server closed connection without DISCONNECT.
The current code I use :
hiveClient = MqttClient.builder()
.identifier(UUID.randomUUID().toString())
.serverHost("mqtt.googleapis.com")
.serverPort(443)
.useMqttVersion3()
.sslWithDefaultConfig()
.simpleAuth(
Mqtt3SimpleAuth.builder()
.username("unused")
.password(StandardCharsets.UTF_8.encode("// a token string generation that works fine with palo"))
.build()
)
.build()
.toBlocking();
hiveClient.connect(); // Error
It looks like the identifier (client ID) should be set to something other than a UUID. The documentation indicates the client ID should be formed as the following path:
projects/PROJECT_ID/locations/REGION/registries/REGISTRY_ID/devices/DEVICE_ID
Note that all of the requirements for the Google Cloud IoT Core MQTT device bridge are strict, so also verify that Hive is configured as follows:
Mqtt 3.1.1
TLS 1.2
Publish to /devices/DEVICE_ID/events or /devices/DEVICE_ID/state
Subscribe to /devices/DEVICE_ID/config or /devices/DEVICE_ID/commands/#
QoS 0 or 1
Note that if you do not adhere to the requirements, your device gets disconnected. Additional information on the disconnect reason may be available in the logging for your registry visible on the Cloud Console for IoT.

Is it possible to connect to the Google IOTCore MQTT Bridge via Javascript?

I've been trying to use the javacscript version of the Eclipse Paho MQTT client to access the Google IOTCore MQTT Bridge, as suggested here:
https://cloud.google.com/iot/docs/how-tos/mqtt-bridge
However, whatever I do, any attempt to connect with known good credentials (working with other clients) results in this connection error:
errorCode: 7, errorMessage: "AMQJS0007E Socket error:undefined."
Not much to go on there, so I'm wondering if anyone has ever been successful connecting to the MQTT Bridge via Javascript with Eclipse Paho, the client implementation suggested by Google in their documentation.
I've gone through their troubleshooting steps, and things seem to be on the up and up, so no help there either.
https://cloud.google.com/iot/docs/troubleshooting
I have noticed that in their docs they have sample code for Java/Python, etc, but not Javascript, so I'm wondering if it's simply not supported and their documentation just fails to mention as such.
I've simplified my code to just use the 'Hello World' example in the Paho documentation, and as far as I can tell I've done things correctly (including using my device path as the ClientID, the JWT token as the password, specifying an 'unused' userName field and explicitly requiring MQTT v3.1.1).
In the meantime I'm falling back to polling via their HTTP bridge, but that has obvious latency and network traffic shortcomings.
// Create a client instance
client = new Paho.MQTT.Client("mqtt.googleapis.com", Number(8883), "projects/[my-project-id]/locations/us-central1/registries/[my registry name]/devices/[my device id]");
// set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
// connect the client
client.connect({
mqttVersion: 4, // maps to MQTT V3.1.1, required by IOTCore
onSuccess:onConnect,
onFailure: onFailure,
userName: 'unused', // suggested by Google for this field
password: '[My Confirmed Working JWT Token]' // working JWT token
function onFailure(resp) {
console.log(resp);
}
// called when the client connects
function onConnect() {
// Once a connection has been made, make a subscription and send a message.
console.log("onConnect");
client.subscribe("World");
message = new Paho.MQTT.Message("Hello");
message.destinationName = "World";
client.send(message);
}
// called when the client loses its connection
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:"+responseObject.errorMessage);
}
}
// called when a message arrives
function onMessageArrived(message) {
console.log("onMessageArrived:"+message.payloadString);
}
I'm a Googler (but I don't work in Cloud IoT).
Your code looks good to me and it should work. I will try it for myself this evening or tomorrow and report back to you.
I've spent the past day working on a Golang version of the samples published on Google's documentation. Like you, I was disappointed to not see all Google's regular languages covered by samples.
Are you running the code from a browser or is it running on Node.JS?
Do you have a package.json (if Node) that you would share too please?
Update
Here's a Node.JS (JavaScript but non-browser) that connects to Cloud IoT, subscribes to /devices/${DEVICE}/config and publishes to /devices/${DEVICE}/events.
https://gist.github.com/DazWilkin/65ad8890d5f58eae9612632d594af2de
Place all the files in the same directory
Replace values in index.js of the location of Google's CA and your key
Replaces [[YOUR-X]] values in config.json
Use "npm install" to pull the packages
Use node index.js
You should be able to pull messages from the Pub/Sub subscription and you should be able to send config messages to the device.
Short answer is no. Google Cloud IoT Core doesn't support WebSockets.
All the JavaScript MQTT libraries use WebSocket because JavaScript is restricted to perform HTTP requests and WebSocket connections only.