Commit d9104ac0 authored by mh's avatar mh

initial rework for schleuder 3

parent 3fa1a6a3
.tmp_*~
.librarian
.tmp
spec/fixtures/modules
spec/fixtures/manifests
*.lock
source 'https://rubygems.org'
if ENV.key?('PUPPET_VERSION')
puppetversion = "~> #{ENV['PUPPET_VERSION']}"
else
puppetversion = ['>= 3.8.7']
end
if RUBY_VERSION == '1.8.7'
# 4.0.0 requires 1.9.3
puppetversion = ['~> 3.8.7']
gem 'i18n', '~> 0.6.11'
gem 'activesupport', '~> 3.2'
gem 'librarian-puppet', '~> 1.0.0'
gem 'highline', '~> 1.6.21'
gem 'rake', '< 11'
gem 'json', '< 2.0.2'
else
gem 'rake'
gem 'librarian-puppet', '>=0.9.10'
end
gem 'puppet', puppetversion
gem 'puppet-lint', '>=0.3.2'
gem 'puppetlabs_spec_helper', '>=0.2.0'
forge 'https://forgeapi.puppetlabs.com'
mod 'puppetlabs-stdlib'
mod 'puppetlabs-concat', '~> 1.2.5'
mod 'puppet-healthcheck'
mod 'scl', :git => 'https://git-ipuppet.immerda.ch/module-scl'
require 'bundler'
Bundler.require(:rake)
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
Rake::Task[:lint].clear
PuppetLint::RakeTask.new :lint do |config|
config.ignore_paths = ["spec/**/*.pp", "vendor/**/*.pp"]
config.log_format = '%{path}:%{line}:%{KIND}: %{message}'
config.disable_checks = [ "class_inherits_from_params_class", "80chars" ]
end
# use librarian-puppet to manage fixtures instead of .fixtures.yml
# offers more possibilities like explicit version management, forge downloads,...
task :librarian_spec_prep do
sh "librarian-puppet install --path=spec/fixtures/modules/"
pwd = `pwd`.strip
unless File.directory?("#{pwd}/spec/fixtures/modules/munin")
sh "ln -s #{pwd} #{pwd}/spec/fixtures/modules/munin"
end
end
task :spec_prep => :librarian_spec_prep
task :default => [:spec, :lint]
Facter.add('schleuder_tls_fingerprint') do
setcode do
# check whether schleuder could actually find a cert
if File.exists?('/etc/schleuder/schleuder.yml') &&
(config = YAML.load_file('/etc/schleuder/schleuder.yml')) &&
File.exists?(config['api']['tls_cert_file']) &&
(fp = Facter::Util::Resolution.exec('schleuder cert fingerprint'))
fp.split(': ').last
else
nil
end
end
end
require 'puppet/provider/parsedfile'
Puppet::Type.type(:schleuder_list).provide(:base) do
has_command(:cli, '/usr/bin/schleuder-cli') do
environment({ 'HOME' => ENV['HOME'] })
end
mk_resource_methods
# Return a list of existing schleuder lists
def self.instances
cli('lists','list').
split("\n").
collect { |line| new(:ensure => :present, :name => line.strip) }
end
# Prefetch our list list, yo.
def self.prefetch(lists)
instances.each do |prov|
if list = lists[prov.name] || lists[prov.name.downcase]
list.provider = prov
end
end
end
# Create the list.
def create
args = ['lists','new']
args << self.name
if val = @resource[:admin]
args << val
else
raise ArgumentError, "Schleuder lists require an administrator email address"
end
if val = @resource[:admin_publickey]
args << val
else
raise ArgumentError, "Schleuder lists require a public key of the admin"
end
cli(*args)
end
# Delete the list.
def destroy
args = ['lists','delete']
args << self.name
args << '--YES'
cli(*args)
end
# Does our list exist already?
def exists?
properties[:ensure] != :absent
end
# Clear out the cached values.
def flush
@property_hash.clear
end
# Look up the current status.
def properties
if @property_hash.empty?
@property_hash = query || {:ensure => :absent}
@property_hash[:ensure] = :absent if @property_hash.empty?
end
@property_hash.dup
end
# Pull the current state of the list from the full list. We're
# getting some double entendre here....
def query
self.class.instances.each do |list|
if list.name == self.name or list.name.downcase == self.name
return list.properties
end
end
nil
end
end
module Puppet
newtype(:schleuder_list) do
@doc = "Manage schleuder lists. This resource type can only create
and remove lists; it cannot currently reconfigure them."
ensurable do
defaultvalues
end
newparam(:name, :namevar => true) do
desc "The name of the schleuder list."
end
newparam(:admin) do
desc "The email address of the administrator."
end
newparam(:admin_publickey) do
desc "Path to the public key of the administrator"
end
autorequire(:package) do
['schleuder-cli']
end
autorequire(:file) do
self[:admin_publickey] if self[:admin_publickey]
end
end
end
# manage basic things of schleuder
# manage a schleuder installation
class schleuder::base {
include rubygems::tmail
include rubygems::gpgme
if $schleuder::enable_highline {
include rubygems::highline
package{'schleuder':
ensure => installed,
} -> file{'/etc/schleuder/schleuder.yml':
content => template('schleuder/schleuder.yml.erb'),
owner => 'root',
group => 'schleuder',
mode => '0640',
} ~> exec{'schleuder install':
refreshonly => true,
notify => Service['schleuder-api-daemon'],
} -> file{
['/etc/schleuder/schleuder-certificate.pem',
'/etc/schleuder/schleuder-private-key.pem']:
owner => root,
group => 'schleuder',
mode => '0640';
} ~> service{'schleuder-api-daemon':
ensure => running,
enable => true,
} -> http_conn_validator { 'schleuder-api-ready':
host => $schleuder::api_host,
port => $schleuder::api_port,
use_ssl => true,
test_url => '/status.json',
# api likely uses custom certs
verify_peer => false,
# at the moment api requires always
# authentication
expected_code => 401,
}
$user_shell = $::operatingsystem ? {
debian => '/usr/sbin/nologin',
ubuntu => '/usr/sbin/nologin',
default => '/sbin/nologin'
}
user::managed{'schleuder':
name_comment => 'schleuder user',
managehome => false,
homedir => '/var/schleuderlists',
shell => $user_shell,
file{'/var/lib/schleuder/adminkeys':
ensure => directory,
owner => 'root',
group => 'schleuder',
mode => '0640',
purge => true,
force => true,
recurse => true,
require => Package['schleuder'],
}
git::clone{'schleuder':
git_repo => 'git://git.immerda.ch/schleuder.git',
projectroot => $schleuder::install_dir,
cloneddir_group => 'schleuder',
require => [ User::Managed['schleuder'], Package['tmail'], Package['ruby-gpgme'] ],
if $schleuder::cli_api_key {
class{'schleuder::client':
api_key => $schleuder::cli_api_key,
tls_fingerprint => $schleuder::tls_fingerprint,
host => $schleuder::api_host,
port => $schleuder::api_port,
}
# make sure we only setup the cli once schleuder itself is done
Http_conn_validator['schleuder-api-ready'] -> File['/root/.schleuder-cli']
}
file{
["${schleuder::install_dir}/bin/schleuder", "${schleuder::install_dir}/contrib/newlist.rb" ]:
require => Git::Clone['schleuder'],
owner => root,
group => 'schleuder',
mode => '0750';
[ '/etc/schleuder', '/var/schleuderlists', '/var/schleuderlists/initmemberkeys' ]:
ensure => directory,
require => [ User::Managed['schleuder'], Git::Clone['schleuder'] ],
owner => root,
group => schleuder,
mode => '0640';
'/etc/schleuder/default-list.conf':
source => [ "puppet:///modules/site_schleuder/config/${::fqdn}/default-list.conf",
'puppet:///modules/site_schleuder/config/default-list.conf',
'puppet:///modules/schleuder/config/default-list.conf' ],
owner => root,
group => schleuder,
mode => '0640';
'/etc/schleuder/schleuder.conf':
source => ["puppet:///modules/site_schleuder/config/${::fqdn}/schleuder.conf",
'puppet:///modules/site_schleuder/config/schleuder.conf',
'puppet:///modules/schleuder/config/schleuder.conf' ],
owner => root,
group => schleuder,
mode => '0640';
'/var/log/schleuder':
ensure => directory,
require => User::Managed['schleuder'],
# as we might run schleuder as different user,
# the log file schould be writeable for the group.
owner => schleuder,
group => schleuder,
mode => '0660';
'/var/log/schleuder/schleuder.log':
# as we might run schleuder as different user,
# the log file schould be writeable for the group.
owner => schleuder,
group => schleuder,
mode => '0660';
if empty($schleuder::database_config) or $schleuder::database_config['adapter'] == 'sqlite3' {
if empty($schleuder::database_config) or !$schleuder::database_config['database'] {
$db_file = '/var/lib/schleuder/db.sqlite'
} else {
$db_file = $schleuder::database_config['database']
}
file{
$db_file:
owner => 'schleuder',
group => 'schleuder',
mode => '0640',
require => Exec['schleuder install'],
before => Service['schleuder-api-daemon'],
}
}
}
# centos dependencies
class schleuder::centos inherits schleuder::base {
require ::scl::ruby23
Package['rh-ruby23-ruby-devel','rh-ruby23-rubygem-bundler'] -> Package['schleuder']
}
# manage schleuder cli installation
class schleuder::client(
$api_key,
$tls_fingerprint = $schleuder_tls_fingerprint,
$host = 'localhost',
$port = '4443',
){
# place the file first, so everything is here
# when the package is being installed
file{
'/root/.schleuder-cli':
ensure => directory,
owner => root,
group => 0,
mode => '0600',
} -> concat{'/root/.schleuder-cli/schleuder-cli.yml':
owner => root,
group => 0,
mode => '0600',
} -> package{'schleuder-cli':
ensure => installed,
}
# we use a fragement to trick around the fingerprint
# into one run
concat::fragment{
'schleuder-cli-header':
target => '/root/.schleuder-cli/schleuder-cli.yml',
content => template('schleuder/schleuder-cli.yml.erb'),
order => '050';
'schleuder-cli-fingerprint':
target => '/root/.schleuder-cli/schleuder-cli.yml',
order => '060';
}
if $tls_fingerprint {
Concat::Fragment['schleuder-cli-fingerprint']{
content => "tls_fingerprint: ${tls_fingerprint}\n"
}
} else {
# trick the manually generated cert fingerprint
# into the first run, if possible
Concat::Fragment['schleuder-cli-fingerprint']{
content => ''
}
exec{"schleuder cert fingerprint | awk -F: '{ print \"tls_fingerprint: \"\$2 }' >> /root/.schleuder-cli/schleuder-cli.yml":
require => Concat['/root/.schleuder-cli/schleuder-cli.yml'],
before => Package['schleuder-cli'],
onlyif => 'bash -c "test -x /usr/bin/schleuder"',
}
}
}
......@@ -10,16 +10,24 @@
#
# The following variables are possible to tune this module:
#
# schleuder_enable_highline:
# wether we'd like to install highline support for
# schleuder or not.
# schleuder_install_dir:
# The directory in which you'd like to install schleuder
# Default: '/opt/schleuder',
class schleuder(
$enable_highline = true,
$install_dir = '/opt/schleuder',
$valid_api_keys = [],
$cli_api_key = undef,
$tls_fingerprint = getvar('::schleuder_tls_fingerprint'),
$api_host = 'localhost',
$api_port = '4443',
$use_shorewall = false,
$database_config = {},
$adminkeys_path = 'modules/site_schleuder/adminkeys',
$lists = {},
) {
include schleuder::base
case $operatingsystem {
'CentOS': { include schleuder::centos }
default: { include schleuder::base }
}
if $use_shorewall and $api_host != 'localhost' {
include schleuder::shorewall
}
create_resources('schleuder::list',$lists)
}
# run_as:
# - 'name': use the name var to determine the actual user
# - default: set permission for schleuder to this user. Default is schleuder.
# manage_run_as: wether to manage the run_as user
# - false, don't do anything (*Default*)
# - true, create run_as user and put it into the group schleuder
# email: the email address of the list
# adminaddress: list admin
# initmember: initial member of the list
# - 'admin': list admin is taken (*Default*)
# - default: this address is taken
# initmemberkey: public key of the initial admin
# - 'member': list initmember address is taken and postfixed with .pub (*Default*)
# - default: this address is taken
# Lookup path:
# - modules/site_schleuder/initmemberkeys/${::fqdn}/${initmemberkey}.pub
# - modules/site_schleuder/initmemberkeys/${initmemberkey}.pub
# realname: Name of the list
# - 'absent': Something like "${name} schleuder list" will be added" (*Default*)
# - default: this value will be taken
# manage_alias: Wether to add an alias or not
# - true: add alias to /etc/aliases (*Default*)
# Note: you have to check your MTA Setup wether it supports the correct run_as User
# - false: don't add aliases
#
# a small wrapper to manage init member keys and a schleuder_list
define schleuder::list(
$email = $name,
$adminaddress = undef,
$ensure = present,
$run_as = 'schleuder',
$manage_run_as = false,
$initmember = 'admin',
$initmemberkey = 'member',
$realname = 'absent',
$manage_alias = true,
$webpassword = 'absent',
$webpassword_encrypted = true,
$webpassword_force = false
$ensure = present,
$admin = undef,
$admin_publickey = undef,
){
if ($webpassword != 'absent') and ($run_as != 'schleuder') {
fail("You can't enable schleuder list ${name} on ${::fqdn} for web if it isn't running as user schleuder!")
}
if ($ensure == 'present') and !$adminaddress {
if ($ensure == 'present') and !$admin {
fail("Must pass adminaddress to Schleuder::List[${name}]")
}
include ::schleuder
$real_run_as = $run_as ? {
'name' => $name,
default => $run_as
}
$real_realname = $realname ? {
'absent' => "${name} schleuder list",
default => $realname
}
$real_initmember = $initmember ? {
'admin' => $adminaddress,
default => $initmember
}
$real_initmemberkey = $initmemberkey ? {
'member' => $real_initmember,
default => $initmemberkey
}
if $manage_run_as {
$user_shell = $::operatingsystem ? {
debian => '/usr/sbin/nologin',
ubuntu => '/usr/sbin/nologin',
default => '/sbin/nologin'
}
user::managed{$real_run_as:
ensure => $ensure,
groups => 'schleuder',
manage_group => false,
managehome => false,
homedir => "/var/schleuderlists/${name}",
shell => $user_shell,
require => User::Managed['schleuder'],
}
schleuder_list{
$name:
ensure => $ensure,
}
file{"/var/schleuderlists/initmemberkeys/${name}_${real_initmemberkey}.pub":
ensure => $ensure;
}
exec{"manage_schleuder_list_${name}": }
if $ensure == present {
File["/var/schleuderlists/initmemberkeys/${name}_${real_initmemberkey}.pub"]{
source => [ "puppet:///modules/site_schleuder/initmemberkeys/${::fqdn}/${real_initmemberkey}.pub",
"puppet:///modules/site_schleuder/initmemberkeys/${real_initmemberkey}.pub" ],
owner => root,
group => schleuder,
mode => '0640'
}
$exec_require = $manage_run_as ? {
true => [ User::Managed[$real_run_as], File["/var/schleuderlists/initmemberkeys/${name}_${real_initmemberkey}.pub",'/etc/schleuder/schleuder.conf'] ],
default => File["/var/schleuderlists/initmemberkeys/${name}_${real_initmemberkey}.pub",'/etc/schleuder/schleuder.conf']
}
Exec["manage_schleuder_list_${name}"]{
command => "${schleuder::install_dir}/contrib/newlist.rb ${name} -email ${email} -realname \"${real_realname}\" -adminaddress ${adminaddress} -initmember ${real_initmember} -initmemberkey /var/schleuderlists/initmemberkeys/${name}_${real_initmemberkey}.pub -nointeractive -mailuser ${run_as} && chown schleuder:schleuder /var/log/schleuder/schleuder.log && chmod 0660 /var/log/schleuder/schleuder.log",
creates => "/var/schleuderlists/${name}/list.conf",
timeout => '-1',
before => File['/var/log/schleuder/schleuder.log'],
require => $exec_require,
}
} else {
Exec["manage_schleuder_list_${name}"]{
command => "rm -rf /var/schleuderlists/${name}",
onlyif => "test -d /var/schleuderlists/${name}",
}
}
if $manage_alias {
sendmail::mailalias{
$name:
ensure => $ensure,
recipient => "|${schleuder::install_dir}/bin/schleuder ${name}",
require => Exec["manage_schleuder_list_${name}"];
"${name}-bounce":
ensure => $ensure,
recipient => "|${schleuder::install_dir}/bin/schleuder ${name}",
require => Exec["manage_schleuder_list_${name}"];
"${name}-sendkey":
ensure => $ensure,
recipient => "|${schleuder::install_dir}/bin/schleuder ${name}",
require => Exec["manage_schleuder_list_${name}"];
}
}
if $webpassword != 'absent' {
webschleuder::list{$name:
ensure => $ensure,
password => $webpassword,
password_encrypted => $webpassword_encrypted,
force_password => $webpassword_force,
if $admin_publickey =~ /^\// {
$real_admin_publickey = $admin_publickey
} else {
$real_admin_publickey = "/var/lib/schleuder/adminkeys/${name}_${admin}.pub"
file{$real_admin_publickey:
owner => 'root',
group => 'schleuder',
mode => '0640'
}
if !$admin_publickey {
File[$real_admin_publickey]{
source => "puppet:///${schleuder::adminkeys_path}/${adminaddress}.pub",
}
} elsif $admin_publickey =~ /^puppet:\/\// {
File[$real_admin_publickey]{
source => $admin_publickey,
}
} else {
File[$real_admin_publickey]{
content => $admin_publickey,
}
}
}
Schleuder_list[$name]{
admin_publickey => $real_admin_publickey,
admin => $admin,
}
}
}
# schleuder api daemon
class schleuder::shorewall {
$port = $schleuder::api_port
shorewall::rule { "net-me-${port}-tcp":
source => 'net',
destination => '$FW',
proto => 'tcp',
destinationport => $port,
order => 240,
action => 'ACCEPT';
}
# must be ready before setting up
Service['shorewall'] -> Exec['schleuder install']
if $schleuder::database_config['adapter'] == 'postgresql' {
include shorewall::rules::out::postgres
} elsif $schleuder::database_config['adapter'] == 'mysql' {
include shorewall::rules::out::mysql
}
}
{
"name": "duritong-schleuder",
"version": "0.0.1",
"author": "duritong",
"summary": "Puppet module to manage schleuder installation and lists",
"license": "Apache License, Version 2.0",
"source": "git://github.com/duritong/puppet-schleuder.git",
"project_page": "https://github.com/duritong/puppet-schleuder",
"issues_url": "https://github.com/duritong/puppet-schleuder/issues",
"description": "Schleuder is an encrypted mailinglist manager",
"dependencies": [
{"name":"puppetlabs/concat","version_requirement":">= 1.1.0"},
{"name":"puppetlabs/stdlib","version_requirement":">= 3.2.0"},
{"name":"puppet/healthcheck","version_requirement":">= 0.2.0"}
]
}
require 'spec_helper'
describe 'schleuder' do
let(:facts){
{
:operatingsystem => 'CentOS',
:concat_basedir => '/tmp',
}
}
let(:pre_condition){