mirror of
https://git.lapiole.org/dani/ansible-roles.git
synced 2025-07-27 00:05:44 +02:00
Update to 2021-12-01 19:13
This commit is contained in:
1
roles/zimbra/amavis.yml
Normal file
1
roles/zimbra/amavis.yml
Normal file
@@ -0,0 +1 @@
|
||||
---
|
79
roles/zimbra/defaults/main.yml
Normal file
79
roles/zimbra/defaults/main.yml
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
|
||||
zcs_install: False
|
||||
zcs_version: 8.8.12
|
||||
zcs_archive_name: zcs-8.8.12_GA_3794.RHEL7_64.20190329045002.tgz
|
||||
zcs_archive_url: https://files.zimbra.com/downloads/{{ zcs_version }}_GA/{{ zcs_archive_name }}
|
||||
zcs_archive_sha1: 9b1e5a13de311aab106953e321fc04970bfd3730
|
||||
|
||||
# Primary LDAP server of the cluster
|
||||
# zcs_primary_ldap: ldap1.example.org
|
||||
|
||||
# Zimbra components to install
|
||||
zcs_components: []
|
||||
# - ldap
|
||||
# - logger
|
||||
# - mta
|
||||
# - store
|
||||
# - spell
|
||||
# - memcached
|
||||
# - proxy
|
||||
|
||||
zcs_main_domain: "{{ ansible_domain }}"
|
||||
|
||||
zcs_cluster_ip: []
|
||||
zcs_smtp_src_ip:
|
||||
- 0.0.0.0/0
|
||||
zcs_http_src_ip:
|
||||
- 0.0.0.0/0
|
||||
# Additional list of IP able to access ldap services (zcs_cluster_ip are already allowed)
|
||||
zcs_ldap_src_ip: []
|
||||
zcs_clients_src_ip:
|
||||
- 0.0.0.0/0
|
||||
zcs_admin_src_ip: []
|
||||
zcs_mysql_src_ip: []
|
||||
|
||||
# If we should get certificate from Let's Encrypt
|
||||
# the letsencrypt role should be deployed also on the primary LDAP server
|
||||
# Note that the certificate requested will have all the cluster members as alt names
|
||||
# so be sure all the challenges can be resolved
|
||||
zcs_letsencrypt: False
|
||||
|
||||
# The LDAP admin password (used for other servers to join the cluster for example
|
||||
# zcs_ldap_admin_pass:
|
||||
|
||||
# Domain and their configuration. Used to sync LDAP with Zimbra
|
||||
zcs_domains: {}
|
||||
# zcs_domains:
|
||||
# fws.fr:
|
||||
# public_url: https://zm.fws.fr
|
||||
# admin_url: https://zm.fws.fr:9071
|
||||
# ldapsync:
|
||||
# ldap:
|
||||
# servers:
|
||||
# - ldap://dc1.fws.fr:389
|
||||
# schema: ad
|
||||
# bind_dn: CN=Zimbra,OU=Apps,DC=fws,DC=fr
|
||||
# bind_pass: s4cr3t.
|
||||
# users:
|
||||
# base: OU=People,DC=fws,DC=fr
|
||||
# filter: (mail=*)
|
||||
# groups:
|
||||
# base: OU=Groups,DC=fws,DC=fr
|
||||
# cas:
|
||||
# enabled: False
|
||||
# server_url: https://sso.fws.fr/cas
|
||||
|
||||
zcs_domain_defaults:
|
||||
cas:
|
||||
enabled: False
|
||||
|
||||
# Additional libs needed for CAS
|
||||
zcs_cas_libs:
|
||||
- url: https://repo1.maven.org/maven2/org/jasig/cas/client/cas-client-core/3.6.2/cas-client-core-3.6.2.jar
|
||||
sha1: ccb636b9b8d8c048b4dd14b0b0627350def5e3a2
|
||||
- url: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.32/slf4j-api-1.7.32.jar
|
||||
sha1: cdcff33940d9f2de763bc41ea05a0be5941176c3
|
||||
|
||||
# If defined, will add an always_bcc directive on MTA servers
|
||||
# zcs_always_bcc: maillog@example.org
|
217
roles/zimbra/files/zmpostfixpolicyd
Executable file
217
roles/zimbra/files/zmpostfixpolicyd
Executable file
@@ -0,0 +1,217 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Zimbra Collaboration Suite Server
|
||||
# Copyright (C) 2008, 2009, 2010, 2012, 2013, 2014, 2015, 2016 Synacor, Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software Foundation,
|
||||
# version 2 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the GNU General Public License for more details.
|
||||
# You should have received a copy of the GNU General Public License along with this program.
|
||||
# If not, see <https://www.gnu.org/licenses/>.
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
use strict;
|
||||
use lib '/opt/zimbra/common/lib/perl5';
|
||||
use Sys::Syslog qw(:DEFAULT setlogsock);
|
||||
use Net::LDAPapi;
|
||||
use XML::Simple;
|
||||
|
||||
#
|
||||
# Syslogging options for verbose mode and for fatal errors.
|
||||
# NOTE: comment out the $syslog_socktype line if syslogging does not
|
||||
# work on your system.
|
||||
#
|
||||
my $syslog_socktype = 'unix';
|
||||
my $syslog_facility="mail";
|
||||
my $syslog_options="pid";
|
||||
our $syslog_priority="info";
|
||||
our ($verbose, %attr, @ldap_url, $ldap_starttls_supported, $postfix_pw, $zimbra_pw, $delim_re);
|
||||
my ($option, $action, $ldap_url, @val);
|
||||
|
||||
$ENV{'HOME'}='/opt/zimbra';
|
||||
setlogsock $syslog_socktype;
|
||||
openlog $0, $syslog_options, $syslog_facility;
|
||||
|
||||
my $localxml = XMLin("/opt/zimbra/conf/localconfig.xml");
|
||||
|
||||
$ldap_starttls_supported = $localxml->{key}->{ldap_starttls_supported}->{value};
|
||||
chomp ($ldap_starttls_supported);
|
||||
$postfix_pw = $localxml->{key}->{ldap_postfix_password}->{value};
|
||||
chomp($postfix_pw);
|
||||
$zimbra_pw = $localxml->{key}->{zimbra_ldap_password}->{value};
|
||||
chomp($zimbra_pw);
|
||||
$ldap_url = $localxml->{key}->{ldap_url}->{value};
|
||||
chomp($ldap_url);
|
||||
@ldap_url = split / /, $ldap_url;
|
||||
|
||||
sub smtpd_access_policy {
|
||||
my($domain, $ldap, $mesg, $user, $canon_user, $daddr, @attrs, $result);
|
||||
$daddr = lc $attr{recipient};
|
||||
($user, $domain) = split /\@/, lc $attr{recipient};
|
||||
$canon_user = (defined $delim_re) ? (split /$delim_re/, $user)[0] : $user;
|
||||
syslog $syslog_priority, "Recipient Domain: %s", $domain if $verbose;
|
||||
syslog $syslog_priority, "Recipient userid: %s", $user if $verbose;
|
||||
foreach my $url (@ldap_url) {
|
||||
$ldap=Net::LDAPapi->new(-url=>$url);
|
||||
if ( $ldap_starttls_supported ) {
|
||||
$mesg = $ldap->start_tls_s();
|
||||
if ($mesg != 0) {
|
||||
next;
|
||||
}
|
||||
}
|
||||
$mesg = $ldap->bind_s("uid=zmpostfix,cn=appaccts,cn=zimbra",$postfix_pw);
|
||||
if ($mesg != 0) {
|
||||
next;
|
||||
} else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
if ($mesg != 0) {
|
||||
syslog $syslog_priority, "Error: zmpostfixpolicyd unable to find working LDAP server";
|
||||
return "dunno";
|
||||
}
|
||||
@attrs=('zimbraDomainType', 'zimbraMailCatchAllForwardingAddress');
|
||||
$mesg = $ldap->search_s(
|
||||
"",
|
||||
LDAP_SCOPE_SUBTREE,
|
||||
"(&(zimbraDomainName=$domain)(objectClass=zimbraDomain))",
|
||||
\@attrs,
|
||||
0,
|
||||
$result
|
||||
);
|
||||
my $ent = $ldap->first_entry();
|
||||
if ($ent != 0) {
|
||||
if (lc(($ldap->get_values("zimbraDomainType"))[0]) eq "alias") {
|
||||
my $robject = ($ldap->get_values("zimbraMailCatchAllForwardingAddress"))[0];
|
||||
syslog $syslog_priority, "Real Domain: %s", $robject if $verbose;
|
||||
@attrs=('1.1');
|
||||
$mesg = $ldap->search_s(
|
||||
"",
|
||||
LDAP_SCOPE_SUBTREE,
|
||||
"(&(|(zimbraMailDeliveryAddress=$user"."$robject)(zimbraMailDeliveryAddress=$canon_user"."$robject)".
|
||||
"(zimbraMailDeliveryAddress=$daddr)(zimbraMailAlias=$user"."$robject)(zimbraMailAlias=$canon_user"."$robject)".
|
||||
"(zimbraMailAlias=$daddr)(zimbraMailCatchAllAddress=$user"."$robject)(zimbraMailCatchAllAddress=$robject)".
|
||||
"(zimbraMailCatchAllAddress=$daddr))(zimbraMailStatus=enabled))",
|
||||
\@attrs,
|
||||
0,
|
||||
$result
|
||||
);
|
||||
$ent = $ldap->first_entry();
|
||||
$ldap->unbind;
|
||||
if ($ent != 0) {
|
||||
return "dunno";
|
||||
} else {
|
||||
return "reject 5.1.1 Mailbox unavailable";
|
||||
}
|
||||
} else {
|
||||
$ldap->unbind;
|
||||
return "dunno";
|
||||
}
|
||||
}
|
||||
$ldap->unbind;
|
||||
return "dunno";
|
||||
}
|
||||
|
||||
#
|
||||
# Log an error and abort.
|
||||
#
|
||||
sub fatal_exit {
|
||||
my($first) = shift(@_);
|
||||
syslog "err", "fatal: $first", @_;
|
||||
exit 1;
|
||||
}
|
||||
|
||||
#
|
||||
# We don't need getopt() for now.
|
||||
#
|
||||
while ($option = shift(@ARGV)) {
|
||||
if ($option eq "-v") {
|
||||
$verbose = 1;
|
||||
} else {
|
||||
syslog $syslog_priority, "Invalid option: %s. Usage: %s [-v]",
|
||||
$option, $0;
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Unbuffer standard output.
|
||||
#
|
||||
select((select(STDOUT), $| = 1)[0]);
|
||||
|
||||
# Try to get recipient delimiter, if defined
|
||||
# This will allow checking for valid recipient on alias domains
|
||||
# even for recipient using delimiter. Eg user+foobar@alias.example.org
|
||||
# will correctly check if user@example.org is valid
|
||||
my ($ldap, $mesg, @attrs, $result);
|
||||
foreach my $url (@ldap_url) {
|
||||
$ldap=Net::LDAPapi->new(-url=>$url);
|
||||
if ( $ldap_starttls_supported ) {
|
||||
$mesg = $ldap->start_tls_s();
|
||||
if ($mesg != 0) {
|
||||
next;
|
||||
}
|
||||
}
|
||||
$mesg = $ldap->bind_s("uid=zimbra,cn=admins,cn=zimbra",$zimbra_pw);
|
||||
if ($mesg != 0) {
|
||||
next;
|
||||
} else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
if ($mesg == 0){
|
||||
@attrs=('zimbraMtaRecipientDelimiter');
|
||||
$mesg = $ldap->search_s(
|
||||
"",
|
||||
LDAP_SCOPE_SUBTREE,
|
||||
"(&(cn=config)(objectClass=zimbraGlobalConfig))",
|
||||
\@attrs,
|
||||
0,
|
||||
$result
|
||||
);
|
||||
my $ent = $ldap->first_entry();
|
||||
if ($ent != 0){
|
||||
my $delim = ($ldap->get_values('zimbraMtaRecipientDelimiter'))[0];
|
||||
if ($delim ne ''){
|
||||
$delim_re = qr{[$delim]};
|
||||
syslog $syslog_priority, "Recipient delimiter regex is $delim_re" if $verbose;
|
||||
} else {
|
||||
syslog $syslog_priority, "Recipient delimiter is an empty string so it won't be used" if $verbose;
|
||||
}
|
||||
} else {
|
||||
syslog $syslog_priority, "Recipient delimiter not found" if $verbose;
|
||||
}
|
||||
# Unbind, everything else will bind with the postfix LDAP user
|
||||
$ldap->unbind;
|
||||
} else {
|
||||
syslog $syslog_priority, "Couldn't bind with zimbra account, recipient delimiter won't be used" if $verbose;
|
||||
}
|
||||
|
||||
#
|
||||
# Receive a bunch of attributes, evaluate the policy, send the result.
|
||||
#
|
||||
while (<STDIN>) {
|
||||
if (/([^=]+)=(.*)\n/) {
|
||||
$attr{substr($1, 0, 512)} = substr($2, 0, 512);
|
||||
} elsif ($_ eq "\n") {
|
||||
if ($verbose) {
|
||||
for (keys %attr) {
|
||||
syslog $syslog_priority, "Attribute: %s=%s", $_, $attr{$_};
|
||||
}
|
||||
}
|
||||
fatal_exit "unrecognized request type: '%s'", $attr{"request"}
|
||||
unless $attr{"request"} eq "smtpd_access_policy";
|
||||
$action = smtpd_access_policy();
|
||||
syslog $syslog_priority, "Action: %s", $action if $verbose;
|
||||
print STDOUT "action=$action\n\n";
|
||||
%attr = ();
|
||||
} else {
|
||||
chop;
|
||||
syslog $syslog_priority, "warning: ignoring garbage: %.100s", $_;
|
||||
}
|
||||
}
|
97
roles/zimbra/files/zmpostfixpolicyd_recipient_delim.patch
Normal file
97
roles/zimbra/files/zmpostfixpolicyd_recipient_delim.patch
Normal file
@@ -0,0 +1,97 @@
|
||||
--- /opt/zimbra/libexec/zmpostfixpolicyd.bak 2019-07-18 21:24:39.000000000 +0200
|
||||
+++ /opt/zimbra/libexec/zmpostfixpolicyd 2020-11-23 10:02:37.956775250 +0100
|
||||
@@ -30,7 +30,7 @@
|
||||
my $syslog_facility="mail";
|
||||
my $syslog_options="pid";
|
||||
our $syslog_priority="info";
|
||||
-our ($verbose, %attr, @ldap_url, $ldap_starttls_supported, $postfix_pw);
|
||||
+our ($verbose, %attr, @ldap_url, $ldap_starttls_supported, $postfix_pw, $zimbra_pw, $delim_re);
|
||||
my ($option, $action, $ldap_url, @val);
|
||||
|
||||
$ENV{'HOME'}='/opt/zimbra';
|
||||
@@ -43,14 +43,17 @@
|
||||
chomp ($ldap_starttls_supported);
|
||||
$postfix_pw = $localxml->{key}->{ldap_postfix_password}->{value};
|
||||
chomp($postfix_pw);
|
||||
+$zimbra_pw = $localxml->{key}->{zimbra_ldap_password}->{value};
|
||||
+chomp($zimbra_pw);
|
||||
$ldap_url = $localxml->{key}->{ldap_url}->{value};
|
||||
chomp($ldap_url);
|
||||
@ldap_url = split / /, $ldap_url;
|
||||
|
||||
sub smtpd_access_policy {
|
||||
- my($domain, $ldap, $mesg, $user, $daddr, @attrs, $result);
|
||||
+ my($domain, $ldap, $mesg, $user, $canon_user, $daddr, @attrs, $result);
|
||||
$daddr = lc $attr{recipient};
|
||||
($user, $domain) = split /\@/, lc $attr{recipient};
|
||||
+ $canon_user = (defined $delim_re) ? (split /$delim_re/, $user)[0] : $user;
|
||||
syslog $syslog_priority, "Recipient Domain: %s", $domain if $verbose;
|
||||
syslog $syslog_priority, "Recipient userid: %s", $user if $verbose;
|
||||
foreach my $url (@ldap_url) {
|
||||
@@ -90,8 +93,9 @@
|
||||
$mesg = $ldap->search_s(
|
||||
"",
|
||||
LDAP_SCOPE_SUBTREE,
|
||||
- "(&(|(zimbraMailDeliveryAddress=$user"."$robject)(zimbraMailDeliveryAddress=$daddr)(zimbraMailAlias=$user".
|
||||
- "$robject)(zimbraMailAlias=$daddr)(zimbraMailCatchAllAddress=$user"."$robject)(zimbraMailCatchAllAddress=$robject)".
|
||||
+ "(&(|(zimbraMailDeliveryAddress=$user"."$robject)(zimbraMailDeliveryAddress=$canon_user"."$robject)".
|
||||
+ "(zimbraMailDeliveryAddress=$daddr)(zimbraMailAlias=$user"."$robject)(zimbraMailAlias=$canon_user"."$robject)".
|
||||
+ "(zimbraMailAlias=$daddr)(zimbraMailCatchAllAddress=$user"."$robject)(zimbraMailCatchAllAddress=$robject)".
|
||||
"(zimbraMailCatchAllAddress=$daddr))(zimbraMailStatus=enabled))",
|
||||
\@attrs,
|
||||
0,
|
||||
@@ -140,6 +144,54 @@
|
||||
#
|
||||
select((select(STDOUT), $| = 1)[0]);
|
||||
|
||||
+# Try to get recipient delimiter, if defined
|
||||
+# This will allow checking for valid recipient on alias domains
|
||||
+# even for recipient using delimiter. Eg user+foobar@alias.example.org
|
||||
+# will correctly check if user@example.org is valid
|
||||
+my ($ldap, $mesg, @attrs, $result);
|
||||
+foreach my $url (@ldap_url) {
|
||||
+ $ldap=Net::LDAPapi->new(-url=>$url);
|
||||
+ if ( $ldap_starttls_supported ) {
|
||||
+ $mesg = $ldap->start_tls_s();
|
||||
+ if ($mesg != 0) {
|
||||
+ next;
|
||||
+ }
|
||||
+ }
|
||||
+ $mesg = $ldap->bind_s("uid=zimbra,cn=admins,cn=zimbra",$zimbra_pw);
|
||||
+ if ($mesg != 0) {
|
||||
+ next;
|
||||
+ } else {
|
||||
+ last;
|
||||
+ }
|
||||
+}
|
||||
+if ($mesg == 0){
|
||||
+ @attrs=('zimbraMtaRecipientDelimiter');
|
||||
+ $mesg = $ldap->search_s(
|
||||
+ "",
|
||||
+ LDAP_SCOPE_SUBTREE,
|
||||
+ "(&(cn=config)(objectClass=zimbraGlobalConfig))",
|
||||
+ \@attrs,
|
||||
+ 0,
|
||||
+ $result
|
||||
+ );
|
||||
+ my $ent = $ldap->first_entry();
|
||||
+ if ($ent != 0){
|
||||
+ my $delim = ($ldap->get_values('zimbraMtaRecipientDelimiter'))[0];
|
||||
+ if ($delim ne ''){
|
||||
+ $delim_re = qr{[$delim]};
|
||||
+ syslog $syslog_priority, "Recipient delimiter regex is $delim_re" if $verbose;
|
||||
+ } else {
|
||||
+ syslog $syslog_priority, "Recipient delimiter is an empty string so it won't be used" if $verbose;
|
||||
+ }
|
||||
+ } else {
|
||||
+ syslog $syslog_priority, "Recipient delimiter not found" if $verbose;
|
||||
+ }
|
||||
+ # Unbind, everything else will bind with the postfix LDAP user
|
||||
+ $ldap->unbind;
|
||||
+} else {
|
||||
+ syslog $syslog_priority, "Couldn't bind with zimbra account, recipient delimiter won't be used" if $verbose;
|
||||
+}
|
||||
+
|
||||
#
|
||||
# Receive a bunch of attributes, evaluate the policy, send the result.
|
||||
#
|
11
roles/zimbra/handlers/main.yml
Normal file
11
roles/zimbra/handlers/main.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
|
||||
- name: restart zimbra
|
||||
command: zmcontrol restart
|
||||
|
||||
- name: restart rsyslog
|
||||
service: name=rsyslog state=restarted
|
||||
|
||||
- name: restart zmmailboxd
|
||||
command: /opt/zimbra/bin/zmmailboxdctl restart
|
||||
become_user: zimbra
|
4
roles/zimbra/meta/main.yml
Normal file
4
roles/zimbra/meta/main.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
|
||||
dependencies:
|
||||
- role: mkdir
|
1
roles/zimbra/service.yml
Normal file
1
roles/zimbra/service.yml
Normal file
@@ -0,0 +1 @@
|
||||
---
|
1
roles/zimbra/stats.yml
Normal file
1
roles/zimbra/stats.yml
Normal file
@@ -0,0 +1 @@
|
||||
---
|
1
roles/zimbra/tasks/antispam.yml
Normal file
1
roles/zimbra/tasks/antispam.yml
Normal file
@@ -0,0 +1 @@
|
||||
---
|
1
roles/zimbra/tasks/apache.yml
Normal file
1
roles/zimbra/tasks/apache.yml
Normal file
@@ -0,0 +1 @@
|
||||
---
|
239
roles/zimbra/tasks/cas.yml
Normal file
239
roles/zimbra/tasks/cas.yml
Normal file
@@ -0,0 +1,239 @@
|
||||
---
|
||||
|
||||
- name: Install cas client lib
|
||||
get_url:
|
||||
url: "{{ item.url }}"
|
||||
checksum: sha1:{{ item.sha1 }}
|
||||
dest: /opt/zimbra/jetty/common/lib/
|
||||
loop: "{{ zcs_cas_libs }}"
|
||||
tags: zcs
|
||||
|
||||
- name: Get or generate a pre authentication key
|
||||
shell: |
|
||||
KEY=$(/opt/zimbra/bin/zmprov getDomain {{ item }} zimbrapreauthkey | perl -ne '/^(?:zimbraP|p)reAuthKey: (.*)/ && print $1')
|
||||
[ -z $KEY ] && KEY=$(/opt/zimbra/bin/zmprov generateDomainPreAuthKey {{ item }} | perl -ne '/^(?:zimbraP|p)reAuthKey: (.*)/ && print $1')
|
||||
echo $KEY
|
||||
become_user: zimbra
|
||||
register: zcs_preauthkeys
|
||||
changed_when: False
|
||||
loop: "{{ zcs_domains.keys() | list }}"
|
||||
tags: zcs
|
||||
|
||||
- name: Install preauth pages
|
||||
template: src=cas_preauth.jsp.j2 dest=/opt/zimbra/jetty/webapps/zimbra/public/preauth_{{ item.item }}.jsp owner=zimbra group=zimbra
|
||||
loop: "{{ zcs_preauthkeys.results }}"
|
||||
notify: restart zimbra
|
||||
tags: zcs
|
||||
|
||||
- name: Install admin preauth pages
|
||||
template: src=cas_preauth_admin.jsp.j2 dest=/opt/zimbra/jetty/webapps/zimbraAdmin/public/preauth_{{ item.item }}.jsp owner=zimbra group=zimbra
|
||||
loop: "{{ zcs_preauthkeys.results }}"
|
||||
notify: restart zimbra
|
||||
tags: zcs
|
||||
|
||||
- name: Configure CAS filters
|
||||
blockinfile:
|
||||
path: /opt/zimbra/jetty/etc/zimbra.web.xml.in
|
||||
block: |2
|
||||
|
||||
{% for domain in zcs_domains.keys() | list %}
|
||||
{% if zcs_domains[domain].cas is defined and zcs_domains[domain].cas.enabled is defined and zcs_domains[domain].cas.enabled %}
|
||||
<!-- CAS filters for domain {{ domain }} -->
|
||||
<filter>
|
||||
<filter-name>CasSingleSignOutFilter{{ domain }}</filter-name>
|
||||
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>casServerUrlPrefix</param-name>
|
||||
<param-value>{{ zcs_domains[domain].cas.server_url }}</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>CasSingleSignOutFilter{{ domain }}</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<filter>
|
||||
<filter-name>CasAuthenticationFilter{{ domain }}</filter-name>
|
||||
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>casServerLoginUrl</param-name>
|
||||
<param-value>{{ zcs_domains[domain].cas.server_url }}/login</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>serverName</param-name>
|
||||
<param-value>{{ zcs_domains[domain].public_url }}</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>CasAuthenticationFilter{{ domain }}</filter-name>
|
||||
<url-pattern>/public/preauth_{{ domain }}.jsp</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<filter>
|
||||
<filter-name>CasValidationFilter{{ domain }}</filter-name>
|
||||
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>casServerUrlPrefix</param-name>
|
||||
<param-value>{{ zcs_domains[domain].cas.server_url }}</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>serverName</param-name>
|
||||
<param-value>{{ zcs_domains[domain].public_url }}</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>redirectAfterValidation</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>CasValidationFilter{{ domain }}</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
<!-- End CAS filter config for domain {{ domain }} -->
|
||||
|
||||
{% else %}
|
||||
|
||||
<!-- CAS not enabled for domain {{ domain }} -->
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<filter>
|
||||
<filter-name>CasHttpServletRequestWrapperFilter</filter-name>
|
||||
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>CasHttpServletRequestWrapperFilter</filter-name>
|
||||
<url-pattern>/public/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<!-- prevent Zimbra from adding ;jsessionid=XXXX in the URL, which the CAS server could reject
|
||||
as it doesn't match the initial service anymore -->
|
||||
<session-config>
|
||||
<tracking-mode>COOKIE</tracking-mode>
|
||||
</session-config>
|
||||
marker: '<!-- "# {mark} ANSIBLE MANAGED BLOCK" -->'
|
||||
insertafter: '</error-page>'
|
||||
validate: xmllint %s
|
||||
notify: restart zimbra
|
||||
tags: zcs
|
||||
|
||||
- name: Configure CAS admin filters
|
||||
blockinfile:
|
||||
path: /opt/zimbra/jetty/etc/zimbraAdmin.web.xml.in
|
||||
block: |2
|
||||
|
||||
{% for domain in zcs_domains.keys() | list %}
|
||||
{% if zcs_domains[domain].cas is defined and zcs_domains[domain].cas.enabled is defined and zcs_domains[domain].cas.enabled %}
|
||||
<!-- CAS filters for domain {{ domain }} -->
|
||||
<filter>
|
||||
<filter-name>CasSingleSignOutFilter{{ domain }}</filter-name>
|
||||
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>casServerUrlPrefix</param-name>
|
||||
<param-value>{{ zcs_domains[domain].cas.server_url }}</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>CasSingleSignOutFilter{{ domain }}</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<filter>
|
||||
<filter-name>CasAuthenticationFilter{{ domain }}</filter-name>
|
||||
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>casServerLoginUrl</param-name>
|
||||
<param-value>{{ zcs_domains[domain].cas.server_url }}/login</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>serverName</param-name>
|
||||
<param-value>{{ zcs_domains[domain].admin_url }}</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>CasAuthenticationFilter{{ domain }}</filter-name>
|
||||
<url-pattern>/public/preauth_{{ domain }}.jsp</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<filter>
|
||||
<filter-name>CasValidationFilter{{ domain }}</filter-name>
|
||||
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>casServerUrlPrefix</param-name>
|
||||
<param-value>{{ zcs_domains[domain].cas.server_url }}</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>serverName</param-name>
|
||||
<param-value>{{ zcs_domains[domain].admin_url }}</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>redirectAfterValidation</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>CasValidationFilter{{ domain }}</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<!-- End of CAS filters settings for domaine {{ domain }} -->
|
||||
|
||||
{% else %}
|
||||
|
||||
<!-- CAS not enabled for domain {{ domain }} -->
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<filter>
|
||||
<filter-name>CasHttpServletRequestWrapperFilter</filter-name>
|
||||
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>CasHttpServletRequestWrapperFilter</filter-name>
|
||||
<url-pattern>/public/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<!-- prevent Zimbra from adding ;jsessionid=XXXX in the URL, which the CAS server could reject
|
||||
as it doesn't match the initial service anymore -->
|
||||
<session-config>
|
||||
<tracking-mode>COOKIE</tracking-mode>
|
||||
</session-config>
|
||||
marker: '<!-- "# {mark} ANSIBLE MANAGED BLOCK" -->'
|
||||
insertafter: '</error-page>'
|
||||
validate: xmllint %s
|
||||
notify: restart zimbra
|
||||
tags: zcs
|
||||
|
||||
- name: Configure login and logout URL
|
||||
shell: |
|
||||
/opt/zimbra/bin/zmprov modifyDomain {{ item }} zimbraWebClientLoginURL "{{ zcs_domains[item].public_url | regex_replace('/$','') }}/public/preauth_{{ item }}.jsp"
|
||||
/opt/zimbra/bin/zmprov modifyDomain {{ item }} zimbraAdminConsoleLoginURL "{{ zcs_domains[item].admin_url | regex_replace('/$','') }}/zimbraAdmin/public/preauth_{{ item }}.jsp"
|
||||
/opt/zimbra/bin/zmprov modifyDomain {{ item }} zimbraWebClientLogoutURL "{{ zcs_domains[item].cas.server_url | regex_replace('/$','') }}/logout"
|
||||
/opt/zimbra/bin/zmprov modifyDomain {{ item }} zimbraAdminConsoleLogoutURL "{{ zcs_domains[item].cas.server_url | regex_replace('/$','') }}/logout"
|
||||
become_user: zimbra
|
||||
loop: "{{ zcs_domains.keys() | list }}"
|
||||
when:
|
||||
- zcs_domains[item].cas is defined
|
||||
- zcs_domains[item].cas.enabled is defined
|
||||
- zcs_domains[item].cas.enabled == True
|
||||
changed_when: False
|
||||
tags: zcs
|
||||
|
5
roles/zimbra/tasks/filebeat.yml
Normal file
5
roles/zimbra/tasks/filebeat.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
|
||||
- name: Deploy filebeat configuration
|
||||
template: src=filebeat.yml.j2 dest=/etc/filebeat/ansible_inputs.d/zimbra.yml
|
||||
tags: zcs,log
|
36
roles/zimbra/tasks/install.yml
Normal file
36
roles/zimbra/tasks/install.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
|
||||
- name: Create temp dir
|
||||
file: path=/tmp/zimbra state=directory
|
||||
tags: zcs
|
||||
|
||||
- name: Download Zimbra
|
||||
get_url:
|
||||
url: "{{ zcs_archive_url }}"
|
||||
dest: /tmp/zimbra
|
||||
checksum: "sha1:{{ zcs_archive_sha1 }}"
|
||||
tags: zcs
|
||||
|
||||
- name: Extract Zimbra archive
|
||||
unarchive:
|
||||
src: /tmp/zimbra/{{ zcs_archive_name }}
|
||||
dest: /tmp/zimbra
|
||||
remote_src: True
|
||||
tags: zcs
|
||||
|
||||
- name: Upload installation scripts
|
||||
template: src={{ item }}.j2 dest=/tmp/zimbra/{{ item }}
|
||||
loop:
|
||||
- zcs_install_answers
|
||||
- zcs_init_config
|
||||
tags: zcs
|
||||
|
||||
- name: Install Zimbra
|
||||
shell: ./install.sh -s < /tmp/zimbra/zcs_install_answers
|
||||
args:
|
||||
chdir: /tmp/zimbra/{{ zcs_archive_name | splitext | first }}
|
||||
tags: zcs
|
||||
|
||||
- name: Provision initial configuration
|
||||
shell: /opt/zimbra/libexec/zmsetup.pl -c /tmp/zimbra/zcs_init_config
|
||||
tags: zcs
|
9
roles/zimbra/tasks/ldap.yml
Normal file
9
roles/zimbra/tasks/ldap.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
|
||||
- name: Handle Zimbra LDAP ports
|
||||
iptables_raw:
|
||||
name: zcs_ldap_ports
|
||||
state: "{{ (zcs_cluster_ip | length > 0 ) | ternary('present','absent') }}"
|
||||
rules: "-A INPUT -m state --state NEW -p tcp -m multiport --dports 389,636 -s {{ (zcs_cluster_ip + zcs_ldap_src_ip) | join(',') }} -j ACCEPT"
|
||||
when: iptables_manage | default(True)
|
||||
tags: zcs
|
10
roles/zimbra/tasks/logger.yml
Normal file
10
roles/zimbra/tasks/logger.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
|
||||
- name: Handle Zimbra logger ports
|
||||
iptables_raw:
|
||||
name: zcs_logger_ports
|
||||
state: "{{ (zcs_cluster_ip | length > 0 ) | ternary('present','absent') }}"
|
||||
rules: "-A INPUT -m state --state NEW -p udp --dport 514 -s {{ zcs_cluster_ip | join(',') }} -j ACCEPT"
|
||||
when: iptables_manage | default(True)
|
||||
tags: zcs
|
||||
|
158
roles/zimbra/tasks/mailbox.yml
Normal file
158
roles/zimbra/tasks/mailbox.yml
Normal file
@@ -0,0 +1,158 @@
|
||||
---
|
||||
|
||||
- name: Install needed tools
|
||||
yum:
|
||||
name:
|
||||
- git
|
||||
tags: zcs
|
||||
|
||||
- name: Configure MySQL bind IP
|
||||
ini_file:
|
||||
section: mysqld
|
||||
option: bind-address
|
||||
value: 0.0.0.0
|
||||
path: /opt/zimbra/conf/my.cnf
|
||||
mode: 0640
|
||||
owner: zimbra
|
||||
group: zimbra
|
||||
notify: restart zimbra
|
||||
tags: zcs
|
||||
|
||||
- name: Get MySQL root password
|
||||
shell: /opt/zimbra/bin/zmlocalconfig -s mysql_root_password | awk '{ print $3 }'
|
||||
become_user: zimbra
|
||||
register: zcs_mysql_root_password
|
||||
changed_when: False
|
||||
tags: zcs
|
||||
|
||||
- name: Create sqladmin user account
|
||||
mysql_user:
|
||||
name: sqladmin
|
||||
password: '{{ mysql_admin_pass }}'
|
||||
host: '%'
|
||||
priv: '*.*:ALL,GRANT'
|
||||
state: present
|
||||
login_user: root
|
||||
login_password: "{{ zcs_mysql_root_password.stdout }}"
|
||||
login_unix_socket: /opt/zimbra/data/tmp/mysql/mysql.sock
|
||||
when: mysql_admin_pass is defined
|
||||
tags: zcs
|
||||
|
||||
- name: Handle Zimbra store ports
|
||||
iptables_raw:
|
||||
name: zcs_store_ports
|
||||
state: "{{ (zcs_cluster_ip | length > 0) | ternary('present','absent') }}"
|
||||
rules: "-A INPUT -m state --state NEW -p tcp -m multiport --dports 143,993,7143,7993 -s {{ zcs_cluster_ip | join(',') }} -j ACCEPT\n
|
||||
-A INPUT -m state --state NEW -p tcp -m multiport --dports 110,995,7110,7995 -s {{ zcs_cluster_ip | join(',') }} -j ACCEPT\n
|
||||
-A INPUT -m state --state NEW -p tcp -m multiport --dports 8080,8443,7071,7072,7073 -s {{ zcs_cluster_ip | join(',') }} -j ACCEPT\n
|
||||
-A INPUT -m state --state NEW -p tcp -m multiport --dports 7025,7026 -s {{ zcs_cluster_ip | join(',') }} -j ACCEPT\n
|
||||
-A INPUT -m state --state NEW -p tcp -m multiport --dports 8735,8736 -s {{ zcs_cluster_ip | join(',') }} -j ACCEPT"
|
||||
when: iptables_manage | default(True)
|
||||
tags: zcs
|
||||
|
||||
- name: Handle Zimbra MySQL ports
|
||||
iptables_raw:
|
||||
name: zcs_mysql_ports
|
||||
state: "{{ (zcs_mysql_src_ip | length > 0) | ternary('present','absent') }}"
|
||||
rules: "-A INPUT -m state --state NEW -p tcp --dport 7306 -s {{ zcs_mysql_src_ip | join(',') }} -j ACCEPT"
|
||||
when: iptables_manage | default(True)
|
||||
tags: zcs
|
||||
|
||||
#- name: Create ShareToolki cache dir
|
||||
# file: path=/opt/zimbra/addon_cache/sharetoolkit state=directory
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Clone ShareToolkit repo
|
||||
# git:
|
||||
# repo: https://github.com/Zimbra-Community/shared-mailbox-toolkit.git
|
||||
# dest: /opt/zimbra/addon_cache/sharetoolkit
|
||||
# force: True
|
||||
# register: zcs_sharetoolkit_repo
|
||||
# notify: restart zmmailboxd
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Remove previous ShareToolkit client zimlet
|
||||
# file: path=/opt/zimbra/zimlets-deployed/_dev/tk_barrydegraaff_sharetoolkit_client state=absent
|
||||
# when: zcs_sharetoolkit_repo.changed
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Create ShareToolkit client Zimlet directory
|
||||
# file: path=/opt/zimbra/zimlets-deployed/_dev/ state=directory
|
||||
# when: zcs_sharetoolkit_repo.changed
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Deploy ShareToolkit client zimlet
|
||||
# copy: src=/opt/zimbra/addon_cache/sharetoolkit/tk_barrydegraaff_sharetoolkit_client dest=/opt/zimbra/zimlets-deployed/_dev/ remote_src=True
|
||||
# when: zcs_sharetoolkit_repo.changed
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Undeploy previous ShareToolkit Zimlet
|
||||
# command: /opt/zimbra/bin/zmzimletctl undeploy tk_barrydegraaff_sharetoolkit_admin
|
||||
# become_user: zimbra
|
||||
# when: zcs_sharetoolkit_repo.changed
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Create a ZIP archive for ShareToolkit admin zimlet
|
||||
# archive:
|
||||
# path: /opt/zimbra/addon_cache/sharetoolkit/tk_barrydegraaff_sharetoolkit_admin/*
|
||||
# dest: /tmp/tk_barrydegraaff_sharetoolkit_admin.zip
|
||||
# format: zip
|
||||
# when: zcs_sharetoolkit_repo.changed
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Deploy new ShareToolkit admin zimlet
|
||||
# command: /opt/zimbra/bin/zmzimletctl deploy /tmp/tk_barrydegraaff_sharetoolkit_admin.zip
|
||||
# become_user: zimbra
|
||||
# when: zcs_sharetoolkit_repo.changed
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Remove previous Java server extension
|
||||
# file: path=/opt/zimbra/lib/ext/ShareToolkit state=absent
|
||||
# when: zcs_sharetoolkit_repo.changed
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Create ShareToolkit Java server extension dir
|
||||
# file: path=/opt/zimbra/lib/ext/ShareToolkit state=directory
|
||||
# when: zcs_sharetoolkit_repo.changed
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Deploy new Java server extension
|
||||
# copy: src=/opt/zimbra/addon_cache/sharetoolkit/extension/ShareToolkit/out/artifacts/ShareToolkit/ShareToolkit.jar dest=/opt/zimbra/lib/ext/ShareToolkit/ remote_src=True
|
||||
# when: zcs_sharetoolkit_repo.changed
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Enable the X-Authenticated-User header
|
||||
# command: /opt/zimbra/bin/zmprov modifyConfig {{ inner_item.attr }} {{ inner_item.value }}
|
||||
# become_user: zimbra
|
||||
# loop:
|
||||
# - attr: zimbraSmtpSendAddAuthenticatedUser
|
||||
# value: 'TRUE'
|
||||
# - attr: zimbraMtaSmtpdSaslAuthenticatedHeader
|
||||
# value: 'yes'
|
||||
# loop_control:
|
||||
# loop_var: inner_item
|
||||
# when: zcs_sharetoolkit_repo.changed
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Deploy ShareToolkit CLI tools
|
||||
# synchronize:
|
||||
# src: /opt/zimbra/addon_cache/sharetoolkit/bin/
|
||||
# dest: /usr/local/sbin/
|
||||
# rsync_opts:
|
||||
# - "--chmod=F755"
|
||||
# delegate_to: "{{ inventory_hostname }}"
|
||||
# when: zcs_sharetoolkit_repo.changed
|
||||
# tags: zcs
|
||||
#
|
||||
#- name: Flush Zimbra cache
|
||||
# command: /opt/zimbra/bin/zmprov flushCache all
|
||||
# become_user: zimbra
|
||||
# when: zcs_sharetoolkit_repo.changed
|
||||
# tags: zcs
|
||||
|
||||
- name: Remove ADPassword listener (not working with JDK 13)
|
||||
file: path=/opt/zimbra/lib/ext/adpassword state=absent
|
||||
tags: zcs
|
||||
|
||||
- include_tasks: cas.yml
|
||||
tags: zcs
|
211
roles/zimbra/tasks/main.yml
Normal file
211
roles/zimbra/tasks/main.yml
Normal file
@@ -0,0 +1,211 @@
|
||||
---
|
||||
|
||||
#- name: Build config for domains
|
||||
# set_fact: zcs_domains_conf={{ zcs_domains_conf | default([]) + [zcs_domain_defaults | combine(zcs_domains[item])] }}
|
||||
# with_items: "{{ zcs_domains.keys() | list }}"
|
||||
# tags: zcs
|
||||
#- set_fact: zcs_domains={{ zcs_domains_conf | default([]) }}
|
||||
# tags: zcs
|
||||
|
||||
- include_vars: "{{ item }}"
|
||||
with_first_found:
|
||||
- vars/{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml
|
||||
- vars/{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml
|
||||
- vars/{{ ansible_distribution }}.yml
|
||||
- vars/{{ ansible_os_family }}.yml
|
||||
tags: zcs
|
||||
|
||||
- name: Install dependencies
|
||||
package: name={{ zcs_packages }}
|
||||
tags: zcs
|
||||
|
||||
- name: Check if zimbra is installed
|
||||
stat: path=/opt/zimbra/bin/zmprov
|
||||
register: zcs_zmprov
|
||||
tags: zcs
|
||||
|
||||
#- name: Stop postfix
|
||||
# service: name=postfix state=stopped enabled=False
|
||||
# tags: zcs
|
||||
|
||||
- include_tasks: install.yml
|
||||
when:
|
||||
- zcs_install == True
|
||||
- not zcs_zmprov.stat.exists
|
||||
tags: zcs
|
||||
|
||||
- name: Exit if not installed
|
||||
meta: end_host
|
||||
when: zcs_install != True and (zcs_zmprov is not defined or zcs_zmprov.stat is not defined or not zcs_zmprov.stat.exists)
|
||||
tags: zcs
|
||||
|
||||
- set_fact: zcs_i_am_primary_ldap={{ (inventory_hostname == zcs_primary_ldap) | ternary(True,False) }}
|
||||
tags: zcs
|
||||
|
||||
- name: Fetch the LDAP admin pass
|
||||
shell: /opt/zimbra/bin/zmlocalconfig -s zimbra_ldap_password | awk '{ print $3}'
|
||||
changed_when: False
|
||||
register: zcs_ldap_admin_pass
|
||||
when: zcs_ldap_admin_pass is not defined
|
||||
tags: zcs
|
||||
- set_fact: zcs_ldap_admin_pass={{ zcs_ldap_admin_pass.stdout }}
|
||||
when: zcs_ldap_admin_pass.stdout is defined
|
||||
tags: zcs
|
||||
|
||||
- name: Install wrapper scripts
|
||||
template: src=zimbra_wrapper.j2 dest=/usr/local/bin/{{ item }} mode=0755
|
||||
loop:
|
||||
- zmprov
|
||||
- zmcontrol
|
||||
- zmhostname
|
||||
- zmmailbox
|
||||
- zmlocalconfig
|
||||
tags: zcs
|
||||
|
||||
#- name: Check installed components
|
||||
# command: rpm -q zimbra-{{ item }}
|
||||
# args:
|
||||
# warn: False
|
||||
# register: zcs_components
|
||||
# failed_when: False
|
||||
# changed_when: False
|
||||
# loop:
|
||||
# - ldap
|
||||
# - logger
|
||||
# - mta
|
||||
# - dnscache
|
||||
# - snmp
|
||||
# - store
|
||||
# - apache
|
||||
# - spell
|
||||
# - memcached
|
||||
# - proxy
|
||||
# - drive
|
||||
# tags: zcs
|
||||
|
||||
- name: List enabled components
|
||||
shell: '/opt/zimbra/bin/zmprov getServer {{ inventory_hostname }} zimbraServiceEnabled | perl -ne ''m/^zimbraServiceEnabled: (\w+)/ && print "$1\n"'''
|
||||
become_user: zimbra
|
||||
register: zcs_enabled_components
|
||||
changed_when: False
|
||||
tags: zcs
|
||||
- set_fact: zcs_enabled_components={{ zcs_enabled_components.stdout_lines }}
|
||||
tags: zcs
|
||||
|
||||
- include_tasks: "{{ component }}.yml"
|
||||
loop: "{{ zcs_enabled_components }}"
|
||||
loop_control:
|
||||
loop_var: component
|
||||
tags: zcs
|
||||
|
||||
- name: Handle general ports
|
||||
iptables_raw:
|
||||
name: zcs_general_ports
|
||||
state: "{{ (zcs_cluster_ip | length > 0) | ternary('present','absent') }}"
|
||||
rules: "-A INPUT -m state --state NEW -p tcp -m multiport --dports 22 -s {{ zcs_cluster_ip | join(',') }} -j ACCEPT"
|
||||
when: iptables_manage | default(True)
|
||||
tags: zcs
|
||||
|
||||
- include_tasks: zmldapsync.yml
|
||||
when: zcs_i_am_primary_ldap == True
|
||||
tags: zcs
|
||||
|
||||
- name: Install backup help script
|
||||
get_url:
|
||||
url: https://git.fws.fr/dani/zimbra/raw/branch/master/zmbh/zmbh.pl
|
||||
dest: /opt/zimbra/bin/zmbh
|
||||
mode: '0755'
|
||||
tags: zcs
|
||||
|
||||
- name: Remove old backup helper script
|
||||
file: path=/usr/local/bin/zmbh.pl state=absent
|
||||
tags: zcs
|
||||
|
||||
- name: Create directories
|
||||
file: path={{ item.dir }} state=directory owner={{ item.owner | default(omit) }} group={{ item.group | default(omit) }} mode={{ item.mode | default(omit) }}
|
||||
loop:
|
||||
- dir: /opt/zimbra/addon_cache
|
||||
- dir: /opt/zimbra/meta
|
||||
mode: '0700'
|
||||
tags: zcs
|
||||
|
||||
#- include_tasks: backup.yml
|
||||
# when: zcs_i_am_primary_ldap == True
|
||||
# tags: zcs
|
||||
|
||||
- name: Identify logger host
|
||||
shell: /opt/zimbra/bin/zmprov gcf zimbraLogHostname | awk '{ print $2 }'
|
||||
become_user: zimbra
|
||||
register: zcs_log_hostname
|
||||
changed_when: False
|
||||
tags: zcs
|
||||
- set_fact: zcs_log_hostname={{ zcs_log_hostname.stdout }}
|
||||
tags: zcs
|
||||
|
||||
- name: Deploy syslog config
|
||||
template: src=rsyslog.conf.j2 dest=/etc/rsyslog.conf
|
||||
notify: restart rsyslog
|
||||
tags: zcs
|
||||
|
||||
- name: Fix logrotate config to reload rsyslog
|
||||
replace:
|
||||
path: /etc/logrotate.d/zimbra
|
||||
regexp: '^(.*)/var/run/syslog\*\.pid(.*)'
|
||||
replace: '\1/run/rsyslogd.pid\2'
|
||||
tags: zcs
|
||||
|
||||
- name: Set correct SELinux context
|
||||
block:
|
||||
- sefcontext:
|
||||
target: "/opt/zimbra/log(/.*)?"
|
||||
setype: var_log_t
|
||||
- sefcontext:
|
||||
target: "/etc/rc.d/init.d/zimbra"
|
||||
setype: bin_t
|
||||
- command: restorecon -R /opt/zimbra/log /etc/rc.d/init.d/zimbra
|
||||
changed_when: False
|
||||
when: ansible_selinux.status == 'enabled'
|
||||
tags: zcs
|
||||
|
||||
- name: Deploy Let's Encrypt hook
|
||||
template: src=dehydrated_hook.sh.j2 dest=/etc/dehydrated/hooks_deploy_cert.d/20zimbra.sh mode=755
|
||||
when: zcs_letsencrypt == True
|
||||
tags: zcs
|
||||
|
||||
- name: Remove Let's Encrypt hook
|
||||
file: path=/etc/dehydrated/hooks_deploy_cert.d/20zimbra.sh state=absent
|
||||
when: zcs_letsencrypt != True
|
||||
tags: zcs
|
||||
|
||||
- name: Create pre and post backup hook dir
|
||||
file: path=/etc/backup/{{ item }}.d state=directory
|
||||
loop:
|
||||
- pre
|
||||
- post
|
||||
tags: zcs
|
||||
|
||||
# The cert bundle provided by Zimbra is not very up to date
|
||||
# so link the system wide one here
|
||||
- name: Push system trusted CA store to Zimbra
|
||||
file: src=/etc/pki/tls/cert.pem dest=/opt/zimbra/common/etc/ssl/cert.pem state=link
|
||||
tags: zcs
|
||||
|
||||
- name: Deploy pre and post backup scripts
|
||||
template: src={{ item }}_backup.sh.j2 dest=/etc/backup/{{ item }}.d/zimbra.sh mode=0750
|
||||
loop:
|
||||
- pre
|
||||
- post
|
||||
tags: zcs
|
||||
|
||||
- name: Create backup mount point
|
||||
file: path=/home/lbkp/zimbra state=directory
|
||||
tags: zcs
|
||||
|
||||
- name: Remove temp files
|
||||
file: path={{ item }} state=absent
|
||||
loop:
|
||||
- /tmp/zimbra
|
||||
- /tmp/tk_barrydegraaff_sharetoolkit_admin.zip
|
||||
tags: zcs
|
||||
|
||||
- include: filebeat.yml
|
10
roles/zimbra/tasks/memcached.yml
Normal file
10
roles/zimbra/tasks/memcached.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
|
||||
- name: Handle Zimbra memcached ports
|
||||
iptables_raw:
|
||||
name: zcs_memcached_ports
|
||||
state: "{{ (zcs_cluster_ip | length > 0 ) | ternary('present','absent') }}"
|
||||
rules: "-A INPUT -m state --state NEW -p tcp -m multiport --dports 11211 -s {{ zcs_cluster_ip | join(',') }} -j ACCEPT\n
|
||||
-A INPUT -m state --state NEW -p udp -m multiport --dports 11211 -s {{ zcs_cluster_ip | join(',') }} -j ACCEPT"
|
||||
when: iptables_manage | default(True)
|
||||
tags: zcs
|
36
roles/zimbra/tasks/mta.yml
Normal file
36
roles/zimbra/tasks/mta.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
|
||||
- name: Configure Zimbra's sendmail as alternative to sendmail
|
||||
alternatives:
|
||||
name: mta
|
||||
link: /usr/sbin/sendmail
|
||||
path: /opt/zimbra/common/sbin/sendmail
|
||||
priority: 90
|
||||
tags: zcs
|
||||
|
||||
- name: Set zimbra's sendmail as the default sendmail
|
||||
command: update-alternatives --set mta /opt/zimbra/common/sbin/sendmail
|
||||
changed_when: False
|
||||
tags: zcs
|
||||
|
||||
- name: Override zmpostfixpolicyd to support recipient delimiter
|
||||
copy: src=zmpostfixpolicyd dest=/opt/zimbra/libexec/zmpostfixpolicyd
|
||||
notify: restart zimbra
|
||||
tags: zcs
|
||||
|
||||
- name: Handle Zimbra mta ports
|
||||
iptables_raw:
|
||||
name: zcs_mta_ports
|
||||
state: present
|
||||
rules: "-A INPUT -m state --state NEW -p tcp -m multiport --dports 25,465,587 -j ACCEPT"
|
||||
when: iptables_manage | default(True)
|
||||
tags: zcs
|
||||
|
||||
- name: Enable always_bcc
|
||||
lineinfile:
|
||||
dest: /opt/zimbra/common/conf/main.cf
|
||||
regexp: '^always_bcc =.*'
|
||||
line: always_bcc = {{ zcs_always_bcc }}
|
||||
when: zcs_always_bcc is defined
|
||||
notify: restart zimbra
|
||||
tags: zcs
|
1
roles/zimbra/tasks/opendkim.yml
Normal file
1
roles/zimbra/tasks/opendkim.yml
Normal file
@@ -0,0 +1 @@
|
||||
---
|
32
roles/zimbra/tasks/proxy.yml
Normal file
32
roles/zimbra/tasks/proxy.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
|
||||
- name: Handle Zimbra proxy ports
|
||||
iptables_raw:
|
||||
name: zcs_proxy_ports
|
||||
state: present
|
||||
rules: "{% if zcs_http_src_ip | length > 0 %}-A INPUT -m state --state NEW -p tcp -m multiport --dports 80,443 -s {{ zcs_http_src_ip | join(',') }} -j ACCEPT\n{% endif %}
|
||||
{% if zcs_clients_src_ip | length > 0 %}-A INPUT -m state --state NEW -p tcp -m multiport --dports 110,995,143,993 -s {{ zcs_clients_src_ip | join(',') }} -j ACCEPT\n{% endif %}
|
||||
{% if zcs_admin_src_ip | length > 0 %}-A INPUT -m state --state NEW -p tcp -m multiport --dports 9071 -s {{ zcs_admin_src_ip | join(',') }} -j ACCEPT{% endif %}"
|
||||
when: iptables_manage | default(True)
|
||||
tags: zcs
|
||||
|
||||
- name: Enable proxy for the admin interface
|
||||
command: /opt/zimbra/bin/zmprov ms {{ inventory_hostname }} zimbraReverseProxyAdminEnabled TRUE
|
||||
changed_when: False
|
||||
become_user: zimbra
|
||||
tags: zcs
|
||||
|
||||
- name: Build a list of vhosts to be used for Let's Encrypt cert
|
||||
shell: |
|
||||
for DOMAIN in $(/opt/zimbra/bin/zmprov getAllDomains); do
|
||||
/opt/zimbra/bin/zmprov getDomain $DOMAIN zimbraVirtualHostname | perl -ne 'm/^zimbraVirtualHostname: (.*)/ && print "$1\n"'
|
||||
done
|
||||
become_user: zimbra
|
||||
register: zcs_vhosts
|
||||
changed_when: False
|
||||
when: zcs_letsencrypt == True
|
||||
tags: zcs
|
||||
- set_fact: zcs_vhosts={{ zcs_vhosts.stdout_lines }}
|
||||
when: zcs_vhosts.stdout_lines is defined
|
||||
tags: zcs
|
||||
|
1
roles/zimbra/tasks/snmp.yml
Normal file
1
roles/zimbra/tasks/snmp.yml
Normal file
@@ -0,0 +1 @@
|
||||
---
|
9
roles/zimbra/tasks/spell.yml
Normal file
9
roles/zimbra/tasks/spell.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
|
||||
- name: Handle Zimbra spell ports
|
||||
iptables_raw:
|
||||
name: zcs_spell_ports
|
||||
state: "{{ (zcs_cluster_ip | length > 0) | ternary('present','absent') }}"
|
||||
rules: "-A INPUT -m state --state NEW -p tcp --dport 7780 -s {{ zcs_http_src_ip | join(',') }} -j ACCEPT"
|
||||
when: iptables_manage | default(True)
|
||||
tags: zcs
|
56
roles/zimbra/tasks/zmldapsync.yml
Normal file
56
roles/zimbra/tasks/zmldapsync.yml
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
|
||||
- name: Install zmldapsync dependencies
|
||||
yum:
|
||||
name:
|
||||
- perl-LDAP
|
||||
- perl-YAML-Tiny
|
||||
- perl-Data-UUID
|
||||
- perl-String-ShellQuote
|
||||
- perl-Array-Diff
|
||||
- perl-List-MoreUtils
|
||||
- perl-Hash-Merge-Simple
|
||||
- perl-Text-Unidecode
|
||||
- perl-Email-MIME
|
||||
- perl-Email-Sender
|
||||
tags: zcs
|
||||
|
||||
- name: Install zmldapsync
|
||||
get_url:
|
||||
url: "{{ item.url }}"
|
||||
dest: "{{ item.dest }}"
|
||||
mode: "{{ item.mode }}"
|
||||
loop:
|
||||
- url: https://git.fws.fr/dani/zimbra/raw/branch/master/zmldapsync/zmldapsync.pl
|
||||
dest: /opt/zimbra/bin/zmldapsync
|
||||
mode: 755
|
||||
- url: https://git.fws.fr/dani/zimbra/raw/branch/master/zmldapsync/zmldapsync.yml
|
||||
dest: /opt/zimbra/conf/zmldapsync.yml.dist
|
||||
mode: 640
|
||||
tags: zcs
|
||||
|
||||
- name: Remove old zmldapsync script
|
||||
file: path=/opt/zimbra/bin/zmldapsync.pl state=absent
|
||||
tags: zcs
|
||||
|
||||
- name: Deploy zmldapsync configuration
|
||||
template: src=zmldapsync.yml.j2 dest=/opt/zimbra/conf/zmldapsync.yml owner=root group=zimbra mode=0640
|
||||
tags: zcs
|
||||
|
||||
- name: Deploy zmldapsync systemd units
|
||||
template: src={{ item }}.j2 dest=/etc/systemd/system/{{ item }}
|
||||
loop:
|
||||
- zmldapsync.service
|
||||
- zmldapsync.timer
|
||||
register: zcs_zmldapsync_unit
|
||||
tags: zcs
|
||||
|
||||
- name: Reload systemd
|
||||
systemd: daemon_reload=True
|
||||
when: zcs_zmldapsync_unit.changed
|
||||
tags: zcs
|
||||
|
||||
- name: Enable zmldapsync timer
|
||||
systemd: name=zmldapsync.timer state={{ (zcs_domains.keys() | length > 0) | ternary('started','stopped') }} enabled={{ (zcs_domains.keys() | length > 0) | ternary(True,False) }}
|
||||
when: zcs_domains.keys() | length > 0
|
||||
tags: zcs
|
98
roles/zimbra/templates/cas_preauth.jsp.j2
Normal file
98
roles/zimbra/templates/cas_preauth.jsp.j2
Normal file
@@ -0,0 +1,98 @@
|
||||
<%@ page import="java.security.InvalidKeyException" %>
|
||||
<%@ page import="java.security.NoSuchAlgorithmException" %>
|
||||
<%@ page import="java.security.SecureRandom" %>
|
||||
<%@ page import="java.util.HashMap" %>
|
||||
<%@ page import="java.util.Map" %>
|
||||
<%@ page import="java.util.Iterator" %>
|
||||
<%@ page import="java.util.TreeSet" %>
|
||||
<%@ page import="javax.crypto.Mac" %>
|
||||
<%@ page import="javax.crypto.SecretKey" %>
|
||||
<%!
|
||||
public static final String DOMAIN_KEY =
|
||||
"{{ item.stdout }}";
|
||||
|
||||
public static String generateRedirect(HttpServletRequest request, String name) {
|
||||
HashMap params = new HashMap();
|
||||
String ts = System.currentTimeMillis()+"";
|
||||
params.put("account", name);
|
||||
params.put("by", "name"); // needs to be part of hmac
|
||||
params.put("timestamp", ts);
|
||||
params.put("expires", "0"); // means use the default
|
||||
|
||||
String preAuth = computePreAuth(params, DOMAIN_KEY);
|
||||
return request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/service/preauth/?" +
|
||||
"account="+name+
|
||||
"&by=name"+
|
||||
"×tamp="+ts+
|
||||
"&expires=0"+
|
||||
"&preauth="+preAuth;
|
||||
}
|
||||
|
||||
public static String computePreAuth(Map params, String key) {
|
||||
TreeSet names = new TreeSet(params.keySet());
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
for (Iterator it=names.iterator(); it.hasNext();) {
|
||||
if (sb.length() > 0) sb.append('|');
|
||||
sb.append(params.get(it.next()));
|
||||
}
|
||||
return getHmac(sb.toString(), key.getBytes());
|
||||
}
|
||||
|
||||
private static String getHmac(String data, byte[] key) {
|
||||
try {
|
||||
ByteKey bk = new ByteKey(key);
|
||||
Mac mac = Mac.getInstance("HmacSHA1");
|
||||
mac.init(bk);
|
||||
return toHex(mac.doFinal(data.getBytes()));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("fatal error", e);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new RuntimeException("fatal error", e);
|
||||
}
|
||||
}
|
||||
|
||||
static class ByteKey implements SecretKey {
|
||||
private byte[] mKey;
|
||||
|
||||
ByteKey(byte[] key) {
|
||||
mKey = (byte[]) key.clone();;
|
||||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
public String getAlgorithm() {
|
||||
return "HmacSHA1";
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return "RAW";
|
||||
}
|
||||
}
|
||||
|
||||
public static String toHex(byte[] data) {
|
||||
StringBuilder sb = new StringBuilder(data.length * 2);
|
||||
|
||||
for (int i=0; i<data.length; i++ ) {
|
||||
sb.append(hex[(data[i] & 0xf0) >>> 4]);
|
||||
sb.append(hex[data[i] & 0x0f] );
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static final char[] hex =
|
||||
{'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,
|
||||
'8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f'};
|
||||
%><%
|
||||
String casUser = request.getRemoteUser().toString().trim();
|
||||
String redirect = generateRedirect(request, casUser+"@{{ item.item }}");
|
||||
response.sendRedirect(redirect);
|
||||
%>
|
||||
<html>
|
||||
<head>
|
||||
<title>Pre-auth redirect</title>
|
||||
</head>
|
||||
<body>You should never see this page!</body>
|
||||
</html>
|
100
roles/zimbra/templates/cas_preauth_admin.jsp.j2
Normal file
100
roles/zimbra/templates/cas_preauth_admin.jsp.j2
Normal file
@@ -0,0 +1,100 @@
|
||||
<%@ page import="java.security.InvalidKeyException" %>
|
||||
<%@ page import="java.security.NoSuchAlgorithmException" %>
|
||||
<%@ page import="java.security.SecureRandom" %>
|
||||
<%@ page import="java.util.HashMap" %>
|
||||
<%@ page import="java.util.Map" %>
|
||||
<%@ page import="java.util.Iterator" %>
|
||||
<%@ page import="java.util.TreeSet" %>
|
||||
<%@ page import="javax.crypto.Mac" %>
|
||||
<%@ page import="javax.crypto.SecretKey" %>
|
||||
<%!
|
||||
public static final String DOMAIN_KEY =
|
||||
"{{ item.stdout }}";
|
||||
|
||||
public static String generateRedirect(HttpServletRequest request, String name) {
|
||||
HashMap params = new HashMap();
|
||||
String ts = System.currentTimeMillis()+"";
|
||||
params.put("account", name);
|
||||
params.put("by", "name"); // needs to be part of hmac
|
||||
params.put("timestamp", ts);
|
||||
params.put("expires", "0"); // means use the default
|
||||
params.put("admin", "1");
|
||||
|
||||
String preAuth = computePreAuth(params, DOMAIN_KEY);
|
||||
return request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/service/preauth/?" +
|
||||
"account="+name+
|
||||
"&by=name"+
|
||||
"×tamp="+ts+
|
||||
"&expires=0"+
|
||||
"&admin=1"+
|
||||
"&preauth="+preAuth;
|
||||
}
|
||||
|
||||
public static String computePreAuth(Map params, String key) {
|
||||
TreeSet names = new TreeSet(params.keySet());
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
for (Iterator it=names.iterator(); it.hasNext();) {
|
||||
if (sb.length() > 0) sb.append('|');
|
||||
sb.append(params.get(it.next()));
|
||||
}
|
||||
return getHmac(sb.toString(), key.getBytes());
|
||||
}
|
||||
|
||||
private static String getHmac(String data, byte[] key) {
|
||||
try {
|
||||
ByteKey bk = new ByteKey(key);
|
||||
Mac mac = Mac.getInstance("HmacSHA1");
|
||||
mac.init(bk);
|
||||
return toHex(mac.doFinal(data.getBytes()));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("fatal error", e);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new RuntimeException("fatal error", e);
|
||||
}
|
||||
}
|
||||
|
||||
static class ByteKey implements SecretKey {
|
||||
private byte[] mKey;
|
||||
|
||||
ByteKey(byte[] key) {
|
||||
mKey = (byte[]) key.clone();;
|
||||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
public String getAlgorithm() {
|
||||
return "HmacSHA1";
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return "RAW";
|
||||
}
|
||||
}
|
||||
|
||||
public static String toHex(byte[] data) {
|
||||
StringBuilder sb = new StringBuilder(data.length * 2);
|
||||
|
||||
for (int i=0; i<data.length; i++ ) {
|
||||
sb.append(hex[(data[i] & 0xf0) >>> 4]);
|
||||
sb.append(hex[data[i] & 0x0f] );
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static final char[] hex =
|
||||
{'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,
|
||||
'8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f'};
|
||||
%><%
|
||||
String casUser = request.getRemoteUser().toString().trim();
|
||||
String redirect = generateRedirect(request, casUser+"@{{ item.item }}");
|
||||
response.sendRedirect(redirect);
|
||||
%>
|
||||
<html>
|
||||
<head>
|
||||
<title>Pre-auth redirect</title>
|
||||
</head>
|
||||
<body>You should never see this page!</body>
|
||||
</html>
|
60
roles/zimbra/templates/dehydrated_hook.sh.j2
Normal file
60
roles/zimbra/templates/dehydrated_hook.sh.j2
Normal file
@@ -0,0 +1,60 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
{% if zcs_letsencrypt == True %}
|
||||
if [ $1 == "{{ inventory_hostname }}" ]; then
|
||||
cat /var/lib/dehydrated/certificates/certs/{{ inventory_hostname }}/privkey.pem > /opt/zimbra/ssl/zimbra/commercial/commercial.key
|
||||
chown zimbra:zimbra /opt/zimbra/ssl/zimbra/commercial/commercial.key
|
||||
chmod 600 /opt/zimbra/ssl/zimbra/commercial/commercial.key
|
||||
cp /var/lib/dehydrated/certificates/certs/{{ inventory_hostname }}/cert.pem /tmp/zimbra_cert.pem
|
||||
cp /var/lib/dehydrated/certificates/certs/{{ inventory_hostname }}/chain.pem /tmp/zimbra_chain.pem
|
||||
# Zimbra needs the root cert to validate the whole chain
|
||||
cat <<_EOF >> /tmp/zimbra_chain.pem
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
||||
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
|
||||
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
|
||||
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
|
||||
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
|
||||
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
|
||||
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
|
||||
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
|
||||
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
|
||||
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
|
||||
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
|
||||
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
|
||||
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
|
||||
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
|
||||
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
||||
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
|
||||
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
|
||||
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
|
||||
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
|
||||
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
|
||||
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
|
||||
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
|
||||
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
|
||||
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
|
||||
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
|
||||
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
|
||||
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
||||
-----END CERTIFICATE-----
|
||||
_EOF
|
||||
chown zimbra:zimbra /opt/zimbra/ssl/zimbra/commercial/commercial.key /tmp/zimbra_{cert,chain}.pem
|
||||
|
||||
su - zimbra -c "/opt/zimbra/bin/zmcertmgr deploycrt comm /tmp/zimbra_cert.pem /tmp/zimbra_chain.pem"
|
||||
rm -f /tmp/zimbra_{cert,chain}.pem
|
||||
{% if 'mta' in zcs_enabled_components %}
|
||||
su - zimbra -c "/opt/zimbra/bin/zmmtactl reload"
|
||||
{% endif %}
|
||||
{% if 'proxy' in zcs_enabled_components %}
|
||||
# Don't put the root cert for nginx, as some monitoring tools might not like this
|
||||
cat /var/lib/dehydrated/certificates/certs/{{ inventory_hostname }}/fullchain.pem > /opt/zimbra/conf/nginx.crt
|
||||
su - zimbra -c "/opt/zimbra/bin/zmproxyctl reload"
|
||||
{% endif %}
|
||||
{% if 'mailbox' in zcs_enabled_components %}
|
||||
su - zimbra -c "/opt/zimbra/bin/zmmailboxdctl reload"
|
||||
{% endif %}
|
||||
fi
|
||||
{% endif %}
|
9
roles/zimbra/templates/filebeat.yml.j2
Normal file
9
roles/zimbra/templates/filebeat.yml.j2
Normal file
@@ -0,0 +1,9 @@
|
||||
- type: log
|
||||
enabled: True
|
||||
paths:
|
||||
- /var/log/zimbra.log
|
||||
- /opt/zimbra/log/*.log
|
||||
exclude_files:
|
||||
- '\.[gx]z$'
|
||||
- '\d+$'
|
||||
|
11
roles/zimbra/templates/post_backup.sh.j2
Normal file
11
roles/zimbra/templates/post_backup.sh.j2
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
echo 'Removing Zimbra database dumps'
|
||||
rm -f /home/lbkp/zimbra/{ldap*,mysql*}
|
||||
rm -rf /home/lbkp/zimbra/exports/
|
||||
|
||||
# Remove snapshot mount point
|
||||
echo 'Cleanup backup mount point and snapshot'
|
||||
/opt/zimbra/bin/zmbh --post --shutdown=ldap --verbose --mount=/home/lbkp/zimbra/mount
|
68
roles/zimbra/templates/pre_backup.sh.j2
Normal file
68
roles/zimbra/templates/pre_backup.sh.j2
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
mkdir -p /home/lbkp/zimbra/mount
|
||||
|
||||
source /opt/zimbra/bin/zmshutil
|
||||
zmsetvars
|
||||
|
||||
echo 'Starting Zimbra backup'
|
||||
|
||||
{% if 'ldap' in zcs_enabled_components %}
|
||||
echo 'Dumping LDAP database'
|
||||
|
||||
# Dump ldap data
|
||||
/opt/zimbra/common/sbin/slapcat \
|
||||
-F /opt/zimbra/data/ldap/config \
|
||||
-n 0 | zstd -c > /home/lbkp/zimbra/ldap-config.ldif.zst
|
||||
/opt/zimbra/common/sbin/slapcat \
|
||||
-F /opt/zimbra/data/ldap/config \
|
||||
-b "" | zstd -c > /home/lbkp/zimbra/ldap.ldif.zst
|
||||
{% endif %}
|
||||
{% if 'mailbox' in zcs_enabled_components %}
|
||||
|
||||
# Dump MySQL data
|
||||
echo 'Dumping MySQL database'
|
||||
/opt/zimbra/common/bin/mysqldump \
|
||||
--user=root \
|
||||
--password=$mysql_root_password \
|
||||
--socket=$mysql_socket \
|
||||
--all-databases \
|
||||
--single-transaction \
|
||||
--flush-logs | zstd -c > /home/lbkp/zimbra/mysql.sql.zst
|
||||
|
||||
# Export calendars, tasks and address books to ics and vcf files
|
||||
OLDIFS=$IFS
|
||||
IFS=$'\n'
|
||||
for MAILBOX in $(/usr/local/bin/zmprov getQuotaUsage $(hostname --fqdn) | awk '{ print $1}'); do
|
||||
echo ''
|
||||
echo "Cheking contact and calendar folders for $MAILBOX"
|
||||
for LINE in $(/usr/local/bin/zmmailbox -z -m $MAILBOX -t 0 getAllFolders); do
|
||||
# Skip folders whose ID indicates it's a shared folder
|
||||
if echo $LINE | grep -qiP '^\s*[a-z0-9]{8}\-[a-z0-9]'; then
|
||||
continue
|
||||
fi
|
||||
DIR=$(echo $LINE | perl -ne 'm/\s*\d+\s+(\w{4})\s+\d+\s+\d+\s+(\/.*)/ && print "$2\n"')
|
||||
if echo $DIR | grep -qiP '\([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}:\d+\)$'; then
|
||||
continue
|
||||
fi
|
||||
TYPE=$(echo $LINE | perl -ne 'm/\s*\d+\s+(\w{4})\s+\d+\s+\d+\s+(\/.*)/ && print "$1\n"')
|
||||
if [ "$TYPE" == "appo" -o "$TYPE" == "task" -o "$TYPE" == "cont" ]; then
|
||||
echo "Exporting folder $DIR (account $MAILBOX, type $TYPE)"
|
||||
mkdir -p /home/lbkp/zimbra/exports/$MAILBOX/$(dirname $DIR)
|
||||
fi
|
||||
if [ "$TYPE" == "appo" -o "$TYPE" == "task" ]; then
|
||||
/usr/local/bin/zmmailbox -z -m $MAILBOX -t 0 getRestUrl "$(printf '%q' $DIR)?fmt=ics" > "/home/lbkp/zimbra/exports/$MAILBOX/$DIR"".ics"
|
||||
elif [ "$TYPE" == "cont" ]; then
|
||||
/usr/local/bin/zmmailbox -z -m $MAILBOX -t 0 getRestUrl "$(printf '%q' $DIR)?fmt=vcf" > "/home/lbkp/zimbra/exports/$MAILBOX/$DIR"".vcf"
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$OLDIFS
|
||||
|
||||
{% endif %}
|
||||
# Try to snapshot Zimbra tree
|
||||
echo ''
|
||||
echo "Handle /opt/zimbra snapshot / bind mount on /home/lbkp/zimbra/mount"
|
||||
/opt/zimbra/bin/zmbh --pre --snap-size=10G --verbose --mount=/home/lbkp/zimbra/mount --shutdown=ldap
|
23
roles/zimbra/templates/rsyslog.conf.j2
Normal file
23
roles/zimbra/templates/rsyslog.conf.j2
Normal file
@@ -0,0 +1,23 @@
|
||||
$ModLoad imuxsock
|
||||
$ModLoad imjournal
|
||||
$OmitLocalLogging on
|
||||
$IMJournalStateFile imjournal.state
|
||||
$WorkDirectory /var/lib/rsyslog
|
||||
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
|
||||
{% if 'logger' in zcs_enabled_components %}
|
||||
$ModLoad imudp
|
||||
$UDPServerRun 514
|
||||
local0.* -/var/log/zimbra.log
|
||||
local1.* -/var/log/zimbra-stats.log
|
||||
auth.* -/var/log/zimbra.log
|
||||
mail.* -/var/log/zimbra.log
|
||||
{% else %}
|
||||
local0.* @{{ zcs_log_hostname }}
|
||||
local1.* @{{ zcs_log_hostname }}
|
||||
auth.* @{{ zcs_log_hostname }}
|
||||
local0.* -/var/log/zimbra.log
|
||||
local1.* -/var/log/zimbra-stats.log
|
||||
auth.* -/var/log/zimbra.log
|
||||
mail.* @{{ zcs_log_hostname }}
|
||||
mail.* -/var/log/zimbra.log
|
||||
{% endif %}
|
86
roles/zimbra/templates/zcs_init_config.j2
Normal file
86
roles/zimbra/templates/zcs_init_config.j2
Normal file
@@ -0,0 +1,86 @@
|
||||
AVDOMAIN="{{ zcs_main_domain }}"
|
||||
AVUSER="admin@{{ zcs_main_domain }}"
|
||||
CREATEADMIN="admin@{{ zcs_main_domain }}"
|
||||
CREATEADMINPASS="zimbraadmin"
|
||||
CREATEDOMAIN="{{ zcs_main_domain }}"
|
||||
DOCREATEADMIN="yes"
|
||||
DOCREATEDOMAIN="yes"
|
||||
DOTRAINSA="yes"
|
||||
EXPANDMENU="no"
|
||||
HOSTNAME="{{ inventory_hostname }}"
|
||||
HTTPPORT="8080"
|
||||
HTTPPROXYPORT="80"
|
||||
HTTPSPORT="8443"
|
||||
HTTPSPROXYPORT="443"
|
||||
IMAPPORT="7143"
|
||||
IMAPPROXYPORT="143"
|
||||
IMAPSSLPORT="7993"
|
||||
IMAPSSLPROXYPORT="993"
|
||||
INSTALL_WEBAPPS="service zimlet zimbra zimbraAdmin"
|
||||
JAVAHOME="/opt/zimbra/common/lib/jvm/java"
|
||||
LDAPBESSEARCHSET="set"
|
||||
LDAPHOST="{{ zcs_primary_ldap }}"
|
||||
LDAPPORT="389"
|
||||
LDAPREPLICATIONTYPE="{{ zcs_i_am_primary_ldap | ternary('master','salve') }}"
|
||||
LDAPSERVERID="2"
|
||||
MAILBOXDMEMORY="{{ (ansible_memtotal_mb * 0.25) | int }}"
|
||||
MAILPROXY="TRUE"
|
||||
MODE="redirect"
|
||||
MYSQLMEMORYPERCENT="30"
|
||||
POPPORT="7110"
|
||||
POPPROXYPORT="110"
|
||||
POPSSLPORT="7995"
|
||||
POPSSLPROXYPORT="995"
|
||||
PROXYMODE="redirect"
|
||||
REMOVE="no"
|
||||
RUNARCHIVING="no"
|
||||
RUNAV="{{ (zcs_run_av == True) | ternary('yes','no') }}"
|
||||
RUNCBPOLICYD="{{ (zcs_run_cbpolicyd == True) | ternary('yes','no') }}"
|
||||
RUNDKIM="{{ (zcs_run_dkim == True) | ternary('yes','no') }}"
|
||||
RUNSA="{{ (zcs_run_sa == True) | ternary('yes','no') }}"
|
||||
RUNVMHA="no"
|
||||
SERVICEWEBAPP="yes"
|
||||
SMTPDEST="admin@{{ zcs_main_domain }}"
|
||||
SMTPHOST="{{ inventory_hostname }}"
|
||||
SMTPNOTIFY="yes"
|
||||
SMTPSOURCE="admin@{{ zcs_main_domain }}"
|
||||
SNMPNOTIFY="{{ ('snmp' in zcs_components) | ternary('yes','no') }}"
|
||||
SNMPTRAPHOST="{{ inventory_hostname }}"
|
||||
SPELLURL="http://{{ inventory_hostname }}:7780/aspell.php"
|
||||
STARTSERVERS="yes"
|
||||
STRICTSERVERNAMEENABLED="TRUE"
|
||||
TRAINSAHAM="ham.{{ ('ham' | password_hash('sha256', 65534 | random(seed=zcs_main_domain) | string))[9:17] }}@{{ zcs_main_domain }}"
|
||||
TRAINSASPAM="spam.{{ ('spam' | password_hash('sha256', 65534 | random(seed=zcs_main_domain) | string))[9:17] }}@{{ zcs_main_domain }}"
|
||||
UIWEBAPPS="yes"
|
||||
UPGRADE="yes"
|
||||
USEEPHEMERALSTORE="no"
|
||||
USESPELL="{{ ('spell' in zcs_components) | ternary('yes','no') }}"
|
||||
VERSIONUPDATECHECKS="TRUE"
|
||||
VIRUSQUARANTINE="virus-quarantine.{{ ('virus' | password_hash('sha256', 65534 | random(seed=zcs_main_domain) | string))[9:17] }}@{{ zcs_main_domain }}"
|
||||
ZIMBRA_REQ_SECURITY="yes"
|
||||
ldap_bes_searcher_password="{{ ('bes_searcher' | password_hash('sha256', 65534 | random(seed=zcs_main_domain) | string))[9:22] }}"
|
||||
ldap_dit_base_dn_config="cn=zimbra"
|
||||
ldap_nginx_password="{{ ('nginx' | password_hash('sha256', 65534 | random(seed=zcs_main_domain) | string))[9:22] }}"
|
||||
mailboxd_directory="/opt/zimbra/mailboxd"
|
||||
mailboxd_keystore="/opt/zimbra/mailboxd/etc/keystore"
|
||||
mailboxd_keystore_password="{{ ('keystore' | password_hash('sha256', 65534 | random(seed=zcs_main_domain) | string))[9:22] }}"
|
||||
mailboxd_server="jetty"
|
||||
mailboxd_truststore="/opt/zimbra/common/lib/jvm/java/lib/security/cacerts"
|
||||
mailboxd_truststore_password="changeit"
|
||||
postfix_mail_owner="postfix"
|
||||
postfix_setgid_group="postdrop"
|
||||
ssl_default_digest="sha256"
|
||||
zimbraFeatureBriefcasesEnabled="Enabled"
|
||||
zimbraFeatureTasksEnabled="Enabled"
|
||||
zimbraIPMode="ipv4"
|
||||
zimbraMailProxy="{{ ('proxy' in zcs_components) | ternary('TRUE','FALSE') }}"
|
||||
zimbraMtaMyNetworks="127.0.0.0/8"
|
||||
zimbraPrefTimeZoneId="{{ system_tz | default('Europe/Paris') }}"
|
||||
zimbraReverseProxyLookupTarget="TRUE"
|
||||
zimbraVersionCheckNotificationEmail="admin@{{ zcs_main_domain }}"
|
||||
zimbraVersionCheckNotificationEmailFrom="admin@{{ zcs_main_domain }}"
|
||||
zimbraVersionCheckSendNotifications="TRUE"
|
||||
zimbraWebProxy="{{ ('proxy' in zcs_components) | ternary('TRUE','FALSE') }}"
|
||||
zimbra_ldap_userdn="uid=zimbra,cn=admins,cn=zimbra"
|
||||
zimbra_require_interprocess_security="1"
|
||||
INSTALL_PACKAGES="zimbra-core {{ zcs_components | map('regex_replace', '^(.*)$', 'zimbra-\\1') | join(' ') }} "
|
6
roles/zimbra/templates/zcs_install_answers.j2
Normal file
6
roles/zimbra/templates/zcs_install_answers.j2
Normal file
@@ -0,0 +1,6 @@
|
||||
{# Accept License #}y
|
||||
{# Use Online repo #}y
|
||||
{% for component in [ 'ldap', 'logger', 'mta', 'dnscache', 'snmp', 'store', 'apache', 'spell', 'memcached', 'proxy', 'drive', 'imapd', 'chat' ] %}
|
||||
{{ (component in zcs_components) | ternary('y','n') }}
|
||||
{% endfor %}
|
||||
{# Confirm continue #}y
|
3
roles/zimbra/templates/zimbra_wrapper.j2
Normal file
3
roles/zimbra/templates/zimbra_wrapper.j2
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
su - zimbra -c "LC_ALL=C.utf8 /opt/zimbra/bin/{{ item }} $*"
|
7
roles/zimbra/templates/zmldapsync.service.j2
Normal file
7
roles/zimbra/templates/zmldapsync.service.j2
Normal file
@@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Sync LDAP accounts into Zimbra
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/opt/zimbra/bin/zmldapsync
|
||||
TimeoutSec=300
|
8
roles/zimbra/templates/zmldapsync.timer.j2
Normal file
8
roles/zimbra/templates/zmldapsync.timer.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
[Unit]
|
||||
Description=Sync LDAP Users with Zimbra
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*:0/5
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
14
roles/zimbra/templates/zmldapsync.yml.j2
Normal file
14
roles/zimbra/templates/zmldapsync.yml.j2
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
general:
|
||||
notify:
|
||||
from: zimbra@{{ ansible_domain }}
|
||||
to: {{ system_admin_email }}
|
||||
|
||||
domains:
|
||||
{% for domain in zcs_domains.keys() %}
|
||||
{% if zcs_domains[domain].ldapsync is defined %}
|
||||
{{ domain }}:
|
||||
{{ zcs_domains[domain].ldapsync | to_nice_yaml(indent=2) | indent(width=4, first=True) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
7
roles/zimbra/vars/RedHat-7.yml
Normal file
7
roles/zimbra/vars/RedHat-7.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
|
||||
zcs_packages:
|
||||
- tar
|
||||
- MySQL-python
|
||||
- perl-JSON
|
||||
- patch
|
7
roles/zimbra/vars/RedHat-8.yml
Normal file
7
roles/zimbra/vars/RedHat-8.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
|
||||
zcs_packages:
|
||||
- tar
|
||||
- python3-mysql
|
||||
- perl-JSON
|
||||
- patch
|
2
roles/zimbra/vars/main.yml
Normal file
2
roles/zimbra/vars/main.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
system_postfix: False
|
1
roles/zimbra/zimbra.yml
Normal file
1
roles/zimbra/zimbra.yml
Normal file
@@ -0,0 +1 @@
|
||||
---
|
1
roles/zimbra/zimbraAdmin.yml
Normal file
1
roles/zimbra/zimbraAdmin.yml
Normal file
@@ -0,0 +1 @@
|
||||
---
|
1
roles/zimbra/zimlet.yml
Normal file
1
roles/zimbra/zimlet.yml
Normal file
@@ -0,0 +1 @@
|
||||
---
|
Reference in New Issue
Block a user