Most of you are familiar with the roles and profiles method of writing and classifying Puppet code. However, the roles and profiles method doesn’t have to exist only in your control repository. In fact, as I’ve been developing Puppet code centered around compliance, I’ve found that adapting the roles and profiles method into a design pattern to Puppet modules makes the code more auditable, reusable, and maintainable!
For the uninitiated, the roles and profiles method, or roles and profiles pattern, allows you to separate resources and logic in your Puppet code from the actual manifest you classify against a node. This is done by writing profiles, logically-grouped resources and the like, and including them in wrapper classes called roles which actually get classified. Profiles are generally tech stacks or base code for all nodes, while roles are named after the business logic they describe with the included profiles. In other words, the roles and profiles pattern creates a simple interface for a node so that classification of the node doesn’t get bloated with the actual resource implementation details.
For those of you familiar with software engineering, the concept of separating your code into interfaces and implementations probably sounds familiar. That’s because the roles and profiles pattern closely resembles the Facade design pattern, one of the famous “Gang of Four” design patterns that is widely used in software engineering. The facade pattern, like the roles and profiles method, allows us to hide a sprawling, complex code base behind simple, succinct interfaces. Sounds like the perfect design pattern to use for a CIS or STIG Puppet module!
How to use the roles and profiles method in a compliance Puppet module
To illustrate how to use the roles and profiles method in a compliance Puppet module, let’s assume we’re writing a Puppet module for compliance. We want to enforce the CIS control
1.1.22 Ensure sticky bit is set on all world-writable directories from the CentOS 7 benchmark. We know this control appears in other benchmarks, like the Red Hat 7 benchmark, however we’re unsure of the numbering.
We start by creating a Puppet class called
compliance::cis::utils::sticky_bit that contains resources and logic to ensure the sticky bit is set on all world-writable directories. This is similar to a profile. We then create another Puppet class called
compliance::cis::ensure_sticky_bit_is_set_on_all_world_writable_directories that includes
compliance::cis::utils::sticky_bit. This is similar to a role.
We now have a simple interface that maps directly to the CentOS 7 control name. This allows us to audit what code is in charge of what controls easily without having to know anything other than the control name. Additionally, we don’t have to worry if the control numbering is different between the CentOS and Red Hat benchmarks. Furthermore, when our boss tells us we now need Puppet code to enforce the new
Framework, Yoda Compliance that has the control
Sticky bit set, all world-writable directories must have we just need to create a class called
If you found this interesting and would like some more in depth examples and explanations of how to adapt the roles and profiles method to compliance code, please join me at Puppet Camp: Get compliance under control on March 25th, 2021! Register here.