Skip to content
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
3425f77
WIP: running the role
Nov 14, 2024
08265c2
Additionnal aliases_db_type in sympa.conf
Nov 18, 2024
f76d0de
superflous changes
Nov 26, 2024
153012a
adding LDAP perl module
Mar 21, 2025
3c535f7
adding IO::Socket::SSL module, also for LDAP auth
May 2, 2025
58e92a6
fixing list of modules, robots.conf configuration
May 4, 2025
f7fdcaf
Merge branch 'main' into cielito
May 5, 2025
9df15d0
fix if clause, perl modules
fzadikian Jul 30, 2025
0e47990
add task to install LDAP libraries needed
Jul 31, 2025
123afa6
Update sympa.conf template to use DKIM
Aug 7, 2025
55d051b
WIP: configuring robots
Aug 8, 2025
735140f
considering compounding parameters
Aug 9, 2025
bc172c6
fixing: compounding parameters
Aug 9, 2025
fee0a63
default value for sympa_robots, documentation
Aug 9, 2025
55c990c
Merge branch 'robots-config' into cielito
Aug 9, 2025
67a06e6
sympa_robots as a dict
Aug 11, 2025
245491a
Merge branch 'robots-config' into cielito
Aug 11, 2025
f61f71a
fixing robot.conf template merge
Aug 11, 2025
b00cb5a
add no ssl ldap option
fzadikian Aug 11, 2025
5498477
add LDAP to README.md
fzadikian Aug 11, 2025
f095e88
wwsympa_url instead of web_domain
Aug 13, 2025
3b26398
Merge branch 'robots-config' into cielito
Aug 13, 2025
a9fb16f
sympa_robots default as empty dict, not list
Aug 21, 2025
8340e19
if dkim_feature, config dkim requirements
Aug 28, 2025
b63c87b
rename ldaps variable
fzadikian Sep 2, 2025
f2f7e00
follow DRY principle for dkim_signature_apply_on
fzadikian Sep 5, 2025
6f70d93
Update sympa.conf template to use DKIM
Aug 7, 2025
a286266
if dkim_feature, config dkim requirements
Aug 28, 2025
17846bc
respect sympa defaults, add missing dkim_add_signature_to variable to…
fzadikian Sep 5, 2025
99e78d8
merge branch 'dkim-upstream' into cielito
fzadikian Sep 8, 2025
7214997
sympa_config_extra_parameters as a dict
Sep 8, 2025
a089342
accept string instead of list parameter
Sep 9, 2025
29a605e
templates and vars: list or strings as jinja macro
Sep 9, 2025
f163afd
workaround dbtype for postgresql
fzadikian Sep 10, 2025
2bff66c
no arc folder per robot, set attributes to existing elementi in insta…
Sep 12, 2025
9f3af37
accepitng sympa_robots elements only with domain key
Sep 15, 2025
592b602
fix bug from when expression
fzadikian Oct 1, 2025
af2f987
fix more conditionals containing 'count'
fzadikian Oct 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,47 @@ If no value is provided, `listmaster` will be joined with a @ to the

For example: *listmaster@lists.example.com*.

### Sympa robots

#### *sympa_robots*

With *sympa_robots* the role defines and populates the `robots.conf` files of a multi-domains Sympa server.

