Multitenancy

Bosch IoT Things service provides various ways to support solution developers in creating multitenant-ready applications by allowing to restrict the access rights on things and their messages at different levels.

Multitenancy as a principle

Multitenancy is the capability of a single application instance to handle different tenants while the strict separation of their data is ensured.

This principle is fully implemented by the Things service:

  • The cloud platform marketplace will not show any customer who else has booked our service
  • When working with a thing we apply strict control by always:
    • Identifying which solution tries to call the service,
    • Authenticating technical clients or users, and
    • Authorizing technical clients and user based on the thing’s own data.

Permissions on a thing

Our main concept is, that a thing belongs in the first place to the solution which has “created” the thing. Thus the solution is fully responsible for setting the initial permission for the specific thing. To ensure all your solution parts which need to access your things are not handicapped, grant all your client IDs permission on the thing.

Tenant identifier included in namespace

In addition to the concept on how you can create a thing ID (see Things and features, regarding multitenancy the best practice would be to include the tenant identifier within the namespace. This would allow to reflect the affiliation of a thing to a distinct tenant, even at the persistence level. However, always on top make sure to set the rightful actors as authorized subjects in the thing’s policy.

Including the tenant information is useful for either a setup where different subscriptions of the Things service are used for different tenants, or for a setup where a common Things service subscription is used. In the latter case, please be aware of restrictions regarding the number of namespaces per instance. See restrictions.

Example 1

Tenant 1 and Tenant 2 will share your solution but must not be aware of the existence of one another:

Tenant 1 Tenant 2
Solution ID 123 123
Device Integration Client 123:deviceIntegration 123:deviceIntegration
Web UI Client 123:WebUI 123:WebUI
Namespace com.bosch.iot.maker.tenant1 com.bosch.iot.maker.tenant2
Thing ID com.bosch.iot.maker.tenant1:sensorxyz com.bosch.iot.maker.tenant2:sensorxyz
Policy Tenant1-Policy authorizes
- users, groups, roles from own Tenant
- your solution clients
Tenant2-Policy authorizes
- users, groups, roles from own Tenant
- your solution clients

The setup could be as shown in following picture:

tenants

Example 1 - policy for a thing owned by tenant 1

{
  "policyId": "com.bosch.iot.maker.tenant1:sensorxyz",
  "entries": {
    "User-of-Tenant1-Policy": {
       "subjects": {
          "iot-permissions:111-my-all-users-group-ID": {
             "type": "iot-permissions-groupid"
          }
       },
       "resources": {
          "thing:/": {
            "grant": ["READ", "WRITE"],
            "revoke": []
          },
          "policy:/": {
            "grant": ["READ", "WRITE"],
            "revoke": []
          },
          "message:/": {
            "grant": ["READ", "WRITE"],
            "revoke": []
          }
       }
    },
    "Solutions-Policy": {
      "subjects": {
         "iot-things:123:WebUI": {
           "type": "iot-things-clientid"
         },
         "iot-things:123:deviceIntegration": {
            "type": "iot-things-clientid"
         }
      },
      "resources": {
         "thing:/": {
           "grant": ["READ", "WRITE"],
           "revoke": []
         }
      }
    }
  }
}

Example 1 - policy for a thing owned by tenant 2

{
  "policyId": "com.bosch.iot.maker.tenant2:sensorxyz",
  "entries": {
    "User-of-Tenant2-Policy": {
       "subjects": {
            "iot-permissions:222-my-all-users-group-ID": {
            "type": "iot-permissions-groupid"
          }
       },
       "resources": {
          "thing:/": {
            "grant": ["READ", "WRITE"],
            "revoke": []
          },
          "policy:/": {
            "grant": ["READ", "WRITE"],
            "revoke": []
          },
          "message:/": {
            "grant": ["READ", "WRITE"],
            "revoke": []
          }
       }
    },
    "Solutions-Policy": {
      "subjects": {
           "iot-things:123:WebUI": {
           "type": "iot-things-clientid"
         },
           "iot-things:123:deviceIntegration": {
           "type": "iot-things-clientid"
         }
      },
      "resources": {
         "thing:/": {
           "grant": ["READ", "WRITE"],
           "revoke": []
         }
      }
    }
  }
}

Tenant identifier included in client suffix

A further option to make sure one tenant never get to see a thing of another tenant is to fully customize the “tenant-specific” view on the data. In our example we have extended the technical client ID with a tenant identifier, but you can apply the method also for technical client instances respectively. However, always on top make sure to set the rightful actors as authorized subjects.

Example 2

Tenant 1 and Tenant 2 will share your solution but must not be aware of the existence of one another:

Tenant 1 Tenant 2
Solution ID 123 123
Device Integration Client 123:integration 123:integration
Web UI Client 123:WebUItenant1 123:WebUItenant2
Namespace com.bosch.iot.maker.tenant1 com.bosch.iot.maker.tenant2
Thing ID com.bosch.iot.maker.tenant1:sensorxyz com.bosch.iot.maker.tenant2:sensorxyz
Policy Tenant1-Policy
authorizes only users, groups, roles from own Tenant
Tenant2-Policy
authorizes only users, groups, roles from own Tenant

tenants example 2

Example 2 - policy for a thing owned by tenant 1

{
  "policyId": "com.bosch.iot.maker.tenant1:sensorxyz",
  "entries": {
    "User-of-Tenant1-Policy": {
      "subjects": {
         "iot-permissions:111-my-all-users-group-ID": {
           "type": "iot-permissions-groupid"
         }
      },
      "resources": {
         "thing:/": {
           "grant": ["READ", "WRITE"],
           "revoke": []
         },
         "policy:/": {
           "grant": ["READ", "WRITE"],
           "revoke": []
         },
         "message:/": {
           "grant": ["READ", "WRITE"],
           "revoke": []
         }
      }
    },
    "Solutions-Policy": {
      "subjects": {
         "iot-things:123:WebUItenant1": {
           "type": "iot-things-clientid"
         },
         "iot-things:123:deviceIntegration": {
           "type": "iot-things-clientid"
         }
      },
      "resources": {
         "thing:/": {
           "grant": ["READ", "WRITE"],
           "revoke": []
         }
      }
    }
  }
}

Example 2 - policy for a thing owned by tenant 2

{
  "policyId": "com.bosch.iot.maker.tenant2:sensorxyz",
  "entries": {
    "User-of-Tenant2-Policy": {
      "subjects": {
        "iot-permissions:222-my-all-users-group-ID": {
          "type": "iot-permissions-groupid"
        }
      },
      "resources": {
         "thing:/": {
          "grant": ["READ", "WRITE"],
          "revoke": []
        },
         "policy:/": {
          "grant": ["READ", "WRITE"],
          "revoke": []
        },
         "message:/": {
          "grant": ["READ", "WRITE"],
          "revoke": []
        }
      }
    },
    "Solutions-Policy": {
      "subjects": {
        "iot-things:123:WebUItenant2": {
          "type": "iot-things-clientid"
        },
        "iot-things:123:deviceIntegration": {
          "type": "iot-things-clientid"
        }
      },
      "resources": {
         "thing:/": {
           "grant": ["READ", "WRITE"],
           "revoke": []
        }
      }
    }
  }
}
Imprint Legal info Privacy statement