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:
Name | Version | Codename |
---|---|---|
Debian GNU/Linux | 11 | Bullseye |
Debian GNU/Linux | 12 | Bookworm |
Ubuntu | 22.04 | Jammy |
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.
Name | Description | Mandatory | Default |
---|---|---|---|
PULLCONF_LISTEN_ON | The socket address which the server should bind to. | yes | 127.0.0.1:443 |
PULLCONF_TLS_CERTIFICATE | Path to a TLS certificate file in PEM format. | yes | /etc/pullconfd/tls/server.crt |
PULLCONF_TLS_PRIVATE_KEY | Path to the corresponding private key in PEM format. | yes | /etc/pullconfd/tls/server.key |
PULLCONF_RESOURCE_DIR | Directory 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_DIR | Directory 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_LOG | This variable is read by the underlying logging library. Check their documentation for a complete overview of valid values. | no | info |
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.
Name | Description | Mandatory | Default |
---|---|---|---|
PULLCONF_SERVER | The socket address of the pullconfd server that pullconf should connect to, e.g. pullconf.local | yes | |
PULLCONF_API_KEY | The 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 32 | yes | |
PULLCONF_CA_DIR | A 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_LOG | This variable is read by the underlying logging library. Check their documentation for a complete overview of valid values. | no | info |
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 ofgit
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
andcom
-
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:
Name | Value | Example |
---|---|---|
hostname | The 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:
Name | Description | Mandatory | Default |
---|---|---|---|
type | A string that determines how to parse this resource. Must match one of the supported resource type identifiers. See below for valid values. | yes | |
parameters | A hash of resource-specific parameters. | yes | |
requires | An 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
Name | Type | Description | Mandatory | Default |
---|---|---|---|---|
ensure | string | Determines the desired state of the resource. One of present , absent or purged 1. | yes | present |
name | string | Primary parameter: Name of the package. | yes | |
version | string | The 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 |
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
Name | Type | Description | Mandatory | Default |
---|---|---|---|---|
ensure | string | Determines the desired state of the resource. One of present or absent . | yes | present |
name | string | Primary parameter: Name of the preference. The name will also be used as file name. | yes | |
order | string | A 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 | |
explanation | string | The value of the Explanation field as described in the man pages. | no | |
package | string | The value of the Package field as described in the man pages. | yes | |
pin | string | The value of the Pin field as described in the man pages. | yes | |
pin_priority | string | The 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
Name | Type | Description | Mandatory | Default |
---|---|---|---|---|
ensure | string | Determines the desired state of the resource. One of present or absent . | yes | present |
name | string | Primary 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 | |
schedule | string | A schedule expression that indicates when cron should execute the job. | yes | |
user | string | The name of the user that the command should be run as. | yes | |
command | string | The command to execute. | yes | |
environment | array | Environment variables that the process run by cron should inherhit. | no |
The environment
array must contain hashes with the following keys:
Name | Type | Description | Mandatory | Default |
---|---|---|---|---|
name | string | The name of the environment variable. | yes | |
value | string | The 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
Name | Type | Description | Mandatory | Default |
---|---|---|---|---|
ensure | string | Determines the desired state of the resource. One of present or absent . | yes | present |
path | string | Primary parameter: An absolute filesystem path. | yes | |
owner | string | The name of the user who owns the directory. | yes | root |
group | string | The name of the group who owns the directory. | no | |
purge | string | Determines 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 . | no | false |
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
Name | Type | Description | Mandatory | Default |
---|---|---|---|---|
ensure | string | Determines the desired state of the resource. One of present or absent . | yes | present |
path | string | Primary parameter: An absolute filesystem path. | yes | |
mode | string | The file permission mode in octal notation. | yes | 644 |
owner | string | The name of the user who owns the file. | yes | root |
group | string | The name of the group who owns the file. | no | |
content | string | The content to be written as-is to the file. Mutually exclusive with source . | no | |
source | string | An 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
Name | Type | Description | Mandatory | Default |
---|---|---|---|---|
ensure | string | Determines the desired state of the resource. One of present or absent . | yes | present |
name | string | Primary parameter: The group name. | yes | |
system | string | Determines if the group is a system group. One of true or false . | yes | false |
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
Name | Type | Description | Mandatory | Default |
---|---|---|---|---|
ensure | string | Determines the desired state of the resource. One of present or absent . | yes | present |
ip_address | string | Primary parameter: The IP address for this entry. Both IPv4 and IPv6 addresses are supported. | yes | |
hostname | string | The canonical hostname associated with the IP address. | yes | |
aliases | array | A 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
Name | Type | Description | Mandatory | Default |
---|---|---|---|---|
ensure | string | Determines the desired state of the resource. One of present or absent . | yes | present |
nameservers | array | A list of IP addresses that each correspond to a name server. Array items must be strings. | no | |
search | array | A list of domain names for hostname lookup. Array items must be strings. | no | |
sortlist | array | A 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 | |
options | array | A 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 15timeout:x
where x is a number between 0 and 30attempts:x
where x is a number between 0 and 5rotate
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
Name | Type | Description | Mandatory | Default |
---|---|---|---|---|
ensure | string | Determines the desired state of the resource. One of present or absent . | yes | present |
path | string | Primary parameter: An absolute filesystem path. | yes | |
target | string | An 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
Name | Type | Description | Mandatory | Default |
---|---|---|---|---|
ensure | string | Determines the desired state of the resource. One of present or absent . | yes | present |
name | string | Primary parameter: The user name. | yes | |
system | string | Determines if the user is a system user. One of true or false . | yes | false |
comment | string | An optional comment to add to the database entry for this user. | no | |
shell | string | The path to the login shell of this user. Note that when this parameter is omitted, platform-dependent defaults may apply. | no | |
home | string | The home directory of this user. | no | /home/<name> |
password | string | The password hash of this user. | no | ! which means "locked" |
expiry_date | string | The 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 | |
group | string | The name of the user's primary group. | no | same as name |
groups | array | A 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