pythongoogle-cloud-platformgoogle-cloud-iot

GCP - Python create IoT device PermissionDenied


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!


Solution

  • 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.