Collaboration with Directory Service (opsi-directory-connector)

Introduction

The opsi directory connector transfers data from an LDAP directory service to an opsi installation. This way it is no longer necessary to manage data on multiple systems—​the automatic synchronisation reduces the administration effort. Since the directory connector uses LDAP in the background, it works with Active Directory as well as with Samba 4.

Prerequisites

This module is currently a paid extension. This means that you need an activation file to unlock it. You will receive this file after you have purchased the extension. For evaluation purposes, we’re happy to provide you with a temporary license free of charge. Please contact us via email.

General Requirements

  • The directory service on the machine serving as the source must implement the LDAP protocol.

  • The target system must run opsi 4.0.7 or later. Older versions may work; however, we have not tested this.

  • The machine running the directory connector must have network access to the machine running the directory service and to the opsi-server.

You can run all components on the same machine. However, let’s assume for now that there are multiple machines involved.

Hardware Requirements

For a small environment with up to 500 opsi clients you need at least:

  • 256 MB free RAM

  • Network Connections

In larger environments, 256 MB of RAM may not be sufficient. Adjust the hardware equipment of the machines if necessary.

Software Requirements

Installation and operation of the Directory Connector is only supported on Linux. Support for Windows systems is not planned.

Since the extension uses standard protocols for communication over the network, no any additional opsi or directory service components are required.

Installation

To install the Directory Connector, first add the opsi repository (see the chapter Getting Started, sections on Debian/Ubuntu, openSUSE/SLES, and CentOS/RHEL). Next, install the package opsi-directory-connector via the package manager of your distribution.

For example, on Debian-based systems, use this command:

apt-get install opsi-directory-connector

Configuration

The Directory Connector offers a wide range of settings to adapt it to very different environments. The configuration file /etc/opsi/opsidirectoryconnector-custom.conf is in JSON format and must contain valid JSON (key-value pairs). For boolean values use true or false; text is enclosed in double quotes (e.g. "this is text").

Our package contains an example configuration. You can use the file /usr/share/opsi-directory-connector/opsi-directory-connector.example.conf as a template for your own configuration:
cp /usr/share/opsi-directory-connector/opsi-directory-connector.example.conf /etc/opsi/opsidirectoryconnector-custom.conf

Connection to the Directory Service (directory)

In the directory section you configure the connection to the directory service. Here you can also limit the search scope to certain areas and objects.

{
    "directory": {
        "address": "ldap://192.168.12.34",
        "user": "DOMAIN\\opsiconnector",
        "password": "insertpasswordhere",
        "passwordFile": "",
        "search_base": "dc=testcompany,dc=local",
        "search_query_computers": "(objectClass=computer)",
        "identifying_attribute": "dn",
        "connection_options": {
            "paged_search_limit": 768
        }
    },
    …
}

Enter the address of the LDAP server after address. If the protocol ldaps or the port 636 is used, then the communication is SSL-encrypted:

        "address": "192.168.12.34:636",

In addition, enter the user name (user) and password (password) for authentication to the directory service.

To increase security, we recommend using a dedicated user account.

Instead of a password, you can enter the path to a file containing the password after passwordFile. The advantage is that the password is not stored in plain text in the configuration file. A password read from passwordFile overwrites any values set for password.

The format of the user name depends on the directory service application in use and its configuration:
Down-Level Logon Name: DOMAIN\username
User Principal Name (UPN): user@domain
Distinguished Name (DN): uid=opsiconnect,cn=users,dc=test,dc=intranet

Specify the point from which the connector looks for matching entries behind search_base. The filter used to search for clients can be configured via search_query_computers.

From version 23, the optional key identifying_attribute specifies which attribute should be used for the unique identification of a client. The default setting is dn. A common alternative is distinguishedName, which is mainly used in the Microsoft’s Active Directory.

