diff --git a/hieradata/common.yaml b/hieradata/common.yaml index 3863f91..7ca2200 100644 --- a/hieradata/common.yaml +++ b/hieradata/common.yaml @@ -158,6 +158,15 @@ lookup_options: rke2::config_hash: merge: strategy: deep + postfix::configs: + merge: + strategy: deep + postfix::maps: + merge: + strategy: deep + postfix::virtuals: + merge: + strategy: deep facts_path: '/opt/puppetlabs/facter/facts.d' diff --git a/hieradata/roles/infra/mail/gateway.yaml b/hieradata/roles/infra/mail/gateway.yaml index f3069bd..a258330 100644 --- a/hieradata/roles/infra/mail/gateway.yaml +++ b/hieradata/roles/infra/mail/gateway.yaml @@ -3,3 +3,33 @@ # additional altnames profiles::pki::vault::alt_names: - in-mta.main.unkin.net + +# base postfix configuration (passed to postfix class) +postfix::relayhost: 'direct' +postfix::myorigin: 'main.unkin.net' +postfix::mydestination: 'blank' +postfix::mynetworks: '127.0.0.0/8 [::1]/128' +postfix::mta: true +postfix::manage_aliases: true + +# profile parameters for customization +profiles::postfix::gateway::myhostname: 'in-mta.main.unkin.net' + +# postfix transports +postfix::transports: + 'main.unkin.net': + ensure: present + destination: 'relay' + nexthop: 'ausyd1nxvm2120.main.unkin.net:25' + +# postfix virtuals +postfix::virtuals: + 'root': + ensure: present + destination: 'ben@main.unkin.net' + 'postmaster': + ensure: present + destination: 'ben@main.unkin.net' + 'abuse': + ensure: present + destination: 'ben@main.unkin.net' diff --git a/site/profiles/manifests/postfix/gateway.pp b/site/profiles/manifests/postfix/gateway.pp index 8b78be2..7110b74 100644 --- a/site/profiles/manifests/postfix/gateway.pp +++ b/site/profiles/manifests/postfix/gateway.pp @@ -1,250 +1,362 @@ class profiles::postfix::gateway ( - $tls_cert_file = '/etc/pki/tls/vault/certificate.pem', - $tls_key_file = '/etc/pki/tls/vault/certificate.pem', - $tls_ca_file = '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem', + Stdlib::Absolutepath $tls_cert_file = '/etc/pki/tls/vault/certificate.pem', + Stdlib::Absolutepath $tls_key_file = '/etc/pki/tls/vault/certificate.pem', + Stdlib::Absolutepath $tls_ca_file = '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem', + String $myhostname = $trusted['certname'], + String $message_size_limit = '133169152', + String $mailbox_size_limit = '133169152', + String $local_transport = 'error:No local mail delivery', + Boolean $enable_postscreen = true, + Array[String] $alias_maps = [ + 'hash:/etc/aliases', + 'hash:/etc/postfix/aliases', + ], + Array[String] $postscreen_dnsbl_sites = [ + 'zen.spamhaus.org*3', + 'b.barracudacentral.org=127.0.0.[2..11]*2', + 'bl.spameatingmonkey.net*2', + 'bl.spamcop.net', + 'dnsbl.sorbs.net', + 'swl.spamhaus.org*-4', + 'list.dnswl.org=127.[0..255].[0..255].0*-2', + 'list.dnswl.org=127.[0..255].[0..255].1*-4', + 'list.dnswl.org=127.[0..255].[0..255].[2..3]*-6', + ], + Array[String] $smtpd_client_restrictions = [ + 'permit_sasl_authenticated', + 'permit_mynetworks', + 'reject_rbl_client zen.spamhaus.org', + ], + Array[String] $smtpd_sender_restrictions = [ + 'permit_sasl_authenticated', + 'check_sender_access hash:/etc/postfix/sender_access', + 'reject_non_fqdn_sender', + 'reject_unknown_sender_domain', + ], + Array[String] $smtpd_recipient_restrictions = [ + 'permit_sasl_authenticated', + 'permit_mynetworks', + 'reject_unauth_destination', + 'reject_non_fqdn_recipient', + 'reject_unknown_recipient_domain', + 'check_recipient_access hash:/etc/postfix/recipient_access', + 'reject_unverified_recipient', + ], + Array[String] $smtpd_relay_restrictions = [ + 'permit_sasl_authenticated', + 'permit_mynetworks', + 'reject_unauth_destination', + ], + Hash[String, String] $smtp_tls_policy_maps = {}, + Hash[String, String] $smtpd_tls_policy_maps = {}, ) { - $alias_maps = 'hash:/etc/aliases, hash:/etc/postfix/aliases' + $alias_maps_string = join($alias_maps, ', ') - class { 'postfix': - relayhost => 'direct', - myorigin => 'main.unkin.net', - mydestination => 'blank', - mynetworks => '127.0.0.0/8 [::1]/128', - alias_maps => $alias_maps, - mta => true, - manage_aliases => true, - master_smtp => 'smtp inet n - n - 1 postscreen', - master_entries => [ - # Postscreen backend services + # Set master.cf configuration based on postscreen setting + if $enable_postscreen { + $master_smtp = 'smtp inet n - n - 1 postscreen' + $master_entries = [ 'smtpd pass - - n - - smtpd', 'dnsblog unix - - n - 0 dnsblog', 'tlsproxy unix - - n - 0 tlsproxy', - ], + ] + $postscreen_configs = { + 'postscreen_access_list' => { + 'value' => 'permit_mynetworks, cidr:/etc/postfix/postscreen_access' + }, + 'postscreen_blacklist_action' => { + 'value' => 'enforce' + }, + 'postscreen_cache_map' => { + 'value' => 'btree:$data_directory/postscreen_cache' + }, + 'postscreen_dnsbl_action' => { + 'value' => 'enforce' + }, + 'postscreen_dnsbl_sites' => { + 'value' => join($postscreen_dnsbl_sites, ', ') + }, + 'postscreen_dnsbl_threshold' => { + 'value' => '2' + }, + 'postscreen_greet_action' => { + 'value' => 'enforce' + }, + 'postscreen_greet_banner' => { + 'value' => '$smtpd_banner' + }, + 'postscreen_greet_wait' => { + 'value' => "\${stress?2}\${stress:6}s" + }, + } + } else { + $master_smtp = undef + $master_entries = [] + $postscreen_configs = {} } - postfix::config { - 'alias_database': - value => $alias_maps; - 'default_destination_recipient_limit': - value => '1'; - 'disable_vrfy_command': - value => 'yes'; - 'enable_long_queue_ids': - value => 'yes'; - 'error_notice_recipient': - value => 'root'; - 'header_checks': - value => 'regexp:/etc/postfix/header_checks'; - 'local_recipient_maps': - ensure => 'blank'; # no local mailboxes - 'local_transport': - value => 'error:No local mail delivery'; - 'mailbox_size_limit': - value => '133169152'; # ~127MB - 'message_size_limit': - value => '133169152'; # ~127MB - 'myhostname': - value => 'in-mta.main.unkin.net'; - 'non_smtpd_milters': - ensure => 'blank'; - 'postscreen_access_list': - value => 'permit_mynetworks, cidr:/etc/postfix/postscreen_access'; - 'postscreen_blacklist_action': - value => 'enforce'; - 'postscreen_cache_map': - value => 'btree:$data_directory/postscreen_cache'; - 'postscreen_dnsbl_action': - value => 'enforce'; - 'postscreen_dnsbl_sites': - value => join([ - 'zen.spamhaus.org*3', - 'b.barracudacentral.org=127.0.0.[2..11]*2', - 'bl.spameatingmonkey.net*2', - 'bl.spamcop.net', - 'dnsbl.sorbs.net', - 'swl.spamhaus.org*-4', - 'list.dnswl.org=127.[0..255].[0..255].0*-2', - 'list.dnswl.org=127.[0..255].[0..255].1*-4', - 'list.dnswl.org=127.[0..255].[0..255].[2..3]*-6' - ], ', '); - 'postscreen_dnsbl_threshold': - value => '2'; - 'postscreen_greet_action': - value => 'enforce'; - 'postscreen_greet_banner': - value => '$smtpd_banner'; - 'postscreen_greet_wait': - value => "\${stress?2}\${stress:6}s"; - 'qmqpd_authorized_clients': - value => '127.0.0.1 [::1]'; - 'recipient_canonical_maps': - value => 'hash:/etc/postfix/recipient_canonical'; - 'recipient_delimiter': - value => '+'; - 'relay_domains': - value => 'hash:/etc/postfix/relay_domains'; - 'relay_recipient_maps': - value => 'hash:/etc/postfix/relay_recipients'; - 'sender_canonical_maps': - value => 'hash:/etc/postfix/sender_canonical'; - 'smtp_tls_CAfile': - value => $tls_ca_file; - 'smtp_tls_mandatory_protocols': - value => '!SSLv2,!SSLv3'; - 'smtp_tls_note_starttls_offer': - value => 'yes'; - 'smtp_tls_protocols': - value => '!SSLv2,!SSLv3'; - 'smtp_tls_security_level': - value => 'may'; - 'smtp_tls_session_cache_database': - value => 'btree:/var/lib/postfix/smtp_tls_session_cache'; - 'smtp_use_tls': - value => 'yes'; - 'smtpd_banner': - value => '$myhostname ESMTP $mail_name'; - 'smtpd_client_restrictions': - value => 'permit_sasl_authenticated, permit_mynetworks, reject_rbl_client zen.spamhaus.org'; - 'smtpd_data_restrictions': - value => 'reject_unauth_pipelining'; - 'smtpd_delay_reject': - value => 'yes'; - 'smtpd_discard_ehlo_keywords': - value => 'chunking, silent-discard'; - 'smtpd_forbid_bare_newline': - value => 'yes'; - 'smtpd_forbid_bare_newline_exclusions': - value => '$mynetworks'; - 'smtpd_forbid_unauth_pipelining': - value => 'yes'; - 'smtpd_helo_required': - value => 'yes'; - 'smtpd_helo_restrictions': - value => 'check_helo_access hash:/etc/postfix/helo_access, reject_invalid_hostname'; - 'smtpd_milters': - value => 'inet:127.0.0.1:33333'; - 'smtpd_recipient_restrictions': - value => join([ - 'permit_sasl_authenticated', - 'permit_mynetworks', - 'reject_unauth_destination', - 'reject_non_fqdn_recipient', - 'reject_unknown_recipient_domain', - 'check_recipient_access hash:/etc/postfix/recipient_access', - 'check_policy_service inet:127.0.0.1:2501', - 'reject_unverified_recipient' - ], ', '); - 'smtpd_relay_restrictions': - value => 'permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination'; - 'smtpd_sender_restrictions': - value => join([ - 'permit_sasl_authenticated', - 'check_sender_access hash:/etc/postfix/sender_access', - 'reject_non_fqdn_sender', - 'reject_unknown_sender_domain' - ], ', '); - 'smtpd_tls_CAfile': - value => $tls_ca_file; - 'smtpd_tls_cert_file': - value => $tls_cert_file; - 'smtpd_tls_ciphers': - value => 'medium'; - 'smtpd_tls_key_file': - value => $tls_key_file; - 'smtpd_tls_loglevel': - value => '1'; - 'smtpd_tls_mandatory_protocols': - value => '!SSLv2,!SSLv3'; - 'smtpd_tls_protocols': - value => '!SSLv2,!SSLv3'; - 'smtpd_tls_received_header': - value => 'yes'; - 'smtpd_tls_security_level': - value => 'may'; - 'smtpd_tls_session_cache_database': - value => 'btree:/var/lib/postfix/smtpd_tls_session_cache'; - 'smtpd_tls_session_cache_timeout': - value => '3600s'; - 'smtpd_use_tls': - value => 'yes'; - 'tls_medium_cipherlist': - value => join([ + # Base postfix configuration + $base_configs = { + 'alias_database' => { + 'value' => $alias_maps_string + }, + 'default_destination_recipient_limit' => { + 'value' => '1' + }, + 'disable_vrfy_command' => { + 'value' => 'yes' + }, + 'enable_long_queue_ids' => { + 'value' => 'yes' + }, + 'error_notice_recipient' => { + 'value' => 'root' + }, + 'header_checks' => { + 'value' => 'regexp:/etc/postfix/header_checks' + }, + 'local_recipient_maps' => { + 'ensure' => 'blank' + }, + 'local_transport' => { + 'value' => $local_transport + }, + 'mailbox_size_limit' => { + 'value' => $mailbox_size_limit + }, + 'message_size_limit' => { + 'value' => $message_size_limit + }, + 'myhostname' => { + 'value' => $myhostname + }, + 'non_smtpd_milters' => { + 'ensure' => 'blank' + }, + 'qmqpd_authorized_clients' => { + 'value' => '127.0.0.1 [::1]' + }, + 'recipient_canonical_maps' => { + 'value' => 'hash:/etc/postfix/recipient_canonical' + }, + 'recipient_delimiter' => { + 'value' => '+' + }, + 'relay_domains' => { + 'value' => 'hash:/etc/postfix/relay_domains' + }, + 'relay_recipient_maps' => { + 'value' => 'hash:/etc/postfix/relay_recipients' + }, + 'sender_canonical_maps' => { + 'value' => 'hash:/etc/postfix/sender_canonical' + }, + 'smtp_tls_CAfile' => { + 'value' => $tls_ca_file + }, + 'smtp_tls_mandatory_protocols' => { + 'value' => '!SSLv2,!SSLv3' + }, + 'smtp_tls_note_starttls_offer' => { + 'value' => 'yes' + }, + 'smtp_tls_protocols' => { + 'value' => '!SSLv2,!SSLv3' + }, + 'smtp_tls_security_level' => { + 'value' => 'may' + }, + 'smtp_tls_session_cache_database' => { + 'value' => 'btree:/var/lib/postfix/smtp_tls_session_cache' + }, + 'smtp_use_tls' => { + 'value' => 'yes' + }, + 'smtpd_banner' => { + 'value' => '$myhostname ESMTP $mail_name' + }, + 'smtpd_client_restrictions' => { + 'value' => join($smtpd_client_restrictions, ', ') + }, + 'smtpd_data_restrictions' => { + 'value' => 'reject_unauth_pipelining' + }, + 'smtpd_delay_reject' => { + 'value' => 'yes' + }, + 'smtpd_discard_ehlo_keywords' => { + 'value' => 'chunking, silent-discard' + }, + 'smtpd_forbid_bare_newline' => { + 'value' => 'yes' + }, + 'smtpd_forbid_bare_newline_exclusions' => { + 'value' => '$mynetworks' + }, + 'smtpd_forbid_unauth_pipelining' => { + 'value' => 'yes' + }, + 'smtpd_helo_required' => { + 'value' => 'yes' + }, + 'smtpd_helo_restrictions' => { + 'value' => 'check_helo_access hash:/etc/postfix/helo_access, reject_invalid_hostname' + }, + 'smtpd_milters' => { + 'value' => 'inet:127.0.0.1:33333' + }, + 'smtpd_recipient_restrictions' => { + 'value' => join($smtpd_recipient_restrictions, ', ') + }, + 'smtpd_relay_restrictions' => { + 'value' => join($smtpd_relay_restrictions, ', ') + }, + 'smtpd_sender_restrictions' => { + 'value' => join($smtpd_sender_restrictions, ', ') + }, + 'smtpd_tls_CAfile' => { + 'value' => $tls_ca_file + }, + 'smtpd_tls_cert_file' => { + 'value' => $tls_cert_file + }, + 'smtpd_tls_ciphers' => { + 'value' => 'medium' + }, + 'smtpd_tls_key_file' => { + 'value' => $tls_key_file + }, + 'smtpd_tls_loglevel' => { + 'value' => '1' + }, + 'smtpd_tls_mandatory_protocols' => { + 'value' => '!SSLv2,!SSLv3' + }, + 'smtpd_tls_protocols' => { + 'value' => '!SSLv2,!SSLv3' + }, + 'smtpd_tls_received_header' => { + 'value' => 'yes' + }, + 'smtpd_tls_security_level' => { + 'value' => 'may' + }, + 'smtpd_tls_session_cache_database' => { + 'value' => 'btree:/var/lib/postfix/smtpd_tls_session_cache' + }, + 'smtpd_tls_session_cache_timeout' => { + 'value' => '3600s' + }, + 'smtpd_use_tls' => { + 'value' => 'yes' + }, + 'tls_medium_cipherlist' => { + 'value' => join([ 'ECDSA+AESGCM:ECDH+AESGCM:DH+AESGCM:ECDSA+AES:ECDH+AES:DH+AES', 'ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS' - ], ':'); - 'tls_preempt_cipherlist': - value => 'yes'; - 'tls_random_source': - value => 'dev:/dev/urandom'; - 'unverified_recipient_reject_code': - value => '550'; - 'unverified_recipient_reject_reason': - value => 'No user at this address'; + ], ':') + }, + 'tls_preempt_cipherlist' => { + 'value' => 'yes' + }, + 'tls_random_source' => { + 'value' => 'dev:/dev/urandom' + }, + 'unverified_recipient_reject_code' => { + 'value' => '550' + }, + 'unverified_recipient_reject_reason' => { + 'value' => 'No user at this address' + }, + 'smtp_tls_policy_maps' => { + 'value' => 'hash:/etc/postfix/smtp_tls_policy_maps' + }, + 'smtpd_tls_policy_maps' => { + 'value' => 'hash:/etc/postfix/smtpd_tls_policy_maps' + }, } - postfix::map { 'postscreen_access': - ensure => present, - type => 'cidr', - source => 'puppet:///modules/profiles/postfix/gateway/postscreen_access' - } - postfix::map { 'relay_recipients': - ensure => present, - type => 'hash', - source => 'puppet:///modules/profiles/postfix/gateway/relay_recipients' - } - postfix::map { 'relay_domains': - ensure => present, - type => 'hash', - source => 'puppet:///modules/profiles/postfix/gateway/relay_domains' - } - postfix::map { 'aliases': - ensure => present, - type => 'hash', - source => 'puppet:///modules/profiles/postfix/gateway/aliases' - } - postfix::map { 'helo_access': - ensure => present, - type => 'hash', - source => 'puppet:///modules/profiles/postfix/gateway/helo_access' - } - postfix::map { 'sender_access': - ensure => present, - type => 'hash', - source => 'puppet:///modules/profiles/postfix/gateway/sender_access' - } - postfix::map { 'recipient_access': - ensure => present, - type => 'hash', - source => 'puppet:///modules/profiles/postfix/gateway/recipient_access' - } - postfix::map { 'recipient_canonical': - ensure => present, - type => 'hash', - source => 'puppet:///modules/profiles/postfix/gateway/recipient_canonical' - } - postfix::map { 'sender_canonical': - ensure => present, - type => 'hash', - source => 'puppet:///modules/profiles/postfix/gateway/sender_canonical' + + # Generate TLS policy content + $smtp_tls_content = !empty($smtp_tls_policy_maps) ? { + true => $smtp_tls_policy_maps.map |$domain, $policy| { "${domain} ${policy}" }.join("\n"), + false => "# SMTP TLS policy map\n# Format: destination policy\n# Example: gmail.com encrypt" } - postfix::transport { - 'main.unkin.net': - ensure => present, - destination => 'relay', - nexthop => 'ausyd1nxvm2120.main.unkin.net:25'; + $smtpd_tls_content = !empty($smtpd_tls_policy_maps) ? { + true => $smtpd_tls_policy_maps.map |$client, $policy| { "${client} ${policy}" }.join("\n"), + false => "# SMTPD TLS policy map\n# Format: client policy\n# Example: 192.168.1.0/24 encrypt" } - postfix::virtual { - 'root': - ensure => present, - destination => 'ben@main.unkin.net'; - 'postmaster': - ensure => present, - destination => 'ben@main.unkin.net'; - 'abuse': - ensure => present, - destination => 'ben@main.unkin.net'; + + # Postfix maps (includes TLS policy maps) + $postfix_maps = { + 'postscreen_access' => { + 'ensure' => 'present', + 'type' => 'cidr', + 'source' => 'puppet:///modules/profiles/postfix/gateway/postscreen_access' + }, + 'relay_recipients' => { + 'ensure' => 'present', + 'type' => 'hash', + 'source' => 'puppet:///modules/profiles/postfix/gateway/relay_recipients' + }, + 'relay_domains' => { + 'ensure' => 'present', + 'type' => 'hash', + 'source' => 'puppet:///modules/profiles/postfix/gateway/relay_domains' + }, + 'aliases' => { + 'ensure' => 'present', + 'type' => 'hash', + 'source' => 'puppet:///modules/profiles/postfix/gateway/aliases' + }, + 'helo_access' => { + 'ensure' => 'present', + 'type' => 'hash', + 'source' => 'puppet:///modules/profiles/postfix/gateway/helo_access' + }, + 'sender_access' => { + 'ensure' => 'present', + 'type' => 'hash', + 'source' => 'puppet:///modules/profiles/postfix/gateway/sender_access' + }, + 'recipient_access' => { + 'ensure' => 'present', + 'type' => 'hash', + 'source' => 'puppet:///modules/profiles/postfix/gateway/recipient_access' + }, + 'recipient_canonical' => { + 'ensure' => 'present', + 'type' => 'hash', + 'source' => 'puppet:///modules/profiles/postfix/gateway/recipient_canonical' + }, + 'sender_canonical' => { + 'ensure' => 'present', + 'type' => 'hash', + 'source' => 'puppet:///modules/profiles/postfix/gateway/sender_canonical' + }, + 'smtp_tls_policy_maps' => { + 'ensure' => 'present', + 'type' => 'hash', + 'content' => $smtp_tls_content, + }, + 'smtpd_tls_policy_maps' => { + 'ensure' => 'present', + 'type' => 'hash', + 'content' => $smtpd_tls_content, + }, + } + + # Merge base configs with postscreen configs + $all_configs = $base_configs + $postscreen_configs + + class { 'postfix': + master_smtp => $master_smtp, + master_entries => $master_entries, + alias_maps => $alias_maps_string, + configs => $all_configs, + maps => $postfix_maps, } }