fanout, a super useful linux script if you manage multiple, similar servers

I love this fanout script for running the same command on multiple servers, just in case you’re interested:

http://www.stearns.org/fanout/fanout

[[email protected] scripts]# fanout "$SERVERS" "cp /root/.ssh/authorized_keys /home/user/.ssh/"
Starting [email protected]
Starting [email protected]
Starting [email protected]
Starting [email protected]
Starting [email protected]
Starting [email protected]
Fanout executing "cp /root/.ssh/authorized_keys /home/user/.ssh/"
Start time Wed Dec 23 23:45:35 EST 2009 , End time Wed Dec 23 23:45:47 EST 2009
==== As root on db1 ====

==== As root on db2 ====

==== As root on nas ====

==== As root on www1 ====

==== As root on www2 ====

==== As root on www3 ====

Exiting fanout, cleaning up...done.

[[email protected] scripts]# fanout "$SERVERSWWW" "/etc/init.d/httpd restart"
Starting [email protected]
Starting [email protected]
Starting [email protected]
Fanout executing "/etc/init.d/httpd restart"
Start time Wed Dec 23 23:50:52 EST 2009 , End time Wed Dec 23 23:50:59 EST 2009
==== As root on www1 ====
Stopping httpd: [ OK ]
Starting httpd: [ OK ]

==== As root on www2 ====
Stopping httpd: [ OK ]
Starting httpd: [ OK ]

==== As root on www3 ====
Stopping httpd: [ OK ]
Starting httpd: [ OK ]

Exiting fanout, cleaning up...done.

[[email protected] scripts]# echo $SERVERS
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
[[email protected] scripts]# echo $SERVERSWWW
[email protected] [email protected] [email protected]

A great way to execute the same commands on multiple servers… if you export the $SERVERS to a standard list, in your .bashrc or whatnot… it’s even easier. Of course, you’ll probably want to setup authorized_keys for your servers so that you don’t have to authenticate to each…

DarkAuth for the win!

I’ve been working with CakePHP for a few years now and am very happy with it.  I’ve been working with the 1.2 version for a few months (since it went stable) and playing with the Auth and ACL core components.

I’ve decided that ACL is too complicated for most setups, and Auth is fine, but not perfect.  So after some research, I switched to the DarkAuth component, which was much better suited to my needs.

The main reasons I prefer it are:

  • Role/Group based access out of the box, which is how I ususally provision security anyway
  • Easy to customize/tweak to suit my needs (more below)
  • Easy to setup permissions, easy to add to app_controller, without then having to explicitly allow public controllers/actions… instead I have to explicitly restrict controllers or actions.  Also it’s easy to check for prefixes and restrict based on that (more below)
  • Fast

So here are some of my customizations:

I like having some parameters set on the controller for easy access to “who is logged in”, so I put this in the bottom of the DarkAuth startup() function:

//finally give the view access to the data
$this->controller->user = $this->getAllUserInfo();
$this->controller->set('_DarkAuth',$this->controller->user);
$this->controller->isadmin = $this-> isAllowed("admin");
$this->controller->isloggedin = $this->isAllowed();

I like using the core security class for password hashing, which can easily be done like so:

var $securityImported = false;
function hasher($plain_text){
//$hashed = md5('dark'.$plain_text.'cake');
if (!$this->securityImported) {
App::import('Core','Security');
$this->securityImported = true;
}
return Security::hash($plain_text, null, true);
}

Here’s how to inject admin requirements based on the admin routing path (prefix):


if (isset($this->params["prefix"]) && $this->params["prefix"]=='admin') {
$this->_DarkAuth = array('required' => array("admin"));
}

And some other useful controller tricks:


/**
* assigns the DarkAuth profile of a different member account, as if you had logged in as them
* also backs up your current DarkAuth profile so you can later "depersonate"
*/
function admin_impersonate($id) {
$this->Session->write('AdminDepersonate',array_intersect_key($this->user['Member'],array('id'=>0,'username'=>0)));
$this->DarkAuth->authenticate('Auth',$this->Member->read(null,$id));
return $this->redirect("/members/home");
}