Introduction

Pullconf is a configuration management system for Debian GNU/Linux and other Debian-based Linux servers. It is heavily influenced by Puppet (a popular and widely-used configuration management system). In contrast to other configuration management systems this project focuses a lot on simplicity and ease of use. Or to put it in other words: its primary goal is being boring. Ideally as boring as its uninspired name.

Pullconf uses a simple client-server architecture: Clients communicate with a central server in order to retrieve a list of resources via an HTTP API. These resources are then applied on the client to achieve a desired state, e.g. create a file at a certain location.

  • the server component is called pullonfd and runs as a daemon
  • the client component is called pullconf and is run at certain intervals to apply resources

As the name implies Pullconf follows a pull-based approach to system configuration: a client actively fetches a designated list of resources and applies it according to a certain schedule. Pullconf thereby ensures that every resource maintains its desired state, e.g. that a file has specific content and is owned by a certain user.

Resources such as file, directory or user are defined in configuration files on the server. These files follow the StrictYAML syntax.

Scripting and the development of custom modules is not supported and out of scope of this project. It focuses instead on including all kinds of resources directly into the project source, thus prioritizing performance and correctness at the cost of flexibility and development speed. However it should ultimately be possible to create simple files but also install and manage the configuration of complex software, e.g. a Prometheus server, by defining them as resources.

The following is a basic example for a client configuration file to get a sense of the way StrictYAML is used to define resources:

# /etc/pullconfd/conf.d/blechkiste.local.yaml

type: client
name: blechkiste.local
api_key: 20b5094257d70c8d126cf278510b6443d5139e86e18be1389b90a28d526c8236
groups:
  - sshd
  - postfix
  - nginx
  - hardening

variables:
  ip_address: 172.16.5.6

resources:
  - type: host
    parameters:
	  # `$pullconf::hostname` is a pre-defined variable that evaluates to `blechkiste.local`
	  hostname: $pullconf::hostname
	  ip_address: $pullconf::ip_address

  - type: host
    parameters:
	  hostname: proxy
	  ip_address: 172.16.10.5
	  aliases:
	    - proxy.local

  - type: file
    parameters:
	  path: /etc/logrotate.d/rsyslog
	  owner: root
	  group: root
	  mode: 0644
	  content: |
	    /var/log/syslog
		/var/log/mail.info
		/var/log/mail.warn
		/var/log/mail.err
		/var/log/mail.log
		/var/log/daemon.log
		/var/log/kern.log
		/var/log/auth.log
		/var/log/user.log
		/var/log/lpr.log
		/var/log/cron.log
		/var/log/debug
		/var/log/messages
		{
			rotate 4
			weekly
			missingok
			notifempty
			compress
			delaycompress
			sharedscripts
			postrotate
			/usr/lib/rsyslog/rsyslog-rotate
			endscript
		}

Use cases

As far as configuration management systems go, Pullconf's features are and will remain to be quite minimal and straightforward.

You might want to consider using it when:

  • you operate a fleet of homogeneous server systems and your needs for extensive customization are thus low.
  • you are just getting started with system configuration management and other, more powerful systems such as Ansible, Puppet or Chef may be overkill.
  • all the resource types that you require are covered by Pullconf.
  • you do not care so much about DRY ("don't repeat yourself") and value having your client configuration in a comparatively flat structure, instead of having a multi-layered hierarchy and complex rules of inheritance.
  • you can live without a DSL (domain-specific language) that would enable you to conditionally include or exclude resources or resource parameters.
  • you want to turn your pet systems to cattle (to some extent), because it just happens that this is what configuration management systems are for.

Concepts

StrictYAML

Pullconf uses StrictYAML as configuration format. Pullconf validates resources extensively to ensure that erroneous user input is noticed early and minimize the chance that a client applies syntactically or semantically wrong configuration.

For example Pullconf ensures that an IP address provided to a host resource is indeed a valid IP address.

For this reason YAML literals in configuration files might as well all be interpreted as strings before being further scrutinized by pullconfd and parsed to a more specific, internal type. Among other things StrictYAML does exactly that.

The YAML parser is only concerned with three types of nodes:

  • hashes/maps
  • arrays
  • string literals

Reducing the YAML feature set in that way has the added side effect of making Pullconf configuration files more readable than other configuration formats would be able to.

Server component

The Pullconf server (pullconfd) is a simple server application that parses resources defined in StrictYAML configuration files and exposes them via an HTTP API. Clients (pullconf) use this API to request their designated list of resources via HTTP. All resources remain in memory until the server is restarted or reloaded.

The server also validates configuration extensively and fails if some part of the configuration is erroneous or ambiguous. While not possible in every single case, this approach should prevent any faulty configuration making its way to the client.

