create new tag
view all tags

Introduction to LCFG : Part 4b

The following examples assume you are using the virtual appliance described in IntroductoryTutorial.

This tutorial follows on from IntroductoryTutorialPart4a. In the following examples we will work on the task of managing a Secure Shell (SSH) service. Although in this tutorial we're only configuring this for a single machine keep in mind that this could be something you need to do for a large collection of machines. Once you go beyond a small number of machines doing this manually will be inefficient, tedious and there's the potential to miss out some of them.

Getting Started

As with the previous tutorial start by opening several terminal windows. To see the entire process of a change to an LCFG source profile being applied tail the server and client log files - /var/log/lcfg/server and /var/log/lcfg/client. You will also need root access in one terminal so you can modify the source profile, that can be acquired using sudo bash with the password being the same as the username.

For all these examples we will be using the LCFG file component, this is well suited to the task of managing a single file but once things become more complicated (e.g. you also need to manage services) you will want to look for another more specific component that supports that service.

All the files for this tutorial are provided in the lcfg-tutorial package, for Focal they are stored in the /usr/share/lcfg/tutorial/examples/focal/. To ensure you have the latest version run apt update and apt upgrade before starting.

Example 5 - Using a template

In the previous part of this tutorial a simple message of the day file was managed using the file component. That example was simple enough that the entire contents could be simply expressed via the tmpl resource (i.e. the type of the managed file is literal). When managing services there will typically be one or more complex configuration files, parts of which need to be managed.

Consider the situation in which you have been asked to install and configure the openssh service, the configuration for this is stored in /etc/ssh/sshd_config so you need to manage that file.

Firstly install the example template:

cp /usr/share/lcfg/tutorial/examples/focal/sshd_config.tmpl /usr/share/lcfg/conf/file

Normally that template file would be provided in that location as part of a package (e.g. RPM or Deb), in this case we do it manually to simulate that distribution process.

Aside: Every LCFG component has a standard directory within /usr/share/lcfg/conf/ where it will search for templates if you specify them using a relative path. You may otherwise store them anywhere if you specify them using an absolute path.

This is available in source/example5, either copy that file to overwrite your lcfg-tutorial profile (in /var/lib/lcfg/conf/server/source/) like:

cp /usr/share/lcfg/tutorial/examples/focal/source/example5 /var/lib/lcfg/conf/server/source/lcfg-tutorial

Or directly edit the lcfg-tutorial source profile, remove any previous motd configuration and add the following:

!file.files         mADD(example)
file.file_example   /etc/ssh/sshd_config
file.type_example   template : perl
file.tmpl_example    sshd_config.tmpl
file.owner_example root
file.group_example root
file.mode_example 0600

The important differences here are in the type and tmpl of the file. It is specified as a template and furthermore that is set to use the perl (Template Toolkit) style. If you do not specify perl your template will be processed in a deprecated legacy style which is very difficult to read and write so we recommend avoiding that where possible...

Again watch the change go through the server, client and file component logs. Once it has all finished check the contents of /etc/ssh/sshd_config

That template has produced the default configuration for the SSH service on Ubuntu. We have added one line of comment at the top:

# This file is managed by LCFG - manual changes will *NOT* be preserved!

This is good practice and you will see it in most configuration files managed using LCFG.

It is instructive to compare the template with the generated file:

diff -u /usr/share/lcfg/conf/file/sshd_config.tmpl /etc/ssh/sshd_config

In particular note the output from the conditional block.

Example 6 - Using Variables

Having configured the SSH service consider a situation in which you have been tasked with changing the configuration so that the daemon listens on a non-standard port. That is done by altering the Port option in the sshd_config. If you examine the template (/usr/share/lcfg/conf/file/sshd_config.tmpl) you will see that it has already been written with this task in mind:

[% IF v_port -%]
# Listening port configured by LCFG
Port [% v_port %]
[% ELSE -%]
#Port 22
[% END -%]

The v_port parameter maps onto an LCFG resource of the same name for the LCFG file component, if it is not set then the default will be applied.

This is available in source/example6, either copy that file to overwrite your lcfg-tutorial profile (in /var/lib/lcfg/conf/server/source/) like:

cp /usr/share/lcfg/tutorial/examples/focal/source/example6 /var/lib/lcfg/conf/server/source/lcfg-tutorial

