Policy
A policy enables developers to configure fine-grained access control for things and other entities in an easy way.
The policy concept is only supported for
Bosch IoT Thing HTTP API version 2.
Find the API reference at Policies resources.
Authorization concept
A specific policy provides someone (called subject), permission to READ and/or WRITE at a given resource.
The WRITE permission at the policy root
resource (i.e. “
policy:/
") allows to manage the policy itself.
Find an example at the end of the page.
Please note, that in most cases it makes sense to grant READ permission in addition to a WRITE permission, because WRITE does not imply READ.
Who can be addressed?
A subject can be a technical client or a user.
Examples for subjects
{
"subjects": {
"bosch:xxx-bosch-id-xxx@ciamids_xxx-client-id-xxx": {
"type": "bosch-id-user-account"
},
"integration:xxx-solution-id-xxx:hub": {
"type": "hub-connection"
},
"iot-suite:/service-instance.xxx-solution-id-xxx.iot-things@iot-things": {
"type": "suite-auth-token",
"expiry": "2020-12-24T12:00:00Z"
},
"iot-things:xxx-solution-id-xxx:my-client":{
"type": "iot-things-client-id"
},
"google:xxx-google-id-xxx":{
"type": "google-id",
"expiry": "2020-12-18T12:00:00Z"
},
"your-project:your-subject/your-scope1@your-client":{
"type": "custom-oauth-provider"
}
}
}
Built-in subject ID pattern
You can find the subject IDs for your current authentication, using the
Who Am I
-REST call.
See
FAQ > How to find the authorization subject IDs that I can use in policies?
Prefix / issuer (mandatory) | ID (mandatory) | Type (informational) | Description | Example |
---|---|---|---|---|
bosch |
<BoschId>@<clientId> |
bosch-id | Recommended notation: the ID of a Bosch account (<BoschId> ) and the client ID (<clientId> ) separated by an at (@ ) character. |
bosch:xxx-bosch-id-xxx@456 |
integration |
<solutionId>:<your-postfix> |
hub, amqp, or mqtt | The ID of a technical client, used for receiving or publishing messages over Connections |
integration:xxx-solution-id-xxx:hub |
iot-suite |
/<iot-things-scope>@<clientId> |
suite-auth | Recommended notation: a slash (/ ) followed by the "Client Scope" of Bosch IoT Things (<iot-things-scope> ) and "Client ID" (<clientId> ) of the OAuth2 client managed at Bosch IoT Suite portal separated by an at (@ ) character.See https://accounts.bosch-iot-suite.com/oauth2-clients/ |
iot-suite:/service-instance.4-5-6.iot-things@7-8-9 |
iot-suite |
/organization.<org-guid>.<Role> |
team-role | Recommended notation: a slash (/ ) followed by `organization`, a dot (`.`), the `See Bosch IoT Suite for Device management > Auth for subscription management |
iot-suite:/service-instance.4-5-6.iot-things@7-8-9 |
iot-things |
<solutionId>:<your-postfix> |
iot-things-client-id | The ID of a technical client (Java client) |
iot-things:xxx-solution-id-xxx:my-app |
google |
<UUID> |
google-id | The ID of a Google user | google:123 |
Outdated and alternative versions
Prefix / issuer (mandatory) | ID (mandatory) | Type (informational) | Description | Example |
---|---|---|---|---|
bosch |
<BoschId> |
bosch-id | The ID of a Bosch account (<BoschId> )Not recommended any longer. Use the new notation with the client ID for production scenarios. |
bosch:xxx-bosch-id-xxx |
iot-suite |
<BoschId>/<iot-things-scope>@<clientId> |
suite-auth | The ID of a Bosch account (<BoschId> ),followed by a slash ( / ), the "Client Scope" of Bosch IoT Things (<iot-things-scope> ) and "Client ID" (<clientId> ) of the OAuth2 client managed at Bosch IoT Suite portal separated by an at (@ ) character.See https://accounts.bosch-iot-suite.com/oauth2-clients/ |
iot-suite:xxx-bosch-id-xxx/service-instance.4-5-6.iot-things@7-8-9 |
iot-suite |
<BoschId>/<iot-things-scope> |
suite-auth | The ID of a Bosch account (<BoschId> ),followed by a slash ( / ) and the "Client Scope" of Bosch IoT Things (<iot-things-scope> ) of the OAuth2 client managed at Bosch IoT Suite portal.See https://accounts.bosch-iot-suite.com/oauth2-clients/ |
iot-suite:xxx-bosch-id-xxx/service-instance.4-5-6.iot-things |
iot-suite |
/<iot-things-scope> |
suite-auth | A slash (/ ) followed by the "Client Scope" of Bosch IoT Things (<iot-things-scope> ) of the OAuth2 client managed at Bosch IoT Suite portal.See https://accounts.bosch-iot-suite.com/oauth2-clients/ |
iot-suite:/service-instance.4-5-6.iot-things |
iot-suite |
<clientId> |
suite-auth | The ID is the "Client ID" (<clientId> ) of the OAuth2 client managed at Bosch IoT Suite portal.See https://accounts.bosch-iot-suite.com/oauth2-clients/ Not recommended any longer. Use the new notation with scope and client ID for production scenarios. |
iot-suite:7-8-9 |
iot-suite |
service:iot-things-<region>:<iot-suite-service-instance-id>_things/full-access> |
suite-auth | The old scope notation which was previously found for OAuth2 clients managed at Bosch IoT Suite portal. E.g. iot-suite:service:iot-things-eu-1:1-2-3_things/full-access
See https://accounts.bosch-iot-suite.com/oauth2-clients/ Not recommended any longer. Use the new notation with the new scope and client ID for production scenarios. |
The old scope format service:iot-things-eu-1:1-2-3_things/full-access can
be mapped to new format service-instance.1-2-3.iot-things
|
The type is offered only for documentation purposes. You are not restricted to any specific types, but we recommend to use it to specify the kind of the subject as shown in our examples.
Custom subject of your custom OAuth2 authorization provider
Upon request, the Things service team will configure your custom OAuth2 authorization provider (which needs to be OpenID Connect compliant, see https://openid.net/connect/).
Will need to know the specific URL of the issuer. Find details at the FAQ section.
Prefix / issuer (mandatory) | ID (mandatory) | Type (informational) | Description |
---|---|---|---|
Your will get a custom prefix | Your custom IDs will be derived from the value of the external_sub claim e.g. <external_sub>/<scope> |
The type is offered only for documentation purposes. You are not restricted to any specific types. | For each scope of the JWT, a subject with the format<subject-issuer>:<external_sub>/<scope>@<client> will be generated. |
As a second step, you will need to register a client to your Bosch IoT
Things subscription.
See APIdocs - PUT /solutions/{solutionId}/clients
.
The type is offered only for documentation purposes. You are not restricted to any specific types, but we recommend to use it to specify the kind of the subject as shown in our examples.
Subject expiry
A policy subject may optionally contain an expiry timestamp (a string in ISO-8601 format).
By defining an expiry timestamp you can specify that certain subjects (e.g. users or applications) may only be allowed
until a certain time to e.g. access or modify a resource secured by the policy.
A subject having an expiry timestamp will get automatically deleted from the policy once this timestamp was reached.
Example of a timely limited “guest” entry:
{
"subjects": {
"bosch:xxx-a-Bosch-id-xxx": {
"type": "Bosch ID",
"expiry": "2021-05-01T12:00:00Z",
"announcement": {
"beforeExpiry": "1d",
"whenDeleted": true,
"requestedAcks": {
"labels": [ "connection-id:suffix" ],
"timeout": "10s"
}
}
}
},
"resources": {
"thing:/": {
"grant": [
"READ"
],
"revoke": []
}
}
}
The settings under announcement
control when a policy announcement is published (before expiry or when deleted).
If the field requestedAcks
is set, then the announcements are published with at-least-once delivery until
the acknowledgement requests under labels
are fulfilled. Policy announcements are published to websockets and
connections that have the relevant subject ID.
Actions
Policy actions are available via the HTTP API and can be invoked for specific policy entries or for complete policies.
They require neither READ
nor WRITE
permission, but instead a granted EXECUTE
permission on the specific action
name, e.g. for a single policy entry:
policy:/entries/{label}/actions/{actionName}
Activate or deactivate a token integration subject
When authenticating using OpenID Connect, it is possible to inject a subject into policies. The subject expires
when the JSON Web Token (JWT) expires.
A subject with the EXECUTE
permission on a policy entry is authorized to inject
the token integration subject. The WRITE
permission on the policy entry is not necessary. However, for the activateTokenIntegration
action, at least one READ
permission to a thing:/
resource path must be granted.
The token integration subject follows the pattern:
integration:<iot-things-solution-id>:<jwt-client-id>
The <jwt-client-id>
is extracted either from a JWT claim client_id
, or, if client_id
was not present in the JWT,
from the azp
claim from the JWT.
To activate or deactivate a token integration subject, send a POST request to the following HTTP routes:
- POST /api/2/policies/{policy-id}/actions/activateTokenIntegration
Injects a new subject into all matched policy entries calculated with information extracted from the authenticated JWT.- The authenticated token must be granted the
EXECUTE
permission to perform theactivateTokenIntegration
action. - One of the subject IDs must be contained in the authenticated token.
- At least one
READ
permission to athing:/
resource path must be granted.
- The authenticated token must be granted the
- POST /api/2/policies/{policy-id}/actions/deactivateTokenIntegration
Removes the calculated subject with information extracted from the authenticated JWT from all matched policy entries.- The authenticated token must be granted the
EXECUTE
permission to perform thedeactivateTokenIntegration
action. - One of the subject IDs must be contained in the authenticated token.
- The authenticated token must be granted the
- POST /api/2/policies/{policy-id}/entries/{label}/actions/activateTokenIntegration
Injects the calculated subject into the policy entry specified by the label. The subject is calculated with information extracted from the authenticated JWT.- The authenticated token must be granted the
EXECUTE
permission to perform theactivateTokenIntegration
action. - One of the subject IDs must be contained in the authenticated token.
- At least one
READ
permission to athing:/
resource path must be granted.
- The authenticated token must be granted the
- POST /api/2/policies/{policy-id}/entries/{label}/actions/deactivateTokenIntegration
Removes the calculated subject from the policy entry specified by the label. The subject is calculated with information extracted from the authenticated JWT.- The authenticated token must be granted the
EXECUTE
permission to perform thedeactivateTokenIntegration
action. - One of the subject IDs must be contained in the authenticated token.
- The authenticated token must be granted the
Which resources can be controlled?
A policy can contain access control definitions for several resources:
- Policy
Someone who was granted WRITE permission at the policy root resource (i.e.policy:/
) is allowed to manage the policy itself. - Thing
The resource can be defined as rough or as fine-grained as necessary for the respective use case: e.g. “thing:/
” as top-level resource, or on sub-resources such as “thing:/features
”. At runtime, the permissions are propagated down to all thing sub-entities.- In case you grant READ permission on top-level and revoke it at a sub-entity, the subject can read the upper part only.
- In case you omit a subject at top-level but grant permission at a sub-entity, the subject can access the lower part only (and the thingId).
- Message
The resource can be defined as rough or as fine-grained as necessary for the respective use case: e.g. “message:/
” as top-level resource. - Solution
Someone who was granted WRITE permission at the solution root resource (i.e.solution:/
) is allowed to manage the solution itself. See Policy of a solution.
Policy
The policy resource (addressable as “policy:/
") defines the access
control for the policy itself.
Please make sure to define at least one user (for which
you have the credentials) with top-level READ and WRITE permissions
on the policy, otherwise you won’t be able to access/change it.
Resource | Addressed data, description |
---|---|
policy:/ | The policy itself (top-level) Applies to the Policy and all of its sub-resources. |
policy:/policyId | The ID of the policy. However, such a reference is not recommended because write is not supported anyway, and read on the ID only, does not provide any benefit. |
policy:/entries | Applies to all entries of the policy. |
policy:/entries/X | Applies to all subjects and resources of the specific entry X. |
policy:/entries/X/actions | Applies to all actions of the specific entry X. |
policy:/entries/X/actions/Y | Applies to action Y of the specific entry X. |
policy:/entries/X/subjects | Applies to all subjects of the specific entry X. |
policy:/entries/X/subjects/Y | Applies to subject Y of the specific entry X. |
policy:/entries/X/resources | Applies to all resources of the specific entry X. |
policy:/entries/X/resources/Y | Applies to resource Y of the specific entry X. |
Example: The example at the end of the page also defines access control on the policy resource.
Thing
The thing resource (addressable as “thing:/
") defines the access
control for things.
In case you want to re-use a policy for various things,
we recommend to name the policyId differently than the thingId.
Example:
{
"thingId": "org.example:coffee-machine-01",
"policyId": "org.example:coffee-machine-policy"
}
In case multiple things share the same policy, the settings at the thing:/
resource will be applied to all things referencing this policy.
Resource | Addressed data, description |
---|---|
thing:/ | The thing itself (top-level). Applies to the thing and all of its sub-resources. |
thing:/thingId | The ID of the thing. Not recommended, because write is not supported anyway and read on the ID only does not provide any benefit. |
thing:/policyId | Applies to the policy ID of the thing, which implicitly defines its access control. Please double-check write permissions on this resource. |
thing:/definition | Applies to the definition field of the thing. |
thing:/attributes | Applies to all attributes of the thing. |
thing:/attributes/X | Applies to the specific attribute X and its sub-paths. X may be a nested path such as tire/pressure. |
Example: Find an example at the end of the page.
Feature
Resource | Addressed data, description |
---|---|
thing:/features | Applies to all features of the thing. |
thing:/features/X | Applies to the feature with ID X and all its sub-paths. |
thing:/features/X/properties | Applies to all properties of the feature X. |
thing:/features/X/properties/Y | Applies to the property with path Y (and its sub-paths) of the feature with ID X. Y may be a nested path such as tire/pressure. |
thing:/features/X/desiredProperties | Applies to all desired properties of the feature X. |
thing:/features/X/desiredProperties/Y | Applies to the desired property with path Y (and its sub-paths) of the feature with ID X. Y may be a nested path such as tire/pressure. |
Example: Find an example at the end of the page.
Message
The message resource (addressable as “message:/
") defines the access
control for messages.
The access control definitions will be applied to all messages sent to or from a thing referencing this policy.
- For sending messages to a thing or its features WRITE permission is required
- For receiving messages from a thing or its features READ permission is required.
Such permissions can be defined at resources of different granularity.
Resource | Addressed data, description |
---|---|
message:/ | All messages (top-level) Applies to all messages sent to or from things referencing this policy and all messages sent to or from features of these things. |
message:/inbox | Applies to all messages sent to a specific thing (or multiple things referencing this policy) |
message:/inbox/messages/X | Applies to all messages on message-subject X, sent to a thing referencing this policy |
message:/outbox | Applies to all messages sent from a thing referencing this policy |
message:/outbox/messages/X | Applies to all messages on message-subject X, sent from a thing referencing this policy |
message:/features | Messages for all features Applies to all messages sent to or from all features of a thing referencing this policy |
message:/features/Y | Applies to all messages sent to or from feature Y of a things referencing this policy |
message:/features/Y/inbox | Applies to all messages sent to feature Y of a thing referencing this policy |
message:/features/Y/inbox/messages/X | Applies to all messages on message-subject X sent to feature Y of a thing referencing this policy |
message:/features/Y/outbox | Applies to all messages sent from feature Y of a thing referencing this policy |
message:/features/Y/outbox/messages/X | Applies to all messages on message-subject X sent from feature Y of a thing referencing this policy |
The resources “
message:/inbox
” and
“message:/outbox
” do not address feature-related messages. For
providing access to feature-related messages, you have to either grant
top-level permission (message:/
") or grant permission to the resource
message:/features
” (or the required sub-resources).
Example: The example at the end of the page also defines access control on messages.
Solution
The solution resource (addressable as “solution:/
") defines the access
control for your Bosch IoT Things service instance.
The solution policy defines the access rules for your solution.
The solution policy ID is defined automatically by our service
at the time of subscribing the service, thus you will not be able to set
a different ID (e.g. like you could do it for a thing entity). Find your
solution policy ID at the dashboard’s Basic data tab.
Resource | Addressed data, description |
---|---|
solution:/ | The solution itself (top-level). Applies to the solution and all of its sub-resources. |
solution:/namespaces | Applies to all namespaces of the solution. |
solution:/connections | Applies to all connections of the solution. |
solution:/connections/<connectionId> | Applies to the specific connection with the given connectionId . |
solution:/connections/<connectionId>/status | Applies to the status of the specific connection with the given connectionId . |
solution:/connections/<connectionId>/metrics | Applies to all metrics of the specific connection with the given connectionId . |
solution:/connections/<connectionId>/metrics/etc. | Applies to specific metrics of the specific connection with the given connectionId . |
solution:/connections/<connectionId>/logs | Applies to all logs of the specific connection with the given connectionId . |
solution:/connections/<connectionId>/logs/etc. | Applies to specific log entries of the specific connection with the given connectionId . |
Find an example at
Policy of a solution.
Grant and revoke permission
Change | Permission | Description |
---|---|---|
grant | READ | All subjects named in the section are granted READ permission on the resources specified in the path, and all nested paths, except they are revoked at a deeper level, or another policy entry (label). |
grant | WRITE | All subjects named in the section are granted WRITE permission on the resources specified in the path, and all nested paths, except they are revoked at a deeper level, or another policy entry (label). |
grant | EXECUTE | All subjects named in the section are granted EXECUTE permission on the resources specified in the path, and all nested paths, except they are revoked at a deeper level, or another policy entry (label). |
revoke | READ | All subjects named in the section are prohibited to READ on the resources specified in the path, and all nested paths, except they are granted again such permission at a deeper level, or another policy entry (label). |
revoke | WRITE | All subjects named in the section are prohibited to WRITE on the resources specified in the path, and all nested paths, except they are granted again such permission at a deeper level, or another policy entry (label). |
revoke | EXECUTE | All subjects named in the section are prohibited to EXECUTE on the resources specified in the path, and all nested paths, except they are granted again such permission at a deeper level, or another policy entry (label). |
Tools for editing a policy
The policy can be edited with a text editor of your choice. Just make sure it is in valid JSON representation, and that at least one valid subject is granted WRITE permission at the root resources.
The easiest way is, to copy the model schema provided at the interactive HTTP API documentation, and adapt it to your needs.
In case of fine-grained access on things, keep an eye on your actual thing structure to make sure that all paths will be granted or revoked the permissions your use case is supposed to support.
Example
Given you need to support the following scenario:
- Owner
The thing my.namespace:thing-0123 is owned by a subject managed by a custom OAuth provider. The owner needs full access and admin rights for the complete thing.
In our example his ID is bosch-xxx:xxx-id-xxx/owner-scope - Observer of changes at featureX and featureY
- Another application needs to be informed on each change at those features. In our example its ID is iot-suite:eebbb40e-xxxx-xxxx-xxxx-f79a4653946b.
- Privacy
- The value of the “city” property at “featureY” is confidential and needs to be “hidden” from the other application.
To accomplish all conditions mentioned above, your policy might look like the following image.
The correct JSON notation would be as shown in the following code block.
{
"policyId": "my.namespace:policy-a",
"entries": {
"owner": {
"subjects": {
"bosch-xxx:xxx-id-xxx/owner-scope": {
"type": "custom-oauth-provider"
}
},
"resources": {
"thing:/": {
"grant": ["READ", "WRITE"],
"revoke": []
},
"policy:/": {
"grant": ["READ", "WRITE"],
"revoke": []
},
"message:/": {
"grant": ["READ", "WRITE"],
"revoke": []
}
}
},
"observer": {
"subjects": {
"iot-suite:eebbb40e-xxxx-xxxx-xxxx-f79a4653946b": {
"type": "suite-auth-client"
}
},
"resources": {
"thing:/features/featureX": {
"grant": ["READ"],
"revoke": []
},
"thing:/features/featureY": {
"grant": ["READ"],
"revoke": []
},
"thing:/features/featureY/properties/location/city": {
"grant": [],
"revoke": ["READ"]
}
}
}
}
}
The IDs from the example above
are just example values.
The policy can be found:
- Via GET request at
/api/2/policies/<policyId>
, and - Via GET request at
/api/2/things/{thingId}/policyId
- At any thing itself in its JSON representation.
A common get thing request, does not include the full policy by default, but you can be retrieve it by appending the field _policy as a query parameter
e.g./api/2/things/<thingId>?fields=_policy
In case of doubt, add for each role an own policy entry (label), and later add the subject which you need to empower in the specific section.