In between commit auto user creation before system email refactoring

This commit is contained in:
Kevin Veen-Birkenbach 2025-04-24 14:42:38 +02:00
parent f27076a5cc
commit 59e985eb3b
No known key found for this signature in database
GPG Key ID: 44D8F11FD62F878E
12 changed files with 119 additions and 53 deletions

View File

@ -15,17 +15,43 @@ primary_domain_sld: "cymais" # Second
primary_domain: "{{primary_domain_sld}}.{{primary_domain_tld}}" # Primary Domain of the server
# Helper Variables
# Helper Variables for administrator
_users_administrator_username: "{{ users.administrator.username | default('administrator') }}"
_users_administrator_email: "{{ users.administrator.email | default(_users_administrator_username ~ '@' ~ primary_domain) }}"
# Helper Variables for bouncer
_users_bouncer_username: "{{ users.bouncer.username | default('bouncer') }}"
_users_bouncer_email: "{{ users.bouncer.email | default(_users_bouncer_username ~ '@' ~ primary_domain) }}"
# Helper Variables for no-reply
_users_no_reply_username: "{{ users.no-reply.username | default('no-reply') }}"
_users_no_reply_email: "{{ users.no-reply.email | default(_users_no_reply_username ~ '@' ~ primary_domain) }}"
# Administrator
default_users:
administrator:
username: "{{_users_administrator_username}}" # Username of the administrator
email: "{{_users_administrator_email}}" # Email of the administrator
# initial_password: Null # Example initialisation password needs to be set in inventory file
password: "{{ansible_become_password}}" # Example initialisation password needs to be set in inventory file
uid: 1001 # Posix User ID
gid: 1001 # Posix Group ID
is_admin: true # Define as admin user
bouncer:
username: "{{ _users_bouncer_username }}" # Bounce-handler account username
email: "{{ _users_bouncer_email }}" # Email address for handling bounces
password: "{{ansible_become_password}}" # Example initialisation password needs to be set in inventory file
uid: 1002 # Posix User ID for bouncer
gid: 1002 # Posix Group ID for bouncer
no-reply:
username: "{{ _users_no_reply_username }}" # No-reply account username
email: "{{ _users_no_reply_email }}" # Email address for outgoing no-reply mails
password: "{{ansible_become_password}}" # Example initialisation password needs to be set in inventory file
uid: 1003 # Posix User ID for no-reply
gid: 1003 # Posix Group ID for no-reply
# Test Email
test_email: "test@{{primary_domain}}"

View File

@ -124,7 +124,7 @@ run:
- exec: rails r "SiteSetting.username_change_period = 0" # Deactivate changing of username
# Activate Administrator User
#- exec: printf '{{users.administrator.email}}\n{{users.administrator.initial_password}}\n{{users.administrator.initial_password}}\nY\n' | rake admin:create
#- exec: printf '{{users.administrator.email}}\n{{users.administrator.password}}\n{{users.administrator.password}}\nY\n' | rake admin:create
#- exec: rails r "User.find_by_email('{{users.administrator.email}}').update(username: '{{users.administrator.username}}')"
# The following code is just an inspiration, how to connect with the oidc account. as long as this is not set the admini account needs to be manually connected with oidc

View File

@ -19,4 +19,4 @@ KC_DB_PASSWORD= {{database_password}}
# If the initial administrator already exists and the environment variables are still present at startup, an error message stating the failed creation of the initial administrator is shown in the logs. Keycloak ignores the values and starts up correctly.
KC_BOOTSTRAP_ADMIN_USERNAME= {{users.administrator.username}}
KC_BOOTSTRAP_ADMIN_PASSWORD= {{users.administrator.initial_password}}
KC_BOOTSTRAP_ADMIN_PASSWORD= {{users.administrator.password}}

View File

