I seem to be having a brain disconnect on how to get the Augeas type to
manage things that have multiple values (i.e. an Augeas tree) via Puppet.
If I run this in augtool:
augtool> set /files/etc/ssh/sshd_config/AllowGroups/1000 sshuser
augtool> save
I see this in /etc/ssh/sshd_config:
AllowGroups sshuser
However, if I try this in an Augeas type:
augeas { "sshd_conf_group_sshuser":
context => "/files/etc/ssh/sshd_config",
changes => "set /files/etc/ssh/sshd_config/AllowGroups/10000 sshuser",
}
I get the following errors from puppetd:
info: Caching catalog at /var/lib/puppet/localconfig.yaml
notice: Starting catalog run
/usr/share/augeas/lenses/sshd.aug:20.7-.37:Short split for concat
err:
//Node[testnode]/ssh/Ssh::Sshd_conf_group[sshuser]/Augeas[sshd_conf_group_sshuser]/returns:
change from need_to_run to 0 failed: Save failed with return code false
notice: Finished catalog run in 9.46 seconds
I also want to add an onlyif to that type so that it only adds the
sshuser group if it doesn't already exist, but none of these seem to work:
onlyif => "match /files/etc/ssh/sshd_config/AllowGroups/* != sshuser"
onlyif => "match /files/etc/ssh/sshd_config/AllowGroups/ != sshuser"
onlyif => "match /files/etc/ssh/sshd_config/AllowGroups != sshuser"
Any assistance/samples would be appreciated. :)
Thanks,
Avi
Think of the context as a "save me from typing" prepending to the
changes and only ifs. So.. try writing it like this:
augeas { "sshd_conf_group_sshuser":
context => "/files/etc/ssh/sshd_config",
changes => "set AllowGroups/10000 sshuser",
onlyif => "match AllowGroups != sshuser
}
The code will prepend the context onto your set and match to give it the
correct full path. BTW.. I asked James to pull in some code which should
make the need to set and do an onlyif on the same code not necessary.
-- bk
Bryan Kearney wrote:
> augeas { "sshd_conf_group_sshuser":
> context => "/files/etc/ssh/sshd_config",
> changes => "set AllowGroups/10000 sshuser",
> onlyif => "match AllowGroups != sshuser
> }
This doesn't seem to work either. If I try it without the "onlyif",
it'll add the sshuser group line properly. However, if I add the onlyif
line, it does not add the line at all. I tested this on an sshd_config
file that had no AllowGroups entries and one that had a different entry.
Help! :)
Thanks,
Avi
The current type does not support what you want. Tehre are 2 issues.
One, match currently only returns the nodes.. not the values. Second, I
gave you no "not include".
The supplied patch file solves both problems. It adds a matchValues
command that will scan the values, and not the nodes. So.. if you apply
this to a 0.24.x version you should be able to run this:
augeas { "sshd_conf_group_sshuser":
context => "/files/etc/ssh/sshd_config",
changes => "set AllowGroups/1000 sshuser",
onlyif => "matchValue AllowGroups/* !include sshuser",
}
I want to check with James about how best he would prefer me to merge
this in, but then I will mainline it.
-- bk
Even better, I spoke with David Lutterkort, and he suggested the following:
augeas { "sshd_conf_group_sshuser":
context => "/files/etc/ssh/sshd_config",
changes => "set AllowGroups/1000 sshuser",
onlyif => "match AllowGroups/*[.='sshuser'] size == 0",
}
that will work with no changes to the code base.
-- bk
If you are using Augeas 0.4.0 or newer, you can use the following:
...
onlyif => "match AllowGroups/*[ . = 'sshuser']"
...
That will produce a match iff there is an AllowGroups node that has a
child with value 'sshuser'.
David
David Lutterkort wrote:
> If you are using Augeas 0.4.0 or newer, you can use the following:
Unfortunately, I'm using Augeus 0.3.6, which is the latest version in
EPEL. I will download the 0.4.0 sources and rebuild the RPM and give it
a whirl.
Any idea when 0.4.0 will show up on EPEL in an official format? :)
Thanks,
Avi
EPEL only pushes from epel-testing to epel infrequently (usually when a
coresponding RHEL update release happens) That means that if you want
updates in between, you need to enable the epel-testing repo.
Augeas 0.4.0 should be in epel-testing now, and 0.4.1 will get there as
soon as somebody signs the package and pushes it. In the meantime, you
can get it from plague[1]
David
[1] EL-5: http://buildsys.fedoraproject.org/logs/fedora-5-epel/1583-augeas-0.4.1-1.el5/
EL-4: http://buildsys.fedoraproject.org/logs/fedora-4-epel/1582-augeas-0.4.1-1.el4/
David Lutterkort wrote:
> EPEL only pushes from epel-testing to epel infrequently (usually when a
> coresponding RHEL update release happens) That means that if you want
> updates in between, you need to enable the epel-testing repo.
Awesome, thanks!
cYa,
Avi
Bryan Kearney wrote:
> onlyif => "match AllowGroups/*[.='sshuser'] size == 0",
Just to let you all know that this works perfectly with Augeas 0.4.1-1
from EPEL-testing.
Now to move onto using Augeas with the pam.d files. :) I have to work
out how to remove lines that are found in various files.
At least it'll keep me busy.
cYa,
Avi
You definitely should read up on path expressions[1] for that, and maybe
even have a look at the test cases for them[2], since they show some
more esoteric uses.
David
[1] http://augeas.net/page/Path_expressions
[2] http://git.fedoraproject.org/git/?p=augeas.git;a=blob_plain;f=tests/xpath.tests;hb=HEAD
David Lutterkort wrote:
> You definitely should read up on path expressions[1] for that, and maybe
> even have a look at the test cases for them[2], since they show some
> more esoteric uses.
I'm still having a bit of a brain disconnect on converting Augeas' XPath
stuff into Puppet types.
Here is my test Puppet entry:
augeas { "pam_set_cracklib":
context => "/files/etc/pam.d/system-auth",
changes => "rm *[module='pam_cracklib.so']/argument",
onlyif => "match *[module='pam_cracklib.so'][count(argument)>5]",
}
Which, theoretically, should remove all the arguments if the entry that
contains the pam_cracklib.so module has more than 5 arguments.
If I run the match (in the onlyif line) in augtool, I get:
augtool> match
/files/etc/pam.d/system-auth/*[module='pam_cracklib.so'][count(argument)>5]
/files/etc/pam.d/system-auth/8 = (none)
Which suggests that line 8 in that file matches.
However, when I run this entry in Puppet, I get:
err: //Node[testnode]/pam/Augeas[pam_set_cracklib]: Failed to retrieve
current state of resource: Error sending command 'match' with params
["/files/etc/pam.d/system-auth/*[module='pam_cracklib.so'][count(argument)>5]"]/Invalid
command: match
/files/etc/pam.d/system-auth/*[module='pam_cracklib.so'][count(argument)>5]
Any ideas?
Essentially, what I'm trying to achieve is the capability to change
pam.d file entries if they don't match what they're supposed to.
Thanks,
Avi
If you have Augeas 0.4.1 on both the puppet client and master (count was
only added in 0.4.1) this should work. Bryan, any ideas what could be
wrong ?
David
David Lutterkort wrote:
> If you have Augeas 0.4.1 on both the puppet client and master (count was
> only added in 0.4.1) this should work. Bryan, any ideas what could be
> wrong ?
I have upgraded both my test client and master to 0.4.1 and I have
worked out the problem. Switching to this onlyif line works:
onlyif => "match *[module='pam_cracklib.so'][count(argument)>6] size > 0"
However, note that the > appears to imply >=, i.e. if I use
count(argument)>5 then it will fire when there are 5 arguments. If I use
>6, it will not fire on 5 arguments, but will fire on 6.
Hope that makes sense.
cYa,
Avi
Ouch .. you are right. There's a bug that makes '>' mean '>=' and '>='
mean '>'. I'll commit a fix.
David
David Lutterkort wrote:
> Ouch .. you are right. There's a bug that makes '>' mean'>=' and '>='
> mean '>'. I'll commit a fix.
Well, on the plus side, it means I'm not actually going insane. :)
Quick question: I'm trying to have multiple onlyif matches using
standard Puppet syntax, i.e.
onlyif => [ "match ..", "match .." ]
I'm getting this error from Puppet:
err: //Node[testnode]/pam/Augeas[pam_set_cracklib]: Failed to retrieve
current state of resource: private method `split' called for
#<Array:0x2aaaab13fc60>
I assume this means that the Augeas type doesn't support an array in
onlyif, but I thought I'd check to be 100% sure. :)
Ta,
Avi
Yeah, that's what that means. Here's a dirty trick to check multiple
conditions:
onlyif => "match /files[ (cond1 or cond2) and cond3] size == 0"
IOW, you can combine multiple path expressions with 'and' and 'or',
though you will have to use full paths in the conditions, since the
Augeas type won't understand that it has to set the context on the
inside, too.
So, to trigger the onlyif if you have an entry in /etc/hosts with IP
address 127.0.0.1 or a mail alias for root and sshd permits root login
(seriously contrived example), you can write
match "/files[(count(/files/etc/hosts/*[ipaddr='127.0.0.1']) > 0 or count(/files/etc/aliases/*[name = 'root']) > 0) and count(/files/etc/ssh/sshd_config/PermitRootLogin[. = 'yes']) > 0]"
in augtool. The Augeas type might choke on all the spaces in the path
expression, not sure.
David
David Lutterkort wrote:
> Yeah, that's what that means. Here's a dirty trick to check multiple
> conditions:
Your assistance so far has been awesome. If I had more time to play, I'm
sure I could solve this in time, but I'm being hammered by the security
teams and I need to get a solution onto our servers as soon as possible.
I'm trying to check/change /etc/pam.d/system-auth
The initial (default set) lines look like this:
password requisite pam_cracklib.so try_first_pass retry=3
password sufficient pam_unix.so md5 shadow nullok try_first_pass
use_authtok
I want to change them to this (result set):
password requisite pam_cracklib.so retry=3 lcredit=1 ucredit=1
dcredit=1 ocredit=1
password sufficient pam_unix.so md5 shadow try_first_pass
use_authtok remember=7
Essentially, I need to check if the lines match the result set and if
not, to make the change. I'm happily able to make the proper changes,
using the following (using the first line as an example):
changes => [ "rm *[module='pam_cracklib.so'][type='password']/argument",
"set *[module='pam_cracklib.so'][type='password']/argument[1] retry=3",
"set *[module='pam_cracklib.so'][type='password']/argument[2] lcredit=1",
"set *[module='pam_cracklib.so'][type='password']/argument[3] ucredit=1",
"set *[module='pam_cracklib.so'][type='password']/argument[4] dcredit=1",
"set *[module='pam_cracklib.so'][type='password']/argument[5] ocredit=1"],
But I'm really struggling with the onlyif line to check that all the
arguments are in place, the correct value and there are no extras. I'm
able to test individual argument values and the overall count, but I
seem unable to build a full match that checks everything at once, i.e.
checks each of the first five argument values and ensures that there are
only 5 arguments total.
I hate stretching the friendship, but any assistance would be appreciated!
Thanks,
Avi
If you don't mind an unnecessary change the first time you run your
Augeas resource on a system, you don't need the onlyif - unnecessary
here means that system-auth might be changed simply because there's
different amounts of spaces between the current file and what Augeas
would generate based on your tree changes.
Augeas will not actually change the file if it stays byte-for-byte
identical, even if you made changes to the tree (e.g. change the value
of a node to something new, then back to the old thing)
Depending on the version of the Augeas plugin you have, puppet _might_
report changes even though none were necessary (or made) - Bryan might
be able to shed some light on the state of reporting in the Augeas type
in 0.24.7 vs the latest in git.
David
Well, that's handy. :)
Thanks!
Avi
For this one, the puppet match is slight different then the augeas
match. Puppet match is
match [AUGEAS_PATH] [size = [int]| include [string]| == [an array]]
So.. you need to add one of the testers on to the end for that.
-- bk
Yeah... match does not support arrays. I will add a feature request for
that.
-- bk
http://projects.reductivelabs.com/issues/2048
-- bk
Yes, there are ruby bindings[1] The existing Augeas type should give you
a good idea of what's involved in making Augeas functionality available.
David
[1] http://augeas.net/download.html
David Lutterkort wrote:
> If you have Augeas 0.4.1 on both the puppet client and master (count was
> only added in 0.4.1) this should work. Bryan, any ideas what could be
> wrong ?
Just a follow-up and warning: if you try this on an older version of
augeas (0.3.5 in my case), it tends to erase the contents of all the files.
Here is my pam class:
#
# Module: pam
#
class pam {
augeas { "pam_set_cracklib":
context => "/files/etc/pam.d/system-auth",
changes => [ "rm *[module='pam_cracklib.so'][type='password']/argument",
"set *[module='pam_cracklib.so'][type='password']/argument[1]
retry=3",
"set *[module='pam_cracklib.so'][type='password']/argument[2]
lcredit=1",
"set *[module='pam_cracklib.so'][type='password']/argument[3]
ucredit=1",
"set *[module='pam_cracklib.so'][type='password']/argument[4]
dcredit=1",
"set *[module='pam_cracklib.so'][type='password']/argument[5]
ocredit=1"],
onlyif => "get
*[module='pam_cracklib.so'][type='password']/argument[1] != retry=3",
}
augeas { "pam_set_unix":
context => "/files/etc/pam.d/system-auth",
changes => [ "rm *[module='pam_unix.so'][type='password']/argument",
"set
*[module='pam_unix.so'][type='password']/argument[1] md5",
"set
*[module='pam_unix.so'][type='password']/argument[2] shadow",
"set
*[module='pam_unix.so'][type='password']/argument[3] try_first_pass",
"set
*[module='pam_unix.so'][type='password']/argument[4] use_authtok",
"set
*[module='pam_unix.so'][type='password']/argument[5] remember=7", ],
onlyif => "get
*[module='pam_unix.so'][type='password']/argument[1] != md5",
}
# augeas { "pam_set_su_wheel":
# context => "/files/etc/pam.d/su",
# changes => [ "ins 1000 after *[type='auth'][module='pam_rootok.so']",
# "set 1000/type auth",
# "set 1000/control required",
# "set 1000/module pam_wheel.so" ],
# onlyif => "match
*[type='auth'][control='required'][module='pam_wheel.so'] size == 0",
# }
augeas { "pam_remove_console":
context => "/files/etc/pam.d/",
changes => "rm */*[module='pam_console.so']",
onlyif => "match */*[module='pam_console.so'] size > 0",
}
augeas { "pam_remove_rhosts_auth":
context => "/files/etc/pam.d",
changes => "rm */*[module='pam_rhosts_auth.so']",
onlyif => "match */*[module='pam_rhosts_auth.so'] size > 0",
}
}
When this ran on a machine that had augeas-libs 0.3.5, it erased the
contents of all the files in /etc/pam.d. That was fun to fix, especially
as this happened to the puppet master itself.
I'm not sure exactly which one of these caused the problem. I wasn't
about to do detailed troubleshooting, because I needed to get my puppet
master allowing logins. :)
Anyway, just thought I'd let you all know.
cYa,
Avi
[root@dcpuppet01 puppet]# /etc/init.d/puppetmaster start
Starting puppetmaster: undefined local variable or method `detail' for
#<Puppet::SSLCertificates::CA:0xb79cfdbc>
[FAILED]
[root@dcpuppet01 puppet]#
Cheers!
Jonathan