From 158a9c2fbe77793a708f6a0dde7cd454edd447dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Wed, 29 Nov 2023 22:26:29 +0100 Subject: [PATCH 01/26] Update postfix cookbook --- Berksfile | 2 +- Berksfile.lock | 4 +- cookbooks/postfix/.markdownlint-cli2.yaml | 5 + cookbooks/postfix/CHANGELOG.md | 194 +++++++++++++++-- cookbooks/postfix/CONTRIBUTING.md | 1 - cookbooks/postfix/LICENSE | 202 ++++++++++++++++++ cookbooks/postfix/MAINTAINERS.md | 15 -- cookbooks/postfix/README.md | 77 +++++-- cookbooks/postfix/attributes/default.rb | 50 +++-- cookbooks/postfix/chefignore | 115 ++++++++++ cookbooks/postfix/metadata.json | 46 +++- cookbooks/postfix/metadata.rb | 20 ++ cookbooks/postfix/recipes/_attributes.rb | 38 +--- cookbooks/postfix/recipes/_common.rb | 109 ++++++++-- cookbooks/postfix/recipes/access.rb | 4 +- cookbooks/postfix/recipes/aliases.rb | 4 +- cookbooks/postfix/recipes/client.rb | 7 +- cookbooks/postfix/recipes/default.rb | 2 +- cookbooks/postfix/recipes/maps.rb | 13 +- .../postfix/recipes/relay_restrictions.rb | 8 +- cookbooks/postfix/recipes/sasl_auth.rb | 10 +- cookbooks/postfix/recipes/server.rb | 2 +- cookbooks/postfix/recipes/transports.rb | 8 +- cookbooks/postfix/recipes/virtual_aliases.rb | 4 +- .../recipes/virtual_aliases_domains.rb | 4 +- cookbooks/postfix/renovate.json | 17 ++ .../templates/{default => }/access.erb | 0 .../templates/{default => }/aliases.erb | 0 .../postfix/templates/default/sasl_passwd.erb | 4 - cookbooks/postfix/templates/mailer.erb | 10 + .../templates/{default => }/main.cf.erb | 0 .../{default => }/manifest-postfix.xml.erb | 0 .../postfix/templates/{default => }/maps.erb | 0 .../templates/{default => }/master.cf.erb | 0 .../templates/{default => }/port_smtp.erb | 0 .../postfix/templates/recipient_canonical.erb | 9 + .../{default => }/relay_restrictions.erb | 0 cookbooks/postfix/templates/sasl_passwd.erb | 8 + .../{default => }/sender_canonical.erb | 0 .../templates/{default => }/smtp_generic.erb | 0 .../templates/{default => }/transport.erb | 0 .../{default => }/virtual_aliases.erb | 0 .../{default => }/virtual_aliases_domains.erb | 0 43 files changed, 836 insertions(+), 156 deletions(-) create mode 100644 cookbooks/postfix/.markdownlint-cli2.yaml delete mode 100644 cookbooks/postfix/CONTRIBUTING.md create mode 100644 cookbooks/postfix/LICENSE delete mode 100644 cookbooks/postfix/MAINTAINERS.md create mode 100644 cookbooks/postfix/chefignore create mode 100644 cookbooks/postfix/metadata.rb create mode 100644 cookbooks/postfix/renovate.json rename cookbooks/postfix/templates/{default => }/access.erb (100%) rename cookbooks/postfix/templates/{default => }/aliases.erb (100%) delete mode 100644 cookbooks/postfix/templates/default/sasl_passwd.erb create mode 100644 cookbooks/postfix/templates/mailer.erb rename cookbooks/postfix/templates/{default => }/main.cf.erb (100%) rename cookbooks/postfix/templates/{default => }/manifest-postfix.xml.erb (100%) rename cookbooks/postfix/templates/{default => }/maps.erb (100%) rename cookbooks/postfix/templates/{default => }/master.cf.erb (100%) rename cookbooks/postfix/templates/{default => }/port_smtp.erb (100%) create mode 100644 cookbooks/postfix/templates/recipient_canonical.erb rename cookbooks/postfix/templates/{default => }/relay_restrictions.erb (100%) create mode 100644 cookbooks/postfix/templates/sasl_passwd.erb rename cookbooks/postfix/templates/{default => }/sender_canonical.erb (100%) rename cookbooks/postfix/templates/{default => }/smtp_generic.erb (100%) rename cookbooks/postfix/templates/{default => }/transport.erb (100%) rename cookbooks/postfix/templates/{default => }/virtual_aliases.erb (100%) rename cookbooks/postfix/templates/{default => }/virtual_aliases_domains.erb (100%) diff --git a/Berksfile b/Berksfile index eef1c52..ec09e0e 100644 --- a/Berksfile +++ b/Berksfile @@ -32,7 +32,7 @@ cookbook 'ntp', '= 3.4.0' cookbook 'ohai', '~> 5.2.5' cookbook 'openssl', '~> 8.5.5' cookbook 'php', '~> 8.0.0' -cookbook 'postfix', '= 5.0.2' +cookbook 'postfix', '~> 6.0.26' cookbook 'timezone_iii', '= 1.0.4' cookbook 'ulimit', '~> 1.0.0' cookbook 'users', '~> 5.3.1' diff --git a/Berksfile.lock b/Berksfile.lock index f15885a..cf6ade6 100644 --- a/Berksfile.lock +++ b/Berksfile.lock @@ -28,7 +28,7 @@ DEPENDENCIES ohai (~> 5.2.5) openssl (~> 8.5.5) php (~> 8.0.0) - postfix (= 5.0.2) + postfix (~> 6.0.26) redisio (~> 6.4.1) ruby_build (~> 2.5.0) timezone_iii (= 1.0.4) @@ -89,7 +89,7 @@ GRAPH openssl (8.5.5) php (8.0.1) yum-epel (>= 0.0.0) - postfix (5.0.2) + postfix (6.0.26) redisio (6.4.1) selinux (>= 0.0.0) ruby_build (2.5.0) diff --git a/cookbooks/postfix/.markdownlint-cli2.yaml b/cookbooks/postfix/.markdownlint-cli2.yaml new file mode 100644 index 0000000..6fa8e77 --- /dev/null +++ b/cookbooks/postfix/.markdownlint-cli2.yaml @@ -0,0 +1,5 @@ +config: + ul-indent: false # MD007 + line-length: false # MD013 + no-duplicate-heading: false # MD024 + reference-links-images: false # MD052 diff --git a/cookbooks/postfix/CHANGELOG.md b/cookbooks/postfix/CHANGELOG.md index 415b74c..1b7f2b2 100644 --- a/cookbooks/postfix/CHANGELOG.md +++ b/cookbooks/postfix/CHANGELOG.md @@ -2,6 +2,176 @@ This file is used to list changes made in each version of the postfix cookbook. +## 6.0.26 - *2023-10-03* + +- add installation of postfix addon packages for RHEL 8 + +## 6.0.25 - *2023-10-03* + +Fix markdown + +## 6.0.24 - *2023-09-28* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.23 - *2023-09-04* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.22 - *2023-08-29* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.21 - *2023-05-17* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.20 - *2023-04-17* + +Fix CI permissions + +## 6.0.19 - *2023-04-17* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.18 - *2023-04-07* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.17 - *2023-04-01* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.16 - *2023-04-01* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.15 - *2023-04-01* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.14 - *2023-03-20* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.13 - *2023-03-15* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.12 - *2023-02-23* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.11 - *2023-02-16* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.10 - *2023-02-14* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.9 - *2023-02-14* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.8 - *2022-12-08* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.7 - *2022-02-03* + +Standardise files with files in sous-chefs/repo-management + +## 6.0.6 - *2022-02-02* + +- Update tested platforms +- Remove delivery and move to calling RSpec directly via a reusable workflow + +## 6.0.5 - *2022-01-08* + +- resolved cookstyle error: test/integration/helpers/serverspec/spec_helper.rb:9:21 convention: `Style/FileRead` + +## 6.0.4 - *2021-08-19* + +## 6.0.3 - *2021-08-19* + +- Fixed TLS configuration + +## 6.0.2 - *2021-06-30* + +- Make sure we write the main.conf and master.conf before we try to use any commands (like postmap) + +## 6.0.1 - *2021-06-01* + +## 6.0.0 - *2020-11-23* + +- Disabled SSLv3 by default + +## 5.4.1 - 2020-10-20 + +- Ensure all postmap files are rebuilt immediately if needed + +## 5.4.0 - 2020-10-11 + +### Changed + +- Sous Chefs Adoption +- Update to use Sous Chefs GH workflow +- Update README to sous-chefs +- Update metadata.rb to Sous Chefs +- Update test-kitchen to Sous Chefs + +### Added + +- Standardise files with files in sous-chefs/repo-management +- Add Ubuntu 20.04 testing + +### Fixed + +- Cookstyle fixes +- ChefSpec fixes +- Yamllint fixes +- MDL fixes +- Fix OpenSUSE installation issues + +### Removed + +- Remove EL 6 testing +- Remove Amazon Linux 1 testing + +## 5.3.1 (2018-07-24) + +- Fixed sbin issue with Chef13 + +## 5.3.0 (2018-05-23) + +- support multiple sasl_passwd entries +- Add `packages` attribute so different postfix packages can be installed +- add ability to set network connection port for a remote relayhost + +## 5.2.1 (2017-11-22) + +- Properly support FreeBSD +- Do not run service restart for solaris which fails + +## 5.2.0 (2017-08-07) + +- Lazily evaluate the config template variables to allow overrides to properly apply +- Avoid Chefspec deprecation warnings + +## 5.1.1 (2017-07-28) + +- Fix support for Amazon Linux on Chef 13 +- Expand testing to cover Debian 9 in Travis + +## 5.1.0 (2017-07-28) + +- Add an option to allow recipient canonical maps + +## 5.0.3 (2017-06-26) + +- Correct attribute line for use_relay_restrictions_maps to prevent converge failures + ## 5.0.2 (2017-05-17) - Fix use_relay_restrictions_maps attribute misspelling in attributes file @@ -117,51 +287,51 @@ Reverting #37 - [COOK-3418] Virtual Domain Support PR - duplicate of #55 ### Bug -- **[COOK-4357](https://tickets.chef.io/browse/COOK-4357)** - postfix::sasl_auth recipe fails to converge +- postfix::sasl_auth recipe fails to converge ## v3.1.0 (2014-02-19) ### Bug -- **[COOK-4322](https://tickets.chef.io/browse/COOK-4322)** - Postfix cookbook has incorrect default path for sasl_passwd +- Postfix cookbook has incorrect default path for sasl_passwd ### New Feature -- **[COOK-4086](https://tickets.chef.io/browse/COOK-4086)** - use conf_dir attribute for sasl recipe, and add omnios support -- **[COOK-2551](https://tickets.chef.io/browse/COOK-2551)** - Support creating the sender_canonical map file +- use conf_dir attribute for sasl recipe, and add omnios support +- Support creating the sender_canonical map file ## v3.0.4 ### Bug -- **[COOK-3824](https://tickets.chef.io/browse/COOK-3824)** - main.cf.erb mishandles lists +- main.cf.erb mishandles lists ### Improvement -- **[COOK-3822](https://tickets.chef.io/browse/COOK-3822)** - postfix cookbook readme has an incorrect example +- postfix cookbook readme has an incorrect example - Got rubocop errors down to 32 ### New Feature -- **[COOK-2551](https://tickets.chef.io/browse/COOK-2551)** - Support creating the sender_canonical map file +- Support creating the sender_canonical map file ## v3.0.2 ### Bug -- **[COOK-3617](https://tickets.chef.io/browse/COOK-3617)** - Fix error when no there is no FQDN -- **[COOK-3530](https://tickets.chef.io/browse/COOK-3530)** - Update `client.rb` after 3.0.0 refactor -- **[COOK-2499](https://tickets.chef.io/browse/COOK-2499)** - Do not use resource cloning +- Fix error when no there is no FQDN +- Update `client.rb` after 3.0.0 refactor +- Do not use resource cloning ### Improvement -- **[COOK-3116](https://tickets.chef.io/browse/COOK-3116)** - Add SmartOS support +- Add SmartOS support ## v3.0.0 ### Improvement -- **[COOK-3328](https://tickets.chef.io/browse/COOK-3328)** - Postfix main/master and attributes refactor +- Postfix main/master and attributes refactor **Breaking changes**: diff --git a/cookbooks/postfix/CONTRIBUTING.md b/cookbooks/postfix/CONTRIBUTING.md deleted file mode 100644 index cd21578..0000000 --- a/cookbooks/postfix/CONTRIBUTING.md +++ /dev/null @@ -1 +0,0 @@ -Please refer to diff --git a/cookbooks/postfix/LICENSE b/cookbooks/postfix/LICENSE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/cookbooks/postfix/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/cookbooks/postfix/MAINTAINERS.md b/cookbooks/postfix/MAINTAINERS.md deleted file mode 100644 index 645ed14..0000000 --- a/cookbooks/postfix/MAINTAINERS.md +++ /dev/null @@ -1,15 +0,0 @@ - - -# Maintainers - -This file lists how this cookbook project is maintained. When making changes to the system, this file tells you who needs to review your patch - you need a review from an existing maintainer for the cookbook to provide a :+1: on your pull request. Additionally, you need to not receive a veto from a Lieutenant or the Project Lead. - -Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) for details on the process and how to become a maintainer or the project lead. - -# Project Maintainer -* [Tim Smith](https://github.com/tas50) - -# Maintainers -* [Jennifer Davis](https://github.com/sigje) -* [Tim Smith](https://github.com/tas50) -* [Thom May](https://github.com/thommay) diff --git a/cookbooks/postfix/README.md b/cookbooks/postfix/README.md index 3531da4..e7dc535 100644 --- a/cookbooks/postfix/README.md +++ b/cookbooks/postfix/README.md @@ -1,19 +1,28 @@ # postfix Cookbook -[![Build Status](https://travis-ci.org/chef-cookbooks/postfix.svg?branch=master)](https://travis-ci.org/chef-cookbooks/postfix) [![Cookbook Version](https://img.shields.io/cookbook/v/postfix.svg)](https://supermarket.chef.io/cookbooks/postfix) +[![Cookbook Version](https://img.shields.io/cookbook/v/postfix.svg)](https://supermarket.chef.io/cookbooks/postfix) +[![CI State](https://github.com/sous-chefs/postfix/workflows/ci/badge.svg)](https://github.com/sous-chefs/postfix/actions?query=workflow%3Aci) +[![OpenCollective](https://opencollective.com/sous-chefs/backers/badge.svg)](#backers) +[![OpenCollective](https://opencollective.com/sous-chefs/sponsors/badge.svg)](#sponsors) +[![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0) Installs and configures postfix for client or outbound relayhost, or to do SASL authentication. On RHEL-family systems, sendmail will be replaced with postfix. +## Maintainers + +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). + ## Requirements ### Platforms -- Ubuntu 12.04+ -- Debian 7.0+ -- RHEL/CentOS/Scientific 5.7+, 6.2+ +- Ubuntu +- Debian +- RHEL/CentOS/Scientific - Amazon Linux (as of AMIs created after 4/9/2012) +- FreeBSD May work on other platforms with or without modification. @@ -33,6 +42,7 @@ See `attributes/default.rb` for default values. - `node['postfix']['mail_type']` - Sets the kind of mail configuration. `master` will set up a server (relayhost). - `node['postfix']['relayhost_role']` - name of a role used for search in the client recipe. +- `node['postfix']['relayhost_port']` - listening network port of the relayhost. - `node['postfix']['multi_environment_relay']` - set to true if nodes should not constrain search for the relayhost in their own environment. - `node['postfix']['use_procmail']` - set to true if nodes should use procmail as the delivery agent. - `node['postfix']['use_alias_maps']` - set to true if you want the cookbook to use/configure alias maps @@ -43,7 +53,7 @@ See `attributes/default.rb` for default values. - `node['postfix']['aliases']` - hash of aliases to create with `recipe[postfix::aliases]`, see below under **Recipes** for more information. - `node['postfix']['transports']` - hash of transports to create with `recipe[postfix::transports]`, see below under **Recipes** for more information. - `node['postfix']['access']` - hash of access to create with `recipe[postfix::access]`, see below under **Recipes** for more information. -- `node['postfix']['virtual_aliases']` - hash of virtual_aliases to create with `recipe[postfix::virtual_aliases]`, see below under __Recipes__ for more information. +- `node['postfix']['virtual_aliases']` - hash of virtual_aliases to create with `recipe[postfix::virtual_aliases]`, see below under **Recipes** for more information. - `node['postfix']['main_template_source']` - Cookbook source for main.cf template. Default 'postfix' - `node['postfix']['master_template_source']` - Cookbook source for master.cf template. Default 'postfix' @@ -75,10 +85,20 @@ This change in namespace to `node['postfix']['main']` should allow for greater f - `node['postfix']['main']['smtp_sasl_password_maps']` - Set to `hash:/etc/postfix/sasl_passwd` template file - `node['postfix']['main']['smtp_sasl_security_options']` - Set to noanonymous - `node['postfix']['main']['relayhost']` - Set to empty string -- `node['postfix']['sasl']['smtp_sasl_user_name']` - SASL user to authenticate as. Default empty -- `node['postfix']['sasl']['smtp_sasl_passwd']` - SASL password to use. Default empty. - `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. - `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. +- `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. +- `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. +- `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. +- `node['postfix']['sasl']` = ```json { + "relayhost1" => { + 'username' => 'foo', + 'password' => 'bar' + }, + "relayhost2" => { + ... + } + }``` - You must set the following attribute, otherwise the attribute will default to empty Example of json role config, for setup *_map_entries: @@ -331,8 +351,14 @@ override_attributes( "smtp_sasl_auth_enable" => "yes" }, "sasl" => { - "smtp_sasl_passwd" => "your_password", - "smtp_sasl_user_name" => "your_username" + "relayhost1" => { + "username" => "your_password", + "password" => "your_username" + }, + "relayhost2" => { + ... + }, + ... } } ) @@ -425,22 +451,27 @@ override_attributes( ) ``` -## License & Authors +## Contributors -**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io)) +This project exists thanks to all the people who [contribute.](https://opencollective.com/sous-chefs/contributors.svg?width=890&button=false) -**Copyright:** 2009-2016, Chef Software, Inc. +### Backers -``` -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +Thank you to all our backers! - http://www.apache.org/licenses/LICENSE-2.0 +![https://opencollective.com/sous-chefs#backers](https://opencollective.com/sous-chefs/backers.svg?width=600&avatarHeight=40) -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -``` +### Sponsors + +Support this project by becoming a sponsor. Your logo will show up here with a link to your website. + +![https://opencollective.com/sous-chefs/sponsor/0/website](https://opencollective.com/sous-chefs/sponsor/0/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/1/website](https://opencollective.com/sous-chefs/sponsor/1/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/2/website](https://opencollective.com/sous-chefs/sponsor/2/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/3/website](https://opencollective.com/sous-chefs/sponsor/3/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/4/website](https://opencollective.com/sous-chefs/sponsor/4/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/5/website](https://opencollective.com/sous-chefs/sponsor/5/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/6/website](https://opencollective.com/sous-chefs/sponsor/6/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/7/website](https://opencollective.com/sous-chefs/sponsor/7/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/8/website](https://opencollective.com/sous-chefs/sponsor/8/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/9/website](https://opencollective.com/sous-chefs/sponsor/9/avatar.svg?avatarHeight=100) diff --git a/cookbooks/postfix/attributes/default.rb b/cookbooks/postfix/attributes/default.rb index d467072..6ec3d88 100644 --- a/cookbooks/postfix/attributes/default.rb +++ b/cookbooks/postfix/attributes/default.rb @@ -1,5 +1,5 @@ # Author:: Joshua Timberman -# Copyright:: 2009-2017, Chef Software, Inc. +# Copyright:: 2009-2019, Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,12 +14,15 @@ # See the License for the specific language governing permissions and # limitations under the License. +default['postfix']['packages'] = %w(postfix) + # Generic cookbook attributes default['postfix']['mail_type'] = 'client' default['postfix']['relayhost_role'] = 'relayhost' +default['postfix']['relayhost_port'] = '25' default['postfix']['multi_environment_relay'] = false default['postfix']['use_procmail'] = false -default['postfix']['use_alias_maps'] = (node['platform'] == 'freebsd') +default['postfix']['use_alias_maps'] = platform?('freebsd') default['postfix']['use_transport_maps'] = false default['postfix']['use_access_maps'] = false default['postfix']['use_virtual_aliases'] = false @@ -33,6 +36,7 @@ default['postfix']['main_template_source'] = 'postfix' default['postfix']['master_template_source'] = 'postfix' default['postfix']['sender_canonical_map_entries'] = {} default['postfix']['smtp_generic_map_entries'] = {} +default['postfix']['recipient_canonical_map_entries'] = {} default['postfix']['access_db_type'] = 'hash' default['postfix']['aliases_db_type'] = 'hash' default['postfix']['transport_db_type'] = 'hash' @@ -84,6 +88,10 @@ default['postfix']['main']['myorigin'] = '$myhostname' default['postfix']['main']['mydestination'] = [node['postfix']['main']['myhostname'], node['hostname'], 'localhost.localdomain', 'localhost'].compact default['postfix']['main']['smtpd_use_tls'] = 'yes' default['postfix']['main']['smtp_use_tls'] = 'yes' +default['postfix']['main']['smtpd_tls_mandatory_protocols'] = '!SSLv2,!SSLv3' +default['postfix']['main']['smtp_tls_mandatory_protocols'] = '!SSLv2,!SSLv3' +default['postfix']['main']['smtpd_tls_protocols'] = '!SSLv2,!SSLv3' +default['postfix']['main']['smtp_tls_protocols'] = '!SSLv2,!SSLv3' default['postfix']['main']['smtp_sasl_auth_enable'] = 'no' default['postfix']['main']['mailbox_size_limit'] = 0 default['postfix']['main']['mynetworks'] = nil @@ -99,6 +107,11 @@ when 'smartos' default['postfix']['cafile'] = '/opt/local/etc/postfix/cacert.pem' when 'rhel' default['postfix']['cafile'] = '/etc/pki/tls/cert.pem' +when 'amazon' + default['postfix']['cafile'] = '/etc/pki/tls/cert.pem' +when 'suse' + default['postfix']['main']['setgid_group'] = 'maildrop' + default['postfix']['main']['daemon_directory'] = '/usr/lib/postfix/bin' else default['postfix']['cafile'] = "#{node['postfix']['conf_dir']}/cacert.pem" end @@ -374,27 +387,24 @@ default['postfix']['master']['bsmtp']['command'] = 'pipe' default['postfix']['master']['bsmtp']['args'] = ['flags=Fq. user=foo argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient'] # OS Aliases -default['postfix']['aliases'] = case node['platform'] - when 'freebsd' +default['postfix']['aliases'] = if platform?('freebsd') { - 'MAILER-DAEMON' => 'postmaster', - 'bin' => 'root', - 'daemon' => 'root', - 'named' => 'root', - 'nobody' => 'root', - 'uucp' => 'root', - 'www' => 'root', - 'ftp-bugs' => 'root', - 'postfix' => 'root', - 'manager' => 'root', - 'dumper' => 'root', - 'operator' => 'root', - 'abuse' => 'postmaster', + 'MAILER-DAEMON' => 'postmaster', + 'bin' => 'root', + 'daemon' => 'root', + 'named' => 'root', + 'nobody' => 'root', + 'uucp' => 'root', + 'www' => 'root', + 'ftp-bugs' => 'root', + 'postfix' => 'root', + 'manager' => 'root', + 'dumper' => 'root', + 'operator' => 'root', + 'abuse' => 'postmaster', } else {} end -if node['postfix']['use_relay_restrictions_maps'] - default['postfix']['main']['smtpd_relay_restrictions'] = "hash:#{node['postfix']['relay_restrictions_db']}, reject" -end +default['postfix']['main']['smtpd_relay_restrictions'] = "hash:#{node['postfix']['relay_restrictions_db']}, reject" if node['postfix']['use_relay_restrictions_maps'] diff --git a/cookbooks/postfix/chefignore b/cookbooks/postfix/chefignore new file mode 100644 index 0000000..a27b0b2 --- /dev/null +++ b/cookbooks/postfix/chefignore @@ -0,0 +1,115 @@ +# Put files/directories that should be ignored in this file when uploading +# to a Chef Infra Server or Supermarket. +# Lines that start with '# ' are comments. + +# OS generated files # +###################### +.DS_Store +ehthumbs.db +Icon? +nohup.out +Thumbs.db +.envrc + +# EDITORS # +########### +.#* +.project +.settings +*_flymake +*_flymake.* +*.bak +*.sw[a-z] +*.tmproj +*~ +\#* +REVISION +TAGS* +tmtags +.vscode +.editorconfig + +## COMPILED ## +############## +*.class +*.com +*.dll +*.exe +*.o +*.pyc +*.so +*/rdoc/ +a.out +mkmf.log + +# Testing # +########### +.circleci/* +.codeclimate.yml +.delivery/* +.foodcritic +.kitchen* +.mdlrc +.overcommit.yml +.rspec +.rubocop.yml +.travis.yml +.watchr +.yamllint +azure-pipelines.yml +Dangerfile +examples/* +features/* +Guardfile +kitchen*.yml +mlc_config.json +Procfile +Rakefile +spec/* +test/* + +# SCM # +####### +.git +.gitattributes +.gitconfig +.github/* +.gitignore +.gitkeep +.gitmodules +.svn +*/.bzr/* +*/.git +*/.hg/* +*/.svn/* + +# Berkshelf # +############# +Berksfile +Berksfile.lock +cookbooks/* +tmp + +# Bundler # +########### +vendor/* +Gemfile +Gemfile.lock + +# Policyfile # +############## +Policyfile.rb +Policyfile.lock.json + +# Documentation # +############# +CODE_OF_CONDUCT* +CONTRIBUTING* +documentation/* +TESTING* +UPGRADING* + +# Vagrant # +########### +.vagrant +Vagrantfile diff --git a/cookbooks/postfix/metadata.json b/cookbooks/postfix/metadata.json index e535f33..1bbe467 100644 --- a/cookbooks/postfix/metadata.json +++ b/cookbooks/postfix/metadata.json @@ -1 +1,45 @@ -{"name":"postfix","version":"5.0.2","description":"Installs and configures postfix for client or outbound relayhost, or to do SASL auth","long_description":"# postfix Cookbook\n\n[![Build Status](https://travis-ci.org/chef-cookbooks/postfix.svg?branch=master)](https://travis-ci.org/chef-cookbooks/postfix) [![Cookbook Version](https://img.shields.io/cookbook/v/postfix.svg)](https://supermarket.chef.io/cookbooks/postfix)\n\nInstalls and configures postfix for client or outbound relayhost, or to do SASL authentication.\n\nOn RHEL-family systems, sendmail will be replaced with postfix.\n\n## Requirements\n\n### Platforms\n\n- Ubuntu 12.04+\n- Debian 7.0+\n- RHEL/CentOS/Scientific 5.7+, 6.2+\n- Amazon Linux (as of AMIs created after 4/9/2012)\n\nMay work on other platforms with or without modification.\n\n### Chef\n\n- Chef 12.1+\n\n### Cookbooks\n\n- none\n\n## Attributes\n\nSee `attributes/default.rb` for default values.\n\n### Generic cookbook attributes\n\n- `node['postfix']['mail_type']` - Sets the kind of mail configuration. `master` will set up a server (relayhost).\n- `node['postfix']['relayhost_role']` - name of a role used for search in the client recipe.\n- `node['postfix']['multi_environment_relay']` - set to true if nodes should not constrain search for the relayhost in their own environment.\n- `node['postfix']['use_procmail']` - set to true if nodes should use procmail as the delivery agent.\n- `node['postfix']['use_alias_maps']` - set to true if you want the cookbook to use/configure alias maps\n- `node['postfix']['use_transport_maps']` - set to true if you want the cookbook to use/configure transport maps\n- `node['postfix']['use_access_maps']` - set to true if you want the cookbook to use/configure access maps\n- `node['postfix']['use_virtual_aliases']` - set to true if you want the cookbook to use/configure virtual alias maps\n- `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\n- `node['postfix']['aliases']` - hash of aliases to create with `recipe[postfix::aliases]`, see below under **Recipes** for more information.\n- `node['postfix']['transports']` - hash of transports to create with `recipe[postfix::transports]`, see below under **Recipes** for more information.\n- `node['postfix']['access']` - hash of access to create with `recipe[postfix::access]`, see below under **Recipes** for more information.\n- `node['postfix']['virtual_aliases']` - hash of virtual_aliases to create with `recipe[postfix::virtual_aliases]`, see below under __Recipes__ for more information.\n- `node['postfix']['main_template_source']` - Cookbook source for main.cf template. Default 'postfix'\n- `node['postfix']['master_template_source']` - Cookbook source for master.cf template. Default 'postfix'\n\n### main.cf and sasl_passwd template attributes\n\nThe 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.\n\nThis 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`.\n\n- `node['postfix']['main']['biff']` - (yes/no); default no\n- `node['postfix']['main']['append_dot_mydomain']` - (yes/no); default no\n- `node['postfix']['main']['myhostname']` - defaults to fqdn from Ohai\n- `node['postfix']['main']['mydomain']` - defaults to domain from Ohai\n- `node['postfix']['main']['myorigin']` - defaults to $myhostname\n- `node['postfix']['main']['mynetworks']` - default is nil, which forces Postfix to default to loopback addresses.\n- `node['postfix']['main']['inet_interfaces']` - set to `loopback-only`, or `all` for server recipe\n- `node['postfix']['main']['alias_maps']` - set to `hash:/etc/aliases`\n- `node['postfix']['main']['mailbox_size_limit']` - set to `0` (disabled)\n- `node['postfix']['main']['mydestination']` - default fqdn, hostname, localhost.localdomain, localhost\n- `node['postfix']['main']['smtpd_use_tls']` - (yes/no); default yes. See conditional cert/key attributes.\n- `node['postfix']['main']['smtpd_tls_cert_file']` - conditional attribute, set to full path of server's x509 certificate.\n- `node['postfix']['main']['smtpd_tls_key_file']` - conditional attribute, set to full path of server's private key\n- `node['postfix']['main']['smtpd_tls_CAfile']` - set to platform specific CA bundle\n- `node['postfix']['main']['smtpd_tls_session_cache_database']` - set to `btree:${data_directory}/smtpd_scache`\n- `node['postfix']['main']['smtp_use_tls']` - (yes/no); default yes. See following conditional attributes.\n- `node['postfix']['main']['smtp_tls_CAfile']` - set to platform specific CA bundle\n- `node['postfix']['main']['smtp_tls_session_cache_database']` - set to `btree:${data_directory}/smtpd_scache`\n- `node['postfix']['main']['smtp_sasl_auth_enable']` - (yes/no); default no. If enabled, see following conditional attributes.\n- `node['postfix']['main']['smtp_sasl_password_maps']` - Set to `hash:/etc/postfix/sasl_passwd` template file\n- `node['postfix']['main']['smtp_sasl_security_options']` - Set to noanonymous\n- `node['postfix']['main']['relayhost']` - Set to empty string\n- `node['postfix']['sasl']['smtp_sasl_user_name']` - SASL user to authenticate as. Default empty\n- `node['postfix']['sasl']['smtp_sasl_passwd']` - SASL password to use. Default empty.\n- `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.\n- `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.\n\nExample of json role config, for setup *_map_entries:\n\n`postfix : {`\n\n`...`\n\n`\"smtp_generic_map_entries\" : { \"root@youinternaldomain.local\" : \"admin@example.com\", \"admin@youinternaldomain.local\" : \"admin@example.com\" }`\n\n`}`\n\n### master.cf template attributes\n\nThe 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.\n\nExamples of json role config, for customize master.cf:\n\n`postfix : {`\n\n`...`\n\nturn some services off or on:\n\n```json\n \"master\" : {\n \"smtps\": {\n \"active\": true\n },\n \"old-cyrus\": {\n \"active\": false\n },\n \"cyrus\": {\n \"active\": false\n },\n \"uucp\": {\n \"active\": false\n },\n \"ifmail\": {\n \"active\": false\n },\n```\n\n`...` define you own service:\n\n```json\n \"spamfilter\": {\n \"comment\": \"My own spamfilter\",\n \"active\": true,\n \"order\": 590,\n \"type\": \"unix\",\n \"unpriv\": false,\n \"chroot\": false,\n \"command\": \"pipe\",\n \"args\": [\"flags=Rq user=spamd argv=/usr/bin/spamfilter.sh -oi -f ${sender} ${recipient}\"]\n }\n```\n\n`...`\n\n`}` `}`\n\nThe possible service hash fields and their meanings: hash key - have to be unique, unless you wish to override default definition.\n\nField | Mandatory | Description\n------- | --------- | --------------------------------------------------------------------\nactive | Yes | Boolean. Defines whether or not the service needs to be in master.cf\ncomment | No | String. If you would like to add a comment line before service line\norder | Yes | Integer. Number to define the order of lines in the file\ntype | Yes | String. Type of the service (inet, unix, fifo)\nprivate | No | Boolean. If present replaced by `y` or `n`, otherwise by `-`\nunpriv | No | Boolean. If present replaced by `y` or `n`, otherwise by `-`\nchroot | No | Boolean. If present replaced by `y` or `n`, otherwise by `-`\nwakeup | No | String. If present value placed in file, otherwise replaced by `-`\nmaxproc | No | String. If present value placed in file, otherwise replaced by `-`\ncommand | Yes | String. The command to be executed.\nargs | Yes | Array of Strings. Arguments passed to command.\n\nFor more information about meaning of the fields consult `master (5)` manual: \n\n## Recipes\n\n### default\n\nInstalls 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\n\nFor a more dynamic approach to discovery for the relayhost, see the `client` and `server` recipes below.\n\n### client\n\nUse 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.\n\nIncludes the default recipe to install, configure and start postfix.\n\nDoes not work with `chef-solo`.\n\n### sasl_auth\n\nSets up the system to authenticate with a remote mail relay using SASL authentication.\n\n### server\n\nTo 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.\n\n**Note** This recipe will set the `node['postfix']['mail_type']` to \"master\" with an override attribute.\n\n### maps\n\nGeneral 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:\n\n```json\n \"override_attributes\": {\n \"postfix\": {\n \"maps\": {\n \"hash\": {\n \"/etc/postfix/vmailbox\": {\n \"john@example.com\": \"ok\",\n \"john@example.net\": \"ok\",\n },\n \"/etc/postfix/virtual\": {\n \"postmaster@example.com\": \"john@example.com\",\n \"postmaster@example.net\": \"john@example.net\",\n \"root@mail.example.net\": \"john@example.net\"\n },\n \"/etc/postfix/envelope_senders\": {\n \"@example.com\": \"john@example.com\",\n \"@example.net\": \"john@example.net\"\n },\n \"/etc/postfix/relay_recipients\": {\n \"john@example.net\": \"ok\",\n \"john@example.com\": \"ok\",\n \"admin@example.com\": \"ok\",\n }\n },\n \"pgsql\": {\n \"/etc/postfix/pgtest\": {\n \"hosts\": \"db.local:2345\",\n \"user\": \"postfix\",\n \"password\": \"test\",\n \"dbname\": \"postdb\",\n \"query\": \"SELECT replacement FROM aliases WHERE mailbox = '%s'\"\n }\n }\n }\n }\n```\n\nTo use these files in your configuration reference them in `node['postfix']['main']`, for instance:\n\n```json\n \"postfix\": {\n \"main\": {\n \"smtpd_sender_login_maps\": \"hash:/etc/postfix/envelope_senders\",\n \"relay_recipient_maps\": \"hash:/etc/postfix/relay_recipients\",\n \"virtual_mailbox_maps\": \"hash:/etc/postfix/vmailbox\",\n \"virtual_alias_maps\": \"hash:/etc/postfix/virtual\",\n }\n }\n```\n\n### aliases\n\nManage `/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.\n\nArrays 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.\n\n### aliases\n\nManage `/etc/aliases` with this recipe.\n\n### transports\n\nManage `/etc/postfix/transport` with this recipe.\n\n### access\n\nManage `/etc/postfix/access` with this recipe.\n\n### virtual_aliases\n\nManage `/etc/postfix/virtual` with this recipe.\n\n### relay_restrictions\n\nManage `/etc/postfix/relay_restriction` with this recipe The postfix option smtpd_relay_restrictions in main.cf will point to this hash map db.\n\n\n\n## Usage\n\nOn 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.\n\nOn 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.\n\nIf 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.\n\nFor each of these implementations, see **Examples** for role usage.\n\n### Examples\n\nThe example roles below only have the relevant postfix usage. You may have other contents depending on what you're configuring on your systems.\n\nThe `base` role is applied to all nodes in the environment.\n\n```ruby\nname \"base\"\nrun_list(\"recipe[postfix]\")\noverride_attributes(\n \"postfix\" => {\n \"mail_type\" => \"client\",\n \"main\" => {\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\",\n \"relayhost\" => \"[smtp.example.com]\",\n \"smtp_use_tls\" => \"no\"\n }\n }\n)\n```\n\nThe `relayhost` role is applied to the nodes that are relayhosts. Often this is 2 systems using a CNAME of `smtp.example.com`.\n\n```ruby\nname \"relayhost\"\nrun_list(\"recipe[postfix::server]\")\noverride_attributes(\n \"postfix\" => {\n \"mail_type\" => \"master\",\n \"main\" => {\n \"mynetworks\" => [ \"10.3.3.0/24\", \"127.0.0.0/8\" ],\n \"inet_interfaces\" => \"all\",\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n)\n```\n\nThe `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.\n\n```ruby\nname \"sasl_relayhost\"\nrun_list(\"recipe[postfix], recipe[postfix::sasl_auth]\")\noverride_attributes(\n \"postfix\" => {\n \"mail_type\" => \"master\",\n \"main\" => {\n \"mynetworks\" => \"10.3.3.0/24\",\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\",\n \"relayhost\" => \"[smtp.comcast.net]:587\",\n \"smtp_sasl_auth_enable\" => \"yes\"\n },\n \"sasl\" => {\n \"smtp_sasl_passwd\" => \"your_password\",\n \"smtp_sasl_user_name\" => \"your_username\"\n }\n }\n)\n```\n\nFor an example of using encrypted data bags to encrypt the SASL password, see the following blog post:\n\n- \n\n#### Examples using the client & server recipes\n\nIf you'd like to use the more dynamic search based approach for discovery, use the server and client recipes. First, create a relayhost role.\n\n```ruby\nname \"relayhost\"\nrun_list(\"recipe[postfix::server]\")\noverride_attributes(\n \"postfix\" => {\n \"main\" => {\n \"mynetworks\" => \"10.3.3.0/24\",\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n }\n)\n```\n\nThen, add the `postfix::client` recipe to the run list of your `base` role or equivalent role for postfix clients.\n\n```ruby\nname \"base\"\nrun_list(\"recipe[postfix::client]\")\noverride_attributes(\n \"postfix\" => {\n \"mail_type\" => \"client\",\n \"main\" => {\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n }\n)\n```\n\nIf 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:\n\n```ruby\nname \"postfix_master\"\ndescription \"a role for postfix master that isn't relayhost\"\nrun_list(\"recipe[postfix::server]\")\noverride_attributes(\n \"postfix\" => {\n \"main\" => {\n \"mynetworks\" => \"10.3.3.0/24\",\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n }\n)\n```\n\nThe base role would look something like this:\n\n```ruby\nname \"base\"\nrun_list(\"recipe[postfix::client]\")\noverride_attributes(\n \"postfix\" => {\n \"relayhost_role\" => \"postfix_master\",\n \"mail_type\" => \"client\",\n \"main\" => {\n \"mydomain\" => \"example.com\",\n \"myorigin\" => \"example.com\"\n }\n }\n)\n```\n\nTo use relay restrictions override the relay restrictions attribute in this format:\n\n```ruby\noverride_attributes(\n \"postfix\" => {\n \"use_relay_restrictions_maps\" => true,\n \"relay_restrictions\" => {\n \"chef.io\" => \"OK\",\n \".chef.io\" => \"OK\",\n \"example.com\" => \"OK\"\n }\n }\n)\n```\n\n## License & Authors\n\n**Author:** Cookbook Engineering Team ([cookbooks@chef.io](mailto:cookbooks@chef.io))\n\n**Copyright:** 2009-2016, Chef Software, Inc.\n\n```\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache-2.0","platforms":{"ubuntu":">= 0.0.0","debian":">= 0.0.0","redhat":">= 0.0.0","centos":">= 0.0.0","amazon":">= 0.0.0","oracle":">= 0.0.0","scientific":">= 0.0.0","smartos":">= 0.0.0","fedora":">= 0.0.0"},"dependencies":{},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{"postfix":"Installs and configures postfix","postfix::sasl_auth":"Set up postfix to auth to a server with sasl","postfix::aliases":"Manages /etc/aliases","postfix::transports":"Manages /etc/postfix/transport","postfix::access":"Manages /etc/postfix/access","postfix::virtual_aliases":"Manages /etc/postfix/virtual","postfix::client":"Searches for the relayhost based on an attribute","postfix::server":"Sets the mail_type attribute to master","postfix::maps":"Manages any number of any type postfix lookup tables"},"source_url":"https://github.com/chef-cookbooks/postfix","issues_url":"https://github.com/chef-cookbooks/postfix/issues","chef_version":[[">= 12.1"]],"ohai_version":[]} \ No newline at end of file +{ + "name": "postfix", + "description": "Installs and configures postfix for client or outbound relayhost, or to do SASL auth", + "long_description": "", + "maintainer": "Sous Chefs", + "maintainer_email": "help@sous-chefs.org", + "license": "Apache-2.0", + "platforms": { + "amazon": ">= 0.0.0", + "centos": ">= 0.0.0", + "debian": ">= 0.0.0", + "fedora": ">= 0.0.0", + "freebsd": ">= 0.0.0", + "oracle": ">= 0.0.0", + "redhat": ">= 0.0.0", + "scientific": ">= 0.0.0", + "smartos": ">= 0.0.0", + "ubuntu": ">= 0.0.0" + }, + "dependencies": { + + }, + "providing": { + + }, + "recipes": { + + }, + "version": "6.0.26", + "source_url": "https://github.com/sous-chefs/postfix", + "issues_url": "https://github.com/sous-chefs/postfix/issues", + "privacy": false, + "chef_versions": [ + [ + ">= 12.15" + ] + ], + "ohai_versions": [ + + ], + "gems": [ + + ], + "eager_load_libraries": true +} diff --git a/cookbooks/postfix/metadata.rb b/cookbooks/postfix/metadata.rb new file mode 100644 index 0000000..7289daa --- /dev/null +++ b/cookbooks/postfix/metadata.rb @@ -0,0 +1,20 @@ +name 'postfix' +maintainer 'Sous Chefs' +maintainer_email 'help@sous-chefs.org' +license 'Apache-2.0' +description 'Installs and configures postfix for client or outbound relayhost, or to do SASL auth' +version '6.0.26' +source_url 'https://github.com/sous-chefs/postfix' +issues_url 'https://github.com/sous-chefs/postfix/issues' +chef_version '>= 12.15' + +supports 'amazon' +supports 'centos' +supports 'debian' +supports 'fedora' +supports 'freebsd' +supports 'oracle' +supports 'redhat' +supports 'scientific' +supports 'smartos' +supports 'ubuntu' diff --git a/cookbooks/postfix/recipes/_attributes.rb b/cookbooks/postfix/recipes/_attributes.rb index f3ffe6e..5e7449d 100644 --- a/cookbooks/postfix/recipes/_attributes.rb +++ b/cookbooks/postfix/recipes/_attributes.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2017, Chef Software, Inc. +# Copyright:: 2012-2019, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,9 +13,7 @@ # limitations under the License. # -if node['postfix']['use_procmail'] - node.default_unless['postfix']['main']['mailbox_command'] = '/usr/bin/procmail -a "$EXTENSION"' -end +node.default_unless['postfix']['main']['mailbox_command'] = '/usr/bin/procmail -a "$EXTENSION"' if node['postfix']['use_procmail'] if node['postfix']['main']['smtpd_use_tls'] == 'yes' node.default_unless['postfix']['main']['smtpd_tls_cert_file'] = '/etc/ssl/certs/ssl-cert-snakeoil.pem' @@ -38,34 +36,18 @@ if node['postfix']['main']['smtp_sasl_auth_enable'] == 'yes' node.default_unless['postfix']['main']['relayhost'] = '' end -if node['postfix']['use_alias_maps'] - node.default_unless['postfix']['main']['alias_maps'] = ["hash:#{node['postfix']['aliases_db']}"] -end +node.default_unless['postfix']['main']['alias_maps'] = ["hash:#{node['postfix']['aliases_db']}"] if node['postfix']['use_alias_maps'] -if node['postfix']['use_transport_maps'] - node.default_unless['postfix']['main']['transport_maps'] = ["hash:#{node['postfix']['transport_db']}"] -end +node.default_unless['postfix']['main']['transport_maps'] = ["hash:#{node['postfix']['transport_db']}"] if node['postfix']['use_transport_maps'] -if node['postfix']['use_access_maps'] - node.default_unless['postfix']['main']['access_maps'] = ["hash:#{node['postfix']['access_db']}"] -end +node.default_unless['postfix']['main']['access_maps'] = ["hash:#{node['postfix']['access_db']}"] if node['postfix']['use_access_maps'] -if node['postfix']['use_virtual_aliases'] - node.default_unless['postfix']['main']['virtual_alias_maps'] = ["#{node['postfix']['virtual_alias_db_type']}:#{node['postfix']['virtual_alias_db']}"] -end +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'] -if node['postfix']['use_virtual_aliases_domains'] - node.default_unless['postfix']['main']['virtual_alias_domains'] = ["#{node['postfix']['virtual_alias_domains_db_type']}:#{node['postfix']['virtual_alias_domains_db']}"] -end +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'] -if node['postfix']['use_relay_restrictions_maps'] - default['postfix']['main']['smtpd_relay_restrictions'] = "hash:#{node['postfix']['relay_restrictions_db']}, reject" -end +node.default_unless['postfix']['main']['smtpd_relay_restrictions'] = "hash:#{node['postfix']['relay_restrictions_db']}, reject" if node['postfix']['use_relay_restrictions_maps'] -if node['postfix']['master']['maildrop']['active'] - node.default_unless['postfix']['main']['maildrop_destination_recipient_limit'] = 1 -end +node.default_unless['postfix']['main']['maildrop_destination_recipient_limit'] = 1 if node['postfix']['master']['maildrop']['active'] -if node['postfix']['master']['cyrus']['active'] - node.default_unless['postfix']['main']['cyrus_destination_recipient_limit'] = 1 -end +node.default_unless['postfix']['main']['cyrus_destination_recipient_limit'] = 1 if node['postfix']['master']['cyrus']['active'] diff --git a/cookbooks/postfix/recipes/_common.rb b/cookbooks/postfix/recipes/_common.rb index 17d5e0e..ab3aeab 100644 --- a/cookbooks/postfix/recipes/_common.rb +++ b/cookbooks/postfix/recipes/_common.rb @@ -2,7 +2,7 @@ # Cookbook:: common # Recipe:: default # -# Copyright:: 2009-2017, Chef Software, Inc. +# Copyright:: 2009-2020, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,12 +19,19 @@ include_recipe 'postfix::_attributes' -package 'postfix' +# use multi-package when we can +if node['os'] == 'linux' + package node['postfix']['packages'] +else + node['postfix']['packages'].each do |pkg| + package pkg + end +end package 'procmail' if node['postfix']['use_procmail'] case node['platform_family'] -when 'rhel', 'fedora' +when 'rhel', 'fedora', 'amazon' service 'sendmail' do action :nothing end @@ -35,6 +42,8 @@ when 'rhel', 'fedora' notifies :start, 'service[postfix]' not_if '/usr/bin/test /etc/alternatives/mta -ef /usr/sbin/sendmail.postfix' end +when 'suse' + file '/var/adm/postfix.configured' when 'omnios' manifest_path = ::File.join(Chef::Config[:file_cache_path], 'manifest-postfix.xml') @@ -67,7 +76,68 @@ when 'omnios' execute 'load postfix manifest' do action :nothing command "svccfg import #{manifest_path}" - notifies :restart, 'service[postfix]' + notifies :restart, 'service[postfix]' unless platform_family?('solaris2') + end +when 'freebsd' + # Actions are based on docs provided by FreeBSD: + # https://www.freebsd.org/doc/handbook/mail-changingmta.html + service 'sendmail' do + action :nothing + end + + template '/etc/mail/mailer.conf' do + source 'mailer.erb' + owner 'root' + group 0 + notifies :restart, 'service[postfix]' unless platform_family?('solaris2') + end + + execute 'switch_mailer_to_postfix' do + command [ + 'sysrc', + 'sendmail_enable=NO', + 'sendmail_submit_enable=NO', + 'sendmail_outbound_enable=NO', + 'sendmail_msp_queue_enable=NO', + 'postfix_enable=YES', + ] + notifies :stop, 'service[sendmail]', :immediately + notifies :disable, 'service[sendmail]', :immediately + notifies :start, 'service[postfix]', :delayed + 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)'" + end + + execute 'disable_periodic' do + # rubocop:disable Lint/ParenthesesAsGroupedExpression + environment ({ 'RC_CONFS' => '/etc/periodic.conf' }) + command [ + 'sysrc', + 'daily_clean_hoststat_enable=NO', + 'daily_status_mail_rejects_enable=NO', + 'daily_status_include_submit_mailq=NO', + 'daily_submit_queuerun=NO', + ] + 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)'" + end +end + +# We need to write the config first as the below postmap immediately commands assume config is correct +# Which is not the case as ipv6 is assumed to be available by the postfix package +# And if someone wants to disable this first we need to update the config first aswell +%w( main master ).each do |cfg| + template "#{node['postfix']['conf_dir']}/#{cfg}.cf" do + source "#{cfg}.cf.erb" + owner 'root' + group node['root_group'] + mode '0644' + # restart service for solaris on chef-client has a bug + # unless condition can be removed after + # https://github.com/chef/chef/pull/6596 merge/release + notifies :restart, 'service[postfix]' unless platform_family?('solaris2') + variables( + lazy { { settings: node['postfix'][cfg] } } + ) + cookbook node['postfix']["#{cfg}_template_source"] end end @@ -81,13 +151,11 @@ unless node['postfix']['sender_canonical_map_entries'].empty? owner 'root' group node['root_group'] mode '0644' - notifies :run, 'execute[update-postfix-sender_canonical]' + notifies :run, 'execute[update-postfix-sender_canonical]', :immediately notifies :reload, 'service[postfix]' end - unless node['postfix']['main'].key?('sender_canonical_maps') - node.normal['postfix']['main']['sender_canonical_maps'] = "hash:#{node['postfix']['conf_dir']}/sender_canonical" - end + node.default['postfix']['main']['sender_canonical_maps'] = "hash:#{node['postfix']['conf_dir']}/sender_canonical" unless node['postfix']['main'].key?('sender_canonical_maps') end execute 'update-postfix-smtp_generic' do @@ -100,28 +168,31 @@ unless node['postfix']['smtp_generic_map_entries'].empty? owner 'root' group node['root_group'] mode '0644' - notifies :run, 'execute[update-postfix-smtp_generic]' + notifies :run, 'execute[update-postfix-smtp_generic]', :immediately notifies :reload, 'service[postfix]' end - unless node['postfix']['main'].key?('smtp_generic_maps') - node.normal['postfix']['main']['smtp_generic_maps'] = "hash:#{node['postfix']['conf_dir']}/smtp_generic" - end + node.default['postfix']['main']['smtp_generic_maps'] = "hash:#{node['postfix']['conf_dir']}/smtp_generic" unless node['postfix']['main'].key?('smtp_generic_maps') end -%w( main master ).each do |cfg| - template "#{node['postfix']['conf_dir']}/#{cfg}.cf" do - source "#{cfg}.cf.erb" +execute 'update-postfix-recipient_canonical' do + command "postmap #{node['postfix']['conf_dir']}/recipient_canonical" + action :nothing +end + +unless node['postfix']['recipient_canonical_map_entries'].empty? + template "#{node['postfix']['conf_dir']}/recipient_canonical" do owner 'root' group node['root_group'] mode '0644' - notifies :restart, 'service[postfix]' - variables(settings: node['postfix'][cfg]) - cookbook node['postfix']["#{cfg}_template_source"] + notifies :run, 'execute[update-postfix-recipient_canonical]', :immediately + notifies :reload, 'service[postfix]' end + + node.default['postfix']['main']['recipient_canonical_maps'] = "hash:#{node['postfix']['conf_dir']}/recipient_canonical" unless node['postfix']['main'].key?('recipient_canonical_maps') end service 'postfix' do supports status: true, restart: true, reload: true - action :enable + action [:enable, :start] end diff --git a/cookbooks/postfix/recipes/access.rb b/cookbooks/postfix/recipes/access.rb index 62e3025..cfe5dbd 100644 --- a/cookbooks/postfix/recipes/access.rb +++ b/cookbooks/postfix/recipes/access.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2017, Chef Software, Inc. +# Copyright:: 2012-2019, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,5 +23,5 @@ end template node['postfix']['access_db'] do source 'access.erb' - notifies :run, 'execute[update-postfix-access]' + notifies :run, 'execute[update-postfix-access]', :immediately end diff --git a/cookbooks/postfix/recipes/aliases.rb b/cookbooks/postfix/recipes/aliases.rb index 67d6db7..f8eec97 100644 --- a/cookbooks/postfix/recipes/aliases.rb +++ b/cookbooks/postfix/recipes/aliases.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2017, Chef Software, Inc. +# Copyright:: 2012-2019, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,5 +25,5 @@ end template node['postfix']['aliases_db'] do source 'aliases.erb' - notifies :run, 'execute[update-postfix-aliases]' + notifies :run, 'execute[update-postfix-aliases]', :immediately end diff --git a/cookbooks/postfix/recipes/client.rb b/cookbooks/postfix/recipes/client.rb index 2231ce2..b5009a6 100644 --- a/cookbooks/postfix/recipes/client.rb +++ b/cookbooks/postfix/recipes/client.rb @@ -2,7 +2,7 @@ # Cookbook:: postfix # Recipe:: client # -# Copyright:: 2009-2017, Chef Software, Inc. +# Copyright:: 2009-2019, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -24,6 +24,9 @@ end query = "role:#{node['postfix']['relayhost_role']}" relayhost = '' +# if the relayhost_port attribute is not port 25, append to the relayhost +relayhost_port = node['postfix']['relayhost_port'].to_s != '25' ? ":#{node['postfix']['relayhost_port']}" : '' + # results = [] if node.run_list.roles.include?(node['postfix']['relayhost_role']) @@ -36,6 +39,6 @@ else relayhost = results.map { |n| n['ipaddress'] }.first end -node.normal['postfix']['main']['relayhost'] = "[#{relayhost}]" +node.default['postfix']['main']['relayhost'] = "[#{relayhost}]#{relayhost_port}" include_recipe 'postfix' diff --git a/cookbooks/postfix/recipes/default.rb b/cookbooks/postfix/recipes/default.rb index 07026e4..9fed0be 100644 --- a/cookbooks/postfix/recipes/default.rb +++ b/cookbooks/postfix/recipes/default.rb @@ -2,7 +2,7 @@ # Cookbook:: postfix # Recipe:: default # -# Copyright:: 2009-2017, Chef Software, Inc. +# Copyright:: 2009-2019, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/maps.rb b/cookbooks/postfix/recipes/maps.rb index 9c47486..35ea9ad 100644 --- a/cookbooks/postfix/recipes/maps.rb +++ b/cookbooks/postfix/recipes/maps.rb @@ -1,5 +1,4 @@ -# encoding: utf-8 -# Copyright:: 2012-2017, Chef Software, Inc. +# Copyright:: 2012-2019, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,7 +14,11 @@ # node['postfix']['maps'].each do |type, maps| - if node['platform_family'] == 'debian' + if platform_family?('debian') + package "postfix-#{type}" if %w(pgsql mysql ldap cdb).include?(type) + end + + if platform?('redhat') && node['platform_version'].to_i == 8 package "postfix-#{type}" if %w(pgsql mysql ldap cdb).include?(type) end @@ -38,9 +41,7 @@ node['postfix']['maps'].each do |type, maps| map: content, separator: separator ) - if %w(btree cdb dbm hash sdbm).include?(type) - notifies :run, "execute[update-postmap-#{file}]" - end + notifies :run, "execute[update-postmap-#{file}]" if %w(btree cdb dbm hash sdbm).include?(type) notifies :restart, 'service[postfix]' end end diff --git a/cookbooks/postfix/recipes/relay_restrictions.rb b/cookbooks/postfix/recipes/relay_restrictions.rb index c5548e4..08aabcd 100644 --- a/cookbooks/postfix/recipes/relay_restrictions.rb +++ b/cookbooks/postfix/recipes/relay_restrictions.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2017, Chef Software, Inc. +# Copyright:: 2012-2019, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,13 +15,15 @@ include_recipe 'postfix::_common' +postmap_command = platform_family?('rhel') ? '/usr/sbin/postmap' : 'postmap' + execute 'update-postfix-relay-restrictions' do - command "postmap #{node['postfix']['relay_restrictions_db']}" + command "#{postmap_command} #{node['postfix']['relay_restrictions_db']}" environment PATH: "#{ENV['PATH']}:/opt/omni/bin:/opt/omni/sbin" if platform_family?('omnios') action :nothing end template node['postfix']['relay_restrictions_db'] do source 'relay_restrictions.erb' - notifies :run, 'execute[update-postfix-relay-restrictions]' + notifies :run, 'execute[update-postfix-relay-restrictions]', :immediately end diff --git a/cookbooks/postfix/recipes/sasl_auth.rb b/cookbooks/postfix/recipes/sasl_auth.rb index 38f040e..bd9c18f 100644 --- a/cookbooks/postfix/recipes/sasl_auth.rb +++ b/cookbooks/postfix/recipes/sasl_auth.rb @@ -3,7 +3,7 @@ # Cookbook:: postfix # Recipe:: sasl_auth # -# Copyright:: 2009-2017, Chef Software, Inc. +# Copyright:: 2009-2019, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -28,11 +28,9 @@ case node['platform_family'] when 'debian' sasl_pkgs = %w(libsasl2-2 libsasl2-modules ca-certificates) when 'rhel' - sasl_pkgs = if node['platform_version'].to_i < 6 - %w(cyrus-sasl cyrus-sasl-plain openssl) - else - %w(cyrus-sasl cyrus-sasl-plain ca-certificates) - end + sasl_pkgs = %w(cyrus-sasl cyrus-sasl-plain ca-certificates) +when 'amazon' + sasl_pkgs = %w(cyrus-sasl cyrus-sasl-plain ca-certificates) when 'fedora' sasl_pkgs = %w(cyrus-sasl cyrus-sasl-plain ca-certificates) end diff --git a/cookbooks/postfix/recipes/server.rb b/cookbooks/postfix/recipes/server.rb index 2166777..eaa14a6 100644 --- a/cookbooks/postfix/recipes/server.rb +++ b/cookbooks/postfix/recipes/server.rb @@ -3,7 +3,7 @@ # Cookbook:: postfix # Recipe:: server # -# Copyright:: 2009-2017, Chef Software, Inc. +# Copyright:: 2009-2019, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cookbooks/postfix/recipes/transports.rb b/cookbooks/postfix/recipes/transports.rb index 7386caa..5436ae6 100644 --- a/cookbooks/postfix/recipes/transports.rb +++ b/cookbooks/postfix/recipes/transports.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2017, Chef Software, Inc. +# Copyright:: 2012-2019, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,13 +15,15 @@ include_recipe 'postfix::_common' +postmap_command = platform_family?('rhel') ? '/usr/sbin/postmap' : 'postmap' + execute 'update-postfix-transport' do - command "postmap #{node['postfix']['transport_db']}" + command "#{postmap_command} #{node['postfix']['transport_db']}" environment PATH: "#{ENV['PATH']}:/opt/omni/bin:/opt/omni/sbin" if platform_family?('omnios') action :nothing end template node['postfix']['transport_db'] do source 'transport.erb' - notifies :run, 'execute[update-postfix-transport]' + notifies :run, 'execute[update-postfix-transport]', :immediately end diff --git a/cookbooks/postfix/recipes/virtual_aliases.rb b/cookbooks/postfix/recipes/virtual_aliases.rb index f8e9eda..7047807 100644 --- a/cookbooks/postfix/recipes/virtual_aliases.rb +++ b/cookbooks/postfix/recipes/virtual_aliases.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2017, Chef Software, Inc. +# Copyright:: 2012-2019, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,6 +23,6 @@ end template node['postfix']['virtual_alias_db'] do source 'virtual_aliases.erb' - notifies :run, 'execute[update-postfix-virtual-alias]' + notifies :run, 'execute[update-postfix-virtual-alias]', :immediately notifies :restart, 'service[postfix]' end diff --git a/cookbooks/postfix/recipes/virtual_aliases_domains.rb b/cookbooks/postfix/recipes/virtual_aliases_domains.rb index 067b697..3ded82d 100644 --- a/cookbooks/postfix/recipes/virtual_aliases_domains.rb +++ b/cookbooks/postfix/recipes/virtual_aliases_domains.rb @@ -1,4 +1,4 @@ -# Copyright:: 2012-2017, Chef Software, Inc. +# Copyright:: 2012-2019, Chef Software, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,6 +23,6 @@ end template node['postfix']['virtual_alias_domains_db'] do source 'virtual_aliases_domains.erb' - notifies :run, 'execute[update-postfix-virtual-alias-domains]' + notifies :run, 'execute[update-postfix-virtual-alias-domains]', :immediately notifies :restart, 'service[postfix]' end diff --git a/cookbooks/postfix/renovate.json b/cookbooks/postfix/renovate.json new file mode 100644 index 0000000..7e7a8ba --- /dev/null +++ b/cookbooks/postfix/renovate.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:base"], + "packageRules": [{ + "groupName": "Actions", + "matchUpdateTypes": ["patch", "pin", "digest"], + "automerge": true, + "addLabels": ["Release: Patch", "Skip: Announcements"] + }, + { + "groupName": "Actions", + "matchUpdateTypes": ["major"], + "automerge": false, + "addLabels": ["Release: Patch", "Skip: Announcements"] + } + ] +} diff --git a/cookbooks/postfix/templates/default/access.erb b/cookbooks/postfix/templates/access.erb similarity index 100% rename from cookbooks/postfix/templates/default/access.erb rename to cookbooks/postfix/templates/access.erb diff --git a/cookbooks/postfix/templates/default/aliases.erb b/cookbooks/postfix/templates/aliases.erb similarity index 100% rename from cookbooks/postfix/templates/default/aliases.erb rename to cookbooks/postfix/templates/aliases.erb diff --git a/cookbooks/postfix/templates/default/sasl_passwd.erb b/cookbooks/postfix/templates/default/sasl_passwd.erb deleted file mode 100644 index 18f16b3..0000000 --- a/cookbooks/postfix/templates/default/sasl_passwd.erb +++ /dev/null @@ -1,4 +0,0 @@ -# Auto-generated by Chef. -# Local modifications will be overwritten. -# -<%= node['postfix']['main']['relayhost'] %> <%= @settings['smtp_sasl_user_name'] %>:<%= @settings['smtp_sasl_passwd'] %> diff --git a/cookbooks/postfix/templates/mailer.erb b/cookbooks/postfix/templates/mailer.erb new file mode 100644 index 0000000..1865157 --- /dev/null +++ b/cookbooks/postfix/templates/mailer.erb @@ -0,0 +1,10 @@ +# +# Auto-generated by Chef. +# Local modifications will be overwritten. +# +# Execute the Postfix sendmail program, named /usr/local/sbin/sendmail +# +sendmail /usr/local/sbin/sendmail +send-mail /usr/local/sbin/sendmail +mailq /usr/local/sbin/sendmail +newaliases /usr/local/sbin/sendmail diff --git a/cookbooks/postfix/templates/default/main.cf.erb b/cookbooks/postfix/templates/main.cf.erb similarity index 100% rename from cookbooks/postfix/templates/default/main.cf.erb rename to cookbooks/postfix/templates/main.cf.erb diff --git a/cookbooks/postfix/templates/default/manifest-postfix.xml.erb b/cookbooks/postfix/templates/manifest-postfix.xml.erb similarity index 100% rename from cookbooks/postfix/templates/default/manifest-postfix.xml.erb rename to cookbooks/postfix/templates/manifest-postfix.xml.erb diff --git a/cookbooks/postfix/templates/default/maps.erb b/cookbooks/postfix/templates/maps.erb similarity index 100% rename from cookbooks/postfix/templates/default/maps.erb rename to cookbooks/postfix/templates/maps.erb diff --git a/cookbooks/postfix/templates/default/master.cf.erb b/cookbooks/postfix/templates/master.cf.erb similarity index 100% rename from cookbooks/postfix/templates/default/master.cf.erb rename to cookbooks/postfix/templates/master.cf.erb diff --git a/cookbooks/postfix/templates/default/port_smtp.erb b/cookbooks/postfix/templates/port_smtp.erb similarity index 100% rename from cookbooks/postfix/templates/default/port_smtp.erb rename to cookbooks/postfix/templates/port_smtp.erb diff --git a/cookbooks/postfix/templates/recipient_canonical.erb b/cookbooks/postfix/templates/recipient_canonical.erb new file mode 100644 index 0000000..bfff5c1 --- /dev/null +++ b/cookbooks/postfix/templates/recipient_canonical.erb @@ -0,0 +1,9 @@ +# +# Auto-generated by Chef. +# Local modifications will be overwritten. +# +# See man 5 canonical for format + +<% node['postfix']['recipient_canonical_map_entries'].each do |name, value| %> +<%= name %> <%= value %> +<% end unless node['postfix']['recipient_canonical_map_entries'].nil? %> diff --git a/cookbooks/postfix/templates/default/relay_restrictions.erb b/cookbooks/postfix/templates/relay_restrictions.erb similarity index 100% rename from cookbooks/postfix/templates/default/relay_restrictions.erb rename to cookbooks/postfix/templates/relay_restrictions.erb diff --git a/cookbooks/postfix/templates/sasl_passwd.erb b/cookbooks/postfix/templates/sasl_passwd.erb new file mode 100644 index 0000000..7ead10e --- /dev/null +++ b/cookbooks/postfix/templates/sasl_passwd.erb @@ -0,0 +1,8 @@ +# Auto-generated by Chef. +# Local modifications will be overwritten. + +<% if !@settings.nil? && !@settings.empty? -%> +<% @settings.sort.map do |relayhost,value| -%> +<%= relayhost %> <%= value['username'] %>:<%= value['password'] %> +<% end -%> +<% end -%> diff --git a/cookbooks/postfix/templates/default/sender_canonical.erb b/cookbooks/postfix/templates/sender_canonical.erb similarity index 100% rename from cookbooks/postfix/templates/default/sender_canonical.erb rename to cookbooks/postfix/templates/sender_canonical.erb diff --git a/cookbooks/postfix/templates/default/smtp_generic.erb b/cookbooks/postfix/templates/smtp_generic.erb similarity index 100% rename from cookbooks/postfix/templates/default/smtp_generic.erb rename to cookbooks/postfix/templates/smtp_generic.erb diff --git a/cookbooks/postfix/templates/default/transport.erb b/cookbooks/postfix/templates/transport.erb similarity index 100% rename from cookbooks/postfix/templates/default/transport.erb rename to cookbooks/postfix/templates/transport.erb diff --git a/cookbooks/postfix/templates/default/virtual_aliases.erb b/cookbooks/postfix/templates/virtual_aliases.erb similarity index 100% rename from cookbooks/postfix/templates/default/virtual_aliases.erb rename to cookbooks/postfix/templates/virtual_aliases.erb diff --git a/cookbooks/postfix/templates/default/virtual_aliases_domains.erb b/cookbooks/postfix/templates/virtual_aliases_domains.erb similarity index 100% rename from cookbooks/postfix/templates/default/virtual_aliases_domains.erb rename to cookbooks/postfix/templates/virtual_aliases_domains.erb From fbcf1ed5e707f67d70848937adbdbb6b858268a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 1 Dec 2023 09:50:35 +0100 Subject: [PATCH 02/26] WIP Add initial cookbook and roles for email service --- roles/email_proxy.rb | 5 + roles/email_server.rb | 6 + site-cookbooks/kosmos_email/.gitignore | 25 ++ site-cookbooks/kosmos_email/CHANGELOG.md | 7 + site-cookbooks/kosmos_email/LICENSE | 20 + .../kosmos_email/attributes/default.rb | 4 + site-cookbooks/kosmos_email/chefignore | 115 +++++ .../kosmos_email/compliance/README.md | 25 ++ site-cookbooks/kosmos_email/kitchen.yml | 53 +++ site-cookbooks/kosmos_email/metadata.rb | 10 + .../kosmos_email/recipes/default.rb | 25 ++ .../kosmos_email/recipes/dovecot.rb | 84 ++++ .../kosmos_email/recipes/firewall.rb | 34 ++ .../kosmos_email/recipes/postfix.rb | 144 ++++++ .../templates/dovecot-ldap.conf.ext.erb | 151 +++++++ .../kosmos_email/templates/dovecot.conf.erb | 105 +++++ .../templates/dovecot_10-auth.conf.erb | 127 ++++++ .../templates/dovecot_10-mail.conf.erb | 421 ++++++++++++++++++ .../templates/dovecot_10-master.conf.erb | 113 +++++ .../templates/dovecot_10-ssl.conf.erb | 83 ++++ .../templates/ldap-aliases.cf.erb | 7 + .../templates/ldap-virtual-mailboxes.cf.erb | 7 + .../test/integration/default/default_test.rb | 16 + 23 files changed, 1587 insertions(+) create mode 100644 roles/email_proxy.rb create mode 100644 roles/email_server.rb create mode 100644 site-cookbooks/kosmos_email/.gitignore create mode 100644 site-cookbooks/kosmos_email/CHANGELOG.md create mode 100644 site-cookbooks/kosmos_email/LICENSE create mode 100644 site-cookbooks/kosmos_email/attributes/default.rb create mode 100644 site-cookbooks/kosmos_email/chefignore create mode 100644 site-cookbooks/kosmos_email/compliance/README.md create mode 100644 site-cookbooks/kosmos_email/kitchen.yml create mode 100644 site-cookbooks/kosmos_email/metadata.rb create mode 100644 site-cookbooks/kosmos_email/recipes/default.rb create mode 100644 site-cookbooks/kosmos_email/recipes/dovecot.rb create mode 100644 site-cookbooks/kosmos_email/recipes/firewall.rb create mode 100644 site-cookbooks/kosmos_email/recipes/postfix.rb create mode 100644 site-cookbooks/kosmos_email/templates/dovecot-ldap.conf.ext.erb create mode 100644 site-cookbooks/kosmos_email/templates/dovecot.conf.erb create mode 100644 site-cookbooks/kosmos_email/templates/dovecot_10-auth.conf.erb create mode 100644 site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb create mode 100644 site-cookbooks/kosmos_email/templates/dovecot_10-master.conf.erb create mode 100644 site-cookbooks/kosmos_email/templates/dovecot_10-ssl.conf.erb create mode 100644 site-cookbooks/kosmos_email/templates/ldap-aliases.cf.erb create mode 100644 site-cookbooks/kosmos_email/templates/ldap-virtual-mailboxes.cf.erb create mode 100644 site-cookbooks/kosmos_email/test/integration/default/default_test.rb diff --git a/roles/email_proxy.rb b/roles/email_proxy.rb new file mode 100644 index 0000000..e0030dc --- /dev/null +++ b/roles/email_proxy.rb @@ -0,0 +1,5 @@ +name "email_proxy" + +run_list %w( + kosmos_email::firewall +) diff --git a/roles/email_server.rb b/roles/email_server.rb new file mode 100644 index 0000000..fd3e781 --- /dev/null +++ b/roles/email_server.rb @@ -0,0 +1,6 @@ +name "email_server" + +run_list %w( + role[ldap_client] + kosmos_email::default +) diff --git a/site-cookbooks/kosmos_email/.gitignore b/site-cookbooks/kosmos_email/.gitignore new file mode 100644 index 0000000..f1e57b8 --- /dev/null +++ b/site-cookbooks/kosmos_email/.gitignore @@ -0,0 +1,25 @@ +.vagrant +*~ +*# +.#* +\#*# +.*.sw[a-z] +*.un~ + +# Bundler +Gemfile.lock +gems.locked +bin/* +.bundle/* + +# test kitchen +.kitchen/ +kitchen.local.yml + +# Chef Infra +Berksfile.lock +.zero-knife.rb +Policyfile.lock.json + +.idea/ + diff --git a/site-cookbooks/kosmos_email/CHANGELOG.md b/site-cookbooks/kosmos_email/CHANGELOG.md new file mode 100644 index 0000000..b33cc1a --- /dev/null +++ b/site-cookbooks/kosmos_email/CHANGELOG.md @@ -0,0 +1,7 @@ +# kosmos_email CHANGELOG + +This file is used to list changes made in each version of the kosmos_email cookbook. + +## 0.1.0 + +Initial release. diff --git a/site-cookbooks/kosmos_email/LICENSE b/site-cookbooks/kosmos_email/LICENSE new file mode 100644 index 0000000..b28fde8 --- /dev/null +++ b/site-cookbooks/kosmos_email/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) Kosmos Developers + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/site-cookbooks/kosmos_email/attributes/default.rb b/site-cookbooks/kosmos_email/attributes/default.rb new file mode 100644 index 0000000..dd60bc8 --- /dev/null +++ b/site-cookbooks/kosmos_email/attributes/default.rb @@ -0,0 +1,4 @@ +node.default["email"]["domain"] = "example.com" +node.default["email"]["hostname"] = "mail.example.com" +# node.default["email"]["user"] = "ray" +# node.default["email"]["group"] = "email" diff --git a/site-cookbooks/kosmos_email/chefignore b/site-cookbooks/kosmos_email/chefignore new file mode 100644 index 0000000..cc170ea --- /dev/null +++ b/site-cookbooks/kosmos_email/chefignore @@ -0,0 +1,115 @@ +# Put files/directories that should be ignored in this file when uploading +# to a Chef Infra Server or Supermarket. +# Lines that start with '# ' are comments. + +# OS generated files # +###################### +.DS_Store +ehthumbs.db +Icon? +nohup.out +Thumbs.db +.envrc + +# EDITORS # +########### +.#* +.project +.settings +*_flymake +*_flymake.* +*.bak +*.sw[a-z] +*.tmproj +*~ +\#* +REVISION +TAGS* +tmtags +.vscode +.editorconfig + +## COMPILED ## +############## +*.class +*.com +*.dll +*.exe +*.o +*.pyc +*.so +*/rdoc/ +a.out +mkmf.log + +# Testing # +########### +.circleci/* +.codeclimate.yml +.delivery/* +.foodcritic +.kitchen* +.mdlrc +.overcommit.yml +.rspec +.rubocop.yml +.travis.yml +.watchr +.yamllint +azure-pipelines.yml +Dangerfile +examples/* +features/* +Guardfile +kitchen.yml* +mlc_config.json +Procfile +Rakefile +spec/* +test/* + +# SCM # +####### +.git +.gitattributes +.gitconfig +.github/* +.gitignore +.gitkeep +.gitmodules +.svn +*/.bzr/* +*/.git +*/.hg/* +*/.svn/* + +# Berkshelf # +############# +Berksfile +Berksfile.lock +cookbooks/* +tmp + +# Bundler # +########### +vendor/* +Gemfile +Gemfile.lock + +# Policyfile # +############## +Policyfile.rb +Policyfile.lock.json + +# Documentation # +############# +CODE_OF_CONDUCT* +CONTRIBUTING* +documentation/* +TESTING* +UPGRADING* + +# Vagrant # +########### +.vagrant +Vagrantfile diff --git a/site-cookbooks/kosmos_email/compliance/README.md b/site-cookbooks/kosmos_email/compliance/README.md new file mode 100644 index 0000000..947be3e --- /dev/null +++ b/site-cookbooks/kosmos_email/compliance/README.md @@ -0,0 +1,25 @@ +# compliance + +This directory contains Chef InSpec profile, waiver and input objects which are used with the Chef Infra Compliance Phase. + +Detailed information on the Chef Infra Compliance Phase can be found in the [Chef Documentation](https://docs.chef.io/chef_compliance_phase/). + +```plain +./compliance +├── inputs +├── profiles +└── waivers +``` + +Use the `chef generate` command from Chef Workstation to create content for these directories: + +```sh +# Generate a Chef InSpec profile +chef generate profile PROFILE_NAME + +# Generate a Chef InSpec waiver file +chef generate waiver WAIVER_NAME + +# Generate a Chef InSpec input file +chef generate input INPUT_NAME +``` diff --git a/site-cookbooks/kosmos_email/kitchen.yml b/site-cookbooks/kosmos_email/kitchen.yml new file mode 100644 index 0000000..3e87682 --- /dev/null +++ b/site-cookbooks/kosmos_email/kitchen.yml @@ -0,0 +1,53 @@ +--- +driver: + name: dokken + chef_version: 18.2.7 + pull_platform_image: false + pull_chef_image: false + memory_limit: 2147483648 # 2GB + volumes: + # saves the apt archieves outside of the container + - /var/cache/apt/archives/:/var/cache/apt/archives/ + ## The forwarded_port port feature lets you connect to ports on the VM guest via + ## localhost on the host. + ## see also: https://www.vagrantup.com/docs/networking/forwarded_ports + # network: + # - ["forwarded_port", { guest: 4444, host: 4444 }] + +transport: + name: dokken + +provisioner: + name: dokken + # clean_dokken_sandbox: false + # You may wish to disable always updating cookbooks in CI or other testing environments. + # For example: + # always_update_cookbooks: <%= !ENV['CI'] %> + # always_update_cookbooks: false + + ## product_name and product_version specifies a specific Chef product and version to install. + ## see the Chef documentation for more details: https://docs.chef.io/workstation/config_yml_kitchen/ + # product_name: chef + # product_version: 16 + +verifier: + name: inspec + +platforms: + - name: ubuntu-22.04 + driver: + image: dokken/ubuntu-22.04 + privileged: true + pid_one_command: /usr/lib/systemd/systemd + intermediate_instructions: + # prevent APT from deleting the APT folder + - RUN rm /etc/apt/apt.conf.d/docker-clean + +suites: + - name: default + run_list: + - recipe[kosmos_email::default] + verifier: + inspec_tests: + - test/integration/default + attributes: diff --git a/site-cookbooks/kosmos_email/metadata.rb b/site-cookbooks/kosmos_email/metadata.rb new file mode 100644 index 0000000..cc689c3 --- /dev/null +++ b/site-cookbooks/kosmos_email/metadata.rb @@ -0,0 +1,10 @@ +name 'kosmos_email' +maintainer 'Kosmos Developers' +maintainer_email 'ops@kosmos.org' +license 'MIT' +description 'Installs/configures an email service' +version '0.1.0' +chef_version '>= 18.0' + +depends "hostname" +depends "postfix" diff --git a/site-cookbooks/kosmos_email/recipes/default.rb b/site-cookbooks/kosmos_email/recipes/default.rb new file mode 100644 index 0000000..c431328 --- /dev/null +++ b/site-cookbooks/kosmos_email/recipes/default.rb @@ -0,0 +1,25 @@ +# +# Cookbook:: kosmos_email +# Recipe:: default +# + +domain = node["email"]["domain"] +hostname = node["email"]["hostname"] +ip_addr = node["knife_zero"]["host"] + +node.override["set_fqdn"] = hostname +include_recipe "hostname" + +tls_cert_for hostname do + auth "gandi_dns" + action :create +end + +firewall_rule "private network access" do + command :allow + protocol :tcp + source "10.1.1.0/24" +end + +include_recipe 'kosmos_email::postfix' +include_recipe 'kosmos_email::dovecot' diff --git a/site-cookbooks/kosmos_email/recipes/dovecot.rb b/site-cookbooks/kosmos_email/recipes/dovecot.rb new file mode 100644 index 0000000..fff9274 --- /dev/null +++ b/site-cookbooks/kosmos_email/recipes/dovecot.rb @@ -0,0 +1,84 @@ +# +# Cookbook:: kosmos_email +# Recipe:: dovecot +# + +%w[ + dovecot-core + dovecot-imapd + dovecot-ldap + dovecot-lmtpd + dovecot-pop3d +].each do |pkg| + apt_package pkg +end + +domain = node["email"]["domain"] +hostname = node["email"]["hostname"] +ip_addr = node["knife_zero"]["host"] + +credentials = Chef::EncryptedDataBagItem.load('credentials', 'email') + +user "vmail" do + gid "mail" + system true + manage_home false +end + +template "/etc/dovecot/dovecot.conf" do + source "dovecot.conf.erb" + mode 0644 + # TODO variables protocols: "imap pop3 lmtp" + variables protocols: "imap lmtp", + # TODO find by email_proxy role + haproxy_trusted_networks: "10.1.1.167/32" + notifies :restart, "service[dovecot]", :delayed +end + +template "/etc/dovecot/dovecot-ldap.conf.ext" do + source "dovecot-ldap.conf.ext.erb" + mode 0600 + variables uris: "ldap://ldap.kosmos.local", # TODO add list of all IPs instead? + dn: credentials['ldap_dn'], + dnpass: credentials['ldap_dnpass'], + base: "ou=kosmos.org,cn=users,dc=kosmos,dc=org", + user_attrs: "mailhome=home", + user_filter: "(&(objectClass=person)(cn=%u))", + pass_attrs: "cn=user,mailpassword=password", + pass_filter: "(&(objectClass=person)(cn=%u))", + default_pass_scheme: "BLF-CRYPT" + notifies :restart, "service[dovecot]", :delayed +end + +template "/etc/dovecot/conf.d/10-auth.conf" do + source "dovecot_10-auth.conf.erb" + mode 0644 + notifies :restart, "service[dovecot]", :delayed +end + +template "/etc/dovecot/conf.d/10-mail.conf" do + source "dovecot_10-mail.conf.erb" + mode 0644 + variables mail_uid: "vmail", + mail_gid: "mail" + notifies :restart, "service[dovecot]", :delayed +end + +template "/etc/dovecot/conf.d/10-master.conf" do + source "dovecot_10-master.conf.erb" + mode 0644 + notifies :restart, "service[dovecot]", :delayed +end + +template "/etc/dovecot/conf.d/10-ssl.conf" do + source "dovecot_10-ssl.conf.erb" + mode 0644 + variables ssl: "required", + ssl_cert: node['postfix']['main']['smtpd_tls_cert_file'], + ssl_key: node['postfix']['main']['smtpd_tls_key_file'] + notifies :restart, "service[dovecot]", :delayed +end + +service "dovecot" do + action [:enable, :start] +end diff --git a/site-cookbooks/kosmos_email/recipes/firewall.rb b/site-cookbooks/kosmos_email/recipes/firewall.rb new file mode 100644 index 0000000..d4a76c0 --- /dev/null +++ b/site-cookbooks/kosmos_email/recipes/firewall.rb @@ -0,0 +1,34 @@ +# +# Cookbook:: kosmos_email +# Recipe:: firewall +# + +firewall_rule "SMTP" do + command :allow + port 25 + protocol :tcp +end + +firewall_rule "SMTPS" do + command :allow + port 465 + protocol :tcp +end + +firewall_rule "SMTPS" do + command :allow + port 587 + protocol :tcp +end + +firewall_rule "IMAP" do + command :allow + port 143 + protocol :tcp +end + +firewall_rule "IMAPS" do + command :allow + port 993 + protocol :tcp +end diff --git a/site-cookbooks/kosmos_email/recipes/postfix.rb b/site-cookbooks/kosmos_email/recipes/postfix.rb new file mode 100644 index 0000000..3a46d3d --- /dev/null +++ b/site-cookbooks/kosmos_email/recipes/postfix.rb @@ -0,0 +1,144 @@ +# +# Cookbook:: kosmos_email +# Recipe:: postfix +# + +%w[ + postfix + postfix-ldap +].each do |pkg| + apt_package pkg +end + +domain = node["email"]["domain"] +hostname = node["email"]["hostname"] +ip_addr = node["knife_zero"]["host"] + +credentials = Chef::EncryptedDataBagItem.load('credentials', 'email') + +node.normal["postfix"]["mail_type"] = "master" +node.normal["postfix"]["use_relay_restrictions_maps"] = true +node.normal["postfix"]["relay_restrictions"] = { domain => "OK", hostname => "OK" } + +node.normal['postfix']['main']['mydomain'] = domain +node.normal['postfix']['main']['myorigin'] = domain +node.normal['postfix']['main']['myhostname'] = hostname +node.normal['postfix']['main']['mynetworks'] = ["10.1.1.0/24", "127.0.0.0/8"] +node.normal['postfix']['main']['smtpd_use_tls'] = "yes" +node.normal['postfix']['main']['smtpd_tls_cert_file'] = "/etc/letsencrypt/live/#{hostname}/fullchain.pem" +node.normal['postfix']['main']['smtpd_tls_key_file'] = "/etc/letsencrypt/live/#{hostname}/privkey.pem" +node.normal['postfix']['main']['mailbox_transport'] = "lmtp:unix:private/dovecot-lmtp" +node.normal['postfix']['main']['virtual_transport'] = "lmtp:unix:private/dovecot-lmtp" +node.normal['postfix']['main']['smtputf8_enable'] = "no" +node.normal['postfix']['main']['recipient_delimiter'] = "+" +node.normal['postfix']['main']['alias_maps'] = "hash:/etc/aliases, ldap:/etc/postfix/ldap-aliases.cf" +# node.normal['postfix']['main']['virtual_mailbox_maps'] = "ldap:/etc/postfix/ldap-virtual-mailboxes.cf" + +node.normal['postfix']['master'] = { + "#{ip_addr}:2525": { + "active": true, + "order": 1, + "type": "inet", + "private": false, + "maxproc": "1", + "command": "postscreen", + "args": [ + "-o postscreen_upstream_proxy_protocol=haproxy", + "-o postscreen_cache_map=btree:$data_directory/postscreen_2525_cache", + "-o syslog_name=postfix/2525" + ] + }, + "#{ip_addr}:10587": { + "active": true, + "order": 2, + "type": "inet", + "private": false, + "chroot": true, + "command": "smtpd", + "args": [ + "-o syslog_name=postfix/10587", + "-o smtpd_tls_security_level=encrypt", + "-o smtpd_tls_wrappermode=no", + "-o smtpd_sasl_auth_enable=yes", + "-o smtpd_relay_restrictions=permit_sasl_authenticated,reject", + "-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject", + "-o smtpd_sasl_type=dovecot", + "-o smtpd_sasl_path=private/auth", + "-o smtpd_upstream_proxy_protocol=haproxy", + ] + }, + "#{ip_addr}:10465": { + "active": true, + "order": 3, + "type": "inet", + "private": false, + "chroot": true, + "command": "smtpd", + "args": [ + "-o syslog_name=postfix/10465", + "-o smtpd_tls_wrappermode=yes", + "-o smtpd_sasl_auth_enable=yes", + "-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject", + "-o smtpd_sasl_type=dovecot", + "-o smtpd_sasl_path=private/auth", + "-o smtpd_upstream_proxy_protocol=haproxy", + ] + }, + "smtpd": { + "active": true, + "order": 100, + "type": "pass", + "chroot": true, + "command": "smtpd", + "args": [] + }, + "dnsblog": { + "active": true, + "order": 101, + "type": "unix", + "chroot": true, + "maxproc": "0", + "command": "dnsblog", + "args": [] + }, + "tlsproxy": { + "active": true, + "order": 102, + "type": "unix", + "chroot": true, + "maxproc": "0", + "command": "tlsproxy", + "args": [] + } +} + +template "/etc/postfix/ldap-aliases.cf" do + source "ldap-aliases.cf.erb" + mode 0600 + variables server_host: "ldap.kosmos.local", + bind_dn: credentials['ldap_dn'], + bind_pw: credentials['ldap_dnpass'], + search_base: "ou=kosmos.org,cn=users,dc=kosmos,dc=org", + query_filter: "(&(objectClass=person)(cn=%u))", + result_attribute: "maildrop" + notifies :restart, "service[postfix]", :delayed +end + +# template "/etc/postfix/ldap-virtual-mailboxes.cf" do +# source "ldap-virtual-mailboxes.cf.erb" +# mode 0600 +# variables server_host: "ldap.kosmos.local", +# bind_dn: credentials['ldap_dn'], +# bind_pw: credentials['ldap_dnpass'], +# search_base: "ou=kosmos.org,cn=users,dc=kosmos,dc=org", +# query_filter: "maildrop=%s", +# result_attribute: "mailhome", +# result_format: "%s/mail/" +# notifies :restart, "service[postfix]", :delayed +# end + +include_recipe 'postfix::server' + +service "postfix" do + action [:enable, :start] +end diff --git a/site-cookbooks/kosmos_email/templates/dovecot-ldap.conf.ext.erb b/site-cookbooks/kosmos_email/templates/dovecot-ldap.conf.ext.erb new file mode 100644 index 0000000..10ca936 --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/dovecot-ldap.conf.ext.erb @@ -0,0 +1,151 @@ +# This file is commonly accessed via passdb {} or userdb {} section in +# conf.d/auth-ldap.conf.ext + +# This file is opened as root, so it should be owned by root and mode 0600. +# +# http://wiki2.dovecot.org/AuthDatabase/LDAP +# +# NOTE: If you're not using authentication binds, you'll need to give +# dovecot-auth read access to userPassword field in the LDAP server. +# With OpenLDAP this is done by modifying /etc/ldap/slapd.conf. There should +# already be something like this: + +# access to attribute=userPassword +# by dn="" read # add this +# by anonymous auth +# by self write +# by * none + +# Space separated list of LDAP hosts to use. host:port is allowed too. +#hosts = + +# LDAP URIs to use. You can use this instead of hosts list. Note that this +# setting isn't supported by all LDAP libraries. +uris = <%= @uris %> + +# Distinguished Name - the username used to login to the LDAP server. +# Leave it commented out to bind anonymously (useful with auth_bind=yes). +dn = <%= @dn %> + +# Password for LDAP server, if dn is specified. +dnpass = <%= @dnpass %> + +# Use SASL binding instead of the simple binding. Note that this changes +# ldap_version automatically to be 3 if it's lower. +#sasl_bind = no +# SASL mechanism name to use. +#sasl_mech = +# SASL realm to use. +#sasl_realm = +# SASL authorization ID, ie. the dnpass is for this "master user", but the +# dn is still the logged in user. Normally you want to keep this empty. +#sasl_authz_id = + +# Use TLS to connect to the LDAP server. +#tls = no +# TLS options, currently supported only with OpenLDAP: +#tls_ca_cert_file = +#tls_ca_cert_dir = +#tls_cipher_suite = +# TLS cert/key is used only if LDAP server requires a client certificate. +#tls_cert_file = +#tls_key_file = +# Valid values: never, hard, demand, allow, try +#tls_require_cert = + +# Use the given ldaprc path. +#ldaprc_path = + +# LDAP library debug level as specified by LDAP_DEBUG_* in ldap_log.h. +# -1 = everything. You may need to recompile OpenLDAP with debugging enabled +# to get enough output. +#debug_level = 1 + +# Use authentication binding for verifying password's validity. This works by +# logging into LDAP server using the username and password given by client. +# The pass_filter is used to find the DN for the user. Note that the pass_attrs +# is still used, only the password field is ignored in it. Before doing any +# search, the binding is switched back to the default DN. +#auth_bind = no + +# If authentication binding is used, you can save one LDAP request per login +# if users' DN can be specified with a common template. The template can use +# the standard %variables (see user_filter). Note that you can't +# use any pass_attrs if you use this setting. +# +# If you use this setting, it's a good idea to use a different +# dovecot-ldap.conf.ext for userdb (it can even be a symlink, just as long as +# the filename is different in userdb's args). That way one connection is used +# only for LDAP binds and another connection is used for user lookups. +# Otherwise the binding is changed to the default DN before each user lookup. +# +# For example: +# auth_bind_userdn = cn=%u,ou=people,o=org +# +#auth_bind_userdn = + +# LDAP protocol version to use. Likely 2 or 3. +#ldap_version = 3 + +# LDAP base. %variables can be used here. +# For example: dc=mail, dc=example, dc=org +base = <%= @base %> + +# Dereference: never, searching, finding, always +#deref = never + +# Search scope: base, onelevel, subtree +#scope = subtree + +# User attributes are given in LDAP-name=dovecot-internal-name list. The +# internal names are: +# uid - System UID +# gid - System GID +# home - Home directory +# mail - Mail location +# +# There are also other special fields which can be returned, see +# http://wiki2.dovecot.org/UserDatabase/ExtraFields +user_attrs = <%= @user_attrs %> + +# Filter for user lookup. Some variables can be used (see +# http://wiki2.dovecot.org/Variables for full list): +# %u - username +# %n - user part in user@domain, same as %u if there's no domain +# %d - domain part in user@domain, empty if user there's no domain +user_filter = <%= @user_filter %> + +# Password checking attributes: +# user: Virtual user name (user@domain), if you wish to change the +# user-given username to something else +# password: Password, may optionally start with {type}, eg. {crypt} +# There are also other special fields which can be returned, see +# http://wiki2.dovecot.org/PasswordDatabase/ExtraFields +pass_attrs = <%= @pass_attrs %> + +# If you wish to avoid two LDAP lookups (passdb + userdb), you can use +# userdb prefetch instead of userdb ldap in dovecot.conf. In that case you'll +# also have to include user_attrs in pass_attrs field prefixed with "userdb_" +# string. For example: +#pass_attrs = uid=user,userPassword=password,\ +# homeDirectory=userdb_home,uidNumber=userdb_uid,gidNumber=userdb_gid + +# Filter for password lookups +pass_filter = <%= @pass_filter %> + +# Attributes and filter to get a list of all users +#iterate_attrs = uid=user +#iterate_filter = (objectClass=posixAccount) + +# Default password scheme. "{scheme}" before password overrides this. +# List of supported schemes is in: http://wiki2.dovecot.org/Authentication +default_pass_scheme = <%= @default_pass_scheme %> + +# By default all LDAP lookups are performed by the auth master process. +# If blocking=yes, auth worker processes are used to perform the lookups. +# Each auth worker process creates its own LDAP connection so this can +# increase parallelism. With blocking=no the auth master process can +# keep 8 requests pipelined for the LDAP connection, while with blocking=yes +# each connection has a maximum of 1 request running. For small systems the +# blocking=no is sufficient and uses less resources. +#blocking = no diff --git a/site-cookbooks/kosmos_email/templates/dovecot.conf.erb b/site-cookbooks/kosmos_email/templates/dovecot.conf.erb new file mode 100644 index 0000000..6b29a7f --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/dovecot.conf.erb @@ -0,0 +1,105 @@ +## Dovecot configuration file + +# If you're in a hurry, see http://wiki2.dovecot.org/QuickConfiguration + +# "doveconf -n" command gives a clean output of the changed settings. Use it +# instead of copy&pasting files when posting to the Dovecot mailing list. + +# '#' character and everything after it is treated as comments. Extra spaces +# and tabs are ignored. If you want to use either of these explicitly, put the +# value inside quotes, eg.: key = "# char and trailing whitespace " + +# Most (but not all) settings can be overridden by different protocols and/or +# source/destination IPs by placing the settings inside sections, for example: +# protocol imap { }, local 127.0.0.1 { }, remote 10.0.0.0/8 { } + +# Default values are shown for each setting, it's not required to uncomment +# those. These are exceptions to this though: No sections (e.g. namespace {}) +# or plugin settings are added by default, they're listed only as examples. +# Paths are also just examples with the real defaults being based on configure +# options. The paths listed here are for configure --prefix=/usr +# --sysconfdir=/etc --localstatedir=/var + +# Enable installed protocols +protocols = <%= @protocols %> +#!include_try /usr/share/dovecot/protocols.d/*.protocol + +# A comma separated list of IPs or hosts where to listen in for connections. +# "*" listens in all IPv4 interfaces, "::" listens in all IPv6 interfaces. +# If you want to specify non-default ports or anything more complex, +# edit conf.d/master.conf. +#listen = *, :: + +# Base directory where to store runtime data. +#base_dir = /var/run/dovecot/ + +# Name of this instance. In multi-instance setup doveadm and other commands +# can use -i to select which instance is used (an alternative +# to -c ). The instance name is also added to Dovecot processes +# in ps output. +#instance_name = dovecot + +# Greeting message for clients. +#login_greeting = Dovecot ready. + +# Space separated list of trusted network ranges. Connections from these +# IPs are allowed to override their IP addresses and ports (for logging and +# for authentication checks). disable_plaintext_auth is also ignored for +# these networks. Typically you'd specify your IMAP proxy servers here. +#login_trusted_networks = + +# Space separated list of login access check sockets (e.g. tcpwrap) +#login_access_sockets = + +# With proxy_maybe=yes if proxy destination matches any of these IPs, don't do +# proxying. This isn't necessary normally, but may be useful if the destination +# IP is e.g. a load balancer's IP. +#auth_proxy_self = + +# Show more verbose process titles (in ps). Currently shows user name and +# IP address. Useful for seeing who are actually using the IMAP processes +# (eg. shared mailboxes or if same uid is used for multiple accounts). +#verbose_proctitle = no + +# Should all processes be killed when Dovecot master process shuts down. +# Setting this to "no" means that Dovecot can be upgraded without +# forcing existing client connections to close (although that could also be +# a problem if the upgrade is e.g. because of a security fix). +#shutdown_clients = yes + +# If non-zero, run mail commands via this many connections to doveadm server, +# instead of running them directly in the same process. +#doveadm_worker_count = 0 +# UNIX socket or host:port used for connecting to doveadm server +#doveadm_socket_path = doveadm-server + +# Space separated list of environment variables that are preserved on Dovecot +# startup and passed down to all of its child processes. You can also give +# key=value pairs to always set specific settings. +#import_environment = TZ + +## +## Dictionary server settings +## + +# Dictionary can be used to store key=value lists. This is used by several +# plugins. The dictionary can be accessed either directly or though a +# dictionary server. The following dict block maps dictionary names to URIs +# when the server is used. These can then be referenced using URIs in format +# "proxy::". + +dict { + #quota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext +} + +# Most of the actual configuration gets included below. The filenames are +# first sorted by their ASCII value and parsed in that order. The 00-prefixes +# in filenames are intended to make it easier to understand the ordering. +!include conf.d/*.conf + +# A config file can also tried to be included without giving an error if +# it's not found: +!include_try local.conf + +haproxy_trusted_networks = <%= @haproxy_trusted_networks %> +haproxy_timeout = 3s diff --git a/site-cookbooks/kosmos_email/templates/dovecot_10-auth.conf.erb b/site-cookbooks/kosmos_email/templates/dovecot_10-auth.conf.erb new file mode 100644 index 0000000..f3270b1 --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/dovecot_10-auth.conf.erb @@ -0,0 +1,127 @@ +## +## Authentication processes +## + +# Disable LOGIN command and all other plaintext authentications unless +# SSL/TLS is used (LOGINDISABLED capability). Note that if the remote IP +# matches the local IP (ie. you're connecting from the same computer), the +# connection is considered secure and plaintext authentication is allowed. +# See also ssl=required setting. +disable_plaintext_auth = yes + +# Authentication cache size (e.g. 10M). 0 means it's disabled. Note that +# bsdauth and PAM require cache_key to be set for caching to be used. +#auth_cache_size = 0 +# Time to live for cached data. After TTL expires the cached record is no +# longer used, *except* if the main database lookup returns internal failure. +# We also try to handle password changes automatically: If user's previous +# authentication was successful, but this one wasn't, the cache isn't used. +# For now this works only with plaintext authentication. +#auth_cache_ttl = 1 hour +# TTL for negative hits (user not found, password mismatch). +# 0 disables caching them completely. +#auth_cache_negative_ttl = 1 hour + +# Space separated list of realms for SASL authentication mechanisms that need +# them. You can leave it empty if you don't want to support multiple realms. +# Many clients simply use the first one listed here, so keep the default realm +# first. +#auth_realms = + +# Default realm/domain to use if none was specified. This is used for both +# SASL realms and appending @domain to username in plaintext logins. +#auth_default_realm = + +# List of allowed characters in username. If the user-given username contains +# a character not listed in here, the login automatically fails. This is just +# an extra check to make sure user can't exploit any potential quote escaping +# vulnerabilities with SQL/LDAP databases. If you want to allow all characters, +# set this value to empty. +#auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@ + +# Username character translations before it's looked up from databases. The +# value contains series of from -> to characters. For example "#@/@" means +# that '#' and '/' characters are translated to '@'. +#auth_username_translation = + +# Username formatting before it's looked up from databases. You can use +# the standard variables here, eg. %Lu would lowercase the username, %n would +# drop away the domain if it was given, or "%n-AT-%d" would change the '@' into +# "-AT-". This translation is done after auth_username_translation changes. +auth_username_format = %n + +# If you want to allow master users to log in by specifying the master +# username within the normal username string (ie. not using SASL mechanism's +# support for it), you can specify the separator character here. The format +# is then . UW-IMAP uses "*" as the +# separator, so that could be a good choice. +#auth_master_user_separator = + +# Username to use for users logging in with ANONYMOUS SASL mechanism +#auth_anonymous_username = anonymous + +# Maximum number of dovecot-auth worker processes. They're used to execute +# blocking passdb and userdb queries (eg. MySQL and PAM). They're +# automatically created and destroyed as needed. +#auth_worker_max_count = 30 + +# Host name to use in GSSAPI principal names. The default is to use the +# name returned by gethostname(). Use "$ALL" (with quotes) to allow all keytab +# entries. +#auth_gssapi_hostname = + +# Kerberos keytab to use for the GSSAPI mechanism. Will use the system +# default (usually /etc/krb5.keytab) if not specified. You may need to change +# the auth service to run as root to be able to read this file. +#auth_krb5_keytab = + +# Do NTLM and GSS-SPNEGO authentication using Samba's winbind daemon and +# ntlm_auth helper. +#auth_use_winbind = no + +# Path for Samba's ntlm_auth helper binary. +#auth_winbind_helper_path = /usr/bin/ntlm_auth + +# Time to delay before replying to failed authentications. +#auth_failure_delay = 2 secs + +# Require a valid SSL client certificate or the authentication fails. +#auth_ssl_require_client_cert = no + +# Take the username from client's SSL certificate, using +# X509_NAME_get_text_by_NID() which returns the subject's DN's +# CommonName. +#auth_ssl_username_from_cert = no + +# Space separated list of wanted authentication mechanisms: +# plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp +# gss-spnego +# NOTE: See also disable_plaintext_auth setting. +auth_mechanisms = plain login + +## +## Password and user databases +## + +# +# Password database is used to verify user's password (and nothing more). +# You can have multiple passdbs and userdbs. This is useful if you want to +# allow both system users (/etc/passwd) and virtual users to login without +# duplicating the system users into virtual database. +# +# +# +# User database specifies where mails are located and what user/group IDs +# own them. For single-UID configuration use "static" userdb. +# +# + +#!include auth-deny.conf.ext +#!include auth-master.conf.ext + +#!include auth-system.conf.ext +#!include auth-sql.conf.ext +!include auth-ldap.conf.ext +#!include auth-passwdfile.conf.ext +#!include auth-checkpassword.conf.ext +#!include auth-static.conf.ext diff --git a/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb b/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb new file mode 100644 index 0000000..b5b0593 --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb @@ -0,0 +1,421 @@ +## +## Mailbox locations and namespaces +## + +# Location for users' mailboxes. The default is empty, which means that Dovecot +# tries to find the mailboxes automatically. This won't work if the user +# doesn't yet have any mail, so you should explicitly tell Dovecot the full +# location. +# +# If you're using mbox, giving a path to the INBOX file (eg. /var/mail/%u) +# isn't enough. You'll also need to tell Dovecot where the other mailboxes are +# kept. This is called the "root mail directory", and it must be the first +# path given in the mail_location setting. +# +# There are a few special variables you can use, eg.: +# +# %u - username +# %n - user part in user@domain, same as %u if there's no domain +# %d - domain part in user@domain, empty if there's no domain +# %h - home directory +# +# See doc/wiki/Variables.txt for full list. Some examples: +# +# mail_location = maildir:~/Maildir +# mail_location = mbox:~/mail:INBOX=/var/mail/%u +# mail_location = mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%n +# +# +# +mail_location = mbox:~/mail:INBOX=/var/mail/%d/%u + +# If you need to set multiple mailbox locations or want to change default +# namespace settings, you can do it by defining namespace sections. +# +# You can have private, shared and public namespaces. Private namespaces +# are for user's personal mails. Shared namespaces are for accessing other +# users' mailboxes that have been shared. Public namespaces are for shared +# mailboxes that are managed by sysadmin. If you create any shared or public +# namespaces you'll typically want to enable ACL plugin also, otherwise all +# users can access all the shared mailboxes, assuming they have permissions +# on filesystem level to do so. +namespace inbox { + # Namespace type: private, shared or public + #type = private + + # Hierarchy separator to use. You should use the same separator for all + # namespaces or some clients get confused. '/' is usually a good one. + # The default however depends on the underlying mail storage format. + #separator = + + # Prefix required to access this namespace. This needs to be different for + # all namespaces. For example "Public/". + #prefix = + + # Physical location of the mailbox. This is in same format as + # mail_location, which is also the default for it. + #location = + + # There can be only one INBOX, and this setting defines which namespace + # has it. + inbox = yes + + # If namespace is hidden, it's not advertised to clients via NAMESPACE + # extension. You'll most likely also want to set list=no. This is mostly + # useful when converting from another server with different namespaces which + # you want to deprecate but still keep working. For example you can create + # hidden namespaces with prefixes "~/mail/", "~%u/mail/" and "mail/". + #hidden = no + + # Show the mailboxes under this namespace with LIST command. This makes the + # namespace visible for clients that don't support NAMESPACE extension. + # "children" value lists child mailboxes, but hides the namespace prefix. + #list = yes + + # Namespace handles its own subscriptions. If set to "no", the parent + # namespace handles them (empty prefix should always have this as "yes") + #subscriptions = yes + + # See 15-mailboxes.conf for definitions of special mailboxes. +} + +# Example shared namespace configuration +#namespace { + #type = shared + #separator = / + + # Mailboxes are visible under "shared/user@domain/" + # %%n, %%d and %%u are expanded to the destination user. + #prefix = shared/%%u/ + + # Mail location for other users' mailboxes. Note that %variables and ~/ + # expands to the logged in user's data. %%n, %%d, %%u and %%h expand to the + # destination user's data. + #location = maildir:%%h/Maildir:INDEX=~/Maildir/shared/%%u + + # Use the default namespace for saving subscriptions. + #subscriptions = no + + # List the shared/ namespace only if there are visible shared mailboxes. + #list = children +#} +# Should shared INBOX be visible as "shared/user" or "shared/user/INBOX"? +#mail_shared_explicit_inbox = no + +# System user and group used to access mails. If you use multiple, userdb +# can override these by returning uid or gid fields. You can use either numbers +# or names. +mail_uid = <%= @mail_uid %> +mail_gid = <%= @mail_gid %> + +# Group to enable temporarily for privileged operations. Currently this is +# used only with INBOX when either its initial creation or dotlocking fails. +# Typically this is set to "mail" to give access to /var/mail. +mail_privileged_group = mail + +# Grant access to these supplementary groups for mail processes. Typically +# these are used to set up access to shared mailboxes. Note that it may be +# dangerous to set these if users can create symlinks (e.g. if "mail" group is +# set here, ln -s /var/mail ~/mail/var could allow a user to delete others' +# mailboxes, or ln -s /secret/shared/box ~/mail/mybox would allow reading it). +#mail_access_groups = + +# Allow full filesystem access to clients. There's no access checks other than +# what the operating system does for the active UID/GID. It works with both +# maildir and mboxes, allowing you to prefix mailboxes names with eg. /path/ +# or ~user/. +#mail_full_filesystem_access = no + +# Dictionary for key=value mailbox attributes. This is used for example by +# URLAUTH and METADATA extensions. +#mail_attribute_dict = + +# A comment or note that is associated with the server. This value is +# accessible for authenticated users through the IMAP METADATA server +# entry "/shared/comment". +#mail_server_comment = "" + +# Indicates a method for contacting the server administrator. According to +# RFC 5464, this value MUST be a URI (e.g., a mailto: or tel: URL), but that +# is currently not enforced. Use for example mailto:admin@example.com. This +# value is accessible for authenticated users through the IMAP METADATA server +# entry "/shared/admin". +#mail_server_admin = + +## +## Mail processes +## + +# Don't use mmap() at all. This is required if you store indexes to shared +# filesystems (NFS or clustered filesystem). +#mmap_disable = no + +# Rely on O_EXCL to work when creating dotlock files. NFS supports O_EXCL +# since version 3, so this should be safe to use nowadays by default. +#dotlock_use_excl = yes + +# When to use fsync() or fdatasync() calls: +# optimized (default): Whenever necessary to avoid losing important data +# always: Useful with e.g. NFS when write()s are delayed +# never: Never use it (best performance, but crashes can lose data) +#mail_fsync = optimized + +# Locking method for index files. Alternatives are fcntl, flock and dotlock. +# Dotlocking uses some tricks which may create more disk I/O than other locking +# methods. NFS users: flock doesn't work, remember to change mmap_disable. +#lock_method = fcntl + +# Directory where mails can be temporarily stored. Usually it's used only for +# mails larger than >= 128 kB. It's used by various parts of Dovecot, for +# example LDA/LMTP while delivering large mails or zlib plugin for keeping +# uncompressed mails. +#mail_temp_dir = /tmp + +# Valid UID range for users, defaults to 500 and above. This is mostly +# to make sure that users can't log in as daemons or other system users. +# Note that denying root logins is hardcoded to dovecot binary and can't +# be done even if first_valid_uid is set to 0. +#first_valid_uid = 500 +#last_valid_uid = 0 + +# Valid GID range for users, defaults to non-root/wheel. Users having +# non-valid GID as primary group ID aren't allowed to log in. If user +# belongs to supplementary groups with non-valid GIDs, those groups are +# not set. +#first_valid_gid = 1 +#last_valid_gid = 0 + +# Maximum allowed length for mail keyword name. It's only forced when trying +# to create new keywords. +#mail_max_keyword_length = 50 + +# ':' separated list of directories under which chrooting is allowed for mail +# processes (ie. /var/mail will allow chrooting to /var/mail/foo/bar too). +# This setting doesn't affect login_chroot, mail_chroot or auth chroot +# settings. If this setting is empty, "/./" in home dirs are ignored. +# WARNING: Never add directories here which local users can modify, that +# may lead to root exploit. Usually this should be done only if you don't +# allow shell access for users. +#valid_chroot_dirs = + +# Default chroot directory for mail processes. This can be overridden for +# specific users in user database by giving /./ in user's home directory +# (eg. /home/./user chroots into /home). Note that usually there is no real +# need to do chrooting, Dovecot doesn't allow users to access files outside +# their mail directory anyway. If your home directories are prefixed with +# the chroot directory, append "/." to mail_chroot. +#mail_chroot = + +# UNIX socket path to master authentication server to find users. +# This is used by imap (for shared users) and lda. +#auth_socket_path = /var/run/dovecot/auth-userdb + +# Directory where to look up mail plugins. +#mail_plugin_dir = /usr/lib/dovecot/modules + +# Space separated list of plugins to load for all services. Plugins specific to +# IMAP, LDA, etc. are added to this list in their own .conf files. +#mail_plugins = + +## +## Mailbox handling optimizations +## + +# Mailbox list indexes can be used to optimize IMAP STATUS commands. They are +# also required for IMAP NOTIFY extension to be enabled. +#mailbox_list_index = yes + +# Trust mailbox list index to be up-to-date. This reduces disk I/O at the cost +# of potentially returning out-of-date results after e.g. server crashes. +# The results will be automatically fixed once the folders are opened. +#mailbox_list_index_very_dirty_syncs = yes + +# Should INBOX be kept up-to-date in the mailbox list index? By default it's +# not, because most of the mailbox accesses will open INBOX anyway. +#mailbox_list_index_include_inbox = no + +# The minimum number of mails in a mailbox before updates are done to cache +# file. This allows optimizing Dovecot's behavior to do less disk writes at +# the cost of more disk reads. +#mail_cache_min_mail_count = 0 + +# When IDLE command is running, mailbox is checked once in a while to see if +# there are any new mails or other changes. This setting defines the minimum +# time to wait between those checks. Dovecot can also use inotify and +# kqueue to find out immediately when changes occur. +#mailbox_idle_check_interval = 30 secs + +# Save mails with CR+LF instead of plain LF. This makes sending those mails +# take less CPU, especially with sendfile() syscall with Linux and FreeBSD. +# But it also creates a bit more disk I/O which may just make it slower. +# Also note that if other software reads the mboxes/maildirs, they may handle +# the extra CRs wrong and cause problems. +#mail_save_crlf = no + +# Max number of mails to keep open and prefetch to memory. This only works with +# some mailbox formats and/or operating systems. +#mail_prefetch_count = 0 + +# How often to scan for stale temporary files and delete them (0 = never). +# These should exist only after Dovecot dies in the middle of saving mails. +#mail_temp_scan_interval = 1w + +# How many slow mail accesses sorting can perform before it returns failure. +# With IMAP the reply is: NO [LIMIT] Requested sort would have taken too long. +# The untagged SORT reply is still returned, but it's likely not correct. +#mail_sort_max_read_count = 0 + +protocol !indexer-worker { + # If folder vsize calculation requires opening more than this many mails from + # disk (i.e. mail sizes aren't in cache already), return failure and finish + # the calculation via indexer process. Disabled by default. This setting must + # be 0 for indexer-worker processes. + #mail_vsize_bg_after_count = 0 +} + +## +## Maildir-specific settings +## + +# By default LIST command returns all entries in maildir beginning with a dot. +# Enabling this option makes Dovecot return only entries which are directories. +# This is done by stat()ing each entry, so it causes more disk I/O. +# (For systems setting struct dirent->d_type, this check is free and it's +# done always regardless of this setting) +#maildir_stat_dirs = no + +# When copying a message, do it with hard links whenever possible. This makes +# the performance much better, and it's unlikely to have any side effects. +#maildir_copy_with_hardlinks = yes + +# Assume Dovecot is the only MUA accessing Maildir: Scan cur/ directory only +# when its mtime changes unexpectedly or when we can't find the mail otherwise. +#maildir_very_dirty_syncs = no + +# If enabled, Dovecot doesn't use the S= in the Maildir filenames for +# getting the mail's physical size, except when recalculating Maildir++ quota. +# This can be useful in systems where a lot of the Maildir filenames have a +# broken size. The performance hit for enabling this is very small. +#maildir_broken_filename_sizes = no + +# Always move mails from new/ directory to cur/, even when the \Recent flags +# aren't being reset. +#maildir_empty_new = no + +## +## mbox-specific settings +## + +# Which locking methods to use for locking mbox. There are four available: +# dotlock: Create .lock file. This is the oldest and most NFS-safe +# solution. If you want to use /var/mail/ like directory, the users +# will need write access to that directory. +# dotlock_try: Same as dotlock, but if it fails because of permissions or +# because there isn't enough disk space, just skip it. +# fcntl : Use this if possible. Works with NFS too if lockd is used. +# flock : May not exist in all systems. Doesn't work with NFS. +# lockf : May not exist in all systems. Doesn't work with NFS. +# +# You can use multiple locking methods; if you do the order they're declared +# in is important to avoid deadlocks if other MTAs/MUAs are using multiple +# locking methods as well. Some operating systems don't allow using some of +# them simultaneously. +# +# The Debian value for mbox_write_locks differs from upstream Dovecot. It is +# changed to be compliant with Debian Policy (section 11.6) for NFS safety. +# Dovecot: mbox_write_locks = dotlock fcntl +# Debian: mbox_write_locks = fcntl dotlock +# +#mbox_read_locks = fcntl +#mbox_write_locks = fcntl dotlock + +# Maximum time to wait for lock (all of them) before aborting. +#mbox_lock_timeout = 5 mins + +# If dotlock exists but the mailbox isn't modified in any way, override the +# lock file after this much time. +#mbox_dotlock_change_timeout = 2 mins + +# When mbox changes unexpectedly we have to fully read it to find out what +# changed. If the mbox is large this can take a long time. Since the change +# is usually just a newly appended mail, it'd be faster to simply read the +# new mails. If this setting is enabled, Dovecot does this but still safely +# fallbacks to re-reading the whole mbox file whenever something in mbox isn't +# how it's expected to be. The only real downside to this setting is that if +# some other MUA changes message flags, Dovecot doesn't notice it immediately. +# Note that a full sync is done with SELECT, EXAMINE, EXPUNGE and CHECK +# commands. +#mbox_dirty_syncs = yes + +# Like mbox_dirty_syncs, but don't do full syncs even with SELECT, EXAMINE, +# EXPUNGE or CHECK commands. If this is set, mbox_dirty_syncs is ignored. +#mbox_very_dirty_syncs = no + +# Delay writing mbox headers until doing a full write sync (EXPUNGE and CHECK +# commands and when closing the mailbox). This is especially useful for POP3 +# where clients often delete all mails. The downside is that our changes +# aren't immediately visible to other MUAs. +#mbox_lazy_writes = yes + +# If mbox size is smaller than this (e.g. 100k), don't write index files. +# If an index file already exists it's still read, just not updated. +#mbox_min_index_size = 0 + +# Mail header selection algorithm to use for MD5 POP3 UIDLs when +# pop3_uidl_format=%m. For backwards compatibility we use apop3d inspired +# algorithm, but it fails if the first Received: header isn't unique in all +# mails. An alternative algorithm is "all" that selects all headers. +#mbox_md5 = apop3d + +## +## mdbox-specific settings +## + +# Maximum dbox file size until it's rotated. +#mdbox_rotate_size = 10M + +# Maximum dbox file age until it's rotated. Typically in days. Day begins +# from midnight, so 1d = today, 2d = yesterday, etc. 0 = check disabled. +#mdbox_rotate_interval = 0 + +# When creating new mdbox files, immediately preallocate their size to +# mdbox_rotate_size. This setting currently works only in Linux with some +# filesystems (ext4, xfs). +#mdbox_preallocate_space = no + +## +## Mail attachments +## + +# sdbox and mdbox support saving mail attachments to external files, which +# also allows single instance storage for them. Other backends don't support +# this for now. + +# Directory root where to store mail attachments. Disabled, if empty. +#mail_attachment_dir = + +# Attachments smaller than this aren't saved externally. It's also possible to +# write a plugin to disable saving specific attachments externally. +#mail_attachment_min_size = 128k + +# Filesystem backend to use for saving attachments: +# posix : No SiS done by Dovecot (but this might help FS's own deduplication) +# sis posix : SiS with immediate byte-by-byte comparison during saving +# sis-queue posix : SiS with delayed comparison and deduplication +#mail_attachment_fs = sis posix + +# Hash format to use in attachment filenames. You can add any text and +# variables: %{md4}, %{md5}, %{sha1}, %{sha256}, %{sha512}, %{size}. +# Variables can be truncated, e.g. %{sha256:80} returns only first 80 bits +#mail_attachment_hash = %{sha1} + +# Settings to control adding $HasAttachment or $HasNoAttachment keywords. +# By default, all MIME parts with Content-Disposition=attachment, or inlines +# with filename parameter are consired attachments. +# add-flags - Add the keywords when saving new mails or when fetching can +# do it efficiently. +# content-type=type or !type - Include/exclude content type. Excluding will +# never consider the matched MIME part as attachment. Including will only +# negate an exclusion (e.g. content-type=!foo/* content-type=foo/bar). +# exclude-inlined - Exclude any Content-Disposition=inline MIME part. +#mail_attachment_detection_options = diff --git a/site-cookbooks/kosmos_email/templates/dovecot_10-master.conf.erb b/site-cookbooks/kosmos_email/templates/dovecot_10-master.conf.erb new file mode 100644 index 0000000..a55a9a6 --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/dovecot_10-master.conf.erb @@ -0,0 +1,113 @@ +#default_process_limit = 100 +#default_client_limit = 1000 + +# Default VSZ (virtual memory size) limit for service processes. This is mainly +# intended to catch and kill processes that leak memory before they eat up +# everything. +#default_vsz_limit = 256M + +# Login user is internally used by login processes. This is the most untrusted +# user in Dovecot system. It shouldn't have access to anything at all. +#default_login_user = dovenull + +# Internal user is used by unprivileged processes. It should be separate from +# login user, so that login processes can't disturb other processes. +#default_internal_user = dovecot + +service imap-login { + inet_listener imap { + port = 143 + } + inet_listener imaps { + port = 993 + ssl = yes + } + inet_listener imap_haproxy { + port = 10143 + haproxy = yes + } + inet_listener imaps_haproxy { + port = 10993 + ssl = yes + haproxy = yes + } + + # Number of connections to handle before starting a new process. Typically + # the only useful values are 0 (unlimited) or 1. 1 is more secure, but 0 + # is faster. + #service_count = 1 + + # Number of processes to always keep waiting for more connections. + #process_min_avail = 0 + + # If you set service_count=0, you probably need to grow this. + #vsz_limit = $default_vsz_limit +} + +service pop3-login { + inet_listener pop3 { + #port = 110 + } + inet_listener pop3s { + #port = 995 + #ssl = yes + } +} + +service submission-login { + inet_listener submission { + #port = 587 + } +} + +service lmtp { + unix_listener /var/spool/postfix/private/dovecot-lmtp { + mode = 0600 + user = postfix + group = postfix + } +} + +service imap { + # Most of the memory goes to mmap()ing files. You may need to increase this + # limit if you have huge mailboxes. + #vsz_limit = $default_vsz_limit + + # Max. number of IMAP processes (connections) + #process_limit = 1024 +} + +service pop3 { + # Max. number of POP3 processes (connections) + #process_limit = 1024 +} + +service submission { + # Max. number of SMTP Submission processes (connections) + #process_limit = 1024 +} + +service auth { + unix_listener /var/spool/postfix/private/auth { + mode = 0660 + user = postfix + group = postfix + } +} + +service auth-worker { + # Auth worker process is run as root by default, so that it can access + # /etc/shadow. If this isn't necessary, the user should be changed to + # $default_internal_user. + #user = root +} + +service dict { + # If dict proxy is used, mail processes should have access to its socket. + # For example: mode=0660, group=vmail and global mail_access_groups=vmail + unix_listener dict { + #mode = 0600 + #user = + #group = + } +} diff --git a/site-cookbooks/kosmos_email/templates/dovecot_10-ssl.conf.erb b/site-cookbooks/kosmos_email/templates/dovecot_10-ssl.conf.erb new file mode 100644 index 0000000..649a26a --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/dovecot_10-ssl.conf.erb @@ -0,0 +1,83 @@ +## +## SSL settings +## + +# SSL/TLS support: yes, no, required. +ssl = <%= @ssl %> + +# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before +# dropping root privileges, so keep the key file unreadable by anyone but +# root. Included doc/mkcert.sh can be used to easily generate self-signed +# certificate, just make sure to update the domains in dovecot-openssl.cnf +ssl_cert = <<%= @ssl_cert %> +ssl_key = <<%= @ssl_key %> + +# If key file is password protected, give the password here. Alternatively +# give it when starting dovecot with -p parameter. Since this file is often +# world-readable, you may want to place this setting instead to a different +# root owned 0600 file by using ssl_key_password = +bind_dn = <%= @bind_dn %> +bind_pw = <%= @bind_pw %> + +search_base = <%= @search_base %> +query_filter = <%= @query_filter %> +result_attribute = <%= @result_attribute %> diff --git a/site-cookbooks/kosmos_email/templates/ldap-virtual-mailboxes.cf.erb b/site-cookbooks/kosmos_email/templates/ldap-virtual-mailboxes.cf.erb new file mode 100644 index 0000000..b65d8d2 --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/ldap-virtual-mailboxes.cf.erb @@ -0,0 +1,7 @@ +server_host = <%= @server_host %> +bind_dn = <%= @bind_dn %> +bind_pw = <%= @bind_pw %> + +query_filter = <%= @query_filter %> +result_attribute = <%= @result_attribute %> +result_format = <%= @result_format %> diff --git a/site-cookbooks/kosmos_email/test/integration/default/default_test.rb b/site-cookbooks/kosmos_email/test/integration/default/default_test.rb new file mode 100644 index 0000000..cd23e4f --- /dev/null +++ b/site-cookbooks/kosmos_email/test/integration/default/default_test.rb @@ -0,0 +1,16 @@ +# Chef InSpec test for recipe kosmos_email::default + +# The Chef InSpec reference, with examples and extensive documentation, can be +# found at https://docs.chef.io/inspec/resources/ + +describe package('postfix') do + it { should be_installed } +end + +# describe package('dovecot-core') do +# it { should be_installed } +# end + +describe port(25) do + it { should be_listening } +end From 51068e5259f5add096ea94455bf9d6419c52da97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 1 Dec 2023 09:58:25 +0100 Subject: [PATCH 03/26] Add email credentials --- data_bags/credentials/email.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 data_bags/credentials/email.json diff --git a/data_bags/credentials/email.json b/data_bags/credentials/email.json new file mode 100644 index 0000000..50f54f7 --- /dev/null +++ b/data_bags/credentials/email.json @@ -0,0 +1,17 @@ +{ + "id": "email", + "ldap_dn": { + "encrypted_data": "jMHHa8DeU4HCieF/ElOxrNJcHLRzjXGGFB1eJubtiARFpMYx+4hG\n", + "iv": "ojKHl8Va1GOj1sfr\n", + "auth_tag": "wkHLRyFF7WYllh+hXRIBJA==\n", + "version": 3, + "cipher": "aes-256-gcm" + }, + "ldap_dnpass": { + "encrypted_data": "mCyzownpB0Q7BW4k7E+yXIwzSzaChPTEZHAWGiEcnXo2ioQ=\n", + "iv": "jc9/VY7AlQ5ttMm8\n", + "auth_tag": "mAZuoZOIJ4zRLdYbaetiag==\n", + "version": 3, + "cipher": "aes-256-gcm" + } +} \ No newline at end of file From 495a4231fbd9dd75aee070438b3d44e5beaf10d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 1 Dec 2023 09:59:41 +0100 Subject: [PATCH 04/26] Add mail server node --- clients/email-1.json | 4 +++ nodes/mail.kosmos.org.json | 67 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 clients/email-1.json create mode 100644 nodes/mail.kosmos.org.json diff --git a/clients/email-1.json b/clients/email-1.json new file mode 100644 index 0000000..5f0be00 --- /dev/null +++ b/clients/email-1.json @@ -0,0 +1,4 @@ +{ + "name": "email-1", + "public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxDRdvMYKRjejoFsOxS6s\n4gj0Gsaxk/j25A5VPHBcEhr+NOh8W/6NnTTHuFMaorEIl/2kscgrcwriDN7xIFmO\nz/C1+spDLPMGSWd+422KSS3fjVfByLlMwxh171RDZBlZVze7H7CIV/rxCG7Ri85y\nPvyp2rT4ioyVGyYK3e8CiXwQckpFC1ex9VRk/GR8zbCYUIw+qbTFRcl/mQuxKqWK\n22vrgAR+6OL8lcyhssmKiQ1r3GtxwJusgffw4/5S8sRR1z8OB4wiwgOWR1E36EbF\nhTBjFzPiKVjVjP/TQpUoYdnBhuD223M8nPWJl1HMVQPMjL6R2BBOF+iK0Wx9SiFD\nJwIDAQAB\n-----END PUBLIC KEY-----\n" +} \ No newline at end of file diff --git a/nodes/mail.kosmos.org.json b/nodes/mail.kosmos.org.json new file mode 100644 index 0000000..e9b7f83 --- /dev/null +++ b/nodes/mail.kosmos.org.json @@ -0,0 +1,67 @@ +{ + "name": "mail.kosmos.org", + "chef_environment": "production", + "normal": { + "knife_zero": { + "host": "10.1.1.141" + } + }, + "automatic": { + "fqdn": "mail.kosmos.org", + "os": "linux", + "os_version": "5.15.0-1045-kvm", + "hostname": "mail", + "ipaddress": "192.168.122.127", + "roles": [ + "base", + "kvm_guest", + "email_server", + "ldap_client" + ], + "recipes": [ + "kosmos-base", + "kosmos-base::default", + "kosmos_kvm::guest", + "kosmos-dirsrv::hostsfile", + "kosmos_email", + "kosmos_email::default", + "apt::default", + "timezone_iii::default", + "timezone_iii::debian", + "ntp::default", + "ntp::apparmor", + "kosmos-base::systemd_emails", + "apt::unattended-upgrades", + "kosmos-base::firewall", + "kosmos-postfix::default", + "hostname::default", + "kosmos-base::letsencrypt", + "kosmos_email::postfix", + "postfix::server", + "postfix::default", + "postfix::_common", + "postfix::_attributes", + "postfix::relay_restrictions", + "kosmos_email::dovecot" + ], + "platform": "ubuntu", + "platform_version": "22.04", + "cloud": null, + "chef_packages": { + "chef": { + "version": "18.3.0", + "chef_root": "/opt/chef/embedded/lib/ruby/gems/3.1.0/gems/chef-18.3.0/lib", + "chef_effortless": null + }, + "ohai": { + "version": "18.1.4", + "ohai_root": "/opt/chef/embedded/lib/ruby/gems/3.1.0/gems/ohai-18.1.4/lib/ohai" + } + } + }, + "run_list": [ + "role[base]", + "role[kvm_guest]", + "role[email_server]" + ] +} From 9d0ff358ef2d6e1a63c8f465c54b831dcd6896cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 1 Dec 2023 10:00:07 +0100 Subject: [PATCH 05/26] Only use certbot deploy hook when applicable --- site-cookbooks/kosmos-base/resources/tls_cert_for.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site-cookbooks/kosmos-base/resources/tls_cert_for.rb b/site-cookbooks/kosmos-base/resources/tls_cert_for.rb index c359ac4..02e73d2 100644 --- a/site-cookbooks/kosmos-base/resources/tls_cert_for.rb +++ b/site-cookbooks/kosmos-base/resources/tls_cert_for.rb @@ -36,8 +36,8 @@ action :create do --agree-tos \ --manual-auth-hook '#{hook_path} auth' \ --manual-cleanup-hook '#{hook_path} cleanup' \ - --deploy-hook /etc/letsencrypt/renewal-hooks/post/openresty \ --email ops@kosmos.org \ + #{node.run_list.roles.include?("openresty_proxy") ? '--deploy-hook /etc/letsencrypt/renewal-hooks/post/openresty' : nil } \ #{domains.map {|d| "-d #{d}" }.join(" ")} CMD not_if do From 335a0821712ac92a498e84d097dbb90069f7ff21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 1 Dec 2023 10:00:35 +0100 Subject: [PATCH 06/26] Put an LDAP server in the production env --- nodes/ldap-4.kosmos.org.json | 1 + 1 file changed, 1 insertion(+) diff --git a/nodes/ldap-4.kosmos.org.json b/nodes/ldap-4.kosmos.org.json index 4a7230c..f66c37e 100644 --- a/nodes/ldap-4.kosmos.org.json +++ b/nodes/ldap-4.kosmos.org.json @@ -1,5 +1,6 @@ { "name": "ldap-4.kosmos.org", + "chef_environment": "production", "normal": { "knife_zero": { "host": "10.1.1.106" From e4abfb1b756c89d57467540357ce82e7d34bd8ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 1 Dec 2023 10:01:34 +0100 Subject: [PATCH 07/26] Use more reasonable priority for attributes in recipe --- .../kosmos-postfix/recipes/default.rb | 42 ++++++------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/site-cookbooks/kosmos-postfix/recipes/default.rb b/site-cookbooks/kosmos-postfix/recipes/default.rb index 8fa2c14..53e0837 100644 --- a/site-cookbooks/kosmos-postfix/recipes/default.rb +++ b/site-cookbooks/kosmos-postfix/recipes/default.rb @@ -2,39 +2,21 @@ # Cookbook Name:: kosmos-postfix # Recipe:: default # -# The MIT License (MIT) -# -# Copyright:: 2019, Kosmos Developers -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. + +node.default['postfix']['main']['smtp_tls_CAfile'] = '/etc/ssl/certs/ca-certificates.crt' +node.default['postfix']['main']['smtpd_tls_CAfile'] = '/etc/ssl/certs/ca-certificates.crt' + +return if node.run_list.roles.include?("email_server") smtp_credentials = Chef::EncryptedDataBagItem.load('credentials', 'smtp') -node.override['postfix']['sasl']['smtp_sasl_user_name'] = smtp_credentials['user_name'] -node.override['postfix']['sasl']['smtp_sasl_passwd'] = smtp_credentials['password'] -node.override['postfix']['sasl_password_file'] = "#{node['postfix']['conf_dir']}/sasl_passwd" +node.default['postfix']['sasl']['smtp_sasl_user_name'] = smtp_credentials['user_name'] +node.default['postfix']['sasl']['smtp_sasl_passwd'] = smtp_credentials['password'] +node.default['postfix']['sasl_password_file'] = "#{node['postfix']['conf_dir']}/sasl_passwd" # Postfix doesn't support smtps relayhost, use STARTSSL instead -node.override['postfix']['main']['relayhost'] = smtp_credentials['relayhost'] -node.override['postfix']['main']['smtp_sasl_auth_enable'] = 'yes' -node.override['postfix']['main']['smtp_sasl_password_maps'] = "hash:#{node['postfix']['sasl_password_file']}" -node.override['postfix']['main']['smtp_sasl_security_options'] = 'noanonymous' -node.override['postfix']['main']['smtp_tls_CAfile'] = '/etc/ssl/certs/ca-certificates.crt' -node.override['postfix']['main']['smtpd_tls_CAfile'] = '/etc/ssl/certs/ca-certificates.crt' +node.default['postfix']['main']['relayhost'] = smtp_credentials['relayhost'] +node.default['postfix']['main']['smtp_sasl_auth_enable'] = 'yes' +node.default['postfix']['main']['smtp_sasl_password_maps'] = "hash:#{node['postfix']['sasl_password_file']}" +node.default['postfix']['main']['smtp_sasl_security_options'] = 'noanonymous' include_recipe 'postfix::default' From 89d00afd1cbfe60f5564bf842f61713605b87f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 1 Dec 2023 10:02:11 +0100 Subject: [PATCH 08/26] Set up email proxy --- nodes/draco.kosmos.org.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nodes/draco.kosmos.org.json b/nodes/draco.kosmos.org.json index 82b3a25..9854a65 100644 --- a/nodes/draco.kosmos.org.json +++ b/nodes/draco.kosmos.org.json @@ -26,6 +26,7 @@ "roles": [ "base", "kvm_host", + "email_proxy", "openresty_proxy", "openresty", "garage_gateway", @@ -36,6 +37,7 @@ "kosmos-base::default", "kosmos_kvm::host", "kosmos_kvm::backup", + "kosmos_email::firewall", "kosmos_openresty", "kosmos_openresty::default", "kosmos_openresty::firewall", @@ -119,6 +121,7 @@ "run_list": [ "role[base]", "role[kvm_host]", + "role[email_proxy]", "role[openresty_proxy]", "recipe[kosmos_encfs]", "recipe[kosmos-ejabberd::firewall]", From 366c0c0d3c3715c9fef2e0dd31fe4a08cec8ee59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 1 Dec 2023 10:02:25 +0100 Subject: [PATCH 09/26] Add WIP email domain and hostname --- environments/production.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/environments/production.json b/environments/production.json index 8404558..76db794 100644 --- a/environments/production.json +++ b/environments/production.json @@ -19,6 +19,10 @@ "ejabberd": { "turn_ip_address": "148.251.83.201" }, + "email": { + "domain": "mail.kosmos.org", + "hostname": "mail.kosmos.org" + }, "garage": { "replication_mode": "2", "s3_api_root_domain": "s3.kosmos.org", From ce00852bba1e948788b74ed5491b7b954a02a6da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Fri, 1 Dec 2023 12:19:21 +0100 Subject: [PATCH 10/26] Remove obsolete config file --- site-cookbooks/kosmos_email/recipes/postfix.rb | 13 ------------- .../templates/ldap-virtual-mailboxes.cf.erb | 7 ------- 2 files changed, 20 deletions(-) delete mode 100644 site-cookbooks/kosmos_email/templates/ldap-virtual-mailboxes.cf.erb diff --git a/site-cookbooks/kosmos_email/recipes/postfix.rb b/site-cookbooks/kosmos_email/recipes/postfix.rb index 3a46d3d..ef1b9e4 100644 --- a/site-cookbooks/kosmos_email/recipes/postfix.rb +++ b/site-cookbooks/kosmos_email/recipes/postfix.rb @@ -124,19 +124,6 @@ template "/etc/postfix/ldap-aliases.cf" do notifies :restart, "service[postfix]", :delayed end -# template "/etc/postfix/ldap-virtual-mailboxes.cf" do -# source "ldap-virtual-mailboxes.cf.erb" -# mode 0600 -# variables server_host: "ldap.kosmos.local", -# bind_dn: credentials['ldap_dn'], -# bind_pw: credentials['ldap_dnpass'], -# search_base: "ou=kosmos.org,cn=users,dc=kosmos,dc=org", -# query_filter: "maildrop=%s", -# result_attribute: "mailhome", -# result_format: "%s/mail/" -# notifies :restart, "service[postfix]", :delayed -# end - include_recipe 'postfix::server' service "postfix" do diff --git a/site-cookbooks/kosmos_email/templates/ldap-virtual-mailboxes.cf.erb b/site-cookbooks/kosmos_email/templates/ldap-virtual-mailboxes.cf.erb deleted file mode 100644 index b65d8d2..0000000 --- a/site-cookbooks/kosmos_email/templates/ldap-virtual-mailboxes.cf.erb +++ /dev/null @@ -1,7 +0,0 @@ -server_host = <%= @server_host %> -bind_dn = <%= @bind_dn %> -bind_pw = <%= @bind_pw %> - -query_filter = <%= @query_filter %> -result_attribute = <%= @result_attribute %> -result_format = <%= @result_format %> From 87411274aeab26e4178d7bf9a90c2086b839323f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Sun, 3 Dec 2023 18:29:35 +0100 Subject: [PATCH 11/26] Configure email domain for production --- environments/production.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/environments/production.json b/environments/production.json index 76db794..1b83e66 100644 --- a/environments/production.json +++ b/environments/production.json @@ -20,7 +20,7 @@ "turn_ip_address": "148.251.83.201" }, "email": { - "domain": "mail.kosmos.org", + "domain": "kosmos.org", "hostname": "mail.kosmos.org" }, "garage": { From 738e96f7e4c792cee28b8cfed219e4306daaf954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Sun, 3 Dec 2023 18:31:12 +0100 Subject: [PATCH 12/26] Fix auth for SMTP submission on port 465 --- site-cookbooks/kosmos_email/recipes/postfix.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/site-cookbooks/kosmos_email/recipes/postfix.rb b/site-cookbooks/kosmos_email/recipes/postfix.rb index ef1b9e4..6d6d18e 100644 --- a/site-cookbooks/kosmos_email/recipes/postfix.rb +++ b/site-cookbooks/kosmos_email/recipes/postfix.rb @@ -78,6 +78,7 @@ node.normal['postfix']['master'] = { "-o syslog_name=postfix/10465", "-o smtpd_tls_wrappermode=yes", "-o smtpd_sasl_auth_enable=yes", + "-o smtpd_relay_restrictions=permit_sasl_authenticated,reject", "-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject", "-o smtpd_sasl_type=dovecot", "-o smtpd_sasl_path=private/auth", From 568197737a7d0be94d9ccbe9864a7fc893ce22ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Sun, 3 Dec 2023 18:31:47 +0100 Subject: [PATCH 13/26] Fix SMTP connection delay when peer hostname cannot be resolved --- site-cookbooks/kosmos_email/recipes/postfix.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/site-cookbooks/kosmos_email/recipes/postfix.rb b/site-cookbooks/kosmos_email/recipes/postfix.rb index 6d6d18e..3942dd1 100644 --- a/site-cookbooks/kosmos_email/recipes/postfix.rb +++ b/site-cookbooks/kosmos_email/recipes/postfix.rb @@ -27,6 +27,7 @@ node.normal['postfix']['main']['mynetworks'] = ["10.1.1.0/24", "127.0.0.0/8"] node.normal['postfix']['main']['smtpd_use_tls'] = "yes" node.normal['postfix']['main']['smtpd_tls_cert_file'] = "/etc/letsencrypt/live/#{hostname}/fullchain.pem" node.normal['postfix']['main']['smtpd_tls_key_file'] = "/etc/letsencrypt/live/#{hostname}/privkey.pem" +node.normal['postfix']['main']['smtpd_peername_lookup'] = "no" node.normal['postfix']['main']['mailbox_transport'] = "lmtp:unix:private/dovecot-lmtp" node.normal['postfix']['main']['virtual_transport'] = "lmtp:unix:private/dovecot-lmtp" node.normal['postfix']['main']['smtputf8_enable'] = "no" From 8a7eeb1dd9b41fa931e3429eb7f73e0471bf6118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Sun, 3 Dec 2023 18:32:55 +0100 Subject: [PATCH 14/26] Change INBOX location --- site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb b/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb index b5b0593..8d7b41f 100644 --- a/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb +++ b/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb @@ -27,7 +27,7 @@ # # # -mail_location = mbox:~/mail:INBOX=/var/mail/%d/%u +mail_location = mbox:~/mail:INBOX=~/mail/INBOX # If you need to set multiple mailbox locations or want to change default # namespace settings, you can do it by defining namespace sections. From fbad0bf8962aa8b4d1c86e3489282ad885171cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Sun, 3 Dec 2023 18:33:12 +0100 Subject: [PATCH 15/26] More explicit postfix configs --- site-cookbooks/kosmos_email/recipes/postfix.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site-cookbooks/kosmos_email/recipes/postfix.rb b/site-cookbooks/kosmos_email/recipes/postfix.rb index 3942dd1..7c61475 100644 --- a/site-cookbooks/kosmos_email/recipes/postfix.rb +++ b/site-cookbooks/kosmos_email/recipes/postfix.rb @@ -24,6 +24,9 @@ node.normal['postfix']['main']['mydomain'] = domain node.normal['postfix']['main']['myorigin'] = domain node.normal['postfix']['main']['myhostname'] = hostname node.normal['postfix']['main']['mynetworks'] = ["10.1.1.0/24", "127.0.0.0/8"] +node.normal['postfix']['main']['mydestination'] = [domain, hostname, 'localhost.localdomain', 'localhost'].compact +node.normal['postfix']['main']['smtp_use_tls'] = "yes" +node.normal['postfix']['main']['smtp_tls_security_level'] = "may" node.normal['postfix']['main']['smtpd_use_tls'] = "yes" node.normal['postfix']['main']['smtpd_tls_cert_file'] = "/etc/letsencrypt/live/#{hostname}/fullchain.pem" node.normal['postfix']['main']['smtpd_tls_key_file'] = "/etc/letsencrypt/live/#{hostname}/privkey.pem" From c9ad3c2d18a562ec38ca4a199662feb1fea95020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Mon, 4 Dec 2023 13:33:23 +0100 Subject: [PATCH 16/26] Create/configure common default mailboxes --- .../templates/dovecot_10-mail.conf.erb | 84 ++++++++++++------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb b/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb index 8d7b41f..8833f28 100644 --- a/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb +++ b/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb @@ -40,43 +40,63 @@ mail_location = mbox:~/mail:INBOX=~/mail/INBOX # users can access all the shared mailboxes, assuming they have permissions # on filesystem level to do so. namespace inbox { - # Namespace type: private, shared or public - #type = private - - # Hierarchy separator to use. You should use the same separator for all - # namespaces or some clients get confused. '/' is usually a good one. - # The default however depends on the underlying mail storage format. - #separator = - - # Prefix required to access this namespace. This needs to be different for - # all namespaces. For example "Public/". - #prefix = - - # Physical location of the mailbox. This is in same format as - # mail_location, which is also the default for it. - #location = - - # There can be only one INBOX, and this setting defines which namespace - # has it. + type = private inbox = yes - # If namespace is hidden, it's not advertised to clients via NAMESPACE - # extension. You'll most likely also want to set list=no. This is mostly - # useful when converting from another server with different namespaces which - # you want to deprecate but still keep working. For example you can create - # hidden namespaces with prefixes "~/mail/", "~%u/mail/" and "mail/". - #hidden = no + mailbox Drafts { + special_use = \Drafts + auto = subscribe + } - # Show the mailboxes under this namespace with LIST command. This makes the - # namespace visible for clients that don't support NAMESPACE extension. - # "children" value lists child mailboxes, but hides the namespace prefix. - #list = yes + mailbox Junk { + special_use = \Junk + auto = create + } - # Namespace handles its own subscriptions. If set to "no", the parent - # namespace handles them (empty prefix should always have this as "yes") - #subscriptions = yes + mailbox spam { + special_use = \Junk + auto = no + } - # See 15-mailboxes.conf for definitions of special mailboxes. + mailbox Spam { + special_use = \Junk + auto = no + } + + mailbox Trash { + special_use = \Trash + auto = subscribe + } + + mailbox TRASH { + special_use = \Trash + auto = no + } + + mailbox Sent { + special_use = \Sent + auto = subscribe + } + + mailbox "Sent Mail" { + special_use = \Sent + auto = no + } + + mailbox "Sent Messages" { + special_use = \Sent + auto = no + } + + mailbox Archive { + special_use = \Archive + auto = create + } + + mailbox "Archives" { + special_use = \Archive + auto = no + } } # Example shared namespace configuration From 42c04538d84dd63af85f16ddef2875c01e40ea79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Mon, 4 Dec 2023 13:40:37 +0100 Subject: [PATCH 17/26] Set up DKIM signing and verification --- .../kosmos_email/recipes/default.rb | 1 + .../kosmos_email/recipes/opendkim.rb | 74 +++++++++++++++++++ .../kosmos_email/recipes/postfix.rb | 5 +- .../kosmos_email/templates/opendkim.conf.erb | 59 +++++++++++++++ .../templates/opendkim_default.erb | 31 ++++++++ .../templates/opendkim_keytable.erb | 1 + .../templates/opendkim_signingtable.erb | 1 + 7 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 site-cookbooks/kosmos_email/recipes/opendkim.rb create mode 100644 site-cookbooks/kosmos_email/templates/opendkim.conf.erb create mode 100644 site-cookbooks/kosmos_email/templates/opendkim_default.erb create mode 100644 site-cookbooks/kosmos_email/templates/opendkim_keytable.erb create mode 100644 site-cookbooks/kosmos_email/templates/opendkim_signingtable.erb diff --git a/site-cookbooks/kosmos_email/recipes/default.rb b/site-cookbooks/kosmos_email/recipes/default.rb index c431328..d775dfa 100644 --- a/site-cookbooks/kosmos_email/recipes/default.rb +++ b/site-cookbooks/kosmos_email/recipes/default.rb @@ -21,5 +21,6 @@ firewall_rule "private network access" do source "10.1.1.0/24" end +include_recipe 'kosmos_email::opendkim' include_recipe 'kosmos_email::postfix' include_recipe 'kosmos_email::dovecot' diff --git a/site-cookbooks/kosmos_email/recipes/opendkim.rb b/site-cookbooks/kosmos_email/recipes/opendkim.rb new file mode 100644 index 0000000..1447895 --- /dev/null +++ b/site-cookbooks/kosmos_email/recipes/opendkim.rb @@ -0,0 +1,74 @@ +# +# Cookbook:: kosmos_email +# Recipe:: opendkim +# + +%w[ + opendkim + opendkim-tools +].each do |pkg| + apt_package pkg +end + +domain = node["email"]["domain"] +selector = "mail" +socket = "inet:12301@localhost" + +template "/etc/opendkim.conf" do + source "opendkim.conf.erb" + mode 0644 + variables domain: domain, + selector: selector, + socket: socket + notifies :restart, "service[opendkim]", :delayed +end + +template "/etc/default/opendkim" do + source "opendkim_default.erb" + mode 0644 + variables socket: socket + notifies :restart, "service[opendkim]", :delayed +end + +directory "/run/opendkim" do + owner "opendkim" + group "opendkim" + action :create +end + +directory "/etc/opendkim" + +template "/etc/opendkim/keytable" do + source "opendkim_keytable.erb" + mode 0644 + variables domain: domain, + selector: selector + notifies :restart, "service[opendkim]", :delayed +end + +template "/etc/opendkim/signingtable" do + source "opendkim_signingtable.erb" + mode 0644 + variables domain: domain, + selector: selector + notifies :restart, "service[opendkim]", :delayed +end + +directory "/etc/opendkim/keys/#{domain}" do + recursive true +end + +execute "Create DKIM keys" do + cwd "/etc/opendkim/keys/#{domain}" + command "opendkim-genkey -s #{selector} -d #{domain}" + creates "/etc/opendkim/keys/#{domain}/#{selector}.private" +end + +file "/etc/opendkim/keys/#{domain}/#{selector}.private" do + owner "opendkim" + group "opendkim" +end + +service "opendkim" do + action [:enable, :start] +end diff --git a/site-cookbooks/kosmos_email/recipes/postfix.rb b/site-cookbooks/kosmos_email/recipes/postfix.rb index 7c61475..1e9475c 100644 --- a/site-cookbooks/kosmos_email/recipes/postfix.rb +++ b/site-cookbooks/kosmos_email/recipes/postfix.rb @@ -36,7 +36,10 @@ node.normal['postfix']['main']['virtual_transport'] = "lmtp:unix:private/dovecot node.normal['postfix']['main']['smtputf8_enable'] = "no" node.normal['postfix']['main']['recipient_delimiter'] = "+" node.normal['postfix']['main']['alias_maps'] = "hash:/etc/aliases, ldap:/etc/postfix/ldap-aliases.cf" -# node.normal['postfix']['main']['virtual_mailbox_maps'] = "ldap:/etc/postfix/ldap-virtual-mailboxes.cf" +node.normal['postfix']['main']['milter_protocol'] = "2" +node.normal['postfix']['main']['milter_default_action'] = "accept" +node.normal['postfix']['main']['smtpd_milters'] = "inet:localhost:12301" +node.normal['postfix']['main']['non_smtpd_milters'] = "inet:localhost:12301" node.normal['postfix']['master'] = { "#{ip_addr}:2525": { diff --git a/site-cookbooks/kosmos_email/templates/opendkim.conf.erb b/site-cookbooks/kosmos_email/templates/opendkim.conf.erb new file mode 100644 index 0000000..9616128 --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/opendkim.conf.erb @@ -0,0 +1,59 @@ +# This is a basic configuration for signing and verifying. It can easily be +# adapted to suit a basic installation. See opendkim.conf(5) and +# /usr/share/doc/opendkim/examples/opendkim.conf.sample for complete +# documentation of available configuration parameters. + +Syslog yes +SyslogSuccess yes +LogWhy yes + +AutoRestart yes +AutoRestartRate 10/1h + +# Common signing and verification parameters. In Debian, the "From" header is +# oversigned, because it is often the identity key used by reputation systems +# and thus somewhat security sensitive. +Canonicalization relaxed/simple +Mode sv +#SubDomains no +OversignHeaders From + +# Signing domain, selector, and key (required). For example, perform signing +# for domain "example.com" with selector "2020" (2020._domainkey.example.com), +# using the private key stored in /etc/dkimkeys/example.private. More granular +# setup options can be found in /usr/share/doc/opendkim/README.opendkim. +Domain <%= @domain %> +Selector <%= @selector %> +#KeyFile /etc/dkimkeys/example.private + +# In Debian, opendkim runs as user "opendkim". A umask of 007 is required when +# using a local socket with MTAs that access the socket as a non-privileged +# user (for example, Postfix). You may need to add user "postfix" to group +# "opendkim" in that case. +UserID opendkim +UMask 007 + +# Socket for the MTA connection (required). If the MTA is inside a chroot jail, +# it must be ensured that the socket is accessible. In Debian, Postfix runs in +# a chroot in /var/spool/postfix, therefore a Unix socket would have to be +# configured as shown on the last line below. +Socket local:/run/opendkim/opendkim.sock +#Socket inet:8891@localhost +#Socket inet:8891 +#Socket local:/var/spool/postfix/opendkim/opendkim.sock + +PidFile /run/opendkim/opendkim.pid + +# Hosts for which to sign rather than verify, default is 127.0.0.1. See the +# OPERATION section of opendkim(8) for more information. +#InternalHosts 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12 + +KeyTable refile:/etc/opendkim/keytable +SigningTable refile:/etc/opendkim/signingtable + +# The trust anchor enables DNSSEC. In Debian, the trust anchor file is provided +# by the package dns-root-data. +TrustAnchorFile /usr/share/dns/root.key +#Nameservers 127.0.0.1 + +Socket <%= @socket %> diff --git a/site-cookbooks/kosmos_email/templates/opendkim_default.erb b/site-cookbooks/kosmos_email/templates/opendkim_default.erb new file mode 100644 index 0000000..08e9032 --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/opendkim_default.erb @@ -0,0 +1,31 @@ +# NOTE: This is a legacy configuration file. It is not used by the opendkim +# systemd service. Please use the corresponding configuration parameters in +# /etc/opendkim.conf instead. +# +# Previously, one would edit the default settings here, and then execute +# /lib/opendkim/opendkim.service.generate to generate systemd override files at +# /etc/systemd/system/opendkim.service.d/override.conf and +# /etc/tmpfiles.d/opendkim.conf. While this is still possible, it is now +# recommended to adjust the settings directly in /etc/opendkim.conf. +# +#DAEMON_OPTS="" +# Change to /var/spool/postfix/run/opendkim to use a Unix socket with +# postfix in a chroot: +#RUNDIR=/var/spool/postfix/run/opendkim +RUNDIR=/run/opendkim +# +# Uncomment to specify an alternate socket +# Note that setting this will override any Socket value in opendkim.conf +# default: +#SOCKET=local:$RUNDIR/opendkim.sock +# listen on all interfaces on port 54321: +#SOCKET=inet:54321 +# listen on loopback on port 12345: +#SOCKET=inet:12345@localhost +# listen on 192.0.2.1 on port 12345: +#SOCKET=inet:12345@192.0.2.1 +SOCKET=<%= @socket %> +USER=opendkim +GROUP=opendkim +PIDFILE=$RUNDIR/$NAME.pid +EXTRAAFTER= diff --git a/site-cookbooks/kosmos_email/templates/opendkim_keytable.erb b/site-cookbooks/kosmos_email/templates/opendkim_keytable.erb new file mode 100644 index 0000000..9935194 --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/opendkim_keytable.erb @@ -0,0 +1 @@ +<%= @selector %>._domainkey.<%= @domain %> <%= @domain %>:<%= @selector %>:/etc/opendkim/keys/<%= @domain %>/mail.private diff --git a/site-cookbooks/kosmos_email/templates/opendkim_signingtable.erb b/site-cookbooks/kosmos_email/templates/opendkim_signingtable.erb new file mode 100644 index 0000000..5f21353 --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/opendkim_signingtable.erb @@ -0,0 +1 @@ +*@<%= @domain %> <%= @selector %>._domainkey.<%= @domain %> From c746b38ebfdbca5c7a2b5cb8a83a2a39e64978d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Tue, 5 Dec 2023 14:19:52 +0100 Subject: [PATCH 18/26] Update node info --- nodes/mail.kosmos.org.json | 1 + 1 file changed, 1 insertion(+) diff --git a/nodes/mail.kosmos.org.json b/nodes/mail.kosmos.org.json index e9b7f83..0e7f7b0 100644 --- a/nodes/mail.kosmos.org.json +++ b/nodes/mail.kosmos.org.json @@ -36,6 +36,7 @@ "kosmos-postfix::default", "hostname::default", "kosmos-base::letsencrypt", + "kosmos_email::opendkim", "kosmos_email::postfix", "postfix::server", "postfix::default", From b3f2ca415ea0c35fc55fc56465df575e8b02097b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Wed, 6 Dec 2023 12:12:00 +0100 Subject: [PATCH 19/26] Set up SpamAssassin Scan incoming and outgoing email for spam. Use a local Unbound for DNS, so we don't run into blocks for RBL queries. --- Berksfile | 1 + Berksfile.lock | 2 + cookbooks/unbound/CHANGELOG.md | 64 ++++++ cookbooks/unbound/LICENSE | 201 ++++++++++++++++++ cookbooks/unbound/README.md | 78 +++++++ cookbooks/unbound/chefignore | 115 ++++++++++ cookbooks/unbound/kitchen.dokken.yml | 56 +++++ cookbooks/unbound/libraries/helpers.rb | 59 +++++ cookbooks/unbound/libraries/template.rb | 26 +++ cookbooks/unbound/metadata.json | 42 ++++ cookbooks/unbound/metadata.rb | 13 ++ cookbooks/unbound/recipes/default.rb | 25 +++ cookbooks/unbound/renovate.json | 6 + .../resources/config_authority_zone.rb | 93 ++++++++ cookbooks/unbound/resources/config_cachedb.rb | 67 ++++++ cookbooks/unbound/resources/config_dns64.rb | 58 +++++ .../unbound/resources/config_dnscrypt.rb | 80 +++++++ cookbooks/unbound/resources/config_dnstap.rb | 116 ++++++++++ .../resources/config_dynamic_library.rb | 48 +++++ .../unbound/resources/config_forward_zone.rb | 80 +++++++ .../unbound/resources/config_python_script.rb | 53 +++++ .../resources/config_remote_control.rb | 77 +++++++ .../unbound/resources/config_rpz_zone.rb | 98 +++++++++ cookbooks/unbound/resources/config_server.rb | 58 +++++ .../unbound/resources/config_stub_zone.rb | 84 ++++++++ cookbooks/unbound/resources/config_view.rb | 68 ++++++ cookbooks/unbound/resources/package.rb | 36 ++++ .../resources/partials/_config_file.rb | 122 +++++++++++ cookbooks/unbound/resources/service.rb | 69 ++++++ .../default/partials/_generic_config.erb | 22 ++ .../templates/default/unbound.conf.erb | 5 + nodes/mail.kosmos.org.json | 2 + .../kosmos_email/attributes/default.rb | 3 +- site-cookbooks/kosmos_email/metadata.rb | 1 + .../kosmos_email/recipes/default.rb | 2 + .../kosmos_email/recipes/postfix.rb | 5 +- .../kosmos_email/recipes/spamassassin.rb | 34 +++ .../kosmos_email/templates/spamass-milter.erb | 28 +++ .../templates/spamassassin_default.erb | 33 +++ .../templates/spamassassin_local.cf.erb | 119 +++++++++++ 40 files changed, 2145 insertions(+), 4 deletions(-) create mode 100644 cookbooks/unbound/CHANGELOG.md create mode 100644 cookbooks/unbound/LICENSE create mode 100644 cookbooks/unbound/README.md create mode 100644 cookbooks/unbound/chefignore create mode 100644 cookbooks/unbound/kitchen.dokken.yml create mode 100644 cookbooks/unbound/libraries/helpers.rb create mode 100644 cookbooks/unbound/libraries/template.rb create mode 100644 cookbooks/unbound/metadata.json create mode 100644 cookbooks/unbound/metadata.rb create mode 100644 cookbooks/unbound/recipes/default.rb create mode 100644 cookbooks/unbound/renovate.json create mode 100644 cookbooks/unbound/resources/config_authority_zone.rb create mode 100644 cookbooks/unbound/resources/config_cachedb.rb create mode 100644 cookbooks/unbound/resources/config_dns64.rb create mode 100644 cookbooks/unbound/resources/config_dnscrypt.rb create mode 100644 cookbooks/unbound/resources/config_dnstap.rb create mode 100644 cookbooks/unbound/resources/config_dynamic_library.rb create mode 100644 cookbooks/unbound/resources/config_forward_zone.rb create mode 100644 cookbooks/unbound/resources/config_python_script.rb create mode 100644 cookbooks/unbound/resources/config_remote_control.rb create mode 100644 cookbooks/unbound/resources/config_rpz_zone.rb create mode 100644 cookbooks/unbound/resources/config_server.rb create mode 100644 cookbooks/unbound/resources/config_stub_zone.rb create mode 100644 cookbooks/unbound/resources/config_view.rb create mode 100644 cookbooks/unbound/resources/package.rb create mode 100644 cookbooks/unbound/resources/partials/_config_file.rb create mode 100644 cookbooks/unbound/resources/service.rb create mode 100644 cookbooks/unbound/templates/default/partials/_generic_config.erb create mode 100644 cookbooks/unbound/templates/default/unbound.conf.erb create mode 100644 site-cookbooks/kosmos_email/recipes/spamassassin.rb create mode 100644 site-cookbooks/kosmos_email/templates/spamass-milter.erb create mode 100644 site-cookbooks/kosmos_email/templates/spamassassin_default.erb create mode 100644 site-cookbooks/kosmos_email/templates/spamassassin_local.cf.erb diff --git a/Berksfile b/Berksfile index ec09e0e..e82e5ed 100644 --- a/Berksfile +++ b/Berksfile @@ -37,6 +37,7 @@ cookbook 'timezone_iii', '= 1.0.4' cookbook 'ulimit', '~> 1.0.0' cookbook 'users', '~> 5.3.1' cookbook 'zerotier', '~> 1.0.7' +cookbook 'unbound', '~> 3.0.2' # openresty dependency cookbook 'jemalloc', '~> 0.1.7' diff --git a/Berksfile.lock b/Berksfile.lock index cf6ade6..c3bab6f 100644 --- a/Berksfile.lock +++ b/Berksfile.lock @@ -33,6 +33,7 @@ DEPENDENCIES ruby_build (~> 2.5.0) timezone_iii (= 1.0.4) ulimit (~> 1.0.0) + unbound (~> 3.0.2) users (~> 5.3.1) yum zerotier (~> 1.0.7) @@ -99,6 +100,7 @@ GRAPH seven_zip (4.2.2) timezone_iii (1.0.4) ulimit (1.0.0) + unbound (3.0.2) users (5.3.1) windows (7.0.2) yum (7.4.13) diff --git a/cookbooks/unbound/CHANGELOG.md b/cookbooks/unbound/CHANGELOG.md new file mode 100644 index 0000000..ce0a267 --- /dev/null +++ b/cookbooks/unbound/CHANGELOG.md @@ -0,0 +1,64 @@ +# CHANGELOG + +This file is used to list changes made in each version of the unbound cookbook. + +## 3.0.2 - *2023-10-02* + +- Update Ci files and remove CircleCI config + +## 3.0.1 - *2022-09-30* + +- Add missing `fallback-enable` setting to `config_authority_zone` + +## 3.0.0 - *2022-04-04* + +- Add separate configuration resources +- Default recipe now only runs installation +- Refactor configuration template to be Hash driven + +## 2.0.3 - *2022-03-04* + +- resolved cookstyle error: .delivery/project.toml:2:8 convention: `Style/StringLiterals` +- resolved cookstyle error: .delivery/project.toml:4:10 convention: `Style/StringLiterals` +- resolved cookstyle error: .delivery/project.toml:5:13 convention: `Style/StringLiterals` +- resolved cookstyle error: .delivery/project.toml:6:10 convention: `Style/StringLiterals` +- resolved cookstyle error: .delivery/project.toml:7:9 convention: `Style/StringLiterals` +- resolved cookstyle error: .delivery/project.toml:8:14 convention: `Style/StringLiterals` +- resolved cookstyle error: .delivery/project.toml:9:11 convention: `Style/StringLiterals` + +## 2.0.2 - *2021-08-31* + +- Standardise files with files in sous-chefs/repo-management + +## 2.0.1 - *2021-06-01* + +- Updated tests folder to match other cookbooks +- Updated spec platform to supported version + +## 2.0.0 - 2020-05-05 + +- Upgraded to circleci for testing +- Minimum Chef Infra Client version is now **13.0** +- Removed unused long_description metadata.rb field +- Simplify overly complex platform logic +- Migrate to actions for testing + +## [1.0.1] + +- Simplify logic with root_group +- Fix `root_group` not using new_resource +- Use strings for file modes +- Resolve foodcritic warnings in the `rr` resource +- Fix platform_family logic on the service Update platforms. +- Use dokken images for travis testing. +- Don't test on debian-8/9 and centos-6 as these services don't currently start. +- Account for a list of forward-addrs / effectively disable remote control (#27) + +## [1.0.0] + +- Add new custom resources `unbound_install` & `unbound_configure` + +## [0.1.1] + +- Adding support and kitchen testing for forward_zone generation +- Updating to use Sous Chefs guidelines diff --git a/cookbooks/unbound/LICENSE b/cookbooks/unbound/LICENSE new file mode 100644 index 0000000..11069ed --- /dev/null +++ b/cookbooks/unbound/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/cookbooks/unbound/README.md b/cookbooks/unbound/README.md new file mode 100644 index 0000000..700cf8a --- /dev/null +++ b/cookbooks/unbound/README.md @@ -0,0 +1,78 @@ +# Unbound Cookbook + +[![Cookbook Version](https://img.shields.io/cookbook/v/unbound.svg)](https://supermarket.chef.io/cookbooks/unbound) +[![Build Status](https://img.shields.io/circleci/project/github/sous-chefs/unbound/master.svg)](https://circleci.com/gh/sous-chefs/unbound) +[![OpenCollective](https://opencollective.com/sous-chefs/backers/badge.svg)](#backers) +[![OpenCollective](https://opencollective.com/sous-chefs/sponsors/badge.svg)](#sponsors) +[![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0) + +Installs and manages the unbound DNS server. + +- [http://unbound.net](http://unbound.net) + +## Maintainers + +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). + +## Requirements + +### Platform + +A platform with unbound available as a native package. The following platforms have unbound packaged, but note that the filesystem locations are not consistent and at this time only Linux + FHS is supported. + +- Ubuntu/Debian +- Red Hat/CentOS/Fedora (requires EPEL) +- FreeBSD + +### Chef + +- Chef 16 + +## Resources + +- [unbound_config_authority_zone](documentation/unbound_config_authority_zone.md) +- [unbound_config_cachedb](documentation/unbound_config_cachedb.md) +- [unbound_config_dns64](documentation/unbound_config_dns64.md) +- [unbound_config_dnscrypt](documentation/unbound_config_dnscrypt.md) +- [unbound_config_dnstap](documentation/unbound_config_dnstap.md) +- [unbound_config_dynamic_library](documentation/unbound_config_dynamic_library.md) +- [unbound_config_forward_zone](documentation/unbound_config_forward_zone.md) +- [unbound_config_python_script](documentation/unbound_config_python_script.md) +- [unbound_config_remote_control](documentation/unbound_config_remote_control.md) +- [unbound_config_rpz_zone](documentation/unbound_config_rpz_zone.md) +- [unbound_config_server](documentation/unbound_config_server.md) +- [unbound_config_stub_zone](documentation/unbound_config_stub_zone.md) +- [unbound_config_view](documentation/unbound_config_view.md) +- [unbound_package](documentation/unbound_package.md) +- [unbound_service](documentation/unbound_service.md) + +## Recipes + +### default + +Installs unbound using defaults. + +## Contributors + +This project exists thanks to all the people who [contribute.](https://opencollective.com/sous-chefs/contributors.svg?width=890&button=false) + +### Backers + +Thank you to all our backers! + +![https://opencollective.com/sous-chefs#backers](https://opencollective.com/sous-chefs/backers.svg?width=600&avatarHeight=40) + +### Sponsors + +Support this project by becoming a sponsor. Your logo will show up here with a link to your website. + +![https://opencollective.com/sous-chefs/sponsor/0/website](https://opencollective.com/sous-chefs/sponsor/0/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/1/website](https://opencollective.com/sous-chefs/sponsor/1/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/2/website](https://opencollective.com/sous-chefs/sponsor/2/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/3/website](https://opencollective.com/sous-chefs/sponsor/3/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/4/website](https://opencollective.com/sous-chefs/sponsor/4/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/5/website](https://opencollective.com/sous-chefs/sponsor/5/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/6/website](https://opencollective.com/sous-chefs/sponsor/6/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/7/website](https://opencollective.com/sous-chefs/sponsor/7/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/8/website](https://opencollective.com/sous-chefs/sponsor/8/avatar.svg?avatarHeight=100) +![https://opencollective.com/sous-chefs/sponsor/9/website](https://opencollective.com/sous-chefs/sponsor/9/avatar.svg?avatarHeight=100) diff --git a/cookbooks/unbound/chefignore b/cookbooks/unbound/chefignore new file mode 100644 index 0000000..cc170ea --- /dev/null +++ b/cookbooks/unbound/chefignore @@ -0,0 +1,115 @@ +# Put files/directories that should be ignored in this file when uploading +# to a Chef Infra Server or Supermarket. +# Lines that start with '# ' are comments. + +# OS generated files # +###################### +.DS_Store +ehthumbs.db +Icon? +nohup.out +Thumbs.db +.envrc + +# EDITORS # +########### +.#* +.project +.settings +*_flymake +*_flymake.* +*.bak +*.sw[a-z] +*.tmproj +*~ +\#* +REVISION +TAGS* +tmtags +.vscode +.editorconfig + +## COMPILED ## +############## +*.class +*.com +*.dll +*.exe +*.o +*.pyc +*.so +*/rdoc/ +a.out +mkmf.log + +# Testing # +########### +.circleci/* +.codeclimate.yml +.delivery/* +.foodcritic +.kitchen* +.mdlrc +.overcommit.yml +.rspec +.rubocop.yml +.travis.yml +.watchr +.yamllint +azure-pipelines.yml +Dangerfile +examples/* +features/* +Guardfile +kitchen.yml* +mlc_config.json +Procfile +Rakefile +spec/* +test/* + +# SCM # +####### +.git +.gitattributes +.gitconfig +.github/* +.gitignore +.gitkeep +.gitmodules +.svn +*/.bzr/* +*/.git +*/.hg/* +*/.svn/* + +# Berkshelf # +############# +Berksfile +Berksfile.lock +cookbooks/* +tmp + +# Bundler # +########### +vendor/* +Gemfile +Gemfile.lock + +# Policyfile # +############## +Policyfile.rb +Policyfile.lock.json + +# Documentation # +############# +CODE_OF_CONDUCT* +CONTRIBUTING* +documentation/* +TESTING* +UPGRADING* + +# Vagrant # +########### +.vagrant +Vagrantfile diff --git a/cookbooks/unbound/kitchen.dokken.yml b/cookbooks/unbound/kitchen.dokken.yml new file mode 100644 index 0000000..46cae69 --- /dev/null +++ b/cookbooks/unbound/kitchen.dokken.yml @@ -0,0 +1,56 @@ +--- +driver: + name: dokken + privileged: true + chef_version: <%= ENV['CHEF_VERSION'] || 'current' %> + +transport: + name: dokken + +provisioner: + name: dokken + +platforms: + - name: centos-7 + driver: + image: dokken/centos-7 + pid_one_command: /usr/lib/systemd/systemd + + - name: centos-stream-8 + driver: + image: dokken/centos-stream-8 + pid_one_command: /usr/lib/systemd/systemd + + - name: fedora-latest + driver: + image: dokken/fedora-latest + pid_one_command: /usr/lib/systemd/systemd + + - name: ubuntu-18.04 + driver: + image: dokken/ubuntu-18.04 + pid_one_command: /bin/systemd + intermediate_instructions: + - RUN /usr/bin/apt-get update + + - name: ubuntu-20.04 + driver: + image: dokken/ubuntu-20.04 + pid_one_command: /bin/systemd + intermediate_instructions: + - RUN /usr/bin/apt-get update + + - name: debian-10 + driver: + image: dokken/debian-10 + pid_one_command: /bin/systemd + intermediate_instructions: + - RUN /usr/bin/apt-get update + + - name: debian-11 + driver: + image: dokken/debian-11 + pid_one_command: /bin/systemd + intermediate_instructions: + - RUN /usr/bin/apt-get update +... diff --git a/cookbooks/unbound/libraries/helpers.rb b/cookbooks/unbound/libraries/helpers.rb new file mode 100644 index 0000000..bb46228 --- /dev/null +++ b/cookbooks/unbound/libraries/helpers.rb @@ -0,0 +1,59 @@ +# +# Cookbook:: unbound +# Library:: helpers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +module Unbound + module Cookbook + module Helpers + def default_config_dir + return '/etc/unbound' if %i(unbound_config unbound_configure unbound_config_server).include?(declared_type) + + return '/etc/unbound/unbound.conf.d' if platform?('debian', 'ubuntu') + + case declared_type + when :unbound_config_local + '/etc/unbound/local.d' + when :unbound_config_key + '/etc/unbound/keys.d' + else + '/etc/unbound/conf.d' + end + end + + def default_includes_dir + case node['platform_family'] + when 'rhel', 'fedora' + %w(/etc/unbound/conf.d/*.conf /etc/unbound/local.d/*.conf) + when 'debian' + %w(/etc/unbound/unbound.conf.d/*.conf) + else + raise "Unsupported platform family #{node['platform_family']}" + end + end + + def unbound_yes_no?(value) + case value + when true + 'yes' + when false + 'no' + when 'yes', 'YES', 'no', 'NO' + value.downcase + end + end + end + end +end diff --git a/cookbooks/unbound/libraries/template.rb b/cookbooks/unbound/libraries/template.rb new file mode 100644 index 0000000..acc3c62 --- /dev/null +++ b/cookbooks/unbound/libraries/template.rb @@ -0,0 +1,26 @@ +# +# Cookbook:: unbound +# Library:: template +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +module Unbound + module Cookbook + module TemplateHelpers + def template_partial_indent(output, level, spaces = 2) + output.split("\n").each { |l| l.prepend(' ' * (level * spaces)) }.join("\n") + end + end + end +end diff --git a/cookbooks/unbound/metadata.json b/cookbooks/unbound/metadata.json new file mode 100644 index 0000000..560d7e2 --- /dev/null +++ b/cookbooks/unbound/metadata.json @@ -0,0 +1,42 @@ +{ + "name": "unbound", + "description": "Manages unbound DNS resolver", + "long_description": "", + "maintainer": "Sous Chefs", + "maintainer_email": "help@sous-chefs.org", + "license": "Apache-2.0", + "platforms": { + "debian": ">= 0.0.0", + "ubuntu": ">= 0.0.0", + "centos": ">= 0.0.0", + "redhat": ">= 0.0.0", + "scientific": ">= 0.0.0", + "oracle": ">= 0.0.0", + "amazon": ">= 0.0.0" + }, + "dependencies": { + + }, + "providing": { + + }, + "recipes": { + + }, + "version": "3.0.2", + "source_url": "https://github.com/sous-chefs/unbound", + "issues_url": "https://github.com/sous-chefs/unbound/issues", + "privacy": false, + "chef_versions": [ + [ + ">= 16" + ] + ], + "ohai_versions": [ + + ], + "gems": [ + + ], + "eager_load_libraries": true +} diff --git a/cookbooks/unbound/metadata.rb b/cookbooks/unbound/metadata.rb new file mode 100644 index 0000000..7e52ea9 --- /dev/null +++ b/cookbooks/unbound/metadata.rb @@ -0,0 +1,13 @@ +name 'unbound' +maintainer 'Sous Chefs' +maintainer_email 'help@sous-chefs.org' +license 'Apache-2.0' +description 'Manages unbound DNS resolver' +version '3.0.2' +issues_url 'https://github.com/sous-chefs/unbound/issues' +source_url 'https://github.com/sous-chefs/unbound' +chef_version '>= 16' + +%w(debian ubuntu centos redhat scientific oracle amazon).each do |os| + supports os +end diff --git a/cookbooks/unbound/recipes/default.rb b/cookbooks/unbound/recipes/default.rb new file mode 100644 index 0000000..28e20ef --- /dev/null +++ b/cookbooks/unbound/recipes/default.rb @@ -0,0 +1,25 @@ +# +# Cookbook:: unbound +# Recipe:: default +# +# Copyright:: 2011, Joshua Timberman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +log 'v3_warning' do + message 'Version 3.0.0 of this cookbook removed all configuration actions from the default recipe' + level :warn +end + +unbound_package 'unbound' diff --git a/cookbooks/unbound/renovate.json b/cookbooks/unbound/renovate.json new file mode 100644 index 0000000..39a2b6e --- /dev/null +++ b/cookbooks/unbound/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ] +} diff --git a/cookbooks/unbound/resources/config_authority_zone.rb b/cookbooks/unbound/resources/config_authority_zone.rb new file mode 100644 index 0000000..6ea9626 --- /dev/null +++ b/cookbooks/unbound/resources/config_authority_zone.rb @@ -0,0 +1,93 @@ +# +# Cookbook:: unbound +# Resource:: config_authority_zone +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +provides :unbound_config_auth_zone + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/authority-zone-#{name}.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :zone_name, String, + default: lazy { name } + +property :primary, [String, Array], + coerce: proc { |p| Array(p) } + +property :master, [String, Array], + coerce: proc { |p| Array(p) } + +property :url, [String, Array], + coerce: proc { |p| Array(p) } + +property :allow_notify, [String, Array], + coerce: proc { |p| Array(p) } + +property :fallback_enabled, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :for_downstream, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :for_upstream, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :zonemd_check, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :zonemd_reject_absence, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :zonefile, String + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + zone_config = { + 'name' => new_resource.zone_name, + 'primary' => new_resource.primary.dup, + 'master' => new_resource.master.dup, + 'url' => new_resource.url.dup, + 'allow-notify' => new_resource.allow_notify.dup, + 'fallback-enabled' => new_resource.fallback_enabled, + 'for-downstream' => new_resource.for_downstream, + 'for-upstream' => new_resource.for_upstream, + 'zonemd-check' => new_resource.zonemd_check, + 'zonemd-reject-absence' => new_resource.zonemd_reject_absence, + 'zonefile' => new_resource.zonefile, + }.compact + + config = { + 'auth-zone' => zone_config, + } + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/config_cachedb.rb b/cookbooks/unbound/resources/config_cachedb.rb new file mode 100644 index 0000000..1c415b7 --- /dev/null +++ b/cookbooks/unbound/resources/config_cachedb.rb @@ -0,0 +1,67 @@ +# +# Cookbook:: unbound +# Resource:: config_cachedb +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/cachedb.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :backend, String + +property :secret_seed, String + +property :redis_server_host, String + +property :redis_server_port, Integer + +property :redis_timeout, Integer + +property :redis_expire_records, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + cachedb_config = { + 'backend' => new_resource.backend, + 'secret-seed' => new_resource.secret_seed, + 'redis-server-host' => new_resource.redis_server_host, + 'redis-server-port' => new_resource.redis_server_port, + 'redis-timeout' => new_resource.redis_timeout, + 'redis-expire-records' => new_resource.redis_expire_records, + }.compact + + config = { + 'cachedb' => cachedb_config, + } + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/config_dns64.rb b/cookbooks/unbound/resources/config_dns64.rb new file mode 100644 index 0000000..4c4a9e5 --- /dev/null +++ b/cookbooks/unbound/resources/config_dns64.rb @@ -0,0 +1,58 @@ +# +# Cookbook:: unbound +# Resource:: config_dns64 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/dns64.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :dns64_prefix, String + +property :dns64_synthall, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :dns64_ignore_aaaa, String + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + dns64_config = { + 'dns64-prefix' => new_resource.dns64_prefix, + 'dns64-synthall' => new_resource.dns64_synthall, + 'dns64-ignore-aaaa' => new_resource.dns64_ignore_aaaa, + }.compact + + config = { + 'server' => dns64_config, + } + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/config_dnscrypt.rb b/cookbooks/unbound/resources/config_dnscrypt.rb new file mode 100644 index 0000000..f6ebff8 --- /dev/null +++ b/cookbooks/unbound/resources/config_dnscrypt.rb @@ -0,0 +1,80 @@ +# +# Cookbook:: unbound +# Resource:: config_dnscrypt +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/dnscrypt.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :dnscrypt_enable, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :dnscrypt_port, Integer + +property :dnscrypt_provider, [String, Array], + coerce: proc { |p| Array(p) } + +property :dnscrypt_secret_key, String + +property :dnscrypt_provider_cert, String + +property :dnscrypt_provider_cert_rotated, String + +property :dnscrypt_shared_secret_cache_size, String + +property :dnscrypt_shared_secret_cache_slabs, Integer + +property :dnscrypt_nonce_cache_size, String + +property :dnscrypt_nonce_cache_slabs, Integer + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + dnscrypt_config = { + 'dnscrypt-enable' => new_resource.dnscrypt_enable, + 'dnscrypt-port' => new_resource.dnscrypt_port, + 'dnscrypt-provider' => new_resource.dnscrypt_provider.dup, + 'dnscrypt-secret-key' => new_resource.dnscrypt_secret_key, + 'dnscrypt-provider-cert' => new_resource.dnscrypt_provider_cert, + 'dnscrypt-provider-cert-rotated' => new_resource.dnscrypt_provider_cert_rotated, + 'dnscrypt-shared-secret-cache-size' => new_resource.dnscrypt_shared_secret_cache_size, + 'dnscrypt-shared-secret-cache-slabs' => new_resource.dnscrypt_shared_secret_cache_slabs, + 'dnscrypt-nonce-cache-size' => new_resource.dnscrypt_nonce_cache_size, + 'dnscrypt-nonce-cache-slabs' => new_resource.dnscrypt_nonce_cache_slabs, + }.compact + + config = { + 'dnscrypt' => dnscrypt_config, + } + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/config_dnstap.rb b/cookbooks/unbound/resources/config_dnstap.rb new file mode 100644 index 0000000..60c2d0f --- /dev/null +++ b/cookbooks/unbound/resources/config_dnstap.rb @@ -0,0 +1,116 @@ +# +# Cookbook:: unbound +# Resource:: config_dnstap +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/dnstap.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :dnstap_enable, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :dnstap_bidirectional, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :dnstap_socket_path, String + +property :dnstap_ip, String + +property :dnstap_tls, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :dnstap_tls_server_name, String + +property :dnstap_tls_cert_bundle, String + +property :dnstap_tls_client_key_file, String + +property :dnstap_tls_client_cert_file, String + +property :dnstap_send_identity, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :dnstap_send_version, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :dnstap_identity, String + +property :dnstap_version, String + +property :dnstap_log_resolver_query_messages, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :dnstap_log_resolver_response_messages, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :dnstap_log_client_query_messages, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :dnstap_log_client_response_messages, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :dnstap_log_forwarder_query_messages, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :dnstap_log_forwarder_response_messages, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + zone_config = { + 'dnstap-enable' => new_resource.dnstap_enable, + 'dnstap-bidirectional' => new_resource.dnstap_bidirectional, + 'dnstap-socket-path' => new_resource.dnstap_socket_path, + 'dnstap-ip' => new_resource.dnstap_ip, + 'dnstap-tls' => new_resource.dnstap_tls, + 'dnstap-tls-server-name' => new_resource.dnstap_tls_server_name, + 'dnstap-tls-cert-bundle' => new_resource.dnstap_tls_cert_bundle, + 'dnstap-tls-client-key-file' => new_resource.dnstap_tls_client_key_file, + 'dnstap-tls-client-cert-file' => new_resource.dnstap_tls_client_cert_file, + 'dnstap-send-identity' => new_resource.dnstap_send_identity, + 'dnstap-send-version' => new_resource.dnstap_send_version, + 'dnstap-identity' => new_resource.dnstap_identity, + 'dnstap-version' => new_resource.dnstap_version, + 'dnstap-log-resolver-query-messages' => new_resource.dnstap_log_resolver_query_messages, + 'dnstap-log-resolver-response-messages' => new_resource.dnstap_log_resolver_response_messages, + 'dnstap-log-client-query-messages' => new_resource.dnstap_log_client_query_messages, + 'dnstap-log-client-response-messages' => new_resource.dnstap_log_client_response_messages, + 'dnstap-log-forwarder-query-messages' => new_resource.dnstap_log_forwarder_query_messages, + 'dnstap-log-forwarder-response-messages' => new_resource.dnstap_log_forwarder_response_messages, + }.compact + + config = { + 'dnstap' => zone_config, + } + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/config_dynamic_library.rb b/cookbooks/unbound/resources/config_dynamic_library.rb new file mode 100644 index 0000000..8500454 --- /dev/null +++ b/cookbooks/unbound/resources/config_dynamic_library.rb @@ -0,0 +1,48 @@ +# +# Cookbook:: unbound +# Resource:: config_dynamic_library +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/dyn-lib-#{name}.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :dynlib_file, [String, Array], + coerce: proc { |p| Array(p) } + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + config = { + 'dynlib-file' => new_resource.dynlib_file.dup, + } + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/config_forward_zone.rb b/cookbooks/unbound/resources/config_forward_zone.rb new file mode 100644 index 0000000..05d9eb7 --- /dev/null +++ b/cookbooks/unbound/resources/config_forward_zone.rb @@ -0,0 +1,80 @@ +# +# Cookbook:: unbound +# Resource:: config_forward_zone +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/forward-zone-#{name}.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :zone_name, String, + default: lazy { name } + +property :forward_host, [String, Array], + coerce: proc { |p| Array(p) } + +property :forward_addr, [String, Array], + coerce: proc { |p| Array(p) } + +property :forward_first, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :forward_tls_upstream, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :forward_ssl_upstream, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :forward_tcp_upstream, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :forward_no_cache, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + zone_config = { + 'name' => new_resource.zone_name, + 'forward-host' => new_resource.forward_host.dup, + 'forward-addr' => new_resource.forward_addr.dup, + 'forward-first' => new_resource.forward_first, + 'forward-tls-upstream' => new_resource.forward_tls_upstream, + 'forward-ssl-upstream' => new_resource.forward_ssl_upstream, + 'forward-tcp-upstream' => new_resource.forward_tcp_upstream, + 'forward-no-cache' => new_resource.forward_no_cache, + }.compact + + config = { + 'forward-zone' => zone_config, + } + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/config_python_script.rb b/cookbooks/unbound/resources/config_python_script.rb new file mode 100644 index 0000000..d9a5923 --- /dev/null +++ b/cookbooks/unbound/resources/config_python_script.rb @@ -0,0 +1,53 @@ +# +# Cookbook:: unbound +# Resource:: config_python_script +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/python-script-#{name}.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :python_script, [String, Array], + coerce: proc { |p| Array(p) }, + required: true + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + declare_resource(:package, 'python3-unbound') + + config = { + 'python' => { + 'python-script' => new_resource.python_script.dup, + }, + } + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/config_remote_control.rb b/cookbooks/unbound/resources/config_remote_control.rb new file mode 100644 index 0000000..6042ef6 --- /dev/null +++ b/cookbooks/unbound/resources/config_remote_control.rb @@ -0,0 +1,77 @@ +# +# Cookbook:: unbound +# Resource:: config_remote_control +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/remote-control.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :control_enable, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :control_interface, [String, Array], + coerce: proc { |p| Array(p) } + +property :control_port, Integer + +property :control_use_cert, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :control_key_file, String + +property :control_cert_file, String + +property :server, String + +property :server_key_file, String + +property :server_cert_file, String + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + remote_control = { + 'control-enable' => new_resource.control_enable, + 'control-interface' => new_resource.control_interface.dup, + 'control-port' => new_resource.control_port, + 'control-use-cert' => new_resource.control_use_cert, + 'control-key-file' => new_resource.control_key_file, + 'control-cert-file' => new_resource.control_cert_file, + 'server-key-file' => new_resource.server_key_file, + 'server-cert-file' => new_resource.server_cert_file, + }.compact + + config = { + 'remote-control' => remote_control, + } + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/config_rpz_zone.rb b/cookbooks/unbound/resources/config_rpz_zone.rb new file mode 100644 index 0000000..2e8292a --- /dev/null +++ b/cookbooks/unbound/resources/config_rpz_zone.rb @@ -0,0 +1,98 @@ +# +# Cookbook:: unbound +# Resource:: config_rpz_zone +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/rpz-zone-#{name}.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :zone_name, String, + default: lazy { name } + +property :primary, [String, Array], + coerce: proc { |p| Array(p) } + +property :master, [String, Array], + coerce: proc { |p| Array(p) } + +property :url, [String, Array], + coerce: proc { |p| Array(p) } + +property :allow_notify, [String, Array], + coerce: proc { |p| Array(p) } + +property :zonefile, String + +property :rpz_action_override, [String, Symbol], + equal_to: %w(nxdomain nodata passthru drop disabled cname), + coerce: proc { |p| p.to_s } + +property :rpz_cname_override, String + +property :rpz_log, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :rpz_log_name, String + +property :rpz_signal_nxdomain_ra, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :for_downstream, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :tags, [String, Array], + coerce: proc { |p| "\"#{p.to_a.join(' ')} \"" } + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + zone_config = { + 'name' => new_resource.zone_name, + 'primary' => new_resource.primary.dup, + 'master' => new_resource.master.dup, + 'url' => new_resource.url.dup, + 'allow-notify' => new_resource.allow_notify.dup, + 'zonefile' => new_resource.zonefile, + 'rpz-action-override' => new_resource.rpz_action_override, + 'rpz-cname-override' => new_resource.rpz_cname_override, + 'rpz-log' => new_resource.rpz_log, + 'rpz-log-name' => new_resource.rpz_log_name, + 'rpz-signal-nxfomain-ra' => new_resource.rpz_signal_nxdomain_ra, + 'for-downstream' => new_resource.for_downstream, + 'tags' => new_resource.tags.dup, + }.compact + + config = { + 'rpz' => zone_config, + } + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/config_server.rb b/cookbooks/unbound/resources/config_server.rb new file mode 100644 index 0000000..0e58d7e --- /dev/null +++ b/cookbooks/unbound/resources/config_server.rb @@ -0,0 +1,58 @@ +# +# Cookbook:: unbound +# Resource:: config_server +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +provides :unbound_config_server +provides :unbound_configure +provides :unbound_config + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/unbound.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :include, [String, Array], + default: lazy { default_includes_dir }, + coerce: proc { |p| Array(p) } + +property :server, Hash, + default: {}, + description: 'Server configuration as a Hash' + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + config = { + 'include' => new_resource.include.dup, + 'server' => new_resource.server.dup, + }.compact + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/config_stub_zone.rb b/cookbooks/unbound/resources/config_stub_zone.rb new file mode 100644 index 0000000..2a74fa5 --- /dev/null +++ b/cookbooks/unbound/resources/config_stub_zone.rb @@ -0,0 +1,84 @@ +# +# Cookbook:: unbound +# Resource:: config_stub_zone +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/stub-zone-#{name}.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :zone_name, String, + default: lazy { name } + +property :stub_host, [String, Array], + coerce: proc { |p| Array(p) } + +property :stub_addr, [String, Array], + coerce: proc { |p| Array(p) } + +property :stub_prime, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :stub_first, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :stub_tls_upstream, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :stub_ssl_upstream, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :stub_tcp_upstream, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +property :stub_no_cache, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + zone_config = { + 'name' => new_resource.zone_name, + 'stub-host' => new_resource.stub_host.dup, + 'stub-addr' => new_resource.stub_addr.dup, + 'stub-prime' => new_resource.stub_prime, + 'stub-first' => new_resource.stub_first, + 'stub-tls-upstream' => new_resource.stub_tls_upstream, + 'stub-ssl-upstream' => new_resource.stub_ssl_upstream, + 'stub-tcp-upstream' => new_resource.stub_tcp_upstream, + 'stub-no-cache' => new_resource.stub_no_cache, + }.compact + + config = { + 'stub-zone' => zone_config, + } + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/config_view.rb b/cookbooks/unbound/resources/config_view.rb new file mode 100644 index 0000000..67f602b --- /dev/null +++ b/cookbooks/unbound/resources/config_view.rb @@ -0,0 +1,68 @@ +# +# Cookbook:: unbound +# Resource:: config_view +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +use 'partials/_config_file' + +property :config_file, String, + default: lazy { "#{config_dir}/view-#{name}.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :zone_name, String, + default: lazy { name } + +property :local_zone, [String, Array], + coerce: proc { |p| Array(p) } + +property :local_data, [String, Array], + coerce: proc { |p| Array(p) } + +property :local_data_ptr, [String, Array], + coerce: proc { |p| Array(p) } + +property :view_first, [String, true, false], + coerce: proc { |p| unbound_yes_no?(p) } + +load_current_value do |new_resource| + current_value_does_not_exist! unless ::File.exist?(new_resource.config_file) + + if ::File.exist?(new_resource.config_file) + owner ::Etc.getpwuid(::File.stat(new_resource.config_file).uid).name + group ::Etc.getgrgid(::File.stat(new_resource.config_file).gid).name + mode ::File.stat(new_resource.config_file).mode.to_s(8)[-4..-1] + end +end + +action_class do + def do_template_action + zone_config = { + 'name' => new_resource.zone_name, + 'local-zone' => new_resource.local_zone.dup, + 'local-data' => new_resource.local_data.dup, + 'local-data-ptr' => new_resource.local_data_ptr.dup, + 'view-first' => new_resource.view_first, + }.compact + + config = { + 'view' => zone_config, + } + + perform_config_action(config) + end +end diff --git a/cookbooks/unbound/resources/package.rb b/cookbooks/unbound/resources/package.rb new file mode 100644 index 0000000..faff561 --- /dev/null +++ b/cookbooks/unbound/resources/package.rb @@ -0,0 +1,36 @@ +# +# Cookbook:: unbound +# Resource:: package +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +provides :unbound_install + +property :packages, [String, Array], + coerce: proc { |p| p.is_a?(Array) ? p : [ p ] }, + default: %w(unbound), + description: 'Unbound packages to install.' + +action_class do + def do_package_action(action) + package 'unbound' do + package_name new_resource.packages + action action + end + end +end + +%i(install upgrade remove).each { |pkg_action| action(pkg_action) { do_package_action(action) } } diff --git a/cookbooks/unbound/resources/partials/_config_file.rb b/cookbooks/unbound/resources/partials/_config_file.rb new file mode 100644 index 0000000..eae83b2 --- /dev/null +++ b/cookbooks/unbound/resources/partials/_config_file.rb @@ -0,0 +1,122 @@ +# +# Cookbook:: unbound +# Resource:: _config_file +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +include Unbound::Cookbook::Helpers + +property :owner, String, + default: 'root', + description: 'Set to override config file owner. Defaults to root.' + +property :group, String, + default: 'unbound', + description: 'Set to override config file group. Defaults to unbound.' + +property :mode, String, + default: '0640', + description: 'Set to override config file mode. Defaults to 0640.' + +property :directory_mode, String, + default: '0750', + description: 'Set to override config directory mode. Defaults to 0750.' + +property :config_dir, String, + default: lazy { default_config_dir }, + desired_state: false, + description: 'Set to override unbound configuration directory.' + +property :config_file, String, + default: lazy { "#{config_dir}/#{name}.conf" }, + desired_state: false, + description: 'Set to override unbound configuration file.' + +property :cookbook, String, + default: 'unbound', + desired_state: false, + description: 'Template source cookbook for the unbound configuration file.' + +property :template, String, + default: 'unbound.conf.erb', + desired_state: false, + description: 'Template source file for the unbound configuration file.' + +property :sensitive, [true, false], + desired_state: false, + description: 'Ensure that sensitive resource data is not output by Chef Infra Client.' + +property :sort, [true, false], + default: true + +property :template_properties, Hash, + default: {} + +property :extra_options, Hash, + default: {} + +action_class do + def deepsort? + return if defined?(DeepSort) + + begin + Gem::Specification.find_by_name('deepsort') + rescue Gem::MissingSpecError + declare_resource(:chef_gem, 'deepsort') + end + + require 'deepsort' + + true + end + + def perform_config_action(config) + directory new_resource.config_dir do + owner new_resource.owner + group new_resource.group + mode new_resource.directory_mode + + recursive true + + action new_resource.action.eql?(:delete) ? :delete : :create + end + + config.merge!(new_resource.extra_options.dup) unless new_resource.extra_options.empty? + + if new_resource.sort + deepsort? + config.deep_sort! + end + + template new_resource.config_file do + cookbook new_resource.cookbook + source new_resource.template + + owner new_resource.owner + group new_resource.group + mode new_resource.mode + sensitive new_resource.sensitive + + helpers(Unbound::Cookbook::TemplateHelpers) + + variables(content: config) + + action new_resource.action + end + end +end + +%i(create create_if_missing delete).each { |action_type| action(action_type) { do_template_action } } diff --git a/cookbooks/unbound/resources/service.rb b/cookbooks/unbound/resources/service.rb new file mode 100644 index 0000000..3797275 --- /dev/null +++ b/cookbooks/unbound/resources/service.rb @@ -0,0 +1,69 @@ +# +# Cookbook:: unbound +# Resource:: service +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +unified_mode true + +property :service_name, String, + default: 'unbound', + description: 'The service name to perform actions upon' + +property :config_test, [true, false], + default: true, + description: 'Perform configuration file test before performing service action' + +property :config_test_fail_action, Symbol, + equal_to: %i(raise log), + default: :raise, + description: 'Action to perform upon configuration test failure.' + +action_class do + def perform_config_test + cmd = shell_out('/usr/sbin/unbound-checkconf') + cmd.error! + rescue Mixlib::ShellOut::ShellCommandFailed + if new_resource.config_test_fail_action.eql?(:log) + Chef::Log.error("Configuration test failed, #{new_resource.service_name} #{action} action aborted!\n\n"\ + "Error\n-----\n#{cmd.stderr}") + else + raise "Configuration test failed, #{new_resource.service_name} #{action} action aborted!\n\n"\ + "Error\n-----\nAction: #{action}\n#{cmd.stderr}" + end + end + + def do_service_action(service_action) + with_run_context(:root) do + if %i(start restart reload).include?(service_action) + if new_resource.config_test + perform_config_test + Chef::Log.info("Configuration test passed, creating #{new_resource.service_name} #{new_resource.declared_type} resource with action #{service_action}") + else + Chef::Log.info("Configuration test disabled, creating #{new_resource.service_name} #{new_resource.declared_type} resource with action #{service_action}") + end + + declare_resource(:service, new_resource.service_name) { delayed_action(service_action) } + else + declare_resource(:service, new_resource.service_name) { action(service_action) } + end + end + end +end + +%i(start stop restart reload enable disable).each { |action_type| action(action_type) { do_service_action(action_type) } } + +action :test do + converge_by('Performing configuration test') { perform_config_test } +end diff --git a/cookbooks/unbound/templates/default/partials/_generic_config.erb b/cookbooks/unbound/templates/default/partials/_generic_config.erb new file mode 100644 index 0000000..9cb367f --- /dev/null +++ b/cookbooks/unbound/templates/default/partials/_generic_config.erb @@ -0,0 +1,22 @@ +<% unless @content.nil? -%> +<% @content.each do |key, value| %> +<% case value %> +<% when nil %> +<%= key %> +<% when String, Numeric %> +<%= key %><% if @separator %><%= @separator %><% end %> <%= value %> +<% when Array %> +<% value.each do |val| %> +<% if val.is_a?(Hash) %> +<%= key %><% if @separator %><%= @separator %><% end %> +<%= template_partial_indent(render('partials/_generic_config.erb', cookbook: 'unbound', variables: { content: val, separator: ':' }), 1, 2) %> +<% else %> +<%= key %><% if @separator %><%= @separator %><% end %> <%= val %> +<% end %> +<% end %> +<% when Hash %> +<%= key %><% if @separator %><%= @separator %><% end %> +<%= template_partial_indent(render('partials/_generic_config.erb', cookbook: 'unbound', variables: { content: value, separator: ':' }), 1, 2) %> +<% end %> +<% end %> +<% end %> diff --git a/cookbooks/unbound/templates/default/unbound.conf.erb b/cookbooks/unbound/templates/default/unbound.conf.erb new file mode 100644 index 0000000..763be29 --- /dev/null +++ b/cookbooks/unbound/templates/default/unbound.conf.erb @@ -0,0 +1,5 @@ +# +# Generated by Chef Infra for <%= node['fqdn'] %> +# Do NOT modify this file by hand, any changes will be overwritten. + +<%= render('partials/_generic_config.erb', cookbook: 'unbound', variables: { content: @content, separator: ':' }) %> diff --git a/nodes/mail.kosmos.org.json b/nodes/mail.kosmos.org.json index 0e7f7b0..2e384ef 100644 --- a/nodes/mail.kosmos.org.json +++ b/nodes/mail.kosmos.org.json @@ -36,7 +36,9 @@ "kosmos-postfix::default", "hostname::default", "kosmos-base::letsencrypt", + "unbound::default", "kosmos_email::opendkim", + "kosmos_email::spamassassin", "kosmos_email::postfix", "postfix::server", "postfix::default", diff --git a/site-cookbooks/kosmos_email/attributes/default.rb b/site-cookbooks/kosmos_email/attributes/default.rb index dd60bc8..0276203 100644 --- a/site-cookbooks/kosmos_email/attributes/default.rb +++ b/site-cookbooks/kosmos_email/attributes/default.rb @@ -1,4 +1,3 @@ node.default["email"]["domain"] = "example.com" node.default["email"]["hostname"] = "mail.example.com" -# node.default["email"]["user"] = "ray" -# node.default["email"]["group"] = "email" +node.default["email"]["report_contact"] = "abuse@example.com" diff --git a/site-cookbooks/kosmos_email/metadata.rb b/site-cookbooks/kosmos_email/metadata.rb index cc689c3..71cf8ef 100644 --- a/site-cookbooks/kosmos_email/metadata.rb +++ b/site-cookbooks/kosmos_email/metadata.rb @@ -7,4 +7,5 @@ version '0.1.0' chef_version '>= 18.0' depends "hostname" +depends "unbound" depends "postfix" diff --git a/site-cookbooks/kosmos_email/recipes/default.rb b/site-cookbooks/kosmos_email/recipes/default.rb index d775dfa..96eced0 100644 --- a/site-cookbooks/kosmos_email/recipes/default.rb +++ b/site-cookbooks/kosmos_email/recipes/default.rb @@ -21,6 +21,8 @@ firewall_rule "private network access" do source "10.1.1.0/24" end +include_recipe 'unbound' include_recipe 'kosmos_email::opendkim' +include_recipe 'kosmos_email::spamassassin' include_recipe 'kosmos_email::postfix' include_recipe 'kosmos_email::dovecot' diff --git a/site-cookbooks/kosmos_email/recipes/postfix.rb b/site-cookbooks/kosmos_email/recipes/postfix.rb index 1e9475c..69b7b57 100644 --- a/site-cookbooks/kosmos_email/recipes/postfix.rb +++ b/site-cookbooks/kosmos_email/recipes/postfix.rb @@ -36,9 +36,10 @@ node.normal['postfix']['main']['virtual_transport'] = "lmtp:unix:private/dovecot node.normal['postfix']['main']['smtputf8_enable'] = "no" node.normal['postfix']['main']['recipient_delimiter'] = "+" node.normal['postfix']['main']['alias_maps'] = "hash:/etc/aliases, ldap:/etc/postfix/ldap-aliases.cf" -node.normal['postfix']['main']['milter_protocol'] = "2" +node.normal['postfix']['main']['smtpd_sender_login_maps'] = "ldap:/etc/postfix/ldap-username-aliases.cf" +node.normal['postfix']['main']['milter_protocol'] = "6" node.normal['postfix']['main']['milter_default_action'] = "accept" -node.normal['postfix']['main']['smtpd_milters'] = "inet:localhost:12301" +node.normal['postfix']['main']['smtpd_milters'] = "inet:localhost:12301 local:spamass/spamass.sock" node.normal['postfix']['main']['non_smtpd_milters'] = "inet:localhost:12301" node.normal['postfix']['master'] = { diff --git a/site-cookbooks/kosmos_email/recipes/spamassassin.rb b/site-cookbooks/kosmos_email/recipes/spamassassin.rb new file mode 100644 index 0000000..3971c62 --- /dev/null +++ b/site-cookbooks/kosmos_email/recipes/spamassassin.rb @@ -0,0 +1,34 @@ +# +# Cookbook:: kosmos_email +# Recipe:: spamassassin +# + +%w[ + spamassassin + spamc + spamass-milter +].each do |pkg| + apt_package pkg +end + +domain = node["email"]["domain"] +report_contact = node["email"]["report_contact"] + +template "/etc/default/spamassassin" do + source "spamassassin_default.erb" + mode 0644 + variables options: "-u debian-spamd --nouser-config --max-children 10" + notifies :restart, "service[spamassassin]", :delayed +end + +template "/etc/spamassassin/local.cf" do + source "spamassassin_local.cf.erb" + mode 0644 + variables whitelist_auth: "*@#{domain}", + report_contact: report_contact + notifies :restart, "service[spamassassin]", :delayed +end + +service "spamassassin" do + action [:enable, :start] +end diff --git a/site-cookbooks/kosmos_email/templates/spamass-milter.erb b/site-cookbooks/kosmos_email/templates/spamass-milter.erb new file mode 100644 index 0000000..8922fb5 --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/spamass-milter.erb @@ -0,0 +1,28 @@ +# spamass-milt startup defaults + +# OPTIONS are passed directly to spamass-milter. +# man spamass-milter for details + +# Non-standard configuration notes: +# See README.Debian if you use the -x option with sendmail +# You should not pass the -d option in OPTIONS; use SOCKET for that. + +# Default, use the spamass-milter user as the default user, ignore +# messages from localhost +OPTIONS="-u spamass-milter -i 127.0.0.1" + +# Reject emails with spamassassin scores > 15. +#OPTIONS="${OPTIONS} -r 15" + +# Do not modify Subject:, Content-Type: or body. +#OPTIONS="${OPTIONS} -m" + +###################################### +# If /usr/sbin/postfix is executable, the following are set by +# default. You can override them by uncommenting and changing them +# here. +###################################### +# SOCKET="/var/spool/postfix/spamass/spamass.sock" +# SOCKETOWNER="postfix:postfix" +# SOCKETMODE="0660" +###################################### diff --git a/site-cookbooks/kosmos_email/templates/spamassassin_default.erb b/site-cookbooks/kosmos_email/templates/spamassassin_default.erb new file mode 100644 index 0000000..624688a --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/spamassassin_default.erb @@ -0,0 +1,33 @@ +# /etc/default/spamassassin +# Duncan Findlay + +# WARNING: please read README.spamd before using. +# There may be security risks. + +# Prior to version 3.4.2-1, spamd could be enabled by setting +# ENABLED=1 in this file. This is no longer supported. Instead, please +# use the update-rc.d command, invoked for example as "update-rc.d +# spamassassin enable", to enable the spamd service. + +# Options +# See man spamd for possible options. The -d option is automatically added. + +# SpamAssassin uses a preforking model, so be careful! You need to +# make sure --max-children is not set to anything higher than 5, +# unless you know what you're doing. + +OPTIONS="<%= @options %>" + +# Pid file +# Where should spamd write its PID to file? If you use the -u or +# --username option above, this needs to be writable by that user. +# Otherwise, the init script will not be able to shut spamd down. +PIDFILE="/var/run/spamd.pid" + +# Set nice level of spamd +#NICE="--nicelevel 15" + +# Cronjob +# Set to anything but 0 to enable the cron job to automatically update +# spamassassin's rules on a nightly basis +CRON=0 diff --git a/site-cookbooks/kosmos_email/templates/spamassassin_local.cf.erb b/site-cookbooks/kosmos_email/templates/spamassassin_local.cf.erb new file mode 100644 index 0000000..c196054 --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/spamassassin_local.cf.erb @@ -0,0 +1,119 @@ +# This is the right place to customize your installation of SpamAssassin. +# +# See 'perldoc Mail::SpamAssassin::Conf' for details of what can be +# tweaked. +# +# Only a small subset of options are listed below +# +########################################################################### + +dns_available yes +dns_server 127.0.0.1 + +whitelist_auth <%= @whitelist_auth %> + +# A 'contact address' users should contact for more info. (replaces +# _CONTACTADDRESS_ in the report template) +report_contact <%= @report_contact %> + + +# Add *****SPAM***** to the Subject header of spam e-mails +# +# rewrite_header Subject *****SPAM***** + + +# Save spam messages as a message/rfc822 MIME attachment instead of +# modifying the original message (0: off, 2: use text/plain instead) +# +# report_safe 1 + + +# Set which networks or hosts are considered 'trusted' by your mail +# server (i.e. not spammers) +# +# trusted_networks 212.17.35. + + +# Set file-locking method (flock is not safe over NFS, but is faster) +# +# lock_method flock + + +# Set the threshold at which a message is considered spam (default: 5.0) +# +# required_score 5.0 + + +# Use Bayesian classifier (default: 1) +# +# use_bayes 1 + + +# Bayesian classifier auto-learning (default: 1) +# +# bayes_auto_learn 1 + + +# Set headers which may provide inappropriate cues to the Bayesian +# classifier +# +# bayes_ignore_header X-Bogosity +# bayes_ignore_header X-Spam-Flag +# bayes_ignore_header X-Spam-Status + + +# Whether to decode non- UTF-8 and non-ASCII textual parts and recode +# them to UTF-8 before the text is given over to rules processing. +# +# normalize_charset 1 + +# Textual body scan limit (default: 50000) +# +# Amount of data per email text/* mimepart, that will be run through body +# rules. This enables safer and faster scanning of large messages, +# perhaps having very large textual attachments. There should be no need +# to change this well tested default. +# +# body_part_scan_size 50000 + +# Textual rawbody data scan limit (default: 500000) +# +# Amount of data per email text/* mimepart, that will be run through +# rawbody rules. +# +# rawbody_part_scan_size 500000 + +# Some shortcircuiting, if the plugin is enabled +# +ifplugin Mail::SpamAssassin::Plugin::Shortcircuit +# +# default: strongly-whitelisted mails are *really* whitelisted now, if the +# shortcircuiting plugin is active, causing early exit to save CPU load. +# Uncomment to turn this on +# +# SpamAssassin tries hard not to launch DNS queries before priority -100. +# If you want to shortcircuit without launching unneeded queries, make +# sure such rule priority is below -100. These examples are already: +# +# shortcircuit USER_IN_WHITELIST on +# shortcircuit USER_IN_DEF_WHITELIST on +# shortcircuit USER_IN_ALL_SPAM_TO on +# shortcircuit SUBJECT_IN_WHITELIST on + +# the opposite; blacklisted mails can also save CPU +# +# shortcircuit USER_IN_BLACKLIST on +# shortcircuit USER_IN_BLACKLIST_TO on +# shortcircuit SUBJECT_IN_BLACKLIST on + +# if you have taken the time to correctly specify your "trusted_networks", +# this is another good way to save CPU +# +# shortcircuit ALL_TRUSTED on + +# and a well-trained bayes DB can save running rules, too +# +# shortcircuit BAYES_99 spam +# shortcircuit BAYES_00 ham + +endif # Mail::SpamAssassin::Plugin::Shortcircuit From 5a4cdf9c3060b6e93452031d43a0c0b7f8dd1b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Wed, 6 Dec 2023 12:27:38 +0100 Subject: [PATCH 20/26] Prevent local users from impersonating other local users --- site-cookbooks/kosmos_email/recipes/postfix.rb | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/site-cookbooks/kosmos_email/recipes/postfix.rb b/site-cookbooks/kosmos_email/recipes/postfix.rb index 69b7b57..d8892bd 100644 --- a/site-cookbooks/kosmos_email/recipes/postfix.rb +++ b/site-cookbooks/kosmos_email/recipes/postfix.rb @@ -68,8 +68,9 @@ node.normal['postfix']['master'] = { "-o smtpd_tls_security_level=encrypt", "-o smtpd_tls_wrappermode=no", "-o smtpd_sasl_auth_enable=yes", + "-o smtpd_sender_restrictions=reject_sender_login_mismatch", "-o smtpd_relay_restrictions=permit_sasl_authenticated,reject", - "-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject", + "-o smtpd_recipient_restrictions=permit_mynetworks,reject_sender_login_mismatch,permit_sasl_authenticated,reject", "-o smtpd_sasl_type=dovecot", "-o smtpd_sasl_path=private/auth", "-o smtpd_upstream_proxy_protocol=haproxy", @@ -87,6 +88,7 @@ node.normal['postfix']['master'] = { "-o smtpd_tls_wrappermode=yes", "-o smtpd_sasl_auth_enable=yes", "-o smtpd_relay_restrictions=permit_sasl_authenticated,reject", + "-o smtpd_sender_restrictions=reject_sender_login_mismatch", "-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject", "-o smtpd_sasl_type=dovecot", "-o smtpd_sasl_path=private/auth", @@ -133,6 +135,18 @@ template "/etc/postfix/ldap-aliases.cf" do notifies :restart, "service[postfix]", :delayed end +template "/etc/postfix/ldap-username-aliases.cf" do + source "ldap-aliases.cf.erb" + mode 0600 + variables server_host: "ldap.kosmos.local", + bind_dn: credentials['ldap_dn'], + bind_pw: credentials['ldap_dnpass'], + search_base: "ou=kosmos.org,cn=users,dc=kosmos,dc=org", + query_filter: "(&(objectClass=person)(cn=%u))", + result_attribute: "cn" + notifies :restart, "service[postfix]", :delayed +end + include_recipe 'postfix::server' service "postfix" do From ca580bcfe24af523fabc931bc991aa124af05c91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Thu, 7 Dec 2023 09:37:37 +0100 Subject: [PATCH 21/26] Set email report contact in production --- environments/production.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/environments/production.json b/environments/production.json index 68e9acc..ae7ba44 100644 --- a/environments/production.json +++ b/environments/production.json @@ -21,7 +21,8 @@ }, "email": { "domain": "kosmos.org", - "hostname": "mail.kosmos.org" + "hostname": "mail.kosmos.org", + "report_contact": "abuse@kosmos.org" }, "garage": { "replication_mode": "2", From 69af908f6b1265334c4178e9cac50714ce8d96aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Thu, 7 Dec 2023 14:02:37 +0100 Subject: [PATCH 22/26] Virtual domain configs --- .../kosmos_email/attributes/default.rb | 8 +- .../kosmos_email/recipes/dovecot.rb | 23 +++- .../kosmos_email/recipes/postfix.rb | 75 +++++++++---- .../templates/dovecot_10-auth.conf.erb | 2 +- .../templates/dovecot_10-mail.conf.erb | 61 +--------- .../templates/dovecot_15-mailboxes.conf.erb | 106 ++++++++++++++++++ ...aliases.cf.erb => postfix_ldap-map.cf.erb} | 3 + 7 files changed, 188 insertions(+), 90 deletions(-) create mode 100644 site-cookbooks/kosmos_email/templates/dovecot_15-mailboxes.conf.erb rename site-cookbooks/kosmos_email/templates/{ldap-aliases.cf.erb => postfix_ldap-map.cf.erb} (73%) diff --git a/site-cookbooks/kosmos_email/attributes/default.rb b/site-cookbooks/kosmos_email/attributes/default.rb index 0276203..c77e52b 100644 --- a/site-cookbooks/kosmos_email/attributes/default.rb +++ b/site-cookbooks/kosmos_email/attributes/default.rb @@ -1,3 +1,5 @@ -node.default["email"]["domain"] = "example.com" -node.default["email"]["hostname"] = "mail.example.com" -node.default["email"]["report_contact"] = "abuse@example.com" +node.default["email"]["domain"] = "example.com" +node.default["email"]["hostname"] = "mail.example.com" +node.default["email"]["report_contact"] = "abuse@example.com" +node.default["email"]["ldap_host"] = "ldap.kosmos.local" +node.default["email"]["ldap_search_base"] = "cn=users,dc=kosmos,dc=org" diff --git a/site-cookbooks/kosmos_email/recipes/dovecot.rb b/site-cookbooks/kosmos_email/recipes/dovecot.rb index fff9274..9ebafd6 100644 --- a/site-cookbooks/kosmos_email/recipes/dovecot.rb +++ b/site-cookbooks/kosmos_email/recipes/dovecot.rb @@ -17,6 +17,9 @@ domain = node["email"]["domain"] hostname = node["email"]["hostname"] ip_addr = node["knife_zero"]["host"] +ldap_search_base = node["email"]["ldap_search_base"] +ldap_user_filter = "(&(objectClass=person)(mailRoutingAddress=%u))" + credentials = Chef::EncryptedDataBagItem.load('credentials', 'email') user "vmail" do @@ -41,11 +44,11 @@ template "/etc/dovecot/dovecot-ldap.conf.ext" do variables uris: "ldap://ldap.kosmos.local", # TODO add list of all IPs instead? dn: credentials['ldap_dn'], dnpass: credentials['ldap_dnpass'], - base: "ou=kosmos.org,cn=users,dc=kosmos,dc=org", - user_attrs: "mailhome=home", - user_filter: "(&(objectClass=person)(cn=%u))", - pass_attrs: "cn=user,mailpassword=password", - pass_filter: "(&(objectClass=person)(cn=%u))", + base: ldap_search_base, + user_filter: ldap_user_filter, + user_attrs: "", + pass_filter: ldap_user_filter, + pass_attrs: "mailRoutingAddress=user,mailpassword=password", default_pass_scheme: "BLF-CRYPT" notifies :restart, "service[dovecot]", :delayed end @@ -60,7 +63,9 @@ template "/etc/dovecot/conf.d/10-mail.conf" do source "dovecot_10-mail.conf.erb" mode 0644 variables mail_uid: "vmail", - mail_gid: "mail" + mail_gid: "mail", + mail_location: "mbox:~/mail:INBOX=~/mail/INBOX", + mail_home: "/var/vmail/%d/%n" notifies :restart, "service[dovecot]", :delayed end @@ -79,6 +84,12 @@ template "/etc/dovecot/conf.d/10-ssl.conf" do notifies :restart, "service[dovecot]", :delayed end +template "/etc/dovecot/conf.d/15-mailboxes.conf" do + source "dovecot_15-mailboxes.conf.erb" + mode 0644 + notifies :restart, "service[dovecot]", :delayed +end + service "dovecot" do action [:enable, :start] end diff --git a/site-cookbooks/kosmos_email/recipes/postfix.rb b/site-cookbooks/kosmos_email/recipes/postfix.rb index d8892bd..a66dbf1 100644 --- a/site-cookbooks/kosmos_email/recipes/postfix.rb +++ b/site-cookbooks/kosmos_email/recipes/postfix.rb @@ -14,17 +14,19 @@ domain = node["email"]["domain"] hostname = node["email"]["hostname"] ip_addr = node["knife_zero"]["host"] +ldap_host = node["email"]["ldap_host"] +ldap_search_base = node["email"]["ldap_search_base"] + credentials = Chef::EncryptedDataBagItem.load('credentials', 'email') node.normal["postfix"]["mail_type"] = "master" node.normal["postfix"]["use_relay_restrictions_maps"] = true node.normal["postfix"]["relay_restrictions"] = { domain => "OK", hostname => "OK" } -node.normal['postfix']['main']['mydomain'] = domain -node.normal['postfix']['main']['myorigin'] = domain node.normal['postfix']['main']['myhostname'] = hostname +node.normal['postfix']['main']['mydomain'] = "$myhostname" +node.normal['postfix']['main']['myorigin'] = "$myhostname" node.normal['postfix']['main']['mynetworks'] = ["10.1.1.0/24", "127.0.0.0/8"] -node.normal['postfix']['main']['mydestination'] = [domain, hostname, 'localhost.localdomain', 'localhost'].compact node.normal['postfix']['main']['smtp_use_tls'] = "yes" node.normal['postfix']['main']['smtp_tls_security_level'] = "may" node.normal['postfix']['main']['smtpd_use_tls'] = "yes" @@ -35,8 +37,13 @@ node.normal['postfix']['main']['mailbox_transport'] = "lmtp:unix:private/dovecot node.normal['postfix']['main']['virtual_transport'] = "lmtp:unix:private/dovecot-lmtp" node.normal['postfix']['main']['smtputf8_enable'] = "no" node.normal['postfix']['main']['recipient_delimiter'] = "+" -node.normal['postfix']['main']['alias_maps'] = "hash:/etc/aliases, ldap:/etc/postfix/ldap-aliases.cf" -node.normal['postfix']['main']['smtpd_sender_login_maps'] = "ldap:/etc/postfix/ldap-username-aliases.cf" + +# node.normal['postfix']['main']['virtual_alias_domains'] = "ldap:/etc/postfix/ldap-virtual_alias_domains.cf" +node.normal['postfix']['main']['virtual_alias_maps'] = "hash:/var/vmail/aliases, ldap:/etc/postfix/ldap-virtual_alias_maps.cf" +node.normal['postfix']['main']['virtual_mailbox_domains'] = "ldap:/etc/postfix/ldap-virtual_mailbox_domains.cf" +node.normal['postfix']['main']['virtual_mailbox_maps'] = "ldap:/etc/postfix/ldap-virtual_mailbox_maps.cf" +node.normal['postfix']['main']['smtpd_sender_login_maps'] = "ldap:/etc/postfix/ldap-smtpd_sender_login_maps.cf" + node.normal['postfix']['main']['milter_protocol'] = "6" node.normal['postfix']['main']['milter_default_action'] = "accept" node.normal['postfix']['main']['smtpd_milters'] = "inet:localhost:12301 local:spamass/spamass.sock" @@ -70,7 +77,7 @@ node.normal['postfix']['master'] = { "-o smtpd_sasl_auth_enable=yes", "-o smtpd_sender_restrictions=reject_sender_login_mismatch", "-o smtpd_relay_restrictions=permit_sasl_authenticated,reject", - "-o smtpd_recipient_restrictions=permit_mynetworks,reject_sender_login_mismatch,permit_sasl_authenticated,reject", + "-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject", "-o smtpd_sasl_type=dovecot", "-o smtpd_sasl_path=private/auth", "-o smtpd_upstream_proxy_protocol=haproxy", @@ -123,27 +130,51 @@ node.normal['postfix']['master'] = { } } -template "/etc/postfix/ldap-aliases.cf" do - source "ldap-aliases.cf.erb" +ldap_default_variables = { + server_host: ldap_host, + bind_dn: credentials['ldap_dn'], + bind_pw: credentials['ldap_dnpass'], + search_base: ldap_search_base +} + +template "/etc/postfix/ldap-virtual_mailbox_domains.cf" do + source "postfix_ldap-map.cf.erb" mode 0600 - variables server_host: "ldap.kosmos.local", - bind_dn: credentials['ldap_dn'], - bind_pw: credentials['ldap_dnpass'], - search_base: "ou=kosmos.org,cn=users,dc=kosmos,dc=org", - query_filter: "(&(objectClass=person)(cn=%u))", - result_attribute: "maildrop" + variables ldap_default_variables.merge({ + query_filter: "mailRoutingAddress=*@%s", + result_attribute: "mailRoutingAddress", + result_format: "%d" + }) notifies :restart, "service[postfix]", :delayed end -template "/etc/postfix/ldap-username-aliases.cf" do - source "ldap-aliases.cf.erb" +template "/etc/postfix/ldap-virtual_alias_maps.cf" do + source "postfix_ldap-map.cf.erb" mode 0600 - variables server_host: "ldap.kosmos.local", - bind_dn: credentials['ldap_dn'], - bind_pw: credentials['ldap_dnpass'], - search_base: "ou=kosmos.org,cn=users,dc=kosmos,dc=org", - query_filter: "(&(objectClass=person)(cn=%u))", - result_attribute: "cn" + variables ldap_default_variables.merge({ + query_filter: "(&(mailRoutingAddress=%s)(mailForwardingAddress=*))", + result_attribute: "mailForwardingAddress" + }) + notifies :restart, "service[postfix]", :delayed +end + +template "/etc/postfix/ldap-virtual_mailbox_maps.cf" do + source "postfix_ldap-map.cf.erb" + mode 0600 + variables ldap_default_variables.merge({ + query_filter: "mailRoutingAddress=%s", + result_attribute: "mailRoutingAddress" + }) + notifies :restart, "service[postfix]", :delayed +end + +template "/etc/postfix/ldap-smtpd_sender_login_maps.cf" do + source "postfix_ldap-map.cf.erb" + mode 0600 + variables ldap_default_variables.merge({ + query_filter: "mailRoutingAddress=%s", + result_attribute: "mailRoutingAddress, mailForwardingAddress" + }) notifies :restart, "service[postfix]", :delayed end diff --git a/site-cookbooks/kosmos_email/templates/dovecot_10-auth.conf.erb b/site-cookbooks/kosmos_email/templates/dovecot_10-auth.conf.erb index f3270b1..7c079aa 100644 --- a/site-cookbooks/kosmos_email/templates/dovecot_10-auth.conf.erb +++ b/site-cookbooks/kosmos_email/templates/dovecot_10-auth.conf.erb @@ -48,7 +48,7 @@ disable_plaintext_auth = yes # the standard variables here, eg. %Lu would lowercase the username, %n would # drop away the domain if it was given, or "%n-AT-%d" would change the '@' into # "-AT-". This translation is done after auth_username_translation changes. -auth_username_format = %n +auth_username_format = %Lu # If you want to allow master users to log in by specifying the master # username within the normal username string (ie. not using SASL mechanism's diff --git a/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb b/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb index 8833f28..21c0ee2 100644 --- a/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb +++ b/site-cookbooks/kosmos_email/templates/dovecot_10-mail.conf.erb @@ -27,7 +27,9 @@ # # # -mail_location = mbox:~/mail:INBOX=~/mail/INBOX +mail_location = <%= @mail_location %> + +mail_home = <%= @mail_home %> # If you need to set multiple mailbox locations or want to change default # namespace settings, you can do it by defining namespace sections. @@ -40,63 +42,6 @@ mail_location = mbox:~/mail:INBOX=~/mail/INBOX # users can access all the shared mailboxes, assuming they have permissions # on filesystem level to do so. namespace inbox { - type = private - inbox = yes - - mailbox Drafts { - special_use = \Drafts - auto = subscribe - } - - mailbox Junk { - special_use = \Junk - auto = create - } - - mailbox spam { - special_use = \Junk - auto = no - } - - mailbox Spam { - special_use = \Junk - auto = no - } - - mailbox Trash { - special_use = \Trash - auto = subscribe - } - - mailbox TRASH { - special_use = \Trash - auto = no - } - - mailbox Sent { - special_use = \Sent - auto = subscribe - } - - mailbox "Sent Mail" { - special_use = \Sent - auto = no - } - - mailbox "Sent Messages" { - special_use = \Sent - auto = no - } - - mailbox Archive { - special_use = \Archive - auto = create - } - - mailbox "Archives" { - special_use = \Archive - auto = no - } } # Example shared namespace configuration diff --git a/site-cookbooks/kosmos_email/templates/dovecot_15-mailboxes.conf.erb b/site-cookbooks/kosmos_email/templates/dovecot_15-mailboxes.conf.erb new file mode 100644 index 0000000..a2c2c59 --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/dovecot_15-mailboxes.conf.erb @@ -0,0 +1,106 @@ +## +## Mailbox definitions +## + +# Each mailbox is specified in a separate mailbox section. The section name +# specifies the mailbox name. If it has spaces, you can put the name +# "in quotes". These sections can contain the following mailbox settings: +# +# auto: +# Indicates whether the mailbox with this name is automatically created +# implicitly when it is first accessed. The user can also be automatically +# subscribed to the mailbox after creation. The following values are +# defined for this setting: +# +# no - Never created automatically. +# create - Automatically created, but no automatic subscription. +# subscribe - Automatically created and subscribed. +# +# special_use: +# A space-separated list of SPECIAL-USE flags (RFC 6154) to use for the +# mailbox. There are no validity checks, so you could specify anything +# you want in here, but it's not a good idea to use flags other than the +# standard ones specified in the RFC: +# +# \All - This (virtual) mailbox presents all messages in the +# user's message store. +# \Archive - This mailbox is used to archive messages. +# \Drafts - This mailbox is used to hold draft messages. +# \Flagged - This (virtual) mailbox presents all messages in the +# user's message store marked with the IMAP \Flagged flag. +# \Important - This (virtual) mailbox presents all messages in the +# user's message store deemed important to user. +# \Junk - This mailbox is where messages deemed to be junk mail +# are held. +# \Sent - This mailbox is used to hold copies of messages that +# have been sent. +# \Trash - This mailbox is used to hold messages that have been +# deleted. +# +# comment: +# Defines a default comment or note associated with the mailbox. This +# value is accessible through the IMAP METADATA mailbox entries +# "/shared/comment" and "/private/comment". Users with sufficient +# privileges can override the default value for entries with a custom +# value. + +# NOTE: Assumes "namespace inbox" has been defined in 10-mail.conf. +namespace inbox { + type = private + inbox = yes + + mailbox Drafts { + special_use = \Drafts + auto = subscribe + } + + mailbox Junk { + special_use = \Junk + auto = create + } + + mailbox spam { + special_use = \Junk + auto = no + } + + mailbox Spam { + special_use = \Junk + auto = no + } + + mailbox Trash { + special_use = \Trash + auto = subscribe + } + + mailbox TRASH { + special_use = \Trash + auto = no + } + + mailbox Sent { + special_use = \Sent + auto = subscribe + } + + mailbox "Sent Mail" { + special_use = \Sent + auto = no + } + + mailbox "Sent Messages" { + special_use = \Sent + auto = no + } + + mailbox Archive { + special_use = \Archive + auto = create + } + + mailbox "Archives" { + special_use = \Archive + auto = no + } +} diff --git a/site-cookbooks/kosmos_email/templates/ldap-aliases.cf.erb b/site-cookbooks/kosmos_email/templates/postfix_ldap-map.cf.erb similarity index 73% rename from site-cookbooks/kosmos_email/templates/ldap-aliases.cf.erb rename to site-cookbooks/kosmos_email/templates/postfix_ldap-map.cf.erb index 3b266a6..2711e0d 100644 --- a/site-cookbooks/kosmos_email/templates/ldap-aliases.cf.erb +++ b/site-cookbooks/kosmos_email/templates/postfix_ldap-map.cf.erb @@ -5,3 +5,6 @@ bind_pw = <%= @bind_pw %> search_base = <%= @search_base %> query_filter = <%= @query_filter %> result_attribute = <%= @result_attribute %> +<% if @result_format %> +result_format = <%= @result_format %> +<% end %> From cfa7da2051333e26ce03b703ee5e87e971b954f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Mon, 8 Jan 2024 10:47:19 +0300 Subject: [PATCH 23/26] Create vmail dir on fresh systems --- site-cookbooks/kosmos_email/recipes/dovecot.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/site-cookbooks/kosmos_email/recipes/dovecot.rb b/site-cookbooks/kosmos_email/recipes/dovecot.rb index 9ebafd6..4ad1c2c 100644 --- a/site-cookbooks/kosmos_email/recipes/dovecot.rb +++ b/site-cookbooks/kosmos_email/recipes/dovecot.rb @@ -28,6 +28,11 @@ user "vmail" do manage_home false end +directory "/var/vmail" do + owner "vmail" + group "mail" +end + template "/etc/dovecot/dovecot.conf" do source "dovecot.conf.erb" mode 0644 From 98acd429de031ac7bc88488a3a9a43a0270f5b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Mon, 8 Jan 2024 11:29:56 +0300 Subject: [PATCH 24/26] Add configs for virtual email aliases --- environments/production.json | 12 ++++++++++- .../kosmos_email/attributes/default.rb | 4 ++++ .../kosmos_email/recipes/postfix.rb | 20 +++++++++++++++---- .../templates/virtual-aliases.erb | 3 +++ 4 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 site-cookbooks/kosmos_email/templates/virtual-aliases.erb diff --git a/environments/production.json b/environments/production.json index ae7ba44..ca1912e 100644 --- a/environments/production.json +++ b/environments/production.json @@ -22,7 +22,17 @@ "email": { "domain": "kosmos.org", "hostname": "mail.kosmos.org", - "report_contact": "abuse@kosmos.org" + "report_contact": "abuse@kosmos.org", + "virtual_aliases": { + "admin@kosmos.org": "ops@kosmos.org", + "ops@kosmos.org": "ops@5apps.com", + "webmaster": "mail@kosmos.org", + "hostmaster@kosmos.org": "mail@kosmos.org", + "postmaster@kosmos.org": "mail@kosmos.org", + "abuse@kosmos.org": "mail@kosmos.org", + "mail@kosmos.org": "foundation@kosmos.org", + "hackerhouse@kosmos.org": "mail@lagrange6.com" + } }, "garage": { "replication_mode": "2", diff --git a/site-cookbooks/kosmos_email/attributes/default.rb b/site-cookbooks/kosmos_email/attributes/default.rb index c77e52b..9463a3d 100644 --- a/site-cookbooks/kosmos_email/attributes/default.rb +++ b/site-cookbooks/kosmos_email/attributes/default.rb @@ -1,5 +1,9 @@ +node.default["email"]["root_directory"] = "/var/vmail" node.default["email"]["domain"] = "example.com" node.default["email"]["hostname"] = "mail.example.com" node.default["email"]["report_contact"] = "abuse@example.com" node.default["email"]["ldap_host"] = "ldap.kosmos.local" node.default["email"]["ldap_search_base"] = "cn=users,dc=kosmos,dc=org" +node.default["email"]["virtual_aliases"] = { + "admin@example.com" => "administrator@example.com" +} diff --git a/site-cookbooks/kosmos_email/recipes/postfix.rb b/site-cookbooks/kosmos_email/recipes/postfix.rb index a66dbf1..3b61533 100644 --- a/site-cookbooks/kosmos_email/recipes/postfix.rb +++ b/site-cookbooks/kosmos_email/recipes/postfix.rb @@ -12,6 +12,7 @@ end domain = node["email"]["domain"] hostname = node["email"]["hostname"] +root_dir = node["email"]["root_directory"] ip_addr = node["knife_zero"]["host"] ldap_host = node["email"]["ldap_host"] @@ -37,13 +38,10 @@ node.normal['postfix']['main']['mailbox_transport'] = "lmtp:unix:private/dovecot node.normal['postfix']['main']['virtual_transport'] = "lmtp:unix:private/dovecot-lmtp" node.normal['postfix']['main']['smtputf8_enable'] = "no" node.normal['postfix']['main']['recipient_delimiter'] = "+" - -# node.normal['postfix']['main']['virtual_alias_domains'] = "ldap:/etc/postfix/ldap-virtual_alias_domains.cf" -node.normal['postfix']['main']['virtual_alias_maps'] = "hash:/var/vmail/aliases, ldap:/etc/postfix/ldap-virtual_alias_maps.cf" +node.normal['postfix']['main']['virtual_alias_maps'] = "hash:#{root_dir}/aliases, ldap:/etc/postfix/ldap-virtual_alias_maps.cf" node.normal['postfix']['main']['virtual_mailbox_domains'] = "ldap:/etc/postfix/ldap-virtual_mailbox_domains.cf" node.normal['postfix']['main']['virtual_mailbox_maps'] = "ldap:/etc/postfix/ldap-virtual_mailbox_maps.cf" node.normal['postfix']['main']['smtpd_sender_login_maps'] = "ldap:/etc/postfix/ldap-smtpd_sender_login_maps.cf" - node.normal['postfix']['main']['milter_protocol'] = "6" node.normal['postfix']['main']['milter_default_action'] = "accept" node.normal['postfix']['main']['smtpd_milters'] = "inet:localhost:12301 local:spamass/spamass.sock" @@ -130,6 +128,20 @@ node.normal['postfix']['master'] = { } } +bash "compile_postfix_aliases" do + cwd root_dir + code "postmap #{root_dir}/aliases" + action :nothing + notifies :restart, "service[postfix]", :delayed +end + +template "#{root_dir}/aliases" do + source "virtual-aliases.erb" + mode 0755 + variables aliases: node["email"]["virtual_aliases"] + notifies :run, "bash[compile_postfix_aliases]", :immediately +end + ldap_default_variables = { server_host: ldap_host, bind_dn: credentials['ldap_dn'], diff --git a/site-cookbooks/kosmos_email/templates/virtual-aliases.erb b/site-cookbooks/kosmos_email/templates/virtual-aliases.erb new file mode 100644 index 0000000..8aa699b --- /dev/null +++ b/site-cookbooks/kosmos_email/templates/virtual-aliases.erb @@ -0,0 +1,3 @@ +<% @aliases.each do |k, v| %> +<%= "#{k}\t#{v}" %> +<% end %> From daadd9374f4d93224bb8823021741bec29aeb9ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Mon, 8 Jan 2024 11:35:04 +0300 Subject: [PATCH 25/26] Use attribute for root dir --- site-cookbooks/kosmos_email/recipes/default.rb | 12 ++++++++++++ site-cookbooks/kosmos_email/recipes/dovecot.rb | 14 ++------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/site-cookbooks/kosmos_email/recipes/default.rb b/site-cookbooks/kosmos_email/recipes/default.rb index 96eced0..bb80c24 100644 --- a/site-cookbooks/kosmos_email/recipes/default.rb +++ b/site-cookbooks/kosmos_email/recipes/default.rb @@ -5,11 +5,23 @@ domain = node["email"]["domain"] hostname = node["email"]["hostname"] +root_dir = node["email"]["root_directory"] ip_addr = node["knife_zero"]["host"] node.override["set_fqdn"] = hostname include_recipe "hostname" +user "vmail" do + gid "mail" + system true + manage_home false +end + +directory root_dir do + owner "vmail" + group "mail" +end + tls_cert_for hostname do auth "gandi_dns" action :create diff --git a/site-cookbooks/kosmos_email/recipes/dovecot.rb b/site-cookbooks/kosmos_email/recipes/dovecot.rb index 4ad1c2c..0a6f1f7 100644 --- a/site-cookbooks/kosmos_email/recipes/dovecot.rb +++ b/site-cookbooks/kosmos_email/recipes/dovecot.rb @@ -15,6 +15,7 @@ end domain = node["email"]["domain"] hostname = node["email"]["hostname"] +root_dir = node["email"]["root_directory"] ip_addr = node["knife_zero"]["host"] ldap_search_base = node["email"]["ldap_search_base"] @@ -22,17 +23,6 @@ ldap_user_filter = "(&(objectClass=person)(mailRoutingAddress=%u))" credentials = Chef::EncryptedDataBagItem.load('credentials', 'email') -user "vmail" do - gid "mail" - system true - manage_home false -end - -directory "/var/vmail" do - owner "vmail" - group "mail" -end - template "/etc/dovecot/dovecot.conf" do source "dovecot.conf.erb" mode 0644 @@ -70,7 +60,7 @@ template "/etc/dovecot/conf.d/10-mail.conf" do variables mail_uid: "vmail", mail_gid: "mail", mail_location: "mbox:~/mail:INBOX=~/mail/INBOX", - mail_home: "/var/vmail/%d/%n" + mail_home: "#{root_dir}/%d/%n" notifies :restart, "service[dovecot]", :delayed end From 456ec7a5fa7fc33e078a6041fcb7427c31ea96ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Tue, 9 Jan 2024 15:57:04 +0300 Subject: [PATCH 26/26] Deploy new email VM --- nodes/mail.kosmos.org.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nodes/mail.kosmos.org.json b/nodes/mail.kosmos.org.json index 2e384ef..b308e91 100644 --- a/nodes/mail.kosmos.org.json +++ b/nodes/mail.kosmos.org.json @@ -3,15 +3,15 @@ "chef_environment": "production", "normal": { "knife_zero": { - "host": "10.1.1.141" + "host": "10.1.1.95" } }, "automatic": { "fqdn": "mail.kosmos.org", "os": "linux", - "os_version": "5.15.0-1045-kvm", + "os_version": "5.15.0-1048-kvm", "hostname": "mail", - "ipaddress": "192.168.122.127", + "ipaddress": "192.168.122.131", "roles": [ "base", "kvm_guest",