@ -1,3 +1,8 @@
{##
# Iterate over all users and create LDAP entries for each, then assign admin to application roles
# This template loops through a 'users' list variable where each user is a dict with keys:
# username, uid, gid, password (optional), sn (optional), cn (optional)
##}
#######################################################################
# Container for Application Roles (if not already created)
#######################################################################
@ -6,28 +11,39 @@ objectClass: organizationalUnit
ou: roles
description: Container for application access profiles
{% for user in users %}
#######################################################################
# Create Admin User
# Create User {{ user.username }}
#######################################################################
dn: {{ldap.attributes.user_id}}={{users.administrator.username}},{{ldap.dn.users}}
dn: {{ ldap.attributes.user_id }}={{ user.username }},{{ ldap.dn.users }}
objectClass: top
objectClass: inetOrgPerson
objectClass: posixAccount
{{ldap.attributes.user_id}}: {{users.administrator.username}}
sn: Administrator
cn: Administrator
userPassword: {SSHA}CHANGE_THIS_PASSWORD
{{ ldap.attributes.user_id }}: {{ user.username }}
sn: {{ user.username }}
cn: {{ user.username }}
userPassword: {{ user.password }}
loginShell: /bin/bash
homeDirectory: /home/admin
uidNumber: {{users.administrator.uid}}
gidNumber: {{users.administrator.gid}}
homeDirectory: /home/{{ user.username }}
uidNumber: {{ user.uid }}
gidNumber: {{ user.gid }}
#######################################################################
# Add Admin User to All Application Role Groups
# Assign {{ user.username }} to application user roles
#######################################################################
{# Loop over each application defined in defaults_applications #}
{% for app, config in defaults_applications.items() %}
dn: cn={{ app }}-user,{{ ldap.dn.application_roles }}
changetype: modify
add: roleOccupant
roleOccupant: {{ ldap.attributes.user_id }}={{ user.username }},{{ ldap.dn.users }}
{% endfor %}
{% endfor %}
#######################################################################
# Add Admin User to All Application Role Groups (unchanged)
#######################################################################
{% for app, config in defaults_applications.items() %}
dn: cn={{ app }}-administrator,{{ ldap.dn.application_roles }}
changetype: modify
add: roleOccupant
@ -39,3 +55,4 @@ add: roleOccupant
roleOccupant: {{ ldap.attributes.user_id }}={{ users.administrator.username }},{{ ldap.dn.users }}
{% endfor %}

View File

@ -19,4 +19,5 @@ galaxy_info:
documentation: "https://s.veen.world/cymais"
logo:
class: "fa-solid fa-list"
dependencies: []
dependencies:
- docker-mailu

View File

@ -70,7 +70,7 @@ listmonk_settings:
value: '"{{ service_provider.platform.logo }}"'
- key: "app.site_name"
value: '"Mailing list"'
value: '"{{ service_provider.company.titel }} Mailing list"'
# - key: "bounce.enabled"
# value: 'false'

View File

@ -1,7 +1,8 @@
---
# tasks/create-mailu-user-and-token.yml
#
# Ensures a Mailu user exists and idempotently creates an API token for them.
# Ensures a Mailu user exists and idempotently creates an API token for them,
# storing tokens in a dictionary for targeted access.
#
# Required variables:
# mailu_compose_dir: Path to your docker-compose.yml directory
@ -12,11 +13,11 @@
# mailu_global_api_token: Global API token (from API_TOKEN environment variable)
#
# Optional variable:
# mailu_user_token: Pre-existing API token for the user (if already created)
# mailu_user_tokens: Dictionary of existing tokens, e.g. { "alice": "secret" }
- name: "Ensure Mailu user {{ mailu_user }}@{{ mailu_domain }} exists"
command: >
docker compose exec admin flask mailu user {{ mailu_user }} {{ mailu_domain }} '{{ mailu_password }}'
docker compose exec admin flask mailu {{ mailu_action }} {{ mailu_user }} {{ mailu_domain }} '{{ mailu_password }}'
args:
chdir: "{{ mailu_compose_dir }}"
register: mailu_user_creation
@ -51,19 +52,21 @@
body_format: json
body:
comment: "{{ mailu_user }}"
ip: "0.0.0.0/0"
ip: "{{ mailu_token_ip }}"
status_code: 201
register: mailu_token_creation
when: mailu_user_existing_token is not defined
- name: "Set mailu_user_token fact"
- name: "Set mailu_user_tokens dictionary"
set_fact:
mailu_user_token: >
{{ (mailu_token_creation is defined)
? mailu_token_creation.json.secret
: (mailu_user_existing_token.secret | default('')) }}
mailu_user_tokens: >
{{ (mailu_user_tokens | default({}))
| combine({ mailu_user: ((mailu_token_creation is defined)
| ternary(mailu_token_creation.json.secret,
mailu_user_existing_token.secret)) }) }}
# Note:
# - GET /tokens returns only metadata (id, comment, ip, created), not the secret itself.
# - The secret is returned only by the POST request and must be captured when created.
# - Store mailu_user_token securely (e.g., in Ansible Vault) for future use.
# - Tokens are stored in the mailu_user_tokens dictionary for targeted access.
# - Persist mailu_user_tokens securely (e.g., in Ansible Vault) for future use.

View File

@ -1,29 +1,48 @@
---
- name: "include docker-central-database"
- name: "Include docker-central-database"
include_role:
name: docker-central-database
when: run_once_docker_mailu is not defined
- name: "include role nginx-domain-setup for {{application_id}}"
- name: "Include role nginx-domain-setup for {{ application_id }}"
include_role:
name: nginx-domain-setup
vars:
domain: "{{ domains[application_id] }}"
http_port: "{{ ports.localhost.http[application_id] }}"
vars:
nginx_docker_reverse_proxy_extra_configuration: "client_max_body_size 31M;"
when: run_once_docker_mailu is not defined
- name: "Include the nginx-docker-cert-deploy role"
include_role:
name: nginx-docker-cert-deploy
when: run_once_docker_mailu is not defined
- name: "copy docker-compose.yml and env file"
- name: "Copy docker-compose.yml and env file"
include_tasks: copy-docker-compose-and-env.yml
when: run_once_docker_mailu is not defined
- name: flush docker service
- name: Flush docker service handlers
meta: flush_handlers
when: run_once_docker_mailu is not defined
- name: create administrator account
command:
cmd: "docker compose -p mailu exec admin flask mailu admin {{users.administrator.username}} {{primary_domain}} {{applications.mailu.initial_administrator_password}}"
chdir: "{{docker_compose.directories.instance}}"
ignore_errors: true
- name: "Create Mailu accounts and API tokens"
include_tasks: create-mailu-user-and-token.yml
vars:
mailu_compose_dir: "{{ docker_compose.directories.instance }}"
mailu_domain: "{{ domain }}"
mailu_api_base_url: "{{ web_protocol }}://{{ domain }}/api/v1"
mailu_global_api_token: "{{ applications.mailu.credentials.api_token }}"
mailu_action: "{{ item.value.is_admin | default(false) | ternary('admin','user') }}"
mailu_user: "{{ item.key }}"
mailu_password: "{{ item.value.password }}"
mailu_token_ip: "{{ item.value.ip | default('') }}"
loop: "{{ users | dict2items }}"
loop_control:
loop_var: item
when: run_once_docker_mailu is not defined
- name: Run the docker_mailu tasks once
set_fact:
run_once_docker_mailu: true
when: run_once_docker_mailu is not defined

View File

@ -182,7 +182,7 @@ OIDC_CHANGE_PASSWORD_REDIRECT_ENABLED=True
# Redirect URL for password change. Defaults to provider issuer url appended by /.well-known/change-password
OIDC_CHANGE_PASSWORD_REDIRECT_URL={{oidc.client.change_credentials}}
{% if applications[application_id].features.oidc | bool %}
{% if applications[application_id].oidc.email_by_username | bool %}
# The OIDC claim used as the username. If the selected claim contains an email address, it will be used as is. If it is not an email (e.g., sub), the email address will be constructed as <OIDC_USERNAME_CLAIM>@<OIDC_USER_DOMAIN>. Defaults to email.
OIDC_USERNAME_CLAIM={{oidc.attributes.username}}

View File

@ -25,7 +25,7 @@ MAIL_DOMAIN= "{{system_email.domain}}"
# Initial Admin Data
NEXTCLOUD_ADMIN_USER= "{{applications[application_id].users.administrator.username}}"
NEXTCLOUD_ADMIN_PASSWORD= "{{applications[application_id].users.administrator.initial_password}}"
NEXTCLOUD_ADMIN_PASSWORD= "{{applications[application_id].users.administrator.password}}"
# Security

View File

@ -2,7 +2,7 @@
user:
name: administrator
update_password: on_create
password: "{{ users.administrator.initial_password | password_hash('sha512') }}"
password: "{{ users.administrator.password | password_hash('sha512') }}"
create_home: yes
generate_ssh_key: yes
ssh_key_type: rsa

View File

@ -231,7 +231,7 @@ defaults_applications:
# LDAP Account Manager
lam:
version: "latest"
# administrator_password: "{{users.administrator.initial_password}}" # CHANGE for security reasons
# administrator_password: "{{users.administrator.password}}" # CHANGE for security reasons
oauth2_proxy:
application: application # Needs to be the same as webinterface
port: 80 # application port
@ -428,7 +428,7 @@ defaults_applications:
users:
administrator:
username: "{{users.administrator.username}}"
initial_password: "{{users.administrator.initial_password}}" # Keep in mind to change the password fast after creation and activate 2FA
password: "{{users.administrator.password}}" # Keep in mind to change the password fast after creation and activate 2FA
default_quota: '1000000000' # Quota to assign if no quota is specified in the OIDC response (bytes)
legacy_login_mask:
enabled: False # If true, then legacy login mask is shown. Otherwise just SSO
@ -680,7 +680,7 @@ defaults_applications:
users:
administrator:
email: "{{ users.administrator.email }}" # Initial login email address
password: "{{ users.administrator.initial_password }}" # Initial login password should be overridden in inventory for security
password: "{{ users.administrator.password }}" # Initial login password should be overridden in inventory for security
oauth2_proxy:
application: "application"
port: "80"