Vue d’ensemble du code de provision des VMs
Maintenant que l’on a notre code pour l’infra, il est temps de passer à la partie provision des vms. Pour cela, comme je vous le disais, j’utilise Ansible. Pourquoi ? Parce qu’il est de plus en plus inclus dans l’écosystème RedHat, que la communauté autour du projet est très vivante et que l’on n’a aucun de mal à trouver des infos. Je vous rappelle que ce code met à disposition des serveurs dans un réseau isolé. Je vous montre l’arborescence des rôles et playbooks en fonction de mon architecture :
.
├── playbooks
│ ├── db.yml
│ ├── main.yml
│ ├── nc.yml
│ └── rd.yml
└── roles
├── common
│ ├── handlers
│ │ └── main.yml
│ └── tasks
│ └── main.yml
├── firewalld
│ ├── handlers
│ │ └── main.yml
│ └── tasks
│ └── main.yml
├── httpd
│ ├── handlers
│ │ └── main.yml
│ └── tasks
│ └── main.yml
├── mariadb
│ ├── handlers
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ ├── my.cnf.j2
│ └── mycnf.j2
├── nextcloud
│ ├── handlers
│ │ └── main.yml
│ ├── tasks
│ │ ├── fips.yml
│ │ ├── main.yml
│ │ ├── nextcloud_httpd.yml
│ │ ├── nextcloud_mariadb.yml
│ │ └── nextcloud_php.yml
│ ├── templates
│ │ ├── 10-opcache.ini.j2
│ │ ├── dhparams.pem.j2
│ │ ├── htaccess.j2
│ │ ├── httpd.conf.j2
│ │ ├── nextcloud.conf.j2
│ │ ├── php.ini.j2
│ │ ├── upgrade.sh.j2
│ │ └── www.conf.j2
│ └── vars
│ └── main.yml
├── php
│ ├── files
│ │ └── phpinfo.php
│ ├── handlers
│ │ └── main.yml
│ └── tasks
│ └── main.yml
└── redis
├── handlers
│ └── main.yml
├── tasks
│ └── main.yml
└── templates
└── redis.conf.j2
30 directories, 37 files
Pour ce qui est du durcissement, de la sécurité des souches, il existe un rôle mis à disposition par Openstack, basé sur les recommandations STIG, je vous le conseille : https://docs.openstack.org/ansible-hardening/latest/
Les playbooks
Je vais passer en revue les fichiers les plus importants. On commence par le fichier d’entrée, main.yml qui est lancé par terraform :
---
- hosts: all
become: yes
gather_facts: yes
tasks:
- name: Load variables
include_vars:
dir: ../roles/nextcloud/vars
name: main
extensions: [yml]
roles:
- role: common
- name: Include Redis play
import_playbook: rd.yml
- name: Include Mariadb play
import_playbook: db.yml
- name: Include Nextcloud play
import_playbook: nc.yml
...
On charge le fichier des variables que j’ai placé dans le répertoire vars du rôle nextcloud. On exécute le rôle common et ensuite on lance les différents playbooks pour redis, mariadb et l’application Nextcloud.
---
- name: Install Redis Server
hosts: lan_rd
become: true
vars:
list_open_ports: ["6379"]
roles:
- role: redis
- role: firewalld
...
Le playbook rd.yml va exécuter les rôles redis et firewalld sur le group lan_rd.
---
- name: Install DB Server for Nextcloud
hosts: lan_db
become: true
roles:
- role: mariadb
- role: firewalld
vars:
list_open_services: ["mysql"]
...
Même logique sur le groupe lan_db, mais cette fois pour mariadb.
---
- name: Install Nextcloud
hosts: lan_nc
become: true
vars:
list_open_services: ["http", "https"]
openssl_dhparam:
roles:
- role: httpd
- role: firewalld
- role: php
- role: nextcloud
...
Les rôles
Je ne vais pas m’attarder sur les rôles simples comme httpd, php, redis. Le plus important dans ces rôles est la configuration qui souvent se trouve dans un template.
common
Le rôle common s’applique sur l’ensemble des serveurs.
- name: yum-clean-metadata
command: yum clean metadata
args:
warn: no
---
- name: add epel repo
yum_repository:
name: epel
description: Extra Packages for Enterprise Linux 7 - $basearch
mirrorlist: https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch
gpgkey: https://getfedora.org/static/352C64E5.txt
enabled: yes
notify: yum-clean-metadata
- name: Install tools
dnf:
name: ['unzip', 'wget', 'bzip2', 'certbot', 'cronie', 'sysfsutils', 'setroubleshoot', 'mariadb']
state: latest
- name: Enable and start crond.service
service:
name: crond.service
state: started
enabled: yes
J’ai ajouté le repo EPEL, c’est inutile sauf si on veut par la suite installer des packages spécifiques. Vous pouvez retirer le bloc…
firewalld
---
- name: reload_firewall
command: firewall-cmd --reload
---
- name: Install firewalld package
dnf:
name: firewalld
state: latest
- name: Enable and start Firewalld
service:
name: firewalld
enabled: yes
state: started
- name: Get firewalld default zone
shell: firewall-cmd --get-default-zone
register: firewall_zone
changed_when: false
failed_when: false
- name: Get zone of interface eth0
shell: firewall-cmd --get-zone-of-interface=eth0
register: zone_of_interface
changed_when: false
failed_when: false
- name: Set add new interface to firewalld zone "{{ server_fw_zone | default('internal') }}"
command: firewall-cmd --permanent --zone="{{ server_fw_zone | default('internal') }}" --change-interface=eth0
when: '"internal" not in zone_of_interface.stdout'
- name: Set default zone to Firewalld
command: firewall-cmd --set-default-zone="{{ server_fw_zone | default('internal') }}"
when: '"internal" not in firewall_zone.stdout'
- name: Add ports in firewalld rules
firewalld:
zone: "{{ server_fw_zone | default('internal') }}"
port: "{{ item }}/tcp"
permanent: yes
immediate: yes
state: enabled
with_items:
- '{{ list_open_ports }}'
when: list_open_ports is defined
notify: reload_firewall
- name: Add services in firewall rules
firewalld:
zone: "{{ server_fw_zone | default('internal') }}"
service: "{{ item }}"
permanent: yes
immediate: yes
state: enabled
with_items:
- '{{ list_open_services }}'
when: list_open_services is defined
notify: reload_firewall
...
Pour le firewall, on ouvre les ports par numéro ou nom de service en l’indiquant dans une variable lors de l’appel au rôle.
redis
---
- name: 'restart_redis'
service: name=redis state=restarted
...
---
- name: Install Redis
dnf:
name: ['redis']
state: present
- name: Redis Installed Starting
service:
name: redis
state: started
enabled: yes
- name: Change redis conf to unixsocket
template:
src: redis.conf.j2
dest: /etc/redis.conf
owner: root
group: root
mode: '0644'
notify: restart_redis
- name: Checking overcommit memory
shell: 'cat /proc/sys/vm/overcommit_memory'
register: overcommit_memory
changed_when: false
failed_when: false
- name: Overcommit memory
sysctl:
name: vm.overcommit_memory
value: '1'
state: present
when: '"1" not in overcommit_memory.stdout'
tags: cf
- name: Increase max connections
sysctl:
name: net.core.somaxconn
value: '511'
state: present
tags: cf
- name: Disable THP
shell: echo never > /sys/kernel/mm/transparent_hugepage/enabled
notify: restart_redis
...
On place la configuration de redis qui va bien dans le template suivant :
bind {{ ansible_default_ipv4.address }}
protected-mode yes
port 6379
unixsocket /var/run/redis/redis.sock
unixsocketperm 775
maxclients 512
tcp-backlog 511
timeout 1.5
tcp-keepalive 300
daemonize yes
supervised no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile /var/log/redis/redis.log
databases 16
always-show-logo yes
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
replica-priority 100
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
mariadb
---
- name: restart_mariadb
service:
name: mariadb
state: restarted
---
- name: Install MariaDB package
dnf:
name: ['mariadb', 'mariadb-server', 'python3-PyMySQL']
state: latest
- name: Install Python for PyMariaDB package
dnf:
name: python3-PyMySQL
state: latest
- name: Start MariaDB Service
service:
name: mariadb
state: started
enabled: yes
- name: Configure MariaDB
template:
src: my.cnf.j2
dest: /etc/my.cnf
notify: restart_mariadb
- name: Generate new root password
command: openssl rand -hex 7 creates=/root/.my.cnf
register: mysql_new_root_pass
- name: Secure MariaDB -- remove anonymous user
mysql_user:
name: ''
host_all: yes
state: absent
login_unix_socket: "/var/lib/mysql/mysql.sock"
when: mysql_new_root_pass.changed
- name: Secure MariaDB -- remove test db
mysql_db:
name: test
state: absent
login_unix_socket: "/var/lib/mysql/mysql.sock"
when: mysql_new_root_pass.changed
- name: Output new root password
debug:
msg: "New root password is {{ mysql_new_root_pass.stdout }}"
when: mysql_new_root_pass.changed
- name: Update root password
mysql_user:
name: root
host_all: yes
password: "{{ mysql_new_root_pass.stdout }}"
login_unix_socket: "/var/lib/mysql/mysql.sock"
when: mysql_new_root_pass.changed
- name: Create my.cnf
template: src=mycnf.j2 dest=/root/.my.cnf
when: mysql_new_root_pass.changed
- name: Initialize nextcloud database
include_role:
name: nextcloud
tasks_from: nextcloud_mariadb
...
[client]
user=root
password={{ mysql_new_root_pass.stdout }}
[client]
default-character-set = utf8mb4
socket=/var/lib/mysql/mysql.sock
port = 3306
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
nice = 0
socket=/var/lib/mysql/mysql.sock
[mysqld]
basedir = /usr
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mariadb/mariadb.log
pid-file=/run/mariadb/mariadb.pid
bind-address = 0.0.0.0
port = 3306
binlog_format = ROW
bulk_insert_buffer_size = 16M
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
concurrent_insert = 2
connect_timeout = 5
default_storage_engine = InnoDB
expire_logs_days = 7
innodb_buffer_pool_size = 1024M
innodb_buffer_pool_instances = 1
innodb_flush_log_at_trx_commit = 2
innodb_log_buffer_size = 32M
innodb_max_dirty_pages_pct = 90
innodb_file_per_table = 1
innodb_open_files = 400
innodb_io_capacity = 4000
innodb_flush_method = O_DIRECT
innodb_large_prefix = true
innodb_file_format = barracuda
key_buffer_size = 128M
long_query_time = 1
max_allowed_packet = 16M
max_binlog_size = 100M
max_connections = 300
max_heap_table_size = 64M
myisam_recover_options = BACKUP
myisam_sort_buffer_size = 512M
port = 3306
query_cache_limit = 2M
query_cache_size = 64M
query_cache_type = 1
query_cache_min_res_unit = 2k
read_buffer_size = 2M
read_rnd_buffer_size = 1M
skip-external-locking
skip-name-resolve
sort_buffer_size = 4M
table_open_cache = 400
thread_cache_size = 128
tmp_table_size = 64M
tmpdir = /tmp
transaction_isolation = READ-COMMITTED
wait_timeout = 600
[mysqldump]
max_allowed_packet = 16M
quick
quote-names
[isamchk]
key_buffer = 16M
httpd
- name: httpd_restart
service:
name: httpd
state: restarted
---
- name: Installing Web Server
dnf:
name: [httpd, mod_ssl, openssl]
state: latest
- name: Web Server Installed Starting
service:
name: httpd
state: started
enabled: yes
- name: httpd Configuration for Nextcloud
include_role:
name: nextcloud
tasks_from: "nextcloud_httpd.yml"
...
php
---
- name: php_restart
service:
name: php-fpm
state: restarted
---
- name: Install PHP
dnf:
name: ['php', 'php-gd', 'php-common', 'php-dom', 'php-zlib', 'php-json', 'php-mbstring', 'php-intl', 'php-pecl-apcu', 'php-mysqlnd', 'php-pecl-redis', 'php-opcache', 'php-imagick', 'php-zip', 'php-process', 'php-pear', 'php-pdo_mysql', 'php-ctype']
state: present
- name: PHP Installed Starting
service:
name: php-fpm
state: started
enabled: yes
- name: Nextcloud specific php configuration
include_role:
name: nextcloud
tasks_from: nextcloud_php
...
nextcloud
Toute la configuration se trouve dedans le dernier rôle nextcloud.
---
- name: reboot
reboot:
reboot_timeout: 60
- name: httpd_restart
service:
name: httpd
state: restarted
- name: php_restart
service:
name: php-fpm
state: restarted
Pour FIPS ci-dessous, c’est facultatif…
---
- name: Install tools
dnf:
name: ['dracut-fips', 'dracut-fips-aesni']
state: latest
tags: fips
- name: Checking GRUB cmdline
shell: 'grep "fips=1" /etc/default/grub'
register: grub_cfg_grep
changed_when: false
failed_when: false
tags: fips
- name: Recreate initramfs file
command: dracut -f
when: '"fips=1" not in grub_cfg_grep.stdout'
tags: fips
- name: Find uuid of /boot
command: findmnt -no uuid /
register: boot_uuid
when: '"fips=1" not in grub_cfg_grep.stdout'
tags: fips
- name: Configuring GRUB cmdline
replace:
path: '/etc/default/grub'
regexp: '^GRUB_CMDLINE_LINUX="((\w.?)*)"$'
replace: 'GRUB_CMDLINE_LINUX="\1 boot=UUID={{ boot_uuid.stdout }} fips=1"'
when: '"fips=1" not in grub_cfg_grep.stdout'
tags: fips
- name: Reconfigure grub
command: grub2-mkconfig -o /boot/grub2/grub.cfg
when: '"fips=1" not in grub_cfg_grep.stdout'
tags: fips
notify: reboot
---
- name: Configure FIPS
include_tasks: fips.yml
tags: fips
when: fips | bool
- name: Test if nextcloud config exists
stat: path=/var/www/html/nextcloud/config/config.php
register: nc_config_stat
- name: Extract installer
unarchive:
src: "{{ nextcloud_url }}"
dest: /var/www/html/
remote_src: True
owner: apache
group: apache
when: not nc_config_stat.stat.exists
- name: Create Data Directory with permissions
file:
dest: "/var/nc_data"
owner: apache
group: apache
mode: 0775
state: directory
changed_when: false
- name: SELinux allow apache to modify files in differents directories
sefcontext:
target: "{{ item }}"
setype: httpd_sys_rw_content_t
state: present
with_items:
- '/var/www/html/nextcloud/config(/.*)?'
- '/var/nc_data(/.*)?'
- '/var/www/html/nextcloud/data(/.*)?'
- '/var/www/html/nextcloud/apps(/.*)?'
- '/var/www/nextcloud/assets(/.*)?'
- '/var/www/html/nextcloud/.htaccess'
- '/var/www/html/nextcloud/.user.ini'
- '/var/www/html/nextcloud/3rdparty/aws/aws-sdk-php/src/data/logs(/.*)?'
tags: selinux
- name: Set httpd_can_network_connect flag on and keep it persistent across reboots
seboolean:
name: "{{ item }}"
state: yes
persistent: yes
with_items:
- httpd_can_network_connect
- httpd_can_network_connect_db
- httpd_can_network_relay
- httpd_unified
- httpd_graceful_shutdown
- httpd_can_sendmail
- httpd_use_cifs
- httpd_use_fusefs
- httpd_use_gpg
- httpd_execmem
tags: selinux
- name: Configure httpd and selinux
shell: |
restorecon -Rv "{{ item }}"
with_items: ["/var/nc_data", "/var/www/html/nextcloud"]
# if you have trouble with php-fpm and selinux in this nextcloud configuration :
# # ausearch -c 'php-fpm' --raw | audit2allow -M my-phpfpm
# # semodule -X 300 -i my-phpfpm.pp
# # ausearch -c 'df' --raw | audit2allow -M my-df
# # semodule -X 300 -i my-df.pp
- name: Put SELinux in enforcing mode
selinux:
policy: targeted
state: "{{ selinux_state | default(enforcing) }}"
notify: reboot
tags: selinux
- name: Add a php cron task for apache
cron:
name: "php nextcloud tasks"
minute: "*/5"
job: "php -f /var/www/html/nextcloud/cron.php > /dev/null 2>&1"
user: apache
tags: cron
- name: Nextcloud silent installation
shell: |
sudo -u apache php occ maintenance:install --database="mysql" --database-name="{{ nextcloud_db }}" --database-host="{{ hostvars[groups['lan_db'][0]]['inventory_hostname'] }}" --database-user="{{ nextcloud_db_user }}" --database-pass="{{ nextcloud_db_password }}" --database-table-prefix="" --admin-user="{{ nextcloud_admin_user }}" --admin-pass="{{ nextcloud_admin_password }}" --data-dir "/var/nc_data"
sudo -u apache php occ config:system:set trusted_domains 1 --value="{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"
sudo -u apache php occ config:system:set trusted_domains 2 --value="{{ nextcloud_gateway }}"
sudo -u apache php occ config:system:set overwrite.cli.url --value=https://"{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"
sudo -u apache php occ background:cron
sudo -u apache php occ app:disable firstrunwizard
sudo -u apache php occ app:disable survey_client
sudo -u apache php occ app:install files_external
sudo -u apache php occ app:enable files_external
systemctl stop httpd
sudo -u apache php occ db:add-missing-indices
systemctl start httpd
args:
chdir: /var/www/html/nextcloud/
tags: install
when: not nc_config_stat.stat.exists
- name: Change conf in .htaccess file
notify: [httpd_restart, php_restart]
tags: htaccess
blockinfile:
path: /var/www/html/nextcloud/.htaccess
marker: "# {mark} ANSIBLE MANAGED BLOCK"
block: |
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]
RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]
RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff2?|ico|jpg|jpeg)$
RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$
RewriteCond %{REQUEST_FILENAME} !core/img/manifest.json$
RewriteCond %{REQUEST_FILENAME} !/remote.php
RewriteCond %{REQUEST_FILENAME} !/public.php
RewriteCond %{REQUEST_FILENAME} !/cron.php
RewriteCond %{REQUEST_FILENAME} !/core/ajax/update.php
RewriteCond %{REQUEST_FILENAME} !/status.php
RewriteCond %{REQUEST_FILENAME} !/ocs/v1.php
RewriteCond %{REQUEST_FILENAME} !/ocs/v2.php
RewriteCond %{REQUEST_FILENAME} !/robots.txt
RewriteCond %{REQUEST_FILENAME} !/updater/
RewriteCond %{REQUEST_FILENAME} !/ocs-provider/
RewriteCond %{REQUEST_URI} !^/\.well-known/(acme-challenge|pki-validation)/.*
RewriteRule . index.php [PT,E=PATH_INFO:$1]
RewriteBase /
<IfModule mod_env.c>
SetEnv front_controller_active true
<IfModule mod_dir.c>
DirectorySlash off
</IfModule>
</IfModule>
</IfModule>
- name: Adapt nextcloud configuration
blockinfile:
path: /var/www/html/nextcloud/config/config.php
marker: "// {mark} ANSIBLE MANAGED BLOCK"
insertbefore: \);$
block: |
'activity_expire_days' => 14,
'auth.bruteforce.protection.enabled' => true,
'blacklisted_files' =>
array (
0 => '.htaccess',
1 => 'Thumbs.db',
2 => 'thumbs.db',
),
'cron_log' => true,
'enable_previews' => true,
'enabledPreviewProviders' =>
array (
0 => 'OC\\Preview\\PNG',
1 => 'OC\\Preview\\JPEG',
2 => 'OC\\Preview\\GIF',
3 => 'OC\\Preview\\BMP',
4 => 'OC\\Preview\\XBitmap',
5 => 'OC\\Preview\\Movie',
6 => 'OC\\Preview\\PDF',
7 => 'OC\\Preview\\MP3',
8 => 'OC\\Preview\\TXT',
9 => 'OC\\Preview\\MarkDown',
),
'filesystem_check_changes' => 0,
'filelocking.enabled' => 'true',
'htaccess.RewriteBase' => '/',
'integrity.check.disabled' => false,
'knowledgebaseenabled' => false,
'logfile' => '/var/nc_data/nextcloud.log',
'loglevel' => 2,
'logtimezone' => 'Europe/Paris',
'log_rotate_size' => 104857600,
'maintenance' => false,
'memcache.local' => '\\OC\\Memcache\\APCu',
'memcache.locking' => '\\OC\\Memcache\\Redis',
'overwriteprotocol' => 'https',
'preview_max_x' => 1024,
'preview_max_y' => 768,
'preview_max_scale_factor' => 1,
'redis' =>
array (
'host' => '{{ hostvars[groups['lan_rd'][0]]['inventory_hostname'] }}',
'port' => 6379,
'dbindex' => 0,
'timeout' => 1.5,
),
'quota_include_external_storage' => false,
'share_folder' => '/Shares',
'skeletondirectory' => '',
'theme' => '',
'trashbin_retention_obligation' => 'auto, 7',
'updater.release.channel' => 'stable',
notify: [httpd_restart, php_restart]
tags: conf2
- name: adjust .user.ini
replace:
path: /var/www/html/nextcloud/.user.ini
regexp: '{{ item.regexp }}'
replace: '{{ item.replace }}'
backup: yes
with_items:
- { regexp: "output_buffering=.*", replace: "output_buffering='Off'" }
notify: [httpd_restart, php_restart]
tags: conf2
- debug:
msg: "{{ item }}"
with_items:
- "DataBase server's IP: {{ hostvars[groups['lan_db'][0]]['inventory_hostname'] }}"
- "Redis server's IP: {{ hostvars[groups['lan_rd'][0]]['inventory_hostname'] }}"
- "Nextcloud server's IP: {{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"
tags: ip
...
---
- name: Create ssl certificates Directory
file:
dest: "/etc/{{ item }}"
owner: root
group: root
state: directory
tags: cert
with_items:
- "{{ ansible_fqdn }}"
- "{{ ansible_fqdn }}/ssl"
- name: Generate an OpenSSL private key
openssl_privatekey:
path: /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.key
tags: cert
- name: Generate an OpenSSL CSR
openssl_csr:
path: /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.csr
privatekey_path: /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.key
common_name: "{{ ansible_fqdn }}"
tags: cert
- name: Generate a Self Signed OpenSSL certificate
openssl_certificate:
path: /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.crt
privatekey_path: /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.key
csr_path: /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.csr
provider: selfsigned
tags: cert
- name: Test if dhparam pem exists
stat: path=/etc/{{ ansible_fqdn }}/ssl/dhparams.pem
register: dhparam_stat
tags: cert
- name: Generate Diffie-Hellman parameters (2048 bits)
openssl_dhparam:
path: /etc/{{ ansible_fqdn }}/ssl/dhparams.pem
size: 2048 # 4096 warning it's a long time...
when: openssl_dhparam | default(false)
tags: cert
register: dhparam
- name: Import dhparams.pem
template:
src: dhparams.pem.j2
dest: /etc/{{ ansible_fqdn }}/ssl/dhparams.pem
owner: root
group: root
mode: '0600'
when: (not dhparam_stat.stat.exists or openssl_dhparam == "false")
tags: cert
- name: Create virtualhost
template:
src: nextcloud.conf.j2
dest: /etc/httpd/conf.d/nextcloud.conf
owner: root
group: root
mode: '0644'
notify: httpd_restart
- name: Change apache configuration
template:
src: httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
owner: root
group: root
mode: '0644'
notify: httpd_restart
...
---
- name: Create NextCloud database
mysql_db:
name: "{{ nextcloud_db }}"
encoding: utf8mb4
collation: utf8mb4_general_ci
state: present
- name: Create NextCloud database user on localhost
mysql_user:
name: "{{ nextcloud_db_user }}"
password: "{{ nextcloud_db_password }}"
priv: "nextcloud.*:ALL,GRANT"
host: "localhost"
login_unix_socket: "/var/lib/mysql/mysql.sock"
state: present
- name: Create NextCloud database user on all hosts
mysql_user:
name: "{{ nextcloud_db_user }}"
password: "{{ nextcloud_db_password }}"
priv: "nextcloud.*:ALL,GRANT"
host: "%"
state: present
login_unix_socket: "/var/lib/mysql/mysql.sock"
notify: restart_mariadb
...
---
- name: Change PHP conf
template:
src: php.ini.j2
dest: /etc/php.ini
owner: root
group: root
mode: '0644'
notify: php_restart
- name: Change PHP opcache conf
template:
src: 10-opcache.ini.j2
dest: /etc/php.d/10-opcache.ini
owner: root
group: root
mode: '0644'
notify: php_restart
- name: Change PHP www.conf
template:
src: www.conf.j2
dest: /etc/php-fpm.d/www.conf
owner: root
group: root
mode: '0644'
notify: php_restart
...
et les templates des fichiers de configuration qui vont bien :
zend_extension=opcache
memory_limit = 512M
output_buffering = 'Off'
max_execution_time = 1800
max_input_time = 3600
post_max_size = 10240M
upload_max_filesize = 10240M
max_file_uploads = 100
session.cookie_secure = True
opcache.enable=1
opcache.enable_cli=1
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.memory_consumption=128
opcache.save_comments=1
opcache.revalidate_freq=1
Pour le .pem ci-dessous, uniquement pour les tests. Sinon il faut la créer.
-----BEGIN DH PARAMETERS-----
MIICCAKCAgEA8Yl4SFYf4byMREbYhLkzoFGjSshYlhc1vKeIH+7XjJD3dH7YIG2A
4F+3mKEa1HqG88WvPOqRCA+N4JDtQKHpHSjkQfBmhb9SHywOsv/DJmWKytRemp91
0PZvaMac9F7zToLLPctUjR3CFvVUWjv4qWov2eFNTNvLGmKbEz8PXQosMEEhFnQ2
N94FOPnhpdZ4nsfHLSvdXUrKUuoR3fT8C3lBCznpzSamHUPT4XnlQd32q/Lfdh5x
+IKBtf0cJLaRI4dHRgGCZUAcS1L5sjtcC4UrOb/2A1sYF7LGPUzUU6SV01o1kuaV
HqiqMiIXJBVdH1OmYv00W7fbq/U2dSbFyEeIAUlIe1G8EFntfJV+HNICe2+Wbavs
jouztf2I6OQEpHVRws51Bne1Zk7m2JWerXsv8JRkCrvgrTsYQMlFMYKAmuzBL4j/
eoWjc8UGopTw1RmbUbSzrDMlFvQ0W32qM1nm6SVOht86Huc+D6nkXra/b12WUqI3
yPwyA/RN9V3XwvWuseBXg3NAg2caHQT9A7nd8pB5fRXLVcIeBvj+L04LsR7oCaSN
RpLVPlATwQsMIG4l36Qh+w4YynAdzN0qnCjq7gMXetLtniZ2gQKKa5Ofp+ldxg2t
Fpjvx7qgiWjf+phGedOw/49suUbM5UZTQ+qOxtskEyfX/PVzgKV6aRMCAQI=
-----END DH PARAMETERS-----
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]
RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]
RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff2?|ico|jpg|jpeg)$
RewriteCond %{REQUEST_FILENAME} !core/img/favicon.ico$
RewriteCond %{REQUEST_FILENAME} !core/img/manifest.json$
RewriteCond %{REQUEST_FILENAME} !/remote.php
RewriteCond %{REQUEST_FILENAME} !/public.php
RewriteCond %{REQUEST_FILENAME} !/cron.php
RewriteCond %{REQUEST_FILENAME} !/core/ajax/update.php
RewriteCond %{REQUEST_FILENAME} !/status.php
RewriteCond %{REQUEST_FILENAME} !/ocs/v1.php
RewriteCond %{REQUEST_FILENAME} !/ocs/v2.php
RewriteCond %{REQUEST_FILENAME} !/robots.txt
RewriteCond %{REQUEST_FILENAME} !/updater/
RewriteCond %{REQUEST_FILENAME} !/ocs-provider/
RewriteCond %{REQUEST_URI} !^/\.well-known/(acme-challenge|pki-validation)/.*
RewriteRule . index.php [PT,E=PATH_INFO:$1]
RewriteBase /
<IfModule mod_env.c>
SetEnv front_controller_active true
<IfModule mod_dir.c>
DirectorySlash off
</IfModule>
</IfModule>
</IfModule>
ServerRoot "/etc/httpd"
Listen 80
Include conf.modules.d/*.conf
User apache
Group apache
ServerAdmin root@localhost
ServerName {{ ansible_fqdn }}
<Directory />
AllowOverride none
Require all denied
</Directory>
DocumentRoot "/var/www/html"
<Directory "/var/www">
AllowOverride None
Require all granted
</Directory>
<Directory "/var/www/html">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>
<Files ".ht*">
Require all denied
</Files>
ErrorLog "logs/error_log"
LogLevel warn
<IfModule log_config_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
<IfModule logio_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>
CustomLog "logs/access_log" combined
</IfModule>
<IfModule http2_module>
Protocols h2 h2c http/1.1
H2Direct on
H2StreamMaxMemSize 5120000000
</IfModule>
<IfModule prefork.c>
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 150
MaxConnectionsPerChild 1000
</IfModule>
<IfModule mpm_event_module>
StartServers 2
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 150
MaxConnectionsPerChild 1000
</IfModule>
<IfModule alias_module>
ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
</IfModule>
<Directory "/var/www/cgi-bin">
AllowOverride None
Options None
Require all granted
</Directory>
<IfModule mime_module>
TypesConfig /etc/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
</IfModule>
AddDefaultCharset UTF-8
<IfModule mime_magic_module>
MIMEMagicFile conf/magic
</IfModule>
EnableSendfile on
ServerTokens Prod
ServerSignature Off
TraceEnable Off
IncludeOptional conf.d/*.conf
<VirtualHost *:80>
ServerName {{ ansible_fqdn }}
ServerAdmin admin@{{ ansible_fqdn }}
RewriteEngine On
RewriteCond %{SERVER_NAME} ={{ ansible_fqdn }}
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
<IfModule mod_ssl.c>
<VirtualHost *:443>
SSLEngine on
SSLOptions +StrictRequire
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
ServerName {{ ansible_fqdn }}
ServerAdmin admin@{{ ansible_fqdn }}
DocumentRoot /var/www/html/nextcloud
SSLCertificateFile /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.crt
SSLCertificateKeyFile /etc/{{ ansible_fqdn }}/ssl/{{ ansible_fqdn }}.key
<Directory /var/www/html/nextcloud/>
Options +FollowSymlinks
AllowOverride All
<IfModule mod_dav.c>
Dav off
</IfModule>
SetEnv HOME /var/www/html/nextcloud
SetEnv HTTP_HOME /var/www/html/nextcloud
</Directory>
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=15768000; preload"
</IfModule>
</VirtualHost>
SSLProtocol -all +TLSv1.3 +TLSv1.2
SSLCipherSuite TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder on
SSLCompression off
SSLSessionTickets off
SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLStaplingCache shmcb:/var/run/ocsp(128000)
SSLOpenSSLConfCmd Curves X448:secp521r1:secp384r1:prime256v1
SSLOpenSSLConfCmd ECDHParameters secp384r1
SSLOpenSSLConfCmd DHParameters "/etc/{{ ansible_fqdn }}/ssl/dhparams.pem"
SSLRandomSeed startup file:/dev/urandom 1024
SSLRandomSeed connect file:/dev/urandom 1024
</IfModule>
[PHP]
engine = On
short_open_tag = Off
precision = 14
output_buffering = 'Off'
zlib.output_compression = Off
unserialize_callback_func =
serialize_precision = -1
disable_functions =
zend.enable_gc = On
expose_php = On
max_execution_time = 1800
max_input_time = 3600
post_max_size = 10240M
upload_max_filesize = 10240M
max_file_uploads = 100
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
html_errors = On
auto_globals_jit = On
auto_prepend_file =
auto_append_file =
enable_dl = Off
file_uploads = On
allow_url_fopen = On
allow_url_include = Off
cli_server.color = On
[iconv]
[intl]
[mail function]
sendmail_path = /usr/sbin/sendmail -t -i
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultbinmode = 1
[Interbase]
ibase.allow_persistent = 1
ibase.max_persistent = -1
ibase.max_links = -1
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = Off
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[Session]
session.save_handler = files
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_secure = True
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.cookie_samesite =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.sid_length = 26
session.trans_sid_tags = "a=href,area=href,frame=src,form="
session.sid_bits_per_character = 5
[Assertion]
zend.assertions = -1
[mbstring]
tidy.clean_output = Off
soap.wsdl_cache_enabled=1
ldap.max_links = -1
[openssl]
[www]
user = apache
group = apache
listen = /run/php-fpm/www.sock
listen.acl_users = apache,nginx
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 120
pm.start_servers = 12
pm.min_spare_servers = 6
pm.max_spare_servers = 18
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/session
php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache
Pour terminer cet article, le répertoire des variables, à adapter bien sûr :
nextcloud_url: "https://download.nextcloud.com/server/releases/latest.tar.bz2"
nextcloud_db: "nextcloud"
nextcloud_db_password: "pas!sD234"
nextcloud_db_user: "ncuser"
nextcloud_admin_user: "admin"
nextcloud_admin_password: "pas!sD234"
nextcloud_gateway: "192.168.1.254"
selinux_state: "enforcing"
fips: false
C’est terminé.
Bon Hacking !
Quel travail de ouf… Bravo
Merci @Pascal, il faudrait que je le mette à jour cet article… dès que j’aurai le temps