When a client requests its resource list it does so using its hostname and an API key. Unless the server is able to tie the provided API key to the list of resources the client is requesting, the request it will be rejected. How a client's hostname and their API key are tied to each other will be further explained in the sections below.

Client component

Pullconf clients (pullconf) request their designated list of resources from pullconfd and apply it. Authentication is implemented via API keys and hostnames. When a client's hostname (output from $ hostname --fqdn) is my.example.domain it fetches its resource list from HTTP /api/clients/my.example.domain/resources. A client API key is authorized for this single endpoint and is otherwise rejected to prevent a client from requesting another client's resources.

The resource list is applied in the following way: Every resource contains relationship data. Dependencies are one type of relationship that is common to all resource types. If a resource does not depend on other resources or its dependencies have already been applied, it will be applied in this instant. Otherwise it will be appended to the end of a queue and re-tried after the remaining resources have been applied. The client iterates over the resource queue until every resource has been applied.

Resources

Resources are the main building blocks for configuring a client system. There are generic types such as file, directory or symlink. On the other hand there are also very specific resource types as such as host that serve a single purpose, in this case maintaining a line in /etc/hosts.

While generic types could be used to configure most software and components, using specific types (where applicable) enables additional validation that is specific to the domain at hand, e.g. to ensure that entries in /etc/hosts are valid and only certain non-default entries are managed.

Pullconf tries to infer dependencies between configured resources. For example every host resource depends on the target file /etc/hosts. If this file does not exist the resource cannot be applied. If an administrator chose to also manage this file explicitly via the file resource type, the former will depend on the latter and both resources will be applied in order.

Similarly a directory resource depends on other directory resources if those happen to be ancestors to this directory, e.g. /my/absolute/path depends on /my/absolute if both happen to be managed resources.

Groups

As previously explained a client's resource list is defined in a StrictYAML file on the server. The file may contain an optional key that can be used to assign groups to a client. Groups are also StrictYAML files stored on the server that (just as client configuration files) include resources. Groups are a place where common resources are defined that apply to multiple clients. For example the sshd configuration of a client fleet could be defined in a group since this might very well be the same on every system.

When the server is (re)started it reads resources from every group that a client is a member of and evaluates them in the context of this client. Resources that are already defined in the client take precedence over those defined in a group when they identify the same resource. For example when a file resource managing a file at /my/elaborate/path is defined in both the client and the group configuration file, the former takes precedence and the latter will be ignored.

While a client's resources take precedence over those defined in groups, there is no hierarchy on the group level. As such there are a total two configuration levels, the client level on top and all the group level below it. This structure invites you to compose your client's configuration from a set of groups and leave the client configuration file for the specific stuff, while also avoiding complex inheritance rules that might lead to errors.

Compatibility

Both the server and client components (pullconfd and pullconf) have been tried and tested on the following Debian and Debian-based Linux distributions:

NameVersionCodename
Debian GNU/Linux11Bullseye
Debian GNU/Linux12Bookworm
Ubuntu22.04Jammy

While Pullconf is currently limited to Debian-based Linux distributions it may become available for other platforms (e.g. RedHat Linux Enterprise Server) in the future.

Installation

The following sections provide installation and configuration instructions for the server and client component.

Server

The following steps guide you on how to install and configure the Pullconf server component pullconfd.

Download the .deb package from GitHub:

wget https://github.com/puetzp/pullconf/releases/download/v0.2.0/pullconfd_0.2.0-1_amd64.deb

Or: Install Rust, download the source code and build the package yourself:

cargo install cargo-deb
cargo deb -p pullconfd

Install the package:

sudo dpkg -i pullconfd_0.2.0_amd64.deb

The installation script sets up a systemd service unit and a configuration and data directory. Check the unit's status:

sudo systemctl status pullconfd.service

If this is your first installation the unit will likely be in the "failed" state, because some mandatory configuration parameters may need to be set up, such as a path to a valid TLS certificate and corresponding private key. Refer to the log at /var/log/pullconfd/pullconfd.log to see what else might be missing to start the unit.