The key connection_options defines additional options for the connection. For example, you can determine via verify whether or not the certificate is to be validated for an SSL connection. In addition, you can specify the path to a Certificate Authority (CA); enter the name of the file you want to use for verification here. If the connection is started via the unencrypted port 389, then start_tls determines whether a secure connection is started after the login. By default, start_tls is enabled for port 389, but the certificate is not checked.

If multiple queries are used to read the elements from the directory, then define the number behind the optional key paged_search_limit. The value must be an integer. The feature has been supported since version 20.

Are you missing a connection option? If possible, we will implement further features on request. Please feel free to contact us via email.
Since version 14 you can use the parameter --check-directory to test the connection to the directory without connecting to the opsi-server.

Connection to Univention Corporate Server

For a connection to Univention Corporate Server (UCS), enter the Distinguished Name (DN) as the user name. It has the following syntax:

uid=<username>,cn=users,dc=company,dc=mydomain

On UCS, LDAP is accessible via ports 7389 (unsecured) or 7636 (SSL-secured). If Samba is also installed on the server and set up as an AD-compatible domain controller, it listens on ports 389 (unsecured) or 636 (SSL-secured). To use the SSL-secured ports, set the start_tls connection option to true.

The two possible connections also differ as far as the login name is concerned:

  • LDAP: uid=…

  • Samba: dn=…

Normally, a search for computer objects takes place in the computers container. The following command prints the matching value for search_base:

echo "cn=computers,$(ucr get ldap/base)"

To search for Windows clients, enter (objectClass=univentionWindows) as the value for search_query_computers.

The article Cool Solution - LDAP search user / simple authentication account in the Univention Knowledge Base explains how to create a user with read-only access.

Behaviour Settings (behaviour)

These settings control the behaviour of the Directory Connector:

{
    …
    "behaviour": {
        "write_changes_to_opsi": true,
        "root_dir_in_opsi": "clientdirectory",
        "update_existing_clients": true,
        "prefer_location_from_directory": true,
        "group_handling": "dn",
        "group_description": "dn",
        "override_root_dir": true,
        "delete_empty_groups": false,
        "skip_adding_clients": false,
    },
    …
}

If you set write_changes_to_opsi to false, no data will be written to opsi. This is useful, for example, if you want to check the connection settings.

root_dir_in_opsi specifies which group in opsi should be used as root group. Make sure that this group exists.

The management interface opsi-configed shows the group clientdirectory as DIRECTORY. So if clients or groups should appear directly below DIRECTORY, enter clientdirectory as the value for root_dir_in_opsi.

If you set update_existing_clients to false, then clients already existing in opsi will not be changed. If, on the other hand, this value is set to true, then any manually set data will be overwritten with the values from the directory service.

If prefer_location_from_directory is set to true, clients in opsi will be moved to the position they have in the directory service. Set the value to false to disable the behaviour.

Since version 31, the group handling is controlled by the optional key group_handling. The default setting is dn. Groups are derived from the DN (Distinguished Name) of a computer and created accordingly as part of the opsi directory service. A client can only be a member of one single group.

If you activate delete_empty_groups, then groups which are empty after synchronisation are also deleted from the opsi directory service. Only groups below root_dir_in_opsi are considered in that case.

With skip_adding_clients you skip the creation of clients in opsi completely. You can use this option, for example, in conjunction with prefer_location_from_directory so that only existing clients are moved.

Settings for UCS@school

Set the key group_handling to ucsatschool to adapt the behaviour for UCS@school environments. The Directory Connector then automatically searches for schools and determines their rooms. Afterwards, the synchronisation with opsi takes place.

For each school a group is created in opsi. In UCS@school, however, a computer can be a member in more than one room. Therefore, the Directory Connector does not create the groups as a group in the opsi directory service, but as a normal group. In this way, a client can also be in multiple groups in opsi.

If the UCS@school groups are to be created in the opsi directory service after all, set the key override_root_dir to false. The key override_root_dir is only available for "group_handling": "ucsatschool". The default value is true. If override_root_dir is set to false, then make sure that each school computer is only assigned to one room.

