CFEngine build modules are great for quickly integrating 3rd party policy into your policy set. Module input (not to be confused with inputs
in body common control
or body file control
which are the list of policy files to load) allows you to define values that apply for a particular module as it’s integrated into your policy set.
Let’s take a look at a case of extending a module to support input.
Extending the module to support input
The lynis
module (https://build.cfengine.com/modules/lynis/), as of version 3.1.1
provides some variables that can be used to configure the version to be installed, and the hash of that versions archive. Each of those variables support overriding from Augments. The module is hard-coded to download the specified version directly from CISOfy (https://downloads.cisofy.com/lynis/lynis-$(version).tar.gz
). These are all great candidates to expose as module input, allowing users to specify a version, hash, and url to download from, let’s take a look at what is needed to add support.
First, the tar_url
variable needs to be instrumented to allow for the value in policy to be overridden from Augments.
"tar_url" string => "https://downloads.cisofy.com/lynis/lynis-$(version).tar.gz";
To do that we can adjust the policy to define tar_url
only if it’s not already defined (which is the case if the value is defined via Augments, prior to policy evaluation).
"tar_url"
string => "https://downloads.cisofy.com/lynis/lynis-$(version).tar.gz",
if => not( isvariable( "tar_url" ) );
Next, we can also allow hash_type
which defaults to sha256
to be overridden via augments.
"hash_type"
string => "sha256",
if => not( isvariable( "hash_type" ) );
With these two simple changes the policy is ready and we can look to instrument the cfbs.json
file with module input.
You can find the CFEngine Build JSON file format here in JSON.md of the cfbs repository. Checkout the section on Modules with input.
In summary, module input is defined as an array of objects under the input
key for the module.
Here is the specification that covers exposing the version of lynis, the url to retrieve the archive from, the archive hash, and archive hash type with default values that match the policy defaults.
"input": [
{
"type": "string",
"namespace": "lynis",
"bundle": "globals",
"variable": "version",
"label": "Lynis version",
"question": "Where should clients download lynis from (https)",
"default": "3.1.1"
},
{
"type": "string",
"namespace": "lynis",
"bundle": "globals",
"variable": "tar_url",
"label": "Tarball url",
"question": "Where should clients download lynis from (http/https)",
"default": "https://downloads.cisofy.com/lynis/lynis-$(version).tar.gz",
"comment": "Some may want to self host the tarball within their own infrastructure. This provides an easy way to do that."
},
{
"type": "string",
"namespace": "lynis",
"bundle": "globals",
"variable": "archive_hash",
"label": "Hash of the tarball",
"question": "What is the hash of the tarball?",
"default": "d72f4ee7325816bb8dbfcf31eb104207b9fe58a2493c2a875373746a71284cc3"
},
{
"type": "string",
"namespace": "lynis",
"bundle": "globals",
"variable": "hash_type",
"label": "Hash type to verify",
"question": "What hashing algorithm should be used to verify the Lynis script?",
"default": "sha256"
}
]
We also need to add input
to the build steps:
"steps": [
"copy policy/main.cf services/lynis/main.cf",
"json cfbs/def.json def.json",
"input ./input.json def.json"
],
Next we can take a look at the effect of adding support for module input.
Reviewing the effects of module input
Adding the module with this input via cfbs
on the command line results in a session that looks like this:
$ cfbs add lynis
Added module: lynis
The added module 'lynis' accepts user input. Do you want to add it now? [yes/y/NO/n] y
Collecting input for module 'lynis'
What version of Lynis should be used? [3.1.1]
Where should clients download lynis from (http/https) [https://downloads.cisofy.com/lynis/lynis-$(version).tar.gz]:
What is the hash of the tarball? [d72f4ee7325816bb8dbfcf31eb104207b9fe58a2493c2a875373746a71284cc3]
What hashing algorithm should be used to verify the Lynis script? [sha256]
The default commit message is:
Added module 'lynis'
- Added input for module 'lynis'
Edit it? [yes/y/NO/n]
Committing using git:
[main 85dcb1d] Added module 'lynis'
2 files changed, 97 insertions(+)
create mode 100644 lynis/input.json
We could of course override the module input defaults:
$ cfbs add lynis
Added module: lynis
The added module 'lynis' accepts user input. Do you want to add it now? [yes/y/NO/n] y
Collecting input for module 'lynis'
What version of Lynis should be used? [3.1.1] 3.1.0
Where should clients download lynis from (http/https) [https://downloads.cisofy.com/lynis/lynis-$(version).tar.gz]:
What is the hash of the tarball? [d72f4ee7325816bb8dbfcf31eb104207b9fe58a2493c2a875373746a71284cc3] ca192ac67411b07ec8421d579b1f16c038299ff727a53d739403b729817bc2e7
What hashing algorithm should be used to verify the Lynis script? [sha256]
The default commit message is:
Added module 'lynis'
- Added input for module 'lynis'
Edit it? [yes/y/NO/n]
Committing using git:
[main 331b23d] Added module 'lynis'
2 files changed, 97 insertions(+)
create mode 100644 lynis/input.json
For Enterprise users, modules installed from the build index input can be specified from within Mission Portal.
Running the policy, we can see that the module input takes effect, here causing the 3.1.0 package to be downloaded, installed and run:
[root@hub ~]# cf-agent -KI
info: Created directory '/opt/lynis/lynis-3.1.0/.', mode 0700
info: Executing 'no timeout' ... '/usr/bin/curl --silent https://downloads.cisofy.com/lynis/lynis-3.1.0.tar.gz -L --output /opt/lynis/lynis-3.1.0.tar.gz'
info: Completed execution of '/usr/bin/curl --silent https://downloads.cisofy.com/lynis/lynis-3.1.0.tar.gz -L --output /opt/lynis/lynis-3.1.0.tar.gz'
info: Executing 'no timeout' ... '/bin/tar -zxf /opt/lynis/lynis-3.1.0.tar.gz -C /opt/lynis/lynis-3.1.0 --strip-components=1'
info: Completed execution of '/bin/tar -zxf /opt/lynis/lynis-3.1.0.tar.gz -C /opt/lynis/lynis-3.1.0 --strip-components=1'
info: Executing 'no timeout' ... '/opt/lynis/lynis-3.1.0/lynis audit system --quiet --auditor 'CFEngine cf-agent''
notice: Q: "....1.0/lynis audi": /opt/lynis/lynis-3.1.0/include/tests_mac_frameworks: line 161: permissive: command not found
Q: "....1.0/lynis audi": /opt/lynis/lynis-3.1.0/include/tests_mac_frameworks: line 162: permissive: command not found
info: Last 2 quoted lines were generated by promiser '/opt/lynis/lynis-3.1.0/lynis audit system --quiet --auditor 'CFEngine cf-agent''
info: Completed execution of '/opt/lynis/lynis-3.1.0/lynis audit system --quiet --auditor 'CFEngine cf-agent''
Happy Friday! 🎉