pullconfd is configured via environment variables. As you can see in the systemd unit file the unit reads environment variables from /etc/pullconfd/environment (the required format is documented here. Refer to the following table for all available parameters.

NameDescriptionMandatoryDefault
PULLCONF_LISTEN_ONThe socket address which the server should bind to.yes127.0.0.1:443
PULLCONF_TLS_CERTIFICATEPath to a TLS certificate file in PEM format.yes/etc/pullconfd/tls/server.crt
PULLCONF_TLS_PRIVATE_KEYPath to the corresponding private key in PEM format.yes/etc/pullconfd/tls/server.key
PULLCONF_RESOURCE_DIRDirectory containing StrictYAML files that define clients, groups, and their resources. Only files ending with .yaml or .yml will be parsed. Subdirectories may be nested up to ten levels.yes/etc/pullconfd/conf.d
PULLCONF_ASSET_DIRDirectory containing static file assets. This directory is served by the web server to enable clients to download file contents. Subdirectories may be arbitrarily nested.yes/etc/pullconfd/assets
RUST_LOGThis variable is read by the underlying logging library. Check their documentation for a complete overview of valid values.noinfo

After adding or changing environment variables you need to restart the unit:

sudo systemctl restart pullconfd.service

Systemd will then re-apply the settings from the environment file. Whenever environment variables are changed the unit must be restarted. However when files in $PULLCONF_RESOURCE_DIR change a reload will suffice to re-read StrictYAML files from this directory:

sudo systemctl reload pullconfd.service

Note that if the changed configuration cannot be successfully validated, the server will continue to operate with the old configuration.

Client

The following steps guide you on how to install and configure the Pullconf client component pullconf on a client system.

Download the .deb package from GitHub:

wget https://github.com/puetzp/pullconf/releases/download/v0.2.0/pullconf_0.2.0-1_amd64.deb

Or: Install Rust, download the source code and build the package yourself:

cargo install cargo-deb
cargo deb -p pullconf

Install the package:

sudo dpkg -i pullconf_0.2.0_amd64.deb

The installation script sets up a systemd service unit (pullconf.service), a timer unit (pullconf.timer) and a data directory. Check the service unit status:

sudo systemctl status pullconf.service

As you may notice the unit is not enabled by the installation script, because it lacks an [Install] section. It is a static service unit that is activated by a scheduler and exits after resources have been applied. The timer unit from the package is used to execute the pullconf.service unit regularly. By default it is configured to trigger the service unit every five minutes.

Optional: Take a look at the timer unit:

sudo systemctl cat pullconf.timer

Optional: Adjust the OnCalendar expression or other settings by creating an override file:

sudo systemctl edit pullconf.timer

Optional: If you prefer a different scheduling method, disable the timer unit and configure the scheduler of your choice:

sudo systemctl disable pullconf.timer

If this is your first installation the service unit (pullconf.service) will likely be in the "failed" state after being triggered for the first time by the scheduler, because some mandatory configuration parameters need to be set up. Refer to the log at /var/log/pullconf/pullconf.log to see what might be missing to successfully run the program.

As with the server component pullconf is configured via environment variables. As you can see in the systemd unit file the unit reads environment variables from /etc/pullconf/environment (the required format is documented here. Refer to the following table for all available parameters.

NameDescriptionMandatoryDefault
PULLCONF_SERVERThe socket address of the pullconfd server that pullconf should connect to, e.g. pullconf.localyes
PULLCONF_API_KEYThe API key that is used by the client to authenticate to the server. This should be a long, random string. A suitable string can be generated by running openssl rand -base64 32yes
PULLCONF_CA_DIRA directory containing certificates in PEM format that are loaded into the HTTO client truststore. This is useful when the TLS certificate of the server is signed by a custom, internal certificate authority instead of a public one.no
RUST_LOGThis variable is read by the underlying logging library. Check their documentation for a complete overview of valid values.noinfo

Once pullconf.timer triggers pullconf.service the updated values from /etc/pullconf/environment will be used. To run the service unit out-of-schedule simply run:

sudo systemctl start pullconf.service

However unless the client is already known to the server pullconf.service will likely fail again. That is because pullconf tries to authenticate to pullconfd with a hostname and its API key. Both are still unknown to pullconfd as long as no client configuration file exists on the server side. Proceed to creating a client configuration file to let the client successfully fetch its list of resources from the server.

Configuration

The following sections describe how to define clients, groups and the most important thing that is common to both: resources.

Client

Once pullconf is installed on the client system a client configuration must be created on the server. This makes the client known to the server and pullconf can successfully connect to pullconfd.

Configuration files are parsed by pullconfd according to these rules:

  • only files in $PULLCONF_RESOURCE_DIR are parsed.
  • this directory may contain subdirectories that can be nested up to ten levels.
  • in this directory only files ending with a .yaml or .yml extension are parsed, other files are ignored. This enables the usage of git or other version control software.
  • files may contain one or more StrictYAML documents. Every document is expected to define either a client or a group.

For example one straightforward way to manage configuration files in a small environment is to create one file per client in a subdirectory such as $PULLCONF_RESOURCE_DIR/clients. The files in this directory could be named after the clients they define. Thus a client with the hostname blechkiste.local would be defined in the file $PULLCONF_RESOURCE_DIR/clients/blechkiste.local.

The following structure defines a client inside a StrictYAML document:

---
# Tells pullconfd to parse this document as a client.
type: client

# A hostname such as "blechkiste.local".
name: <...>

# The sha256 hash of the client API key.
api_key: <...>

# A list of groups that the client is assigned to.
groups: [...]

# A hash of variables that can be used inside resource definitions.
variables: {...}

# A list of resources.
resources: [...]
  • name:

    Client hostnames must adhere to these rules:

    • cannot be an empty string
    • cannot be more than 253 characters long
    • cannot start with a hyphen
    • cannot contain characters other than [\-a-zA-Z0-9\.]
    • cannot have segments that exceed 63 characters: a hostname my.example.com has three distinct segments, my, example and com
  • api_key:

    The API key corresponds to the sha256 hash of the environment variable $PULLCONF_API_KEY that is provided to pullconf. See client installation for more information.

  • groups:

    Optional: A list of group names. By assigning the client to a group it inherits all resources from that group. Every group names in this array must match an existing group.

  • variables:

    Optional: A hash of variables that are relevant in the context of this client. See the section on variables on details how to use variables inside resource definitions.

  • resources:

    Optional: A list of resources. Resources inherited from groups will be merged with resources listed here and then evaluated in the context of this client (using the variables above).

After defining at least the bare minimum (type, name and api_key) the file can be saved and the server reloaded:

sudo systemctl reload pullconfd.service

The next time the pullconf.service is excecuted on the client system, pullconf will successfully connect to pullconfd, since the server is now able to identify the client by means of its API key and hostname.

Multiple documents per file

As mentioned earlier the StrictYAML parser parses every YAML document inside a configuration file. Thus it is also possible to define multiple clients in a single file using documents.

---

type: client
name: blechkiste
api_key: 20b5094257d70c8d126cf278510b6443d5139e86e18be1389b90a28d526c8236
<...>

---

type: client
name: blechbuechse
api_key: e858777f14b11e7c2eb6f60032fbb6b943a54a2011b5ad43b3ad6f0c6557d2bb
<...>

---

type: client
<...>

Example

The following is a simple and short example of a client configuration file.

# $PULLCONF_RESOURCE_DIR/clients/blechkiste.local.yaml
---
type: client
name: blechkiste.local
api_key: 50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c

groups:
  - linux
  - debian
  - nginx
  - ssh

variables:
  ip_address: 192.168.1.55

resources:
  - type: host
    parameters:
	  ensure: present
	  ip_address: $pullconf::ip_address
	  hostname: $pullconf::hostname
	  aliases:
	    - webserver
	    - webserver.local

  - type: file
    parameters:
	  ensure: present
	  path: /etc/logrotate.d/apt
	  content: |
	    /var/log/apt/term.log {
		  rotate 12
		  monthly
		  compress
		  missingok
		  notifempty
        }

       /var/log/apt/history.log {
         rotate 12
         monthly
         compress
         missingok
         notifempty
       }

Group

As mentioned in the section explaining client configuration, a client can be a member of multiple groups. The client inherits the list of resources defined in a group (in addition to those defined in its own configuration). A little information on the relationship between clients and groups can be found in the concepts section.

In general groups serve the purpose of deduplicating resources that apply to multiple clients and define them in a common collection of resources. For instance when clients share the same set of entries in the /etc/hosts file, these entries could be defined inside a group using the host resource type.

Thus groups are just a list of resources under a common name that tell a user what they produce.

Just like client configuration a group is a StrictYAML document inside a file in $PULLCONF_RESOURCE_DIR or one of its subdirectories. The same restrictions that are explained at the top of the client section apply here as well.

Other than that the document must adhere to the following structure in order to be correctly parsed as a group:

---
# Tells pullconfd to parse this document as a group.
type: group

# A proper name that allows clients to refer to this group.
name: <...>

# A list of resources.
resources: [...]
  • name:

    Group names must adhere to the same rules as client hostnames as described in the client section.

  • resources:

    Optional: A list of resources. These resources will be added to the resource list of every client that is assigned this group and evaluated per-client (using the client's variables if any).

After the group configuration is created and every time it is modified a reload of pullconfd is required to read and re-evaluate the configuration.

sudo systemctl reload pullconfd.service

Example

The following is a simple and short example of a group configuration file.

---
type: group
name: localdomain

resources:
  - type: host
    parameters:
	  ensure: present
	  ip_address: 192.168.1.55
	  hostname: some-webserver
	  aliases:
	    - some-webserver.local

  - type: file
    parameters:
	  ensure: present
	  path: /etc/logrotate.d/apt
	  source: /common/logrotate.d/apt

Variables

Variables are defined within the variables hash in a client configuration. Every resource has parameters (see resources). Every parameter value from the parameters hash can be substituted with a variable.

Variables can be used in resource definitions by appending the prefix $pullconf:: to the variable name. For instance if a client defined a variable sshd_listen: 172.16.10.5, a user can use this variable inside a resource definition by refering to it as $pullconf::sshd_listen.

Since clients inherit the resources from groups that they are assigned to, effectively merging them with their own list of resources, variable substitution applies to those resources as well. This allows a user to define a commonly used resource inside a group, but let it resolve differently based on the variables that are defined in each client:

---

type: client
name: blechkiste
api_key: <...>

groups:
  - common

variables:
  ip_address: 172.16.10.5

---

type: client
name: blechbuechse
api_key: <...>

groups:
  - common

variables:
  ip_address: 172.16.10.10

---

type: group
name: common

resources:
  - type: host
    parameters:
	  ensure: present
	  ip_address: $pullconf::ip_address
	  hostname: $pullconf::hostname

Variables must resolve to the same type that a resource expects as if no variable substitution took place.

Using the example from above, if $pullconf::ip_address in either client declared an array instead of a string literal, parsing the host resource type in the context of that client would result in an error, since host expects a string literal for the ip_address parameter.

Also Pullconf fails to validate the configuration if a client is assigned to a group that contains resource definitions with variables that are not available in the context of this client.

Also note that variables can be nested up to a certain level. This allows users to use variables inside variables:

---

type: client
name: blechkiste
api_key: <...>

variables:
  ip_address: 172.16.10.5
  alias: webserver
  another_alias: webserver.local
  aliases:
    - web
    - $pullconf::alias
	- $pullconf::another_alias

resources:
  - type: host
    parameters:
	  ensure: present
	  ip_address: $pullconf::ip_address
	  hostname: $pullconf::hostname
	  aliases: $pullconf::aliases

Reserved variables

The following variables are reserved and can be used in resource definitions and other variables without having to declare them first:

NameValueExample
hostnameThe hostname of the client.my.example.com

Limitations

It is currently not possible to template values using variables. Variables can only be used to substitute the whole value of a given parameter. Partial substitution is not supported.

For example given a variable myvar with the string value xyz, the string abc$pullconf::myvar would not even be detected as a variable by pullconfd, much less substituted to abcxyz.

Dependencies

Dependencies between resources can be implicit or explicit.

  • implicit dependencies between resources are established by pullconfd itself according to certain internal rules. For instance, a directory resource depends implicitly on other directory resources if they happen to be a parent node to this directory within the filesystem.

    There is a section in each resource documentation section that describes the kind of implicit dependency relationships a resource establishes with other resources. Implicit dependencies are established without specific configuration by the user.

  • explicit dependencies go beyond implicit dependencies in cases where implicit dependencies do not suffice and pullconfd cannot infer a relationship between two resources.

    Explicit dependencies are configured via the requires array that is common to all resource types (see resources).

Explicit dependencies are validated with additional care to avoid dependency loops. Explicit dependencies may also produce other errors during validation if a dependency between two resources cannot be established in a logical sense.

For example a directory resource at /my/example cannot depend on another directory resource at /my/example/further/down, because the former must be processed before the latter.

Within the requires array other resources are usually referred to by their type (e.g. file) and their primary parameter.

However not every resource has a primary parameter (e.g. resolv.conf), because some resources can only appear once within the entire resource list of a client. However most resources are primarily identified by some parameter, e.g. directory is primarily identified by its path parameter.

The primary parameter of a resource is marked in each resource's documentation section.

Example

This example resource contains multiple explicit dependencies.

<...>

resources:
  - type: directory
    parameters:
	  path: /my/elaborate/example
    requires:
	  - type: file
	    path: /totally/different/location
	  - type: resolv.conf
	  - type: host
	    ip_address: 127.0.0.1

<...>

Resources

Resources are the main building blocks of your configuration. They define which files, directories etc. are created and managed on the client.

Resources can be defined inside the resources array in clients and groups.

Every resource is structured the same at the root and contains the following keys:

NameDescriptionMandatoryDefault
typeA string that determines how to parse this resource. Must match one of the supported resource type identifiers. See below for valid values.yes
parametersA hash of resource-specific parameters.yes
requiresAn array of dependencies between resources. See dependencies.no[]

Valid values for type are:

  • apt::package
  • apt::preference
  • cron::job
  • directory
  • file
  • group
  • host
  • resolv.conf
  • symlink
  • user

The keys inside parameters differ between resources, so the respective resource documentation section should be consulted to see the available resource parameters.

Also note that variables can only be used inside the parameters hash.

Example

<...>

resources:
  - type: directory
    parameters:
	  ensure: present
	  path: /path/to/directory
	  purge: true

  - type: file
    parameters:
	  ensure: present
	  path: /path/to/directory/somefile

  - type: file
    parameters:
	  ensure: present
	  path: /path/to/directory/otherfile
    requires:
	  - type: file
	    path: /path/to/directory/somefile
<...>

# All kinds of requirements.
resources:
  - type: directory
    parameters:
	  ensure: present
	  path: /path/to/directory
    requires:
	  - type: apt::package
	    name: some-package

      - type: apt::preference
	    name: some-preference

      - type: cron::job
	    name: some-job

      - type: directory
	    path: /some/directory

      - type: file
	    path: /some/file
	  
	  - type: group
	    name: some-group
	  
	  - type: host
	    ip_address: 172.16.0.1
	  
	  - type: resolv.conf
	  
	  - type: symlink
	    path: /some/symlink
	  
	  - type: user
	    name: some-user

apt::package

This resource manages a package via apt.

Relationship to other resources

At this point apt::package resources do not form implicit dependencies with other types of resources.

Parameters

NameTypeDescriptionMandatoryDefault
ensurestringDetermines the desired state of the resource. One of present, absent or purged1.yespresent
namestringPrimary parameter: Name of the package.yes
versionstringThe version to be installed. Stating a specific version might result in a downgrade. This parameter can be omitted to install the latest known version instead.no
1

purged means that in addition to the package being deleted (just like absent), all configuration files and directories associated with the package are deleted as well.

Examples

resources:
  - type: apt::package
    parameters:
	  name: nginx
resources:
  - type: apt::package
    parameters:
	  ensure: present
	  name: nginx
	  version: 1.18.0-6ubuntu14.4

apt::preference

This resource manages a file containing a single preference record in the directory /etc/apt/preferences.d. Files in this directory are taken into consideration by apt when it assigns priorities to different versions of packages to determine which is selected for installation. Files in this directory are parsed in alphanumeric ascending order.

For more information about apt preferences see man apt_preferences.

Relationship to other resources

This resource implicitly depends on directory and symlink resources whose path parameters are ancestors to the directory /etc/apt/preferences.d.

Parameters

NameTypeDescriptionMandatoryDefault
ensurestringDetermines the desired state of the resource. One of present or absent.yespresent
namestringPrimary parameter: Name of the preference. The name will also be used as file name.yes
orderstringA number that will be prepended to the file name to control the place in which apt parses the file. Files of lower oder will be parsed earlier.no
explanationstringThe value of the Explanation field as described in the man pages.no
packagestringThe value of the Package field as described in the man pages.yes
pinstringThe value of the Pin field as described in the man pages.yes
pin_prioritystringThe value of the Pin-Priority field as described in the man pages.yes

Examples

resources:
  - type: apt::preference
    parameters:
	  name: nginx
	  explanation: Pin nginx at this version even if it results in a downgrade.
	  package: nginx
	  pin: version 1.18.0*
	  pin_priority: 1000
resources:
  - type: apt::preference
    parameters:
      ensure: present
	  name: bookworm
	  order: 10
	  explanation: Assign a higher priority to packages from a distribution by the codename bookworm.
      package: *
      pin: release n=bookworm
      pin_priority: 900

cron::job

This resource manages a crontab file in the directory /etc/cron.d. A file created by this resource contains only a single command. Unlike user-owned crontabs, files in /etc/cron.d are parsed by cron as system-wide crontabs which may be run as any user. As such the cron::job resource also provides a user parameter.

For more information about cron and crontabs see man cron and man 5 crontab.

Relationship to other resources

This resource implicitly depends on directory and symlink resources whose path parameters are ancestors to the directory /etc/cron.d.

Parameters

NameTypeDescriptionMandatoryDefault
ensurestringDetermines the desired state of the resource. One of present or absent.yespresent
namestringPrimary parameter: Name of the cron job. The name will also be used as file name. Note that cron ignores files whose names contain dots and certain other characters. Allowed characters are: [a-zA-Z0-9_\-]yes
schedulestringA schedule expression that indicates when cron should execute the job.yes
userstringThe name of the user that the command should be run as.yes
commandstringThe command to execute.yes
environmentarrayEnvironment variables that the process run by cron should inherhit.no

The environment array must contain hashes with the following keys:

NameTypeDescriptionMandatoryDefault
namestringThe name of the environment variable.yes
valuestringThe value of the environment variable. If this parameter is omitted the variable will be set to an empty string.no

Examples

resources:
  - type: cron::job
    parameters:
	  name: some-job
	  environment:
	    - name: MAILTO
		- name: PATH
		  value: /bin:/usr/bin:/usr/local/sbin
	  schedule: @daily
	  user: root
	  command: run-me-daily.py

directory

This resource manages a directory within the filesystem hierarchy of the client.

Relationship to other resources

The value of the path parameter must be unique among all directory, file and symlink resources.

A directory implicitly depends on other directory or symlink resources whose path parameters are ancestors to the directory path. For example when the path parameter of this directory is set to /my/simple/example and there is another directory whose path is /my/simple, then the former implicitly depends on the latter.

A directory also implicitly depends on user resources whose home parameter matches the directory's path. This is because the tools creating the user already create a home directory. So in most cases the home directory does not need to be managed by a directory resource. But when it is it will be applied after the user resource and operate on the existing home directory that was created by other means.

A directory also forms a relationship with child nodes, that is directory, file and symlink resources who this directory is a parent to. A directory resource needs to keep track of managed child nodes, because if will remove unmanaged child nodes if the purge parameter is set to true.

Parameters

NameTypeDescriptionMandatoryDefault
ensurestringDetermines the desired state of the resource. One of present or absent.yespresent
pathstringPrimary parameter: An absolute filesystem path.yes
ownerstringThe name of the user who owns the directory.yesroot
groupstringThe name of the group who owns the directory.no
purgestringDetermines if unknown child nodes should be removed from the directory. Unknown directories will be removed recursively as well. However note that when this directory contains another managed directory whose purge parameter is set to false, the contents of the other directory will remain intact and will not be recursively deleted. One of true or false.nofalse

Examples

resources:
  - type: directory
    parameters:
      path: /my/simple/example
resources:
  - type: directory
    parameters:
      ensure: present
      path: /my/simple/example
	  owner: myuser
	  group: mygroup

file

This resource manages a file within the filesystem hierarchy of the client.

Relationship to other resources

The value of the path parameter must be unique among all file, directory and symlink resources.

A file implicitly depends on directory and symlink resources whose path parameters are ancestors to the file's path. For example when the path parameter of a file is set to /my/simple/path and there is a directory resource whose path is /my/simple, then the former implicitly depends on the latter.

Parameters

NameTypeDescriptionMandatoryDefault
ensurestringDetermines the desired state of the resource. One of present or absent.yespresent
pathstringPrimary parameter: An absolute filesystem path.yes
modestringThe file permission mode in octal notation.yes644
ownerstringThe name of the user who owns the file.yesroot
groupstringThe name of the group who owns the file.no
contentstringThe content to be written as-is to the file. Mutually exclusive with source.no
sourcestringAn absolute path to a file asset on the server. The remote file will be downloaded and its contents written to the file on the client. For example when this parameter is set to /my/example/file the file must exist on the server at $PULLCONF_ASSET_DIR/my/example/file in order to be downloaded successfully by the client. Mutually exclusive with content.no

Examples

resources:
  - type: file
    parameters:
      path: /my/simple/example/file
resources:
  - type: file
    parameters:
      ensure: present
      path: /my/simple/example/file
	  owner: myuser
	  group: mygroup
	  source: /some/child/path/in/the/asset/directory
resources:
  - type: file
    parameters:
      ensure: present
      path: /my/simple/example/file
	  owner: myuser
	  group: mygroup
	  content: |
	    my
		multiline
		example
		file content

group

This resource manages a user group on the client.

Relationship to other resources

A groups implicitly depends on user resources whose group parameter matches the name of this group, thereby making this group their primary group. This means that primary groups will be processed after user resources, because in this case the lifecycle of the group is left to the system: A typical Debian installation will create the primary group of a user automatically upon user creation and delete it when the user is deleted.

It is recommended not to manage the primary groups of users at all, only supplementary groups. Instead leave it to user resources and the operating system to create and delete primary groups when necessary.

Parameters

NameTypeDescriptionMandatoryDefault
ensurestringDetermines the desired state of the resource. One of present or absent.yespresent
namestringPrimary parameter: The group name.yes
systemstringDetermines if the group is a system group. One of true or false.yesfalse

Examples

resources:
  - type: group
    parameters:
      name: mygroup
resources:
  - type: group
    parameters:
	  ensure: present
      name: mygroup
	  system: true

host

This resource manages a single entry/line in the file /etc/hosts.

Relationship to other resources

Hosts (or host entries), as identified by the value of the ip_address parameter, must be unique. In other words there can only be one host entry per IP address.

If there is a file or symlink resource whose path parameter is /etc/hosts, all host resources depend on it implicitly. However it is not possible to manage the contents of the /etc/hosts file via a file resource and manage one or more host resources at the same time. The content and source parameters of the file resource must be omitted in this case to avoid conflicting resource definitions.

Parameters

NameTypeDescriptionMandatoryDefault
ensurestringDetermines the desired state of the resource. One of present or absent.yespresent
ip_addressstringPrimary parameter: The IP address for this entry. Both IPv4 and IPv6 addresses are supported.yes
hostnamestringThe canonical hostname associated with the IP address.yes
aliasesarrayA list of host aliases associated with the IP address. Array items must be strings.no

Examples

resources:
  - type: host
    parameters:
      ip_address: 172.16.0.2
	  hostname: my.example.com
resources:
  - type: host
    parameters:
      ip_address: 172.16.0.2
	  hostname: my.example.com
	  aliases:
	    - my.example
		- example

resolv.conf

This resource manages the file contents of /etc/resolv.conf, the common resolver configuration file. There may only be one resolv.conf resource per client. For this reason resolv.conf does not need a primary parameter to be uniquely identifiable.

See man resolv.conf for more information.

Relationship to other resources

If there is a file or symlink resource whose path parameter is /etc/resolv.conf, the resolv.conf resource depends on it implicitly. However there cannot be both a file resource managing the contents of /etc/resolv.conf and a resolv.conf resource. The content and source parameters of the file resource must be omitted in this case to avoid conflicting resource definitions.

Parameters

NameTypeDescriptionMandatoryDefault
ensurestringDetermines the desired state of the resource. One of present or absent.yespresent
nameserversarrayA list of IP addresses that each correspond to a name server. Array items must be strings.no
searcharrayA list of domain names for hostname lookup. Array items must be strings.no
sortlistarrayA list of IP-address-netmask pairs where the netmask is optional and separated from the IP address by a slash. Array items must be strings.no
optionsarrayA list of resolver variables. Array items must be strings. Possible values are documented below.no

Each item in options must be one of:

  • debug
  • ndots:x where x is a number between 0 and 15
  • timeout:xwhere x is a number between 0 and 30
  • attempts:x where x is a number between 0 and 5
  • rotate
  • no-check-names
  • inet6
  • edns0
  • single-request
  • single-request-reopen
  • no-tld-query
  • use-vc
  • no-reload
  • trust-ad

Examples

resources:
  - type: resolv.conf
    parameters:
      nameservers:
	    - 8.8.8.8
		- 4.4.4.4
	  search:
	    - domain.local
		- example.com
	  sortlist:
	    - 130.155.160.0/255.255.240.0
		- 130.155.0.0
	  options:
	    - ndots:2
		- timeout:5
		- inet6

symlink

This resource manages a symbolic link within the filesystem hierarchy of the client.

Relationship to other resources

The value of the path parameter must be unique among all symlink, file and directory resources.

A symlink implicitly depends on other symlinks or directory resources whose path parameters are ancestors to this symlink's path. For example when the path parameter of this symlink is set to /my/very/simple/example and there is a directory resource whose path is /my/very/simple, then the former implicitly depends on the latter.

If the target parameter of the symlink resource contains a path that matches the path parameters of a managed file or directory resource, the symlink resource depends on the latter.

Parameters

NameTypeDescriptionMandatoryDefault
ensurestringDetermines the desired state of the resource. One of present or absent.yespresent
pathstringPrimary parameter: An absolute filesystem path.yes
targetstringAn absolute filesystem path that the symlink should point to.yes

Examples

resources:
  - type: symlink
    parameters:
      path: /my/simple/example/link
	  target: /my/simple/target

user

This resource manages a user on the client.

Relationship to other resources

A user implicitly depends on group resources whose name parameter matches one of the strings in the groups array as supplementary groups must be processed first.

Parameters

NameTypeDescriptionMandatoryDefault
ensurestringDetermines the desired state of the resource. One of present or absent.yespresent
namestringPrimary parameter: The user name.yes
systemstringDetermines if the user is a system user. One of true or false.yesfalse
commentstringAn optional comment to add to the database entry for this user.no
shellstringThe path to the login shell of this user. Note that when this parameter is omitted, platform-dependent defaults may apply.no
homestringThe home directory of this user.no/home/<name>
passwordstringThe password hash of this user.no! which means "locked"
expiry_datestringThe date at which the account should expire, in the format YYYY-MM-DD. Note that when this parameter is omitted, platform-dependent defaults may apply.no
groupstringThe name of the user's primary group.nosame as name
groupsarrayA list of names of supplementary groups that the user should be a member of. Array items must be strings.no

Examples

resources:
  - type: user
    parameters:
      name: myuser
resources:
  - type: user
    parameters:
	  ensure: present
      name: myuser
	  system: true
      comment: Employee of the Year
      shell: /bin/zsh
      home: /home/myuser
      password: $6$ugth6io4j7fQHBxh$oDr51KYqju5jMr/lCsYpAouzxOINxhyZhiSRH1220TOZ8VRMxxNaGXnv.JzH/XUN9oezau7sKqrBlcdQfqmGv0
      expiry_date: 2025-12-31
      group: myuser
      groups:
	    - ssh-login
	    - team-xyz