Via group_description you can customise the description of the opsi groups. The following values are possible:

  • dn: The distinguished name of the group will be stored in opsi as the group description.

  • directory: The group description is read from the field description of the directory service group.

  • If the value is not set or is set differently, the name of the group is entered as the description.

…
 "behaviour": {
        "group_handling": "ucsatschool",
        …
        "group_not_in_directory": true,
        "opsi_clients_to_ignore": {
            "clients": ["win1.uib.local","win2.uib.local","win3.uib.local"],
            "groups": ["server"]
        }
 }
 …

If group_not_in_directory is set to true, then all clients which aren’t available in the directory service are added to the group not_in_directory. This option is only available with the setting "group_handling": "uscatschool". With the parameter opsi_clients_to_ignore you can exclude clients or whole groups from this rule.

A short description of all configuration options can also be found in the sample configuration file (/usr/share/opsi-directory-connector).

Matching Attributes (mapping)

Since a directory service is an extremely flexible system, the Directory Connector needs precise information about the attributes and which of them are to be matched to the attributes in opsi itself. For this reason there is a mapping for client attributes.

{
    …
    "mapping": {
        "client": {
            "id": "name",
            "description": "description",
            "notes": "",
            "hardwareAddress": "",
            "ipAddress": "",
            "inventoryNumber": "",
            "oneTimePassword": ""
        }
    },
    …
}

The key is always the attribute in opsi, and the value is the attribute from the directory service. If the value is empty, no mapping takes place.

If the value read from the directory for the client ID is not recognisable as FQDN, a corresponding FQDN is created. The domain part is generated from the DC values of the element.
On Univention Corporate Server (UCS), the value macAddress can be specified for hardwareAddress if the connection is established via LDAP (port 7389 or 7636).

Mapping clients and depots

In the mapping section you can also define the mapping of clients to depots. Currently there is only one mapping type, network.

A client is assigned to a depot if the IP address of the client matches the network address range (networkAddress) of the depot.

Alternatively, you can also assign a list of network ranges to a depot:
{
    …
    "mapping": {
        …
        "depot": {
            "type": "network",
            "test-depot1.test.local": ["192.168.24.0/24","192.168.25.0/24"],
            "test-depot1.test.local": ["192.168.27.0/24","192.168.28.0/24"]
        }
    },
    …
}

Manually assign Group Names

Group names are usually applied without modifications. However, it’s possible that you encounter group names which are invalid in opsi. In this case you can assign group names manually. This is possible from version 23.

To do this, define a subsection group_name in the mapping section. Now assign the names from the directory service to the names of the opsi environment. Always use lower case letters for the group names. The following example assigns the opsi group server to the group _server from the directory service:

{
    …
    "mapping": {
        "client": {
            …
        },
        "group_name": {
            "_server": "server"
        }
    },
    …
}
Please be careful when assigning the names manually, as this may have undesired side effects. Therefore, use this mapping option only in exceptional cases!

Connection to opsi (opsi)

In the opsi section you define how the Directory Connector connects to opsi.

{
    …
    "opsi": {
        "address": "https://localhost:4447",
        "username": "syncuser",
        "password": "secret",
        "exit_on_error": false,
        "passwordFile": "",
        "connection_options": {
            "verify_certificate": true
        }
    }
}

The opsi-server address is specified after address. Don’t forget to enter the port!

A proxy server for the connection can be set via the environment variable HTTPS_PROXY.

The two keys username and password contain the credentials for authentication at opsi-server. Instead of a password, you can enter the path to a file containing the password after passwordFile. The advantage is that the password is not stored in plain text in the configuration file. A password read from passwordFile overwrites any values set for password.

To increase security, we recommend using a dedicated user account.

If the key exit_on_error is set to true, then problems updating the data in opsi will cause the connection to be terminated. This happens, for example, when invalid values are transmitted. On the other hand, if this is set to false, errors are logged, but the connection stays open.

Specify options for the connection to the opsi-server under connection_options. Enable the verify_certificate setting to validate the server certificate. This value should be set to false when using self-signed certificates.

