diff --git a/manifests/client.pp b/manifests/client.pp new file mode 100644 index 0000000..bfc1732 --- /dev/null +++ b/manifests/client.pp @@ -0,0 +1,29 @@ +define openvpn::client ( + $cn, + $tunnelName, + $push = '', + $pushReset = false, + $iroute = '', + $ifconfigPush = '', + $config = '' +) { + + file { "${openvpn::config_dir}/${tunnelName}/ccd/${cn}": + ensure => file, + mode => $openvpn::config_file_mode, + owner => $openvpn::config_file_owner, + group => $openvpn::config_file_group, + content => template('openvpn/ccd.conf.erb'), + require => File[ "${openvpn::config_dir}/${tunnelName}/ccd" ] + } + + exec { "openvpn-client-gen-cert-${name}": + command => ". ./vars && ./pkitool ${cn}", + cwd => "${openvpn::config_dir}/${tunnelName}/easy-rsa", + creates => "${openvpn::config_dir}/${tunnelName}/easy-rsa/keys/${cn}.crt", + provider => 'shell', + notify => Service['openvpn'], + require => Exec["openvpn-tunnel-rsa-ca-${tunnelName}"] + } + +} diff --git a/manifests/init.pp b/manifests/init.pp index f3ede40..b71b092 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -134,7 +134,7 @@ # [*package*] # The name of openvpn package # -# [*package_src*] +# [*package_repo*] # The source of the package. Currently only 'distro' (default) and # 'openvpn' are supported. # @@ -198,6 +198,38 @@ # This is used by monitor, firewall and puppi (optional) components # Can be defined also by the (top scope) variable $openvpn_protocol # +# [*client_definedtype*] +# The Defined Resource Type to invoke when configuring a client +# +# [*easyrsa_package*] +# The name of the easy-rsa package to install to generate TLS certs +# +# [*easyrsa_country*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_province*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_city*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_org*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_email*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_cn*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_name*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_ou*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_key_size*] +# Option for easy-rsa to generate the certificate with # # == Examples # @@ -235,7 +267,7 @@ $debug = params_lookup( 'debug' , 'global' ), $audit_only = params_lookup( 'audit_only' , 'global' ), $package = params_lookup( 'package' ), - $package_src = params_lookup( 'package_src' ), + $package_repo = params_lookup( 'package_repo' ), $service = params_lookup( 'service' ), $service_status = params_lookup( 'service_status' ), $process = params_lookup( 'process' ), @@ -253,7 +285,19 @@ $log_dir = params_lookup( 'log_dir' ), $log_file = params_lookup( 'log_file' ), $port = params_lookup( 'port' ), - $protocol = params_lookup( 'protocol' ) + $protocol = params_lookup( 'protocol' ), + $client_definedtype = params_lookup( 'client_definedtype' ), + $easyrsa_package = params_lookup( 'easyrsa_package' ), + $easyrsa_dir = params_lookup( 'easyrsa_dir' ), + $easyrsa_country = params_lookup( 'easyrsa_country' ), + $easyrsa_province = params_lookup( 'easyrsa_province' ), + $easyrsa_city = params_lookup( 'easyrsa_city' ), + $easyrsa_org = params_lookup( 'easyrsa_org' ), + $easyrsa_email = params_lookup( 'easyrsa_email' ), + $easyrsa_cn = params_lookup( 'easyrsa_cn' ), + $easyrsa_name = params_lookup( 'easyrsa_name' ), + $easyrsa_ou = params_lookup( 'easyrsa_ou' ), + $easyrsa_key_size = params_lookup( 'easyrsa_key_size' ), ) inherits openvpn::params { $bool_source_dir_purge=any2bool($source_dir_purge) @@ -338,9 +382,9 @@ } ### Managed resources - if $package_src != 'distro' and $package_src != 'openvpn' { - fail("Unrecognized value for option package_src") - } elsif $package_src == 'openvpn' { + if $package_repo != 'distro' and $package_repo != 'openvpn' { + fail("Unrecognized value for option package_repo") + } elsif $package_repo == 'openvpn' { class { 'openvpn::repository': before => Package[$openvpn::package] } diff --git a/manifests/params.pp b/manifests/params.pp index 70a088f..10604cb 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -20,7 +20,7 @@ default => 'openvpn', } - $package_src = 'distro' + $package_repo = 'distro' $service = $::operatingsystem ? { default => 'openvpn', @@ -90,7 +90,22 @@ } $port = '1194' - $protocol = 'tcp' + $protocol = 'udp' + + $client_definedtype = 'openvpn::client' + + # Easy-rsa + $easyrsa_package = 'easy-rsa' + $easyrsa_dir = '/usr/share/easy-rsa' + $easyrsa_country = 'EU' + $easyrsa_province = 'Puppet' + $easyrsa_city = 'Example42' + $easyrsa_org = 'Example42' + $easyrsa_email = "PKI@example.org" + $easyrsa_cn = $::fqdn + $easyrsa_name = $::fqdn + $easyrsa_ou = 'DevOps' + $easyrsa_key_size = 4096 # General Settings $my_class = '' diff --git a/manifests/tunnel.pp b/manifests/tunnel.pp index 8d742f2..86167f4 100644 --- a/manifests/tunnel.pp +++ b/manifests/tunnel.pp @@ -47,19 +47,76 @@ # [*enable*] # If the tunnel is enabled or not. # +# [*clients*] +# The clients to allow and their configuration +# +# [*client_definedtype*] +# The Defined Resource Type to invoke when configuring a client +# +# [*easyrsa_country*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_province*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_city*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_org*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_email*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_cn*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_name*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_ou*] +# Option for easy-rsa to generate the certificate with +# +# [*easyrsa_key_size*] +# Option for easy-rsa to generate the certificate with +# +# == Examples +# +# openvpn::tunnel { 'main': +# dev => 'tap', +# server => '172.31.253.0 255.255.255.0', +# easyrsa_email => 'devops@organization', +# clients => { +# 'node42.fqdn' => { pushReset => true } +# } +# } +# +# define openvpn::tunnel ( - $auth_type = 'tls-server', - $mode = 'server', - $remote = '', - $port = '1194', - $auth_key = '', - $proto = 'tcp', - $dev = 'tun', - $server = '10.8.0.0 255.255.255.0', - $route = '', - $push = '', - $template = '', - $enable = true ) { + $auth_type = 'tls-server', + $mode = 'server', + $remote = '', + $port = $openvpn::port, + $auth_key = '', + $proto = $openvpn::protocol, + $dev = 'tun', + $server = '10.8.0.0 255.255.255.0', + $route = '', + $push = '', + $template = '', + $enable = true, + $clients = {}, + $client_definedtype = $openvpn::client_definedtype, + $easyrsa_country = $openvpn::easyrsa_country, + $easyrsa_province = $openvpn::easyrsa_province, + $easyrsa_city = $openvpn::easyrsa_city, + $easyrsa_org = $openvpn::easyrsa_org, + $easyrsa_email = $openvpn::easyrsa_email, + $easyrsa_cn = $openvpn::easyrsa_cn, + $easyrsa_name = $openvpn::easyrsa_name, + $easyrsa_ou = $openvpn::easyrsa_ou, + $easyrsa_key_size = $openvpn::easyrsa_key_size, +) { include openvpn @@ -86,6 +143,18 @@ default => $template, } + if $easyrsa_key_size < 2048 { + # Assuming a CA is generated with a lifetime of 3650 days, 4096 really + # should be used. See also: + # http://lists.debian.org/debian-devel-announce/2010/09/msg00003.html + # http://danielpocock.com/rsa-key-sizes-2048-or-4096-bits + # http://news.techworld.com/security/3214360/rsa-1024-bit-private-key-encryption-cracked/ + # Ask in ##security on Freenode (IRC) + notify { "A key size of ${easyrsa_key_size} bits was specified for\n + tunnel ${name}. You really should upgrade to 2048 bits, or even\n + 4096 bits. Oh well, just don't blame us if you're hacked.": } + } + file { "openvpn_${name}.conf": ensure => $manage_file, path => "${openvpn::config_dir}/${name}.conf", @@ -110,6 +179,103 @@ } } + if $mode == 'server' { + + file { "${openvpn::config_dir}/${name}": + ensure => directory, + mode => $openvpn::config_file_mode, + owner => $openvpn::config_file_owner, + group => $openvpn::config_file_group, + require => Package['openvpn'], + } + + file { "${openvpn::config_dir}/${name}/ccd": + ensure => directory, + mode => $openvpn::config_file_mode, + owner => $openvpn::config_file_owner, + group => $openvpn::config_file_group, + purge => true, + recurse => true, + require => File[ "${openvpn::config_dir}/${name}" ] + } + + if $auth_type == "tls-server" { + + if ! defined(Package[$openvpn::easyrsa_package]) { + package { $openvpn::easyrsa_package: + ensure => installed + } + } + + file { "${openvpn::config_dir}/${name}/easy-rsa/vars": + ensure => present, + content => template('openvpn/easyrsa.vars.erb'), + require => Exec["openvpn-tunnel-setup-easyrsa-${name}"]; + } + + file {"${openvpn::config_dir}/${name}/easy-rsa/openssl.cnf": + ensure => link, + target => "/etc/openvpn/${name}/easy-rsa/openssl-1.0.0.cnf", + require => Exec["openvpn-tunnel-setup-easyrsa-${name}"] + } + + exec { + "openvpn-tunnel-setup-easyrsa-${name}": + command => "/bin/cp -r ${openvpn::easyrsa_dir} ${openvpn::config_dir}/${name}/easy-rsa && \ + chmod 755 ${openvpn::config_dir}/${name}/easy-rsa", + creates => "${openvpn::config_dir}/${name}/easy-rsa", + notify => Service['openvpn'], + require => File["${openvpn::config_dir}/${name}"]; + + "openvpn-tunnel-rsa-dh-${name}": + command => '. ./vars && ./clean-all && ./build-dh', + cwd => "${openvpn::config_dir}/${name}/easy-rsa", + creates => "${openvpn::config_dir}/${name}/easy-rsa/keys/dh${easyrsa_key_size}.pem", + provider => 'shell', + timeout => 0, + notify => Service['openvpn'], + require => File["${openvpn::config_dir}/${name}/easy-rsa/vars"]; + + "openvpn-tunnel-rsa-ca-${name}": + command => '. ./vars && ./pkitool --initca', + cwd => "${openvpn::config_dir}/${name}/easy-rsa", + creates => [ "${openvpn::config_dir}/${name}/easy-rsa/keys/ca.key", + "${openvpn::config_dir}/${name}/easy-rsa/keys/ca.crt" ], + provider => 'shell', + timeout => 0, + notify => Service['openvpn'], + require => [ Exec["openvpn-tunnel-rsa-dh-${name}"], + File["${openvpn::config_dir}/${name}/easy-rsa/openssl.cnf"] ]; + + "openvpn-tunnel-rsa-servercrt-${name}": + command => '. ./vars && ./pkitool --server server', + cwd => "${openvpn::config_dir}/${name}/easy-rsa", + creates => "${openvpn::config_dir}/easy-rsa/keys/${::fqdn}.key", + provider => 'shell', + notify => Service['openvpn'], + require => Exec["openvpn-tunnel-rsa-ca-${name}"]; + } + + file { "${openvpn::config_dir}/${name}/keys": + ensure => link, + target => "${openvpn::config_dir}/${name}/easy-rsa/keys", + require => Exec["openvpn-tunnel-setup-easyrsa-${name}"]; + } + + } + + # The each is required to allow one CN to be used + # with multiple tunnels. + each($clients) |$commonname, $params| { + create_resources( + $client_definedtype, + { "${name}-${commonname}" => $params }, + { cn => $commonname, tunnelName => $name } + ) + + } + } + # Automatic monitoring of port and service if $openvpn::bool_monitor == true { diff --git a/templates/ccd.conf.erb b/templates/ccd.conf.erb new file mode 100644 index 0000000..0841652 --- /dev/null +++ b/templates/ccd.conf.erb @@ -0,0 +1,26 @@ +<% if @push != "" -%> +<% @push.each do |push_entry| -%> +push "<%= push %>" +<% end -%> +<% end -%> + +<% if @pushReset -%> +push-reset +<% end -%> + +<% if @iroute != "" -%> +<% @iroute.each do |iroute_entry| -%> +iroute "<%= iroute_entry %>" +<% end -%> +<% end -%> + +<% if @ifconfigPush != "" -%> +<% @ifconfigPush.each do |ifconfigPush_entry| -%> +ifconfig-push "<%= ifconfigPush_entry %>" +<% end -%> +<% end -%> + + +<% if @config != "" -%> +config "<%= config %>" +<% end -%> diff --git a/templates/easyrsa.vars.erb b/templates/easyrsa.vars.erb new file mode 100644 index 0000000..02ba68a --- /dev/null +++ b/templates/easyrsa.vars.erb @@ -0,0 +1,61 @@ +# File managed by Puppet + +# easy-rsa parameter settings + +# This variable should point to +# the top level of the easy-rsa +# tree. +export EASY_RSA="`pwd`" + +# +# This variable should point to +# the requested executables +# +export OPENSSL="openssl" +export PKCS11TOOL="pkcs11-tool" +export GREP="grep" + + +# This variable should point to +# the openssl.cnf file included +# with easy-rsa. +export KEY_CONFIG=`$EASY_RSA/whichopensslcnf $EASY_RSA` + +# Edit this variable to point to +# your soon-to-be-created key +# directory. +# +# WARNING: clean-all will do +# a rm -rf on this directory +# so make sure you define +# it correctly! +export KEY_DIR="$EASY_RSA/keys" + +# Issue rm -rf warning +# echo NOTE: If you run ./clean-all, I will be doing a rm -rf on $KEY_DIR + +# PKCS11 fixes +export PKCS11_MODULE_PATH="dummy" +export PKCS11_PIN="dummy" + +export KEY_SIZE=<%= @easyrsa_key_size %> + +# In how many days should the root CA key expire? +export CA_EXPIRE=3650 + +# In how many days should certificates expire? +export KEY_EXPIRE=3650 + +# These are the default values for fields +# which will be placed in the certificate. +# Don't leave any of these fields blank. +export KEY_COUNTRY="<%= @easyrsa_country %>" +export KEY_PROVINCE="<%= @easyrsa_province %>" +export KEY_CITY="<%= @easyrsa_city %>" +export KEY_ORG="<%= @easyrsa_org %>" +export KEY_EMAIL="<%= @easyrsa_email %>" +export KEY_CN=<%= @easyrsa_cn %> +export KEY_NAME=<%= @easyrsa_name %> +export KEY_OU=<%= @easyrsa_ou %> +export PKCS11_MODULE_PATH=changeme +export PKCS11_PIN=1234 diff --git a/templates/server.conf.erb b/templates/server.conf.erb index 670ca79..9a02403 100644 --- a/templates/server.conf.erb +++ b/templates/server.conf.erb @@ -4,8 +4,15 @@ mode server port <%= @port %> proto <%= @real_proto %> dev <%= @dev %> -<% if @route != '' %>route <%= @route %><% end -%> -<% if @push != '' %>push <%= @push %><% end -%> + +<% @route.each do |route_entry| -%> +route <%= route_entry %> +<% end -%> + +<% @push.each do |push_entry| -%> +push "<%= push_entry %>" +<% end -%> + <% if @server != '' %>server <%= @server %><% end -%> <% if @auth_type == "key" -%> @@ -13,14 +20,14 @@ secret <%= scope.lookupvar("openvpn::config_dir") %>/<%= @name %>.key <% end -%> <% if @auth_type == "tls-server" -%> tls-server -ca ca.crt -cert <%= @hostname %>.crt -key <%= @hostname %>.key -dh dh1024.pem -# duplicate-cn +ca <%= scope.lookupvar("openvpn::config_dir") %>/<%= @name %>/keys/ca.crt +cert <%= scope.lookupvar("openvpn::config_dir") %>/<%= @name %>/keys/server.crt +key <%= scope.lookupvar("openvpn::config_dir") %>/<%= @name %>/keys/server.crt +dh <%= scope.lookupvar("openvpn::config_dir") %>/<%= @name %>/keys/dh<%= @easyrsa_key_size %>.pem <% end -%> -# client-config-dir ccd +client-config-dir <%= scope.lookupvar("openvpn::config_dir") %>/<%= @name %>/ccd +ccd-exclusive keepalive 10 60 inactive 0 @@ -29,6 +36,7 @@ group <%= scope.lookupvar("openvpn::process_group") %> persist-tun persist-key verb 4 # From 0 to 15 (max) -# comp-lzo # Compress data +comp-lzo # Compress data + # client-connect /etc/openvpn/script/client_connect # client-disconnect /etc/openvpn/script/client_disconnect