Technique reference

A technique is described by a XML file that lists:

  • the template files
  • the sections of the technique
  • the variables that must be defined
  • the compatibility list

Files organisation

The techniques are ordered in Categories. A Category is described by a category.xml file, that defines the name and description of a category. A Category can contain other Categories, or Techniques. A Technique is versioned, and can exist in several versions. The description of a Technique is the metadata.xml file.

techniques
+--- category.xml
+--- fileConfiguration
|   +--- category.xml
|   +--- security
|   |   +--- filesPermissions
|   |   |   +--- 1.0
|   |   |   |   +--- permlist.st
|   |   |   |   +--- metadata.xml
|   |   |   |   +--- filesPermissions.st
|   |   +--- category.xml
|   |   +--- sudoCheck
|   |   |   +--- 2.0
|   |   |   |   +--- metadata.xml
|   |   |   |   +--- sudoCheck.st
|   |   |   +--- 1.0
|   |   |   |   +--- metadata.xml
|   |   |   |   +--- sudoCheck.st

metadata.xml and Techniques templates (*.st)

These files must reside in a folder with a version number. For each Technique, there can be several versions, Rudder will let you choose the version when creating a Directive.

Version number formating

The version number follows a formating "a la Debian" as described here: https://www.debian.org/doc/debian-policy/index.html#s-f-version, (without the debian_revision version)

General Rules

All the tag name in the .xml are in upper case, all the attributes are in camel case:

<SECTION name="example" component="true" componentKey="variable_name">

Details of the metadata.xml file