Since version 14 it is possible to test the connection to the opsi-server via the parameter --check-opsi without establishing a connection to the directory service.

Running the Dierectory Connector

The installation package contains the binary opsi-directory-connector. It expects the path to the configuration file after the --config switch:

opsi-directory-connector --config /etc/opsi/opsi-directory-connector-custom.conf
The user running the command does not need access to the opsi system because the credentials are stored in the configuration file.

The Directory Connector synchronises the data every time it runs. To set up a regular synchronisation, you can either use systemd or create a cronjob. The next two sections show how to set this up.

Recurring Synchronisation: how to set up systemd Units

We recommend setting up systemd units because, unlike cronjobs, systemd prevents simultaneous runs. The example shown here executes the Directory Connector five minutes after a machine has started. After that, it runs regularly every hour.

To do this, set up two user-defined systemd units in the /etc/systemd/system/ directory, a timer unit and a service unit.

Timer Unit

The Timer unit defines the recurring execution of the job; the file /etc/system/system/opsi-directory-connector.timer has the following content:

[Unit]
Description=Start the opsi-directory-connector in regular intervals

[Timer]
OnBootSec=5min
OnUnitActiveSec=1hour

[Install]
WantedBy=timers.target

Service Unit

The job itself is defined in the file /etc/system/system/opsi-directory-connector.service:

[Unit]
Description=Sync clients from AD to opsi.
Wants=network.target

[Service]
Type=oneshot
ExecStart=/usr/bin/opsidirectoryconnector --config /etc/opsi/opsidirectoryconnector-custom.conf

Activate Timer Unit

To enable the timer and start it right away, enter the following two commands:

systemctl enable opsi-directory-connector.timer
systemctl start opsi-directory-connector.timer

Otherwise, the timer runs the first time after the next reboot of the machine.

Recurring Synchronisation: how to set up a Cronjob

As an alternative to the two systemd units, you can automate the regular synchronisation with the Directory Connector via a cronjob.

Select the synchronisation interval so that no simultaneous synchronisation can run. Alternatively, use systemd as shown in the previous section.

Call the command crontab -e to create a new crontab or edit an existing one. The crontab contains information about the executable program. You also define when and how often a cronjob should run. In our example, we add the following line:

0 * * * * /usr/bin/opsidirectoryconnector --config /etc/opsi/opsidirectoryconnector-custom.conf

In this case, synchronisation always takes place on the hour. The first field defines minute 0; all other fields (hour, day, month, and weekday) contain * as a placeholder.

Command Line Arguments

The Directory Connector supports the following parameters and options:

Usage: __main__.py [-h] [--version] [--log-level {0,1,2,3,4,5,6,7,8,9}]
                   [--log-level-stderr {0,1,2,3,4,5,6,7,8,9}]
                   [--log-level-file {0,1,2,3,4,5,6,7,8,9}]
                   [--log-file LOG_FILE]
                   [--max-log-size MAX_LOG_SIZE]
                   [--keep-rotated-logs KEEP_ROTATED_LOGS]
                   [--check-directory | --check-opsi | --delete-clients DELETE_CLIENTS [DELETE_CLIENTS …]]
                   [--dry-run] --config
                   CONFIG

If an arg is specified in more than one place, then commandline values override environment
variables which override defaults.

