Configure a tenant
Configure a tenant
In this tutorial, you are going to configure a tenant using Qlik Cloud management APIs so you can automate the process of analytics delivery to your end customers.
You will configure settings which allow you to deploy content to the tenant, as well as enable users to authenticate to the tenant and access that content.
Sections
- Code examples
- Prerequisites
- Variable substitution
- Quick start
- 1 Configure entitlement and provisioning settings
- 2 Configure an identity provider
- 3 Add groups to the tenant
- 4 Create spaces in a tenant
- Next steps
Code examples
Complete script examples for configuring a tenant using qlik-cli, curl, Python, and API collections are available here.
Prerequisites
- You have reviewed previous tutorials in the Platform Operations series, as this tutorial assumes your knowledge of concepts and steps covered earlier.
- Generated a certificate keypair for use with JWT authorization.
- cURL for running the inline examples.
Variable substitution
Throughout this tutorial, variables will be used to communicate value placement.
The variable substitution format is <VARIABLE_NAME>
. Here is a list of
variables referred to in this tutorial.
Variable | Description |
---|---|
<CLIENT_ID> | The client ID for an OAuth client, specific to the region you're sending requests to. |
<CLIENT_SECRET> | The client secret for the specific OAuth <CLIENT_ID> . |
<TARGET_TENANT> | The domain for the tenant you are configuring. Equivalent to tenant.<REGION>.qlikcloud.com . |
<TARGET_TENANT_ID> | The Qlik Cloud id of the tenant that you are configuring. |
<TARGET_ACCESS_TOKEN> | A bearer token for authorizing https requests to the <TARGET_TENANT> . |
<REGION> | The region identifier for the Qlik Cloud region that you're sending requests to. Examples include ap for Australia, eu for Ireland, sg for Singapore and us for North America. |
<KEY_ID> | A value you provide as the ID for the public certificate that you create the JWT IdP with, for example myportal . This ID value will also be required when making requests against this IdP. |
<PUBLIC_CERTIFICATE> | The body of your public certificate, which is used for creating the JWT IdP. Any requests against this IdP will need to be signed by the corresponding private certificate. |
<ISSUER> | A value that you provide as the issuer for the public certificate, for example https://myportal . This issuer value will also be required when making requests against this IdP. |
<SHARED_SPACE_NAME> | The space name for the shared space you will use as the staging space when deploying content. Note that this cannot be the same as the <MANAGED_SPACE_NAME> as all space names should be unique. |
<SHARED_SPACE_ID> | The Qlik Cloud id for <SHARED_SPACE_NAME> . |
<MANAGED_SPACE_NAME> | The space name for the managed spaces that you will use as the production space where users will consume content. Note that this cannot be the same as the <SHARED_SPACE_NAME> as all space names should be unique. |
<MANAGED_SPACE_ID> | The Qlik Cloud id for <MANAGED_SPACE_NAME> . <MANAGED_SPACE_NAME> |
<GROUP_ID_TO_BE_ASSIGNED> | The Qlik Cloud id for the group that you're giving access to the <MANAGED_SPACE_NAME> managed space. |
Quick start
If you want to dive right into the code, all of the commands in this tutorial are available on the Qlik open source software github repository. Example commands are provided in multiple formats including Python, cURL, and qlik-cli.
1 Configure entitlement and provisioning settings
There are several tenant-level settings that you may want to configure before allowing end customers to access embedded analytics.
Enable auto creation of groups
Security in Qlik Cloud can be applied to both users and groups. Using groups to secure access to content and resources simplifies access management by allowing an identity provider outside of Qlik to manage user access to Qlik resources using group membership. As group membership changes, Qlik automatically picks up the changes and ensures that users can only access content and resources according to their group memberships.
To enable group management on a tenant, access
the /groups/settings
endpoint
and set the autoCreateGroups
property to true
to permit group creation
on user login, and the syncIdpGroups
property to true
if you are using
a compatible interactive Identity Provider and wish groups to be synchronized:
curl -L "https://<TARGET_TENANT>/api/v1/groups/settings" \
-X PATCH \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Content-type: application/json" \
-H "Accept: application/json" \
-d '[{"op": "replace", "path": "/autoCreateGroups", "value": true},{"op": "replace", "path": "/syncIdpGroups", "value": true}]'
The response from this request is an http 204 updated
status code. There are no
additional details provided in the response.
Set user entitlement assignment behavior
You can entitle a user either as an analyzer or a professional user in the tenant.
The analyzer entitlement allows a user to consume content and resources they are assigned to on the tenant.
A professional entitlement adds creator and self-service capabilities to users.
In both cases, this entitlement provides access to content in the tenant. Tenant roles grant the entitled user additional capabilities in the tenant. Space permissions and roles allow further refinement to the content users and groups access depending on the location of the content in the tenant.
Note: Learn more about the different user entitlements for Qlik Cloud here.
To enable a tenant to automatically set users with the analyzer entitlement,
send a request to the /licenses/settings
endpoint to set the autoAssignProfessional
property to false
and the
autoAssignAnalyzer
to true
:
curl -L "https://<TARGET_TENANT>/api/v1/licenses/settings" \
-X PUT \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Content-type: application/json" \
-H "Accept: application/json" \
-d '{"autoAssignProfessional":false,"autoAssignAnalyzer":true}'
2 Configure an identity provider
Obtain the tenant ID
To create an identity provider connection between your host application and the
Qlik Cloud tenant, you need the tenant id
to complete the configuration.
To obtain the tenant id
, send a request to
the /users
API:
curl -L "https://<TARGET_TENANT>/api/v1/users/me" \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Accept: application/json" \
-H "Content-Type: application/json"
The JSON response includes a tenantId
attribute, which you should store for
later use as <TARGET_TENANT_ID>
.
{
"id": "62d8fce9b9f47dc69f17cf0a",
"tenantId": "<TARGET_TENANT_ID>",
"clientId": "00cbb22c600e823ed278d5e3d976f85a",
"status": "active",
"subject": "qlikbot\\00cbb22c600e823ed278d5e3d976f85a",
"name": "US OAuth Client",
"roles": [
"TenantAdmin"
],
"assignedRoles": [
{
"id": "608050f750afab80bd53586d",
"name": "TenantAdmin",
"type": "default",
"level": "admin"
}
],
...
Configure authorization using JSON web tokens
JSON web tokens, or JWTs as they are commonly referred, are a good option for embedded and integration use cases with Qlik because they allow users to authorize access to a tenant and consume content without encountering additional authentication dialogs.
Note: If you plan on using an interactive identity provider to authenticate the user to the tenant, please refer to the guide to add an interactive user to a tenant.
JWT authorization requires these steps to properly authorize users to a tenant:
- A signing certificate key pair to encrypt and decrypt the JWT. Review this guide if you do not already have a public and private key pair to sign JWTs.
- An active JWT authorization configuration in the tenant.
- Code to generate JWTs that your application will send to the tenant to authorize users. You can learn more about the proper JWT format to send to a tenant here.
Adding a JWT authorization configuration to a tenant requires the public key
certificate from the signing key pair in string format with a new line \n
delimiter for each line in the certificate string.
Here's an example payload to create an JWT authorization identity provider:
{
"active": true,
"interactive": false,
"protocol": "jwtAuth",
"provider": "external",
"tenantIds": ["<TARGET_TENANT_ID>"],
"description": "JWT IdP for deferred authentication to my application",
"options": {
"issuer": "<ISSUER>",
"staticKeys": [
{
"kid": "<KEY_ID>",
"pem": "<PUBLIC_CERTIFICATE>"
}
]
}
}
To add a JWT authorization configuration to a tenant, make a request to
the /identity-providers
API:
curl -L "https://<TARGET_TENANT>/api/v1/identity-providers" \
-X POST \
-H 'Authorization: Bearer <TARGET_ACCESS_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"tenantIds": ["<TARGET_TENANT_ID>"],
"provider": "external",
"protocol": "jwtAuth",
"interactive": false,
"active": true,
"description": "JWT IdP for deferred authentication to my application",
"options": {
"jwtLoginEnabled": true,
"issuer": "<ISSUER>",
"staticKeys": [
{
"kid": "<KEY_ID>",
"pem": "<PUBLIC_CERTIFICATE>"
}
]
}
}'
Note that the issuer
and kid
values you configure the IdP with will be needed for
creating signed JWTs to be accepted by this configuration.
An example JSON response:
{
"id": "62a35a55d9b89de8948a6429",
"tenantIds": ["<TARGET_TENANT_ID>"],
"provider": "external",
"protocol": "jwtAuth",
"interactive": false,
"active": true,
"options": {
"jwtLoginEnabled": true,
"issuer": "<ISSUER>",
"staticKeys": [
{
"kid": "<KEY_ID>",
"pem": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
}
]
},
"created": "2022-06-10T14:51:01.042Z",
"lastUpdated": "2022-06-10T14:51:01.042Z",
"description": "JWTAuth IdP",
"clockToleranceSec": 5
}
3 Add groups to the tenant
Groups will be used to control access to the spaces that host your content. Adding groups to a tenant and assigning them to spaces before any users log in ensures that users only have access to content based upon their group membership.
Groups are created from the groups field when using a JWT authorization session.
In the following example the groups Admin
, Finance
, Marketing
, and Sales
are created - if no groups with those names already exist - when a user
authorizes to the tenant with the properly formatted JWT.
Note: In this example, you will set the subject (
sub
) totmpgroupprovisioning
, however the only recommendation is that this is unique, as once you've provisioned the groups, you can remove this user. Also note that groups are not tied to a realm - any IdP on the platform will match groups on only the group name.
const payload = {
"jti": uid.sync(32), // 32 bytes random string
"sub": "tmpgroupprovisioning",
"subType": "user",
"name": "user name",
"email": "username@example.com",
"email_verified": true,
"groups": ["Admin", "Finance", "Marketing", "Sales"],
};
You can learn more about the JSON object payload format in
the JWT authorization
tutorial. The create_group
function in
the tenant_configure.sh
provides an example of how to use JWT authentication to create groups.
Once groups are seeded on the tenant, you are going to need the id
of the
group you want to assign membership to on a space. To obtain a list of group
metadata, use the /groups
API:
curl -L "https://<TARGET_TENANT>/api/v1/groups" \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Accept: application/json" \
-H "Content-Type: application/json"
The JSON response will be a list of groups and their associated metadata:
{
"links": {"..."},
"data": [
{
"id": "507f191e810c19729de860ea",
"tenantId": "<TARGET_TENANT_ID>",
"name": "Admin",
"createdAt": "2021-03-21T17:32:28.000Z",
"lastUpdatedAt": "2021-03-22T10:01:02.000Z",
"status": "active",
"assignedRoles": ["..."],
"links": {"..."}
},
...
}
Record the id
of the group or groups that you are going to assign
as a member to a space.
4 Create spaces in a tenant
A space allows you to define access control rules based on users or groups for the content contained within the space. There are three types of spaces in a tenant: personal, shared, and managed spaces.
Personal spaces reference content only the owner can access. They are not used in embedded use cases.
Shared spaces enable multiple users to collaborate on content creation. Put another way, shared spaces are the main branch for the analytics content deployed to a tenant.
Managed spaces represent the release area for analytics content. When content is published to a managed space, the main content, business logic, and content code cannot be manipulated.
Access to spaces and their content can be provided to named users in a tenant or through group membership. To learn more about spaces, see Working in spaces.
Implementing a shared space for staging deployed content and a managed space to support release consumption is a good design pattern for embedded analytics. Here's how to programmatically create spaces and set access control on them.
Create the shared space
Creating a shared space uses the /spaces
API.
The request for space creation requires a name
for the space and a type
for
the space, which is either shared
or managed
. You may add a description for
the space in this request using the description
attribute.
curl -L "https://<TARGET_TENANT>/api/v1/spaces" \
-X POST \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name": "<SHARED_SPACE_NAME>", "description": "none", "type": "shared"}'
The JSON response when a space is created on a tenant includes metadata
describing the access control available on the space. Make note of the space
id
as <SHARED_SPACE_ID>
as you may need this later to assign groups and permissions.
{
"id": "<SHARED_SPACE_ID>",
"type": "shared",
"ownerId": "00cbb22c600e823ed278d5e3d976f85a",
"tenantId": "<TARGET_TENANT_ID>",
"name": "<SHARED_SPACE_NAME>",
"description": "none",
"meta": {
"actions": ["create", "delete", "read", "update"],
"roles": [],
"assignableRoles": ["consumer", "dataconsumer", "facilitator", "producer"]
},
"links": {"..."},
"createdAt": "2022-06-17T12:55:11.574Z",
"createdBy": "00cbb22c600e823ed278d5e3d976f85a",
"updatedAt": "2022-06-17T12:55:11.574Z"
}
By default, the creator of a space has full access to that space. As this use case leverages the shared space as a staging area for your content prior to publishing to the managed space, you will not assign any additional users or groups at this stage. This is because the API user will be the only user accessing the space, and as that user created the space, it already has full access.
Create the managed space
Creating a managed space uses the same /spaces
API with the same format as the shared space request, but the type value sent in
the request is managed
.
curl -L "https://<TARGET_TENANT>/api/v1/spaces" \
-X POST \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name": "<MANAGED_SPACE_NAME>", "description": "none", "type": "managed"}'
The JSON response when you create a managed space is exactly the same as a
shared space, but with slightly different metadata including the type
set to
managed
.
{
"id": "<MANAGED_SPACE_ID>",
"type": "managed",
"ownerId": "00cbb22c600e823ed278d5e3d976f85a",
"tenantId": "<TARGET_TENANT_ID>",
"name": "<MANAGED_SPACE_NAME>",
"description": "none"
}
Record the id
attribute of the managed space as <MANAGED_SPACE_ID>
for adding a group to the space.
Add a group to a managed space with the consumer role
Access control in spaces is set by adding members (users or groups) to the space and assigning them permissions tied to roles.
Note: Some space permissions may also depend on the user also having the appropriate license allocated, and the user or group having any specific roles assigned.
To provide a group whose users have permission to act as a consumer on a managed space you need:
- The
id
of the group or groups you want to assign permissions (<GROUP_ID_TO_BE_ASSIGNED>
). - The
id
of the managed space to assign the group (<MANAGED_SPACE_ID>
).
Add a group and assign it a role on the managed space
Assigning a group and the role permissions of that group to a space uses
the /assignments
endpoint. The JSON payload for the request requires type
, assigneeId
, and
roles
attributes. The assigneeId
attribute value should be the group id
.
In this example you will set the consumer
role, which permits the specified group
the ability to consume analytics, but not any editing or self-service capabilities.
{
"type": "group",
"assigneeId": "<GROUP_ID_TO_BE_ASSIGNED>",
"roles": ["consumer"]
}
The request path contains the id
of the managed space that you created in the previous step.
curl -L "https://<TARGET_TENANT>/api/v1/spaces/<MANAGED_SPACE_ID>/assignments" \
-X POST \
-H "Authorization: Bearer <TARGET_ACCESS_TOKEN>" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"type": "group", "assigneeId": "<GROUP_ID_TO_BE_ASSIGNED>", "roles": ["consumer"]}'
The JSON response from the tenant confirms the assignment of the group to the managed space was successful.
{
"id":"626ff52f7ca0dba484332c21",
"type":"group",
"assigneeId":"<GROUP_ID_TO_BE_ASSIGNED>",
"roles":["consumer"],
"spaceId":"<MANAGED_SPACE_ID>",
"tenantId":"<TARGET_TENANT_ID>",
"createdAt":"2022-05-02T15:13:51.12Z",
"createdBy":"00cbb22c600e823ed278d5e3d976f85a",
"updatedAt":"2022-05-02T15:13:51.12Z",
"links":{"..."}
}
Next steps
With your tenant, IdP, and spaces ready to go, the stage is set for deploying content to your tenant.