/dev/oops

fiddyspence's blog

Rest Api Security for Fun and Profit

Puppet fileserving supports a REST api for file serving.  Individual mount points can be created which give access to specific nodes.  Alternatively you might use the special modules mount to serve data out of the files directory from <insert name of module here>.

There are security implications of fileserving from modules using the default REST API security configurations.  The issue is that the security landscape is a bit on the flat side - any authenticated node can gain access to any file resource from any module.  The upside is that it’s only open to authenticated nodes - no anonymous access allowed, but the downside is that any node can request any file.

Thus a file resource for my SSL private key,

file { ‘/etc/httpd/ssl/private_keys/puppet.spence.org.uk.local.pem’:
  ensure => file,
  owner  => ‘apache’,
  group  => ‘apache’,
  mode   => ‘0600’,
  source => ‘puppet:///modules/ssl/puppet.spence.org.uk.local.pem’,
}

is a little bit on the risky side if you ask me, because any node knowing the path can ask for the key.  Not.  Awesome.

The solution is to use auth.conf  to restrict access to the files path to just the nodes that need that particular set of resources either at the module or the individual file resource level:

path ~ \A/file_(metadata|content)/modules/ssl/puppet.spence.org.uk.local.pem
auth yes
allow puppet1.spence.org.uk.local
allow puppet2.spence.org.uk.local

You don’t necessarily need to restrict right down to the file level, like I’ve shown here.  In fact auth.conf gives enough flexibility to be able to serve *machine* specific files out of a module using regular expressions.

Consider:

file { ‘/etc/httpd/ssl/private_keys/puppet.spence.org.uk.local.pem’:
  ensure => file,
  owner  => ‘apache’,
  group  => ‘apache’,
  mode   => ‘0600’,
  source => ‘puppet:///modules/ssl/${::clientcert}/puppet.spence.org.uk.local.pem’,
}

Which is controlled by the following ACL:

path ~ \A/file_(metadata|content)s?/modules/[^/]+/([^/]+)
auth yes
allow $2

This means that you can have directory structures to securely serve node specific files from a single module where each node can only access it’s own files and not any other files from the same module:

├── files
│   ├── puppet1.spence.org.uk.local
│   │   └── puppet1.spence.org.uk.local.pem
│   └── spacewalk.spence.org.uk.local
│       └── spacewalk.spence.org.uk.local.pem

There’s some additional overhead to managing this - it’s a slightly custom auth.conf configuration, and it would need to go towards the top of the file so as to be the most specific match for the file_(content|metadata) endpoint.

Whether this is worthwhile depends entirely on whether the paranoia torrent is running strong or not.  I think it’s entirely necessary for multi-tenant infrastructure especially where one is hosting configurations for multiple business units or different organisations.

I also think it’s well worth doing for configurations that are security sensitive - private key data such as I’ve shown here, maybe passwords - that sort of stuff.