3.8. How-to for Nextcloud#
This section provides a how-to for building a packaged integration using Nextcloud as an example. After reading this section, you know how to use the various plugins described in Packaged integrations to create a packaged integration to connect Nextcloud to Nubus for Kubernetes. It focuses on the following objectives:
The Portal Service provides a tile that links to the Nextcloud instance.
Nextcloud uses Nubus for Kubernetes as its identity management source. Identity administrators can use Nubus to decide which user accounts or user groups may use Nextcloud.
The entire configuration is distributable as a packaged integration.
This section addresses software developers for the steps to create the packaged integration. In a second part, it addresses DevOps engineers for the steps on installing the packaged integration.
This how-to takes you along the following steps:
- Software developers
Validate that you meet the Requirements.
Create the Packaged integration directory structure.
Bundle the plugins in a container image as packaged integration.
3.8.1. Requirements#
To go through this how-to you need a computer where you can create a directory structure and files. You need the knowledge listed in Audience and required knowledge.
3.8.2. Packaged integration directory structure#
Before you begin, ensure that you meet the requirements as outlined in Requirements.
To begin with this how-to, you need to create the directory structure in Listing 3.13 on your local machine. The directory contains all the necessary files for the packaged integration.
nextcloud-packaged-integration/
├── docker
└── plugins
You can use a different top-level directory name.
However, keep the directories
docker
and plugins
as they are for consistency reasons.
You can turn the directory structure into a repository for your source code management system to track all the changes over time.
3.8.3. Prepare the plugins#
Before you continue, ensure that you have completed the steps in Packaged integration directory structure.
The packaged integration for Nextcloud uses various plugins for Nubus for Kubernetes. This section describes how you create and add these plugins to the directory structure.
Add extended attributes for Nextcloud.
Add LDAP search user so that Nextcloud can access the Directory Service.
Create tile for Portal Service that points users to Nextcloud.
3.8.3.1. Add LDAP schemas#
An LDAP schema defines the data model in the Directory Service. This plugin type allows extending the data model to store additional information with an object. For more information, see LDAP schema.
Identity administrators can control which user or user group may access Nextcloud. They can also define how much disk space a user may allocate. Operators can then configure Nextcloud to evaluate these attributes. Therefore, the Nextcloud packaged integration provides an LDAP schema to add application specific attributes and object classes to achieve these use cases.
To add the LDAP schema, use the following steps:
Create the directory
ldap-schema/
in yourplugins/
directory.Add the file
nextcloud.schema
to theldap-schema/
directory with the content in Listing 3.14. The schema adds the following LDAP elements:- Attributes
univentionNextcloudEnabled
univentionNextcloudQuota
- Object classes
univentionNextcloudUser
univentionNextcloudGroup
# Attribute Types #----------------- attributetype ( 1.3.6.1.4.1.10176.99999.00424.10 NAME 'univentionNextcloudEnabled' DESC 'whether user or group should be available in Nextcloud' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE) attributetype ( 1.3.6.1.4.1.10176.99999.00424.11 NAME 'univentionNextcloudQuota' DESC 'defines how much disk space is available for the user' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE) # Object Classes #--------------- objectclass ( 1.3.6.1.4.1.10176.99999.00424.12 NAME 'univentionNextcloudUser' DESC 'A Nextcloud user' SUP top AUXILIARY MUST ( cn ) MAY ( univentionNextcloudEnabled $ univentionNextcloudQuota ) ) objectclass ( 1.3.6.1.4.1.10176.99999.00424.13 NAME 'univentionNextcloudGroup' DESC 'A Nextcloud group' SUP top AUXILIARY MUST ( cn ) MAY ( univentionNextcloudEnabled ) )
Your directory structure looks like Listing 3.15.
nextcloud-packaged-integration/
├── docker
└── plugins
└── ldap-schema
└── nextcloud.schema
3.8.3.2. Add extended attributes#
Extended attributes are a feature of UDM which provides a mapping between an input widget and a UDM attribute. The UDM HTTP REST API configures extended attributes. The UDM data loader plugin automates the configuration process of extended attributes for the Nextcloud packaged integration. For more information about the UDM data loader, see UDM data loader.
To add an extended attribute, use the following steps:
Create the directory
udm-data-loader/
in yourplugins/
directory.Add the
86_Nextcloud.yaml
file to theudm-data-loader/
directory with the content in Listing 3.16.Take a look at the first extended attribute with the name
univentionNextcloudEnabled
. The attribute has the propertydefault
. It’s emphasized in the listing. In this case,default: "TRUE"
means that UDM automatically allows newly created users to access Nextcloud, ifuniventionNextcloudEnabled
wasn’t set explicitly when the user was created.Note
The
86_Nextcloud.yaml
file that you can download here, includes more data than shown in Listing 3.16. Section 3.8.3.3 to Section 3.8.3.4 explain the remaining content of the file in detail.--- # Create container for Nextcloud custom attributes action: create module: container/cn position: cn=custom attributes,cn=univention,{{ ldapBaseDn }} properties: name: "nextcloud" --- # Create extended attribute Nextcloud for user action: create module: settings/extended_attribute position: cn=nextcloud,cn=custom attributes,cn=univention,{{ ldapBaseDn }} properties: name: "univentionNextcloudEnabled" CLIName: nextcloudEnabled ldapMapping: univentionNextcloudEnabled module: ["users/user"] shortDescription: Access to Nextcloud overwriteTab: False valueRequired: False tabName: NextCloud Hub syntax: "boolean" multivalue: False tabPosition: 1 tabAdvanced: False overwritePosition: "0" doNotSearch: False hook: 'None' mayChange: True deleteObjectClass: False default: "TRUE" objectClass: univentionNextcloudUser --- # Create extended attribute Nextcloud Quota for user action: create module: settings/extended_attribute position: cn=nextcloud,cn=custom attributes,cn=univention,{{ ldapBaseDn }} properties: name: "univentionNextcloudUserQuota" CLIName: nextcloudQuota ldapMapping: univentionNextcloudQuota module: ["users/user"] shortDescription: "Nextcloud Quota" longDescription: "Amount of storage available to the user (ex: 512 MB or 12 GB)" tabName: NextCloud Hub overwriteTab: False valueRequired: False syntax: 'string' default: "" tabAdvanced: False mayChange: True multivalue: False deleteObjectClass: False tabPosition: 1 overwritePosition: "0" doNotSearch: False hook: 'None' objectClass: univentionNextcloudUser --- # Create extended attribute Nextcloud for group action: create module: settings/extended_attribute position: cn=nextcloud,cn=custom attributes,cn=univention,{{ ldapBaseDn }} properties: name: "univentionNextcloudGroupEnabled" CLIName: nextcloudEnabled ldapMapping: univentionNextcloudEnabled module: ["groups/group"] shortDescription: "Available in Nextcloud" longDescription: "The group is available in Nextcloud" tabName: NextCloud Hub overwriteTab: False valueRequired: False syntax: 'boolean' default: "0" tabAdvanced: False mayChange: True multivalue: False deleteObjectClass: False tabPosition: 1 overwritePosition: "0" doNotSearch: False hook: 'None' objectClass: univentionNextcloudGroup
3.8.3.3. Add LDAP search user#
Applications like Nextcloud read the list of users from the Directory Service. OpenLDAP is the Directory Service in Nubus. To access the Directory Service and read directory objects, it’s best practice to use a separate user account for each application. Each application uses its own user account to search for users in the Directory Service through LDAP. Therefore, the documentation usually refers to this user account with the term LDAP search user.
You need to use the UDM data loader plugin to add the LDAP search user to Nubus. The UDM data loader uses the UDM HTTP REST API to create the directory objects through UDM. For more information about the UDM data loader, see UDM data loader.
To add the LDAP search user,
open the 86_Nextcloud.yaml
file in the plugins/udm-data-loader/
directory
and add the content in
Listing 3.17.
The UDM data loader creates the LDAP search user in the users/ldap
UDM module.
Unlike the users/user
UDM module
which addresses identity administrators to manage user accounts that represent people,
the users/ldap
UDM module hides the LDAP search user
from the user account and user group management in the Management UI.
Note the template variable nextcloudUserPassword
.
Caution
Don’t hard code the user password for the LDAP search user. The UDM data loader provides a template mechanism and uses Jinja2. Using a template variable allows the operator to choose their own password when installing the packaged integration.
Tip
You can use the template mechanism to also make other values configurable. For more information, see Template variables in the data loader.
---
# Create Nextcloud service user
action: create
module: users/ldap
position: cn=users,{{ ldapBaseDn }}
properties:
username: "nextcloudUser"
lastname: "LDAP-system-User"
password: {{ nextcloudUserPassword }}
overridePWHistory: true
overridePWLength: true
See also
- Identity Store and Directory Service
in Univention Nubus for Kubernetes - Architecture Manual [1] for information about the architecture of the Identity Store and Directory Service in Nubus for Kubernetes.
3.8.3.4. Create tile for Portal Service#
A portal tile adds a link to Nextcloud on the Portal Service so that end users have a direct navigation to Nextcloud. Adding a portal tile comprises the following actions:
Create a portal tile, define its appearance, behavior, and visibility.
Add the portal tile to a portal category where the Portal Service shows it.
Important
The Portal Service only shows portal tiles that have a reference entry in the portal category.
A portal tile is also a directory object.
To add the portal tile,
you need to use the UDM data loader plugin.
Open the 86_Nextcloud.yaml
file in the plugins/udm-data-loader/
directory
and add the content in
Listing 3.18.
Note the template variables portalNextcloudLinkBase
and ldapBaseDn
.
Similar to the password for the LDAP Search user in
Add LDAP search user,
the operator must set the value for portalNextcloudLinkBase
upon the installation of the packaged integration.
Nubus for Kubernetes provides the value for ldapBaseDn
by default
so that the operator doesn’t have to set the value for it.
For more information about the template mechanism, see
Template variables in the data loader.
properties.icon
contains the Base64-encoded data of the Nextcloud icon for the portal tile.
---
# Create Nextcloud portal tile
action: create_or_modify
module: portals/entry
position: cn=entry,cn=portals,cn=univention,{{ ldapBaseDn }}
properties:
name: "nextcloud"
icon: "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGlkPSJMYXllcl8xIiB3aWR0aD0iMTQxLjQ4NSIgaGVpZ2h0PSI5OS42MDMiIHg9IjAiIHk9IjAiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDE5Ni42IDcyIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAxMzIuNjQyIDkzLjM3NyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PG1ldGFkYXRhIGlkPSJtZXRhZGF0YTIwIi8+PGRlZnMgaWQ9ImRlZnMxOCI+PGNsaXBQYXRoIGlkPSJjbGlwUGF0aDg4MTIiIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48Y2lyY2xlIGlkPSJjaXJjbGU4ODE0IiBjeD0iOTUuNjY5IiBjeT0iOTUuNjY5IiByPSI3OS43MjQiIHN0eWxlPSJmaWxsOiMwMDA4MGQ7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlLXdpZHRoOjEiLz48L2NsaXBQYXRoPjwvZGVmcz48cGF0aCBpZD0icGF0aDEwNTIiIGQ9Im0gNjYuNDA3ODk2LDkuMzc1IGMgLTExLjgwNTI3MSwwIC0yMS44MTEyMTcsOC4wMDMxOTYgLTI0LjkxMjM5MiwxOC44NDY2MjEgLTIuNjk1MjQ1LC01Ljc1MTUxNyAtOC41MzU5MzQsLTkuNzgwOTM4IC0xNS4yNjMzOTQsLTkuNzgwOTM4IC05LjI1MTg1LDAgLTE2Ljg1NzExLDcuNjA1MjYzIC0xNi44NTcxMSwxNi44NTcxMDggMCw5LjI1MTgzMyA3LjYwNTI2LDE2Ljg2MDU2NyAxNi44NTcxMSwxNi44NjA1NjcgNi43Mjc0NiwwIDEyLjU2ODE0OSwtNC4wMzE4ODUgMTUuMjYzMzk1LC05Ljc4NDQxMiAzLjEwMTE3NSwxMC44NDQyNSAxMy4xMDcxMiwxOC44NTAxMDYgMjQuOTEyMzkxLDE4Ljg1MDEwNiAxMS43MTc5NjQsMCAyMS42NzI4OSwtNy44ODUxMTEgMjQuODUzMzgyLC0xOC42MDcwNDggMi43NDUwMzYsNS42MjE5MzQgOC41MTM0MzYsOS41NDEzNTQgMTUuMTQ1MzQyLDkuNTQxMzU0IDkuMjUxODUsMCAxNi44NjA1NywtNy42MDg3MzQgMTYuODYwNTcsLTE2Ljg2MDU2NyAwLC05LjI1MTg0NSAtNy42MDg3MiwtMTYuODU3MTA4IC0xNi44NjA1NywtMTYuODU3MTA4IC02LjYzMTkwNiwwIC0xMi40MDAzMDYsMy45MTY5NjUgLTE1LjE0NTM0Miw5LjUzNzg5MSBDIDg4LjA4MDc4NiwxNy4yNTc0NzUgNzguMTI1ODYsOS4zNzUgNjYuNDA3ODk2LDkuMzc1IFogbSAwLDkuODk1NTE4IGMgOC45MTE2NDgsMCAxNi4wMzA3NDgsNy4xMTU2NTMgMTYuMDMwNzQ4LDE2LjAyNzI3MyAwLDguOTExNjA1IC03LjExOTEsMTYuMDMwNzM3IC0xNi4wMzA3NDgsMTYuMDMwNzM3IC04LjkxMTU5MywwIC0xNi4wMjcyNDcsLTcuMTE5MTMyIC0xNi4wMjcyNDcsLTE2LjAzMDczNyAwLC04LjkxMTYyIDcuMTE1NjUzLC0xNi4wMjcyNzEgMTYuMDI3MjQ3LC0xNi4wMjcyNzMgeiBNIDI2LjIzMjExLDI4LjMzNjIwMiBjIDMuOTA0MzgsMCA2Ljk2NTA1LDMuMDU3MTg4IDYuOTY1MDUsNi45NjE1ODkgMCwzLjkwNDM4NiAtMy4wNjA2Nyw2Ljk2NTA0OSAtNi45NjUwNSw2Ljk2NTA0OSAtMy45MDQzOSwwIC02Ljk2MTYxLC0zLjA2MDY2MyAtNi45NjE2MSwtNi45NjUwNDkgMCwtMy45MDQ0MDEgMy4wNTcyMiwtNi45NjE1ODkgNi45NjE2MSwtNi45NjE1ODkgeiBtIDgwLjE3NDUxLDAgYyAzLjkwNDQyLDAgNi45NjUwNiwzLjA1NzE4OCA2Ljk2NTA2LDYuOTYxNTg5IDAsMy45MDQzODYgLTMuMDYwNjYsNi45NjUwNDkgLTYuOTY1MDYsNi45NjUwNDkgLTMuOTA0MzYsMCAtNi45NjE1NzYsLTMuMDYwNjYzIC02Ljk2MTU3NiwtNi45NjUwNDkgMCwtMy45MDQ0MDEgMy4wNTcyMjYsLTYuOTYxNTg5IDYuOTYxNTc2LC02Ljk2MTU4OSB6IiBzdHlsZT0iY29sb3I6IzAwMDtmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OjQwMDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZTptZWRpdW07bGluZS1oZWlnaHQ6bm9ybWFsO2ZvbnQtZmFtaWx5OnNhbnMtc2VyaWY7dGV4dC1pbmRlbnQ6MDt0ZXh0LWFsaWduOnN0YXJ0O3RleHQtZGVjb3JhdGlvbjpub25lO3RleHQtZGVjb3JhdGlvbi1saW5lOm5vbmU7dGV4dC1kZWNvcmF0aW9uLXN0eWxlOnNvbGlkO3RleHQtZGVjb3JhdGlvbi1jb2xvcjojMDAwO2xldHRlci1zcGFjaW5nOm5vcm1hbDt3b3JkLXNwYWNpbmc6bm9ybWFsO3RleHQtdHJhbnNmb3JtOm5vbmU7d3JpdGluZy1tb2RlOmxyLXRiO2RpcmVjdGlvbjpsdHI7YmFzZWxpbmUtc2hpZnQ6YmFzZWxpbmU7dGV4dC1hbmNob3I6c3RhcnQ7d2hpdGUtc3BhY2U6bm9ybWFsO2NsaXAtcnVsZTpub256ZXJvO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO29wYWNpdHk6MTtpc29sYXRpb246YXV0bzttaXgtYmxlbmQtbW9kZTpub3JtYWw7Y29sb3ItaW50ZXJwb2xhdGlvbjpzUkdCO2NvbG9yLWludGVycG9sYXRpb24tZmlsdGVyczpsaW5lYXJSR0I7c29saWQtY29sb3I6IzAwMDtzb2xpZC1vcGFjaXR5OjE7ZmlsbDojMDA4MmM5O2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDo1LjU2NTkwMDMzO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7Y29sb3ItcmVuZGVyaW5nOmF1dG87aW1hZ2UtcmVuZGVyaW5nOmF1dG87c2hhcGUtcmVuZGVyaW5nOmF1dG87dGV4dC1yZW5kZXJpbmc6YXV0bztlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIi8+PHBhdGggc3R5bGU9ImZpbGw6IzAwODJjOTtmaWxsLW9wYWNpdHk6MTtzdHJva2Utd2lkdGg6LjQ3MDM4NTIyIiBpZD0icGF0aDExNzQiIGQ9Im0gMjEuMjM1NjkzLDY5LjA0Mzc1NiBjIC0wLjMyOTI2LDAgLTAuNDcxNDcsMC4xODc5MzYgLTAuNDcxNDcsMC41MTcyNDIgViA4My4yMDM2OCBjIDAsMC4zMjkyNyAwLjE0MjIxLDAuNTE0OTUgMC40NzE0NywwLjUxNDk1IGggMC4zNzc2MyBjIDAuMzI5MjcsMCAwLjUxNDk0LC0wLjE4NTY4IDAuNTE0OTQsLTAuNTE0OTUgViA3MS44NzQ4MzMgbCA3LjQ0NzMsMTEuNTU3NzI3IGMgMC4wMzI0LDAuMDUwNSAwLjA2NzcsMC4wODQyIDAuMTAyOTksMC4xMjEyMyAwLjAxMDYsMC4wMTI1IDAuMDE3OSwwLjAyNTYgMC4wMjk4LDAuMDM2NiAwLjAzMTcsMC4wMjg5IDAuMDY2NSwwLjA0NCAwLjEwMDY1LDAuMDYxOCAwLjAxOSwwLjAxIDAuMDMzOCwwLjAyNDcgMC4wNTUsMC4wMzIgMC4wMTQ4LDAuMDA1IDAuMDMwNCwwLjAwMiAwLjA0NTgsMC4wMDYgMC4wNTI1LDAuMDEzNSAwLjEwNjE4LDAuMDI3NSAwLjE2OTM2LDAuMDI3NSBoIDAuMzc1MzQgYyAwLjMyOTI2LDAgMC40NzE0NiwtMC4xODU2NyAwLjQ3MTQ2LC0wLjUxNDk1IFYgNjkuNTYwNzY4IGMgMCwtMC4zMjkzMDUgLTAuMTQyMiwtMC41MTcyNDEgLTAuNDcxNDYsLTAuNTE3MjQxIGggLTAuMzc1MzQgYyAtMC4zMjkyOSwwIC0wLjUxNzI0LDAuMTg3OTM2IC0wLjUxNzI0LDAuNTE3MjQxIFYgODAuODkwMTEgbCAtNy40NDczLC0xMS41NTc3MTYgYyAtMC4wMjU0LC0wLjAzOTM5IC0wLjA1NjEsLTAuMDYzMzkgLTAuMDg0NywtMC4wOTM5IC0wLjA4NiwtMC4xMjE2MTEgLTAuMjIyMiwtMC4xOTQ1NDUgLTAuNDE2NTQsLTAuMTk0NTQ1IHogbSA4OS40MjAxNTcsMC4xODc2NzYgYyAtMC4zMjkyNiwwIC0wLjE4NzY3LDAuMTg3OTU2IC0wLjE4NzY3LDAuNTE3MjQxIHYgNC42NTc0MTcgYyAwLDAuNDcwMzcgMC4wNDU2LDAuNzk4NzIgMC4wNDU2LDAuNzk4NzIgaCAtMC4wNDU2IGMgMCwwIC0wLjg5NDE5LC0yLjA2ODkzIC0zLjM4NzIyLC0yLjA2ODkzIC0yLjcyODIxLDAgLTQuNjU3NzEsMi4xNjM3MiAtNC41NjM1Nyw1LjM2MjMxIDAsMy4xOTg2MiAxLjc0MDI0LDUuNDEwNDEgNC41MTU1MSw1LjQxMDQxIDIuNjgxMTgsMCAzLjU3NDksLTIuMTY1MDggMy41NzQ5LC0yLjE2NTA4IGggMC4wNDggYyAwLDAgLTAuMDkzOSwwLjI4MjgzIC0wLjA5MzksMC42NTkxMyB2IDAuNzk4NzQgYyAwLDAuMzI5MjYgMC4xODc5NiwwLjQ3MTQ4IDAuNTE3MjYsMC40NzE0OCBoIDAuMzI5NTUgYyAwLjMyOTI3LDAgMC40NjkxNywtMC4xODc5OCAwLjQ2OTE3LC0wLjUxNzI0IFYgNjkuNzQ4NjczIGMgMCwtMC4zMjkyODUgLTAuNTE3NTQsLTAuNTE3MjQxIC0wLjg0NjgxLC0wLjUxNzI0MSB6IG0gLTM2LjU0OTg1OSwwLjA0ODEgYyAtMC4zMjkyNzYsMCAtMC4xMzk2MSwwLjE4Nzk3NiAtMC4xMzk2MSwwLjUxNzI0MSBWIDgxLjMyMDE3IGMgMCwyLjI1NzgzIDEuNTAzNzY2LDIuNTQwMzkgMi4zNTA0NjMsMi41NDAzOSAwLjM3NjMwMSwwIDAuNTE3MjE3LC0wLjE4Nzk2IDAuNTE3MjE3LC0wLjUxNzIxIHYgLTAuMzI5NTggYyAwLC0wLjMyOTI2IC0wLjE4ODIxMiwtMC40NjkxOCAtMC40MjMzOTQsLTAuNDY5MTggLTAuNDcwNDA1LC0wLjA0NyAtMS4wODAyNDksLTAuMTg4ODcgLTEuMDgwMjQ5LC0xLjUwNTk0IFYgNjkuNzk2NzcgYyAwLC0wLjMyOTI2NiAtMC41MTc1MzEsLTAuNTE3MjQxIC0wLjg0NjgwNywtMC41MTcyNDEgeiBNIDU3LjIyMDI2Niw3MC41MDE2OSBjIC0wLjMyOTI3LDAgLTAuNTE3MjM4LDAuMTg3OTc1IC0wLjUxNzIzOCwwLjUxNzI0IHYgMi40NDY1OSAxLjE3NjM4IDUuMzE0MjMgYyAwLDIuNDQ1OTkgMS4zNjUxMDUsMy44MTA2NCAzLjYyMjk0NiwzLjgxMDY0IDAuNDIzMzQsMCAwLjU2MzAxMSwtMC4xMzk5MyAwLjU2MzAxMSwtMC40NjkxOCB2IC0wLjI4MzggYyAwLC0wLjM3NjI5IC0wLjEzOTY3MSwtMC40NzAyNCAtMC41NjMwMTEsLTAuNTE3MjQgLTAuNzk5NjUyLC0wLjA0NyAtMi4yNTg5MDUsLTAuMzI5MTIgLTIuMjU4OTA1LC0yLjcyODA5IHYgLTUuMTc0NjQgaCAyLjExNzAwOSBjIDAuMzI5MjY4LDAgMC41MTcyMzgsLTAuMTM5OSAwLjUxNzIzOCwtMC40NjkxOCB2IC0wLjE0MTkgYyAwLC0wLjMyOTI2IC0wLjE4Nzk3LC0wLjUxNzIyIC0wLjUxNzIzOCwtMC41MTcyMiBoIC0yLjExNzAwOSB2IC0yLjQ0NjU5IGMgMCwtMC4zMjkyNjUgLTAuMTM5OTA5LC0wLjUxNzI0IC0wLjQ2OTE3NywtMC41MTcyNCB6IG0gLTE4LjczNDk2MywyLjYzNDI3IGMgLTIuODIyMjksMCAtNS4wODE5MiwyLjAyMzU5IC01LjEyODg4LDUuNDEwMzcgMCwzLjE5ODU5IDIuMzUyODksNS40MDgwOSA1LjQxMDM5LDUuNDA4MDkgMS42NDYzMjgsMCAyLjg2ODUyLC0wLjcwNDk1IDMuNDMyOTg2LC0xLjEyODMxIDAuMjM1MjYsLTAuMTg4MTQgMC4yODMwMTQsLTAuNDIzOTIgMC4xNDE4OTYsLTAuNjU5MTIgbCAtMC4xNDE4OTYsLTAuMjMzNDYgYyAtMC4xNDExMTUsLTAuMjgyMjMgLTAuMzc0NjEyLC0wLjMzMDA1IC0wLjY1Njg0NiwtMC4xNDE4OCAtMC40NzAzODMsMC4zNzYyOSAtMS40MTMyOTUsMC45NDA2NCAtMi43MzAzNzEsMC45NDA2NCAtMi4xMTY3MDksMCAtMy45NTEzMTksLTEuNTA2MDQgLTMuOTk4Mjc5LC00LjE0MDE5IGggNy40NzkzMzEgYyAwLjI4MjI0NywwIDAuNTE3MjM4LC0wLjIzNTAxIDAuNTE3MjM4LC0wLjUxNzI1IDAsLTIuOTYzNCAtMS41NTAyOTEsLTQuOTM4ODkgLTQuMzI1NTY5LC00LjkzODg5IHogbSAyOS4yMjM4ODMsMCBjIC0zLjA1NzQ4MiwwIC01LjQwOTIwMywyLjI1NzU1IC01LjQ1NjE2MSw1LjQ1NjE0IDAsMy4xOTg2IDIuMzUyODk2LDUuNDEwMzkgNS40MTAzODcsNS40MTAzOSAxLjg4MTU0MSwwIDMuMTUxMzA3LC0wLjg5NDkzIDMuNjY4NzE4LC0xLjMxODI4IDAuMjM1MjYyLC0wLjIzNTIgMC4yODA3MjksLTAuNDIyNjUgMC4xMzk2MTksLTAuNzA0OSBMIDcxLjMzMjEzLDgxLjc5MTY1IGMgLTAuMTg4MTM2LC0wLjI4MjI1IC0wLjM3NjkwMiwtMC4zMzAwNSAtMC42NTkxMzEsLTAuMTQxOTEgLTAuNDcwMzgzLDAuNDIzMzQgLTEuNDU3NTUyLDEuMDgyNTUgLTIuOTE1NzUxLDEuMDgyNTUgLTIuMjU3ODI2LDAgLTQuMDQ2MzQ4LC0xLjY5NDE5IC00LjA0NjM0OCwtNC4xNDAxOSAwLC0yLjQ5MzAyIDEuNzg4NTIyLC00LjE4NTk2IDQuMDQ2MzQ4LC00LjE4NTk2IDEuMjIzMDA4LDAgMi4xMTU4MTYsMC42MTEzNyAyLjU4NjE4LDAuOTQwNjUgMC4yODIyNDEsMC4xODgwNyAwLjUxNjc0OCwwLjE4ODM4IDAuNzA0OTEzLC0wLjA5MzggbCAwLjE0MTksLTAuMjM1NzIgYyAwLjIzNTI3MSwtMC4yODIyNCAwLjE4NzEyNSwtMC41MTY3NyAtMC4wNDgxLC0wLjcwNDkgLTAuNTE3NDIyLC0wLjQyMzM3IC0xLjY0NTUxNSwtMS4xNzYzOCAtMy40MzI5ODYsLTEuMTc2MzggeiBtIDE1Ljg5OTMwMSwwIGMgLTMuMDEwNDUxLDAgLTUuNDU2MTU2LDIuMzA0ODIgLTUuNDU2MTU2LDUuMzYyMzEgMCwzLjEwNDUxIDIuNDQ1NzA1LDUuNDU2MTUgNS40NTYxNTYsNS40NTYxNSAzLjAxMDQ3OCwwIDUuNDU2MTY4LC0yLjM1MTY0IDUuNDU2MTY4LC01LjQ1NjE1IDAsLTMuMDU3NDkgLTIuNDQ1NjksLTUuMzYyMzEgLTUuNDU2MTY4LC01LjM2MjMxIHogbSAtMzAuNDI5OTkxLDAuMTU3OTMgYyAtMC4xMTUxOCwwLjAxODQgLTAuMjI2MDM3LDAuMDk1OSAtMC4zMzE4NTcsMC4yMjE5NyBsIC0xLjkwNDE2NCwyLjI2ODA1IC0xLjQyMzU0NiwxLjY5ODE4IC0yLjE1ODIwNSwtMi41NzAxNSAtMS4xNjk1MDUsLTEuMzk2MDggYyAtMC4xMDU4NzYsLTAuMTI2MTEgLTAuMjI1Nzk1LC0wLjE5NTI1IC0wLjM1MDE2MywtMC4yMDU5NyAtMC4xMjQzNTQsLTAuMDEgLTAuMjUzNzk2LDAuMDM2MSAtMC4zNzk5MTksMC4xNDE4OSBsIC0wLjI4ODM3MSwwLjI0MjU4IGMgLTAuMjUyMjIzLDAuMjExNjcgLTAuMjM5MDEsMC40NDU4MyAtMC4wMjc0NSwwLjY5ODA3IGwgMS45MDQxNjYsMi4yNjgwMyAxLjU3OTE3MiwxLjg4MzU3IC0yLjMxMTU0MywyLjc1MzI2IGMgLTAuMDAyNCwwLjAwMiAtMC4wMDM1LDAuMDA1IC0wLjAwNDYsMC4wMDYgbCAtMS4xNjcyMTUsMS4zODkyMyBjIC0wLjIxMTY1MywwLjI1MjIzIC0wLjE4ODEzMiwwLjUxODQyIDAuMDY0MDgsMC43MzAwOSBsIDAuMjg4MzY4LDAuMjQwMyBjIDAuMjUyMjM5LDAuMjExNjQgMC40ODE4MTMsMC4xNTg0MSAwLjY5MzQ2NSwtMC4wOTM5IGwgMS45MDE4NzYsLTIuMjY4MDYgMS40MjU4MzQsLTEuNjk4MTggMi4xNTgyMDQsMi41NzI0NCBjIDEwZS00LDAuMDAyIDAuMDAzNSwwLjAwNCAwLjAwNDYsMC4wMDUgbCAxLjE2NDkyOCwxLjM5MTUgYyAwLjIxMTY1MiwwLjI1MjIzIDAuNDc3ODM0LDAuMjczMzcgMC43MzAwODEsMC4wNjE3IGwgMC4yODgzNzEsLTAuMjQwMyBjIDAuMjUyMjM3LC0wLjIxMTY1IDAuMjM5MTM0LC0wLjQ0NTgxIDAuMDI3NDYsLTAuNjk4MDUgbCAtMS45MDQxNjEsLTIuMjcwMzQgLTEuNTc5MTc3LC0xLjg4MTI5IDIuMzExNTQ2LC0yLjc1NTU0IGMgMC4wMDI0LC0wLjAwMiAwLjAwMzUsLTAuMDA0IDAuMDA0NiwtMC4wMDYgbCAxLjE2NzIxNCwtMS4zODkyMSBjIDAuMjExNjUxLC0wLjI1MjI0IDAuMTg4MTMyLC0wLjUxODQ0IC0wLjA2NDA4LC0wLjczMDA5IGwgLTAuMjg4MzcxLC0wLjI0MDMgYyAtMC4xMjYxMTIsLTAuMTA1ODcgLTAuMjQ2NDA4LC0wLjE0NjU1IC0wLjM2MTYwNywtMC4xMjgxNSB6IG0gMzguNjYyMzA4LDAuMDc3OSBjIC0wLjMyOTI4LDAgLTAuNDcxNDgsMC4xODc5NiAtMC40NzE0OCwwLjUxNzIzIHYgNi4wNjcyMiBjIDAsMi42ODEyIDEuOTc1NywzLjk5ODI5IDQuNDIxNjksMy45OTgyOSAyLjQ0NiwwIDQuNDIxNjk2LC0xLjMxNzA5IDQuNDIxNjk2LC0zLjk5ODI5IHYgLTYuMDY3MjMgYyAwLjA0NywtMC4zMjkyNiAtMC4xMzk5MSwtMC41MTcyMyAtMC40NjkxNzYsLTAuNTE3MjMgaCAtMC4zNzc2MyBjIC0wLjMyOTI3LDAgLTAuNTE3MjQsMC4xODc5NyAtMC41MTcyNCwwLjUxNzIzIHYgNS42OTE4OSBjIDAsMS41OTkzMSAtMS4wMzUsMy4wNTc2NiAtMy4wNTc2NSwzLjA1NzY2IC0xLjk3NTYsMCAtMy4wNTc2MywtMS40NTgzNSAtMy4wNTc2MywtMy4wNTc2NiB2IC01LjY5MTg5IGMgMCwtMC4zMjkyNiAtMC4xODc5NywtMC41MTcyMyAtMC41MTcyNiwtMC41MTcyMyB6IG0gLTUzLjQwMzU2MSwwLjk0MDYzIGMgMS41MDUyMjYsMCAyLjgyMTYxLDEuMDgxNTUgMi45MTU3NTMsMy4yNDUzMSBoIC02LjQ5MDYzMyBjIDAuMzI5MjcsLTIuMTE2NzQgMS44MzQ0NywtMy4yNDUzMSAzLjU3NDg4LC0zLjI0NTMxIHogbSA0NS4xNzEyNDQsMC4wOTM5IGMgMi4yMTA4MDksMCAzLjk5ODMwMywxLjc0MDIzIDMuOTk4MzAzLDQuMDkyMTQgMCwyLjQ0NTk4IC0xLjc4NzQ5NCw0LjIzNDAxIC0zLjk5ODMwMyw0LjIzNDAxIC0yLjIxMDc4MSwwIC0zLjk5OTM4NSwtMS44MzUwNSAtNC4wNDYzMzIsLTQuMjM0MDEgMCwtMi4zMDQ4OCAxLjgzNTU1MSwtNC4wOTIxNCA0LjA0NjMzMiwtNC4wOTIxNCB6IG0gMjMuNTY2MzAzLDAgYyAyLjIxMDgyLDAgMy4yOTMzOSwyLjAyMzQ2IDMuMjkzMzksNC4xNDAyIDAsMi45NjM0IC0xLjYwMTAyLDQuMTg1OTUgLTMuMzQxNDQsNC4xODU5NSAtMS45Mjg1NiwwIC0zLjI0NDEzLC0xLjY0NTkgLTMuMjkxMDgsLTQuMTg1OTUgMCwtMi42MzQxNSAxLjUwNDY1LC00LjE0MDIgMy4zMzkxMywtNC4xNDAyIHoiLz48L3N2Zz4="
link:
- - en_US
- {{ portalNextcloudLinkBase }}/apps/files
allowedGroups:
- 'cn=Domain Users,cn=groups,{{ ldapBaseDn }}'
- 'cn=Domain Admin,cn=groups,{{ ldapBaseDn }}'
linkTarget: newwindow
description:
de_DE: Dateien verwalten, bearbeiten und teilen
en_US: Manage, edit and share files
displayName:
de_DE: Nextcloud
en_US: Nextcloud
---
action: ensure_list_contains
module: portals/category
position: cn=domain-service,cn=category,cn=portals,cn=univention,{{ ldapBaseDn }}
properties:
entries:
- cn=nextcloud,cn=entry,cn=portals,cn=univention,{{ ldapBaseDn }}
...
Your directory structure looks like Listing 3.19.
nextcloud-packaged-integration/
├── docker
└── plugins
├── ldap-schema
│ └── nextcloud.schema
└── udm-data-loader
└── 86_Nextcloud.yaml
3.8.4. Build container image#
After you prepared the plugins for the packaged integration, it’s time to bundle them in a container image. This section follows the steps outlined in Bundle packaged integrations and applies them to the Nextcloud packaged integration.
To bundle the packaged integration, use the following steps:
Create the
Dockerfile
in thedocker/
directory with the content in Listing 3.20.# SPDX-License-Identifier: AGPL-3.0-only # SPDX-FileCopyrightText: 2024 - 2025 Univention GmbH ARG BASE_IMAGE_TAG=3.20 ARG BASE_IMAGE=docker.io/alpine FROM ${BASE_IMAGE}:${BASE_IMAGE_TAG} # Create system group and system user RUN addgroup -S appgroup && adduser -S appuser -G appgroup USER appuser WORKDIR / # Copy plugins of the packaged integration to the Docker image COPY plugins /plugins # Copy the plugin loader to the Docker image COPY docker/loader.sh /bin/loader CMD ["/bin/loader"]
Create the
loader.sh
loader script in thedocker/
directory with the content in Listing 3.21. For information about the loader, see Packaged integration loader.#!/bin/sh # SPDX-License-Identifier: AGPL-3.0-only # SPDX-FileCopyrightText: 2024 - 2025 Univention GmbH set -eu echo "Copying the Nubus plugins into the /target volume" for source in /plugins/*; do plugin_type=$(basename "${source}") target="/target/${plugin_type}" if [ -d "${target}" ]; then echo "COPY - Plugin type ${plugin_type} in /target, copying files." cp -av "${source}" /target else echo "SKIP - Plugin type ${plugin_type} not in /target, skipping." fi done
Finally, your directory structure looks like Listing 3.22.
nextcloud-packaged-integration/ ├── docker │ ├── Dockerfile │ └── loader.sh └── plugins ├── ldap-schema │ └── nextcloud.schema └── udm-data-loader └── 86_Nextcloud.yaml
To build the container image, run the commands in Listing 3.23.
$ export IMAGE_NAME="nextcloud" $ cd nextcloud-packaged-integration $ docker build -t "$IMAGE_NAME" -f docker/Dockerfile .
3.8.5. Publish packaged integration#
To make the packaged integration available for Nubus for Kubernetes, you need to publish it to a container registry where your intended audience has access to.
To publish your container image, use the commands from the example in Listing 3.24.
$ export REGISTRY="artificts.software-univention.de"
$ export REPOSITORY="nubus/images/nextcloud-packaged-integration"
$ export IMAGE_NAME="nextcloud"
$ export IMAGE_TAG="0.1.0"
$ docker image tag "$IMAGE_NAME" "$REGISTRY"/"$REPOSITORY"/"$IMAGE_NAME":"$IMAGE_TAG"
$ docker image push "$REGISTRY"/"$REPOSITORY"/"$IMAGE_NAME":"$IMAGE_TAG"
The environment variables used in Listing 3.24 need to reflect the host and folder structure of your container registry. An operator later uses them in their Helm values when referring to the container image of the packaged integration. Table 3.2 shows the mapping.
Environment variable |
Description |
Helm Chart key |
---|---|---|
|
FQDN and optional port of your container registry |
|
|
PATH to the image on the registry without trailing slash |
|
|
The name of the container image |
|
|
Your version tag or |
|
3.8.6. Communicate packaged integration#
You need to tell operators that want to install your packaged integration, where they can find the container image, what each template variable is for, and which values each variable accepts. Provide an example. This how-to defines the following template variables that you need to communicate:
nextcloudUserPassword
The operator must define a dedicated password for the LDAP search user. They must use the same password in the Nextcloud LDAP configuration for the search user.
portalNextcloudLinkBase
The operator must set the base URL to their Nextcloud instance, for example
https://nextcloud.example.com
.
Tip
You don’t need to communicate the ldapBaseDn
template variable,
because Nubus for Kubernetes automatically fills in the value during installation.