Or directly edit the lcfg-tutorial source profile to add:

!file.variables   mADD(port)
file.v_port       222

This adds a port tag to the file.variables tag list. The value for the tag is set to 222.

Again this shows the power of LCFG to deal with diversity, it would be easy to share this configuration across many machines using a header file. If a particular service needs to run on a non-standard port it has become a simple task of changing a single resource.

One issue here is that if the daemon is already running and the configuration changes there is no change to the running service. At this point we hit another limitation of the file component, the lack of support for fully managing the service. When the configuration changes it does not restart/reload the service and it does not support stopping and starting the service when required. There is support for simple actions to be triggered on file change (see the lcfg-file(8) man page) but they are not intended for fully managing a service.

Example 7 - Using a Component

There are several disadvantages to managing lots of configuration files with the file component. All the information for the files is in a single namespace so it can become difficult to see what is going on using tools like qxprof. It's also possible to get variable tags confused between different intended purposes. Most importantly using the file component breaks the conceptual model (profile/components/resources) that LCFG uses to describe the desired state of a system. It is much better for something like the SSH service to use a separate component. That knows how to configure the daemon and also, importantly, how to ensure the configuration is valid before restarting the daemon when necessary.

This is available in source/example7, either copy that file to overwrite your lcfg-tutorial profile (in /var/lib/lcfg/conf/server/source/) like:

cp /usr/share/lcfg/tutorial/examples/focal/source/example7 /var/lib/lcfg/conf/server/source/lcfg-tutorial

Or directly edit the lcfg-tutorial source profile to remove all the file component config and add:

/* Include default resources for the openssh LCFG component */
#include <lcfg/defaults/openssh.h>

/* Use an non-standard port */


This will enable the openssh component to take over the management of the server-specific /etc/ssh/sshd_config file along with the client-specific /etc/ssh/ssh_config config file.

The openssh component header is included in a slightly unusual way via defaults rather than options, in the fully-managed mode this component is included as standard and thus there is normally no need for an options header.

Note that the port is set using a macro, these are a convenient way of hiding the details of the resource manipulation which can help to make the headers much easier to read. There is a similar LCFG_OPENSSH_SSHC_OPT macro for client options.

Again, when you first add this to your source profile nothing will happen. You will need to install the component package and then enable/start the service:

apt update
apt install lcfg-openssh

You will be prompted to tell dpkg what you want to do with the existing config files, you should select the "keep the local version currently installed" option since you just generated your desired configuration!

systemctl enable lcfg-openssh
systemctl start lcfg-openssh

Check the status of your component and the ssh daemon:

systemctl status lcfg-openssh
systemctl status ssh

You can also verify that the daemon is listening on your alternative port with a tool like lsof:

lsof | grep sshd.*LISTEN

The output should contain something like:

sshd      18731                            root    3u     IPv4              67513      0t0        TCP *:222 (LISTEN)
sshd      18731                            root    4u     IPv6              67524      0t0        TCP *:222 (LISTEN)

Examine the resources for the openssh component using qxprof and take a look at the contents of /etc/ssh/sshd_config, as the openssh component has various default configuration that will be applied automatically, you should see something like:

# This file is autogenerated by the LCFG configuration engine.
# Please do not edit directly.

AcceptEnv LANG LC_*
ChallengeResponseAuthentication no
PrintMotd no
Subsystem sftp /usr/lib/openssh/sftp-server
UsePAM yes
X11Forwarding yes
UseDNS yes
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
Port 222
# End

Aside: One useful feature of generating configuration files from templates using an LCFG component is that it keeps a backup of the most recent previous configuration in a file with a ~ (tilde) prefix, e.g. /etc/ssh/sshd_config~. This makes it easy to see the differences when you change values for LCFG resources.

Take a look at the sshd_config.tt template which is used to generate that file (in the template directory /usr/share/lcfg/conf/openssh), note how this takes a fairly simple approach to managing resources. This makes it very flexible and extensible but has the downside that there is no validation of resource values, for example the LCFG server would not complain if you set the Port value to a string like foobar. There is some protection against invalid configuration since the openssh component will check the validity of the generated configuration before attempting to restart the daemon.

Topic revision: r3 - 2021-03-29 - squinney
This site is powered by the TWiki collaboration platform Powered by PerlCopyright © 2008-2021 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback