I am trying to create IoT devices on the Google Cloud through a Python script.
I have set up the project, IoT registry and authenticated my GCloud and linked the GOOGLE_APPLICATION_CREDENTIALS to the json from the corresponding service account.
Why I use the command line to create an account, e.g.
gcloud iot devices create dev01 --project=... --region=... --registry=...
,
it works.
However, my Python script (run through command prompt) does not seem to yield the same results. I used https://cloud.google.com/iot/docs/samples/device-manager-samples#iot-core-create-rs256-python for the iot_v1 reference.
# Generate Key
key = rsa.generate_private_key(backend=default_backend(), public_exponent=65537, key_size=2048)
# Get Public
public_key = key.public_key().public_bytes(serialization.Encoding.OpenSSH, serialization.PublicFormat.OpenSSH)
# Get Private
pem = key.private_bytes(encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption())
# Decode to UTF-8
private_key_str = pem.decode('utf-8')
public_key_str = public_key.decode('utf-8')
# Write keys
with open('Key Pairs/'+deviceName+'_private.pem', 'wb') as file:
file.write(pem)
with open('Key Pairs/' + deviceName + '_public.pem', 'wb') as file:
file.write(public_key)
# Create Device
client = iot_v1.DeviceManagerClient()
parent = client.registry_path(PROJECTID, REGION, REGISTRY)
deviceTemplate = {
'id': deviceName,
"credentials": [
{
"public_key": {
"format": iot_v1.PublicKeyFormat.RSA_X509_PEM,
"key": public_key_str,
}
}
]
}
client.create_device(request={'parent': parent, 'device': deviceTemplate})
The error traceback is
File "commissioning.py", line 46, in <module>
client.create_device(request={'parent': parent, 'device': deviceTemplate})
File "C:\Users\Niels\AppData\Local\Programs\Python\Python38\lib\site-packages\google\cloud\iot_v1\services\device_manager\client.py", line 728, in create_device
response = rpc(request, retry=retry, timeout=timeout, metadata=metadata,)
File "C:\Users\Niels\AppData\Local\Programs\Python\Python38\lib\site-packages\google\api_core\gapic_v1\method.py", line 145, in __call__
return wrapped_func(*args, **kwargs)
File "C:\Users\Niels\AppData\Local\Programs\Python\Python38\lib\site-packages\google\api_core\grpc_helpers.py", line 59, in error_remapped_callable
six.raise_from(exceptions.from_grpc_error(exc), exc)
File "<string>", line 3, in raise_from
google.api_core.exceptions.PermissionDenied: 403 The caller does not have permission
I guess it is either a problem the way I use iot_v1 or with the permissions of Python. Any help/tips would be much appreciated!
Make sure that the service account being used to create the client has at least the roles/cloudiot.provisioner
Role assigned (if you keep getting the permission errors try adding the roles/cloudiot.admin
role to the service account, as it should grant full control of all IoT devices, find more information about all the available permissions here.)
Once you are sure that the service account has the correct permissions you can take advantage of the the credentials
parameter offered by the iot_v1.DeviceManagerClient() class to make sure you point to the service account key file as explained on the Authentication section of the docs.