{"id":1623,"date":"2013-01-29T16:47:56","date_gmt":"2013-01-29T21:47:56","guid":{"rendered":"http:\/\/www.kickflop.net\/blog\/?p=1623"},"modified":"2013-02-05T12:51:58","modified_gmt":"2013-02-05T17:51:58","slug":"another-case-for-in-place-file-editing-in-cm-tools","status":"publish","type":"post","link":"https:\/\/www.kickflop.net\/blog\/2013\/01\/29\/another-case-for-in-place-file-editing-in-cm-tools\/","title":{"rendered":"Another case for in-place file editing in CM tools"},"content":{"rendered":"<p>Our UNIX\/Linux directory services (nss) data was migrated from NIS in LDAP in 2009. Those who never administered a NIS domain may not even know what a <a href=\"http:\/\/www.lehman.cuny.edu\/cgi-bin\/man-cgi?netgroup+4\">netgroup<\/a>[<a href=\"#footnotes\">1<\/a>] is, but we continue to make significant use of netgroups (stored in LDAP) to define groups of users and hosts for various needs. They&#8217;ve worked great for decades and serve a good purpose.<!--more--><\/p>\n<p>Specifically, as it relates to this blog post, we use netgroups to control the definition of user accounts for a given host. <\/p>\n<p>In <code>\/etc\/nsswitch.conf<\/code><\/p>\n<pre>\r\n...\r\npasswd: compat\r\npasswd_compat: ldap\r\n...\r\n<\/pre>\n<p>For <code>\/etc\/password<\/code>:<\/p>\n<pre>\r\n...\r\n+@mtc_users:x:::::\r\n+:x:::::\/usr\/rcf\/bin\/noaccess\r\n<\/pre>\n<p>and the information for <code>\/etc\/shadow<\/code> to complete the definition:<\/p>\n<pre>\r\n...\r\n+@mtc_users::99999::::::\r\n+::99999::::::\r\n<\/pre>\n<p>Since matching of usernames in <code>\/etc\/passwd<\/code> is sequential, the previous states &#8220;Assuming we have not matched the username\/UID above these lines already&#8230; If the username is in the netgroup <code>mtc_users<\/code>, make use of the user&#8217;s LDAP naming services information (shell, UID, etc). If not, force the shell to be <code>\/usr\/rcf\/bin\/noaccess<\/code> (which spits out a message and exits).&#8221;<\/p>\n<p>As part of our migration from CFEngine 2 to <a href=\"http:\/\/opscode.com\/\">Chef<\/a> implementation, we wanted to continue with this setup. It works great for us &#8211; all information is centralized and we already have netgroups as a mechanism for defining groups of things. We don&#8217;t want or need a configuration management tool to take over our data management, nor are we interested in synching data from LDAP into some CM tool&#8217;s data world-view. To us, the <code>user<\/code> resource in any CM tool is pretty much useless. We&#8217;re not managing 10-50000 nodes that are all identical with 3 accounts on them.<\/p>\n<p>At this point, when you ask about managing files in place with CM tools other than <a href=\"http:\/\/cfengine.com\">CFEngine<\/a> (which has this as a strong point[<a href=\"#footnotes\">2<\/a>]), the common response is &#8220;<em>Don&#8217;t do that. Manage the whole file under CM<\/em>.&#8221; We&#8217;re not about to manage <code>\/etc\/passwd<\/code> and <code>\/etc\/shadow<\/code> from every host on our network as unique host-specific files stored within our CM tool&#8217;s configuration code + data. These files are dynamic based on packages installed on modern Linuxes (you install the mysql-server package and you get a <code>mysql<\/code> user account), so whatever we stored under our CM tool would be out of date quickly. Nevermind the understood insanity of the overall idea to begin with.<\/p>\n<p>As the footnote[<a href=\"#footnotes\">2<\/a>] shows, we did this with CFEngine 2&#8217;s built-in functionality. Chef has no real in-place file editing capabilities out of the box, but when I asked about it on Twitter I found that <a href=\"http:\/\/blog.afistfulofservers.net\/\">Sean O&#8217;Meara<\/a> had written an <code>append_if_no_line<\/code> library <a href=\"https:\/\/github.com\/someara\/line-cookbook\">cookbook<\/a> 2 months prior. After pushing his cookbook up to our chef server, submitting a <a href=\"https:\/\/github.com\/someara\/line-cookbook\/pull\/2\">fix<\/a>, and testing a few things out, I had a working solution:<\/p>\n<pre>\r\nif node['netgroups'].include?('mtc')                                 [<a href=\"#footnotes\">3<\/a>]\r\n  append_if_no_line \"Allow mtc_users passwd\" do\r\n    path '\/etc\/passwd'\r\n    line \"+@mtc_users:x:::::\"\r\n  end\r\n  append_if_no_line \"Allow mtc_users shadow\" do\r\n    path '\/etc\/shadow'\r\n    line \"+@mtc_users::99999::::::\"\r\n  end\r\nend\r\n<\/pre>\n<p>I welcome any thoughts or concerns with what&#8217;s spelled out here. File editing is a real need in any flexible CM tool.<\/p>\n<h3><a name=\"footnotes\">Footnotes<\/a><\/h3>\n<ol>\n<li>That SunOS 5.10 man page is the most accurate description of netgroups in the modern world that I can find.<\/li>\n<li>In CFEngine 2, we do this in-place file editing with the <code>editfiles<\/code> directive and the sub-directives <code>DeleteLinesMatching<\/code>, <code>AppendIfNoLineMatching<\/code>, <code>LocateLineMatching<\/code>, <code>ReplaceLineWith<\/code>, and other friends.<\/li>\n<li>We use a separate cookbook to populate the <code>node['netgroups']<\/code> attribute from LDAP early in our run list. The attribute is set to the list of netgroups the node is found to be a member of.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Our UNIX\/Linux directory services (nss) data was migrated from NIS in LDAP in 2009. Those who never administered a NIS&hellip;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[],"class_list":["post-1623","post","type-post","status-publish","format-standard","hentry","category-sysadmin"],"_links":{"self":[{"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/posts\/1623","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/comments?post=1623"}],"version-history":[{"count":21,"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/posts\/1623\/revisions"}],"predecessor-version":[{"id":1646,"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/posts\/1623\/revisions\/1646"}],"wp:attachment":[{"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/media?parent=1623"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/categories?post=1623"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kickflop.net\/blog\/wp-json\/wp\/v2\/tags?post=1623"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}