--- - 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.