*sympa_robots* is a dict, where each key is the *domain* on which the robot operates (mail and web), and the value is a dict which defines the values of all the parameters of the robot. It may contain parameters such as `wwsympa_url`, `listmaster`, `title`, or any other [configuration parameter valid in a `robot.conf` file](https://www.sympa.community/gpldoc/man/sympa_config.5.html), with its associated value(s).

*listmaster* can be defined as an ansible list of emails, or as a string of comma separated email addresses. Compound paramentes can be defined as sub-dicts. For instance:
```
sympa_robots:
lists.mydomain.tld:
listmaster: ...

archive:
web_access: public
mail_access: private
```
will render in the `lists.mydomain.tld/robot.conf` configuration file:
```
# Robot configuration for lists.mydomain.tld
domain lists.mydomain.tld

# Robot's listmaster
listmaster ...

# archive value(s)
archive.web_access public
archive.mail_access private
```
For backwards compatibility, *sympa_robots* can also be defined as a list of dicts where all items have a parameter *domain* defining the robot:
```
sympa_robots:
- domain: lists.mydomain.tld
listmaster: ...

archive:
web_access: public
mail_access: private
```

### Installation

You can pick from different installation methods through the
Expand Down Expand Up @@ -321,6 +362,16 @@ Protocol for SOAP URL. Defaults to `https`.

Number of FCGI instances (default: 2)

### LDAP

#### *sympa_ldap_auth_enabled*

Whether authentication through LDAP is enabled. Defaults to `false`.

#### *sympa_ldap_auth_ssl*

Whether authentication through LDAP uses SSL. Defaults to `true`.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it SSL or TLS? And shouldn't we allow any transport protocol, for sysadmin to be able to fit their installation with their LDAP requirements?

By the way, to complete LDAP understanding we should also document somewhere how to build sympa_web_authentication. A link to ldap auth.conf configuration would be worthy.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it SSL or TLS?

ldap-secure depends on IO::Socket::SSL, so I guess it is SSL.

And shouldn't we allow any transport protocol, for sysadmin to be able to fit their installation with their LDAP requirements?

What do you mean? We are currently covering both ldap and ldap-secure, the only ldap related features on sympa's cpanfile.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ldap-secure depends on IO::Socket::SSL, so I guess it is SSL.

SSL is often used for secure layer, but strictly SSL is deprecated and being replaced by TLS. Seeing our LDAP parameters, I think we are using TLS 1.2, on port 389. ldaps (i.e. LDAP on SSL listen on port 636).

What do you mean?
I mean the LDAP may pre-exists and Sympa should bind to itl as provided: basic ldap on port 389, ldaps on 636 and/or ldap+starttls on 389 (our LDAP, for instance, took a while to offer this last protocol)

We are currently covering both ldap and ldap-secure, the only ldap related features on sympa's cpanfile.

There are also TLS parameters of the authentication.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are also TLS parameters of the authentication.

I see, then shall I rename variables to reference TLS instead of SSL, or directly reference "secure" instead?

I mean the LDAP may pre-exists and Sympa should bind to itl as provided: basic ldap on port 389, ldaps on 636 and/or ldap+starttls on 389 (our LDAP, for instance, took a while to offer this last protocol)

So then, does that need any special configurations from this role? I thought the {{ key }} {{ value }} approach would eliminate all those quirks.


## Dependencies

None.
Expand Down
22 changes: 20 additions & 2 deletions defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ sympa_config_sendmail: /usr/sbin/sendmail
sympa_config_sendmail_aliases: /etc/mail/sympa/aliases
sympa_config_shared_feature: 'on'

sympa_config_dkim_feature: false

sympa_edit_list_defaults:
- role: privileged_owner
privilege: write
Expand Down Expand Up @@ -134,6 +132,9 @@ sympa_soap_fcgi_enabled: false
sympa_soap_fcgi_protocol: https
sympa_soap_fcgi_instances: 2

sympa_ldap_auth_enabled: false
sympa_ldap_auth_ssl: true

sympa_web_nginx_snippet: |
location = / {
return 301 /{{ sympa_web_path }};
Expand All @@ -159,6 +160,23 @@ sympa_soap_nginx_snippet: |
fastcgi_pass unix:/run/sympasoap/sympasoap.socket;
}

sympa_robots: {}

sympa_install_odbc_driver: false

sympa_rsyslog_unix_user: "{{ sympa_unix_user }}"


sympa_dkim_feature: false

sympa_config_dkim_feature: '{{ sympa_dkim_feature }}'

sympa_dkim_add_signature_to:
- robot
- list

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Candide question: Shouldn't we allow to sign each robot with its specific DKIM key?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it would be better if each robot is from an entirely different fqdn

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now, in cielito.sympa.install, we hard coded dkim_same_key: false when calling dkim role .

But: are we proposing a complete and consistent DKIM features API for this upstream role?

@fzadikian fzadikian Sep 2, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was dkim_same_key from our fork or from upstream? Why is it broken in our fork? Anyways, it doesn't seem like a great idea to have the same key for every (sub)domain.

sympa_dkim_private_key_path: /etc/ssl/dkim_private.key
sympa_dkim_signature_apply_on:
- md5_authenticated_messages
- smime_authenticated_messages
- dkim_authenticated_messages
- editor_validated_messages

@ulvida ulvida Sep 2, 2025

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand you set these values because of these sympa defaults.

However, this is the default behaviour of sympa when dkim_signature_apply_on is not defined. Here, we must allow such setting, not set values that reproduce this behaviour. As we need to allow "dkim_signature_apply_on not defined" in sympa, we shouldn't set a default value here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, we shouldn't set any of these four values, and if the user decides to set dkim_signature_apply_on, they should handle it themselves? Just in case, this code was snipped from our legacy sympa role and adapted by @paulo-ruiz.

@ulvida ulvida Sep 5, 2025

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, we shouldn't set any of these four values, and if the user decides to set dkim_signature_apply_on, they should handle it themselves?

Yes. Eventually the role could assert permitted values, but I think re-coding in the role the default behaviour of sympa conflicts with DRY principle. don't you think so?

Just in case, this code was snipped from our legacy sympa role and adapted by @paulo-ruiz.

legacy or upstream sympa role? There is nothing about DKIM in upstream version of this template. We are building our PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

legacy or upstream sympa role? There is nothing about DKIM in upstream version of this template. We are building our PR.

I am referring to this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Eventually the role could assert permitted values, but I think re-coding in the role the default behaviour of sympa conflicts with DRY principle. don't you think so?

Yes, I agree that it's better to simplify this.

6 changes: 3 additions & 3 deletions tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@
- sympa
- sympa-conf

- name: Create configuration files for robots on request
import_tasks: robots.yml
when: sympa_robots | default([]) | count > 0
- name: Create configuration files for robots on request (dict variable)
import_tasks:
file: robots.yml
tags:
- sympa
- sympa-conf
Expand Down
29 changes: 28 additions & 1 deletion tasks/perl-modules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@
name: "{{ sympa_openssldev_package }}"
when: sympa_config_dkim_feature or sympa_soap_fcgi_enabled

- name: Install SSL development library and zlib development needed for LDAP
package:
name:
- "{{ sympa_openssldev_package }}"
- "{{ sympa_zlibdev_package }}"
when: sympa_ldap_auth_enabled and sympa_ldap_auth_ssl
tags: sympaldap

- name: Add Mail::DKIM::Verifier to features if DKIM support is requested
set_fact:
sympa_cpanm_features: "{{ sympa_cpanm_features + ['Mail::DKIM::Verifier'] }}"
Expand All @@ -58,6 +66,25 @@
when: sympa_soap_fcgi_enabled
tags: sympasoap

- name: Add ldap-secure to features if LDAP (ssl) auth is enabled
set_fact:
sympa_cpanm_features: "{{ sympa_cpanm_features + ['ldap-secure'] }}"
when: sympa_ldap_auth_enabled and sympa_ldap_auth_ssl
tags: sympaldap

- name: Add ldap to features if LDAP (no SSL) auth is enabled
set_fact:
sympa_cpanm_features: "{{ sympa_cpanm_features + ['ldap'] }}"
when: sympa_ldap_auth_enabled and not sympa_ldap_auth_ssl
tags: sympaldap

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

role tags are sympa-conf, sympa-auth, ... should therefore be sympa-ldap here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about sympasoap, though?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right... anyway, all tagging is still to review. not very relevant, so.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these tags are not meant to be run until everything prior has been ran at least once, because the rest of the file has no tags at all


- name: Print features before install
ansible.builtin.debug:
var: sympa_cpanm_features
verbosity: 1

- name: Install Perl modules with cpanm
command: "{{ sympa_cpanm_program }} --notest --installdeps {{ sympa_source_directory }}{% for feature in sympa_cpanm_features %} --with-feature {{ feature }}{% endfor %}"
tags: sympasoap
tags:
- sympasoap
- sympaldap
48 changes: 48 additions & 0 deletions tasks/robot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
# Copyright (C) 2020-2022 Stefan Hornburg (Racke) <racke@linuxia.de>
# SPDX-License-Identifier: GPL-2.0-or-later

- name: Create directory for {{ sympa_robot_domain }} robot
file:
state: directory
path: "{{ sympa_configuration_directory }}/{{ sympa_robot_domain }}"
owner: "{{ sympa_unix_user }}"
group: "{{ sympa_unix_group }}"
mode: 0755

- name: Create list data directory for {{ sympa_robot_domain }} robot
file:
state: directory
path: "{{ sympa_list_home_directory }}/{{ sympa_robot_domain }}"
owner: "{{ sympa_unix_user }}"
group: "{{ sympa_unix_group }}"
mode: 0755

- name: Create archives' directory {{ sympa_robot_domain }} robot
file:
state: directory
path: "{{ sympa_installation_directory }}/arc/{{ sympa_robot_domain }}"
owner: "{{ sympa_unix_user }}"
group: "{{ sympa_unix_group }}"
mode: 0755

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently, these folders per robot are not needed. Sympa create archive folder with the full name of the list list@robot_domain.


- debug:
var: "{{ item }}"
verbosity: 2
loop:
- sympa_robot_domain
- sympa_robot
- sympa_robots


- name: Create {{ sympa_robot_domain }} robot configuration file
template:
src: robot.conf.j2
dest: "{{ sympa_configuration_directory }}/{{ sympa_robot_domain }}/robot.conf"
owner: "{{ sympa_unix_user }}"
group: "{{ sympa_unix_group }}"
mode: 0644
notify:
- restart sympa
- restart wwsympa

76 changes: 35 additions & 41 deletions tasks/robots.yml
Original file line number Diff line number Diff line change
@@ -1,47 +1,41 @@
---
# Copyright (C) 2020-2022 Stefan Hornburg (Racke) <racke@linuxia.de>
# SPDX-License-Identifier: GPL-2.0-or-later
# Sympa robots configuration

- name: Create directory for robots
file:
state: directory
path: "{{ sympa_configuration_directory }}/{{ item.domain }}"
owner: "{{ sympa_unix_user }}"
group: "{{ sympa_unix_group }}"
mode: 0755
when: item.domain != sympa_domain
loop: "{{ sympa_robots }}"
- name: Create configuration files for robots on request (dict variable)
include_tasks:
file: robot.yml
apply:
tags:
- sympa
- sympa-conf
- sympa-robots
loop: "{{ sympa_robots | list }}"
loop_control:
loop_var: sympa_robot_domain
vars:
sympa_robot_domain_query: '"{{ sympa_robot_domain }}"'
sympa_robot: "{{ sympa_robots | community.general.json_query ( sympa_robot_domain_query ) }}"
when:
- sympa_robots is mapping
- sympa_robot_domain != sympa_domain

- name: Create list data directory for robots
file:
state: directory
path: "{{ sympa_list_home_directory }}/{{ item.domain }}"
owner: "{{ sympa_unix_user }}"
group: "{{ sympa_unix_group }}"
mode: 0755
when: item.domain != sympa_domain
loop: "{{ sympa_robots }}"

- name: Create list data directory for robots
file:
state: directory
path: "{{ sympa_list_home_directory }}/{{ item.domain }}"
owner: "{{ sympa_unix_user }}"
group: "{{ sympa_unix_group }}"
mode: 0755
when: item.domain != sympa_domain
loop: "{{ sympa_robots }}"
- name: Create configuration files for robots on request (list variable)
include_tasks:
file: robot.yml
apply:
tags:
- sympa
- sympa-conf
- sympa-robots
loop: "{{ sympa_robots | list }}"
loop_control:
loop_var: sympa_robot
vars:
sympa_robot_domain: "{{ sympa_robot.domain }}"
when:
- sympa_robots is not mapping # then it must be a list of dicts
- sympa_robot_domain != sympa_domain

- name: Create configuration file
template:
src: robot.conf.j2
dest: "{{ sympa_configuration_directory }}/{{ item.domain }}/robot.conf"
owner: "{{ sympa_unix_user }}"
group: "{{ sympa_unix_group }}"
mode: 0644
when: item.domain != sympa_domain
loop: "{{ sympa_robots }}"
notify:
- restart sympa
- restart wwsympa

...
32 changes: 28 additions & 4 deletions templates/robot.conf.j2
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
# Robot configuration for {{ item.domain }}
domain {{ item.domain }}
# Robot configuration for {{ sympa_robot_domain }}
domain {{ sympa_robot_domain }}

# Robot's listmaster
{% if sympa_robot.listmaster is defined %}
listmaster {% if sympa_robot.listmaster is string %}{{ sympa_robot.listmaster }}{% else %}{{ sympa_robot.listmaster | join(',') }}{% endif %}
{% else %}
listmaster listmaster@{{ sympa_robot_domain }}
{% endif %}

{% if sympa_web_fcgi_enabled %}

# Web interface
wwsympa_url {{ sympa_web_fcgi_protocol }}://{{ item.web_domain | default(item.domain) }}/{{ sympa_web_path }}
cookie_domain {{ item.web_domain | default(item.domain) }}
wwsympa_url {{ sympa_web_fcgi_protocol }}://{{ sympa_robot.wwsympa_url | default(sympa_robot.web_domain) | default(sympa_robot_domain) }}/{{ sympa_web_path }}
cookie_domain {{ sympa_robot.wwsympa_url | default(sympa_robot.web_domain) | default(sympa_robot_domain) }}
{% endif %}

{% for robot_param,value in sympa_robot.items() %}

{% if not robot_param in ['domain', 'listmaster', 'wwsympa_url', 'web_domain'] %}

{% if value is mapping %}
# {{ robot_param }} value(s)
{% for sub_el,val in value.items() -%}
{{ robot_param }}.{{ sub_el }} {{ val }}
{% endfor %}
{% else %}
# {{ robot_param }} value
{{ robot_param }} {{ value }}
{%- endif %}
{%- endif %}
{%- endfor %}
36 changes: 36 additions & 0 deletions templates/sympa.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ alias_manager {{ sympa_config_alias_manager }}
aliases_program {{ sympa_config_aliases_program }}
{% endif %}

{% if sympa_config_aliases_db_type is defined %}
aliases_db_type {{ sympa_config_aliases_db_type }}
{% endif %}

{% if sympa_config_aliases_wrapper is defined %}
aliases_wrapper {{ sympa_config_aliases_wrapper }}
{% endif %}
Expand All @@ -139,3 +143,35 @@ process_archive {{ sympa_config_process_archive | bool | ternary('on', 'off') }}
# Extra parameters
{{ sympa_config_extra_parameters }}
{% endif %}

###\\\\ DKIM ////###

## dkim_feature
dkim_feature {% if sympa_dkim_feature %}on{% else %}off{% endif %}

## dkim_signature_apply_on
## Type of message that is added a DKIM signature before distribution to
## subscribers. Possible values are "none", "any" or a list of the following
## keywords: "md5_authenticated_messages", "smime_authenticated_messages",
## "dkim_authenticated_messages", "editor_validated_messages".
{% if sympa_dkim_signature_apply_on | length>0 %}
dkim_signature_apply_on {{ sympa_dkim_signature_apply_on | join(',') }}
{% else %}
dkim_signature_apply_on none

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dkim_signature_apply_on is not mandatory, and default behaviour of sympa when its not defined - or empty? - is not none. I think it's good to define sympa_dkim_signature_apply_on as a list, but not to "over-template" it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, just keep the if statement and remove the else statement entirely?

{% endif %}

## dkim_private_key_path
## Location of the file where DKIM private key is stored
dkim_parameters.private_key_path {{ sympa_dkim_private_key_path }}

## dkim_signer_domain
## The "d=" tag as defined in rfc 4871, default is virtual host domain name
{% if sympa_dkim_signer_domain is defined %}
dkim_parameters.signer_domain {{ sympa_dkim_signer_domain }}
{% endif %}

## dkim_selector
## The selector
{% if sympa_dkim_selector is defined %}
dkim_parameters.selector {{ sympa_dkim_selector }}
{% endif %}
2 changes: 1 addition & 1 deletion templates/topics.conf.j2
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% for topic in sympa_topics %}
{% for topic in sympa_topics | default([]) %}
{{ topic.name }}
title {{ topic.title | default(topic.name ) }}

Expand Down