Page MenuHomePhabricator

Rootless cookbooks/spicerack
Open, MediumPublic


Rootless cookbooks/spicerack

(This is an initial high level view, the finer implementation details will emerge when writing code and tests)

Rootless cookbooks rely on rootless Cumin, but in addition we need additional capabilities to be enabled for rootless operation: For commands executed via a remote we need to deploy the respective sudo rules and for other Spicerack modules we need dedicated access control mechanisms (see below).

By default all cookbooks are assumed to require root, but all cookbooks using the class API can opt-in to rootless operation. To declare a cookbook as rootless-compatible the cookbook needs to implement a get_permissions() function which returns the necessary capabilities. Cookbooks implementing the old module interface need to be converted to the class API.

The following is a high level description of the capabilities set (specific details will follow as part of the implementation):

  • A list of Unix groups which are permitted to run the cookbook as unprivileged users. When running a cookbook via the cookbook(1) command as an unprivileged user, only the cookbooks which are accessible by the current user's group memberships are shown. In addition get_runner() validates the group membership of the calling user and bails out if they are not present (to prevent a non-legit user to simply run a cookbook locally in the filesystem) along with a message which group membership is needed.
  • A list of target hosts (specified in Cumin syntax, so typically a list of roles) on which the cookbook can be run. This allows for clearer error messages and user feedback if a cookbook is run against a set of servers which are not yet enabled for rootless cookbooks.

To deploy the respective user permissions we can create a Puppet define sudo::cookbook which is a wrapper around sudo::group, but with an additional identifier to list the cookbook(s) which need the sudo permissions. These should be tracked by the cookbook name (e.g. sre.hosts.decommission). (Or maybe we extend sudo::group with an optional identifier). This allows for proper garbage collection so that we can identify sudo rules for obsolete cookbooks (or renamed ones, etc. pp.). This way we can also validate that a given sudo change has been rolled out before a cookbook can be run.

Every Spicerack module by default is considered to require root permissions, but each module can declare compatibility for rootless operation for a given set of groups:

To mark a module accessible by rootless users each class can provide an init_rootless() function, which initialises the module for rootless operation and (if needed) initialises alternative credentials (such as different API tokens or similar).

There are other credentials which need to be considered in addition to sudo rules:

  • Phabricator access such as updating a task is available to every user anyway
  • confctl access can operate on locally executed commands (and if needed we can also extend it with ACLs in the future)
  • For Netbox different token may own different permissions, Riccardo to investigate
  • The IPMI module only needs access to the mgmt password, which can be provided by any user who has pwstore access
  • Elastic module mostly just operates on APIs, so might just be a need to manage different credentials

Some open questions TBD:

  • For simplicity we'd always pass sudo in rootless, Moritz will doublecheck potential side effects
  • Can we fix up logging so that log gets written to a cookbook-USER.log file with the ownership of the user (or in their local home), but also to a root-owned log file for untamperibility? Moritz will investigate

Event Timeline

colewhite triaged this task as Medium priority.Jun 4 2021, 7:32 PM

I'm not totally sure about the init_rootless() part of the API, but we can refine it as we implement it depending on the use cases.