optional arguments:
  -h, --help
                              show this help message and exit
  --version
                              show program's version number and exit
  --log-level {0,1,2,3,4,5,6,7,8,9}
                              Sets how much information will be logged. [env var: OPDC_LOG_LEVEL]
                              (default: 4)
  --log-level-stderr {0,1,2,3,4,5,6,7,8,9}, -l {0,1,2,3,4,5,6,7,8,9}
                              Sets how much information will be logged. [env var:
                              ODC_LOG_LEVEL_STDERR] (default: 4)
  --log-level-file {0,1,2,3,4,5,6,7,8,9}
                              Sets how much information will be logged to the log file. [env var:
                              ODC_LOG_LEVEL_FILE] (default: 5)
  --log-file LOG_FILE
                              Sets log file path. [env var: ODC_LOG_FILE] (default:
                              /var/log/opsi/directory-connector.log)
  --max-log-size MAX_LOG_SIZE
                              Limit the size of logfiles to SIZE megabytes.Setting this to 0 will
                              disable any limiting. [env var: ODC_MAX_LOG_SIZE] (default: 5.0)
  --keep-rotated-logs KEEP_ROTATED_LOGS
                              Number of rotated log files to keep. [env var: ODC_KEEP_ROTATED_LOGS]
                              (default: 1)
  --check-directory
                              Check if a connection to the directory can be established and if items
                              will be received. (default: False)
  --check-opsi
                              Check if a connection to the opsi server can be established. (default:
                              False)
  --delete-clients DELETE_CLIENTS [DELETE_CLIENTS …]
                              Delete list of clients from directory. (default: None)
  --dry-run
                              Print what would be done. (default: False)
  --config CONFIG
                              Path to the config. (default: None)

From version 39, the Directory Connector uses the opsi logger (log level 0 to 9). By default, the tool logs to /var/log/opsi-directory-connector and writes errors to stderr. To influence the log level for the two logs, use the parameters --log-level-stderr or --log-level-file. The switch --log-file defines a different log file.

By default, the log file is rotated when it reaches 5 MB, and one of the rotated logs is kept at a time. The parameters --max-log-size and --keep-rotated-logs override these default values.

In addition to the command line parameters, you can also set some of the values as keys in the configuration file or via environment variables. The following order applies:
  • Parameters overwrite everything.

  • Environment variables overwrite the configuration file and the default values.

  • The configuration file overwrites the default values.

Example configuration:

{
…
    "log-level-stderr": 6,
    "log-level-file": 3,
    "keep-rotated-logs": 4
…
}

Test Run (--dry-run)

You can call opsi-directory-connector with the parameter --dry-run to start a test run. You will see the individual steps in the output; changes in opsi will not be made:

---------- opsi actions ----------
Creating client client1.opsidc.intranet.
Creating client ds-win-client-2.opsidc.intranet.
Creating client ds-win-client-1.opsidc.intranet.
Creating client mac-client-1.opsidc.intranet.
Creating client windows-client-1.opsidc.intranet.
Creating client raspberrypi-1.opsidc.intranet.
Adding mac-client-1.opsidc.intranet to opsitestschool-mac pool.
Adding windows-client-1.opsidc.intranet to opsitestschool-pc pool og1.
Adding ds-win-client-2.opsidc.intranet to depotschule-pool-1.
Adding ds-win-client-1.opsidc.intranet to depotschule-pool-1.
----------------------------------
---------- summary ---------------
Create  6 clients and 0 groups.
0 clients removed from group.
Adding 4 clients to a new group.
----------------------------------

Unlike the setting "write_changes_to_opsi": false, which does not write any data to opsi, the switch --dry-run adjusts the output. This gives a better overview of the actions.

Deleting Clients from the Directory

By default, the Directory Connector has read-only access to the directory. If you call the program with the parameter --delete-clients, an independent run starts which tries to delete the given objects from the directory:

opsi-directory-connector --config config.conf --delete-clients client1

In this case, the Directory Connector searches for objects with cn=client1 in the defined search area. If there is a single hit, then the object is deleted. If, however, the program finds several matching objects, then it prints an error message and does not delete anything.

You can specify the objects to be deleted even more precisely:

opsi-directory-connector --config config.conf --delete-clients computers/test-clients/client1

The object cn=client1,ou=test-clients,ou=computers,dc=example,dc=org would be a hit and deleted, but cn=client1,ou=clients,ou=computers,dc=example,dc=org would not.

You can also specify multiple clients:

opsi-directory-connector --config config.conf --delete-clients computers/clients/client1 client2 client3
Always use the parameter --delete-clients with caution! For safety, you can combine the switch with --dry-run and check beforehand whether the correct objects are found.