├── .editorconfig ├── .envrc ├── .gitattributes ├── .github ├── CODEOWNERS └── workflows │ ├── ci.yml │ └── stale.yml ├── .gitignore ├── .markdownlint-cli2.yaml ├── .mdlrc ├── .overcommit.yml ├── .vscode └── extensions.json ├── .yamllint ├── Berksfile ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dangerfile ├── LICENSE ├── README.md ├── TESTING.md ├── attributes └── default.rb ├── chefignore ├── documentation └── .gitkeep ├── kitchen.dokken.yml ├── kitchen.exec.yml ├── kitchen.global.yml ├── kitchen.yml ├── metadata.rb ├── recipes ├── _attributes.rb ├── _common.rb ├── access.rb ├── aliases.rb ├── client.rb ├── default.rb ├── maps.rb ├── relay_restrictions.rb ├── sasl_auth.rb ├── server.rb ├── transports.rb ├── virtual_aliases.rb └── virtual_aliases_domains.rb ├── renovate.json ├── spec ├── default_spec.rb ├── sasl_auth_spec.rb ├── spec_helper.rb └── wrapper_spec.rb ├── templates ├── access.erb ├── aliases.erb ├── mailer.erb ├── main.cf.erb ├── manifest-postfix.xml.erb ├── maps.erb ├── master.cf.erb ├── port_smtp.erb ├── recipient_canonical.erb ├── relay_restrictions.erb ├── sasl_passwd.erb ├── sender_canonical.erb ├── smtp_generic.erb ├── transport.erb ├── virtual_aliases.erb └── virtual_aliases_domains.erb └── test ├── fixtures └── cookbooks │ └── test │ ├── attributes │ └── default.rb │ ├── metadata.rb │ └── recipes │ ├── default.rb │ └── net_setup.rb └── integration ├── aliases ├── controls │ └── aliases.rb └── inspec.yml ├── canonical ├── controls │ └── canonical.rb └── inspec.yml ├── client ├── controls │ └── client.rb └── inspec.yml ├── default ├── controls │ └── default.rb └── inspec.yml ├── sasl_auth_multiple ├── controls │ └── sasl_auth_multiple.rb └── inspec.yml ├── sasl_auth_none ├── controls │ └── sasl_auth_none.rb └── inspec.yml ├── sasl_auth_one ├── controls │ └── sasl_auth_one.rb └── inspec.yml └── server ├── controls └── server.rb └── inspec.yml /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root=true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # 2 space indentation 12 | indent_style = space 13 | indent_size = 2 14 | 15 | # Avoid issues parsing cookbook files later 16 | charset = utf-8 17 | 18 | # Avoid cookstyle warnings 19 | trim_trailing_whitespace = true 20 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use chefworkstation 2 | export KITCHEN_GLOBAL_YAML=kitchen.global.yml 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @sous-chefs/maintainers 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: ci 3 | 4 | "on": 5 | pull_request: 6 | push: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | lint-unit: 12 | uses: sous-chefs/.github/.github/workflows/lint-unit.yml@3.1.1 13 | permissions: 14 | actions: write 15 | checks: write 16 | pull-requests: write 17 | statuses: write 18 | 19 | integration: 20 | needs: 'lint-unit' 21 | runs-on: ubuntu-latest 22 | strategy: 23 | matrix: 24 | os: 25 | - almalinux-8 26 | - almalinux-9 27 | - amazonlinux-2023 28 | - centos-stream-9 29 | - debian-11 30 | - debian-12 31 | - opensuse-leap-15 32 | - rockylinux-8 33 | - rockylinux-9 34 | - ubuntu-2004 35 | - ubuntu-2204 36 | - ubuntu-2404 37 | suite: 38 | - default 39 | - aliases 40 | - client 41 | - server 42 | - canonical 43 | - sasl-auth-none 44 | - sasl-auth-multiple 45 | - sasl-auth-one 46 | fail-fast: false 47 | 48 | steps: 49 | - name: Check out code 50 | uses: actions/checkout@v4 # v4 51 | - name: Install Chef 52 | uses: actionshub/chef-install@3.0.1 53 | - name: Dokken 54 | uses: actionshub/test-kitchen@3.0.0 55 | env: 56 | CHEF_LICENSE: accept-no-persist 57 | KITCHEN_LOCAL_YAML: kitchen.dokken.yml 58 | with: 59 | suite: ${{ matrix.suite }} 60 | os: ${{ matrix.os }} 61 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Mark stale issues and pull requests 3 | 4 | "on": 5 | schedule: [cron: "0 0 * * *"] 6 | 7 | jobs: 8 | stale: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/stale@v9 12 | with: 13 | repo-token: ${{ secrets.GITHUB_TOKEN }} 14 | close-issue-message: > 15 | Closing due to inactivity. 16 | If this is still an issue please reopen or open another issue. 17 | Alternatively drop by the #sous-chefs channel on the [Chef Community Slack](http://community-slack.chef.io/) and we'll be happy to help! 18 | Thanks, Sous-Chefs. 19 | days-before-close: 7 20 | days-before-stale: 365 21 | stale-issue-message: > 22 | Marking stale due to inactivity. 23 | Remove stale label or comment or this will be closed in 7 days. 24 | Alternatively drop by the #sous-chefs channel on the [Chef Community Slack](http://community-slack.chef.io/) and we'll be happy to help! 25 | Thanks, Sous-Chefs. 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.rbc 2 | .config 3 | InstalledFiles 4 | pkg 5 | test/tmp 6 | test/version_tmp 7 | tmp 8 | _Store 9 | *~ 10 | *# 11 | .#* 12 | \#*# 13 | *.un~ 14 | *.tmp 15 | *.bk 16 | *.bkup 17 | 18 | # editor files 19 | .idea 20 | .*.sw[a-z] 21 | 22 | # ruby/bundler/rspec files 23 | .ruby-version 24 | .ruby-gemset 25 | .rvmrc 26 | Gemfile.lock 27 | .bundle 28 | *.gem 29 | coverage 30 | spec/reports 31 | 32 | # YARD / rdoc artifacts 33 | .yardoc 34 | _yardoc 35 | doc/ 36 | rdoc 37 | 38 | # chef infra stuff 39 | Berksfile.lock 40 | .kitchen 41 | kitchen.local.yml 42 | vendor/ 43 | .coverage/ 44 | .zero-knife.rb 45 | Policyfile.lock.json 46 | 47 | # vagrant stuff 48 | .vagrant/ 49 | .vagrant.d/ 50 | -------------------------------------------------------------------------------- /.markdownlint-cli2.yaml: -------------------------------------------------------------------------------- 1 | config: 2 | ul-indent: false # MD007 3 | line-length: false # MD013 4 | no-duplicate-heading: false # MD024 5 | reference-links-images: false # MD052 6 | ignores: 7 | - .github/copilot-instructions.md 8 | -------------------------------------------------------------------------------- /.mdlrc: -------------------------------------------------------------------------------- 1 | rules "~MD013", "~MD024", "~MD025" 2 | -------------------------------------------------------------------------------- /.overcommit.yml: -------------------------------------------------------------------------------- 1 | --- 2 | PreCommit: 3 | TrailingWhitespace: 4 | enabled: true 5 | YamlLint: 6 | enabled: true 7 | required_executable: "yamllint" 8 | ChefSpec: 9 | enabled: true 10 | required_executable: "chef" 11 | command: ["chef", "exec", "rspec"] 12 | Cookstyle: 13 | enabled: true 14 | required_executable: "cookstyle" 15 | command: ["cookstyle"] 16 | MarkdownLint: 17 | enabled: false 18 | required_executable: "npx" 19 | command: ["npx", "markdownlint-cli2", "'**/*.md'"] 20 | include: ["**/*.md"] 21 | 22 | CommitMsg: 23 | HardTabs: 24 | enabled: true 25 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "chef-software.chef", 4 | "rebornix.ruby", 5 | "editorconfig.editorconfig", 6 | "DavidAnson.vscode-markdownlint" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | rules: 4 | line-length: 5 | max: 256 6 | level: warning 7 | document-start: disable 8 | braces: 9 | forbid: false 10 | min-spaces-inside: 0 11 | max-spaces-inside: 1 12 | min-spaces-inside-empty: -1 13 | max-spaces-inside-empty: -1 14 | comments: 15 | min-spaces-from-content: 1 16 | -------------------------------------------------------------------------------- /Berksfile: -------------------------------------------------------------------------------- 1 | source 'https://supermarket.chef.io' 2 | 3 | metadata 4 | 5 | group :integration do 6 | cookbook 'apt' 7 | cookbook 'test', path: 'test/fixtures/cookbooks/test' 8 | end 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # postfix Cookbook CHANGELOG 2 | 3 | This file is used to list changes made in each version of the postfix cookbook. 4 | 5 | ## Unreleased 6 | 7 | ## Unreleased 8 | 9 | ## 6.2.2 - *2025-01-30* 10 | 11 | ## 6.2.1 - *2025-01-30* 12 | 13 | ## 6.2.0 - *2025-01-30* 14 | 15 | ## 6.2.0 16 | 17 | - Correctly fix aliases quoting logic 18 | - Convert all serverspec tests to inspec 19 | - Add Github actions 20 | - Update platforms to test 21 | 22 | ## 6.0.29 - *2024-11-18* 23 | 24 | - Standardise files with files in sous-chefs/repo-management 25 | 26 | ## 6.0.28 - *2024-07-15* 27 | 28 | - Standardise files with files in sous-chefs/repo-management 29 | 30 | ## 6.0.27 - *2024-05-06* 31 | 32 | ## 6.0.26 - *2023-10-03* 33 | 34 | - Add installation of postfix addon packages for RHEL 8 35 | 36 | ## 6.0.25 - *2023-10-03* 37 | 38 | Fix markdown 39 | 40 | ## 6.0.24 - *2023-09-28* 41 | 42 | Standardise files with files in sous-chefs/repo-management 43 | 44 | ## 6.0.23 - *2023-09-04* 45 | 46 | Standardise files with files in sous-chefs/repo-management 47 | 48 | ## 6.0.22 - *2023-08-29* 49 | 50 | Standardise files with files in sous-chefs/repo-management 51 | 52 | ## 6.0.21 - *2023-05-17* 53 | 54 | Standardise files with files in sous-chefs/repo-management 55 | 56 | ## 6.0.20 - *2023-04-17* 57 | 58 | Fix CI permissions 59 | 60 | ## 6.0.19 - *2023-04-17* 61 | 62 | Standardise files with files in sous-chefs/repo-management 63 | 64 | ## 6.0.18 - *2023-04-07* 65 | 66 | Standardise files with files in sous-chefs/repo-management 67 | 68 | ## 6.0.17 - *2023-04-01* 69 | 70 | Standardise files with files in sous-chefs/repo-management 71 | 72 | ## 6.0.16 - *2023-04-01* 73 | 74 | Standardise files with files in sous-chefs/repo-management 75 | 76 | ## 6.0.15 - *2023-04-01* 77 | 78 | Standardise files with files in sous-chefs/repo-management 79 | 80 | ## 6.0.14 - *2023-03-20* 81 | 82 | Standardise files with files in sous-chefs/repo-management 83 | 84 | ## 6.0.13 - *2023-03-15* 85 | 86 | Standardise files with files in sous-chefs/repo-management 87 | 88 | ## 6.0.12 - *2023-02-23* 89 | 90 | Standardise files with files in sous-chefs/repo-management 91 | 92 | ## 6.0.11 - *2023-02-16* 93 | 94 | Standardise files with files in sous-chefs/repo-management 95 | 96 | ## 6.0.10 - *2023-02-14* 97 | 98 | Standardise files with files in sous-chefs/repo-management 99 | 100 | ## 6.0.9 - *2023-02-14* 101 | 102 | Standardise files with files in sous-chefs/repo-management 103 | 104 | ## 6.0.8 - *2022-12-08* 105 | 106 | Standardise files with files in sous-chefs/repo-management 107 | 108 | ## 6.0.7 - *2022-02-03* 109 | 110 | Standardise files with files in sous-chefs/repo-management 111 | 112 | ## 6.0.6 - *2022-02-02* 113 | 114 | - Update tested platforms 115 | - Remove delivery and move to calling RSpec directly via a reusable workflow 116 | 117 | ## 6.0.5 - *2022-01-08* 118 | 119 | - resolved cookstyle error: test/integration/helpers/serverspec/spec_helper.rb:9:21 convention: `Style/FileRead` 120 | 121 | ## 6.0.4 - *2021-08-19* 122 | 123 | ## 6.0.3 - *2021-08-19* 124 | 125 | - Fixed TLS configuration 126 | 127 | ## 6.0.2 - *2021-06-30* 128 | 129 | - Make sure we write the main.conf and master.conf before we try to use any commands (like postmap) 130 | 131 | ## 6.0.1 - *2021-06-01* 132 | 133 | ## 6.0.0 - *2020-11-23* 134 | 135 | - Disabled SSLv3 by default 136 | 137 | ## 5.4.1 - 2020-10-20 138 | 139 | - Ensure all postmap files are rebuilt immediately if needed 140 | 141 | ## 5.4.0 - 2020-10-11 142 | 143 | ### Changed 144 | 145 | - Sous Chefs Adoption 146 | - Update to use Sous Chefs GH workflow 147 | - Update README to sous-chefs 148 | - Update metadata.rb to Sous Chefs 149 | - Update test-kitchen to Sous Chefs 150 | 151 | ### Added 152 | 153 | - Standardise files with files in sous-chefs/repo-management 154 | - Add Ubuntu 20.04 testing 155 | 156 | ### Fixed 157 | 158 | - Cookstyle fixes 159 | - ChefSpec fixes 160 | - Yamllint fixes 161 | - MDL fixes 162 | - Fix OpenSUSE installation issues 163 | 164 | ### Removed 165 | 166 | - Remove EL 6 testing 167 | - Remove Amazon Linux 1 testing 168 | 169 | ## 5.3.1 (2018-07-24) 170 | 171 | - Fixed sbin issue with Chef13 172 | 173 | ## 5.3.0 (2018-05-23) 174 | 175 | - support multiple sasl_passwd entries 176 | - Add `packages` attribute so different postfix packages can be installed 177 | - add ability to set network connection port for a remote relayhost 178 | 179 | ## 5.2.1 (2017-11-22) 180 | 181 | - Properly support FreeBSD 182 | - Do not run service restart for solaris which fails 183 | 184 | ## 5.2.0 (2017-08-07) 185 | 186 | - Lazily evaluate the config template variables to allow overrides to properly apply 187 | - Avoid Chefspec deprecation warnings 188 | 189 | ## 5.1.1 (2017-07-28) 190 | 191 | - Fix support for Amazon Linux on Chef 13 192 | - Expand testing to cover Debian 9 in Travis 193 | 194 | ## 5.1.0 (2017-07-28) 195 | 196 | - Add an option to allow recipient canonical maps 197 | 198 | ## 5.0.3 (2017-06-26) 199 | 200 | - Correct attribute line for use_relay_restrictions_maps to prevent converge failures 201 | 202 | ## 5.0.2 (2017-05-17) 203 | 204 | - Fix use_relay_restrictions_maps attribute misspelling in attributes file 205 | 206 | ## 5.0.1 (2017-03-03) 207 | 208 | - Fix documentation error on inet-interfaces 209 | - Test with Local Delivery instead of Rake 210 | - Fix master.cf attributes types on README 211 | 212 | ## 5.0.0 (2017-01-17) 213 | 214 | - Manage any hash: tables for postfix with hash_maps recipe 215 | - Fully customizable master.cf file 216 | - Support for any kind of postfix lookup tables 217 | - Remove old minitest files 218 | - Update chef requirement in the readme 219 | - Update tests for new config comment blocks 220 | - fixing /etc/aliases syntax for full-mailaddresses 221 | 222 | ## 4.0.0 (2016-09-07) 223 | 224 | - Update supported platforms in metadata 225 | - Remove node name from config file 226 | - Testing updates 227 | - Use node.normal vs. node.set to avoid deprecation warnings 228 | - Require Chef 12+ 229 | 230 | ## v3.8.0 (2016-04-01) 231 | 232 | - Updated attributes to use node.default_unless instead of node.default to be more wrapper friendly 233 | - Added integration and unit testing in Travis CI 234 | - Added rubocop config and resolved rubocop warnings 235 | - Added Gemfile with all necessary test deps 236 | - Added standard gitignore and chefignore files 237 | - Added updated contributing and testing docs 238 | - Removed the Kitchen Digital Ocean files and dependencies 239 | - Added additional platforms to the Test Kitchen config 240 | - Added a Rakefile for simplified testing 241 | - Fixed a typo in the use_relay_restrictions_maps attribute that prevented the default from being set 242 | - Added fedora and oracle as supported platforms in the metadata 243 | - Removed the attributes from the metadata. 244 | - Added long_description to the metadata 245 | - Added Chef 11 compatibility checks to issues_url and source_url in metadata.rb 246 | - Added maintainers.md and maintainers.toml files 247 | 248 | ## v3.7.0 (2015-04-30) 249 | 250 | - Adding support for relay restrictions 251 | - Update chefspec and serverspec tests 252 | 253 | ## v3.6.2 (2014-10-31) 254 | 255 | - Fix FreeBSDisms 256 | 257 | ## v3.6.1 (2014-10-28) 258 | 259 | - Fix documentation around node['postfix']['main']['relayhost'] attribute 260 | - Fix logic around include_recipe 'postfix::virtual_aliases_domains' 261 | 262 | ## v3.6.0 (2014-08-25) 263 | 264 | - restart postfix after updating virtual alias templates #86 265 | - fixing typo for alias_db location in omnios 266 | - moving conditional attributes to a recipe so they can be modified 267 | - via other cookbook attributes 268 | 269 | ## v3.5.0 (2014-08-25) 270 | 271 | Adding virtual_domains functionality 272 | 273 | ## v3.4.1 (2014-08-20) 274 | 275 | Removing unused parameters from main.cf 276 | 277 | ## v3.4.0 (2014-07-25) 278 | 279 | Refactoring to fix some logic issues 280 | 281 | ## v3.3.1 (2014-06-11) 282 | 283 | Reverting #37 - [COOK-3418] Virtual Domain Support PR - duplicate of #55 284 | 285 | ## v3.3.0 (2014-06-11) 286 | 287 | - 37 - [COOK-3418] - Virtual Domain Support 288 | - 44 - Fix minor formatting issue in attributes 289 | - 55 - Add support for virtual aliases 290 | - 57 - Fixing attributes bug in README 291 | - 64 - add smtp_generic maps configuration option 292 | - 66 - [COOK-3652] Add support for transport mappings 293 | - 67 - [COOK-4662] Added support for access control 294 | - 68 - Properly handle binding to loopback on mixed IPV4/IPV6 systems 295 | 296 | ## v3.2.0 (2014-05-09) 297 | 298 | - [COOK-4619] - no way to unset recipient_delimiter 299 | 300 | ## v3.1.8 (2014-03-27) 301 | 302 | - [COOK-4410] - Fix sender_canonical configuration by adding template 303 | - and postmap execution 304 | 305 | ## v3.1.6 (2014-03-19) 306 | 307 | - [COOK-4423] - use platform_family, find cert.pem on rhel 308 | 309 | ## v3.1.4 (2014-02-27) 310 | 311 | [COOK-4329] Migrate minitest PITs to latest test-kitchen + serverspec 312 | 313 | ## v3.1.2 (2014-02-19) 314 | 315 | ### Bug 316 | 317 | - postfix::sasl_auth recipe fails to converge 318 | 319 | ## v3.1.0 (2014-02-19) 320 | 321 | ### Bug 322 | 323 | - Postfix cookbook has incorrect default path for sasl_passwd 324 | 325 | ### New Feature 326 | 327 | - use conf_dir attribute for sasl recipe, and add omnios support 328 | - Support creating the sender_canonical map file 329 | 330 | ## v3.0.4 331 | 332 | ### Bug 333 | 334 | - main.cf.erb mishandles lists 335 | 336 | ### Improvement 337 | 338 | - postfix cookbook readme has an incorrect example 339 | - Got rubocop errors down to 32 340 | 341 | ### New Feature 342 | 343 | - Support creating the sender_canonical map file 344 | 345 | ## v3.0.2 346 | 347 | ### Bug 348 | 349 | - Fix error when no there is no FQDN 350 | - Update `client.rb` after 3.0.0 refactor 351 | - Do not use resource cloning 352 | 353 | ### Improvement 354 | 355 | - Add SmartOS support 356 | 357 | ## v3.0.0 358 | 359 | ### Improvement 360 | 361 | - Postfix main/master and attributes refactor 362 | 363 | **Breaking changes**: 364 | 365 | - Attributes are namespaced as `node['postfix']`, `node['postfix']['main']`, and `node['postfix']['master']`. 366 | 367 | ## v2.1.6 368 | 369 | ### Bug 370 | 371 | - [COOK-2501]: Reference to `['postfix']['domain']` should be `['postfix']['mydomain']` 372 | - [COOK-2715]: master.cf uses old name for `smtp_fallback_relay` (`fallback_relay`) parameter in master.cf 373 | 374 | ## v2.1.4 375 | 376 | - [COOK-2281] - postfix aliases uses require_recipe statement 377 | 378 | ## v2.1.2 379 | 380 | - [COOK-2010] - postfix sasl_auth does not include the sasl plain package 381 | 382 | ## v2.1.0 383 | 384 | - [COOK-1233] - optional configuration for canonical maps 385 | - [COOK-1660] - allow comma separated arrays in aliases 386 | - [COOK-1662] - allow inet_interfaces configuration via attribute 387 | 388 | ## v2.0.0 389 | 390 | This version uses platform_family attribute, making the cookbook incompatible with older versions of Chef/Ohai, hence the major version bump. 391 | 392 | - [COOK-1535] - `smtpd_cache` should be in `data_directory`, not `queue_directory` 393 | - [COOK-1790] - /etc/aliases template is only in ubuntu directory 394 | - [COOK-1792] - add minitest-chef tests to postfix cookbook 395 | 396 | ## v1.2.2 397 | 398 | - [COOK-1442] - Missing ['postfix']['domain'] Attribute causes initial installation failure 399 | - [COOK-1520] - Add support for procmail delivery 400 | - [COOK-1528] - Make aliasses template less specific 401 | - [COOK-1538] - Add iptables_rule template 402 | - [COOK-1540] - Add smtpd_milters and non_smtpd_milters parameters to main.cf 403 | 404 | ## v1.2.0 405 | 406 | - [COOK-880] - add client/server roles for search-based discovery of relayhost 407 | 408 | ## v1.0.0 409 | 410 | - [COOK-668] - RHEL/CentOS/Scientific/Amazon platform support 411 | - [COOK-733] - postfix::aliases recipe to manage /etc/aliases 412 | - [COOK-821] - add README.md :) 413 | 414 | ## v0.8.4 415 | 416 | - Current public release. 417 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Guidelines 2 | 3 | This project follows the Chef Community Guidelines 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Please refer to 4 | [https://github.com/chef-cookbooks/community_cookbook_documentation/blob/main/CONTRIBUTING.MD](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/main/CONTRIBUTING.MD) 5 | -------------------------------------------------------------------------------- /Dangerfile: -------------------------------------------------------------------------------- 1 | # Reference: http://danger.systems/reference.html 2 | 3 | # A pull request summary is required. Add a description of the pull request purpose. 4 | # Changelog must be updated for each pull request that changes code. 5 | # Warnings will be issued for: 6 | # Pull request with more than 400 lines of code changed 7 | # Pull reqest that change more than 5 lines without test changes 8 | # Failures will be issued for: 9 | # Pull request without summary 10 | # Pull requests with code changes without changelog entry 11 | 12 | def code_changes? 13 | code = %w(libraries attributes recipes resources files templates) 14 | code.each do |location| 15 | return true unless git.modified_files.grep(/#{location}/).empty? 16 | end 17 | false 18 | end 19 | 20 | def test_changes? 21 | tests = %w(spec test kitchen.yml kitchen.dokken.yml) 22 | tests.each do |location| 23 | return true unless git.modified_files.grep(/#{location}/).empty? 24 | end 25 | false 26 | end 27 | 28 | failure 'Please provide a summary of your Pull Request.' if github.pr_body.length < 10 29 | 30 | warn 'This is a big Pull Request.' if git.lines_of_code > 400 31 | 32 | warn 'This is a Table Flip.' if git.lines_of_code > 2000 33 | 34 | # Require a CHANGELOG entry for non-test changes. 35 | if !git.modified_files.include?('CHANGELOG.md') && code_changes? 36 | failure 'Please include a CHANGELOG entry.' 37 | end 38 | 39 | # Require Major Minor Patch version labels 40 | unless github.pr_labels.grep /minor|major|patch/i 41 | warn 'Please add a release label to this pull request' 42 | end 43 | 44 | # A sanity check for tests. 45 | if git.lines_of_code > 5 && code_changes? && !test_changes? 46 | warn 'This Pull Request is probably missing tests.' 47 | end 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # postfix Cookbook 2 | 3 | [![Cookbook Version](https://img.shields.io/cookbook/v/postfix.svg)](https://supermarket.chef.io/cookbooks/postfix) 4 | [![CI State](https://github.com/sous-chefs/postfix/workflows/ci/badge.svg)](https://github.com/sous-chefs/postfix/actions?query=workflow%3Aci) 5 | [![OpenCollective](https://opencollective.com/sous-chefs/backers/badge.svg)](#backers) 6 | [![OpenCollective](https://opencollective.com/sous-chefs/sponsors/badge.svg)](#sponsors) 7 | [![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0) 8 | 9 | Installs and configures postfix for client or outbound relayhost, or to do SASL authentication. 10 | 11 | On RHEL-family systems, sendmail will be replaced with postfix. 12 | 13 | ## Maintainers 14 | 15 | This cookbook is maintained by the Sous Chefs. The Sous Chefs are a community of Chef cookbook maintainers working together to maintain important cookbooks. If you’d like to know more please visit [sous-chefs.org](https://sous-chefs.org/) or come chat with us on the Chef Community Slack in [#sous-chefs](https://chefcommunity.slack.com/messages/C2V7B88SF). 16 | 17 | ## Requirements 18 | 19 | ### Platforms 20 | 21 | - Ubuntu 22 | - Debian 23 | - RHEL/CentOS/Scientific 24 | - Amazon Linux (as of AMIs created after 4/9/2012) 25 | - FreeBSD 26 | 27 | May work on other platforms with or without modification. 28 | 29 | ### Chef 30 | 31 | - Chef 12.1+ 32 | 33 | ### Cookbooks 34 | 35 | - none 36 | 37 | ## Attributes 38 | 39 | See `attributes/default.rb` for default values. 40 | 41 | ### Generic cookbook attributes 42 | 43 | - `node['postfix']['mail_type']` - Sets the kind of mail configuration. `master` will set up a server (relayhost). 44 | - `node['postfix']['relayhost_role']` - name of a role used for search in the client recipe. 45 | - `node['postfix']['relayhost_port']` - listening network port of the relayhost. 46 | - `node['postfix']['multi_environment_relay']` - set to true if nodes should not constrain search for the relayhost in their own environment. 47 | - `node['postfix']['use_procmail']` - set to true if nodes should use procmail as the delivery agent. 48 | - `node['postfix']['use_alias_maps']` - set to true if you want the cookbook to use/configure alias maps 49 | - `node['postfix']['use_transport_maps']` - set to true if you want the cookbook to use/configure transport maps 50 | - `node['postfix']['use_access_maps']` - set to true if you want the cookbook to use/configure access maps 51 | - `node['postfix']['use_virtual_aliases']` - set to true if you want the cookbook to use/configure virtual alias maps 52 | - `node['postfix']['use_relay_restrictions_maps']` - set to true if you want the cookbook to use/configure a list of domains to which postfix will allow relay 53 | - `node['postfix']['aliases']` - hash of aliases to create with `recipe[postfix::aliases]`, see below under **Recipes** for more information. 54 | - `node['postfix']['transports']` - hash of transports to create with `recipe[postfix::transports]`, see below under **Recipes** for more information. 55 | - `node['postfix']['access']` - hash of access to create with `recipe[postfix::access]`, see below under **Recipes** for more information. 56 | - `node['postfix']['virtual_aliases']` - hash of virtual_aliases to create with `recipe[postfix::virtual_aliases]`, see below under **Recipes** for more information. 57 | - `node['postfix']['main_template_source']` - Cookbook source for main.cf template. Default 'postfix' 58 | - `node['postfix']['master_template_source']` - Cookbook source for master.cf template. Default 'postfix' 59 | 60 | ### main.cf and sasl_passwd template attributes 61 | 62 | The main.cf template has been simplified to include any attributes in the `node['postfix']['main']` data structure. The following attributes are still included with this cookbook to maintain some semblance of backwards compatibility. 63 | 64 | This change in namespace to `node['postfix']['main']` should allow for greater flexibility, given the large number of configuration variables for the postfix daemon. All of these cookbook attributes correspond to the option of the same name in `/etc/postfix/main.cf`. 65 | 66 | - `node['postfix']['main']['biff']` - (yes/no); default no 67 | - `node['postfix']['main']['append_dot_mydomain']` - (yes/no); default no 68 | - `node['postfix']['main']['myhostname']` - defaults to fqdn from Ohai 69 | - `node['postfix']['main']['mydomain']` - defaults to domain from Ohai 70 | - `node['postfix']['main']['myorigin']` - defaults to $myhostname 71 | - `node['postfix']['main']['mynetworks']` - default is nil, which forces Postfix to default to loopback addresses. 72 | - `node['postfix']['main']['inet_interfaces']` - set to `loopback-only`, or `all` for server recipe 73 | - `node['postfix']['main']['alias_maps']` - set to `hash:/etc/aliases` 74 | - `node['postfix']['main']['mailbox_size_limit']` - set to `0` (disabled) 75 | - `node['postfix']['main']['mydestination']` - default fqdn, hostname, localhost.localdomain, localhost 76 | - `node['postfix']['main']['smtpd_use_tls']` - (yes/no); default yes. See conditional cert/key attributes. 77 | - `node['postfix']['main']['smtpd_tls_cert_file']` - conditional attribute, set to full path of server's x509 certificate. 78 | - `node['postfix']['main']['smtpd_tls_key_file']` - conditional attribute, set to full path of server's private key 79 | - `node['postfix']['main']['smtpd_tls_CAfile']` - set to platform specific CA bundle 80 | - `node['postfix']['main']['smtpd_tls_session_cache_database']` - set to `btree:${data_directory}/smtpd_scache` 81 | - `node['postfix']['main']['smtp_use_tls']` - (yes/no); default yes. See following conditional attributes. 82 | - `node['postfix']['main']['smtp_tls_CAfile']` - set to platform specific CA bundle 83 | - `node['postfix']['main']['smtp_tls_session_cache_database']` - set to `btree:${data_directory}/smtpd_scache` 84 | - `node['postfix']['main']['smtp_sasl_auth_enable']` - (yes/no); default no. If enabled, see following conditional attributes. 85 | - `node['postfix']['main']['smtp_sasl_password_maps']` - Set to `hash:/etc/postfix/sasl_passwd` template file 86 | - `node['postfix']['main']['smtp_sasl_security_options']` - Set to noanonymous 87 | - `node['postfix']['main']['relayhost']` - Set to empty string 88 | - `node['postfix']['sender_canonical_map_entries']` - (hash with key value pairs); default not configured. Setup generic canonical maps. See `man 5 canonical`. If has at least one value, then will be enabled in config. 89 | - `node['postfix']['smtp_generic_map_entries']` - (hash with key value pairs); default not configured. Setup generic postfix maps. See `man 5 generic`. If has at least one value, then will be enabled in config. 90 | - `node['postfix']['recipient_canonical_map_entries']` - (hash with key value pairs); default not configured. Setup generic canonical maps. See `man 5 canonical`. If has at least one value, then will be enabled in config. 91 | - `node['postfix']['sasl']['smtp_sasl_user_name']` - SASL user to authenticate as. Default empty. You can only use this until the current version. The new syntax is below. 92 | - `node['postfix']['sasl']['smtp_sasl_passwd']` - SASL password to use. Default empty. You can only use this until the current version. The new syntax is below. 93 | - `node['postfix']['sasl']` = ```json { 94 | "relayhost1" => { 95 | 'username' => 'foo', 96 | 'password' => 'bar' 97 | }, 98 | "relayhost2" => { 99 | ... 100 | } 101 | }``` - You must set the following attribute, otherwise the attribute will default to empty 102 | 103 | Example of json role config, for setup *_map_entries: 104 | 105 | `postfix : {` 106 | 107 | `...` 108 | 109 | `"smtp_generic_map_entries" : { "root@youinternaldomain.local" : "admin@example.com", "admin@youinternaldomain.local" : "admin@example.com" }` 110 | 111 | `}` 112 | 113 | ### master.cf template attributes 114 | 115 | The master.cf template has been changed to allow full customization of the file content. For purpose of backwards compatibility default attributes generate the same master.cf. But via `node['postfix']['master']` data structure in your role for instance it can be completelly rewritten. 116 | 117 | Examples of json role config, for customize master.cf: 118 | 119 | `postfix : {` 120 | 121 | `...` 122 | 123 | turn some services off or on: 124 | 125 | ```json 126 | "master" : { 127 | "smtps": { 128 | "active": true 129 | }, 130 | "old-cyrus": { 131 | "active": false 132 | }, 133 | "cyrus": { 134 | "active": false 135 | }, 136 | "uucp": { 137 | "active": false 138 | }, 139 | "ifmail": { 140 | "active": false 141 | }, 142 | ``` 143 | 144 | `...` define you own service: 145 | 146 | ```json 147 | "spamfilter": { 148 | "comment": "My own spamfilter", 149 | "active": true, 150 | "order": 590, 151 | "type": "unix", 152 | "unpriv": false, 153 | "chroot": false, 154 | "command": "pipe", 155 | "args": ["flags=Rq user=spamd argv=/usr/bin/spamfilter.sh -oi -f ${sender} ${recipient}"] 156 | } 157 | ``` 158 | 159 | `...` 160 | 161 | `}` `}` 162 | 163 | The possible service hash fields and their meanings: hash key - have to be unique, unless you wish to override default definition. 164 | 165 | Field | Mandatory | Description 166 | ------- | --------- | -------------------------------------------------------------------- 167 | active | Yes | Boolean. Defines whether or not the service needs to be in master.cf 168 | comment | No | String. If you would like to add a comment line before service line 169 | order | Yes | Integer. Number to define the order of lines in the file 170 | type | Yes | String. Type of the service (inet, unix, fifo) 171 | private | No | Boolean. If present replaced by `y` or `n`, otherwise by `-` 172 | unpriv | No | Boolean. If present replaced by `y` or `n`, otherwise by `-` 173 | chroot | No | Boolean. If present replaced by `y` or `n`, otherwise by `-` 174 | wakeup | No | String. If present value placed in file, otherwise replaced by `-` 175 | maxproc | No | String. If present value placed in file, otherwise replaced by `-` 176 | command | Yes | String. The command to be executed. 177 | args | Yes | Array of Strings. Arguments passed to command. 178 | 179 | For more information about meaning of the fields consult `master (5)` manual: 180 | 181 | ## Recipes 182 | 183 | ### default 184 | 185 | Installs the postfix package and manages the service and the main configuration files (`/etc/postfix/main.cf` and `/etc/postfix/master.cf`). See **Usage** and **Examples** to see how to affect behavior of this recipe through configuration. Depending on the `node['postfix']['use_alias_maps']`, `node['postfix']['use_transport_maps']`, `node['postfix']['use_access_maps']` and `node['postfix']['use_virtual_aliases']` attributes the default recipe can call additional recipes to manage additional postfix configuration files 186 | 187 | For a more dynamic approach to discovery for the relayhost, see the `client` and `server` recipes below. 188 | 189 | ### client 190 | 191 | Use this recipe to have nodes automatically search for the mail relay based which node has the `node['postfix']['relayhost_role']` role. Sets the `node['postfix']['main']['relayhost']` attribute to the first result from the search. 192 | 193 | Includes the default recipe to install, configure and start postfix. 194 | 195 | Does not work with `chef-solo`. 196 | 197 | ### sasl_auth 198 | 199 | Sets up the system to authenticate with a remote mail relay using SASL authentication. 200 | 201 | ### server 202 | 203 | To use Chef Server search to automatically detect a node that is the relayhost, use this recipe in a role that will be relayhost. By default, the role should be "relayhost" but you can change the attribute `node['postfix']['relayhost_role']` to modify this. 204 | 205 | **Note** This recipe will set the `node['postfix']['mail_type']` to "master" with an override attribute. 206 | 207 | ### maps 208 | 209 | General recipe to manage any number of any type postfix lookup tables. You can replace with it recipes like `transport` or `virtual_aliases`, but what is more important - you can create any kinds of maps, which has no own recipe, including database lookup maps configuration. `maps` is a hash keys of which is a lookup table type and value is another hash with filenames as the keys and hash with file content as the value. File content is an any number of key/value pairs which meaning depends on lookup table type. Examlle: 210 | 211 | ```json 212 | "override_attributes": { 213 | "postfix": { 214 | "maps": { 215 | "hash": { 216 | "/etc/postfix/vmailbox": { 217 | "john@example.com": "ok", 218 | "john@example.net": "ok", 219 | }, 220 | "/etc/postfix/virtual": { 221 | "postmaster@example.com": "john@example.com", 222 | "postmaster@example.net": "john@example.net", 223 | "root@mail.example.net": "john@example.net" 224 | }, 225 | "/etc/postfix/envelope_senders": { 226 | "@example.com": "john@example.com", 227 | "@example.net": "john@example.net" 228 | }, 229 | "/etc/postfix/relay_recipients": { 230 | "john@example.net": "ok", 231 | "john@example.com": "ok", 232 | "admin@example.com": "ok", 233 | } 234 | }, 235 | "pgsql": { 236 | "/etc/postfix/pgtest": { 237 | "hosts": "db.local:2345", 238 | "user": "postfix", 239 | "password": "test", 240 | "dbname": "postdb", 241 | "query": "SELECT replacement FROM aliases WHERE mailbox = '%s'" 242 | } 243 | } 244 | } 245 | } 246 | ``` 247 | 248 | To use these files in your configuration reference them in `node['postfix']['main']`, for instance: 249 | 250 | ```json 251 | "postfix": { 252 | "main": { 253 | "smtpd_sender_login_maps": "hash:/etc/postfix/envelope_senders", 254 | "relay_recipient_maps": "hash:/etc/postfix/relay_recipients", 255 | "virtual_mailbox_maps": "hash:/etc/postfix/vmailbox", 256 | "virtual_alias_maps": "hash:/etc/postfix/virtual", 257 | } 258 | } 259 | ``` 260 | 261 | ### aliases 262 | 263 | Manage `/etc/aliases` with this recipe. Currently only Ubuntu 10.04 platform has a template for the aliases file. Add your aliases template to the `templates/default` or to the appropriate platform+version directory per the File Specificity rules for templates. Then specify a hash of aliases for the `node['postfix']['aliases']` attribute. 264 | 265 | Arrays are supported as alias values, since postfix supports comma separated values per alias, simply specify your alias as an array to use this handy feature. 266 | 267 | ### aliases 268 | 269 | Manage `/etc/aliases` with this recipe. 270 | 271 | ### transports 272 | 273 | Manage `/etc/postfix/transport` with this recipe. 274 | 275 | ### access 276 | 277 | Manage `/etc/postfix/access` with this recipe. 278 | 279 | ### virtual_aliases 280 | 281 | Manage `/etc/postfix/virtual` with this recipe. 282 | 283 | ### relay_restrictions 284 | 285 | Manage `/etc/postfix/relay_restriction` with this recipe The postfix option smtpd_relay_restrictions in main.cf will point to this hash map db. 286 | 287 | 288 | 289 | ## Usage 290 | 291 | On systems that should simply send mail directly to a relay, or out to the internet, use `recipe[postfix]` and modify the `node['postfix']['main']['relayhost']` attribute via a role. 292 | 293 | On systems that should be the MX for a domain, set the attributes accordingly and make sure the `node['postfix']['mail_type']` attribute is `master`. See **Examples** for information on how to use `recipe[postfix::server]` to do this automatically. 294 | 295 | If you need to use SASL authentication to send mail through your ISP (such as on a home network), use `postfix::sasl_auth` and set the appropriate attributes. 296 | 297 | For each of these implementations, see **Examples** for role usage. 298 | 299 | ### Examples 300 | 301 | The example roles below only have the relevant postfix usage. You may have other contents depending on what you're configuring on your systems. 302 | 303 | The `base` role is applied to all nodes in the environment. 304 | 305 | ```ruby 306 | name "base" 307 | run_list("recipe[postfix]") 308 | override_attributes( 309 | "postfix" => { 310 | "mail_type" => "client", 311 | "main" => { 312 | "mydomain" => "example.com", 313 | "myorigin" => "example.com", 314 | "relayhost" => "[smtp.example.com]", 315 | "smtp_use_tls" => "no" 316 | } 317 | } 318 | ) 319 | ``` 320 | 321 | The `relayhost` role is applied to the nodes that are relayhosts. Often this is 2 systems using a CNAME of `smtp.example.com`. 322 | 323 | ```ruby 324 | name "relayhost" 325 | run_list("recipe[postfix::server]") 326 | override_attributes( 327 | "postfix" => { 328 | "mail_type" => "master", 329 | "main" => { 330 | "mynetworks" => [ "10.3.3.0/24", "127.0.0.0/8" ], 331 | "inet_interfaces" => "all", 332 | "mydomain" => "example.com", 333 | "myorigin" => "example.com" 334 | } 335 | ) 336 | ``` 337 | 338 | The `sasl_relayhost` role is applied to the nodes that are relayhosts and require authenticating with SASL. For example this might be on a household network with an ISP that otherwise blocks direct internet access to SMTP. 339 | 340 | ```ruby 341 | name "sasl_relayhost" 342 | run_list("recipe[postfix], recipe[postfix::sasl_auth]") 343 | override_attributes( 344 | "postfix" => { 345 | "mail_type" => "master", 346 | "main" => { 347 | "mynetworks" => "10.3.3.0/24", 348 | "mydomain" => "example.com", 349 | "myorigin" => "example.com", 350 | "relayhost" => "[smtp.comcast.net]:587", 351 | "smtp_sasl_auth_enable" => "yes" 352 | }, 353 | "sasl" => { 354 | "relayhost1" => { 355 | "username" => "your_password", 356 | "password" => "your_username" 357 | }, 358 | "relayhost2" => { 359 | ... 360 | }, 361 | ... 362 | } 363 | } 364 | ) 365 | ``` 366 | 367 | For an example of using encrypted data bags to encrypt the SASL password, see the following blog post: 368 | 369 | - 370 | 371 | #### Examples using the client & server recipes 372 | 373 | If you'd like to use the more dynamic search based approach for discovery, use the server and client recipes. First, create a relayhost role. 374 | 375 | ```ruby 376 | name "relayhost" 377 | run_list("recipe[postfix::server]") 378 | override_attributes( 379 | "postfix" => { 380 | "main" => { 381 | "mynetworks" => "10.3.3.0/24", 382 | "mydomain" => "example.com", 383 | "myorigin" => "example.com" 384 | } 385 | } 386 | ) 387 | ``` 388 | 389 | Then, add the `postfix::client` recipe to the run list of your `base` role or equivalent role for postfix clients. 390 | 391 | ```ruby 392 | name "base" 393 | run_list("recipe[postfix::client]") 394 | override_attributes( 395 | "postfix" => { 396 | "mail_type" => "client", 397 | "main" => { 398 | "mydomain" => "example.com", 399 | "myorigin" => "example.com" 400 | } 401 | } 402 | ) 403 | ``` 404 | 405 | If you wish to use a different role name for the relayhost, then also set the attribute in the `base` role. For example, `postfix_master` as the role name: 406 | 407 | ```ruby 408 | name "postfix_master" 409 | description "a role for postfix master that isn't relayhost" 410 | run_list("recipe[postfix::server]") 411 | override_attributes( 412 | "postfix" => { 413 | "main" => { 414 | "mynetworks" => "10.3.3.0/24", 415 | "mydomain" => "example.com", 416 | "myorigin" => "example.com" 417 | } 418 | } 419 | ) 420 | ``` 421 | 422 | The base role would look something like this: 423 | 424 | ```ruby 425 | name "base" 426 | run_list("recipe[postfix::client]") 427 | override_attributes( 428 | "postfix" => { 429 | "relayhost_role" => "postfix_master", 430 | "mail_type" => "client", 431 | "main" => { 432 | "mydomain" => "example.com", 433 | "myorigin" => "example.com" 434 | } 435 | } 436 | ) 437 | ``` 438 | 439 | To use relay restrictions override the relay restrictions attribute in this format: 440 | 441 | ```ruby 442 | override_attributes( 443 | "postfix" => { 444 | "use_relay_restrictions_maps" => true, 445 | "relay_restrictions" => { 446 | "chef.io" => "OK", 447 | ".chef.io" => "OK", 448 | "example.com" => "OK" 449 | } 450 | } 451 | ) 452 | ``` 453 | 454 | ## Contributors 455 | 456 | This project exists thanks to all the people who [contribute.](https://opencollective.com/sous-chefs/contributors.svg?width=890&button=false) 457 | 458 | ### Backers 459 | 460 | Thank you to all our backers! 461 | 462 | ![https://opencollective.com/sous-chefs#backers](https://opencollective.com/sous-chefs/backers.svg?width=600&avatarHeight=40) 463 | 464 | ### Sponsors 465 | 466 | Support this project by becoming a sponsor. Your logo will show up here with a link to your website. 467 | 468 | ![https://opencollective.com/sous-chefs/sponsor/0/website](https://opencollective.com/sous-chefs/sponsor/0/avatar.svg?avatarHeight=100) 469 | ![https://opencollective.com/sous-chefs/sponsor/1/website](https://opencollective.com/sous-chefs/sponsor/1/avatar.svg?avatarHeight=100) 470 | ![https://opencollective.com/sous-chefs/sponsor/2/website](https://opencollective.com/sous-chefs/sponsor/2/avatar.svg?avatarHeight=100) 471 | ![https://opencollective.com/sous-chefs/sponsor/3/website](https://opencollective.com/sous-chefs/sponsor/3/avatar.svg?avatarHeight=100) 472 | ![https://opencollective.com/sous-chefs/sponsor/4/website](https://opencollective.com/sous-chefs/sponsor/4/avatar.svg?avatarHeight=100) 473 | ![https://opencollective.com/sous-chefs/sponsor/5/website](https://opencollective.com/sous-chefs/sponsor/5/avatar.svg?avatarHeight=100) 474 | ![https://opencollective.com/sous-chefs/sponsor/6/website](https://opencollective.com/sous-chefs/sponsor/6/avatar.svg?avatarHeight=100) 475 | ![https://opencollective.com/sous-chefs/sponsor/7/website](https://opencollective.com/sous-chefs/sponsor/7/avatar.svg?avatarHeight=100) 476 | ![https://opencollective.com/sous-chefs/sponsor/8/website](https://opencollective.com/sous-chefs/sponsor/8/avatar.svg?avatarHeight=100) 477 | ![https://opencollective.com/sous-chefs/sponsor/9/website](https://opencollective.com/sous-chefs/sponsor/9/avatar.svg?avatarHeight=100) 478 | -------------------------------------------------------------------------------- /TESTING.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | Please refer to [the community cookbook documentation on testing](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/main/TESTING.MD). 4 | -------------------------------------------------------------------------------- /attributes/default.rb: -------------------------------------------------------------------------------- 1 | # Author:: Joshua Timberman 2 | # Copyright:: 2009-2019, Chef Software, Inc. 3 | # License:: Apache License, Version 2.0 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | default['postfix']['packages'] = %w(postfix) 18 | 19 | # Generic cookbook attributes 20 | default['postfix']['mail_type'] = 'client' 21 | default['postfix']['relayhost_role'] = 'relayhost' 22 | default['postfix']['relayhost_port'] = '25' 23 | default['postfix']['multi_environment_relay'] = false 24 | default['postfix']['use_procmail'] = false 25 | default['postfix']['use_alias_maps'] = platform?('freebsd') 26 | default['postfix']['use_transport_maps'] = false 27 | default['postfix']['use_access_maps'] = false 28 | default['postfix']['use_virtual_aliases'] = false 29 | default['postfix']['use_virtual_aliases_domains'] = false 30 | default['postfix']['use_relay_restrictions_maps'] = false 31 | default['postfix']['transports'] = {} 32 | default['postfix']['access'] = {} 33 | default['postfix']['virtual_aliases'] = {} 34 | default['postfix']['virtual_aliases_domains'] = {} 35 | default['postfix']['main_template_source'] = 'postfix' 36 | default['postfix']['master_template_source'] = 'postfix' 37 | default['postfix']['sender_canonical_map_entries'] = {} 38 | default['postfix']['smtp_generic_map_entries'] = {} 39 | default['postfix']['recipient_canonical_map_entries'] = {} 40 | default['postfix']['access_db_type'] = 'hash' 41 | default['postfix']['aliases_db_type'] = 'hash' 42 | default['postfix']['transport_db_type'] = 'hash' 43 | default['postfix']['virtual_alias_db_type'] = 'hash' 44 | default['postfix']['virtual_alias_domains_db_type'] = 'hash' 45 | 46 | case node['platform'] 47 | when 'smartos' 48 | default['postfix']['conf_dir'] = '/opt/local/etc/postfix' 49 | default['postfix']['aliases_db'] = '/opt/local/etc/postfix/aliases' 50 | default['postfix']['transport_db'] = '/opt/local/etc/postfix/transport' 51 | default['postfix']['access_db'] = '/opt/local/etc/postfix/access' 52 | default['postfix']['virtual_alias_db'] = '/opt/local/etc/postfix/virtual' 53 | default['postfix']['virtual_alias_domains_db'] = '/opt/local/etc/postfix/virtual_domains' 54 | default['postfix']['relay_restrictions_db'] = '/opt/local/etc/postfix/relay_restrictions' 55 | when 'freebsd' 56 | default['postfix']['conf_dir'] = '/usr/local/etc/postfix' 57 | default['postfix']['aliases_db'] = '/etc/aliases' 58 | default['postfix']['transport_db'] = '/usr/local/etc/postfix/transport' 59 | default['postfix']['access_db'] = '/usr/local/etc/postfix/access' 60 | default['postfix']['virtual_alias_db'] = '/usr/local/etc/postfix/virtual' 61 | default['postfix']['virtual_alias_domains_db'] = '/usr/local/etc/postfix/virtual_domains' 62 | default['postfix']['relay_restrictions_db'] = '/etc/postfix/relay_restrictions' 63 | when 'omnios' 64 | default['postfix']['conf_dir'] = '/opt/omni/etc/postfix' 65 | default['postfix']['aliases_db'] = '/opt/omni/etc/postfix/aliases' 66 | default['postfix']['transport_db'] = '/opt/omni/etc/postfix/transport' 67 | default['postfix']['access_db'] = '/opt/omni/etc/postfix/access' 68 | default['postfix']['virtual_alias_db'] = '/etc/omni/etc/postfix/virtual' 69 | default['postfix']['virtual_alias_domains_db'] = '/etc/omni/etc/postfix/virtual_domains' 70 | default['postfix']['relay_restrictions_db'] = '/opt/omni/etc/postfix/relay_restrictions' 71 | default['postfix']['uid'] = 11 72 | else 73 | default['postfix']['conf_dir'] = '/etc/postfix' 74 | default['postfix']['aliases_db'] = '/etc/aliases' 75 | default['postfix']['transport_db'] = '/etc/postfix/transport' 76 | default['postfix']['access_db'] = '/etc/postfix/access' 77 | default['postfix']['virtual_alias_db'] = '/etc/postfix/virtual' 78 | default['postfix']['virtual_alias_domains_db'] = '/etc/postfix/virtual_domains' 79 | default['postfix']['relay_restrictions_db'] = '/etc/postfix/relay_restrictions' 80 | end 81 | 82 | # Non-default main.cf attributes 83 | default['postfix']['main']['biff'] = 'no' 84 | default['postfix']['main']['append_dot_mydomain'] = 'no' 85 | default['postfix']['main']['myhostname'] = (node['fqdn'] || node['hostname']).to_s.chomp('.') 86 | default['postfix']['main']['mydomain'] = (node['domain'] || node['hostname']).to_s.chomp('.') 87 | default['postfix']['main']['myorigin'] = '$myhostname' 88 | default['postfix']['main']['mydestination'] = [node['postfix']['main']['myhostname'], node['hostname'], 'localhost.localdomain', 'localhost'].compact 89 | default['postfix']['main']['smtpd_use_tls'] = 'yes' 90 | default['postfix']['main']['smtp_use_tls'] = 'yes' 91 | default['postfix']['main']['smtpd_tls_mandatory_protocols'] = '!SSLv2,!SSLv3' 92 | default['postfix']['main']['smtp_tls_mandatory_protocols'] = '!SSLv2,!SSLv3' 93 | default['postfix']['main']['smtpd_tls_protocols'] = '!SSLv2,!SSLv3' 94 | default['postfix']['main']['smtp_tls_protocols'] = '!SSLv2,!SSLv3' 95 | default['postfix']['main']['smtp_sasl_auth_enable'] = 'no' 96 | default['postfix']['main']['mailbox_size_limit'] = 0 97 | default['postfix']['main']['mynetworks'] = nil 98 | default['postfix']['main']['inet_interfaces'] = 'loopback-only' 99 | 100 | # Conditional attributes, also reference _attributes recipe 101 | case node['platform_family'] 102 | when 'debian' 103 | default['postfix']['cafile'] = '/etc/ssl/certs/ca-certificates.crt' 104 | when 'smartos' 105 | default['postfix']['main']['smtpd_use_tls'] = 'no' 106 | default['postfix']['main']['smtp_use_tls'] = 'no' 107 | default['postfix']['cafile'] = '/opt/local/etc/postfix/cacert.pem' 108 | when 'rhel' 109 | default['postfix']['cafile'] = '/etc/pki/tls/cert.pem' 110 | when 'amazon' 111 | default['postfix']['cafile'] = '/etc/pki/tls/cert.pem' 112 | when 'suse' 113 | default['postfix']['main']['setgid_group'] = 'maildrop' 114 | default['postfix']['main']['daemon_directory'] = '/usr/lib/postfix/bin' 115 | else 116 | default['postfix']['cafile'] = "#{node['postfix']['conf_dir']}/cacert.pem" 117 | end 118 | 119 | # # Default main.cf attributes according to `postconf -d` 120 | # default['postfix']['main']['relayhost'] = '' 121 | # default['postfix']['main']['milter_default_action'] = 'tempfail' 122 | # default['postfix']['main']['milter_protocol'] = '6' 123 | # default['postfix']['main']['smtpd_milters'] = '' 124 | # default['postfix']['main']['non_smtpd_milters'] = '' 125 | # default['postfix']['main']['sender_canonical_classes'] = nil 126 | # default['postfix']['main']['recipient_canonical_classes'] = nil 127 | # default['postfix']['main']['canonical_classes'] = nil 128 | # default['postfix']['main']['sender_canonical_maps'] = nil 129 | # default['postfix']['main']['recipient_canonical_maps'] = nil 130 | # default['postfix']['main']['canonical_maps'] = nil 131 | 132 | # Master.cf attributes 133 | default['postfix']['master']['smtp']['active'] = true 134 | default['postfix']['master']['smtp']['order'] = 10 135 | default['postfix']['master']['smtp']['type'] = 'inet' 136 | default['postfix']['master']['smtp']['private'] = false 137 | default['postfix']['master']['smtp']['chroot'] = false 138 | default['postfix']['master']['smtp']['command'] = 'smtpd' 139 | default['postfix']['master']['smtp']['args'] = [] 140 | 141 | default['postfix']['master']['submission']['active'] = false 142 | default['postfix']['master']['submission']['order'] = 20 143 | default['postfix']['master']['submission']['type'] = 'inet' 144 | default['postfix']['master']['submission']['private'] = false 145 | default['postfix']['master']['submission']['chroot'] = false 146 | default['postfix']['master']['submission']['command'] = 'smtpd' 147 | default['postfix']['master']['submission']['args'] = ['-o smtpd_enforce_tls=yes', ' -o smtpd_sasl_auth_enable=yes', '-o smtpd_client_restrictions=permit_sasl_authenticated,reject'] 148 | 149 | default['postfix']['master']['smtps']['active'] = false 150 | default['postfix']['master']['smtps']['order'] = 30 151 | default['postfix']['master']['smtps']['type'] = 'inet' 152 | default['postfix']['master']['smtps']['private'] = false 153 | default['postfix']['master']['smtps']['chroot'] = false 154 | default['postfix']['master']['smtps']['command'] = 'smtpd' 155 | default['postfix']['master']['smtps']['args'] = ['-o smtpd_tls_wrappermode=yes', '-o smtpd_sasl_auth_enable=yes', '-o smtpd_client_restrictions=permit_sasl_authenticated,reject'] 156 | 157 | default['postfix']['master']['628']['active'] = false 158 | default['postfix']['master']['628']['order'] = 40 159 | default['postfix']['master']['628']['type'] = 'inet' 160 | default['postfix']['master']['628']['private'] = false 161 | default['postfix']['master']['628']['chroot'] = false 162 | default['postfix']['master']['628']['command'] = 'qmqpdd' 163 | default['postfix']['master']['628']['args'] = [] 164 | 165 | default['postfix']['master']['pickup']['active'] = true 166 | default['postfix']['master']['pickup']['order'] = 50 167 | default['postfix']['master']['pickup']['type'] = 'fifo' 168 | default['postfix']['master']['pickup']['private'] = false 169 | default['postfix']['master']['pickup']['chroot'] = false 170 | default['postfix']['master']['pickup']['wakeup'] = '60' 171 | default['postfix']['master']['pickup']['maxproc'] = '1' 172 | default['postfix']['master']['pickup']['command'] = 'pickup' 173 | default['postfix']['master']['pickup']['args'] = [] 174 | 175 | default['postfix']['master']['cleanup']['active'] = true 176 | default['postfix']['master']['cleanup']['order'] = 60 177 | default['postfix']['master']['cleanup']['type'] = 'unix' 178 | default['postfix']['master']['cleanup']['private'] = false 179 | default['postfix']['master']['cleanup']['chroot'] = false 180 | default['postfix']['master']['cleanup']['maxproc'] = '0' 181 | default['postfix']['master']['cleanup']['command'] = 'cleanup' 182 | default['postfix']['master']['cleanup']['args'] = [] 183 | 184 | default['postfix']['master']['qmgr']['active'] = true 185 | default['postfix']['master']['qmgr']['order'] = 70 186 | default['postfix']['master']['qmgr']['type'] = 'fifo' 187 | default['postfix']['master']['qmgr']['private'] = false 188 | default['postfix']['master']['qmgr']['chroot'] = false 189 | default['postfix']['master']['qmgr']['wakeup'] = '300' 190 | default['postfix']['master']['qmgr']['maxproc'] = '1' 191 | default['postfix']['master']['qmgr']['command'] = 'qmgr' 192 | default['postfix']['master']['qmgr']['args'] = [] 193 | 194 | default['postfix']['master']['tlsmgr']['active'] = true 195 | default['postfix']['master']['tlsmgr']['order'] = 80 196 | default['postfix']['master']['tlsmgr']['type'] = 'unix' 197 | default['postfix']['master']['tlsmgr']['chroot'] = false 198 | default['postfix']['master']['tlsmgr']['wakeup'] = '1000?' 199 | default['postfix']['master']['tlsmgr']['maxproc'] = '1' 200 | default['postfix']['master']['tlsmgr']['command'] = 'tlsmgr' 201 | default['postfix']['master']['tlsmgr']['args'] = [] 202 | 203 | default['postfix']['master']['rewrite']['active'] = true 204 | default['postfix']['master']['rewrite']['order'] = 90 205 | default['postfix']['master']['rewrite']['type'] = 'unix' 206 | default['postfix']['master']['rewrite']['chroot'] = false 207 | default['postfix']['master']['rewrite']['command'] = 'trivial-rewrite' 208 | default['postfix']['master']['rewrite']['args'] = [] 209 | 210 | default['postfix']['master']['bounce']['active'] = true 211 | default['postfix']['master']['bounce']['order'] = 100 212 | default['postfix']['master']['bounce']['type'] = 'unix' 213 | default['postfix']['master']['bounce']['chroot'] = false 214 | default['postfix']['master']['bounce']['maxproc'] = '0' 215 | default['postfix']['master']['bounce']['command'] = 'bounce' 216 | default['postfix']['master']['bounce']['args'] = [] 217 | 218 | default['postfix']['master']['defer']['active'] = true 219 | default['postfix']['master']['defer']['order'] = 110 220 | default['postfix']['master']['defer']['type'] = 'unix' 221 | default['postfix']['master']['defer']['chroot'] = false 222 | default['postfix']['master']['defer']['maxproc'] = '0' 223 | default['postfix']['master']['defer']['command'] = 'bounce' 224 | default['postfix']['master']['defer']['args'] = [] 225 | 226 | default['postfix']['master']['trace']['active'] = true 227 | default['postfix']['master']['trace']['order'] = 120 228 | default['postfix']['master']['trace']['type'] = 'unix' 229 | default['postfix']['master']['trace']['chroot'] = false 230 | default['postfix']['master']['trace']['maxproc'] = '0' 231 | default['postfix']['master']['trace']['command'] = 'bounce' 232 | default['postfix']['master']['trace']['args'] = [] 233 | 234 | default['postfix']['master']['verify']['active'] = true 235 | default['postfix']['master']['verify']['order'] = 130 236 | default['postfix']['master']['verify']['type'] = 'unix' 237 | default['postfix']['master']['verify']['chroot'] = false 238 | default['postfix']['master']['verify']['maxproc'] = '1' 239 | default['postfix']['master']['verify']['command'] = 'verify' 240 | default['postfix']['master']['verify']['args'] = [] 241 | 242 | default['postfix']['master']['flush']['active'] = true 243 | default['postfix']['master']['flush']['order'] = 140 244 | default['postfix']['master']['flush']['type'] = 'unix' 245 | default['postfix']['master']['flush']['private'] = false 246 | default['postfix']['master']['flush']['chroot'] = false 247 | default['postfix']['master']['flush']['wakeup'] = '1000?' 248 | default['postfix']['master']['flush']['maxproc'] = '0' 249 | default['postfix']['master']['flush']['command'] = 'flush' 250 | default['postfix']['master']['flush']['args'] = [] 251 | 252 | default['postfix']['master']['proxymap']['active'] = true 253 | default['postfix']['master']['proxymap']['order'] = 150 254 | default['postfix']['master']['proxymap']['type'] = 'unix' 255 | default['postfix']['master']['proxymap']['chroot'] = false 256 | default['postfix']['master']['proxymap']['command'] = 'proxymap' 257 | default['postfix']['master']['proxymap']['args'] = [] 258 | 259 | default['postfix']['master']['smtpunix']['service'] = 'smtp' 260 | default['postfix']['master']['smtpunix']['active'] = true 261 | default['postfix']['master']['smtpunix']['order'] = 160 262 | default['postfix']['master']['smtpunix']['type'] = 'unix' 263 | default['postfix']['master']['smtpunix']['chroot'] = false 264 | default['postfix']['master']['smtpunix']['maxproc'] = '500' 265 | default['postfix']['master']['smtpunix']['command'] = 'smtp' 266 | default['postfix']['master']['smtpunix']['args'] = [] 267 | 268 | default['postfix']['master']['relay']['active'] = true 269 | default['postfix']['master']['relay']['comment'] = 'When relaying mail as backup MX, disable fallback_relay to avoid MX loops' 270 | default['postfix']['master']['relay']['order'] = 170 271 | default['postfix']['master']['relay']['type'] = 'unix' 272 | default['postfix']['master']['relay']['chroot'] = false 273 | default['postfix']['master']['relay']['command'] = 'smtp' 274 | default['postfix']['master']['relay']['args'] = ['-o smtp_fallback_relay='] 275 | 276 | default['postfix']['master']['showq']['active'] = true 277 | default['postfix']['master']['showq']['order'] = 180 278 | default['postfix']['master']['showq']['type'] = 'unix' 279 | default['postfix']['master']['showq']['private'] = false 280 | default['postfix']['master']['showq']['chroot'] = false 281 | default['postfix']['master']['showq']['command'] = 'showq' 282 | default['postfix']['master']['showq']['args'] = [] 283 | 284 | default['postfix']['master']['error']['active'] = true 285 | default['postfix']['master']['error']['order'] = 190 286 | default['postfix']['master']['error']['type'] = 'unix' 287 | default['postfix']['master']['error']['chroot'] = false 288 | default['postfix']['master']['error']['command'] = 'error' 289 | default['postfix']['master']['error']['args'] = [] 290 | 291 | default['postfix']['master']['discard']['active'] = true 292 | default['postfix']['master']['discard']['order'] = 200 293 | default['postfix']['master']['discard']['type'] = 'unix' 294 | default['postfix']['master']['discard']['chroot'] = false 295 | default['postfix']['master']['discard']['command'] = 'discard' 296 | default['postfix']['master']['discard']['args'] = [] 297 | 298 | default['postfix']['master']['local']['active'] = true 299 | default['postfix']['master']['local']['order'] = 210 300 | default['postfix']['master']['local']['type'] = 'unix' 301 | default['postfix']['master']['local']['unpriv'] = false 302 | default['postfix']['master']['local']['chroot'] = false 303 | default['postfix']['master']['local']['command'] = 'local' 304 | default['postfix']['master']['local']['args'] = [] 305 | 306 | default['postfix']['master']['virtual']['active'] = true 307 | default['postfix']['master']['virtual']['order'] = 220 308 | default['postfix']['master']['virtual']['type'] = 'unix' 309 | default['postfix']['master']['virtual']['unpriv'] = false 310 | default['postfix']['master']['virtual']['chroot'] = false 311 | default['postfix']['master']['virtual']['command'] = 'virtual' 312 | default['postfix']['master']['virtual']['args'] = [] 313 | 314 | default['postfix']['master']['lmtp']['active'] = true 315 | default['postfix']['master']['lmtp']['order'] = 230 316 | default['postfix']['master']['lmtp']['type'] = 'unix' 317 | default['postfix']['master']['lmtp']['chroot'] = false 318 | default['postfix']['master']['lmtp']['command'] = 'lmtp' 319 | default['postfix']['master']['lmtp']['args'] = [] 320 | 321 | default['postfix']['master']['anvil']['active'] = true 322 | default['postfix']['master']['anvil']['order'] = 240 323 | default['postfix']['master']['anvil']['type'] = 'unix' 324 | default['postfix']['master']['anvil']['chroot'] = false 325 | default['postfix']['master']['anvil']['maxproc'] = '1' 326 | default['postfix']['master']['anvil']['command'] = 'anvil' 327 | default['postfix']['master']['anvil']['args'] = [] 328 | 329 | default['postfix']['master']['scache']['active'] = true 330 | default['postfix']['master']['scache']['order'] = 250 331 | default['postfix']['master']['scache']['type'] = 'unix' 332 | default['postfix']['master']['scache']['chroot'] = false 333 | default['postfix']['master']['scache']['maxproc'] = '1' 334 | default['postfix']['master']['scache']['command'] = 'scache' 335 | default['postfix']['master']['scache']['args'] = [] 336 | 337 | default['postfix']['master']['maildrop']['active'] = true 338 | default['postfix']['master']['maildrop']['comment'] = 'See the Postfix MAILDROP_README file for details. To main.cf will be added: maildrop_destination_recipient_limit=1' 339 | default['postfix']['master']['maildrop']['order'] = 510 340 | default['postfix']['master']['maildrop']['type'] = 'unix' 341 | default['postfix']['master']['maildrop']['unpriv'] = false 342 | default['postfix']['master']['maildrop']['chroot'] = false 343 | default['postfix']['master']['maildrop']['command'] = 'pipe' 344 | default['postfix']['master']['maildrop']['args'] = ['flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d ${recipient}'] 345 | 346 | default['postfix']['master']['old-cyrus']['active'] = false 347 | default['postfix']['master']['old-cyrus']['comment'] = 'The Cyrus deliver program has changed incompatibly, multiple times.' 348 | default['postfix']['master']['old-cyrus']['order'] = 520 349 | default['postfix']['master']['old-cyrus']['type'] = 'unix' 350 | default['postfix']['master']['old-cyrus']['unpriv'] = false 351 | default['postfix']['master']['old-cyrus']['chroot'] = false 352 | default['postfix']['master']['old-cyrus']['command'] = 'pipe' 353 | default['postfix']['master']['old-cyrus']['args'] = ['flags=R user=cyrus argv=/usr/lib/cyrus-imapd/deliver -e -m ${extension} ${user}'] 354 | 355 | default['postfix']['master']['cyrus']['active'] = true 356 | default['postfix']['master']['cyrus']['comment'] = 'Cyrus 2.1.5 (Amos Gouaux). To main.cf will be added: cyrus_destination_recipient_limit=1' 357 | default['postfix']['master']['cyrus']['order'] = 530 358 | default['postfix']['master']['cyrus']['type'] = 'unix' 359 | default['postfix']['master']['cyrus']['unpriv'] = false 360 | default['postfix']['master']['cyrus']['chroot'] = false 361 | default['postfix']['master']['cyrus']['command'] = 'pipe' 362 | default['postfix']['master']['cyrus']['args'] = ['user=cyrus argv=/usr/lib/cyrus-imapd/deliver -e -r ${sender} -m ${extension} ${user}'] 363 | 364 | default['postfix']['master']['uucp']['active'] = true 365 | default['postfix']['master']['uucp']['comment'] = 'See the Postfix UUCP_README file for configuration details.' 366 | default['postfix']['master']['uucp']['order'] = 540 367 | default['postfix']['master']['uucp']['type'] = 'unix' 368 | default['postfix']['master']['uucp']['unpriv'] = false 369 | default['postfix']['master']['uucp']['chroot'] = false 370 | default['postfix']['master']['uucp']['command'] = 'pipe' 371 | default['postfix']['master']['uucp']['args'] = ['flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)'] 372 | 373 | default['postfix']['master']['ifmail']['active'] = false 374 | default['postfix']['master']['ifmail']['order'] = 550 375 | default['postfix']['master']['ifmail']['type'] = 'unix' 376 | default['postfix']['master']['ifmail']['unpriv'] = false 377 | default['postfix']['master']['ifmail']['chroot'] = false 378 | default['postfix']['master']['ifmail']['command'] = 'pipe' 379 | default['postfix']['master']['ifmail']['args'] = ['flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)'] 380 | 381 | default['postfix']['master']['bsmtp']['active'] = true 382 | default['postfix']['master']['bsmtp']['order'] = 560 383 | default['postfix']['master']['bsmtp']['type'] = 'unix' 384 | default['postfix']['master']['bsmtp']['unpriv'] = false 385 | default['postfix']['master']['bsmtp']['chroot'] = false 386 | default['postfix']['master']['bsmtp']['command'] = 'pipe' 387 | default['postfix']['master']['bsmtp']['args'] = ['flags=Fq. user=foo argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient'] 388 | 389 | # OS Aliases 390 | default['postfix']['aliases'] = if platform?('freebsd') 391 | { 392 | 'MAILER-DAEMON' => 'postmaster', 393 | 'bin' => 'root', 394 | 'daemon' => 'root', 395 | 'named' => 'root', 396 | 'nobody' => 'root', 397 | 'uucp' => 'root', 398 | 'www' => 'root', 399 | 'ftp-bugs' => 'root', 400 | 'postfix' => 'root', 401 | 'manager' => 'root', 402 | 'dumper' => 'root', 403 | 'operator' => 'root', 404 | 'abuse' => 'postmaster', 405 | } 406 | else 407 | {} 408 | end 409 | 410 | default['postfix']['main']['smtpd_relay_restrictions'] = "hash:#{node['postfix']['relay_restrictions_db']}, reject" if node['postfix']['use_relay_restrictions_maps'] 411 | -------------------------------------------------------------------------------- /chefignore: -------------------------------------------------------------------------------- 1 | # Put files/directories that should be ignored in this file when uploading 2 | # to a Chef Infra Server or Supermarket. 3 | # Lines that start with '# ' are comments. 4 | 5 | # OS generated files # 6 | ###################### 7 | .DS_Store 8 | ehthumbs.db 9 | Icon? 10 | nohup.out 11 | Thumbs.db 12 | .envrc 13 | 14 | # EDITORS # 15 | ########### 16 | .#* 17 | .project 18 | .settings 19 | *_flymake 20 | *_flymake.* 21 | *.bak 22 | *.sw[a-z] 23 | *.tmproj 24 | *~ 25 | \#* 26 | REVISION 27 | TAGS* 28 | tmtags 29 | .vscode 30 | .editorconfig 31 | 32 | ## COMPILED ## 33 | ############## 34 | *.class 35 | *.com 36 | *.dll 37 | *.exe 38 | *.o 39 | *.pyc 40 | *.so 41 | */rdoc/ 42 | a.out 43 | mkmf.log 44 | 45 | # Testing # 46 | ########### 47 | .circleci/* 48 | .codeclimate.yml 49 | .delivery/* 50 | .foodcritic 51 | .kitchen* 52 | .mdlrc 53 | .overcommit.yml 54 | .rspec 55 | .rubocop.yml 56 | .travis.yml 57 | .watchr 58 | .yamllint 59 | azure-pipelines.yml 60 | Dangerfile 61 | examples/* 62 | features/* 63 | Guardfile 64 | kitchen*.yml 65 | mlc_config.json 66 | Procfile 67 | Rakefile 68 | spec/* 69 | test/* 70 | 71 | # SCM # 72 | ####### 73 | .git 74 | .gitattributes 75 | .gitconfig 76 | .github/* 77 | .gitignore 78 | .gitkeep 79 | .gitmodules 80 | .svn 81 | */.bzr/* 82 | */.git 83 | */.hg/* 84 | */.svn/* 85 | 86 | # Berkshelf # 87 | ############# 88 | Berksfile 89 | Berksfile.lock 90 | cookbooks/* 91 | tmp 92 | 93 | # Bundler # 94 | ########### 95 | vendor/* 96 | Gemfile 97 | Gemfile.lock 98 | 99 | # Policyfile # 100 | ############## 101 | Policyfile.rb 102 | Policyfile.lock.json 103 | 104 | # Documentation # 105 | ############# 106 | CODE_OF_CONDUCT* 107 | CONTRIBUTING* 108 | documentation/* 109 | TESTING* 110 | UPGRADING* 111 | 112 | # Vagrant # 113 | ########### 114 | .vagrant 115 | Vagrantfile 116 | -------------------------------------------------------------------------------- /documentation/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sous-chefs/postfix/61a3fae922534721f095229d51bc3160ed2902fe/documentation/.gitkeep -------------------------------------------------------------------------------- /kitchen.dokken.yml: -------------------------------------------------------------------------------- 1 | driver: 2 | name: dokken 3 | privileged: true 4 | chef_version: <%= ENV['CHEF_VERSION'] || 'current' %> 5 | 6 | transport: { name: dokken } 7 | provisioner: { name: dokken } 8 | 9 | platforms: 10 | - name: almalinux-8 11 | driver: 12 | image: dokken/almalinux-8 13 | pid_one_command: /usr/lib/systemd/systemd 14 | 15 | - name: almalinux-9 16 | driver: 17 | image: dokken/almalinux-9 18 | pid_one_command: /usr/lib/systemd/systemd 19 | 20 | - name: almalinux-10 21 | driver: 22 | image: dokken/almalinux-10 23 | pid_one_command: /usr/lib/systemd/systemd 24 | 25 | - name: amazonlinux-2023 26 | driver: 27 | image: dokken/amazonlinux-2023 28 | pid_one_command: /usr/lib/systemd/systemd 29 | 30 | - name: centos-stream-9 31 | driver: 32 | image: dokken/centos-stream-9 33 | pid_one_command: /usr/lib/systemd/systemd 34 | 35 | - name: centos-stream-10 36 | driver: 37 | image: dokken/centos-stream-10 38 | pid_one_command: /usr/lib/systemd/systemd 39 | 40 | - name: debian-11 41 | driver: 42 | image: dokken/debian-11 43 | pid_one_command: /bin/systemd 44 | 45 | - name: debian-12 46 | driver: 47 | image: dokken/debian-12 48 | pid_one_command: /bin/systemd 49 | 50 | - name: fedora-latest 51 | driver: 52 | image: dokken/fedora-latest 53 | pid_one_command: /usr/lib/systemd/systemd 54 | 55 | - name: opensuse-leap-15 56 | driver: 57 | image: dokken/opensuse-leap-15 58 | pid_one_command: /usr/lib/systemd/systemd 59 | 60 | - name: oraclelinux-8 61 | driver: 62 | image: dokken/oraclelinux-8 63 | pid_one_command: /usr/lib/systemd/systemd 64 | 65 | - name: oraclelinux-9 66 | driver: 67 | image: dokken/oraclelinux-9 68 | pid_one_command: /usr/lib/systemd/systemd 69 | 70 | - name: rockylinux-8 71 | driver: 72 | image: dokken/rockylinux-8 73 | pid_one_command: /usr/lib/systemd/systemd 74 | 75 | - name: rockylinux-9 76 | driver: 77 | image: dokken/rockylinux-9 78 | pid_one_command: /usr/lib/systemd/systemd 79 | 80 | - name: ubuntu-20.04 81 | driver: 82 | image: dokken/ubuntu-20.04 83 | pid_one_command: /bin/systemd 84 | 85 | - name: ubuntu-22.04 86 | driver: 87 | image: dokken/ubuntu-22.04 88 | pid_one_command: /bin/systemd 89 | 90 | - name: ubuntu-24.04 91 | driver: 92 | image: dokken/ubuntu-24.04 93 | pid_one_command: /bin/systemd 94 | -------------------------------------------------------------------------------- /kitchen.exec.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: { name: exec } 3 | transport: { name: exec } 4 | 5 | platforms: 6 | - name: macos-latest 7 | - name: windows-latest 8 | -------------------------------------------------------------------------------- /kitchen.global.yml: -------------------------------------------------------------------------------- 1 | --- 2 | provisioner: 3 | name: chef_infra 4 | product_name: chef 5 | product_version: <%= ENV['CHEF_VERSION'] || 'latest' %> 6 | channel: stable 7 | install_strategy: once 8 | chef_license: accept 9 | enforce_idempotency: <%= ENV['ENFORCE_IDEMPOTENCY'] || true %> 10 | multiple_converge: <%= ENV['MULTIPLE_CONVERGE'] || 2 %> 11 | deprecations_as_errors: true 12 | log_level: <%= ENV['CHEF_LOG_LEVEL'] || 'auto' %> 13 | 14 | verifier: 15 | name: inspec 16 | 17 | platforms: 18 | - name: almalinux-8 19 | - name: almalinux-9 20 | - name: amazonlinux-2023 21 | - name: centos-stream-9 22 | - name: debian-11 23 | - name: debian-12 24 | - name: fedora-latest 25 | - name: opensuse-leap-15 26 | - name: oraclelinux-8 27 | - name: oraclelinux-9 28 | - name: rockylinux-8 29 | - name: rockylinux-9 30 | - name: ubuntu-20.04 31 | - name: ubuntu-22.04 32 | - name: ubuntu-24.04 33 | -------------------------------------------------------------------------------- /kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: vagrant 4 | 5 | provisioner: 6 | name: chef_infra 7 | product_name: chef 8 | enforce_idempotency: true 9 | multiple_converge: 2 10 | deprecations_as_errors: true 11 | 12 | verifier: 13 | name: inspec 14 | 15 | platforms: 16 | - name: almalinux-8 17 | - name: almalinux-9 18 | - name: amazonlinux-2023 19 | - name: centos-stream-9 20 | - name: debian-11 21 | - name: debian-12 22 | - name: fedora-latest 23 | - name: opensuse-leap-15 24 | - name: rockylinux-8 25 | - name: rockylinux-9 26 | - name: ubuntu-20.04 27 | - name: ubuntu-22.04 28 | - name: ubuntu-24.04 29 | 30 | suites: 31 | - name: default 32 | run_list: 33 | - recipe[postfix] 34 | 35 | - name: aliases 36 | run_list: 37 | - recipe[postfix::aliases] 38 | attributes: 39 | postfix: 40 | aliases: 41 | foo1: bar 42 | foo@bar: foo 43 | foo2: "|/usr/bin/bar" 44 | foo3: foo,bar 45 | foo4: foo@example.com 46 | foo5: 47 | - foo 48 | - bar 49 | 50 | - name: client 51 | run_list: 52 | - recipe[postfix::client] 53 | 54 | - name: server 55 | run_list: 56 | - recipe[postfix::server] 57 | 58 | - name: canonical 59 | run_list: 60 | - recipe[test::net_setup] 61 | - recipe[postfix] 62 | attributes: 63 | postfix: 64 | recipient_canonical_map_entries: 65 | john: john@doe.com 66 | 67 | - name: sasl_auth_none 68 | run_list: 69 | - recipe[postfix::sasl_auth] 70 | attributes: 71 | postfix: 72 | main: 73 | relayhost: "localhost" 74 | smtp_sasl_auth_enable: "yes" 75 | 76 | - name: sasl_auth_multiple 77 | run_list: 78 | - recipe[postfix::sasl_auth] 79 | attributes: 80 | postfix: 81 | main: 82 | relayhost: "localhost" 83 | smtp_sasl_auth_enable: "yes" 84 | sasl: 85 | relayhost1: 86 | username: "kitchenuser" 87 | password: "not-a-real-thing" 88 | relayhost2: 89 | username: "anotherkitchenuser" 90 | password: "yet-not-a-real-thing" 91 | 92 | - name: sasl_auth_one 93 | run_list: 94 | - recipe[postfix::sasl_auth] 95 | attributes: 96 | postfix: 97 | main: 98 | relayhost: "localhost" 99 | smtp_sasl_auth_enable: "yes" 100 | sasl: 101 | relayhost: 102 | username: "kitchenuser" 103 | password: "not-a-real-thing" 104 | -------------------------------------------------------------------------------- /metadata.rb: -------------------------------------------------------------------------------- 1 | name 'postfix' 2 | maintainer 'Sous Chefs' 3 | maintainer_email 'help@sous-chefs.org' 4 | license 'Apache-2.0' 5 | description 'Installs and configures postfix for client or outbound relayhost, or to do SASL auth' 6 | version '6.2.2' 7 | source_url 'https://github.com/sous-chefs/postfix' 8 | issues_url 'https://github.com/sous-chefs/postfix/issues' 9 | chef_version '>= 12.15' 10 | 11 | supports 'amazon' 12 | supports 'centos' 13 | supports 'debian' 14 | supports 'fedora' 15 | supports 'freebsd' 16 | supports 'oracle' 17 | supports 'redhat' 18 | supports 'scientific' 19 | supports 'smartos' 20 | supports 'ubuntu' 21 | -------------------------------------------------------------------------------- /recipes/_attributes.rb: -------------------------------------------------------------------------------- 1 | # Copyright:: 2012-2019, Chef Software, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | node.default_unless['postfix']['main']['mailbox_command'] = '/usr/bin/procmail -a "$EXTENSION"' if node['postfix']['use_procmail'] 17 | 18 | if node['postfix']['main']['smtpd_use_tls'] == 'yes' 19 | node.default_unless['postfix']['main']['smtpd_tls_cert_file'] = '/etc/ssl/certs/ssl-cert-snakeoil.pem' 20 | node.default_unless['postfix']['main']['smtpd_tls_key_file'] = '/etc/ssl/private/ssl-cert-snakeoil.key' 21 | node.default_unless['postfix']['main']['smtpd_tls_CAfile'] = node['postfix']['cafile'] 22 | node.default_unless['postfix']['main']['smtpd_tls_session_cache_database'] = 'btree:${data_directory}/smtpd_scache' 23 | end 24 | 25 | if node['postfix']['main']['smtp_use_tls'] == 'yes' 26 | node.default_unless['postfix']['main']['smtp_tls_CAfile'] = node['postfix']['cafile'] 27 | node.default_unless['postfix']['main']['smtp_tls_session_cache_database'] = 'btree:${data_directory}/smtp_scache' 28 | end 29 | 30 | if node['postfix']['main']['smtp_sasl_auth_enable'] == 'yes' 31 | node.default_unless['postfix']['sasl_password_file'] = "#{node['postfix']['conf_dir']}/sasl_passwd" 32 | node.default_unless['postfix']['main']['smtp_sasl_password_maps'] = "hash:#{node['postfix']['sasl_password_file']}" 33 | node.default_unless['postfix']['main']['smtp_sasl_security_options'] = 'noanonymous' 34 | node.default_unless['postfix']['sasl']['smtp_sasl_user_name'] = '' 35 | node.default_unless['postfix']['sasl']['smtp_sasl_passwd'] = '' 36 | node.default_unless['postfix']['main']['relayhost'] = '' 37 | end 38 | 39 | node.default_unless['postfix']['main']['alias_maps'] = ["hash:#{node['postfix']['aliases_db']}"] if node['postfix']['use_alias_maps'] 40 | 41 | node.default_unless['postfix']['main']['transport_maps'] = ["hash:#{node['postfix']['transport_db']}"] if node['postfix']['use_transport_maps'] 42 | 43 | node.default_unless['postfix']['main']['access_maps'] = ["hash:#{node['postfix']['access_db']}"] if node['postfix']['use_access_maps'] 44 | 45 | node.default_unless['postfix']['main']['virtual_alias_maps'] = ["#{node['postfix']['virtual_alias_db_type']}:#{node['postfix']['virtual_alias_db']}"] if node['postfix']['use_virtual_aliases'] 46 | 47 | node.default_unless['postfix']['main']['virtual_alias_domains'] = ["#{node['postfix']['virtual_alias_domains_db_type']}:#{node['postfix']['virtual_alias_domains_db']}"] if node['postfix']['use_virtual_aliases_domains'] 48 | 49 | node.default_unless['postfix']['main']['smtpd_relay_restrictions'] = "hash:#{node['postfix']['relay_restrictions_db']}, reject" if node['postfix']['use_relay_restrictions_maps'] 50 | 51 | node.default_unless['postfix']['main']['maildrop_destination_recipient_limit'] = 1 if node['postfix']['master']['maildrop']['active'] 52 | 53 | node.default_unless['postfix']['main']['cyrus_destination_recipient_limit'] = 1 if node['postfix']['master']['cyrus']['active'] 54 | -------------------------------------------------------------------------------- /recipes/_common.rb: -------------------------------------------------------------------------------- 1 | # Author:: Joshua Timberman() 2 | # Cookbook:: common 3 | # Recipe:: default 4 | # 5 | # Copyright:: 2009-2020, Chef Software, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | include_recipe 'postfix::_attributes' 21 | 22 | # use multi-package when we can 23 | if node['os'] == 'linux' 24 | package node['postfix']['packages'] 25 | else 26 | node['postfix']['packages'].each do |pkg| 27 | package pkg 28 | end 29 | end 30 | 31 | package 'procmail' if node['postfix']['use_procmail'] 32 | 33 | case node['platform_family'] 34 | when 'rhel', 'fedora', 'amazon' 35 | service 'sendmail' do 36 | action :nothing 37 | end 38 | 39 | execute 'switch_mailer_to_postfix' do 40 | command '/usr/sbin/alternatives --set mta /usr/sbin/sendmail.postfix' 41 | notifies :stop, 'service[sendmail]' 42 | notifies :start, 'service[postfix]' 43 | not_if '/usr/bin/test /etc/alternatives/mta -ef /usr/sbin/sendmail.postfix' 44 | end 45 | when 'suse' 46 | file '/var/adm/postfix.configured' 47 | when 'omnios' 48 | manifest_path = ::File.join(Chef::Config[:file_cache_path], 'manifest-postfix.xml') 49 | 50 | # we need to manage the postfix group and user 51 | # and then subscribe to the package install because it creates a 52 | # postdrop group and adds postfix user to it. 53 | group 'postfix' do 54 | append true 55 | end 56 | 57 | user 'postfix' do 58 | uid node['postfix']['uid'] 59 | gid 'postfix' 60 | home '/var/spool/postfix' 61 | subscribes :manage, 'package[postfix]' 62 | notifies :run, 'execute[/opt/omni/sbin/postfix set-permissions]', :immediately 63 | end 64 | 65 | # we don't guard this because if the user creation was successful (or happened out of band), then this won't get executed when the action is :nothing. 66 | execute '/opt/omni/sbin/postfix set-permissions' 67 | 68 | template manifest_path do 69 | source 'manifest-postfix.xml.erb' 70 | owner 'root' 71 | group node['root_group'] 72 | mode '0644' 73 | notifies :run, 'execute[load postfix manifest]', :immediately 74 | end 75 | 76 | execute 'load postfix manifest' do 77 | action :nothing 78 | command "svccfg import #{manifest_path}" 79 | notifies :restart, 'service[postfix]' unless platform_family?('solaris2') 80 | end 81 | when 'freebsd' 82 | # Actions are based on docs provided by FreeBSD: 83 | # https://www.freebsd.org/doc/handbook/mail-changingmta.html 84 | service 'sendmail' do 85 | action :nothing 86 | end 87 | 88 | template '/etc/mail/mailer.conf' do 89 | source 'mailer.erb' 90 | owner 'root' 91 | group 0 92 | notifies :restart, 'service[postfix]' unless platform_family?('solaris2') 93 | end 94 | 95 | execute 'switch_mailer_to_postfix' do 96 | command [ 97 | 'sysrc', 98 | 'sendmail_enable=NO', 99 | 'sendmail_submit_enable=NO', 100 | 'sendmail_outbound_enable=NO', 101 | 'sendmail_msp_queue_enable=NO', 102 | 'postfix_enable=YES', 103 | ] 104 | notifies :stop, 'service[sendmail]', :immediately 105 | notifies :disable, 'service[sendmail]', :immediately 106 | notifies :start, 'service[postfix]', :delayed 107 | only_if "sysrc sendmail_enable sendmail_submit_enable sendmail_outbound_enable sendmail_msp_queue_enable | egrep -q '(YES|unknown variable)' || sysrc postfix_enable | egrep -q '(NO|unknown variable)'" 108 | end 109 | 110 | execute 'disable_periodic' do 111 | # rubocop:disable Lint/ParenthesesAsGroupedExpression 112 | environment ({ 'RC_CONFS' => '/etc/periodic.conf' }) 113 | command [ 114 | 'sysrc', 115 | 'daily_clean_hoststat_enable=NO', 116 | 'daily_status_mail_rejects_enable=NO', 117 | 'daily_status_include_submit_mailq=NO', 118 | 'daily_submit_queuerun=NO', 119 | ] 120 | only_if "RC_CONFS=/etc/periodic.conf sysrc daily_clean_hoststat_enable daily_status_mail_rejects_enable daily_status_include_submit_mailq daily_submit_queuerun | egrep -q '(YES|unknown variable)'" 121 | end 122 | end 123 | 124 | # We need to write the config first as the below postmap immediately commands assume config is correct 125 | # Which is not the case as ipv6 is assumed to be available by the postfix package 126 | # And if someone wants to disable this first we need to update the config first aswell 127 | %w( main master ).each do |cfg| 128 | template "#{node['postfix']['conf_dir']}/#{cfg}.cf" do 129 | source "#{cfg}.cf.erb" 130 | owner 'root' 131 | group node['root_group'] 132 | mode '0644' 133 | # restart service for solaris on chef-client has a bug 134 | # unless condition can be removed after 135 | # https://github.com/chef/chef/pull/6596 merge/release 136 | notifies :restart, 'service[postfix]' unless platform_family?('solaris2') 137 | variables( 138 | lazy { { settings: node['postfix'][cfg] } } 139 | ) 140 | cookbook node['postfix']["#{cfg}_template_source"] 141 | end 142 | end 143 | 144 | execute 'update-postfix-sender_canonical' do 145 | command "postmap #{node['postfix']['conf_dir']}/sender_canonical" 146 | action :nothing 147 | end 148 | 149 | unless node['postfix']['sender_canonical_map_entries'].empty? 150 | template "#{node['postfix']['conf_dir']}/sender_canonical" do 151 | owner 'root' 152 | group node['root_group'] 153 | mode '0644' 154 | notifies :run, 'execute[update-postfix-sender_canonical]', :immediately 155 | notifies :reload, 'service[postfix]' 156 | end 157 | 158 | node.default['postfix']['main']['sender_canonical_maps'] = "hash:#{node['postfix']['conf_dir']}/sender_canonical" unless node['postfix']['main'].key?('sender_canonical_maps') 159 | end 160 | 161 | execute 'update-postfix-smtp_generic' do 162 | command "postmap #{node['postfix']['conf_dir']}/smtp_generic" 163 | action :nothing 164 | end 165 | 166 | unless node['postfix']['smtp_generic_map_entries'].empty? 167 | template "#{node['postfix']['conf_dir']}/smtp_generic" do 168 | owner 'root' 169 | group node['root_group'] 170 | mode '0644' 171 | notifies :run, 'execute[update-postfix-smtp_generic]', :immediately 172 | notifies :reload, 'service[postfix]' 173 | end 174 | 175 | node.default['postfix']['main']['smtp_generic_maps'] = "hash:#{node['postfix']['conf_dir']}/smtp_generic" unless node['postfix']['main'].key?('smtp_generic_maps') 176 | end 177 | 178 | execute 'update-postfix-recipient_canonical' do 179 | command "postmap #{node['postfix']['conf_dir']}/recipient_canonical" 180 | action :nothing 181 | end 182 | 183 | unless node['postfix']['recipient_canonical_map_entries'].empty? 184 | template "#{node['postfix']['conf_dir']}/recipient_canonical" do 185 | owner 'root' 186 | group node['root_group'] 187 | mode '0644' 188 | notifies :run, 'execute[update-postfix-recipient_canonical]', :immediately 189 | notifies :reload, 'service[postfix]' 190 | end 191 | 192 | node.default['postfix']['main']['recipient_canonical_maps'] = "hash:#{node['postfix']['conf_dir']}/recipient_canonical" unless node['postfix']['main'].key?('recipient_canonical_maps') 193 | end 194 | 195 | service 'postfix' do 196 | supports status: true, restart: true, reload: true 197 | action [:enable, :start] 198 | end 199 | -------------------------------------------------------------------------------- /recipes/access.rb: -------------------------------------------------------------------------------- 1 | # Copyright:: 2012-2019, Chef Software, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | include_recipe 'postfix::_common' 17 | 18 | execute 'update-postfix-access' do 19 | command "postmap #{node['postfix']['access_db']}" 20 | environment PATH: "#{ENV['PATH']}:/opt/omni/bin:/opt/omni/sbin" if platform_family?('omnios') 21 | action :nothing 22 | end 23 | 24 | template node['postfix']['access_db'] do 25 | source 'access.erb' 26 | notifies :run, 'execute[update-postfix-access]', :immediately 27 | end 28 | -------------------------------------------------------------------------------- /recipes/aliases.rb: -------------------------------------------------------------------------------- 1 | # Copyright:: 2012-2019, Chef Software, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | include_recipe 'postfix::_common' 17 | 18 | execute 'update-postfix-aliases' do 19 | command 'newaliases' 20 | environment PATH: "#{ENV['PATH']}:/opt/omni/bin:/opt/omni/sbin" if platform_family?('omnios') 21 | # On FreeBSD, /usr/sbin/newaliases is the sendmail command, and it's in the path before postfix's /usr/local/bin/newaliases 22 | environment('PATH' => "/usr/local/bin:#{ENV['PATH']}") if platform_family?('freebsd') 23 | action :nothing 24 | end 25 | 26 | template node['postfix']['aliases_db'] do 27 | source 'aliases.erb' 28 | notifies :run, 'execute[update-postfix-aliases]', :immediately 29 | end 30 | -------------------------------------------------------------------------------- /recipes/client.rb: -------------------------------------------------------------------------------- 1 | # Author:: Joshua Timberman() 2 | # Cookbook:: postfix 3 | # Recipe:: client 4 | # 5 | # Copyright:: 2009-2019, Chef Software, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | if Chef::Config[:solo] 21 | Chef::Log.info("#{cookbook_name}::#{recipe_name} is intended for use with Chef Server, use #{cookbook_name}::default with Chef Solo.") 22 | return 23 | end 24 | 25 | query = "role:#{node['postfix']['relayhost_role']}" 26 | relayhost = '' 27 | # if the relayhost_port attribute is not port 25, append to the relayhost 28 | relayhost_port = node['postfix']['relayhost_port'].to_s != '25' ? ":#{node['postfix']['relayhost_port']}" : '' 29 | 30 | # results = [] 31 | 32 | if node.run_list.roles.include?(node['postfix']['relayhost_role']) 33 | relayhost << node['ipaddress'] 34 | elsif node['postfix']['multi_environment_relay'] 35 | results = search(:node, query) 36 | relayhost = results.map { |n| n['ipaddress'] }.first 37 | else 38 | results = search(:node, "#{query} AND chef_environment:#{node.chef_environment}") 39 | relayhost = results.map { |n| n['ipaddress'] }.first 40 | end 41 | 42 | node.default['postfix']['main']['relayhost'] = "[#{relayhost}]#{relayhost_port}" 43 | 44 | include_recipe 'postfix' 45 | -------------------------------------------------------------------------------- /recipes/default.rb: -------------------------------------------------------------------------------- 1 | # Author:: Joshua Timberman() 2 | # Cookbook:: postfix 3 | # Recipe:: default 4 | # 5 | # Copyright:: 2009-2019, Chef Software, Inc. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | include_recipe 'postfix::_common' 21 | 22 | include_recipe 'postfix::sasl_auth' if node['postfix']['main']['smtp_sasl_auth_enable'] == 'yes' 23 | 24 | include_recipe 'postfix::aliases' if node['postfix']['use_alias_maps'] 25 | 26 | include_recipe 'postfix::transports' if node['postfix']['use_transport_maps'] 27 | 28 | include_recipe 'postfix::access' if node['postfix']['use_access_maps'] 29 | 30 | include_recipe 'postfix::virtual_aliases' if node['postfix']['use_virtual_aliases'] 31 | 32 | include_recipe 'postfix::virtual_aliases_domains' if node['postfix']['use_virtual_aliases_domains'] 33 | 34 | include_recipe 'postfix::relay_restrictions' if node['postfix']['use_relay_restrictions_maps'] 35 | 36 | include_recipe 'postfix::maps' if node['postfix']['maps'] 37 | -------------------------------------------------------------------------------- /recipes/maps.rb: -------------------------------------------------------------------------------- 1 | # Copyright:: 2012-2019, Chef Software, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | node['postfix']['maps'].each do |type, maps| 17 | if platform_family?('debian') 18 | package "postfix-#{type}" if %w(pgsql mysql ldap cdb).include?(type) 19 | end 20 | 21 | if platform?('redhat') && node['platform_version'].to_i == 8 22 | package "postfix-#{type}" if %w(pgsql mysql ldap cdb).include?(type) 23 | end 24 | 25 | separator = if %w(pgsql mysql ldap memcache sqlite).include?(type) 26 | ' = ' 27 | else 28 | ' ' 29 | end 30 | maps.each do |file, content| 31 | execute "update-postmap-#{file}" do 32 | command "postmap #{file}" 33 | environment PATH: "#{ENV['PATH']}:/opt/omni/bin:/opt/omni/sbin" if platform_family?('omnios') 34 | action :nothing 35 | end if %w(btree cdb dbm hash sdbm).include?(type) 36 | template "#{file}-#{type}" do 37 | path file 38 | source 'maps.erb' 39 | only_if "postconf -m | grep -q #{type}" 40 | variables( 41 | map: content, 42 | separator: separator 43 | ) 44 | notifies :run, "execute[update-postmap-#{file}]" if %w(btree cdb dbm hash sdbm).include?(type) 45 | notifies :restart, 'service[postfix]' 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /recipes/relay_restrictions.rb: -------------------------------------------------------------------------------- 1 | # Copyright:: 2012-2019, Chef Software, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | include_recipe 'postfix::_common' 17 | 18 | postmap_command = platform_family?('rhel') ? '/usr/sbin/postmap' : 'postmap' 19 | 20 | execute 'update-postfix-relay-restrictions' do 21 | command "#{postmap_command} #{node['postfix']['relay_restrictions_db']}" 22 | environment PATH: "#{ENV['PATH']}:/opt/omni/bin:/opt/omni/sbin" if platform_family?('omnios') 23 | action :nothing 24 | end 25 | 26 | template node['postfix']['relay_restrictions_db'] do 27 | source 'relay_restrictions.erb' 28 | notifies :run, 'execute[update-postfix-relay-restrictions]', :immediately 29 | end 30 | -------------------------------------------------------------------------------- /recipes/sasl_auth.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Joshua Timberman() 3 | # Cookbook:: postfix 4 | # Recipe:: sasl_auth 5 | # 6 | # Copyright:: 2009-2019, Chef Software, Inc. 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | include_recipe 'postfix::_common' 22 | 23 | sasl_pkgs = [] 24 | 25 | # We use case instead of value_for_platform_family because we need 26 | # version specifics for RHEL. 27 | case node['platform_family'] 28 | when 'debian' 29 | sasl_pkgs = %w(libsasl2-2 libsasl2-modules ca-certificates) 30 | when 'rhel' 31 | sasl_pkgs = %w(cyrus-sasl cyrus-sasl-plain ca-certificates) 32 | when 'amazon' 33 | sasl_pkgs = %w(cyrus-sasl cyrus-sasl-plain ca-certificates) 34 | when 'fedora' 35 | sasl_pkgs = %w(cyrus-sasl cyrus-sasl-plain ca-certificates) 36 | end 37 | 38 | sasl_pkgs.each do |pkg| 39 | package pkg 40 | end 41 | 42 | execute 'postmap-sasl_passwd' do 43 | command "postmap #{node['postfix']['sasl_password_file']}" 44 | environment 'PATH' => "#{ENV['PATH']}:/opt/omni/bin:/opt/omni/sbin" if platform_family?('omnios') 45 | action :nothing 46 | end 47 | 48 | template node['postfix']['sasl_password_file'] do 49 | sensitive true 50 | source 'sasl_passwd.erb' 51 | owner 'root' 52 | group node['root_group'] 53 | mode '400' 54 | notifies :run, 'execute[postmap-sasl_passwd]', :immediately 55 | notifies :restart, 'service[postfix]' 56 | variables(settings: node['postfix']['sasl']) 57 | end 58 | -------------------------------------------------------------------------------- /recipes/server.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Joshua Timberman() 3 | # Cookbook:: postfix 4 | # Recipe:: server 5 | # 6 | # Copyright:: 2009-2019, Chef Software, Inc. 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | node.override['postfix']['mail_type'] = 'master' 22 | node.override['postfix']['main']['inet_interfaces'] = 'all' 23 | 24 | include_recipe 'postfix' 25 | -------------------------------------------------------------------------------- /recipes/transports.rb: -------------------------------------------------------------------------------- 1 | # Copyright:: 2012-2019, Chef Software, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | include_recipe 'postfix::_common' 17 | 18 | postmap_command = platform_family?('rhel') ? '/usr/sbin/postmap' : 'postmap' 19 | 20 | execute 'update-postfix-transport' do 21 | command "#{postmap_command} #{node['postfix']['transport_db']}" 22 | environment PATH: "#{ENV['PATH']}:/opt/omni/bin:/opt/omni/sbin" if platform_family?('omnios') 23 | action :nothing 24 | end 25 | 26 | template node['postfix']['transport_db'] do 27 | source 'transport.erb' 28 | notifies :run, 'execute[update-postfix-transport]', :immediately 29 | end 30 | -------------------------------------------------------------------------------- /recipes/virtual_aliases.rb: -------------------------------------------------------------------------------- 1 | # Copyright:: 2012-2019, Chef Software, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | include_recipe 'postfix::_common' 17 | 18 | execute 'update-postfix-virtual-alias' do 19 | command "postmap #{node['postfix']['virtual_alias_db']}" 20 | environment PATH: "#{ENV['PATH']}:/opt/omni/bin:/opt/omni/sbin" if platform_family?('omnios') 21 | action :nothing 22 | end 23 | 24 | template node['postfix']['virtual_alias_db'] do 25 | source 'virtual_aliases.erb' 26 | notifies :run, 'execute[update-postfix-virtual-alias]', :immediately 27 | notifies :restart, 'service[postfix]' 28 | end 29 | -------------------------------------------------------------------------------- /recipes/virtual_aliases_domains.rb: -------------------------------------------------------------------------------- 1 | # Copyright:: 2012-2019, Chef Software, Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | include_recipe 'postfix::_common' 17 | 18 | execute 'update-postfix-virtual-alias-domains' do 19 | command "postmap #{node['postfix']['virtual_alias_domains_db']}" 20 | environment PATH: "#{ENV['PATH']}:/opt/omni/bin:/opt/omni/sbin" if platform_family?('omnios') 21 | action :nothing 22 | end 23 | 24 | template node['postfix']['virtual_alias_domains_db'] do 25 | source 'virtual_aliases_domains.erb' 26 | notifies :run, 'execute[update-postfix-virtual-alias-domains]', :immediately 27 | notifies :restart, 'service[postfix]' 28 | end 29 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:base"], 4 | "packageRules": [ 5 | { 6 | "groupName": "Actions", 7 | "matchUpdateTypes": ["minor", "patch", "pin"], 8 | "automerge": true, 9 | "addLabels": ["Release: Patch", "Skip: Announcements"] 10 | }, 11 | { 12 | "groupName": "Actions", 13 | "matchUpdateTypes": ["major"], 14 | "automerge": false, 15 | "addLabels": ["Release: Patch", "Skip: Announcements"] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /spec/default_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'postfix::default' do 4 | before do 5 | stub_command('/usr/bin/test /etc/alternatives/mta -ef /usr/sbin/sendmail.postfix').and_return(true) 6 | end 7 | 8 | context 'on Centos 8' do 9 | cached(:chef_run) do 10 | ChefSpec::SoloRunner.new(platform: 'centos', version: '8').converge(described_recipe) 11 | end 12 | 13 | it '[COOK-4423] renders file main.cf with /etc/pki/tls/cert.pem' do 14 | expect(chef_run).to render_file('/etc/postfix/main.cf').with_content(%r{smtp_tls_CAfile += +/etc/pki/tls/cert.pem}) 15 | end 16 | 17 | it '[COOK-4619] does not set recipient_delimiter' do 18 | expect(chef_run).to_not render_file('/etc/postfix/main.cf').with_content('recipient_delimiter') 19 | end 20 | end 21 | 22 | context 'on Ubuntu 20.04' do 23 | cached(:chef_run) do 24 | ChefSpec::ServerRunner.new(platform: 'ubuntu', version: 20.04).converge(described_recipe) 25 | end 26 | 27 | it '[COOK-4423] renders file main.cf with /etc/postfix/cacert.pem' do 28 | expect(chef_run).to render_file('/etc/postfix/main.cf').with_content(%r{smtp_tls_CAfile += +/etc/ssl/certs/ca-certificates.crt}) 29 | end 30 | 31 | it '[COOK-4619] does not set recipient_delimiter' do 32 | expect(chef_run).to_not render_file('/etc/postfix/main.cf').with_content('recipient_delimiter') 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/sasl_auth_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'postfix::sasl_auth' do 4 | let(:password_file) { '/etc/postfix/sasl_passwd' } 5 | 6 | cached(:chef_run) do 7 | ChefSpec::ServerRunner.new(platform: 'ubuntu', version: 16.04) do |node| 8 | node.default['postfix']['sasl_password_file'] = password_file 9 | end.converge(described_recipe) 10 | end 11 | 12 | describe 'password file template' do 13 | it 'does not display sensitive information' do 14 | expect(chef_run).to create_template(password_file).with(sensitive: true) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'chefspec' 2 | require 'chefspec/berkshelf' 3 | 4 | RSpec.configure do |config| 5 | config.color = true # Use color in STDOUT 6 | config.formatter = :documentation # Use the specified formatter 7 | config.log_level = :error # Avoid deprecation notice SPAM 8 | end 9 | -------------------------------------------------------------------------------- /spec/wrapper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | ## 4 | # Spec to ensure wrapper cookbook can correctly override 5 | # attributes using default level without _attributes 6 | # recipe clearing them. 7 | 8 | describe 'test::default' do 9 | cached(:chef_run) do 10 | ChefSpec::SoloRunner.new(platform: 'ubuntu', version: 16.04).converge(described_recipe) 11 | end 12 | 13 | describe '_attributes recipes' do 14 | it 'keeps wrapper cookbook default set attributes' do 15 | expect(chef_run.node['postfix']['main']['relayhost']).to eq('please') 16 | expect(chef_run.node['postfix']['main']['smtp_sasl_security_options']).to eq('keep') 17 | expect(chef_run.node['postfix']['sasl']['smtp_sasl_user_name']).to eq('us') 18 | expect(chef_run.node['postfix']['sasl']['smtp_sasl_passwd']).to eq('happy') 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /templates/access.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Auto-generated by Chef. Do not hand edit! 3 | # Local modifications will be overwritten. 4 | # 5 | # See man 5 access for format 6 | 7 | <% node['postfix']['access'].each do |name, value| %> 8 | <%= name %> <%= value %> 9 | <% end unless node['postfix']['access'].nil? %> 10 | -------------------------------------------------------------------------------- /templates/aliases.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Auto-generated by Chef. 3 | # Local modifications will be overwritten. 4 | # 5 | # See man 5 aliases for format 6 | postmaster: root 7 | 8 | <% node['postfix']['aliases'].each do |name, value| %> 9 | <%= name.match?(/[\s#:@]/) ? "\"#{name}\"" : name %>: <%= [value].flatten.map{|x| x.include?("|") ? "\"#{x}\"" : x}.join(',') %> 10 | <% end unless node['postfix']['aliases'].nil? %> 11 | -------------------------------------------------------------------------------- /templates/mailer.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Auto-generated by Chef. 3 | # Local modifications will be overwritten. 4 | # 5 | # Execute the Postfix sendmail program, named /usr/local/sbin/sendmail 6 | # 7 | sendmail /usr/local/sbin/sendmail 8 | send-mail /usr/local/sbin/sendmail 9 | mailq /usr/local/sbin/sendmail 10 | newaliases /usr/local/sbin/sendmail 11 | -------------------------------------------------------------------------------- /templates/main.cf.erb: -------------------------------------------------------------------------------- 1 | ### 2 | # Auto-generated by Chef. 3 | # Local modifications will be overwritten. 4 | # Configured as <%= node['postfix']['mail_type'] %> 5 | ### 6 | 7 | <% @settings.sort.map do |key, value| -%> 8 | <% next if value.nil? -%> 9 | <% if value.kind_of? Array -%> 10 | <%= "#{key} = #{value.join(', ')}"%> 11 | <% else -%> 12 | <%= "#{key} = #{value}"%> 13 | <% end -%> 14 | <% end -%> 15 | -------------------------------------------------------------------------------- /templates/manifest-postfix.xml.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 61 | 62 | 65 | 66 | 69 | 70 | 71 | 72 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /templates/maps.erb: -------------------------------------------------------------------------------- 1 | # 2 | # This file is generated by Chef. 3 | # Local changes will be overwritten 4 | # 5 | 6 | <% @map.each do |key, value| -%> 7 | <%= key %><%= @separator %><%= value %> 8 | <% end unless @map.nil? -%> 9 | -------------------------------------------------------------------------------- /templates/master.cf.erb: -------------------------------------------------------------------------------- 1 | # This file is generated by Chef. 2 | # Local changes will be overwritten 3 | # 4 | # Postfix master process configuration file. For details on the format 5 | # of the file, see the master(5) manual page (command: "man 5 master"). 6 | # 7 | # ========================================================================== 8 | # service type private unpriv chroot wakeup maxproc command + args 9 | # (yes) (yes) (yes) (never) (100) 10 | # ========================================================================== 11 | <% @settings.sort_by{|k,v| v['order']}.map do |service, properties| -%> 12 | <% next if !properties['active'] -%> 13 | <% if properties.has_key?('comment') -%> 14 | # 15 | #<%= properties['comment'] %> 16 | <% end -%> 17 | <% if properties.has_key?('service') -%> 18 | <%= properties['service'].ljust(10) -%> 19 | <% else -%> 20 | <%= service.ljust(10) -%> 21 | <% end -%> 22 | <%= properties['type'].ljust(6) -%> 23 | <% if properties.has_key?('private') -%> 24 | <% if properties['private'] -%> 25 | <% priv='y' -%> 26 | <% else -%> 27 | <% priv='n' -%> 28 | <% end -%> 29 | <% else -%> 30 | <% priv='-' -%> 31 | <% end -%> 32 | <%= priv.ljust(8) -%> 33 | <% if properties.has_key?('unpriv') -%> 34 | <% if properties['unpriv'] -%> 35 | <% unpriv='y' -%> 36 | <% else -%> 37 | <% unpriv='n' -%> 38 | <% end -%> 39 | <% else -%> 40 | <% unpriv='-' -%> 41 | <% end -%> 42 | <%= unpriv.ljust(8) -%> 43 | <% if properties.has_key?('chroot') -%> 44 | <% if properties['chroot'] -%> 45 | <% chroot='y' -%> 46 | <% else -%> 47 | <% chroot='n' -%> 48 | <% end -%> 49 | <% else -%> 50 | <% chroot='-' -%> 51 | <% end -%> 52 | <%= chroot.ljust(7) -%> 53 | <% if properties.has_key?('wakeup') -%> 54 | <%= properties['wakeup'].ljust(7) -%> 55 | <% else -%> 56 | <%= '-'.ljust(7) -%> 57 | <% end -%> 58 | <% if properties.has_key?('maxproc') -%> 59 | <%= properties['maxproc'].ljust(7) -%> 60 | <% else -%> 61 | <%= '-'.ljust(7) -%> 62 | <% end -%> 63 | <%= properties['command'] %> 64 | <% properties['args'].each do |arg| -%> 65 | <%= arg %> 66 | <% end -%> 67 | <% end -%> 68 | -------------------------------------------------------------------------------- /templates/port_smtp.erb: -------------------------------------------------------------------------------- 1 | # SMTP 2 | -A FWR -p tcp -m tcp --dport 25 -j ACCEPT 3 | -------------------------------------------------------------------------------- /templates/recipient_canonical.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Auto-generated by Chef. 3 | # Local modifications will be overwritten. 4 | # 5 | # See man 5 canonical for format 6 | 7 | <% node['postfix']['recipient_canonical_map_entries'].each do |name, value| %> 8 | <%= name %> <%= value %> 9 | <% end unless node['postfix']['recipient_canonical_map_entries'].nil? %> 10 | -------------------------------------------------------------------------------- /templates/relay_restrictions.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Auto-generated by Chef. 3 | # Local modifications will be overwritten. 4 | # 5 | # Attribute name is the domain name, Attribute value is either OK or REJECT 6 | 7 | <% node['postfix']['relay_restrictions'].each do |name, value| %> 8 | <%= name %> <%= value %> 9 | <% end unless node['postfix']['relay_restrictions'].nil? %> 10 | * REJECT 11 | -------------------------------------------------------------------------------- /templates/sasl_passwd.erb: -------------------------------------------------------------------------------- 1 | # Auto-generated by Chef. 2 | # Local modifications will be overwritten. 3 | 4 | <% if !@settings.nil? && !@settings.empty? -%> 5 | <% @settings.sort.map do |relayhost,value| -%> 6 | <%= relayhost %> <%= value['username'] %>:<%= value['password'] %> 7 | <% end -%> 8 | <% end -%> 9 | -------------------------------------------------------------------------------- /templates/sender_canonical.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Auto-generated by Chef. 3 | # Local modifications will be overwritten. 4 | # 5 | # See man 5 canonical for format 6 | 7 | <% node['postfix']['sender_canonical_map_entries'].each do |name, value| %> 8 | <%= name %> <%= value %> 9 | <% end unless node['postfix']['sender_canonical_map_entries'].nil? %> 10 | -------------------------------------------------------------------------------- /templates/smtp_generic.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Auto-generated by Chef. 3 | # Local modifications will be overwritten. 4 | # 5 | # See man 5 generic for format 6 | 7 | <% node['postfix']['smtp_generic_map_entries'].each do |name, value| %> 8 | <%= name %> <%= value %> 9 | <% end unless node['postfix']['smtp_generic_map_entries'].nil? %> 10 | -------------------------------------------------------------------------------- /templates/transport.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Auto-generated by Chef. 3 | # Local modifications will be overwritten. 4 | # 5 | # See man 5 transport for format 6 | 7 | <% node['postfix']['transports'].each do |name, value| %> 8 | <%= name %> <%= value %> 9 | <% end unless node['postfix']['transports'].nil? %> 10 | -------------------------------------------------------------------------------- /templates/virtual_aliases.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Auto-generated by Chef. 3 | # Local modifications will be overwritten. 4 | # 5 | # See man 5 virtual for format 6 | 7 | <% node['postfix']['virtual_aliases'].each do |key, value| %> 8 | <%= key %> <%= value %> 9 | <% end unless node['postfix']['virtual_aliases'].nil? %> 10 | -------------------------------------------------------------------------------- /templates/virtual_aliases_domains.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Auto-generated by Chef. 3 | # Local modifications will be overwritten. 4 | # 5 | # See man 5 virtual for format 6 | 7 | <% node['postfix']['virtual_aliases_domains'].each do |key, value| %> 8 | <%= key %> <%= value %> 9 | <% end unless node['postfix']['virtual_aliases_domains'].nil? %> 10 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/test/attributes/default.rb: -------------------------------------------------------------------------------- 1 | default['postfix']['main']['smtp_sasl_auth_enable'] = 'yes' 2 | default['postfix']['main']['relayhost'] = 'please' 3 | default['postfix']['main']['smtp_sasl_security_options'] = 'keep' 4 | default['postfix']['sasl']['smtp_sasl_user_name'] = 'us' 5 | default['postfix']['sasl']['smtp_sasl_passwd'] = 'happy' 6 | default['postfix']['sender_canonical_map_entries'] = {} 7 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/test/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'test' 2 | version '0.0.1' 3 | description 'Wrapper cookbook, used for testing only.' 4 | depends 'postfix' 5 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/test/recipes/default.rb: -------------------------------------------------------------------------------- 1 | include_recipe 'postfix' 2 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/test/recipes/net_setup.rb: -------------------------------------------------------------------------------- 1 | # sysctl missing on SUSE 2 | package 'procps' if platform_family?('suse') 3 | 4 | sysctl 'net.ipv6.conf.lo.disable_ipv6' do 5 | value 0 6 | end 7 | -------------------------------------------------------------------------------- /test/integration/aliases/controls/aliases.rb: -------------------------------------------------------------------------------- 1 | control 'aliases' do 2 | describe file '/etc/aliases' do 3 | its('content') do 4 | should cmp <<~EOF 5 | # 6 | # Auto-generated by Chef. 7 | # Local modifications will be overwritten. 8 | # 9 | # See man 5 aliases for format 10 | postmaster: root 11 | 12 | foo1: bar 13 | "foo@bar": foo 14 | foo2: "|/usr/bin/bar" 15 | foo3: foo,bar 16 | foo4: foo@example.com 17 | foo5: foo,bar 18 | EOF 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /test/integration/aliases/inspec.yml: -------------------------------------------------------------------------------- 1 | name: aliases 2 | -------------------------------------------------------------------------------- /test/integration/canonical/controls/canonical.rb: -------------------------------------------------------------------------------- 1 | recipient_canonical = 2 | case os.family 3 | when 'suse' 4 | '/etc/postfix/recipient_canonical.lmdb' 5 | else 6 | '/etc/postfix/recipient_canonical.db' 7 | end 8 | 9 | control 'canonical' do 10 | describe file recipient_canonical do 11 | it { should be_file } 12 | end 13 | 14 | describe file '/etc/postfix/main.cf' do 15 | its('content') { should match(%r{^\s*recipient_canonical_maps\s*=.*\/etc\/postfix\/recipient_canonical\s*$}) } 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /test/integration/canonical/inspec.yml: -------------------------------------------------------------------------------- 1 | name: canonical 2 | -------------------------------------------------------------------------------- /test/integration/client/controls/client.rb: -------------------------------------------------------------------------------- 1 | include_controls 'default' 2 | 3 | control 'client' do 4 | describe file '/etc/postfix/main.cf' do 5 | its('content') { should match /Configured as client/ } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/integration/client/inspec.yml: -------------------------------------------------------------------------------- 1 | name: client 2 | depends: 3 | - name: default 4 | path: test/integration/default 5 | -------------------------------------------------------------------------------- /test/integration/default/controls/default.rb: -------------------------------------------------------------------------------- 1 | control 'default' do 2 | describe package 'postfix' do 3 | it { should be_installed } 4 | end 5 | 6 | describe service 'postfix' do 7 | it { should be_enabled } 8 | it { should be_running } 9 | end 10 | 11 | describe file '/etc/postfix/main.cf' do 12 | its('content') { should match(/^# Auto-generated by Chef/) } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /test/integration/default/inspec.yml: -------------------------------------------------------------------------------- 1 | name: default 2 | -------------------------------------------------------------------------------- /test/integration/sasl_auth_multiple/controls/sasl_auth_multiple.rb: -------------------------------------------------------------------------------- 1 | control 'sasl_auth_multiple' do 2 | describe file '/etc/postfix/sasl_passwd' do 3 | its('content') do 4 | should cmp <<~EOF 5 | # Auto-generated by Chef. 6 | # Local modifications will be overwritten. 7 | 8 | relayhost1 kitchenuser:not-a-real-thing 9 | relayhost2 anotherkitchenuser:yet-not-a-real-thing 10 | smtp_sasl_passwd : 11 | smtp_sasl_user_name : 12 | EOF 13 | end 14 | end 15 | 16 | describe postfix_conf '/etc/postfix/main.cf' do 17 | its('smtp_sasl_password_maps') { should eq 'hash:/etc/postfix/sasl_passwd' } 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /test/integration/sasl_auth_multiple/inspec.yml: -------------------------------------------------------------------------------- 1 | name: sasl_auth_multiple 2 | -------------------------------------------------------------------------------- /test/integration/sasl_auth_none/controls/sasl_auth_none.rb: -------------------------------------------------------------------------------- 1 | control 'sasl_auth_none' do 2 | describe file '/etc/postfix/sasl_passwd' do 3 | its('content') do 4 | should cmp <<~EOF 5 | # Auto-generated by Chef. 6 | # Local modifications will be overwritten. 7 | 8 | smtp_sasl_passwd : 9 | smtp_sasl_user_name : 10 | EOF 11 | end 12 | end 13 | 14 | describe postfix_conf '/etc/postfix/main.cf' do 15 | its('smtp_sasl_password_maps') { should eq 'hash:/etc/postfix/sasl_passwd' } 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /test/integration/sasl_auth_none/inspec.yml: -------------------------------------------------------------------------------- 1 | name: sasl_auth_none 2 | -------------------------------------------------------------------------------- /test/integration/sasl_auth_one/controls/sasl_auth_one.rb: -------------------------------------------------------------------------------- 1 | control 'sasl_auth_one' do 2 | describe file '/etc/postfix/sasl_passwd' do 3 | its('content') do 4 | should cmp <<~EOF 5 | # Auto-generated by Chef. 6 | # Local modifications will be overwritten. 7 | 8 | relayhost kitchenuser:not-a-real-thing 9 | smtp_sasl_passwd : 10 | smtp_sasl_user_name : 11 | EOF 12 | end 13 | end 14 | 15 | describe postfix_conf '/etc/postfix/main.cf' do 16 | its('smtp_sasl_password_maps') { should eq 'hash:/etc/postfix/sasl_passwd' } 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /test/integration/sasl_auth_one/inspec.yml: -------------------------------------------------------------------------------- 1 | name: sasl_auth_one 2 | -------------------------------------------------------------------------------- /test/integration/server/controls/server.rb: -------------------------------------------------------------------------------- 1 | include_controls 'default' 2 | 3 | control 'server' do 4 | describe file '/etc/postfix/main.cf' do 5 | its('content') { should match /Configured as master/ } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/integration/server/inspec.yml: -------------------------------------------------------------------------------- 1 | name: server 2 | depends: 3 | - name: default 4 | path: test/integration/default 5 | --------------------------------------------------------------------------------