0

In my cf-serverd's promises.cf I have a bundle like

bundle server host_rules(key, host) {
    access:
        "/srv/cfengine3/$(host)"
        admit_keys      => { "$(key)" };
}

I tried to instanciate it with

body common control {
        bundlesequence =>
        {
        generic_rules,
        host_rules("MD5=362c5fcf568b492f78ae392229299c05", "foo.example.com"),
        };
}

But (with cfengine-3.8.1) this does not seem to have an effect. E.g. cf-serverd -v reports only the access rules in the generic_rules bundle and an access to foo.example.com's files is refused.

generic_rules (which is a simple bundle server generic_rules { ... } bundle) seems to be evaluated when not listed the common bundlesequence.

How can I expand the host_rules bundle in the cf-serverd setup?

EDIT:

I intent to give access to some directories only to a corresponding host which is identified by its key. I know that it is possible to use $(connection.key) in the pathname but dislike it because

  • it is unreadable (having dozens of directories with meaningless MD5=... names makes it difficulty to find the directory belonging to 'foo.example.com')

  • it creates trouble when client key changes (e.g. because it was compromised or because host will be reinstalled). 'git' (which is used to organize my cfengine rules) does not support renaming of files/directories and I would lose history of changes with 'git mv'.

ensc
  • 6,704
  • 14
  • 22

4 Answers4

1

For reference: https://groups.google.com/d/msg/help-cfengine/ba5i_1UXPrU/xaWciJoIDQAJ

bundle server my_host_access_rules
{
  vars:
    # You can build a map of hostname to keys.
    # You might prefer to do this in an external data file formated as
JSON and
    # use readjson to read it in.
    #
    # {
    #   "hub":     "SHA=e...",
    #   "host001": "SHA=b..."
    # }

    "name_to_key[hub]" string =>
"SHA=ee29780b3c86d486699f97e30c5924431475b1b06e02c2724dd925c1524afef6";
    "hosts" slist => getindices( name_to_key );

  access:
    # Grant access to the directory named for the currently iterated
host to the public key sha for that host.
    "/srv/cfengine3/$(hosts)/."
      admit_keys => { "$(name_to_key[$(hosts)])" };
} 

I tested this on a pre-release build of 3.7.3 and I didn't need to have an empty hostname.

Nick Anderson
  • 316
  • 1
  • 4
  • the existence of an (at least) empty `admit_hostnames` is interesting for the `shortcut` case with `$(connection.hostname)` being part of the hostname. I have tested it with 3.8.1 only, not with 3.7.x – ensc Mar 22 '16 at 17:23
  • 1
    I would be wary using shortcut expanding any non connection vars that you expect to differ between connecting agents for the given path. – Nick Anderson Mar 22 '16 at 17:48
0

For reference: https://groups.google.com/forum/#!topic/help-cfengine/ba5i_1UXPrU

The connection variables are expanded by cf-serverd when clients connect. In the case of connection.hostname, the variable expands to the hostname of the connecting agent as determined by a reverse DNS lookup from cf-serverd. So you need to make sure that you have proper reverse dns resolution in order to use that. If instead of organizing the files by hostname, you organized them by key sha you should be able to allow each host access to its own directory using something like the following:

  bundle server my_special_access_rules
  {
    access:
        # /srv/cfengine3/MD5=0a9082478b1a1466f6e56fd5e48db8c4/directory full of files
        "/srv/cfengine3/$(connnection.key)"
          shortcut => "host_cfinput",
          admit_keys => { $(connetion.key) };
  }

And then in an agent bundle you can do this:

  bundle agent have_a_copy_of_my_files
  {
    files:
        # Using the shortcut
        "/tmp/myfiles/."
          copy_from => remote_dcp("host_cfinput", $(sys.policy_hub)),
          depth_search => recurse(inf);

        # Without using the shortcut
        "/tmp/another_myfiles/."
          copy_from => remote_dcp("/srv/cfengine3/$(sys.key_digest)/.", $(sys.policy_hub)),
          depth_search => recurse(inf);
  }

Now you can have a directory for each host in /srv/cfengine3/ named for the public key sha of the host. Each host is only allowed to access its own directory since you have mapped the directory to the admit_keys in a 1:1 relationship.

Nick Anderson
  • 316
  • 1
  • 4
  • thanks for this idea but I dislike to have the key in the pathname. I updated my question with details. – ensc Mar 22 '16 at 16:48
0

As it has been turned out that cf-serverd does not support such bundles, I am tending to implement this by iterating over lists:

bundle server host_list {
    vars:
        "keymap" data => parsejson('
        {
        "foo.example.com" : ["MD5=362c5fcf568b492f78ae392229299c05"],
        }');

        "hosts" slist   => maparray("$(this.k)", keymap);

    access:
        "/srv/cfengine3/$(hosts)"
        admit_keys      => { $(keymap[${hosts}]) };

        "/srv/cfengine3/KEYS/$(hosts)"
        admit_keys      => { $(keymap[${hosts}]) };
}

Shortcuts can be defined by

        "/srv/cfengine3/$(connection.hostname)"
        admit_hostnames => { },
        shortcut        => "host_cfinput";

It seems to be important that an admit_hostnames tag is present; else $(connection.hostname) is not expanded.

ensc
  • 6,704
  • 14
  • 22
0

Try this:

bundle server host_list {
    vars:
        # Each host should only have one key
        "keymap" data => parsejson('
        {
          "foo.example.com" : "MD5=362c5fcf568b492f78ae392229299c05",
        }');

        "hosts" slist   => getindices( keymap );

    access:
        "/srv/cfengine3/$(hosts)"
        admit_keys      => { $(keymap[${hosts}]) };

        "/srv/cfengine3/KEYS/$(hosts)"
        admit_keys      => { $(keymap[${hosts}]) };
}
Nick Anderson
  • 316
  • 1
  • 4