149 lines
3.7 KiB
Python
149 lines
3.7 KiB
Python
import base64
|
|
|
|
def derive_mailadmin_secret(metadata, salt):
|
|
node_id = metadata.get('id')
|
|
raw = base64.b64decode(
|
|
repo.vault.random_bytes_as_base64_for(f'{node_id}_{salt}', length=32).value
|
|
)
|
|
return base64.urlsafe_b64encode(raw).rstrip(b'=').decode('ascii')
|
|
|
|
|
|
defaults = {
|
|
'apt': {
|
|
'packages': {
|
|
'mailman3-full': {
|
|
'needs': {
|
|
'postgres_db:mailman',
|
|
'postgres_role:mailman',
|
|
'zfs_dataset:tank/mailman',
|
|
}
|
|
},
|
|
'postfix': {},
|
|
'python3-psycopg2': {
|
|
'needed_by': {
|
|
'pkg_apt:mailman3-full',
|
|
},
|
|
},
|
|
'apache2': {
|
|
'installed': False,
|
|
'needs': {
|
|
'pkg_apt:mailman3-full',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
'zfs': {
|
|
'datasets': {
|
|
'tank/mailman': {
|
|
'mountpoint': '/var/lib/mailman3',
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
|
|
@metadata_reactor.provides(
|
|
'postgresql',
|
|
'mailman',
|
|
)
|
|
def postgresql(metadata):
|
|
node_id = metadata.get('id')
|
|
db_password = repo.vault.password_for(f'{node_id} database mailman')
|
|
|
|
return {
|
|
'postgresql': {
|
|
'databases': {
|
|
'mailman': {
|
|
'owner': 'mailman',
|
|
},
|
|
},
|
|
'roles': {
|
|
'mailman': {
|
|
'password': db_password,
|
|
},
|
|
},
|
|
},
|
|
'mailman': {
|
|
'db_password': db_password,
|
|
},
|
|
}
|
|
|
|
|
|
@metadata_reactor.provides(
|
|
'nginx/vhosts',
|
|
)
|
|
def nginx(metadata):
|
|
return {
|
|
'nginx': {
|
|
'vhosts': {
|
|
metadata.get('mailman/hostname'): {
|
|
'content': 'mailman/vhost.conf',
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
|
|
@metadata_reactor.provides(
|
|
'mailman/secret_key',
|
|
)
|
|
def secret_key(metadata):
|
|
import base64
|
|
|
|
node_id = metadata.get('id')
|
|
raw = base64.b64decode(
|
|
repo.vault.random_bytes_as_base64_for(f'{node_id}_mailman_secret_key', length=32).value
|
|
)
|
|
secret_key = base64.urlsafe_b64encode(raw).rstrip(b'=').decode('ascii')
|
|
|
|
return {
|
|
'mailman': {
|
|
'secret_key': secret_key,
|
|
},
|
|
}
|
|
|
|
|
|
@metadata_reactor.provides(
|
|
'mailman',
|
|
)
|
|
def secrets(metadata):
|
|
return {
|
|
'mailman': {
|
|
'web_secret': derive_mailadmin_secret(metadata, 'secret_key'),
|
|
'api_password': derive_mailadmin_secret(metadata, 'api_password'),
|
|
'archiver_key': derive_mailadmin_secret(metadata, 'archiver_key'),
|
|
},
|
|
}
|
|
|
|
|
|
@metadata_reactor.provides(
|
|
'dns',
|
|
)
|
|
def dns(metadata):
|
|
report_email = metadata.get('mailman/dmarc_report_email')
|
|
|
|
return {
|
|
'dns': {
|
|
metadata.get('mailman/hostname'): {
|
|
'MX': [f"5 {metadata.get('mailman/hostname')}."],
|
|
'TXT': [
|
|
'v=spf1 a mx -all',
|
|
'; '.join(f'{k}={v}' for k, v in {
|
|
# dmarc version
|
|
'v': 'DMARC1',
|
|
# reject on failure
|
|
'p': 'reject',
|
|
# standard reports
|
|
'rua': f'mailto:{report_email}',
|
|
# forensic reports
|
|
'fo': 1,
|
|
'ruf': f'mailto:{report_email}',
|
|
# require alignment between the DKIM domain and the parent Header From domain
|
|
'adkim': 's',
|
|
# require alignment between the SPF domain (the sender) and the Header From domain
|
|
'aspf': 's',
|
|
}.items())
|
|
],
|
|
},
|
|
},
|
|
}
|