<TECHNIQUE id="technique_unique_id" name="human_name_of_the_technique">
  <DESCRIPTION>Description of the Technique</DESCRIPTION>
  <LONG_DESCRIPTION>Long description of the technique</LONG_DESCRIPTION>
  <DEPRECATED>Deprecation message</DEPRECATED>                <!-- Mark the Technique as deprecated, deprecation message is mandatory, Only available since Rudder 3.0 -->
  <DISPLAY>true/false</DISPLAY>                               <!-- Define if the Technique is displayed in the interface or not. Default value : true -->
  <COMPATIBLE>                                                <!-- Optional, describe the version of the OS and Agent the Technique has been tested on. Only for information purpose -->
    <OS version=">=2.5">OS Name</OS>                          <!-- Optional; OS Name and version on which the Technique has been tested -->
    <AGENT version=">=3.6">cfengine-community</AGENT>         <!-- Optional; Agent name and version on which the Technique has been tested -->
  </COMPATIBLE>
  <MULTIINSTANCE>true/false</MULTIINSTANCE>                   <!-- Optional; defines if several instances of this template with differents variables can be deployed on a node; default value: false -->
  <POLICYGENERATION>separated</POLICYGENERATION>              <!-- Optional; defines if each Directives based on this Technique will be in a separated folder; default value: false. Note, if this parameter is set, you'll have to use the RudderUniqueID special placeholder to avoid duplicate names for methods and bundles -->

  <SYSTEM>true/false</SYSTEM>                                 <!-- Optional, defines if this Technique is a system Technique (internal Rudder usage); default value: false -->
  <BUNDLES>                                                   <!-- List of the bundles that must be included in the bundlesequence -->
    <NAME>BundleName</NAME>
  </BUNDLES>
  <TMLS>                                                      <!-- List of all the templates defined by this Technique -->
   <TML name="tmlName">                                       <!-- Container for a TML (without the trailing .st -->
    <OUTPATH>relativ/path/of/file</OUTPATH>                   <!-- Optional; defines the relative path for the generated file for this template; default: techniqueName/version/tmlName.cf -->
    <INCLUDED>true/false</INCLUDED>                           <!-- Optional; defines if the template must be in the inputs list of the generated promises; default: true -->
   </TML>
  </TMLS>
  <FILES>                                                     <!-- List of files to be copied "as-is" with this Technique. StringTemplate parser is NOT used on these. -->
    <FILE name="file.txt">                                    <!-- Container for a FILE. name (mandatory) = path to the file to copy, can be relative or absolute from RUDDER_CONFIGURATION_REPOSITORY/ (see below) -->
    <FILE name="file2.txt"><OUTPATH>technique_name/newname.txt</OUTPATH></FILE>
    <FILE name="RUDDER_CONFIGURATION_REPOSITORY/directory/other/file.txt"><OUTPATH>technique_name/filename</OUTPATH></FILE>
  </FILES>
  <TRACKINGVARIABLE>                                          <!-- Defines a special system variable TRACKINGKEY that contains all the necessary information to track which Directive generated the promises -->
    <SAMESIZEAS>VariableName</SAMESIZEAS>                     <!-- Optional; defines the cardinality of this variable based on the cardinality of the VariableName -->
  </TRACKINGVARIABLE>

  <RUNHOOKS>                                                  <!-- Optionnal; defines the list of pre and post hooks for techniques with separated policy generation mode -->
    <PRE bundle="pre_hook_bundle">                            <!-- Optionnal; name of the bundle/method to run before any directive based on this technique is run -->
      <REPORT name="Component name"/>                         <!-- Component Name for the report of the hook
      <PARAMETER name="name" value="value"/>                  <!-- Optionnal; parameter to pass to the hook
    </PRE>
    <POST bundle="post_hook_bundle">                          <!-- Optionnal; name of the bundle/method to run after all the directives based on this technique are run -->
      <REPORT name="Component name"/>                         <!-- Component Name for the report of the hook
      <PARAMETER name="name" value="value"/>                  <!-- Optionnal; parameter to pass to the hook
    </POST>
  </RUNHOOKS>


  <SECTIONS>                                                  <!-- Lists all the sections of the promises -->
    <SECTION name="sectionName">                              <!-- Container of a section (see below) -->
    </SECTION>
  </SECTIONS>

</TECHNIQUE>

The <SECTION> tag

In a metadata.xml, there can be only one SECTIONS tag, that encloses one or several SECTION tags. A SECTION tag contains variables declaration and subsections. A SECTION can contains Variables definitions and SECTION.

<SECTION name="sectionName" multivalued="true/false" component="true/false" componentKey="variableName/None">

A SECTION has the following attributes:

  • name : mandatory, the name of the section
  • multivalued : optional, default false, defines if the section is repetable or not. If so, the Web Interface will display a "Add another" and "Delete" button for this section
  • component : optional, default false; defines if the section is a component, and if true, the section will appear in the reporting, with its section name
  • componentKey: optional, default None; defines the variable that is the key of the component. Note that the componentKey can only be defined if component is true
  • displayPriority: optional, default high; defines if the section is displayed by default (high) or hidden by default (low)
[Note]Note

A multivalued section can only contain variable, and cannot contain section

[Note]Note

If there are no SECTION defined with component="true", a default SECTION for reporting will be generated, named after the id of the Technique (the folder name of the Technique)

Variables definitions in the <SECTION> tags

There are three tags to create a variable:

  • SELECT1: Can select only one value out of several. If there are less than 3 possible values, displays radio buttons, otherwise a select field.
  • SELECT: Can select several values out of al the possibles. Displays checkboxes.
  • INPUT: Displays an input field (that can be tuned)
<SELECT1/SELECT/INPUT>                                                        <!-- Depend on the display and behaviour needed -->
  <NAME>variableName</NAME>
  <DESCRIPTION>variableDescription</DESCRIPTION>
  <LONGDESCRIPTION>longDescription</LONGDESCRIPTION>                          <!-- Optional, set the text in the tooltips -->
  <UNIQUEVARIABLE>true/false</UNIQUEVARIABLE>                                 <!-- Optional, default false; if true, this variable will have the same value over all the instance of this template for a given node -->
  <ITEM>                                                                      <!-- Only for SELECT and SELECT1, list of selectable values -->
    <VALUE>value</VALUE>                                                      <!-- value that will be put in the template-->
    <LABEL>humanReadableText</LABEL>                                          <!-- value displayed in the web interface -->
  </ITEM>
  <CONSTRAINT>                                                                <!-- Optional, defines some constraints on values -->
    <DEFAULT>defaultValue</DEFAULT>                                           <!-- Optional; Defines a default value -->
    <TYPE>variableType</TYPE>                                                 <!-- Optional; default string; variable type -->
    <MAYBEEMPTY>true/false</MAYBEEMPTY>                                       <!-- Optional; default false; defines if the variable is optional or not; only for the INPUT variable -->
    <REGEX error="errorMsg">regex</REGEX>                                     <!-- Optional; only for the INPUT variable; efine a regular expression the variable should match, and an optional error message -->
    <PASSWORDHASH>hashtype</PASSWORDHASH>                                     <!-- Optional; only for the password TYPE variable; define the way a password will be handled (hashed or not, hash types allowed ...) -->
  </CONSTRAINT>
</SELECT1/SELECT/INPUT>

Note: It is possible to inline LABEL and VALUE in the ITEM tag

<ITEM label="Red" value="red"/>

is equivalent to

<ITEM>
 <LABEL>Red</LABEL>
 <VALUE>red</VALUE>
</ITEM>
[Note]Note

INPUT fields are automatically escaped, meaning any quote will be written in the policies as \" ; and any backslash will be written as \\

Available types for an INPUT variable

  • string : any string is accepted (no specific displayer)
  • textarea : accept any strings, but use a textarea in place of the input text.
  • perm : display a matrix of read/write/execute by user/group/all
  • integer : only accept integers
  • datetime : display a JQuery calendar and check date format
  • boolean : display a checkbox
  • mail : only accept emails
  • ip : only accept ips. Before Rudder 3.1.14, 3.2.7 and 4.0.0, "ip" was accepting only IPv4 ip. Since these releases, it accepts both IPv4 and IPv6 format. <br />
  • ipv4 [since Rudder 3.1.14, 3.2.7, 4.0.0]: only accept IPv4 formatedt IPs
  • ipv6 [since Rudder 3.1.14, 3.2.7, 4.0.0]: only accept IPv6 formatted IPs
  • size-<unit> : (size-b, size-kb, size-mb, size-gb ou size-tb)
  • raw : the content of this field will not be escaped when written in the promises (Rudder >= 2.6)
  • password : the content of this field will be handled as a password, and thus be hidden and transformed if necessary (see "Password handling" below) (Rudder >= 2.6)

The <FILES> tag

Example:

<FILES>
<FILE name="file.txt"><OUTPATH>foo/bar/other-name.txt</OUTPATH></FILE>
<FILE name="RUDDER_CONFIGURATION_REPOSITORY/some/absolute/file.txt"><OUTPATH>foo/bar/some-name.txt</OUTPATH></FILE>
</FILES>
  • name is mandatory. It’s the path to file to copy, either relative to the technique directory (i.e, at the same level as metadata.xml) or absolute from the configuration repository directory if it starts with RUDDER_CONFIGURATION_REPOSITORY (usually /var/rudder/configuration-repository) (and yes, this forbids the use case where you want to have a sub-directory named RUDDER_CONFIGURATION_REPOSITORY under the technique directory - I’m sure one will find other way to do it if really needed :). The file will be taken from git, at the same git revision as other tehniques files.
  • OUTPATH is optional. If not specified, the file will be copied into the target node promises at the same place as other files for the technique, with the same name. If specified, you have to give a path+name, where path is relative to the directory for agent promises on the node (i.e, if you want to put the file in the technique directory, you need to use "techniqueName/new-file-name.txt")

Examples

Multivalued sections

In the "NFS Client settings" Technique, there is a multivalued section with several entries. Here is a partial extract from it, with

  • A multivalued section, named NFS mountpoint, that is multivalued and is a component. The variable reference for this component (the key) is NFS_CLIENT_LOCAL_PATH
  • One SELECT1 field, that will show two radio buttons, Mount and Unmount, with the default value to Mount
  • One INPUT field, named NFS_CLIENT_LOCAL_PATH, that is a text
 <SECTION name="NFS mountpoint" multivalued="true" component="true" componentKey="NFS_CLIENT_LOCAL_PATH">
     <SELECT1>
       <NAME>NFS_CLIENT_UMOUNT</NAME>
       <DESCRIPTION>Which operation should be done on this mountpoint</DESCRIPTION>
       <ITEM>
         <LABEL>Mount</LABEL>
         <VALUE>no</VALUE>
       </ITEM>
       <ITEM>
         <LABEL>Unmount</LABEL>
         <VALUE>yes</VALUE>
       </ITEM>
       <CONSTRAINT>
         <DEFAULT>no</DEFAULT>
       </CONSTRAINT>
     </SELECT1>
     <INPUT>
       <NAME>NFS_CLIENT_LOCAL_PATH</NAME>
       <DESCRIPTION>Local path to mount the remote on</DESCRIPTION>
     </INPUT>
  ...
 </SECTION>

Unique variable across several instance

This variable can have only one value, over all the instances of this Technique, on a node

  <SECTIONS>
      <INPUT>
        <NAME>UNIQUE</NAME>
        <DESCRIPTION>Unique variable</DESCRIPTION>
        <CONSTRAINT>
          <TYPE>string</TYPE>
        <CONSTRAINT>
        <UNIQUEVARIABLE>true</UNIQUEVARIABLE>
    </INPUT>
  </SECTIONS>

Password handling

The password type allows to show an input text field whose content will be hashed when the form is submitted so that the password is never store in clear text.

Directive Password Field

Available hash formats

For now, the password field support these hash algorithms :

  • PLAIN : that is not an hash algorithm, it just save the password in plain text, as inputed by the user.
  • MD5, SHA1, SHA256, SHA512 : uses the matching hash algorithm
  • LINUX-SHADOW-MD5, LINUX-SHADOW-SHA256, LINUX-SHADOW-SHA512 : build a string compatible with the Linux /etc/shadow format, as "specified" in http://man7.org/linux/man-pages/man3/crypt.3.html

Technique metatdata content

To configure a password, you must specify two things in the <CONSTRAINT> section of the field:

  • <TYPE>password</TYPE> : use the password type
  • <PASSWORDHASH>comma,separated,list,of,hash</PASSWORDHASH> : specify the list of hash algo from witch the user will be allowed to choose.
  • Available algorithm names are the ones from the section above (case insensitive).
  • Choices are presented in order given by the list, the first being the default one.
  • If the list contains only one algo, the drop down select if change to a phrase saying to the user that the given algo will be used.
  • The list can not be empty. Moreover, if the <MAYBEEMPTY> contraint is set to false, the "None" option is not displayed to the user.

Password field definition example

<SECTION name="Password" component="true" componentKey="USERGROUP_USER_LOGIN">
    <INPUT>
        <NAME>USERGROUP_USER_PASSWORD</NAME>
        <DESCRIPTION>Password for this account</DESCRIPTION>
        <CONSTRAINT>
            <MAYBEEMPTY>true</MAYBEEMPTY>
            <TYPE>password</TYPE>
            <PASSWORDHASH>linux-shadow-md5,linux-shadow-sha256,linux-shadow-sha512</PASSWORDHASH>
        </CONSTRAINT>
    </INPUT>
</SECTION>

Separated policy generation

In Rudder 4.3, a new mode of policy generation is introduced, that allows to mix Audit and Enforce mode for Directives based on the same Technique on a given node, and have Directives based on different version of the same Techniques. It is enabled with the entry <POLICYGENERATION>separated</POLICYGENERATION> in metadata.xml, and result on separated generated files for each Directives. One directory is generated by Directive, in the path TechniqueName/TechniqueVersion_DirectiveID, and requires the use of a placeholder, RudderUniqueID, used in bundle/method name, as well as result classes, to avoid name and classes collision at runtime.

Usage of RudderUniqueID

Here is an extract from Technique to exhibit the use of the placeholder

bundle agent sudo_parameter_edit_sudoers_RudderUniqueID(filename, entity, nopasswd, alldo, command)
{
  vars:

      "index" slist => getindices("${entity}");

    pass1::

      "command_all[${index}]" string => "ALL=(ALL) NOPASSWD:ALL",
                      ifvarclass => "(sudo_${index}_RudderUniqueID_alldo.sudo_${index}_nopasswd).(sudo_${index}_RudderUniqueID_command_notempty|sudo_${index}_RudderUniqueID_alldo)";

It is used here in the bundle name, to ensure its unicity, and it is also used in the class name.

Pre and post hooks

Some Techniques require actions to be performed only once, before and/or after all operation (for instance, ensuring that a package is installed before configuring this package). A pre and post hook mechanism has been introduced, for these uses. By convention, all pre and post hooks are located in the hooks.st file, in the System Technique common (so outside of the Technique we consider, to enforce that only one version of the hook may live in the Technique repository at a time).

Hooks have only one parameter, which is a JSON entry, in the format

{
  "parameters":
    {
       "parameterName1":"parameterValue1",
       "parameterName2":"parameterValue2",
    },
  "reports":
    [
      {"id":"DirectiveId1","mode":"enforce/audit", "technique":"techniqueName", "name":"componentName", "value":"componentValue1"},
      {"id":"DirectiveId2","mode":"enforce/audit", "technique":"techniqueName", "name":"componentName", "value":"componentValue2"},
      {"id":"DirectiveId3","mode":"enforce/audit", "technique":"techniqueName", "name":"componentName", "value":"componentValue3"},
   ]
}

The entries parameterName and parameterValue are defined by the PARAMETER tag of the section RUNHOOKS of metadata.xml, while the componentName is defined by its REPORT tag.

Known limitations

There are several known limitations at the moment, that are acknowleged, and will be solved in a "not too distant" future:

Can’t put a multivalued section in a multivalued section

It is not possible, due to limitation in the format in which the variable’s values are stored in the LDAP tree, to put multivalued sections within multivalued sections.

Can’t have several multivalued sections that are components with keys

For the moment, there is only one TRACKINGKEY, so it is not possible to have several multivalued sections that have keys.

Can’t have several sections that are components with keys in multivalued Techniques.

It is a side effect of the previous limitation.