---
- name: Include public variables.
include_vars: ../public/vars.yml
tags: accounts
- name: Include private variables.
include_vars: ../private/vars.yml
tags: accounts
- name: Include members.
include_vars: "{{ lookup('first_found', membership_rolls) }}"
tags: accounts
- name: Configure hostname.
become: yes
copy:
content: "{{ item.name }}\n"
dest: "{{ item.file }}"
loop:
- { name: "core.{{ domain_priv }}", file: /etc/mailname }
- { name: "{{ inventory_hostname }}", file: /etc/hostname }
notify: Update hostname.
- name: Configure resolved.
become: yes
lineinfile:
path: /etc/systemd/resolved.conf
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { regexp: '^ *DNS *=', line: "DNS=127.0.0.1" }
- { regexp: '^ *FallbackDNS *=', line: "FallbackDNS=8.8.8.8" }
- { regexp: '^ *Domains *=', line: "Domains={{ domain_priv }}" }
- { regexp: '^ *Cache *=', line: "Cache=no" }
- { regexp: '^ *DNSStubListener *=', line: "DNSStubListener=no" }
notify:
- Reload Systemd.
- Restart Systemd resolved.
- name: Install netplan.
become: yes
apt: pkg=netplan.io
- name: Configure netplan.
become: yes
copy:
content: |
network:
renderer: networkd
ethernets:
{{ core_ethernet }}:
dhcp4: false
addresses: [ {{ core_addr_cidr }} ]
nameservers:
search: [ {{ domain_priv }} ]
addresses: [ {{ core_addr }} ]
gateway4: {{ gate_addr }}
dest: /etc/netplan/60-core.yaml
mode: u=rw,g=r,o=
notify: Apply netplan.
- name: Install DHCP server.
become: yes
apt: pkg=isc-dhcp-server
- name: Configure DHCP interface.
become: yes
lineinfile:
path: /etc/default/isc-dhcp-server
line: INTERFACESv4="{{ core_ethernet }}"
regexp: ^INTERFACESv4=
notify: Restart DHCP server.
- name: Configure DHCP subnet.
become: yes
copy:
src: ../private/core-dhcpd.conf
dest: /etc/dhcp/dhcpd.conf
notify: Restart DHCP server.
- name: Enable/Start DHCP server.
become: yes
systemd:
service: isc-dhcp-server
enabled: yes
state: started
- name: Install BIND9.
become: yes
apt: pkg=bind9
- name: Configure BIND9 with named.conf.options.
become: yes
copy:
content: |
acl "trusted" {
{{ private_net_cidr }};
{{ public_vpn_net_cidr }};
{{ campus_vpn_net_cidr }};
{{ gate_wifi_net_cidr }};
localhost;
};
options {
directory "/var/cache/bind";
forwarders {
8.8.4.4;
8.8.8.8;
};
allow-query { any; };
allow-recursion { trusted; };
allow-query-cache { trusted; };
listen-on {
{{ core_addr }};
localhost;
};
};
dest: /etc/bind/named.conf.options
notify: Reload BIND9.
- name: Configure BIND9 with named.conf.local.
become: yes
copy:
content: |
include "/etc/bind/zones.rfc1918";
zone "{{ domain_priv }}." {
type master;
file "/etc/bind/db.domain";
};
zone "{{ private_net_cidr | ansible.utils.ipaddr('revdns')
| regex_replace('^0\.','') }}" {
type master;
file "/etc/bind/db.private";
};
zone "{{ public_vpn_net_cidr | ansible.utils.ipaddr('revdns')
| regex_replace('^0\.','') }}" {
type master;
file "/etc/bind/db.public_vpn";
};
zone "{{ campus_vpn_net_cidr | ansible.utils.ipaddr('revdns')
| regex_replace('^0\.','') }}" {
type master;
file "/etc/bind/db.campus_vpn";
};
dest: /etc/bind/named.conf.local
notify: Reload BIND9.
- name: Install BIND9 zonefiles.
become: yes
copy:
src: ../private/db.{{ item }}
dest: /etc/bind/db.{{ item }}
loop: [ domain, private, public_vpn, campus_vpn ]
notify: Reload BIND9.
- name: Enable/Start BIND9.
become: yes
systemd:
service: bind9
enabled: yes
state: started
- name: Add {{ ansible_user }} to system groups.
become: yes
user:
name: "{{ ansible_user }}"
append: yes
groups: root,adm
- name: Create monkey.
become: yes
user:
name: monkey
system: yes
append: yes
groups: staff
- name: Add {{ ansible_user }} to staff groups.
become: yes
user:
name: "{{ ansible_user }}"
append: yes
groups: monkey,staff
- name: Create /home/monkey/.ssh/.
become: yes
file:
path: /home/monkey/.ssh
state: directory
mode: u=rwx,g=,o=
owner: monkey
group: monkey
- name: Configure monkey@core.
become: yes
copy:
src: ../Secret/ssh_monkey/{{ item.name }}
dest: /home/monkey/.ssh/{{ item.name }}
mode: "{{ item.mode }}"
owner: monkey
group: monkey
loop:
- { name: config, mode: "u=rw,g=r,o=" }
- { name: id_rsa.pub, mode: "u=rw,g=r,o=r" }
- { name: id_rsa, mode: "u=rw,g=,o=" }
- name: Configure Monkey SSH known hosts.
become: yes
vars:
pubkeypath: ../Secret/ssh_front/etc/ssh
pubkeyfile: "{{ pubkeypath }}/ssh_host_ecdsa_key.pub"
pubkey: "{{ lookup('file', pubkeyfile) }}"
lineinfile:
regexp: "^{{ domain_name }},{{ front_addr }} ecdsa-sha2-nistp256 "
line: "{{ domain_name }},{{ front_addr }} {{ pubkey }}"
path: /home/monkey/.ssh/known_hosts
create: yes
owner: monkey
group: monkey
mode: "u=rw,g=,o="
- name: Install basic software.
become: yes
apt: pkg=unattended-upgrades
- name: Install expect.
become: yes
apt: pkg=expect
- name: Create user accounts.
become: yes
user:
name: "{{ item }}"
password: "{{ members[item].password_core }}"
update_password: always
home: /home/{{ item }}
loop: "{{ usernames }}"
when: members[item].status == 'current'
tags: accounts
- name: Disable former users.
become: yes
user:
name: "{{ item }}"
password: "!"
loop: "{{ usernames }}"
when: members[item].status != 'current'
tags: accounts
- name: Revoke former user authorized_keys.
become: yes
file:
path: /home/{{ item }}/.ssh/authorized_keys
state: absent
loop: "{{ usernames }}"
when: members[item].status != 'current'
tags: accounts
- name: Install server certificate/key.
become: yes
copy:
src: ../Secret/CA/pki/{{ item.path }}.{{ item.typ }}
dest: /etc/server.{{ item.typ }}
mode: "{{ item.mode }}"
loop:
- { path: "issued/core.{{ domain_priv }}", typ: crt,
mode: "u=r,g=r,o=r" }
- { path: "private/core.{{ domain_priv }}", typ: key,
mode: "u=r,g=,o=" }
notify:
- Restart Postfix.
- Restart Dovecot.
- Restart OpenVPN.
- name: Install NTP.
become: yes
apt: pkg=ntp
- name: Install Postfix.
become: yes
apt: pkg=postfix
- name: Configure Postfix.
become: yes
lineinfile:
path: /etc/postfix/main.cf
regexp: "^ *{{ item.p }} *="
line: "{{ item.p }} = {{ item.v }}"
loop:
- p: smtpd_relay_restrictions
v: permit_mynetworks reject_unauth_destination
- { p: smtpd_tls_security_level, v: none }
- { p: smtp_tls_security_level, v: none }
- { p: message_size_limit, v: 104857600 }
- { p: delay_warning_time, v: 1h }
- { p: maximal_queue_lifetime, v: 4h }
- { p: bounce_queue_lifetime, v: 4h }
- { p: home_mailbox, v: Maildir/ }
- p: mynetworks
v: >-
{{ private_net_cidr }}
{{ public_vpn_net_cidr }}
{{ campus_vpn_net_cidr }}
127.0.0.0/8
[::ffff:127.0.0.0]/104
[::1]/128
- { p: relayhost, v: "[{{ front_private_addr }}]" }
- { p: inet_interfaces, v: "127.0.0.1 {{ core_addr }}" }
- { p: transport_maps, v: "hash:/etc/postfix/transport" }
notify: Restart Postfix.
- name: Configure Postfix transport.
become: yes
copy:
content: |
.{{ domain_name }} local:$myhostname
.{{ domain_priv }} local:$myhostname
dest: /etc/postfix/transport
notify: Postmap transport.
- name: Enable/Start Postfix.
become: yes
systemd:
service: postfix
enabled: yes
state: started
- name: Install institute email aliases.
become: yes
blockinfile:
block: |
webmaster: root
admin: root
www-data: root
monkey: root
root: {{ ansible_user }}
path: /etc/aliases
marker: "# {mark} INSTITUTE MANAGED BLOCK"
notify: New aliases.
- name: Install Dovecot IMAPd.
become: yes
apt: pkg=dovecot-imapd
- name: Configure Dovecot IMAPd.
become: yes
copy:
content: |
protocols = imap
ssl = required
ssl_cert =
ServerName live
ServerAlias live.{{ domain_priv }}
ServerAdmin webmaster@core.{{ domain_priv }}
DocumentRoot /WWW/live
Require all granted
AllowOverride None
UserDir Public/HTML
Require all granted
AllowOverride None
ErrorLog ${APACHE_LOG_DIR}/live-error.log
CustomLog ${APACHE_LOG_DIR}/live-access.log combined
IncludeOptional /etc/apache2/sites-available/live-vhost.conf
dest: /etc/apache2/sites-available/live.conf
mode: u=rw,g=r,o=r
notify: Restart Apache2.
- name: Install test web site.
become: yes
copy:
content: |
ServerName test
ServerAlias test.{{ domain_priv }}
ServerAdmin webmaster@core.{{ domain_priv }}
DocumentRoot /WWW/test
Require all granted
AllowOverride None
UserDir Public/HTML
Require all granted
AllowOverride None
ErrorLog ${APACHE_LOG_DIR}/test-error.log
CustomLog ${APACHE_LOG_DIR}/test-access.log combined
IncludeOptional /etc/apache2/sites-available/test-vhost.conf
dest: /etc/apache2/sites-available/test.conf
mode: u=rw,g=r,o=r
notify: Restart Apache2.
- name: Install campus web site.
become: yes
copy:
content: |
ServerName www
ServerAlias www.{{ domain_priv }}
ServerAdmin webmaster@core.{{ domain_priv }}
DocumentRoot /WWW/campus
Options Indexes FollowSymLinks MultiViews ExecCGI
AddHandler cgi-script .cgi
Require all granted
AllowOverride None
UserDir Public/HTML
Require all granted
AllowOverride None
ErrorLog ${APACHE_LOG_DIR}/campus-error.log
CustomLog ${APACHE_LOG_DIR}/campus-access.log combined
IncludeOptional /etc/apache2/sites-available/www-vhost.conf
dest: /etc/apache2/sites-available/www.conf
mode: u=rw,g=r,o=r
notify: Restart Apache2.
- name: Enable web sites.
become: yes
command:
cmd: a2ensite -q {{ item }}
creates: /etc/apache2/sites-enabled/{{ item }}.conf
loop: [ live, test, www ]
notify: Restart Apache2.
- name: Enable/Start Apache2.
become: yes
systemd:
service: apache2
enabled: yes
state: started
- name: "Install Monkey's webupdate script."
become: yes
copy:
src: ../private/webupdate
dest: /usr/local/sbin/webupdate
mode: u=rx,g=rx,o=
owner: monkey
group: staff
- name: "Create Monkey's webupdate job."
become: yes
cron:
minute: "*/15"
job: "[ -d /WWW/live ] && /usr/local/sbin/webupdate"
name: webupdate
user: monkey
- name: Install OpenVPN.
become: yes
apt: pkg=openvpn
- name: Enable IP forwarding.
become: yes
sysctl:
name: net.ipv4.ip_forward
value: "1"
state: present
- name: Install OpenVPN secret.
become: yes
copy:
src: ../Secret/front-ta.key
dest: /etc/openvpn/ta.key
mode: u=r,g=,o=
notify: Restart OpenVPN.
- name: Install OpenVPN client certificate/key.
become: yes
copy:
src: ../Secret/CA/pki/{{ item.path }}.{{ item.typ }}
dest: /etc/openvpn/client.{{ item.typ }}
mode: "{{ item.mode }}"
loop:
- { path: "issued/core", typ: crt, mode: "u=r,g=r,o=r" }
- { path: "private/core", typ: key, mode: "u=r,g=,o=" }
notify: Restart OpenVPN.
- name: Configure OpenVPN.
become: yes
copy:
content: |
client
dev-type tun
dev ovpn
remote {{ front_addr }}
nobind
user nobody
group nogroup
persist-key
persist-tun
cipher AES-256-GCM
auth SHA256
remote-cert-tls server
verify-x509-name {{ domain_name }} name
verb 3
ca /usr/local/share/ca-certificates/{{ domain_name }}.crt
cert client.crt
key client.key
tls-auth ta.key 1
dest: /etc/openvpn/front.conf
mode: u=r,g=r,o=
notify: Restart OpenVPN.
- name: Enable/Start OpenVPN.
become: yes
systemd:
service: openvpn@front
state: started
enabled: yes
- name: Install NAGIOS4.
become: yes
apt:
pkg: [ nagios4, monitoring-plugins-basic, nagios-nrpe-plugin,
lm-sensors ]
- name: Install inst_sensors NAGIOS plugin.
become: yes
copy:
src: inst_sensors
dest: /usr/local/sbin/inst_sensors
mode: u=rwx,g=rx,o=rx
- name: Configure NAGIOS4.
become: yes
lineinfile:
path: /etc/nagios4/nagios.cfg
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
backrefs: yes
loop:
- { regexp: "^( *cfg_file *= *localhost.cfg)", line: "# \\1" }
- { regexp: "^( *admin_email *= *)", line: "\\1{{ ansible_user }}@localhost" }
notify: Reload NAGIOS4.
- name: Configure NAGIOS4 contacts.
become: yes
lineinfile:
path: /etc/nagios4/objects/contacts.cfg
regexp: "^( *email +)"
line: "\\1sysadm@localhost"
backrefs: yes
notify: Reload NAGIOS4.
- name: Configure NAGIOS4 monitors.
become: yes
template:
src: nagios.cfg
dest: /etc/nagios4/conf.d/institute.cfg
notify: Reload NAGIOS4.
- name: Enable/Start NAGIOS4.
become: yes
systemd:
service: nagios4
enabled: yes
state: started
- name: Install backup script.
become: yes
copy:
src: ../private/backup
dest: /usr/local/sbin/backup
mode: u=rx,g=r,o=
- name: Install packages required by Nextcloud.
become: yes
apt:
pkg: [ apache2, mariadb-server, php, php-apcu, php-bcmath,
php-curl, php-gd, php-gmp, php-json, php-mysql,
php-mbstring, php-intl, php-imagick, php-xml, php-zip,
libapache2-mod-php ]
- name: Enable Apache2 modules for Nextcloud.
become: yes
apache2_module:
name: "{{ item }}"
loop: [ rewrite, headers, env, dir, mime ]
- name: Install Nextcloud web configuration.
become: yes
copy:
src: nextcloud.conf
dest: /etc/apache2/sites-available/nextcloud.conf
notify: Restart Apache2.
- name: Enable Nextcloud web configuration.
become: yes
command:
cmd: a2ensite nextcloud
creates: /etc/apache2/sites-enabled/nextcloud.conf
notify: Restart Apache2.
- name: Add {{ ansible_user }} to web server group.
become: yes
user:
name: "{{ ansible_user }}"
append: yes
groups: www-data
- name: Create Nextcloud cron job.
become: yes
cron:
minute: 11,26,41,56
job: >-
[ -r /var/www/nextcloud/cron.php ]
&& /usr/bin/php -f /var/www/nextcloud/cron.php
name: Nextcloud
user: www-data
- name: Link /var/www/nextcloud.
become: yes
file:
path: /var/www/nextcloud
src: /Nextcloud/nextcloud
state: link
force: yes
follow: no
- name: Set PHP memory_limit for Nextcloud.
become: yes
lineinfile:
path: /etc/php/8.2/apache2/php.ini
regexp: memory_limit *=
line: memory_limit = 768M
- name: Include PHP parameters for Nextcloud.
become: yes
copy:
content: |
; priority=20
apc.enable_cli=1
opcache.enable=1
opcache.enable_cli=1
opcache.interned_strings_buffer=12
opcache.max_accelerated_files=10000
opcache.memory_consumption=128
opcache.save_comments=1
opcache.revalidate_freq=1
dest: /etc/php/8.2/mods-available/nextcloud.ini
notify: Restart Apache2.
- name: Enable Nextcloud PHP modules.
become: yes
command:
cmd: phpenmod {{ item }}
creates: /etc/php/8.2/apache2/conf.d/20-{{ item }}.ini
loop: [ nextcloud, apcu ]
notify: Restart Apache2.
- name: Test for /Nextcloud/nextcloud/.
stat:
path: /Nextcloud/nextcloud
register: nextcloud
- debug:
msg: "/Nextcloud/ does not yet exist"
when: not nextcloud.stat.exists
- name: Configure Nextcloud trusted domains.
become: yes
replace:
path: /var/www/nextcloud/config/config.php
regexp: "^( *)'trusted_domains' *=>[^)]*[)],$"
replace: |-
\1'trusted_domains' =>
\1array (
\1 0 => 'core.{{ domain_priv }}',
\1),
when: nextcloud.stat.exists
- name: Configure Nextcloud dbpasswd.
become: yes
lineinfile:
path: /var/www/nextcloud/config/config.php
regexp: "^ *'dbpassword' *=> *'.*', *$"
line: " 'dbpassword' => '{{ nextcloud_dbpass }}',"
insertbefore: "^[)];"
firstmatch: yes
when: nextcloud.stat.exists
- name: Configure Nextcloud memcache.
become: yes
lineinfile:
path: /var/www/nextcloud/config/config.php
regexp: "^ *'memcache.local' *=> *'.*', *$"
line: " 'memcache.local' => '\\\\OC\\\\Memcache\\\\APCu',"
insertbefore: "^[)];"
firstmatch: yes
when: nextcloud.stat.exists
- name: Configure Nextcloud for Pretty URLs.
become: yes
lineinfile:
path: /var/www/nextcloud/config/config.php
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
insertbefore: "^[)];"
firstmatch: yes
vars:
url: http://core.{{ domain_priv }}/nextcloud
loop:
- regexp: "^ *'overwrite.cli.url' *=>"
line: " 'overwrite.cli.url' => '{{ url }}',"
- regexp: "^ *'htaccess.RewriteBase' *=>"
line: " 'htaccess.RewriteBase' => '/nextcloud',"
when: nextcloud.stat.exists
- name: Configure Nextcloud phone region.
become: yes
lineinfile:
path: /var/www/nextcloud/config/config.php
regexp: "^ *'default_phone_region' *=> *'.*', *$"
line: " 'default_phone_region' => '{{ nextcloud_region }}',"
insertbefore: "^[)];"
firstmatch: yes
when: nextcloud.stat.exists
- name: Create /Nextcloud/dbbackup.cnf.
no_log: yes
become: yes
copy:
content: |
[mysqldump]
no-tablespaces
single-transaction
host=localhost
user=nextclouduser
password={{ nextcloud_dbpass }}
dest: /Nextcloud/dbbackup.cnf
mode: g=,o=
force: no
when: nextcloud.stat.exists
- name: Update /Nextcloud/dbbackup.cnf password.
become: yes
lineinfile:
path: /Nextcloud/dbbackup.cnf
regexp: password=
line: password={{ nextcloud_dbpass }}
when: nextcloud.stat.exists
- name: Install institute passwd command.
become: yes
template:
src: passwd
dest: /usr/local/bin/passwd
mode: u=rwx,g=rx,o=rx
- name: Authorize institute passwd command as {{ ansible_user }}.
become: yes
copy:
content: |
ALL ALL=({{ ansible_user }}) NOPASSWD: /usr/local/bin/passwd
dest: /etc/sudoers.d/01passwd
mode: u=r,g=r,o=
owner: root
group: root
- name: Authorize {{ ansible_user }} to read /etc/shadow.
become: yes
user:
name: "{{ ansible_user }}"
append: yes
groups: shadow
- name: Authorize {{ ansible_user }} to run /usr/bin/php as www-data.
become: yes
copy:
content: |
{{ ansible_user }} ALL=(www-data) NOPASSWD: /usr/bin/php
dest: /etc/sudoers.d/01www-data-php
mode: u=r,g=r,o=
owner: root
group: root
- name: Install root PGP key file.
become: no
copy:
src: ../Secret/root-pub.pem
dest: ~/.gnupg-root-pub.pem
mode: u=r,g=r,o=r
notify: Import root PGP key.