initial upload
This commit is contained in:
60
roles/apache/defaults/main.yml
Normal file
60
roles/apache/defaults/main.yml
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
|
||||
apache_consul_service: "{{ consul_services|default(False) }}"
|
||||
|
||||
apache_mpm_prefork: true
|
||||
|
||||
apache_timeout: 30
|
||||
|
||||
apache_monitoring_ips: "{{ (nagios_nrpe_monitoring_ips|default([]) + firewall_monitoring_ips|default([])) | join(' ') }}"
|
||||
|
||||
apache_mod_ssl_protocols: all -SSLv2 -SSLv3 -TLSv1
|
||||
apache_mod_ssl_ciphers:
|
||||
- ECDHE-RSA-AES128-GCM-SHA256
|
||||
- ECDHE-ECDSA-AES128-GCM-SHA256
|
||||
- ECDHE-RSA-AES256-GCM-SHA384
|
||||
- ECDHE-ECDSA-AES256-GCM-SHA384
|
||||
- ECDHE-RSA-CHACHA20-POLY1305
|
||||
- ECDHE-ECDSA-CHACHA20-POLY1305
|
||||
- ECDHE-RSA-AES128-SHA256
|
||||
- ECDHE-ECDSA-AES128-SHA256
|
||||
- ECDHE-RSA-AES256-SHA384
|
||||
- ECDHE-ECDSA-AES256-SHA384
|
||||
- ECDHE-RSA-AES128-SHA
|
||||
- ECDHE-ECDSA-AES128-SHA
|
||||
- ECDHE-RSA-AES256-SHA
|
||||
- ECDHE-ECDSA-AES256-SHA
|
||||
- DHE-RSA-AES128-GCM-SHA256
|
||||
- DHE-RSA-AES256-GCM-SHA384
|
||||
- DHE-RSA-AES128-SHA256
|
||||
- DHE-RSA-AES256-SHA256
|
||||
- DHE-RSA-AES128-SHA
|
||||
- DHE-RSA-AES256-SHA
|
||||
# - AES128-GCM-SHA256
|
||||
# - AES256-GCM-SHA384
|
||||
# - AES128-SHA256
|
||||
# - AES256-SHA256
|
||||
# - AES128-SHA
|
||||
# - AES256-SHA
|
||||
|
||||
apache_http2_enabled: on
|
||||
|
||||
apache_firewall: yes
|
||||
apache_firewall_public: yes
|
||||
apache_firewall_public_isolated: no
|
||||
apache_firewall_acl: []
|
||||
apache_firewall_drop_dst: []
|
||||
|
||||
apache_security_headers: false
|
||||
|
||||
apache_mod_evasive: off
|
||||
apache_mod_evasive_settings:
|
||||
DOSHashTableSize: 3097
|
||||
DOSPageCount: 20
|
||||
DOSSiteCount: 100
|
||||
DOSPageInterval: 2
|
||||
DOSSiteInterval: 1
|
||||
DOSBlockingPeriod: 10
|
||||
|
||||
apache_mod_security: "{{ apache_firewall_public }}"
|
||||
apache_mod_security_enabled: false
|
||||
11
roles/apache/handlers/main.yml
Normal file
11
roles/apache/handlers/main.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
|
||||
- name: Restart Apache
|
||||
service: name=apache2 state=restarted
|
||||
|
||||
- name: Reload Apache
|
||||
service: name=apache2 state=reloaded
|
||||
|
||||
- name: Reload Apache systemd
|
||||
systemd: daemon_reload=yes
|
||||
|
||||
8
roles/apache/meta/main.yml
Normal file
8
roles/apache/meta/main.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
|
||||
dependencies:
|
||||
- role: firewall
|
||||
when: apache_firewall
|
||||
|
||||
- role: consul
|
||||
when: apache_consul_service
|
||||
164
roles/apache/tasks/main.yml
Normal file
164
roles/apache/tasks/main.yml
Normal file
@@ -0,0 +1,164 @@
|
||||
---
|
||||
|
||||
- name: Install Apache packages
|
||||
apt:
|
||||
pkg:
|
||||
- apache2
|
||||
- socat
|
||||
state: present
|
||||
tags: packages
|
||||
|
||||
- name: Ensure the ssl-cert group exists
|
||||
group:
|
||||
name: ssl-cert
|
||||
system: yes
|
||||
tags: packages
|
||||
|
||||
- name: Ensure apache is a member of ssl-cert
|
||||
user:
|
||||
name: www-data
|
||||
groups: ssl-cert
|
||||
append: yes
|
||||
tags: packages
|
||||
|
||||
- name: Install Apache config
|
||||
template:
|
||||
dest: /etc/apache2/apache2.conf
|
||||
src: etc_apache2_apache2.conf.j2
|
||||
mode: 0644
|
||||
owner: root
|
||||
group: root
|
||||
notify: Reload Apache
|
||||
tags: configs
|
||||
|
||||
- name: Install Apache module configs
|
||||
template:
|
||||
dest: "/etc/apache2/mods-available/{{ item }}"
|
||||
src: "etc_apache2_mods-available_{{ item }}.j2"
|
||||
mode: 0644
|
||||
owner: root
|
||||
group: root
|
||||
with_items:
|
||||
- deflate.conf
|
||||
- http2.conf
|
||||
- ssl.conf
|
||||
- status.conf
|
||||
notify: Reload Apache
|
||||
tags:
|
||||
- configs
|
||||
- apache-configs
|
||||
|
||||
- name: Enable Apache modules
|
||||
apache2_module:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
force: yes
|
||||
with_items:
|
||||
- deflate
|
||||
- env
|
||||
- expires
|
||||
- headers
|
||||
- http2
|
||||
- reqtimeout
|
||||
- rewrite
|
||||
- setenvif
|
||||
- ssl
|
||||
- status
|
||||
- unique_id
|
||||
notify: Restart Apache
|
||||
tags: configs
|
||||
|
||||
- name: Install Apache other configs
|
||||
template:
|
||||
dest: "/etc/apache2/conf-available/{{ item }}"
|
||||
src: "etc_apache2_conf-available_{{ item }}.j2"
|
||||
with_items:
|
||||
- logging.conf
|
||||
- security.conf
|
||||
notify: Reload Apache
|
||||
tags: [configs, logging]
|
||||
|
||||
- name: Enable Apache other configs
|
||||
command: "a2enconf {{ item }}"
|
||||
args:
|
||||
creates: "/etc/apache2/conf-enabled/{{ item }}"
|
||||
with_items:
|
||||
- logging.conf
|
||||
- security.conf
|
||||
notify: Reload Apache
|
||||
tags: configs
|
||||
|
||||
- name: Enable the SSL default vhost
|
||||
command: a2ensite default-ssl
|
||||
args:
|
||||
creates: /etc/apache2/sites-enabled/default-ssl.conf
|
||||
notify: Reload Apache
|
||||
tags: configs
|
||||
|
||||
- name: Install Apache logrotate snippet
|
||||
template:
|
||||
dest: /etc/logrotate.d/apache2
|
||||
src: etc_logrotate.d_apache2.j2
|
||||
mode: 0644
|
||||
owner: root
|
||||
group: root
|
||||
tags: [configs, logrotate]
|
||||
|
||||
- name: Install apache2.service override dir
|
||||
file:
|
||||
dest: /etc/systemd/system/apache2.service.d
|
||||
state: directory
|
||||
mode: 0755
|
||||
owner: root
|
||||
group: root
|
||||
tags: [configs, systemd]
|
||||
|
||||
- name: Install apache2.service override
|
||||
template:
|
||||
dest: /etc/systemd/system/apache2.service.d/local.conf
|
||||
src: etc_systemd_system_apache2.service.d_local.conf.j2
|
||||
mode: 0644
|
||||
owner: root
|
||||
group: root
|
||||
notify: Reload Apache systemd
|
||||
tags: [configs, systemd]
|
||||
|
||||
- name: Ensure Apache is running
|
||||
systemd:
|
||||
name: apache2
|
||||
state: started
|
||||
enabled: yes
|
||||
tags: configs
|
||||
|
||||
- include: mod_evasive.yml
|
||||
when: apache_mod_evasive
|
||||
tags: mod_evasive
|
||||
|
||||
- include: mod_security.yml
|
||||
when: apache_mod_security
|
||||
tags: mod_security
|
||||
|
||||
- name: Install the Apache firewall config
|
||||
template:
|
||||
dest: "/etc/firewall/{{ item }}"
|
||||
src: "etc_firewall_{{ item | replace('/', '_') }}.j2"
|
||||
mode: 0600
|
||||
owner: root
|
||||
group: root
|
||||
when: firewall_enabled and apache_firewall
|
||||
notify: Restart firewall
|
||||
with_items:
|
||||
- rules-v4.d/40_apache.sh
|
||||
- rules-v6.d/40_apache.sh
|
||||
tags:
|
||||
- configs
|
||||
- firewall
|
||||
|
||||
- name: Register the apache service in Consul
|
||||
template:
|
||||
dest: /etc/consul.d/service-apache.hcl
|
||||
src: etc_consul.d_service-apache.hcl.j2
|
||||
when: apache_consul_service
|
||||
notify: Reload consul
|
||||
tags: configs
|
||||
|
||||
27
roles/apache/tasks/mod_evasive.yml
Normal file
27
roles/apache/tasks/mod_evasive.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
|
||||
- name: Install Apache mod_evasive
|
||||
apt:
|
||||
pkg:
|
||||
- libapache2-mod-evasive
|
||||
state: present
|
||||
notify: Restart Apache
|
||||
tags: packages
|
||||
|
||||
- name: Install Apache mod_evasive config
|
||||
template:
|
||||
dest: /etc/apache2/mods-available/evasive.conf
|
||||
src: etc_apache2_mods-available_evasive.conf.j2
|
||||
mode: 0644
|
||||
owner: root
|
||||
group: root
|
||||
notify: Reload Apache
|
||||
tags: configs
|
||||
|
||||
- name: Enable Apache mod_evasive
|
||||
apache2_module:
|
||||
name: evasive
|
||||
state: present
|
||||
force: yes
|
||||
notify: Restart Apache
|
||||
tags: configs
|
||||
38
roles/apache/tasks/mod_security.yml
Normal file
38
roles/apache/tasks/mod_security.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
|
||||
- name: Install Apache mod_security
|
||||
apt:
|
||||
pkg:
|
||||
- libapache2-mod-security2=2.9.*
|
||||
- modsecurity-crs=3.*
|
||||
state: present
|
||||
notify: Restart Apache
|
||||
tags: packages
|
||||
|
||||
- name: Install Apache mod_security config
|
||||
template:
|
||||
dest: /etc/modsecurity/modsecurity.conf
|
||||
src: etc_modsecurity_modsecurity.conf.j2
|
||||
mode: 0644
|
||||
owner: root
|
||||
group: root
|
||||
notify: Reload Apache
|
||||
tags: configs
|
||||
|
||||
- name: Install Apache mod_security ruleset config
|
||||
template:
|
||||
dest: /etc/modsecurity/crs/crs-setup.conf
|
||||
src: etc_modsecurity_crs_crs-setup.conf.j2
|
||||
mode: 0644
|
||||
owner: root
|
||||
group: root
|
||||
notify: Reload Apache
|
||||
tags: configs
|
||||
|
||||
- name: Enable Apache mod_security
|
||||
apache2_module:
|
||||
name: security2
|
||||
state: present
|
||||
force: yes
|
||||
notify: Restart Apache
|
||||
tags: configs
|
||||
233
roles/apache/templates/etc_apache2_apache2.conf.j2
Normal file
233
roles/apache/templates/etc_apache2_apache2.conf.j2
Normal file
@@ -0,0 +1,233 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# This is the main Apache server configuration file. It contains the
|
||||
# configuration directives that give the server its instructions.
|
||||
# See http://httpd.apache.org/docs/2.4/ for detailed information about
|
||||
# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
|
||||
# hints.
|
||||
#
|
||||
#
|
||||
# Summary of how the Apache 2 configuration works in Debian:
|
||||
# The Apache 2 web server configuration in Debian is quite different to
|
||||
# upstream's suggested way to configure the web server. This is because Debian's
|
||||
# default Apache2 installation attempts to make adding and removing modules,
|
||||
# virtual hosts, and extra configuration directives as flexible as possible, in
|
||||
# order to make automating the changes and administering the server as easy as
|
||||
# possible.
|
||||
|
||||
# It is split into several files forming the configuration hierarchy outlined
|
||||
# below, all located in the /etc/apache2/ directory:
|
||||
#
|
||||
# /etc/apache2/
|
||||
# |-- apache2.conf
|
||||
# | `-- ports.conf
|
||||
# |-- mods-enabled
|
||||
# | |-- *.load
|
||||
# | `-- *.conf
|
||||
# |-- conf-enabled
|
||||
# | `-- *.conf
|
||||
# `-- sites-enabled
|
||||
# `-- *.conf
|
||||
#
|
||||
#
|
||||
# * apache2.conf is the main configuration file (this file). It puts the pieces
|
||||
# together by including all remaining configuration files when starting up the
|
||||
# web server.
|
||||
#
|
||||
# * ports.conf is always included from the main configuration file. It is
|
||||
# supposed to determine listening ports for incoming connections which can be
|
||||
# customized anytime.
|
||||
#
|
||||
# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
|
||||
# directories contain particular configuration snippets which manage modules,
|
||||
# global configuration fragments, or virtual host configurations,
|
||||
# respectively.
|
||||
#
|
||||
# They are activated by symlinking available configuration files from their
|
||||
# respective *-available/ counterparts. These should be managed by using our
|
||||
# helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
|
||||
# their respective man pages for detailed information.
|
||||
#
|
||||
# * The binary is called apache2. Due to the use of environment variables, in
|
||||
# the default configuration, apache2 needs to be started/stopped with
|
||||
# /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
|
||||
# work with the default configuration.
|
||||
|
||||
|
||||
# Global configuration
|
||||
#
|
||||
|
||||
#
|
||||
# ServerRoot: The top of the directory tree under which the server's
|
||||
# configuration, error, and log files are kept.
|
||||
#
|
||||
# NOTE! If you intend to place this on an NFS (or otherwise network)
|
||||
# mounted filesystem then please read the Mutex documentation (available
|
||||
# at <URL:http://httpd.apache.org/docs/2.4/mod/core.html#mutex>);
|
||||
# you will save yourself a lot of trouble.
|
||||
#
|
||||
# Do NOT add a slash at the end of the directory path.
|
||||
#
|
||||
#ServerRoot "/etc/apache2"
|
||||
|
||||
#
|
||||
# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
|
||||
#
|
||||
#Mutex file:${APACHE_LOCK_DIR} default
|
||||
|
||||
#
|
||||
# The directory where shm and other runtime files will be stored.
|
||||
#
|
||||
|
||||
DefaultRuntimeDir ${APACHE_RUN_DIR}
|
||||
|
||||
#
|
||||
# PidFile: The file in which the server should record its process
|
||||
# identification number when it starts.
|
||||
# This needs to be set in /etc/apache2/envvars
|
||||
#
|
||||
PidFile ${APACHE_PID_FILE}
|
||||
|
||||
#
|
||||
# Timeout: The number of seconds before receives and sends time out.
|
||||
#
|
||||
Timeout {{ apache_timeout }}
|
||||
|
||||
#
|
||||
# KeepAlive: Whether or not to allow persistent connections (more than
|
||||
# one request per connection). Set to "Off" to deactivate.
|
||||
#
|
||||
KeepAlive On
|
||||
|
||||
#
|
||||
# MaxKeepAliveRequests: The maximum number of requests to allow
|
||||
# during a persistent connection. Set to 0 to allow an unlimited amount.
|
||||
# We recommend you leave this number high, for maximum performance.
|
||||
#
|
||||
MaxKeepAliveRequests 100
|
||||
|
||||
#
|
||||
# KeepAliveTimeout: Number of seconds to wait for the next request from the
|
||||
# same client on the same connection.
|
||||
#
|
||||
KeepAliveTimeout 5
|
||||
|
||||
|
||||
# These need to be set in /etc/apache2/envvars
|
||||
User ${APACHE_RUN_USER}
|
||||
Group ${APACHE_RUN_GROUP}
|
||||
|
||||
#
|
||||
# HostnameLookups: Log the names of clients or just their IP addresses
|
||||
# e.g., www.apache.org (on) or 204.62.129.132 (off).
|
||||
# The default is off because it'd be overall better for the net if people
|
||||
# had to knowingly turn this feature on, since enabling it means that
|
||||
# each client request will result in AT LEAST one lookup request to the
|
||||
# nameserver.
|
||||
#
|
||||
HostnameLookups Off
|
||||
|
||||
# ErrorLog: The location of the error log file.
|
||||
# If you do not specify an ErrorLog directive within a <VirtualHost>
|
||||
# container, error messages relating to that virtual host will be
|
||||
# logged here. If you *do* define an error logfile for a <VirtualHost>
|
||||
# container, that host's errors will be logged there and not here.
|
||||
#
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
|
||||
#
|
||||
# LogLevel: Control the severity of messages logged to the error_log.
|
||||
# Available values: trace8, ..., trace1, debug, info, notice, warn,
|
||||
# error, crit, alert, emerg.
|
||||
# It is also possible to configure the log level for particular modules, e.g.
|
||||
# "LogLevel info ssl:warn"
|
||||
#
|
||||
LogLevel warn
|
||||
|
||||
# Include module configuration:
|
||||
IncludeOptional mods-enabled/*.load
|
||||
IncludeOptional mods-enabled/*.conf
|
||||
|
||||
# Include list of ports to listen on
|
||||
Include ports.conf
|
||||
|
||||
|
||||
# Sets the default security model of the Apache2 HTTPD server. It does
|
||||
# not allow access to the root filesystem outside of /usr/share and /var/www.
|
||||
# The former is used by web applications packaged in Debian,
|
||||
# the latter may be used for local directories served by the web server. If
|
||||
# your system is serving content from a sub-directory in /srv you must allow
|
||||
# access here, or in any related virtual host.
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all denied
|
||||
</Directory>
|
||||
|
||||
<Directory /usr/share>
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<Directory /var/www/>
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<Directory /srv/www>
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
<Directory /opt/kc>
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
|
||||
# AccessFileName: The name of the file to look for in each directory
|
||||
# for additional configuration directives. See also the AllowOverride
|
||||
# directive.
|
||||
#
|
||||
AccessFileName .htaccess
|
||||
|
||||
#
|
||||
# The following lines prevent dot files from being
|
||||
# viewed by Web clients.
|
||||
#
|
||||
<FilesMatch "^\.(?!well-known)">
|
||||
Require all denied
|
||||
</FilesMatch>
|
||||
|
||||
|
||||
#
|
||||
# The following directives define some format nicknames for use with
|
||||
# a CustomLog directive.
|
||||
#
|
||||
# These deviate from the Common Log Format definitions in that they use %O
|
||||
# (the actual bytes sent including headers) instead of %b (the size of the
|
||||
# requested file), because the latter makes it impossible to detect partial
|
||||
# requests.
|
||||
#
|
||||
# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
|
||||
# Use mod_remoteip instead.
|
||||
#
|
||||
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
|
||||
LogFormat "%h %l %u %t \"%r\" %>s %O" common
|
||||
LogFormat "%{Referer}i -> %U" referer
|
||||
LogFormat "%{User-agent}i" agent
|
||||
|
||||
# Include of directories ignores editors' and dpkg's backup files,
|
||||
# see README.Debian for details.
|
||||
|
||||
# Include generic snippets of statements
|
||||
IncludeOptional conf-enabled/*.conf
|
||||
|
||||
# Include the virtual host configurations:
|
||||
IncludeOptional sites-enabled/*.conf
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,7 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# BufferedLogs On
|
||||
|
||||
LogFormat "%v:%p %R %m %>s %H conn=%X %D %O %I %k" metrics
|
||||
|
||||
GlobalLog ${APACHE_LOG_DIR}/metrics.log metrics
|
||||
@@ -0,0 +1,88 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
#
|
||||
# Disable access to the entire file system except for the directories that
|
||||
# are explicitly allowed later.
|
||||
#
|
||||
# This currently breaks the configurations that come with some web application
|
||||
# Debian packages.
|
||||
#
|
||||
<Directory />
|
||||
AllowOverride None
|
||||
Require all denied
|
||||
</Directory>
|
||||
|
||||
|
||||
# Changing the following options will not really affect the security of the
|
||||
# server, but might make attacks slightly more difficult in some cases.
|
||||
|
||||
#
|
||||
# ServerTokens
|
||||
# This directive configures what you return as the Server HTTP response
|
||||
# Header. The default is 'Full' which sends information about the OS-Type
|
||||
# and compiled in modules.
|
||||
# Set to one of: Full | OS | Minimal | Minor | Major | Prod
|
||||
# where Full conveys the most information, and Prod the least.
|
||||
ServerTokens Prod
|
||||
#ServerTokens OS
|
||||
#ServerTokens Full
|
||||
|
||||
#
|
||||
# Optionally add a line containing the server version and virtual host
|
||||
# name to server-generated pages (internal error documents, FTP directory
|
||||
# listings, mod_status and mod_info output etc., but not CGI generated
|
||||
# documents or custom error documents).
|
||||
# Set to "EMail" to also include a mailto: link to the ServerAdmin.
|
||||
# Set to one of: On | Off | EMail
|
||||
ServerSignature Off
|
||||
#ServerSignature On
|
||||
|
||||
#
|
||||
# Allow TRACE method
|
||||
#
|
||||
# Set to "extended" to also reflect the request body (only for testing and
|
||||
# diagnostic purposes).
|
||||
#
|
||||
# Set to one of: On | Off | extended
|
||||
TraceEnable Off
|
||||
#TraceEnable On
|
||||
|
||||
#
|
||||
# Forbid access to version control directories
|
||||
#
|
||||
# If you use version control systems in your document root, you should
|
||||
# probably deny access to their directories. For example, for subversion:
|
||||
#
|
||||
<DirectoryMatch "/\.(git|svn|subversion)">
|
||||
Require all denied
|
||||
</DirectoryMatch>
|
||||
|
||||
#
|
||||
# Setting this header will prevent MSIE from interpreting files as something
|
||||
# else than declared by the content type in the HTTP headers.
|
||||
# Requires mod_headers to be enabled.
|
||||
#
|
||||
#Header set X-Content-Type-Options: "nosniff"
|
||||
|
||||
#
|
||||
# Setting this header will prevent other sites from embedding pages from this
|
||||
# site as frames. This defends against clickjacking attacks.
|
||||
# Requires mod_headers to be enabled.
|
||||
#
|
||||
#Header set X-Frame-Options: "sameorigin"
|
||||
|
||||
{% if apache_security_headers %}
|
||||
#
|
||||
# Security headers for PCI-DSS.
|
||||
#
|
||||
Header always set X-Content-Type-Options: "nosniff"
|
||||
Header always set X-Frame-Options: "sameorigin"
|
||||
Header always set X-XSS-Protection "1; mode=block"
|
||||
{% endif %}
|
||||
|
||||
#
|
||||
# Accept host names with _underscores_
|
||||
#
|
||||
HTTPProtocolOptions unsafe
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,22 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
<IfModule mod_deflate.c>
|
||||
<IfModule mod_filter.c>
|
||||
# these are known to be safe with MSIE 6
|
||||
AddOutputFilterByType DEFLATE text/html text/plain text/xml image/svg+xml
|
||||
|
||||
# everything else may cause problems with MSIE 6
|
||||
AddOutputFilterByType DEFLATE text/css
|
||||
AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript
|
||||
AddOutputFilterByType DEFLATE application/rss+xml
|
||||
AddOutputFilterByType DEFLATE application/xml
|
||||
|
||||
AddOutputFilterByType DEFLATE application/json
|
||||
AddOutputFilterByType DEFLATE application/x-php-serialized-rpc
|
||||
AddOutputFilterByType DEFLATE image/x-icon text/javascript
|
||||
|
||||
DeflateFilterNote Ratio ratio
|
||||
</IfModule>
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,30 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
<IfModule mod_evasive20.c>
|
||||
{% for key, value in apache_mod_evasive_settings | dictsort %}
|
||||
{{ key }} {{ value }}
|
||||
{% endfor %}
|
||||
|
||||
#DOSEmailNotify you@yourdomain.com
|
||||
#DOSSystemCommand "su - someuser -c '/sbin/... %s ...'"
|
||||
#DOSLogDir "/var/log/mod_evasive"
|
||||
|
||||
DOSWhitelist 10.*.*.*
|
||||
DOSWhitelist 192.168.*.*
|
||||
|
||||
DOSWhitelist 63.254.74.*
|
||||
DOSWhitelist 8.28.239.*
|
||||
|
||||
{% for ip in firewall_monitoring_ips|default([]) if ip|ipv4('public') %}
|
||||
DOSWhitelist {{ ip }}
|
||||
{% endfor %}
|
||||
|
||||
{% for ip in firewall_whitelist_office_ip|default([]) %}
|
||||
DOSWhitelist {{ ip | regex_replace('[0-9]+/[0-9]+', '*') }}
|
||||
{% endfor %}
|
||||
|
||||
{% for ip in apache_mod_evasive_whitelist|default([]) %}
|
||||
DOSWhitelist {{ ip | regex_replace('[0-9]+/[0-9]+', '*') }}
|
||||
{% endfor %}
|
||||
|
||||
</IfModule>
|
||||
@@ -0,0 +1,17 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
<IfModule http2_module>
|
||||
{% if apache_http2_enabled %}
|
||||
Protocols h2 h2c http/1.1
|
||||
{% else %}
|
||||
Protocols http/1.1 # http/2 disabled
|
||||
{% endif %}
|
||||
|
||||
H2Push on
|
||||
H2PushPriority * after
|
||||
H2PushPriority text/css before
|
||||
H2PushPriority image/jpeg after 32
|
||||
H2PushPriority image/png after 32
|
||||
H2PushPriority application/javascript interleaved
|
||||
|
||||
</IfModule>
|
||||
@@ -0,0 +1,91 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
<IfModule mod_ssl.c>
|
||||
|
||||
# Pseudo Random Number Generator (PRNG):
|
||||
# Configure one or more sources to seed the PRNG of the SSL library.
|
||||
# The seed data should be of good random quality.
|
||||
# WARNING! On some platforms /dev/random blocks if not enough entropy
|
||||
# is available. This means you then cannot use the /dev/random device
|
||||
# because it would lead to very long connection times (as long as
|
||||
# it requires to make more entropy available). But usually those
|
||||
# platforms additionally provide a /dev/urandom device which doesn't
|
||||
# block. So, if available, use this one instead. Read the mod_ssl User
|
||||
# Manual for more details.
|
||||
#
|
||||
SSLRandomSeed startup builtin
|
||||
SSLRandomSeed startup file:/dev/urandom 512
|
||||
SSLRandomSeed connect builtin
|
||||
SSLRandomSeed connect file:/dev/urandom 512
|
||||
|
||||
##
|
||||
## SSL Global Context
|
||||
##
|
||||
## All SSL configuration in this context applies both to
|
||||
## the main server and all SSL-enabled virtual hosts.
|
||||
##
|
||||
|
||||
#
|
||||
# Some MIME-types for downloading Certificates and CRLs
|
||||
#
|
||||
AddType application/x-x509-ca-cert .crt
|
||||
AddType application/x-pkcs7-crl .crl
|
||||
|
||||
# Pass Phrase Dialog:
|
||||
# Configure the pass phrase gathering process.
|
||||
# The filtering dialog program (`builtin' is a internal
|
||||
# terminal dialog) has to provide the pass phrase on stdout.
|
||||
SSLPassPhraseDialog exec:/usr/share/apache2/ask-for-passphrase
|
||||
|
||||
# Inter-Process Session Cache:
|
||||
# Configure the SSL Session Cache: First the mechanism
|
||||
# to use and second the expiring timeout (in seconds).
|
||||
# (The mechanism dbm has known memory leaks and should not be used).
|
||||
#SSLSessionCache dbm:${APACHE_RUN_DIR}/ssl_scache
|
||||
SSLSessionCache shmcb:${APACHE_RUN_DIR}/ssl_scache(512000)
|
||||
SSLSessionCacheTimeout 300
|
||||
|
||||
# Semaphore:
|
||||
# Configure the path to the mutual exclusion semaphore the
|
||||
# SSL engine uses internally for inter-process synchronization.
|
||||
# (Disabled by default, the global Mutex directive consolidates by default
|
||||
# this)
|
||||
#Mutex file:${APACHE_LOCK_DIR}/ssl_mutex ssl-cache
|
||||
|
||||
# SSL Cipher Suite:
|
||||
# List the ciphers that the client is permitted to negotiate. See the
|
||||
# ciphers(1) man page from the openssl package for list of all available
|
||||
# options.
|
||||
# Enable only secure ciphers:
|
||||
SSLCipherSuite "{{ apache_mod_ssl_ciphers | join(':') }}"
|
||||
#SSLOpenSSLConfCmd DHParameters /etc/apache2/ssl/dhparams.pem
|
||||
|
||||
|
||||
# SSL server cipher order preference:
|
||||
# Use server priorities for cipher algorithm choice.
|
||||
# Clients may prefer lower grade encryption. You should enable this
|
||||
# option if you want to enforce stronger encryption, and can afford
|
||||
# the CPU cost, and did not override SSLCipherSuite in a way that puts
|
||||
# insecure ciphers first.
|
||||
# Default: Off
|
||||
SSLHonorCipherOrder on
|
||||
|
||||
# The protocols to enable.
|
||||
# Available values: all, SSLv3, TLSv1, TLSv1.1, TLSv1.2
|
||||
# SSL v2 is no longer supported
|
||||
SSLProtocol {{ apache_mod_ssl_protocols }}
|
||||
|
||||
# Allow insecure renegotiation with clients which do not yet support the
|
||||
# secure renegotiation protocol. Default: Off
|
||||
#SSLInsecureRenegotiation on
|
||||
|
||||
# Whether to forbid non-SNI clients to access name based virtual hosts.
|
||||
# Default: Off
|
||||
#SSLStrictSNIVHostCheck On
|
||||
|
||||
SSLStaplingCache shmcb:${APACHE_RUN_DIR}/ssl_stcache(512000)
|
||||
SSLUseStapling on
|
||||
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
@@ -0,0 +1,29 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
<IfModule mod_status.c>
|
||||
# Allow server status reports generated by mod_status,
|
||||
# with the URL of http://servername/server-status
|
||||
|
||||
<Location /server-status>
|
||||
SetHandler server-status
|
||||
Require ip 127.0.0.1 ::1 {{ apache_monitoring_ips }}
|
||||
</Location>
|
||||
|
||||
# Keep track of extended status information for each request
|
||||
ExtendedStatus On
|
||||
|
||||
# Determine if mod_status displays the first 63 characters of a request or
|
||||
# the last 63, assuming the request itself is greater than 63 chars.
|
||||
# Default: Off
|
||||
#SeeRequestTail On
|
||||
|
||||
|
||||
<IfModule mod_proxy.c>
|
||||
# Show Proxy LoadBalancer status in mod_status
|
||||
ProxyStatus On
|
||||
</IfModule>
|
||||
|
||||
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
11
roles/apache/templates/etc_consul.d_service-apache.hcl.j2
Normal file
11
roles/apache/templates/etc_consul.d_service-apache.hcl.j2
Normal file
@@ -0,0 +1,11 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
service {
|
||||
name = "apache"
|
||||
port = 443
|
||||
check {
|
||||
http = "https://localhost/server-status?auto"
|
||||
interval = "30s"
|
||||
tlsSkipVerify = true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if apache_firewall_public %}
|
||||
iptables -N apache-in
|
||||
{% if apache_firewall_public_isolated %}
|
||||
{% for ip in apache_firewall_acl %}
|
||||
iptables -A apache-in -s {{ ip }} -j ACCEPT
|
||||
{% endfor %}
|
||||
{% for ip in datacenter_global_networks + datacenter_public_networks %}
|
||||
iptables -A apache-in -s {{ ip }} -j RETURN
|
||||
{% endfor %}
|
||||
{% for ip in apache_firewall_drop_dst %}
|
||||
iptables -A apache-in -d {{ ip }} -j RETURN
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
iptables -A apache-in -j ACCEPT
|
||||
|
||||
iptables -A INPUT -p tcp --dport 80 -m comment --comment "apache-http" -j apache-in
|
||||
iptables -A INPUT -p tcp --dport 443 -m comment --comment "apache-https" -j apache-in
|
||||
{% else %}
|
||||
iptables -A internal-in -p tcp --dport 80 -m comment --comment "apache-http" -j ACCEPT
|
||||
iptables -A internal-in -p tcp --dport 443 -m comment --comment "apache-https" -j ACCEPT
|
||||
{% endif %}
|
||||
|
||||
iptables -A monitoring-in -p tcp --dport 80 -m comment --comment "apache-http" -j ACCEPT
|
||||
iptables -A monitoring-in -p tcp --dport 443 -m comment --comment "apache-https" -j ACCEPT
|
||||
@@ -0,0 +1,19 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if apache_firewall_public %}
|
||||
ip6tables -N apache-in
|
||||
{% if apache_firewall_public_isolated %}
|
||||
ip6tables -A apache-in -s fe80::/10 -j RETURN
|
||||
ip6tables -A apache-in -s fc00::/7 -j RETURN
|
||||
{% for ip in datacenter_public_ipv6_networks %}
|
||||
ip6tables -A apache-in -s {{ ip }} -j RETURN
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
ip6tables -A apache-in -j ACCEPT
|
||||
|
||||
ip6tables -A INPUT -p tcp --dport 80 -m comment --comment "apache-http" -j apache-in
|
||||
ip6tables -A INPUT -p tcp --dport 443 -m comment --comment "apache-https" -j apache-in
|
||||
{% else %}
|
||||
ip6tables -A internal-in -p tcp --dport 80 -m comment --comment "apache-http" -j ACCEPT
|
||||
ip6tables -A internal-in -p tcp --dport 443 -m comment --comment "apache-https" -j ACCEPT
|
||||
{% endif %}
|
||||
23
roles/apache/templates/etc_logrotate.d_apache2.j2
Normal file
23
roles/apache/templates/etc_logrotate.d_apache2.j2
Normal file
@@ -0,0 +1,23 @@
|
||||
/var/log/apache2/*.log {
|
||||
dateext
|
||||
dateformat .%Y%m%d
|
||||
dateyesterday
|
||||
daily
|
||||
missingok
|
||||
rotate 14
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
create 640 root adm
|
||||
sharedscripts
|
||||
postrotate
|
||||
if /etc/init.d/apache2 status > /dev/null ; then \
|
||||
/etc/init.d/apache2 reload > /dev/null; \
|
||||
fi;
|
||||
endscript
|
||||
prerotate
|
||||
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
|
||||
run-parts /etc/logrotate.d/httpd-prerotate; \
|
||||
fi; \
|
||||
endscript
|
||||
}
|
||||
853
roles/apache/templates/etc_modsecurity_crs_crs-setup.conf.j2
Normal file
853
roles/apache/templates/etc_modsecurity_crs_crs-setup.conf.j2
Normal file
@@ -0,0 +1,853 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# OWASP ModSecurity Core Rule Set ver.3.1.0
|
||||
# Copyright (c) 2006-2018 Trustwave and contributors. All rights reserved.
|
||||
#
|
||||
# The OWASP ModSecurity Core Rule Set is distributed under
|
||||
# Apache Software License (ASL) version 2
|
||||
# Please see the enclosed LICENSE file for full details.
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Introduction ]] --------------------------------------------------------
|
||||
#
|
||||
# The OWASP ModSecurity Core Rule Set (CRS) is a set of generic attack
|
||||
# detection rules that provide a base level of protection for any web
|
||||
# application. They are written for the open source, cross-platform
|
||||
# ModSecurity Web Application Firewall.
|
||||
#
|
||||
# See also:
|
||||
# https://coreruleset.org/
|
||||
# https://github.com/SpiderLabs/owasp-modsecurity-crs
|
||||
# https://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# -- [[ System Requirements ]] -------------------------------------------------
|
||||
#
|
||||
# CRS requires ModSecurity version 2.8.0 or above.
|
||||
# We recommend to always use the newest ModSecurity version.
|
||||
#
|
||||
# The configuration directives/settings in this file are used to control
|
||||
# the OWASP ModSecurity CRS. These settings do **NOT** configure the main
|
||||
# ModSecurity settings (modsecurity.conf) such as SecRuleEngine,
|
||||
# SecRequestBodyAccess, SecAuditEngine, SecDebugLog, and XML processing.
|
||||
#
|
||||
# The CRS assumes that modsecurity.conf has been loaded. It is bundled with
|
||||
# ModSecurity. If you don't have it, you can get it from:
|
||||
# 2.x: https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v2/master/modsecurity.conf-recommended
|
||||
# 3.x: https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended
|
||||
#
|
||||
# The order of file inclusion in your webserver configuration should always be:
|
||||
# 1. modsecurity.conf
|
||||
# 2. crs-setup.conf (this file)
|
||||
# 3. rules/*.conf (the CRS rule files)
|
||||
#
|
||||
# Please refer to the INSTALL file for detailed installation instructions.
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Mode of Operation: Anomaly Scoring vs. Self-Contained ]] ---------------
|
||||
#
|
||||
# The CRS can run in two modes:
|
||||
#
|
||||
# -- [[ Anomaly Scoring Mode (default) ]] --
|
||||
# In CRS3, anomaly mode is the default and recommended mode, since it gives the
|
||||
# most accurate log information and offers the most flexibility in setting your
|
||||
# blocking policies. It is also called "collaborative detection mode".
|
||||
# In this mode, each matching rule increases an 'anomaly score'.
|
||||
# At the conclusion of the inbound rules, and again at the conclusion of the
|
||||
# outbound rules, the anomaly score is checked, and the blocking evaluation
|
||||
# rules apply a disruptive action, by default returning an error 403.
|
||||
#
|
||||
# -- [[ Self-Contained Mode ]] --
|
||||
# In this mode, rules apply an action instantly. This was the CRS2 default.
|
||||
# It can lower resource usage, at the cost of less flexibility in blocking policy
|
||||
# and less informative audit logs (only the first detected threat is logged).
|
||||
# Rules inherit the disruptive action that you specify (i.e. deny, drop, etc).
|
||||
# The first rule that matches will execute this action. In most cases this will
|
||||
# cause evaluation to stop after the first rule has matched, similar to how many
|
||||
# IDSs function.
|
||||
#
|
||||
# -- [[ Alert Logging Control ]] --
|
||||
# In the mode configuration, you must also adjust the desired logging options.
|
||||
# There are three common options for dealing with logging. By default CRS enables
|
||||
# logging to the webserver error log (or Event viewer) plus detailed logging to
|
||||
# the ModSecurity audit log (configured under SecAuditLog in modsecurity.conf).
|
||||
#
|
||||
# - To log to both error log and ModSecurity audit log file, use: "log,auditlog"
|
||||
# - To log *only* to the ModSecurity audit log file, use: "nolog,auditlog"
|
||||
# - To log *only* to the error log file, use: "log,noauditlog"
|
||||
#
|
||||
# Examples for the various modes follow.
|
||||
# You must leave one of the following options enabled.
|
||||
# Note that you must specify the same line for phase:1 and phase:2.
|
||||
#
|
||||
|
||||
# Default: Anomaly Scoring mode, log to error log, log to ModSecurity audit log
|
||||
# - By default, offending requests are blocked with an error 403 response.
|
||||
# - To change the disruptive action, see RESPONSE-999-EXCEPTIONS.conf.example
|
||||
# and review section 'Changing the Disruptive Action for Anomaly Mode'.
|
||||
# - In Apache, you can use ErrorDocument to show a friendly error page or
|
||||
# perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html
|
||||
#
|
||||
SecDefaultAction "phase:1,log,auditlog,pass"
|
||||
SecDefaultAction "phase:2,log,auditlog,pass"
|
||||
|
||||
# Example: Anomaly Scoring mode, log only to ModSecurity audit log
|
||||
# - By default, offending requests are blocked with an error 403 response.
|
||||
# - To change the disruptive action, see RESPONSE-999-EXCEPTIONS.conf.example
|
||||
# and review section 'Changing the Disruptive Action for Anomaly Mode'.
|
||||
# - In Apache, you can use ErrorDocument to show a friendly error page or
|
||||
# perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html
|
||||
#
|
||||
# SecDefaultAction "phase:1,nolog,auditlog,pass"
|
||||
# SecDefaultAction "phase:2,nolog,auditlog,pass"
|
||||
|
||||
# Example: Self-contained mode, return error 403 on blocking
|
||||
# - In this configuration the default disruptive action becomes 'deny'. After a
|
||||
# rule triggers, it will stop processing the request and return an error 403.
|
||||
# - You can also use a different error status, such as 404, 406, et cetera.
|
||||
# - In Apache, you can use ErrorDocument to show a friendly error page or
|
||||
# perform a redirect: https://httpd.apache.org/docs/2.4/custom-error.html
|
||||
#
|
||||
# SecDefaultAction "phase:1,log,auditlog,deny,status:403"
|
||||
# SecDefaultAction "phase:2,log,auditlog,deny,status:403"
|
||||
|
||||
# Example: Self-contained mode, redirect back to homepage on blocking
|
||||
# - In this configuration the 'tag' action includes the Host header data in the
|
||||
# log. This helps to identify which virtual host triggered the rule (if any).
|
||||
# - Note that this might cause redirect loops in some situations; for example
|
||||
# if a Cookie or User-Agent header is blocked, it will also be blocked when
|
||||
# the client subsequently tries to access the homepage. You can also redirect
|
||||
# to another custom URL.
|
||||
# SecDefaultAction "phase:1,log,auditlog,redirect:'http://%{request_headers.host}/',tag:'Host: %{request_headers.host}'"
|
||||
# SecDefaultAction "phase:2,log,auditlog,redirect:'http://%{request_headers.host}/',tag:'Host: %{request_headers.host}'"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Paranoia Level Initialization ]] ---------------------------------------
|
||||
#
|
||||
# The Paranoia Level (PL) setting allows you to choose the desired level
|
||||
# of rule checks that will add to your anomaly scores.
|
||||
#
|
||||
# With each paranoia level increase, the CRS enables additional rules
|
||||
# giving you a higher level of security. However, higher paranoia levels
|
||||
# also increase the possibility of blocking some legitimate traffic due to
|
||||
# false alarms (also named false positives or FPs). If you use higher
|
||||
# paranoia levels, it is likely that you will need to add some exclusion
|
||||
# rules for certain requests and applications receiving complex input.
|
||||
#
|
||||
# - A paranoia level of 1 is default. In this level, most core rules
|
||||
# are enabled. PL1 is advised for beginners, installations
|
||||
# covering many different sites and applications, and for setups
|
||||
# with standard security requirements.
|
||||
# At PL1 you should face FPs rarely. If you encounter FPs, please
|
||||
# open an issue on the CRS GitHub site and don't forget to attach your
|
||||
# complete Audit Log record for the request with the issue.
|
||||
# - Paranoia level 2 includes many extra rules, for instance enabling
|
||||
# many regexp-based SQL and XSS injection protections, and adding
|
||||
# extra keywords checked for code injections. PL2 is advised
|
||||
# for moderate to experienced users desiring more complete coverage
|
||||
# and for installations with elevated security requirements.
|
||||
# PL2 comes with some FPs which you need to handle.
|
||||
# - Paranoia level 3 enables more rules and keyword lists, and tweaks
|
||||
# limits on special characters used. PL3 is aimed at users experienced
|
||||
# at the handling of FPs and at installations with a high security
|
||||
# requirement.
|
||||
# - Paranoia level 4 further restricts special characters.
|
||||
# The highest level is advised for experienced users protecting
|
||||
# installations with very high security requirements. Running PL4 will
|
||||
# likely produce a very high number of FPs which have to be
|
||||
# treated before the site can go productive.
|
||||
#
|
||||
# Rules in paranoia level 2 or higher will log their PL to the audit log;
|
||||
# example: [tag "paranoia-level/2"]. This allows you to deduct from the
|
||||
# audit log how the WAF behavior is affected by paranoia level.
|
||||
#
|
||||
# It is important to also look into the variable
|
||||
# tx.enforce_bodyproc_urlencoded (Enforce Body Processor URLENCODED)
|
||||
# defined below. Enabling it closes a possible bypass of CRS.
|
||||
#
|
||||
# Uncomment this rule to change the default:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900000,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.paranoia_level=1"
|
||||
|
||||
|
||||
# It is possible to execute rules from a higher paranoia level but not include
|
||||
# them in the anomaly scoring. This allows you to take a well-tuned system on
|
||||
# paranoia level 1 and add rules from paranoia level 2 without having to fear
|
||||
# the new rules would lead to false positives that raise your score above the
|
||||
# threshold.
|
||||
# This optional feature is enabled by uncommenting the following rule and
|
||||
# setting the tx.executing_paranoia_level.
|
||||
# Technically, rules up to the level defined in tx.executing_paranoia_level
|
||||
# will be executed, but only the rules up to tx.paranoia_level affect the
|
||||
# anomaly scores.
|
||||
# By default, tx.executing_paranoia_level is set to tx.paranoia_level.
|
||||
# tx.executing_paranoia_level must not be lower than tx.paranoia_level.
|
||||
#
|
||||
# Please notice that setting tx.executing_paranoia_level to a higher paranoia
|
||||
# level results in a performance impact that is equally high as setting
|
||||
# tx.paranoia_level to said level.
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900001,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.executing_paranoia_level=1"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Enforce Body Processor URLENCODED ]] -----------------------------------
|
||||
#
|
||||
# ModSecurity selects the body processor based on the Content-Type request
|
||||
# header. But clients are not always setting the Content-Type header for their
|
||||
# request body payloads. This will leave ModSecurity with limited vision into
|
||||
# the payload. The variable tx.enforce_bodyproc_urlencoded lets you force the
|
||||
# URLENCODED body processor in these situations. This is off by default, as it
|
||||
# implies a change of the behaviour of ModSecurity beyond CRS (the body
|
||||
# processor applies to all rules, not only CRS) and because it may lead to
|
||||
# false positives already on paranoia level 1. However, enabling this variable
|
||||
# closes a possible bypass of CRS so it should be considered.
|
||||
#
|
||||
# Uncomment this rule to change the default:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900010,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.enforce_bodyproc_urlencoded=1"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Anomaly Mode Severity Levels ]] ----------------------------------------
|
||||
#
|
||||
# Each rule in the CRS has an associated severity level.
|
||||
# These are the default scoring points for each severity level.
|
||||
# These settings will be used to increment the anomaly score if a rule matches.
|
||||
# You may adjust these points to your liking, but this is usually not needed.
|
||||
#
|
||||
# - CRITICAL severity: Anomaly Score of 5.
|
||||
# Mostly generated by the application attack rules (93x and 94x files).
|
||||
# - ERROR severity: Anomaly Score of 4.
|
||||
# Generated mostly from outbound leakage rules (95x files).
|
||||
# - WARNING severity: Anomaly Score of 3.
|
||||
# Generated mostly by malicious client rules (91x files).
|
||||
# - NOTICE severity: Anomaly Score of 2.
|
||||
# Generated mostly by the protocol rules (92x files).
|
||||
#
|
||||
# In anomaly mode, these scores are cumulative.
|
||||
# So it's possible for a request to hit multiple rules.
|
||||
#
|
||||
# (Note: In this file, we use 'phase:1' to set CRS configuration variables.
|
||||
# In general, 'phase:request' is used. However, we want to make absolutely sure
|
||||
# that all configuration variables are set before the CRS rules are processed.)
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900100,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.critical_anomaly_score=5,\
|
||||
# setvar:tx.error_anomaly_score=4,\
|
||||
# setvar:tx.warning_anomaly_score=3,\
|
||||
# setvar:tx.notice_anomaly_score=2"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Anomaly Mode Blocking Threshold Levels ]] ------------------------------
|
||||
#
|
||||
# Here, you can specify at which cumulative anomaly score an inbound request,
|
||||
# or outbound response, gets blocked.
|
||||
#
|
||||
# Most detected inbound threats will give a critical score of 5.
|
||||
# Smaller violations, like violations of protocol/standards, carry lower scores.
|
||||
#
|
||||
# [ At default value ]
|
||||
# If you keep the blocking thresholds at the defaults, the CRS will work
|
||||
# similarly to previous CRS versions: a single critical rule match will cause
|
||||
# the request to be blocked and logged.
|
||||
#
|
||||
# [ Using higher values ]
|
||||
# If you want to make the CRS less sensitive, you can increase the blocking
|
||||
# thresholds, for instance to 7 (which would require multiple rule matches
|
||||
# before blocking) or 10 (which would require at least two critical alerts - or
|
||||
# a combination of many lesser alerts), or even higher. However, increasing the
|
||||
# thresholds might cause some attacks to bypass the CRS rules or your policies.
|
||||
#
|
||||
# [ New deployment strategy: Starting high and decreasing ]
|
||||
# It is a common practice to start a fresh CRS installation with elevated
|
||||
# anomaly scoring thresholds (>100) and then lower the limits as your
|
||||
# confidence in the setup grows. You may also look into the Sampling
|
||||
# Percentage section below for a different strategy to ease into a new
|
||||
# CRS installation.
|
||||
#
|
||||
# [ Anomaly Threshold / Paranoia Level Quadrant ]
|
||||
#
|
||||
# High Anomaly Limit | High Anomaly Limit
|
||||
# Low Paranoia Level | High Paranoia Level
|
||||
# -> Fresh Site | -> Experimental Site
|
||||
# ------------------------------------------------------
|
||||
# Low Anomaly Limit | Low Anomaly Limit
|
||||
# Low Paranoia Level | High Paranoia Level
|
||||
# -> Standard Site | -> High Security Site
|
||||
#
|
||||
# Uncomment this rule to change the defaults:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900110,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.inbound_anomaly_score_threshold=5,\
|
||||
# setvar:tx.outbound_anomaly_score_threshold=4"
|
||||
|
||||
#
|
||||
# -- [[ Application Specific Rule Exclusions ]] ----------------------------------------
|
||||
#
|
||||
# Some well-known applications may undertake actions that appear to be
|
||||
# malicious. This includes actions such as allowing HTML or Javascript within
|
||||
# parameters. In such cases the CRS aims to prevent false positives by allowing
|
||||
# administrators to enable prebuilt, application specific exclusions on an
|
||||
# application by application basis.
|
||||
# These application specific exclusions are distinct from the rules that would
|
||||
# be placed in the REQUEST-900-EXCLUSION-RULES-BEFORE-CRS configuration file as
|
||||
# they are prebuilt for specific applications. The 'REQUEST-900' file is
|
||||
# designed for users to add their own custom exclusions. Note, using these
|
||||
# application specific exclusions may loosen restrictions of the CRS,
|
||||
# especially if used with an application they weren't designed for. As a result
|
||||
# they should be applied with care.
|
||||
# To use this functionality you must specify a supported application. To do so
|
||||
# uncomment rule 900130. In addition to uncommenting the rule you will need to
|
||||
# specify which application(s) you'd like to enable exclusions for. Only a
|
||||
# (very) limited set of applications are currently supported, please use the
|
||||
# filenames prefixed with 'REQUEST-903' to guide you in your selection.
|
||||
# Such filenames use the following convention:
|
||||
# REQUEST-903.9XXX-{APPNAME}-EXCLUSIONS-RULES.conf
|
||||
#
|
||||
# It is recommended if you run multiple web applications on your site to limit
|
||||
# the effects of the exclusion to only the path where the excluded webapp
|
||||
# resides using a rule similar to the following example:
|
||||
# SecRule REQUEST_URI "@beginsWith /wordpress/" setvar:tx.crs_exclusions_wordpress=1
|
||||
|
||||
#
|
||||
# Modify and uncomment this rule to select which application:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900130,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.crs_exclusions_drupal=1,\
|
||||
# setvar:tx.crs_exclusions_wordpress=1,\
|
||||
# setvar:tx.crs_exclusions_nextcloud=1,\
|
||||
# setvar:tx.crs_exclusions_dokuwiki=1,\
|
||||
# setvar:tx.crs_exclusions_cpanel=1"
|
||||
|
||||
#
|
||||
# -- [[ HTTP Policy Settings ]] ------------------------------------------------
|
||||
#
|
||||
# This section defines your policies for the HTTP protocol, such as:
|
||||
# - allowed HTTP versions, HTTP methods, allowed request Content-Types
|
||||
# - forbidden file extensions (e.g. .bak, .sql) and request headers (e.g. Proxy)
|
||||
#
|
||||
# These variables are used in the following rule files:
|
||||
# - REQUEST-911-METHOD-ENFORCEMENT.conf
|
||||
# - REQUEST-912-DOS-PROTECTION.conf
|
||||
# - REQUEST-920-PROTOCOL-ENFORCEMENT.conf
|
||||
|
||||
# HTTP methods that a client is allowed to use.
|
||||
# Default: GET HEAD POST OPTIONS
|
||||
# Example: for RESTful APIs, add the following methods: PUT PATCH DELETE
|
||||
# Example: for WebDAV, add the following methods: CHECKOUT COPY DELETE LOCK
|
||||
# MERGE MKACTIVITY MKCOL MOVE PROPFIND PROPPATCH PUT UNLOCK
|
||||
# Uncomment this rule to change the default.
|
||||
#SecAction \
|
||||
# "id:900200,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:'tx.allowed_methods=GET HEAD POST OPTIONS'"
|
||||
|
||||
# Content-Types that a client is allowed to send in a request.
|
||||
# Default: application/x-www-form-urlencoded|multipart/form-data|text/xml|\
|
||||
# application/xml|application/soap+xml|application/x-amf|application/json|\
|
||||
# application/octet-stream|text/plain
|
||||
# Uncomment this rule to change the default.
|
||||
SecAction \
|
||||
"id:900220,\
|
||||
phase:1,\
|
||||
nolog,\
|
||||
pass,\
|
||||
t:none,\
|
||||
setvar:'tx.allowed_request_content_type=application/x-php-serialized-rpc|application/x-www-form-urlencoded|multipart/form-data|text/xml|application/xml|application/soap+xml|application/x-amf|application/json|application/octet-stream|text/plain'"
|
||||
|
||||
# Content-Types charsets that a client is allowed to send in a request.
|
||||
# Default: utf-8|iso-8859-1|iso-8859-15|windows-1252
|
||||
# Uncomment this rule to change the default.
|
||||
# Use "|" to separate multiple charsets like in the rule defining
|
||||
# tx.allowed_request_content_type.
|
||||
#SecAction \
|
||||
# "id:900270,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:'tx.allowed_request_content_type_charset=utf-8|iso-8859-1|iso-8859-15|windows-1252'"
|
||||
|
||||
# Allowed HTTP versions.
|
||||
# Default: HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0
|
||||
# Example for legacy clients: HTTP/0.9 HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0
|
||||
# Note that some web server versions use 'HTTP/2', some 'HTTP/2.0', so
|
||||
# we include both version strings by default.
|
||||
# Uncomment this rule to change the default.
|
||||
#SecAction \
|
||||
# "id:900230,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:'tx.allowed_http_versions=HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0'"
|
||||
|
||||
# Forbidden file extensions.
|
||||
# Guards against unintended exposure of development/configuration files.
|
||||
# Default: .asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .resources/ .resx/ .sql/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/
|
||||
# Example: .bak/ .config/ .conf/ .db/ .ini/ .log/ .old/ .pass/ .pdb/ .sql/
|
||||
# Uncomment this rule to change the default.
|
||||
#SecAction \
|
||||
# "id:900240,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:'tx.restricted_extensions=.asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .resources/ .resx/ .sql/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/'"
|
||||
|
||||
# Forbidden request headers.
|
||||
# Header names should be lowercase, enclosed by /slashes/ as delimiters.
|
||||
# Blocking Proxy header prevents 'httpoxy' vulnerability: https://httpoxy.org
|
||||
# Default: /proxy/ /lock-token/ /content-range/ /translate/ /if/
|
||||
# Uncomment this rule to change the default.
|
||||
#SecAction \
|
||||
# "id:900250,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:'tx.restricted_headers=/proxy/ /lock-token/ /content-range/ /translate/ /if/'"
|
||||
|
||||
# File extensions considered static files.
|
||||
# Extensions include the dot, lowercase, enclosed by /slashes/ as delimiters.
|
||||
# Used in DoS protection rule. See section "Anti-Automation / DoS Protection".
|
||||
# Default: /.jpg/ /.jpeg/ /.png/ /.gif/ /.js/ /.css/ /.ico/ /.svg/ /.webp/
|
||||
# Uncomment this rule to change the default.
|
||||
#SecAction \
|
||||
# "id:900260,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:'tx.static_extensions=/.jpg/ /.jpeg/ /.png/ /.gif/ /.js/ /.css/ /.ico/ /.svg/ /.webp/'"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ HTTP Argument/Upload Limits ]] -----------------------------------------
|
||||
#
|
||||
# Here you can define optional limits on HTTP get/post parameters and uploads.
|
||||
# This can help to prevent application specific DoS attacks.
|
||||
#
|
||||
# These values are checked in REQUEST-920-PROTOCOL-ENFORCEMENT.conf.
|
||||
# Beware of blocking legitimate traffic when enabling these limits.
|
||||
#
|
||||
|
||||
# Block request if number of arguments is too high
|
||||
# Default: unlimited
|
||||
# Example: 255
|
||||
# Uncomment this rule to set a limit.
|
||||
#SecAction \
|
||||
# "id:900300,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.max_num_args=255"
|
||||
|
||||
# Block request if the length of any argument name is too high
|
||||
# Default: unlimited
|
||||
# Example: 100
|
||||
# Uncomment this rule to set a limit.
|
||||
#SecAction \
|
||||
# "id:900310,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.arg_name_length=100"
|
||||
|
||||
# Block request if the length of any argument value is too high
|
||||
# Default: unlimited
|
||||
# Example: 400
|
||||
# Uncomment this rule to set a limit.
|
||||
#SecAction \
|
||||
# "id:900320,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.arg_length=400"
|
||||
|
||||
# Block request if the total length of all combined arguments is too high
|
||||
# Default: unlimited
|
||||
# Example: 64000
|
||||
# Uncomment this rule to set a limit.
|
||||
#SecAction \
|
||||
# "id:900330,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.total_arg_length=64000"
|
||||
|
||||
# Block request if the file size of any individual uploaded file is too high
|
||||
# Default: unlimited
|
||||
# Example: 1048576
|
||||
# Uncomment this rule to set a limit.
|
||||
#SecAction \
|
||||
# "id:900340,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.max_file_size=1048576"
|
||||
|
||||
# Block request if the total size of all combined uploaded files is too high
|
||||
# Default: unlimited
|
||||
# Example: 1048576
|
||||
# Uncomment this rule to set a limit.
|
||||
#SecAction \
|
||||
# "id:900350,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.combined_file_sizes=1048576"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Easing In / Sampling Percentage ]] -------------------------------------
|
||||
#
|
||||
# Adding the Core Rule Set to an existing productive site can lead to false
|
||||
# positives, unexpected performance issues and other undesired side effects.
|
||||
#
|
||||
# It can be beneficial to test the water first by enabling the CRS for a
|
||||
# limited number of requests only and then, when you have solved the issues (if
|
||||
# any) and you have confidence in the setup, to raise the ratio of requests
|
||||
# being sent into the ruleset.
|
||||
#
|
||||
# Adjust the percentage of requests that are funnelled into the Core Rules by
|
||||
# setting TX.sampling_percentage below. The default is 100, meaning that every
|
||||
# request gets checked by the CRS. The selection of requests, which are going
|
||||
# to be checked, is based on a pseudo random number generated by ModSecurity.
|
||||
#
|
||||
# If a request is allowed to pass without being checked by the CRS, there is no
|
||||
# entry in the audit log (for performance reasons), but an error log entry is
|
||||
# written. If you want to disable the error log entry, then issue the
|
||||
# following directive somewhere after the inclusion of the CRS
|
||||
# (E.g., RESPONSE-999-EXCEPTIONS.conf).
|
||||
#
|
||||
# SecRuleUpdateActionById 901150 "nolog"
|
||||
#
|
||||
# ATTENTION: If this TX.sampling_percentage is below 100, then some of the
|
||||
# requests will bypass the Core Rules completely and you lose the ability to
|
||||
# protect your service with ModSecurity.
|
||||
#
|
||||
# Uncomment this rule to enable this feature:
|
||||
#
|
||||
#SecAction "id:900400,\
|
||||
# phase:1,\
|
||||
# pass,\
|
||||
# nolog,\
|
||||
# setvar:tx.sampling_percentage=100"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Project Honey Pot HTTP Blacklist ]] ------------------------------------
|
||||
#
|
||||
# Optionally, you can check the client IP address against the Project Honey Pot
|
||||
# HTTPBL (dnsbl.httpbl.org). In order to use this, you need to register to get a
|
||||
# free API key. Set it here with SecHttpBlKey.
|
||||
#
|
||||
# Project Honeypot returns multiple different malicious IP types.
|
||||
# You may specify which you want to block by enabling or disabling them below.
|
||||
#
|
||||
# Ref: https://www.projecthoneypot.org/httpbl.php
|
||||
# Ref: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecHttpBlKey
|
||||
#
|
||||
# Uncomment these rules to use this feature:
|
||||
#
|
||||
#SecHttpBlKey XXXXXXXXXXXXXXXXX
|
||||
#SecAction "id:900500,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.block_search_ip=1,\
|
||||
# setvar:tx.block_suspicious_ip=1,\
|
||||
# setvar:tx.block_harvester_ip=1,\
|
||||
# setvar:tx.block_spammer_ip=1"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ GeoIP Database ]] ------------------------------------------------------
|
||||
#
|
||||
# There are some rulesets that inspect geolocation data of the client IP address
|
||||
# (geoLookup). The CRS uses geoLookup to implement optional country blocking.
|
||||
#
|
||||
# To use geolocation, we make use of the MaxMind GeoIP database.
|
||||
# This database is not included with the CRS and must be downloaded.
|
||||
# You should also update the database regularly, for instance every month.
|
||||
# The CRS contains a tool to download it to util/geo-location/GeoIP.dat:
|
||||
# util/upgrade.py --geoip
|
||||
#
|
||||
# This product includes GeoLite data created by MaxMind, available from:
|
||||
# http://www.maxmind.com.
|
||||
#
|
||||
# Ref: http://blog.spiderlabs.com/2010/10/detecting-malice-with-modsecurity-geolocation-data.html
|
||||
# Ref: http://blog.spiderlabs.com/2010/11/detecting-malice-with-modsecurity-ip-forensics.html
|
||||
#
|
||||
# Uncomment this rule to use this feature:
|
||||
#
|
||||
SecGeoLookupDB /usr/share/GeoIP/GeoIPCity.dat
|
||||
|
||||
|
||||
#
|
||||
# -=[ Block Countries ]=-
|
||||
#
|
||||
# Rules in the IP Reputation file can check the client against a list of high
|
||||
# risk country codes. These countries have to be defined in the variable
|
||||
# tx.high_risk_country_codes via their ISO 3166 two-letter country code:
|
||||
# https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements
|
||||
#
|
||||
# If you are sure that you are not getting any legitimate requests from a given
|
||||
# country, then you can disable all access from that country via this variable.
|
||||
# The rule performing the test has the rule id 910100.
|
||||
#
|
||||
# This rule requires SecGeoLookupDB to be enabled and the GeoIP database to be
|
||||
# downloaded (see the section "GeoIP Database" above.)
|
||||
#
|
||||
# By default, the list is empty. A list used by some sites was the following:
|
||||
# setvar:'tx.high_risk_country_codes=UA ID YU LT EG RO BG TR RU PK MY CN'"
|
||||
#
|
||||
# Uncomment this rule to use this feature:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900600,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:'tx.high_risk_country_codes='"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Anti-Automation / DoS Protection ]] ------------------------------------
|
||||
#
|
||||
# Optional DoS protection against clients making requests too quickly.
|
||||
#
|
||||
# When a client is making more than 100 requests (excluding static files) within
|
||||
# 60 seconds, this is considered a 'burst'. After two bursts, the client is
|
||||
# blocked for 600 seconds.
|
||||
#
|
||||
# Requests to static files are not counted towards DoS; they are listed in the
|
||||
# 'tx.static_extensions' setting, which you can change in this file (see
|
||||
# section "HTTP Policy Settings").
|
||||
#
|
||||
# For a detailed description, see rule file REQUEST-912-DOS-PROTECTION.conf.
|
||||
#
|
||||
# Uncomment this rule to use this feature:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900700,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:'tx.dos_burst_time_slice=60',\
|
||||
# setvar:'tx.dos_counter_threshold=100',\
|
||||
# setvar:'tx.dos_block_timeout=600'"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Check UTF-8 encoding ]] ------------------------------------------------
|
||||
#
|
||||
# The CRS can optionally check request contents for invalid UTF-8 encoding.
|
||||
# We only want to apply this check if UTF-8 encoding is actually used by the
|
||||
# site; otherwise it will result in false positives.
|
||||
#
|
||||
# Uncomment this rule to use this feature:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900950,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.crs_validate_utf8_encoding=1"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Blocking Based on IP Reputation ]] ------------------------------------
|
||||
#
|
||||
# Blocking based on reputation is permanent in the CRS. Unlike other rules,
|
||||
# which look at the indvidual request, the blocking of IPs is based on
|
||||
# a persistent record in the IP collection, which remains active for a
|
||||
# certain amount of time.
|
||||
#
|
||||
# There are two ways an individual client can become flagged for blocking:
|
||||
# - External information (RBL, GeoIP, etc.)
|
||||
# - Internal information (Core Rules)
|
||||
#
|
||||
# The record in the IP collection carries a flag, which tags requests from
|
||||
# individual clients with a flag named IP.reput_block_flag.
|
||||
# But the flag alone is not enough to have a client blocked. There is also
|
||||
# a global switch named tx.do_reput_block. This is off by default. If you set
|
||||
# it to 1 (=On), requests from clients with the IP.reput_block_flag will
|
||||
# be blocked for a certain duration.
|
||||
#
|
||||
# Variables
|
||||
# ip.reput_block_flag Blocking flag for the IP collection record
|
||||
# ip.reput_block_reason Reason (= rule message) that caused to blocking flag
|
||||
# tx.do_reput_block Switch deciding if we really block based on flag
|
||||
# tx.reput_block_duration Setting to define the duration of a block
|
||||
#
|
||||
# It may be important to know, that all the other core rules are skipped for
|
||||
# requests, when it is clear that they carry the blocking flag in question.
|
||||
#
|
||||
# Uncomment this rule to use this feature:
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900960,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.do_reput_block=1"
|
||||
#
|
||||
# Uncomment this rule to change the blocking time:
|
||||
# Default: 300 (5 minutes)
|
||||
#
|
||||
#SecAction \
|
||||
# "id:900970,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# setvar:tx.reput_block_duration=300"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Collection timeout ]] --------------------------------------------------
|
||||
#
|
||||
# Set the SecCollectionTimeout directive from the ModSecurity default (1 hour)
|
||||
# to a lower setting which is appropriate to most sites.
|
||||
# This increases performance by cleaning out stale collection (block) entries.
|
||||
#
|
||||
# This value should be greater than or equal to:
|
||||
# tx.reput_block_duration (see section "Blocking Based on IP Reputation") and
|
||||
# tx.dos_block_timeout (see section "Anti-Automation / DoS Protection").
|
||||
#
|
||||
# Ref: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual#wiki-SecCollectionTimeout
|
||||
|
||||
# Please keep this directive uncommented.
|
||||
# Default: 600 (10 minutes)
|
||||
SecCollectionTimeout 600
|
||||
|
||||
|
||||
#
|
||||
# -- [[ Debug Mode ]] ----------------------------------------------------------
|
||||
#
|
||||
# To enable rule development and debugging, CRS has an optional debug mode
|
||||
# that does not block a request, but instead sends detection information
|
||||
# back to the HTTP client.
|
||||
#
|
||||
# This functionality is currently only supported with the Apache web server.
|
||||
# The Apache mod_headers module is required.
|
||||
#
|
||||
# In debug mode, the webserver inserts "X-WAF-Events" / "X-WAF-Score"
|
||||
# response headers whenever a debug client makes a request. Example:
|
||||
#
|
||||
# # curl -v 'http://192.168.1.100/?foo=../etc/passwd'
|
||||
# X-WAF-Events: TX:930110-OWASP_CRS/WEB_ATTACK/DIR_TRAVERSAL-REQUEST_URI,
|
||||
# TX:930120-OWASP_CRS/WEB_ATTACK/FILE_INJECTION-ARGS:foo,
|
||||
# TX:932160-OWASP_CRS/WEB_ATTACK/RCE-ARGS:foo
|
||||
# X-WAF-Score: Total=15; sqli=0; xss=0; rfi=0; lfi=10; rce=5; php=0; http=0; ses=0
|
||||
#
|
||||
# To enable debug mode, include the RESPONSE-981-DEBUG.conf file.
|
||||
# This file resides in a separate folder, as it is not compatible with
|
||||
# nginx and IIS.
|
||||
#
|
||||
# You must specify the source IP address/network where you will be running the
|
||||
# tests from. The source IP will BYPASS all CRS blocking, and will be sent the
|
||||
# response headers as specified above. Be careful to only list your private
|
||||
# IP addresses/networks here.
|
||||
#
|
||||
# Tip: for regression testing of CRS or your own ModSecurity rules, you may
|
||||
# be interested in using the OWASP CRS regression testing suite instead.
|
||||
# View the file util/regression-tests/README for more information.
|
||||
#
|
||||
# Uncomment these rules, filling in your CRS path and the source IP address,
|
||||
# to enable debug mode:
|
||||
#
|
||||
#Include /usr/share/modsecurity-crs/util/debug/RESPONSE-981-DEBUG.conf
|
||||
#SecRule REMOTE_ADDR "@ipMatch 192.168.1.100" \
|
||||
# "id:900980,\
|
||||
# phase:1,\
|
||||
# nolog,\
|
||||
# pass,\
|
||||
# t:none,\
|
||||
# ctl:ruleEngine=DetectionOnly,\
|
||||
# setvar:tx.crs_debug_mode=1"
|
||||
|
||||
|
||||
#
|
||||
# -- [[ End of setup ]] --------------------------------------------------------
|
||||
#
|
||||
# The CRS checks the tx.crs_setup_version variable to ensure that the setup
|
||||
# has been loaded. If you are not planning to use this setup template,
|
||||
# you must manually set the tx.crs_setup_version variable before including
|
||||
# the CRS rules/* files.
|
||||
#
|
||||
# The variable is a numerical representation of the CRS version number.
|
||||
# E.g., v3.0.0 is represented as 300.
|
||||
#
|
||||
SecAction \
|
||||
"id:900990,\
|
||||
phase:1,\
|
||||
nolog,\
|
||||
pass,\
|
||||
t:none,\
|
||||
setvar:tx.crs_setup_version=310"
|
||||
|
||||
|
||||
# -- [[ Customization ]] -------------------------------------------------------
|
||||
|
||||
# triggers on user.profile for google login urls
|
||||
SecRuleRemoveById 930120
|
||||
230
roles/apache/templates/etc_modsecurity_modsecurity.conf.j2
Normal file
230
roles/apache/templates/etc_modsecurity_modsecurity.conf.j2
Normal file
@@ -0,0 +1,230 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# -- Rule engine initialization ----------------------------------------------
|
||||
|
||||
# Enable ModSecurity, attaching it to every transaction. Use detection
|
||||
# only to start with, because that minimises the chances of post-installation
|
||||
# disruption.
|
||||
#
|
||||
SecRuleEngine {{ 'On' if apache_mod_security_enabled else 'DetectionOnly' }}
|
||||
|
||||
|
||||
# -- Request body handling ---------------------------------------------------
|
||||
|
||||
# Allow ModSecurity to access request bodies. If you don't, ModSecurity
|
||||
# won't be able to see any POST parameters, which opens a large security
|
||||
# hole for attackers to exploit.
|
||||
#
|
||||
SecRequestBodyAccess On
|
||||
|
||||
|
||||
# Enable XML request body parser.
|
||||
# Initiate XML Processor in case of xml content-type
|
||||
#
|
||||
SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \
|
||||
"id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML"
|
||||
|
||||
# Enable JSON request body parser.
|
||||
# Initiate JSON Processor in case of JSON content-type; change accordingly
|
||||
# if your application does not use 'application/json'
|
||||
#
|
||||
SecRule REQUEST_HEADERS:Content-Type "application/json" \
|
||||
"id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON"
|
||||
|
||||
# Maximum request body size we will accept for buffering. If you support
|
||||
# file uploads then the value given on the first line has to be as large
|
||||
# as the largest file you are willing to accept. The second value refers
|
||||
# to the size of data, with files excluded. You want to keep that value as
|
||||
# low as practical.
|
||||
#
|
||||
SecRequestBodyLimit 13107200
|
||||
SecRequestBodyNoFilesLimit 131072
|
||||
|
||||
# Store up to 128 KB of request body data in memory. When the multipart
|
||||
# parser reachers this limit, it will start using your hard disk for
|
||||
# storage. That is slow, but unavoidable.
|
||||
#
|
||||
SecRequestBodyInMemoryLimit 131072
|
||||
|
||||
# What do do if the request body size is above our configured limit.
|
||||
# Keep in mind that this setting will automatically be set to ProcessPartial
|
||||
# when SecRuleEngine is set to DetectionOnly mode in order to minimize
|
||||
# disruptions when initially deploying ModSecurity.
|
||||
#
|
||||
SecRequestBodyLimitAction Reject
|
||||
|
||||
# Verify that we've correctly processed the request body.
|
||||
# As a rule of thumb, when failing to process a request body
|
||||
# you should reject the request (when deployed in blocking mode)
|
||||
# or log a high-severity alert (when deployed in detection-only mode).
|
||||
#
|
||||
SecRule REQBODY_ERROR "!@eq 0" \
|
||||
"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2"
|
||||
|
||||
# By default be strict with what we accept in the multipart/form-data
|
||||
# request body. If the rule below proves to be too strict for your
|
||||
# environment consider changing it to detection-only. You are encouraged
|
||||
# _not_ to remove it altogether.
|
||||
#
|
||||
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
|
||||
"id:'200003',phase:2,t:none,log,deny,status:400, \
|
||||
msg:'Multipart request body failed strict validation: \
|
||||
PE %{REQBODY_PROCESSOR_ERROR}, \
|
||||
BQ %{MULTIPART_BOUNDARY_QUOTED}, \
|
||||
BW %{MULTIPART_BOUNDARY_WHITESPACE}, \
|
||||
DB %{MULTIPART_DATA_BEFORE}, \
|
||||
DA %{MULTIPART_DATA_AFTER}, \
|
||||
HF %{MULTIPART_HEADER_FOLDING}, \
|
||||
LF %{MULTIPART_LF_LINE}, \
|
||||
SM %{MULTIPART_MISSING_SEMICOLON}, \
|
||||
IQ %{MULTIPART_INVALID_QUOTING}, \
|
||||
IP %{MULTIPART_INVALID_PART}, \
|
||||
IH %{MULTIPART_INVALID_HEADER_FOLDING}, \
|
||||
FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'"
|
||||
|
||||
# Did we see anything that might be a boundary?
|
||||
#
|
||||
SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \
|
||||
"id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'"
|
||||
|
||||
# PCRE Tuning
|
||||
# We want to avoid a potential RegEx DoS condition
|
||||
#
|
||||
SecPcreMatchLimit 500000
|
||||
SecPcreMatchLimitRecursion 500000
|
||||
|
||||
# Some internal errors will set flags in TX and we will need to look for these.
|
||||
# All of these are prefixed with "MSC_". The following flags currently exist:
|
||||
#
|
||||
# MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded.
|
||||
#
|
||||
SecRule TX:/^MSC_/ "!@streq 0" \
|
||||
"id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'"
|
||||
|
||||
|
||||
# -- Response body handling --------------------------------------------------
|
||||
|
||||
# Allow ModSecurity to access response bodies.
|
||||
# You should have this directive enabled in order to identify errors
|
||||
# and data leakage issues.
|
||||
#
|
||||
# Do keep in mind that enabling this directive does increases both
|
||||
# memory consumption and response latency.
|
||||
#
|
||||
SecResponseBodyAccess On
|
||||
|
||||
# Which response MIME types do you want to inspect? You should adjust the
|
||||
# configuration below to catch documents but avoid static files
|
||||
# (e.g., images and archives).
|
||||
#
|
||||
SecResponseBodyMimeType text/plain text/html text/xml
|
||||
|
||||
# Buffer response bodies of up to 512 KB in length.
|
||||
SecResponseBodyLimit 524288
|
||||
|
||||
# What happens when we encounter a response body larger than the configured
|
||||
# limit? By default, we process what we have and let the rest through.
|
||||
# That's somewhat less secure, but does not break any legitimate pages.
|
||||
#
|
||||
SecResponseBodyLimitAction ProcessPartial
|
||||
|
||||
|
||||
# -- Filesystem configuration ------------------------------------------------
|
||||
|
||||
# The location where ModSecurity stores temporary files (for example, when
|
||||
# it needs to handle a file upload that is larger than the configured limit).
|
||||
#
|
||||
# This default setting is chosen due to all systems have /tmp available however,
|
||||
# this is less than ideal. It is recommended that you specify a location that's private.
|
||||
#
|
||||
SecTmpDir /tmp/
|
||||
|
||||
# The location where ModSecurity will keep its persistent data. This default setting
|
||||
# is chosen due to all systems have /tmp available however, it
|
||||
# too should be updated to a place that other users can't access.
|
||||
#
|
||||
SecDataDir /tmp/
|
||||
|
||||
|
||||
# -- File uploads handling configuration -------------------------------------
|
||||
|
||||
# The location where ModSecurity stores intercepted uploaded files. This
|
||||
# location must be private to ModSecurity. You don't want other users on
|
||||
# the server to access the files, do you?
|
||||
#
|
||||
#SecUploadDir /opt/modsecurity/var/upload/
|
||||
|
||||
# By default, only keep the files that were determined to be unusual
|
||||
# in some way (by an external inspection script). For this to work you
|
||||
# will also need at least one file inspection rule.
|
||||
#
|
||||
#SecUploadKeepFiles RelevantOnly
|
||||
|
||||
# Uploaded files are by default created with permissions that do not allow
|
||||
# any other user to access them. You may need to relax that if you want to
|
||||
# interface ModSecurity to an external program (e.g., an anti-virus).
|
||||
#
|
||||
#SecUploadFileMode 0600
|
||||
|
||||
|
||||
# -- Debug log configuration -------------------------------------------------
|
||||
|
||||
# The default debug log configuration is to duplicate the error, warning
|
||||
# and notice messages from the error log.
|
||||
#
|
||||
#SecDebugLog /opt/modsecurity/var/log/debug.log
|
||||
#SecDebugLogLevel 3
|
||||
|
||||
|
||||
# -- Audit log configuration -------------------------------------------------
|
||||
|
||||
# Log the transactions that are marked by a rule, as well as those that
|
||||
# trigger a server error (determined by a 5xx or 4xx, excluding 404,
|
||||
# level response status codes).
|
||||
#
|
||||
SecAuditEngine RelevantOnly
|
||||
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
|
||||
|
||||
# Log everything we know about a transaction.
|
||||
SecAuditLogParts ABDEFHIJZ
|
||||
|
||||
# Use a single file for logging. This is much easier to look at, but
|
||||
# assumes that you will use the audit log only ocassionally.
|
||||
#
|
||||
SecAuditLogType Serial
|
||||
SecAuditLogFormat JSON
|
||||
SecAuditLog /var/log/apache2/modsec_audit.log
|
||||
#SecAuditLog "|/usr/bin/socat -u - tcp:127.0.0.1:5172"
|
||||
|
||||
# Specify the path for concurrent audit logging.
|
||||
#SecAuditLogStorageDir /opt/modsecurity/var/audit/
|
||||
|
||||
|
||||
# -- Miscellaneous -----------------------------------------------------------
|
||||
|
||||
# Use the most commonly used application/x-www-form-urlencoded parameter
|
||||
# separator. There's probably only one application somewhere that uses
|
||||
# something else so don't expect to change this value.
|
||||
#
|
||||
SecArgumentSeparator &
|
||||
|
||||
# Settle on version 0 (zero) cookies, as that is what most applications
|
||||
# use. Using an incorrect cookie version may open your installation to
|
||||
# evasion attacks (against the rules that examine named cookies).
|
||||
#
|
||||
SecCookieFormat 0
|
||||
|
||||
# Specify your Unicode Code Point.
|
||||
# This mapping is used by the t:urlDecodeUni transformation function
|
||||
# to properly map encoded data to your language. Properly setting
|
||||
# these directives helps to reduce false positives and negatives.
|
||||
#
|
||||
SecUnicodeMapFile unicode.mapping 20127
|
||||
|
||||
# Improve the quality of ModSecurity by sharing information about your
|
||||
# current ModSecurity version and dependencies versions.
|
||||
# The following information will be shared: ModSecurity version,
|
||||
# Web Server version, APR version, PCRE version, Lua version, Libxml2
|
||||
# version, Anonymous unique id for host.
|
||||
SecStatusEngine On
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
[Service]
|
||||
PrivateTmp=false
|
||||
21
roles/apache_php/defaults/main.yml
Normal file
21
roles/apache_php/defaults/main.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
|
||||
apache_phpfpm_php: "{{ 'php7.4' if ansible_distribution_release == 'focal' else 'php7.4' }}"
|
||||
|
||||
apache_phpfpm_etc_dir: "{{ '/etc/php/7.4/fpm' if ansible_distribution_release == 'focal' else '/etc/php/7.4/fpm' }}"
|
||||
|
||||
apache_phpfpm_max_workers: 30
|
||||
apache_phpfpm_timeout: 120
|
||||
|
||||
apache_phpfpm_php_settings:
|
||||
short_open_tag: on
|
||||
display_errors: off
|
||||
|
||||
apache_phpfpm_php_admin_settings:
|
||||
log_errors: on
|
||||
error_log: /var/log/php-fpm.$pool.log
|
||||
memory_limit: 512M
|
||||
open_basedir: /srv/www:/var/www:/opt:/usr/share:/var/lib/{{ apache_phpfpm_php }}:/var/lib/php:/dev:/tmp:/var/log/kc:/var/spool/asterisk
|
||||
|
||||
apache_phpfpm_xcache_size: 128M
|
||||
|
||||
5
roles/apache_php/handlers/main.yml
Normal file
5
roles/apache_php/handlers/main.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
|
||||
- name: Reload PHP-FPM
|
||||
service: name={{ apache_phpfpm_php }}-fpm state=reloaded
|
||||
|
||||
4
roles/apache_php/meta/main.yml
Normal file
4
roles/apache_php/meta/main.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
|
||||
dependencies:
|
||||
- apache
|
||||
65
roles/apache_php/tasks/main.yml
Normal file
65
roles/apache_php/tasks/main.yml
Normal file
@@ -0,0 +1,65 @@
|
||||
---
|
||||
|
||||
- name: Install PHP packages
|
||||
apt:
|
||||
pkg:
|
||||
- "{{ apache_phpfpm_php }}-fpm"
|
||||
- php-apcu
|
||||
# check_php-fpm nagios plugin dependencies:
|
||||
- libany-moose-perl
|
||||
- libjson-perl
|
||||
- libjson-xs-perl
|
||||
state: present
|
||||
tags: packages
|
||||
|
||||
- name: Disable Apache modules
|
||||
apache2_module: name="{{ item }}" state=absent force=yes
|
||||
with_items:
|
||||
- "{{ apache_phpfpm_php }}"
|
||||
notify: Restart Apache
|
||||
tags: configs
|
||||
|
||||
- name: Enable Apache modules
|
||||
apache2_module: name="{{ item }}" state=present force=yes
|
||||
with_items:
|
||||
- proxy_fcgi
|
||||
notify: Restart Apache
|
||||
tags: configs
|
||||
|
||||
- name: Ensure mod-php is not installed
|
||||
apt:
|
||||
pkg:
|
||||
- libapache2-mod-{{ apache_phpfpm_php }}
|
||||
- "{{ apache_phpfpm_php }}-cgi"
|
||||
state: absent
|
||||
purge: yes
|
||||
notify: Restart Apache
|
||||
tags: packages
|
||||
|
||||
- name: Install Apache other configs
|
||||
template: src="etc_apache2_conf-available_php-fpm.conf.j2" dest="/etc/apache2/conf-available/{{ apache_phpfpm_php }}-fpm.conf"
|
||||
notify: Reload Apache
|
||||
tags: configs
|
||||
|
||||
- name: Install PHP-FPM pool config
|
||||
template: src=etc_php_fpm_pool.d_www.conf.j2 dest={{ apache_phpfpm_etc_dir }}/pool.d/www.conf
|
||||
notify: Reload PHP-FPM
|
||||
tags: configs
|
||||
|
||||
- name: Install the FGCI client script
|
||||
template: src=usr_local_bin_fcgi-client dest=/usr/local/bin/fcgi-client mode=0755
|
||||
|
||||
- name: Enable PHP-FPM
|
||||
file: dest=/etc/apache2/conf-enabled/{{ apache_phpfpm_php }}-fpm.conf src=../conf-available/{{ apache_phpfpm_php }}-fpm.conf state=link
|
||||
notify: Reload Apache
|
||||
tags: configs
|
||||
|
||||
- name: Ensure PHP-FPM is running
|
||||
service: name={{ apache_phpfpm_php }}-fpm state=started enabled=yes
|
||||
tags: configs
|
||||
|
||||
- name: Register the php-fpm service in Consul
|
||||
template: dest=/etc/consul.d/service-php-fpm.hcl src=etc_consul.d_service-php-fpm.hcl.j2
|
||||
when: apache_consul_service
|
||||
notify: Reload consul
|
||||
tags: configs
|
||||
@@ -0,0 +1,12 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
<Proxy "unix:/run/php/{{ apache_phpfpm_php }}-fpm.sock|fcgi://{{ apache_phpfpm_php }}-fpm">
|
||||
ProxySet max={{ apache_phpfpm_max_workers // 2 - 1 }}
|
||||
ProxySet timeout={{ apache_phpfpm_timeout }}
|
||||
ProxySet retry=0
|
||||
</Proxy>
|
||||
|
||||
<FilesMatch "\.php$">
|
||||
SetEnvIf ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
|
||||
SetHandler "proxy:fcgi://{{ apache_phpfpm_php }}-fpm"
|
||||
</FilesMatch>
|
||||
@@ -0,0 +1,6 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
service {
|
||||
name = "php-fpm"
|
||||
port = 443
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
ARGS= \
|
||||
--phpfpm.socket-directories=/run/php \
|
||||
--phpfpm.status-path=/_fpm/status
|
||||
@@ -0,0 +1,2 @@
|
||||
# {{ ansible_managed }}
|
||||
command[check_php-fpm]={{ nagios_nrpe_tools_dir }}/plugins/check_php-fpm -s /run/php/{{ apache_phpfpm_php }}-fpm.sock -w active_workers:{{ (apache_phpfpm_max_workers * 80 / 100)|int }} -c active_workers:{{ (apache_phpfpm_max_workers * 90 / 100)|int }}
|
||||
85
roles/apache_php/templates/etc_php_fpm_pool.d_www.conf.j2
Normal file
85
roles/apache_php/templates/etc_php_fpm_pool.d_www.conf.j2
Normal file
@@ -0,0 +1,85 @@
|
||||
; {{ ansible_managed }}
|
||||
|
||||
[www]
|
||||
|
||||
;prefix = /path/to/pools/$pool
|
||||
|
||||
user = www-data
|
||||
group = www-data
|
||||
|
||||
listen = /run/php/{{ apache_phpfpm_php }}-fpm.sock
|
||||
listen.owner = www-data
|
||||
listen.group = www-data
|
||||
listen.mode = 0660
|
||||
;listen.allowed_clients = 127.0.0.1
|
||||
|
||||
; process.priority = -19
|
||||
|
||||
pm = dynamic
|
||||
pm.max_children = {{ apache_phpfpm_max_workers }}
|
||||
pm.start_servers = 3
|
||||
pm.min_spare_servers = 2
|
||||
pm.max_spare_servers = 7
|
||||
;pm.process_idle_timeout = 10s
|
||||
pm.max_requests = {{ apache_phpfpm_max_requests | default(50000) }}
|
||||
|
||||
pm.status_path = /_fpm/status
|
||||
ping.path = /_fpm/ping
|
||||
ping.response = pong
|
||||
|
||||
;access.log = /var/log/{{ apache_phpfpm_php }}-fpm.$pool.access.log
|
||||
;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
|
||||
;slowlog = /var/log/{{ apache_phpfpm_php }}-fpm.$pool.slow.log
|
||||
;request_slowlog_timeout = 10s
|
||||
|
||||
;request_terminate_timeout = 0
|
||||
|
||||
;rlimit_files = 1024
|
||||
;rlimit_core = 0
|
||||
|
||||
;chroot =
|
||||
chdir = /
|
||||
|
||||
;catch_workers_output = yes
|
||||
;clear_env = no
|
||||
|
||||
;security.limit_extensions = .php .php3 .php4 .php5 .php7
|
||||
|
||||
;env[HOSTNAME] = $HOSTNAME
|
||||
;env[PATH] = /usr/local/bin:/usr/bin:/bin
|
||||
;env[TMP] = /tmp
|
||||
;env[TMPDIR] = /tmp
|
||||
;env[TEMP] = /tmp
|
||||
|
||||
; Additional php.ini defines, specific to this pool of workers. These settings
|
||||
; overwrite the values previously defined in the php.ini. The directives are the
|
||||
; same as the PHP SAPI:
|
||||
; php_value/php_flag - you can set classic ini defines which can
|
||||
; be overwritten from PHP call 'ini_set'.
|
||||
; php_admin_value/php_admin_flag - these directives won't be overwritten by
|
||||
; PHP call 'ini_set'
|
||||
; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no.
|
||||
|
||||
; Defining 'extension' will load the corresponding shared extension from
|
||||
; extension_dir. Defining 'disable_functions' or 'disable_classes' will not
|
||||
; overwrite previously defined php.ini values, but will append the new value
|
||||
; instead.
|
||||
|
||||
; Note: path INI options can be relative and will be expanded with the prefix
|
||||
; (pool, global or /usr)
|
||||
|
||||
{% for key, value in apache_phpfpm_php_admin_settings|dictsort %}
|
||||
{% if value in (True,False) %}
|
||||
php_admin_flag[{{ key }}] = {{ 'on' if value else 'off' }}
|
||||
{% else %}
|
||||
php_admin_value[{{ key }}] = {{ value }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% for key, value in apache_phpfpm_php_settings|dictsort %}
|
||||
{% if value in (True,False) %}
|
||||
php_flag[{{ key }}] = {{ 'on' if value else 'off' }}
|
||||
{% else %}
|
||||
php_value[{{ key }}] = {{ value }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,88 @@
|
||||
; {{ ansible_managed }}
|
||||
; configuration for php Xcache module
|
||||
|
||||
[xcache-common]
|
||||
;; non-Windows example:
|
||||
extension = xcache.so
|
||||
;; Windows example:
|
||||
; extension = php_xcache.dll
|
||||
|
||||
[xcache.admin]
|
||||
xcache.admin.enable_auth = On
|
||||
; Configure this to use admin pages
|
||||
; xcache.admin.user = "mOo"
|
||||
; xcache.admin.pass = md5($your_password)
|
||||
; xcache.admin.pass = ""
|
||||
xcache.admin.user = "admin"
|
||||
xcache.admin.pass = "726be9b7e6dea1ed28c70800d68be36c"
|
||||
|
||||
[xcache]
|
||||
; ini only settings, all the values here is default unless explained
|
||||
|
||||
; select low level shm implemenation
|
||||
xcache.shm_scheme = "mmap"
|
||||
; to disable: xcache.size=0
|
||||
; to enable : xcache.size=64M etc (any size > 0) and your system mmap allows
|
||||
xcache.size = {{ apache_phpfpm_xcache_size }}
|
||||
; set to cpu count (cat /proc/cpuinfo |grep -c processor)
|
||||
xcache.count = 2
|
||||
; just a hash hints, you can always store count(items) > slots
|
||||
xcache.slots = 8K
|
||||
; ttl of the cache item, 0=forever
|
||||
xcache.ttl = 0
|
||||
; interval of gc scanning expired items, 0=no scan, other values is in seconds
|
||||
xcache.gc_interval = 0
|
||||
|
||||
; same as aboves but for variable cache
|
||||
xcache.var_size = 64M
|
||||
xcache.var_count = 1
|
||||
xcache.var_slots = 8K
|
||||
; default value for $ttl parameter of xcache_*() functions
|
||||
xcache.var_ttl = 0
|
||||
; hard limit ttl that cannot be exceed by xcache_*() functions. 0=unlimited
|
||||
xcache.var_maxttl = 0
|
||||
xcache.var_gc_interval = 300
|
||||
|
||||
; mode:0, const string specified by xcache.var_namespace
|
||||
; mode:1, $_SERVER[xcache.var_namespace]
|
||||
; mode:2, uid or gid (specified by xcache.var_namespace)
|
||||
xcache.var_namespace_mode = 0
|
||||
xcache.var_namespace = ""
|
||||
|
||||
; N/A for /dev/zero
|
||||
xcache.readonly_protection = Off
|
||||
; for *nix, xcache.mmap_path is a file path, not directory. (auto create/overwrite)
|
||||
; Use something like "/tmp/xcache" instead of "/dev/*" if you want to turn on ReadonlyProtection
|
||||
; different process group of php won't share the same /tmp/xcache
|
||||
; for win32, xcache.mmap_path=anonymous map name, not file path
|
||||
xcache.mmap_path = "/dev/zero"
|
||||
|
||||
|
||||
; Useful when XCache crash. leave it blank(disabled) or "/tmp/phpcore/" (writable by php)
|
||||
xcache.coredump_directory = ""
|
||||
; Windows only. leave it as 0 (default) until you're told by XCache dev
|
||||
xcache.coredump_type = 0
|
||||
|
||||
; disable cache after crash
|
||||
xcache.disable_on_crash = Off
|
||||
|
||||
; enable experimental documented features for each release if available
|
||||
xcache.experimental = Off
|
||||
|
||||
; per request settings. can ini_set, .htaccess etc
|
||||
xcache.cacher = On
|
||||
xcache.stat = On
|
||||
xcache.optimizer = Off
|
||||
|
||||
[xcache.coverager]
|
||||
; enabling this feature will impact performance
|
||||
; enabled only if xcache.coverager == On && xcache.coveragedump_directory == "non-empty-value"
|
||||
|
||||
; per request settings. can ini_set, .htaccess etc
|
||||
; enable coverage data collecting and xcache_coverager_start/stop/get/clean() functions
|
||||
xcache.coverager = Off
|
||||
xcache.coverager_autostart = On
|
||||
|
||||
; set in php ini file only
|
||||
; make sure it's readable (open_basedir is checked) by coverage viewer script
|
||||
xcache.coveragedump_directory = ""
|
||||
46
roles/apache_php/templates/usr_local_bin_fcgi-client
Normal file
46
roles/apache_php/templates/usr_local_bin_fcgi-client
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Pod::Usage;
|
||||
use Getopt::Long;
|
||||
use IO::Socket;
|
||||
use IO::Socket::UNIX;
|
||||
use lib '/usr/local/lib/nagios/plugins';
|
||||
use FCGI::Client;
|
||||
|
||||
GetOptions(
|
||||
'h|help' => \my $help,
|
||||
) or pod2usage();
|
||||
pod2usage() if $help;
|
||||
pod2usage() if @ARGV < 2;
|
||||
my ($fcgi_file, $uri, $query_string) = @ARGV;
|
||||
|
||||
my $sock = IO::Socket::UNIX->new(
|
||||
Type => SOCK_STREAM(),
|
||||
Peer => $fcgi_file
|
||||
) or die $!;
|
||||
|
||||
my $client = FCGI::Client::Connection->new( sock => $sock );
|
||||
my ( $stdout, $stderr ) = $client->request(
|
||||
+{
|
||||
REQUEST_METHOD => 'GET',
|
||||
REQUEST_URI => $uri,
|
||||
SCRIPT_FILENAME => "/a/b/c$uri",
|
||||
SCRIPT_NAME => $uri,
|
||||
QUERY_STRING => $query_string || '',
|
||||
},
|
||||
''
|
||||
);
|
||||
print STDERR $stderr if $stderr;
|
||||
print $stdout;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
fcgi-client -
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
$ fcgi-client foo.fcgi URI [foo=bar&hoge=fuga]
|
||||
19
roles/consul/defaults/main.yml
Normal file
19
roles/consul/defaults/main.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
|
||||
consul_version: 1.8.5
|
||||
consul_url: https://releases.hashicorp.com/consul/{{ consul_version }}/consul_{{ consul_version }}_{{ ansible_system|lower }}_{{ ansible_userspace_architecture|replace('x86_64', 'amd64') }}.zip
|
||||
|
||||
consul_data_dir: /opt/consul
|
||||
consul_config_dir: /etc/consul.d
|
||||
consul_server: true
|
||||
consul_bootstrap_expect: 2
|
||||
consul_wan_peers: []
|
||||
consul_encrypt_key: eRhnp22+c0bkV0wPolk6Mw==
|
||||
|
||||
consul_expose_apis: no
|
||||
consul_client_addr: "{{ '0.0.0.0' if consul_expose_apis else '127.0.0.1' }}"
|
||||
|
||||
consul_stub_mode: no
|
||||
consul_dns_forwarders: []
|
||||
|
||||
consul_firewall: yes
|
||||
7
roles/consul/handlers/main.yml
Normal file
7
roles/consul/handlers/main.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
|
||||
- name: Restart consul
|
||||
service: name=consul state=restarted
|
||||
|
||||
- name: Reload consul
|
||||
service: name=consul state=reloaded
|
||||
6
roles/consul/meta/main.yml
Normal file
6
roles/consul/meta/main.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
|
||||
dependencies:
|
||||
- role: firewall
|
||||
when: consul_firewall
|
||||
- network
|
||||
122
roles/consul/tasks/main.yml
Normal file
122
roles/consul/tasks/main.yml
Normal file
@@ -0,0 +1,122 @@
|
||||
---
|
||||
|
||||
|
||||
- name: Ensure the consul user exists
|
||||
user:
|
||||
name: consul
|
||||
home: '{{ consul_data_dir }}'
|
||||
system: yes
|
||||
groups: ssl-cert
|
||||
append: yes
|
||||
shell: /bin/false
|
||||
createhome: no
|
||||
state: present
|
||||
tags: packages
|
||||
|
||||
- name: Ensure the consul config dir exists
|
||||
file:
|
||||
dest: /etc/consul.d
|
||||
owner: root
|
||||
group: consul
|
||||
mode: 0750
|
||||
state: directory
|
||||
tags: packages
|
||||
|
||||
- name: Ensure the consul data dir exists
|
||||
file:
|
||||
dest: /opt/consul
|
||||
owner: consul
|
||||
group: consul
|
||||
mode: 0750
|
||||
state: directory
|
||||
tags: packages
|
||||
|
||||
- name: Remove old consul config
|
||||
file:
|
||||
dest: /etc/consul.d/00-base_config.json
|
||||
state: absent
|
||||
tags: configs
|
||||
|
||||
- name: Install consul config
|
||||
template:
|
||||
dest: /etc/consul.d/00-base_config.hcl
|
||||
src: etc_consul.d_00-base_config.hcl.j2
|
||||
#validate: 'consul validate %s'
|
||||
mode: 0640
|
||||
owner: root
|
||||
group: consul
|
||||
notify: Restart consul
|
||||
tags:
|
||||
- configs
|
||||
- consul.conf
|
||||
|
||||
- name: Install consul service config
|
||||
template:
|
||||
dest: /etc/default/consul
|
||||
src: etc_default_consul.j2
|
||||
when: not consul_stub_mode
|
||||
notify: Restart consul
|
||||
tags: configs
|
||||
|
||||
- name: Install consul service
|
||||
template:
|
||||
dest: /etc/systemd/system/consul.service
|
||||
src: etc_systemd_system_consul.service.j2
|
||||
when: not consul_stub_mode
|
||||
notify: Restart consul
|
||||
tags: configs
|
||||
|
||||
- name: Enable the consul service
|
||||
systemd:
|
||||
name: consul
|
||||
state: "{{ 'started' if not consul_stub_mode else 'stopped' }}"
|
||||
enabled: "{{ not consul_stub_mode }}"
|
||||
daemon_reload: yes
|
||||
when: not consul_stub_mode
|
||||
tags: configs
|
||||
|
||||
- name: Remove the master token if present
|
||||
lineinfile:
|
||||
dest: /root/.bashrc
|
||||
regexp: '^export CONSUL_HTTP_TOKEN=.*'
|
||||
state: absent
|
||||
when: consul_acl_master_token is defined and consul_acl_master_token and not consul_stub_mode
|
||||
tags: configs
|
||||
|
||||
- name: Install packages needed by consul-tag
|
||||
apt:
|
||||
pkg:
|
||||
- python3
|
||||
- python3-requests
|
||||
state: present
|
||||
when: not consul_stub_mode
|
||||
tags: consul-tag
|
||||
|
||||
- name: Install consul-tag
|
||||
template:
|
||||
dest: /usr/local/bin/consul-tag
|
||||
src: usr_local_bin_consul-tag.j2
|
||||
mode: 0755
|
||||
owner: root
|
||||
group: root
|
||||
when: not consul_stub_mode
|
||||
tags: consul-tag
|
||||
|
||||
- name: Remove old firewall config
|
||||
file: dest=/etc/firewall/rules-v4.d/28_consul.sh state=absent
|
||||
when: consul_firewall and not consul_stub_mode
|
||||
notify: Restart firewall
|
||||
tags:
|
||||
- configs
|
||||
- firewall
|
||||
|
||||
- name: Install the consul firewall config
|
||||
template:
|
||||
dest: /etc/firewall/rules-v4.d/78_consul.sh
|
||||
src: etc_firewall_rules-v4.d_78_consul.sh.j2
|
||||
mode: 0600
|
||||
when: consul_firewall
|
||||
notify: Restart firewall
|
||||
tags:
|
||||
- configs
|
||||
- firewall
|
||||
83
roles/consul/templates/etc_consul.d_00-base_config.hcl.j2
Normal file
83
roles/consul/templates/etc_consul.d_00-base_config.hcl.j2
Normal file
@@ -0,0 +1,83 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Logging
|
||||
enable_syslog = true
|
||||
log_level = "INFO"
|
||||
disable_update_check = true
|
||||
|
||||
# Basics
|
||||
data_dir = "{{ consul_data_dir }}"
|
||||
datacenter = "{{ datacenter_id }}"
|
||||
server = {{ 'false' if consul_server else 'true' }}
|
||||
ui = true
|
||||
|
||||
# Network
|
||||
{% if consul_bootstrap_expect > 0 %}
|
||||
encrypt = "{{ consul_encrypt_key }}"
|
||||
{% endif %}
|
||||
client_addr = "{{ consul_client_addr }}"
|
||||
bind_addr = "{{ network_private_ip }}"
|
||||
advertise_addr = "{{ network_private_ip }}"
|
||||
retry_join = [
|
||||
{% for peer in consul_servers if peer != ansible_hostname and hostvars[peer].datacenter_id == datacenter_id %}
|
||||
"{{ hostvars[peer].network_private_ip }}"{{ ',' if not loop.last else '' }}
|
||||
{% endfor %}
|
||||
]
|
||||
{% if consul_server %}
|
||||
{% if consul_bootstrap_expect > 0 %}
|
||||
bootstrap_expect = {{ consul_bootstrap_expect }}
|
||||
{% endif %}
|
||||
rejoin_after_leave = true
|
||||
retry_join_wan = [
|
||||
{% for peer in consul_servers if hostvars[peer].datacenter_id != datacenter_id %}
|
||||
"{{ hostvars[peer].network_private_ip }}"{{ ',' if not loop.last else '' }}
|
||||
{% endfor %}
|
||||
]
|
||||
{% endif %}
|
||||
|
||||
# TLS
|
||||
#ports {
|
||||
# https = 8501
|
||||
#}
|
||||
#key_file = "/etc/letsencrypt/live/{{ ansible_hostname }}.maruntiel.net/privkey1.pem"
|
||||
#cert_file = "/etc/letsencrypt/live/{{ ansible_hostname }}.maruntiel.net/fullchain1.pem"
|
||||
#ca_file = "/etc/letsencrypt/live/{{ ansible_hostname }}.maruntiel.net/chain1.pem"
|
||||
#verify_incoming = true
|
||||
#verify_outgoing = true
|
||||
#tls_min_version = "tls12"
|
||||
|
||||
# Features
|
||||
enable_script_checks = true
|
||||
disable_remote_exec = true
|
||||
|
||||
# ACLs
|
||||
#{% if consul_acl_datacenter is defined and consul_acl_datacenter %}
|
||||
#acl_datacenter = "{{ consul_acl_datacenter }}"
|
||||
#acl_default_policy = "deny"
|
||||
#acl_down_policy = "extend-cache"
|
||||
#acl_agent_token = "{{ consul_acl_agent_token }}"
|
||||
#acl_token = "{{ consul_acl_token }}"
|
||||
#{% if datacenter_id != consul_acl_datacenter %}
|
||||
#acl_replication_token = "{{ consul_acl_replication_token | default(consul_acl_master_token) }}"
|
||||
#{% endif %}
|
||||
#{% endif %}
|
||||
|
||||
# DNS
|
||||
dns_config {
|
||||
node_ttl = "60s"
|
||||
service_ttl {
|
||||
"*" = "15s"
|
||||
}
|
||||
}
|
||||
|
||||
# Metadata
|
||||
node_meta {
|
||||
architecture = "{{ ansible_userspace_architecture }}"
|
||||
product_name = "{{ ansible_system_vendor|replace(' Inc.', '') }} {{ ansible_product_name }}"
|
||||
virtualization_role = "{{ ansible_virtualization_role }}"
|
||||
}
|
||||
|
||||
# Consul Stats
|
||||
telemetry {
|
||||
disable_hostname = true
|
||||
}
|
||||
5
roles/consul/templates/etc_default_consul.j2
Normal file
5
roles/consul/templates/etc_default_consul.j2
Normal file
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if consul_ui_beta|default(False) %}
|
||||
ui_config=enable
|
||||
{% endif %}
|
||||
@@ -0,0 +1,25 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if not consul_stub_mode %}
|
||||
{% if consul_server %}
|
||||
iptables -A internal-in -p tcp --dport 8300:8302 -m comment --comment "consul" -j ACCEPT
|
||||
iptables -A internal-in -p udp --dport 8300:8302 -m comment --comment "consul" -j ACCEPT
|
||||
{% else %}
|
||||
{% for ip in datacenter_local_networks %}
|
||||
iptables -A internal-in -s {{ ip }} -p tcp --dport 8300:8302 -m comment --comment "consul" -j ACCEPT
|
||||
iptables -A internal-in -s {{ ip }} -p udp --dport 8300:8302 -m comment --comment "consul" -j ACCEPT
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if consul_expose_apis %}
|
||||
iptables -A internal-in -p tcp --dport 8500:8501 -m comment --comment "consul-http" -j ACCEPT
|
||||
iptables -A internal-in -p tcp --dport 8600 -m comment --comment "consul-dns" -j ACCEPT
|
||||
iptables -A internal-in -p udp --dport 8600 -m comment --comment "consul-dns" -j ACCEPT
|
||||
{% endif %}
|
||||
|
||||
iptables -A internal-out -p tcp --dport 8300:8302 -m comment --comment "consul" -j ACCEPT
|
||||
iptables -A internal-out -p udp --dport 8300:8302 -m comment --comment "consul" -j ACCEPT
|
||||
iptables -A internal-out -p tcp --dport 8500:8501 -m comment --comment "consul-http" -j ACCEPT
|
||||
iptables -A internal-out -p tcp --dport 8600 -m comment --comment "consul-dns" -j ACCEPT
|
||||
iptables -A internal-out -p udp --dport 8600 -m comment --comment "consul-dns" -j ACCEPT
|
||||
{% endif %}
|
||||
20
roles/consul/templates/etc_systemd_system_consul.service.j2
Normal file
20
roles/consul/templates/etc_systemd_system_consul.service.j2
Normal file
@@ -0,0 +1,20 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
[Unit]
|
||||
Description=Consul Agent
|
||||
Requires=network-online.target
|
||||
After=network-online.target
|
||||
RequiresMountsFor={{ consul_data_dir }}
|
||||
|
||||
[Service]
|
||||
EnvironmentFile=-/etc/default/consul
|
||||
ExecStart=/usr/local/bin/consul agent $CONSUL_FLAGS -config-dir={{ consul_config_dir }} -config-dir={{ consul_data_dir }}
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
KillSignal=SIGINT
|
||||
StandardOutput=null
|
||||
User=consul
|
||||
Group=consul
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
71
roles/consul/templates/usr_local_bin_consul-tag.j2
Normal file
71
roles/consul/templates/usr_local_bin_consul-tag.j2
Normal file
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/python3
|
||||
# {{ ansible_managed }}
|
||||
|
||||
import os
|
||||
import sys
|
||||
import requests
|
||||
|
||||
CONSUL_API = 'http://localhost:8500'
|
||||
|
||||
|
||||
def get_service(sess, service_id):
|
||||
r = sess.get(CONSUL_API + '/v1/agent/services', timeout=2)
|
||||
r.raise_for_status()
|
||||
services = r.json()
|
||||
|
||||
for svc in services.values():
|
||||
if svc['ID'] == service_id:
|
||||
return svc
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def change_service_tags(service, tags_to_add, tags_to_remove):
|
||||
with requests.Session() as sess:
|
||||
sess.headers = {'X-Consul-Token': os.getenv('CONSUL_HTTP_TOKEN')}
|
||||
|
||||
svc = get_service(sess, service)
|
||||
if svc:
|
||||
new_tags = (set(svc.get('Tags', [])) | tags_to_add) - tags_to_remove
|
||||
new_svc = {
|
||||
'ID': svc['ID'],
|
||||
'Name': svc['Service'],
|
||||
'Address': svc.get('Address', ''),
|
||||
'Port': svc.get('Port', 0),
|
||||
'Meta': svc.get('Meta', {}),
|
||||
'Tags': sorted(list(new_tags)),
|
||||
'EnableTagOverride': svc.get('EnableTagOverride', False),
|
||||
}
|
||||
for k, v in new_svc.items():
|
||||
print('{} = {}'.format(k, v))
|
||||
r = sess.put(CONSUL_API + '/v1/agent/service/register', json=new_svc, timeout=2)
|
||||
r.raise_for_status()
|
||||
|
||||
|
||||
def main(argv):
|
||||
if len(argv) < 3:
|
||||
print("Usage: consul-tag service +tag -tag...")
|
||||
return 1
|
||||
|
||||
service = argv[1]
|
||||
tags_to_add = set()
|
||||
tags_to_remove = set()
|
||||
for tag in argv[2:]:
|
||||
if tag.startswith('-'):
|
||||
tags_to_remove.add(tag[1:])
|
||||
elif tag.startswith('+'):
|
||||
tags_to_add.add(tag[1:])
|
||||
else:
|
||||
tags_to_add.add(tag)
|
||||
|
||||
try:
|
||||
change_service_tags(service, tags_to_add, tags_to_remove)
|
||||
except Exception as exc:
|
||||
print("Error: {}".format(exc))
|
||||
return 2
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
||||
28
roles/firewall/defaults/main.yml
Normal file
28
roles/firewall/defaults/main.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
|
||||
firewall_enabled: yes
|
||||
firewall_standard_rules: yes
|
||||
firewall_log_prefix: "FW:"
|
||||
firewall_whitelist_ip: []
|
||||
firewall_whitelist_ipv6: []
|
||||
firewall_late_whitelist_ip: []
|
||||
firewall_late_whitelist_ipv6: []
|
||||
|
||||
firewall_input_default_drop: true
|
||||
firewall_output_default_drop: true
|
||||
firewall_output_whitelist_domains: []
|
||||
firewall_output_whitelist_ipv4: []
|
||||
firewall_output_whitelist_ipv6: []
|
||||
firewall_output_learning: false
|
||||
|
||||
firewall_whitelist_office_ip: []
|
||||
firewall_whitelist_office_ports: []
|
||||
|
||||
firewall_ssh_acl: []
|
||||
firewall_ssh_acl_extra: []
|
||||
firewall_influx_acl: []
|
||||
firewall_influx_acl_extra: []
|
||||
firewall_allow_internal_dns: true
|
||||
|
||||
firewall_custom_ipv4_rules: ""
|
||||
firewall_custom_ipv6_rules: ""
|
||||
4
roles/firewall/handlers/main.yml
Normal file
4
roles/firewall/handlers/main.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
- name: Restart firewall
|
||||
service:
|
||||
name: firewall
|
||||
state: restarted
|
||||
122
roles/firewall/tasks/main.yml
Normal file
122
roles/firewall/tasks/main.yml
Normal file
@@ -0,0 +1,122 @@
|
||||
---
|
||||
|
||||
- name: Ensure iptables packages are installed
|
||||
apt:
|
||||
pkg:
|
||||
- iptables
|
||||
- ipset
|
||||
- conntrack
|
||||
- ipv6calc # Required by update-firewall-outbound
|
||||
state: present
|
||||
when: firewall_run is not defined
|
||||
tags: packages
|
||||
|
||||
- name: Install the firewall init.d script
|
||||
template:
|
||||
dest: /etc/init.d/firewall
|
||||
src: etc_init.d_firewall.j2
|
||||
mode: 0755
|
||||
owner: root
|
||||
group: root
|
||||
when: firewall_run is not defined and firewall_enabled
|
||||
tags:
|
||||
- configs
|
||||
- firewall
|
||||
|
||||
- name: Enable the firewall init.d script
|
||||
service:
|
||||
name: firewall
|
||||
enabled: yes
|
||||
when: firewall_run is not defined and firewall_enabled
|
||||
tags:
|
||||
- configs
|
||||
- firewall
|
||||
|
||||
- name: Ensure the rules directories exist
|
||||
file:
|
||||
path: "/etc/firewall/{{ item }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0700
|
||||
with_items:
|
||||
- rules-v4.d
|
||||
- rules-v6.d
|
||||
when: firewall_run is not defined
|
||||
tags:
|
||||
- configs
|
||||
- firewall
|
||||
|
||||
- name: Install the firewall configs
|
||||
template: dest=/etc/firewall/{{ item }} src={{ item }}.j2 mode=0600
|
||||
with_items:
|
||||
- rules-v4.d/10_conntrack.sh
|
||||
- rules-v4.d/15_local.sh
|
||||
- rules-v4.d/17_monitoring.sh
|
||||
- rules-v4.d/18_internal.sh
|
||||
- rules-v4.d/20_whitelist.sh
|
||||
- rules-v4.d/22_ssh.sh
|
||||
- rules-v4.d/24_influxdb.sh
|
||||
- rules-v4.d/33_mariadb.sh
|
||||
- rules-v4.d/85_whitelist.sh
|
||||
- rules-v4.d/90_allow_outbound.sh
|
||||
- rules-v4.d/90_drop_all.sh
|
||||
- rules-v4.d/95_fail2ban.sh
|
||||
|
||||
- rules-v6.d/10_conntrack.sh
|
||||
- rules-v6.d/15_local.sh
|
||||
- rules-v6.d/18_internal.sh
|
||||
- rules-v6.d/20_whitelist.sh
|
||||
- rules-v4.d/24_influxdb.sh
|
||||
- rules-v4.d/33_mariadb.sh
|
||||
- rules-v4.d/85_whitelist.sh
|
||||
- rules-v6.d/90_allow_outbound.sh
|
||||
- rules-v6.d/90_drop_all.sh
|
||||
when: firewall_run is not defined and firewall_enabled and firewall_standard_rules
|
||||
notify: Restart firewall
|
||||
tags:
|
||||
- configs
|
||||
- firewall
|
||||
|
||||
- name: Install the extra firewall configs
|
||||
template: dest=/etc/firewall/{{ item }} src={{ item }}.j2 mode=0600
|
||||
with_items:
|
||||
- rules-v4.d/50_custom.sh
|
||||
- rules-v6.d/50_custom.sh
|
||||
when: firewall_run is not defined and firewall_enabled and (firewall_custom_ipv4_rules or firewall_custom_ipv6_rules)
|
||||
notify: Restart firewall
|
||||
tags:
|
||||
- configs
|
||||
- firewall
|
||||
|
||||
- name: Install the firewall outbound ACLs
|
||||
template: dest=/etc/firewall/outbound_whitelist.acl src=etc_firewall_outbound_whitelist.acl.j2 mode=0600
|
||||
when: firewall_run is not defined and firewall_enabled and firewall_output_whitelist_domains
|
||||
notify: Restart firewall
|
||||
tags:
|
||||
- configs
|
||||
- firewall
|
||||
- whitelists
|
||||
|
||||
- name: Remove obsolete configs
|
||||
file: dest=/etc/firewall/{{ item }} state=absent
|
||||
with_items:
|
||||
- rules-v4.d/19_monitoring.sh
|
||||
when: firewall_run is not defined and firewall_enabled
|
||||
notify: Restart firewall
|
||||
tags:
|
||||
- configs
|
||||
- firewall
|
||||
|
||||
- name: Install the firewall outbound update script
|
||||
template: dest=/usr/sbin/update-firewall-outbound src=usr_sbin_update-firewall-outbound.j2 mode=0700
|
||||
when: firewall_run is not defined and firewall_enabled and firewall_output_whitelist_domains
|
||||
notify: Restart firewall
|
||||
tags:
|
||||
- firewall
|
||||
- scripts
|
||||
- whitelists
|
||||
|
||||
- set_fact:
|
||||
firewall_run: true
|
||||
when: firewall_run is not defined
|
||||
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% for name in firewall_output_whitelist_domains %}
|
||||
{{ name }}
|
||||
{% endfor %}
|
||||
133
roles/firewall/templates/etc_init.d_firewall.j2
Normal file
133
roles/firewall/templates/etc_init.d_firewall.j2
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/bin/sh
|
||||
|
||||
# {{ ansible_managed }}
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: firewall
|
||||
# Required-Start: $network
|
||||
# Required-Stop: $network
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Set up iptables rules
|
||||
# Description: Loads current iptables rules from/to /etc/firewall
|
||||
### END INIT INFO
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
PATH="/sbin:$PATH"
|
||||
|
||||
rc=0
|
||||
|
||||
flush_ipv4()
|
||||
{
|
||||
for chain in INPUT FORWARD OUTPUT; do
|
||||
iptables -P $chain ACCEPT
|
||||
done
|
||||
for table in $(iptables-save | awk '/^\*/ { print substr($1,2) }'); do
|
||||
iptables -t $table -F
|
||||
iptables -t $table -X
|
||||
iptables -t $table -Z
|
||||
done
|
||||
}
|
||||
|
||||
flush_ipv6()
|
||||
{
|
||||
for chain in INPUT FORWARD OUTPUT; do
|
||||
ip6tables -P $chain ACCEPT
|
||||
done
|
||||
for table in $(ip6tables-save | awk '/^\*/ { print substr($1,2) }'); do
|
||||
ip6tables -t $table -F
|
||||
ip6tables -t $table -X
|
||||
ip6tables -t $table -Z
|
||||
done
|
||||
}
|
||||
|
||||
load_rules()
|
||||
{
|
||||
log_action_begin_msg "Loading iptables rules"
|
||||
|
||||
# load IPv4 rules
|
||||
if [ ! -d /etc/firewall/rules-v4.d ]; then
|
||||
log_action_cont_msg " skipping IPv4 (no rules to load)"
|
||||
else
|
||||
log_action_cont_msg " IPv4"
|
||||
|
||||
flush_ipv4
|
||||
for frag in /etc/firewall/rules-v4.d/*.sh; do
|
||||
if [ -r "$frag" ]; then
|
||||
. "$frag"
|
||||
if [ $? -ne 0 ]; then
|
||||
rc=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# load IPv6 rules
|
||||
if [ ! -d /etc/firewall/rules-v6.d ]; then
|
||||
log_action_cont_msg " skipping IPv6 (no rules to load)"
|
||||
else
|
||||
log_action_cont_msg " IPv6"
|
||||
|
||||
flush_ipv6
|
||||
for frag in /etc/firewall/rules-v6.d/*.sh; do
|
||||
if [ -r "$frag" ]; then
|
||||
. "$frag"
|
||||
if [ $? -ne 0 ]; then
|
||||
rc=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
log_action_end_msg $rc
|
||||
}
|
||||
|
||||
flush_rules()
|
||||
{
|
||||
log_action_begin_msg "Flushing rules"
|
||||
|
||||
if [ ! -f /proc/net/ip_tables_names ]; then
|
||||
log_action_cont_msg " skipping IPv4"
|
||||
else
|
||||
log_action_cont_msg " IPv4"
|
||||
flush_ipv4
|
||||
fi
|
||||
|
||||
if [ ! -f /proc/net/ip6_tables_names ]; then
|
||||
log_action_cont_msg " skipping IPv6"
|
||||
else
|
||||
log_action_cont_msg " IPv6"
|
||||
flush_ipv6
|
||||
fi
|
||||
|
||||
log_action_end_msg 0
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start|restart|reload|force-reload)
|
||||
load_rules
|
||||
;;
|
||||
stop)
|
||||
echo "Automatic flushing disabled, use \"flush\" instead of \"stop\""
|
||||
;;
|
||||
flush)
|
||||
flush_rules
|
||||
;;
|
||||
debug)
|
||||
iptables() { echo "iptables $@"; }
|
||||
ip6tables() { echo "ip6tables $@"; }
|
||||
ipset() { echo "ipset $@"; }
|
||||
log_action_begin_msg() { :; }
|
||||
log_action_cont_msg() { :; }
|
||||
log_action_end_msg() { :; }
|
||||
|
||||
load_rules
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|restart|reload|force-reload|save|flush}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit $rc
|
||||
5
roles/firewall/templates/rules-v4.d/10_conntrack.sh.j2
Normal file
5
roles/firewall/templates/rules-v4.d/10_conntrack.sh.j2
Normal file
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Allow established connections
|
||||
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
5
roles/firewall/templates/rules-v4.d/15_local.sh.j2
Normal file
5
roles/firewall/templates/rules-v4.d/15_local.sh.j2
Normal file
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Allow all traffic from localhost
|
||||
iptables -A INPUT -i lo -j ACCEPT
|
||||
iptables -A OUTPUT -o lo -j ACCEPT
|
||||
7
roles/firewall/templates/rules-v4.d/17_monitoring.sh.j2
Normal file
7
roles/firewall/templates/rules-v4.d/17_monitoring.sh.j2
Normal file
@@ -0,0 +1,7 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
iptables -N monitoring-in
|
||||
|
||||
{% for srcip in firewall_monitoring_ips|default([]) %}
|
||||
iptables -A INPUT -s {{ srcip }} -j monitoring-in
|
||||
{% endfor %}
|
||||
24
roles/firewall/templates/rules-v4.d/18_internal.sh.j2
Normal file
24
roles/firewall/templates/rules-v4.d/18_internal.sh.j2
Normal file
@@ -0,0 +1,24 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if datacenter_global_networks is defined %}
|
||||
iptables -N internal-in
|
||||
{% if firewall_allow_internal_dns %}
|
||||
iptables -A internal-in -p tcp --dport 53 -m comment --comment "common-dns" -j ACCEPT
|
||||
iptables -A internal-in -p udp --dport 53 -m comment --comment "common-dns" -j ACCEPT
|
||||
{% endif %}
|
||||
|
||||
{% for srcip in datacenter_global_networks + datacenter_public_networks %}
|
||||
iptables -A INPUT -s {{ srcip }} -j internal-in
|
||||
{% endfor %}
|
||||
|
||||
iptables -N internal-out
|
||||
iptables -A internal-out -p tcp -m multiport --dports 53,80,443,2181,3306:3310,8086,10231 -m comment --comment "common-services" -j ACCEPT
|
||||
iptables -A internal-out -p udp --dport 53 -m comment --comment "common-dns" -j ACCEPT
|
||||
iptables -A internal-out -p tcp --dport 10514 -m owner --uid-owner 0 -m comment --comment "syslog" -j ACCEPT
|
||||
iptables -A internal-out -p icmp -j ACCEPT
|
||||
|
||||
{% for dstip in datacenter_global_networks + datacenter_public_networks %}
|
||||
iptables -A OUTPUT -d {{ dstip }} -j internal-out
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
8
roles/firewall/templates/rules-v4.d/20_whitelist.sh.j2
Normal file
8
roles/firewall/templates/rules-v4.d/20_whitelist.sh.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if firewall_whitelist_ip %}
|
||||
# Whitelist IPs
|
||||
{% for ip in firewall_whitelist_ip %}
|
||||
iptables -A INPUT -s {{ ip }} -m comment --comment "whitelist" -j ACCEPT
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
8
roles/firewall/templates/rules-v4.d/22_ssh.sh.j2
Normal file
8
roles/firewall/templates/rules-v4.d/22_ssh.sh.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Allow SSH only from IPs:
|
||||
iptables -N ssh-in
|
||||
{% for ip in firewall_ssh_acl|default([]) + firewall_ssh_acl_extra|default([]) %}
|
||||
iptables -A ssh-in -s {{ ip }} -j ACCEPT
|
||||
{% endfor %}
|
||||
iptables -A INPUT -p tcp --dport 22 -m comment --comment "ssh" -j ssh-in
|
||||
8
roles/firewall/templates/rules-v4.d/24_influxdb.sh.j2
Normal file
8
roles/firewall/templates/rules-v4.d/24_influxdb.sh.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Allow InfluxDB Replication only from IPs:
|
||||
iptables -N influx-in
|
||||
{% for ip in firewall_influx_acl|default([]) + firewall_influx_acl_extra|default([]) %}
|
||||
iptables -A influx-in -s {{ ip }} -j ACCEPT
|
||||
{% endfor %}
|
||||
iptables -A INPUT -p tcp --dport 8086 -m comment --comment "influx" -j influx-in
|
||||
8
roles/firewall/templates/rules-v4.d/33_mariadb.sh.j2
Normal file
8
roles/firewall/templates/rules-v4.d/33_mariadb.sh.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Allow MariaDB Replication only from IPs:
|
||||
iptables -N mariadb-in
|
||||
{% for ip in firewall_mariadb_acl|default([]) + firewall_mariadb_acl_extra|default([]) %}
|
||||
iptables -A mariadb-in -s {{ ip }} -j ACCEPT
|
||||
{% endfor %}
|
||||
iptables -A INPUT -p tcp --dport 3306 -m comment --comment "mariadb" -j mariadb-in
|
||||
3
roles/firewall/templates/rules-v4.d/50_custom.sh.j2
Normal file
3
roles/firewall/templates/rules-v4.d/50_custom.sh.j2
Normal file
@@ -0,0 +1,3 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{{ firewall_custom_ipv4_rules }}
|
||||
15
roles/firewall/templates/rules-v4.d/85_whitelist.sh.j2
Normal file
15
roles/firewall/templates/rules-v4.d/85_whitelist.sh.j2
Normal file
@@ -0,0 +1,15 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if firewall_late_whitelist_ip %}
|
||||
# Whitelist IPs
|
||||
{% for ip in firewall_late_whitelist_ip %}
|
||||
iptables -A INPUT -s {{ ip }} -m comment --comment "whitelist" -j ACCEPT
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if firewall_whitelist_office_ip and firewall_whitelist_office_ports %}
|
||||
# Offices TODO remove
|
||||
{% for ip in firewall_whitelist_office_ip %}
|
||||
iptables -A INPUT -s {{ ip }} -p tcp -m multiport --dports "{{ firewall_whitelist_office_ports | join(',') }}" -m comment --comment "office-whitelist" -j ACCEPT
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
69
roles/firewall/templates/rules-v4.d/90_allow_outbound.sh.j2
Normal file
69
roles/firewall/templates/rules-v4.d/90_allow_outbound.sh.j2
Normal file
@@ -0,0 +1,69 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if firewall_output_default_drop or firewall_output_whitelist_ipv4 %}
|
||||
{% for ip in network_nameservers + ['8.8.8.8'] if ip|ipv4 %}
|
||||
{% if loop.first %}
|
||||
# Allow DNS
|
||||
{% endif %}
|
||||
iptables -A OUTPUT -d {{ ip }} -p tcp --dport 53 -m comment --comment "dns" -j ACCEPT
|
||||
iptables -A OUTPUT -d {{ ip }} -p udp --dport 53 -m comment --comment "dns" -j ACCEPT
|
||||
{% endfor %}
|
||||
|
||||
if getent group postfix >/dev/null 2>&1; then
|
||||
# Permit outbound SMTP for Postfix only (TODO: move to postfix role)
|
||||
iptables -A OUTPUT -p tcp --dport 25 -m owner --gid-owner postfix -m comment --comment "smtp" -j ACCEPT
|
||||
fi
|
||||
|
||||
{% if not (firewall_output_learning or firewall_output_whitelist_ipv4) %}
|
||||
# Permit outbound HTTP for user _apt
|
||||
iptables -A OUTPUT -p tcp -m multiport --dports 80,443 -m owner --uid-owner _apt -m comment --comment "apt" -j ACCEPT
|
||||
|
||||
# Permit outbound SSH for normal users
|
||||
iptables -A OUTPUT -p tcp --dport 22 -m owner --uid-owner 1000-65500 -m comment --comment "ssh" -j ACCEPT
|
||||
|
||||
# Allow all outbound traffic for the root user
|
||||
iptables -A OUTPUT -m owner --uid-owner 0 -j ACCEPT
|
||||
{% endif %}
|
||||
|
||||
{% for ip in datacenter_global_networks|default([]) + datacenter_all_networks|default([]) %}
|
||||
iptables -A OUTPUT -d {{ ip }} -m comment --comment "keepcalling" -j ACCEPT
|
||||
{% endfor %}
|
||||
|
||||
{% if firewall_output_whitelist_domains %}
|
||||
# Outbound ACL for whitelist
|
||||
if [ -r /etc/firewall/outbound_whitelist_ipv4.acl ]; then
|
||||
|
||||
ipset -exist create outbound-whitelist hash:net counters comment
|
||||
ipset flush outbound-whitelist
|
||||
grep -v '^#' /etc/firewall/outbound_whitelist_ipv4.acl | while read ip name; do
|
||||
ipset -exist add outbound-whitelist "$ip" comment "$name"
|
||||
done < /etc/firewall/outbound_whitelist_ipv4.acl
|
||||
|
||||
# iptables -A OUTPUT -m set --match-set outbound-whitelist,dst -j ACCEPT
|
||||
fi
|
||||
{% endif %}
|
||||
|
||||
{% if firewall_output_whitelist_ipv4 %}
|
||||
# Outbound ACL for whitelist
|
||||
iptables -N outbound-whitelist
|
||||
{% for item in firewall_output_whitelist_ipv4 %}
|
||||
iptables -A outbound-whitelist -d {{ item.ip }} -m comment --comment "{{ item.name }}" -j ACCEPT
|
||||
{% endfor %}
|
||||
iptables -A OUTPUT -j outbound-whitelist
|
||||
{% endif %}
|
||||
|
||||
{% if firewall_output_learning %}
|
||||
|
||||
ipset -exist create outbound hash:ip counters
|
||||
|
||||
iptables -A OUTPUT -p tcp --syn -m set --match-set outbound dst -j ACCEPT
|
||||
iptables -A OUTPUT -p udp -m set --match-set outbound dst -j ACCEPT
|
||||
|
||||
iptables -A OUTPUT -p tcp --syn -j SET --add-set outbound dst
|
||||
iptables -A OUTPUT -p udp -j SET --add-set outbound dst
|
||||
|
||||
iptables -A internal-out -m limit --limit 10/min --limit-burst 2 -j LOG --log-prefix "{{ firewall_log_prefix }} internal-out DROP: " --log-level 5 --log-uid
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
28
roles/firewall/templates/rules-v4.d/90_drop_all.sh.j2
Normal file
28
roles/firewall/templates/rules-v4.d/90_drop_all.sh.j2
Normal file
@@ -0,0 +1,28 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if firewall_input_default_drop %}
|
||||
# Allow Safe ICMP
|
||||
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
|
||||
iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
|
||||
iptables -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
|
||||
#iptables -A INPUT -p icmp --icmp-type redirect -j ACCEPT
|
||||
iptables -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
|
||||
|
||||
# Drop everything else
|
||||
iptables -A INPUT -m pkttype --pkt-type broadcast -j DROP
|
||||
iptables -A INPUT -m limit --limit 10/min --limit-burst 2 -j LOG --log-prefix "{{ firewall_log_prefix }} INPUT DROP: " --log-level 5
|
||||
iptables -A INPUT -j DROP
|
||||
{% endif %}
|
||||
|
||||
{% if firewall_output_default_drop %}
|
||||
# Allow Safe ICMP
|
||||
iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
|
||||
iptables -A OUTPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
|
||||
#iptables -A OUTPUT -p icmp --icmp-type redirect -j ACCEPT
|
||||
iptables -A OUTPUT -p icmp --icmp-type time-exceeded -j ACCEPT
|
||||
|
||||
# Drop everything else
|
||||
iptables -A OUTPUT -p tcp --syn -m limit --limit 10/min --limit-burst 2 -j LOG --log-prefix "{{ firewall_log_prefix }} OUTPUT DROP: " --log-level 5 --log-uid
|
||||
iptables -A OUTPUT ! -p tcp -m limit --limit 10/min --limit-burst 2 -j LOG --log-prefix "{{ firewall_log_prefix }} OUTPUT DROP: " --log-level 5 --log-uid
|
||||
iptables -A OUTPUT -j REJECT
|
||||
{% endif %}
|
||||
6
roles/firewall/templates/rules-v4.d/95_fail2ban.sh.j2
Normal file
6
roles/firewall/templates/rules-v4.d/95_fail2ban.sh.j2
Normal file
@@ -0,0 +1,6 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Restart fail2ban
|
||||
if systemctl -q is-active fail2ban.service; then
|
||||
systemctl try-restart fail2ban.service
|
||||
fi
|
||||
5
roles/firewall/templates/rules-v6.d/10_conntrack.sh.j2
Normal file
5
roles/firewall/templates/rules-v6.d/10_conntrack.sh.j2
Normal file
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Allow established connections
|
||||
ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
ip6tables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
5
roles/firewall/templates/rules-v6.d/15_local.sh.j2
Normal file
5
roles/firewall/templates/rules-v6.d/15_local.sh.j2
Normal file
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# Allow all traffic from localhost
|
||||
ip6tables -A INPUT -i lo -j ACCEPT
|
||||
ip6tables -A OUTPUT -o lo -j ACCEPT
|
||||
21
roles/firewall/templates/rules-v6.d/18_internal.sh.j2
Normal file
21
roles/firewall/templates/rules-v6.d/18_internal.sh.j2
Normal file
@@ -0,0 +1,21 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if datacenter_global_networks is defined %}
|
||||
ip6tables -N internal-in
|
||||
ip6tables -A INPUT -s fe80::/10 -j internal-in
|
||||
ip6tables -A INPUT -s fc00::/7 -j internal-in
|
||||
{% for net in datacenter_public_ipv6_networks|default([]) %}
|
||||
ip6tables -A INPUT -s {{ net }} -j internal-in
|
||||
{% endfor %}
|
||||
|
||||
ip6tables -N internal-out
|
||||
ip6tables -A internal-out -p tcp -m multiport --dports 53,80,443,3306:3310 -m comment --comment "common-services" -j ACCEPT
|
||||
ip6tables -A internal-out -p udp -m multiport --dports 53,123 -m comment --comment "common-services" -j ACCEPT
|
||||
ip6tables -A internal-out -p icmpv6 -j ACCEPT
|
||||
|
||||
ip6tables -A OUTPUT -d fe80::/10 -j internal-out
|
||||
ip6tables -A OUTPUT -d fc00::/7 -j internal-out
|
||||
{% for net in datacenter_public_ipv6_networks|default([]) %}
|
||||
ip6tables -A OUTPUT -d {{ net }} -j internal-out
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
8
roles/firewall/templates/rules-v6.d/20_whitelist.sh.j2
Normal file
8
roles/firewall/templates/rules-v6.d/20_whitelist.sh.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if firewall_whitelist_ipv6 %}
|
||||
# Whitelist IPs
|
||||
{% for ip in firewall_whitelist_ipv6 %}
|
||||
ip6tables -A INPUT -s {{ ip }} -m comment --comment "whitelist" -j ACCEPT
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
3
roles/firewall/templates/rules-v6.d/50_custom.sh.j2
Normal file
3
roles/firewall/templates/rules-v6.d/50_custom.sh.j2
Normal file
@@ -0,0 +1,3 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{{ firewall_custom_ipv6_rules }}
|
||||
8
roles/firewall/templates/rules-v6.d/85_whitelist.sh.j2
Normal file
8
roles/firewall/templates/rules-v6.d/85_whitelist.sh.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if firewall_late_whitelist_ipv6 %}
|
||||
# Whitelist IPs
|
||||
{% for ip in firewall_late_whitelist_ipv6 %}
|
||||
ip6tables -A INPUT -s {{ ip }} -m comment --comment "whitelist" -j ACCEPT
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
69
roles/firewall/templates/rules-v6.d/90_allow_outbound.sh.j2
Normal file
69
roles/firewall/templates/rules-v6.d/90_allow_outbound.sh.j2
Normal file
@@ -0,0 +1,69 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if firewall_output_default_drop or firewall_output_whitelist_ipv6 %}
|
||||
{% for ip in network_nameservers if ip|ipv6 %}
|
||||
{% if loop.first %}
|
||||
# Allow DNS
|
||||
{% endif %}
|
||||
ip6tables -A OUTPUT -d {{ ip }} -p tcp --dport 53 -m comment --comment "dns" -j ACCEPT
|
||||
ip6tables -A OUTPUT -d {{ ip }} -p udp --dport 53 -m comment --comment "dns" -j ACCEPT
|
||||
{% endfor %}
|
||||
|
||||
if getent group postfix >/dev/null 2>&1; then
|
||||
# Permit outbound SMTP for Postfix only (TODO: move to postfix role)
|
||||
ip6tables -A OUTPUT -p tcp --dport 25 -m owner --gid-owner postfix -m comment --comment "smtp" -j ACCEPT
|
||||
fi
|
||||
|
||||
{% if not firewall_output_learning %}
|
||||
# Permit outbound HTTP for user _apt
|
||||
ip6tables -A OUTPUT -p tcp -m multiport --dports 80,443 -m owner --uid-owner _apt -m comment --comment "apt" -j ACCEPT
|
||||
|
||||
# Permit outbound SSH for normal users
|
||||
ip6tables -A OUTPUT -p tcp --dport 22 -m owner --uid-owner 1000-65500 -m comment --comment "ssh" -j ACCEPT
|
||||
|
||||
# Allow all outbound traffic for the root user
|
||||
ip6tables -A OUTPUT -m owner --uid-owner 0 -j ACCEPT
|
||||
{% endif %}
|
||||
|
||||
{% for ip in datacenter_all_ipv6_networks|default([]) %}
|
||||
ip6tables -A OUTPUT -d {{ ip }} -m comment --comment "keepcalling" -j ACCEPT
|
||||
{% endfor %}
|
||||
|
||||
{% if firewall_output_whitelist_domains %}
|
||||
# Outbound ACL for whitelist
|
||||
if [ -r /etc/firewall/outbound_whitelist_ipv6.acl ]; then
|
||||
|
||||
ipset -exist create outbound-whitelist hash:net family inet6 counters comment
|
||||
ipset flush outbound-whitelist
|
||||
grep -v '^#' /etc/firewall/outbound_whitelist_ipv6.acl | while read ip name; do
|
||||
ipset -exist add outbound-whitelist "$ip" comment "$name"
|
||||
done < /etc/firewall/outbound_whitelist_ipv6.acl
|
||||
|
||||
# ip6tables -A OUTPUT -m set --match-set outbound-whitelist,dst -j ACCEPT
|
||||
fi
|
||||
{% endif %}
|
||||
|
||||
{% if firewall_output_whitelist_ipv6 %}
|
||||
# Outbound ACL for whitelist
|
||||
ip6tables -N outbound-whitelist
|
||||
{% for item in firewall_output_whitelist_ipv6 %}
|
||||
ip6tables -A OUTPUT -d {{ item.ip }} -m comment --comment "{{ item.name }}" -j ACCEPT
|
||||
{% endfor %}
|
||||
ip6tables -A OUTPUT -j outbound-whitelist
|
||||
{% endif %}
|
||||
|
||||
{% if firewall_output_learning %}
|
||||
|
||||
ipset -exist create outbound-ipv6 hash:ip family inet6 netmask 64 counters
|
||||
|
||||
ip6tables -A OUTPUT -p tcp --syn -m set --match-set outbound-ipv6 dst -j ACCEPT
|
||||
ip6tables -A OUTPUT -p udp -m set --match-set outbound dst -j ACCEPT
|
||||
|
||||
ip6tables -A OUTPUT -p tcp --syn -j SET --add-set outbound-ipv6 dst
|
||||
ip6tables -A OUTPUT -p udp -j SET --add-set outbound-ipv6 dst
|
||||
|
||||
ip6tables -A internal-out -m limit --limit 10/min --limit-burst 2 -j LOG --log-prefix "{{ firewall_log_prefix }} internal-out DROP: " --log-level 5 --log-uid
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
21
roles/firewall/templates/rules-v6.d/90_drop_all.sh.j2
Normal file
21
roles/firewall/templates/rules-v6.d/90_drop_all.sh.j2
Normal file
@@ -0,0 +1,21 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if firewall_input_default_drop %}
|
||||
# Allow ICMP
|
||||
ip6tables -A INPUT -p icmpv6 -j ACCEPT
|
||||
|
||||
# Drop everything else
|
||||
ip6tables -A INPUT -m pkttype --pkt-type broadcast -j DROP
|
||||
ip6tables -A INPUT -m limit --limit 10/min --limit-burst 2 -j LOG --log-prefix "{{ firewall_log_prefix }} INPUT DROP: " --log-level 5
|
||||
ip6tables -A INPUT -j DROP
|
||||
{% endif %}
|
||||
|
||||
{% if firewall_output_default_drop %}
|
||||
# Allow ICMP
|
||||
ip6tables -A OUTPUT -p icmpv6 ! --icmpv6-type echo-request -j ACCEPT
|
||||
|
||||
# Drop everything else
|
||||
ip6tables -A OUTPUT -p tcp --syn -m limit --limit 10/min --limit-burst 2 -j LOG --log-prefix "{{ firewall_log_prefix }} OUTPUT DROP: " --log-level 5 --log-uid
|
||||
ip6tables -A OUTPUT ! -p tcp -m limit --limit 10/min --limit-burst 2 -j LOG --log-prefix "{{ firewall_log_prefix }} OUTPUT DROP: " --log-level 5 --log-uid
|
||||
ip6tables -A OUTPUT -j REJECT
|
||||
{% endif %}
|
||||
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Update /etc/firewall/outbound_whitelist_ipv*.acl from /etc/firewall/outbound_whitelist.acl
|
||||
|
||||
resolve_hosts() {
|
||||
local type="$1" out="$2"
|
||||
local tmp=$(mktemp "$out.XXXXXX")
|
||||
|
||||
(
|
||||
echo "# AUTO-GENERATED FROM outbound_whitelist.acl"
|
||||
while read domain; do
|
||||
case $domain in
|
||||
"#"* | "") ;;
|
||||
*)
|
||||
(host -t "$type" "$domain" 2>&1 || true) | sort -n | while read line; do
|
||||
case $line in
|
||||
*"not found"*)
|
||||
echo "$line" >&2
|
||||
;;
|
||||
*"has address"*)
|
||||
ip="${line##* }"
|
||||
case $ip in
|
||||
13.108.*) ip="13.108.0.0/14" ;;
|
||||
*) ip="${ip%.*}.0/24" ;;
|
||||
esac
|
||||
echo "$ip $domain"
|
||||
;;
|
||||
*"has IPv6 address"*)
|
||||
ip="${line##* }"
|
||||
case $ip in
|
||||
2607:f8b0:*) ip="2607:f8b0::/32" ;;
|
||||
*) ip=$(ipv6calc --addr_to_uncompressed "$ip" | cut -d: -f1-4)::/64 ;;
|
||||
esac
|
||||
echo "$ip $domain"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
;;
|
||||
esac
|
||||
done < /etc/firewall/outbound_whitelist.acl | sort -n -u
|
||||
) > "$tmp"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error writing to $out" >&2
|
||||
rm -f "$tmp"
|
||||
elif cmp -s "$tmp" "$out"; then
|
||||
rm -f "$tmp"
|
||||
else
|
||||
echo "--- Differences in $(basename $out): ---"
|
||||
echo
|
||||
diff -u "$out" "$tmp" | grep -v '^\(+++\|---\)' | grep '^[+-]'
|
||||
echo
|
||||
mv -f "$tmp" "$out"
|
||||
fi
|
||||
}
|
||||
|
||||
load_ipset() {
|
||||
local name="$1" family="$2" file="$3"
|
||||
local tmp="$name-$$"
|
||||
|
||||
ipset -exist create "$name" hash:net family "$family" counters comment
|
||||
|
||||
ipset create "$tmp" hash:net family "$family" counters comment
|
||||
grep -v '^#' "$file" | while read ip name; do
|
||||
ipset -exist add "$tmp" "$ip" comment "$name"
|
||||
done
|
||||
ipset swap "$name" "$tmp"
|
||||
ipset destroy "$tmp"
|
||||
}
|
||||
|
||||
resolve_hosts A /etc/firewall/outbound_whitelist_ipv4.acl
|
||||
resolve_hosts AAAA /etc/firewall/outbound_whitelist_ipv6.acl
|
||||
|
||||
load_ipset outbound-whitelist inet /etc/firewall/outbound_whitelist_ipv4.acl
|
||||
load_ipset outbound-whitelist-ipv6 inet6 /etc/firewall/outbound_whitelist_ipv6.acl
|
||||
8
roles/network/templates/etc_resolv.conf.j2
Normal file
8
roles/network/templates/etc_resolv.conf.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
# {{ ansible_managed }}
|
||||
{# use the local bind #}
|
||||
nameserver 127.0.0.1
|
||||
{% if network_fallback_resolvers|d('') %}
|
||||
{% for ip in network_fallback_resolvers if ip != network_private_ip %}
|
||||
nameserver {{ ip }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
9
roles/ntp/defaults/main.yml
Normal file
9
roles/ntp/defaults/main.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
|
||||
ntp_servers:
|
||||
- time1.google.com
|
||||
- time2.google.com
|
||||
- time3.google.com
|
||||
- time4.google.com
|
||||
|
||||
ntp_firewall: no
|
||||
3
roles/ntp/handlers/main.yml
Normal file
3
roles/ntp/handlers/main.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
- name: Restart NTP
|
||||
service: name=ntp state=restarted
|
||||
5
roles/ntp/meta/main.yml
Normal file
5
roles/ntp/meta/main.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
|
||||
dependencies:
|
||||
- role: firewall
|
||||
when: ntp_firewall
|
||||
24
roles/ntp/tasks/main.yml
Normal file
24
roles/ntp/tasks/main.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
- name: Install NTP
|
||||
apt: pkg=ntp state=present
|
||||
|
||||
- name: Configure NTP
|
||||
template: src=ntp.conf.j2 dest=/etc/ntp.conf
|
||||
notify: Restart NTP
|
||||
|
||||
- name: Configure NTP keys
|
||||
template: src=ntp.keys.j2 dest=/etc/ntp.keys owner=ntp group=ntp mode=0400
|
||||
notify: Restart NTP
|
||||
|
||||
- name: Ensure NTP is running
|
||||
service: name=ntp state=started enabled=yes
|
||||
|
||||
- name: Configure firewall rules for NTP
|
||||
template:
|
||||
dest: /etc/firewall/rules-v4.d/21_ntp.sh
|
||||
src: etc_firewall_rules-v4.d_21_ntp.sh.j2
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0600
|
||||
when: ntp_firewall
|
||||
notify: Restart firewall
|
||||
6
roles/ntp/templates/etc_firewall_rules-v4.d_21_ntp.sh.j2
Normal file
6
roles/ntp/templates/etc_firewall_rules-v4.d_21_ntp.sh.j2
Normal file
@@ -0,0 +1,6 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% for ip in ntp_servers | default([]) %}
|
||||
iptables -A INPUT -s {{ ip }} -p udp --dport 123 -m comment --comment "ntp" -j ACCEPT
|
||||
iptables -A OUTPUT -d {{ ip }} -p udp --dport 123 -m comment --comment "ntp" -j ACCEPT
|
||||
{% endfor %}
|
||||
34
roles/ntp/templates/ntp.conf.j2
Normal file
34
roles/ntp/templates/ntp.conf.j2
Normal file
@@ -0,0 +1,34 @@
|
||||
# {{ ansible_managed }}
|
||||
# /etc/ntp.conf, configuration for ntpd; see ntp.conf(5) for help
|
||||
|
||||
driftfile /var/lib/ntp/ntp.drift
|
||||
keys /etc/ntp.keys
|
||||
|
||||
# Enable this if you want statistics to be logged.
|
||||
#statsdir /var/log/ntpstats/
|
||||
|
||||
statistics loopstats peerstats clockstats
|
||||
filegen loopstats file loopstats type day enable
|
||||
filegen peerstats file peerstats type day enable
|
||||
filegen clockstats file clockstats type day enable
|
||||
|
||||
{% if ntp_broadcast_key is defined %}
|
||||
broadcastclient
|
||||
trustedkey 22
|
||||
{% else %}
|
||||
# You do need to talk to an NTP server or two (or three).
|
||||
{% for server in ntp_servers %}
|
||||
server {{ server }} iburst
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
# By default, exchange time with everybody, but don't allow configuration.
|
||||
restrict -4 default kod notrap nomodify nopeer noquery limited
|
||||
restrict -6 default kod notrap nomodify nopeer noquery limited
|
||||
|
||||
# Local users may interrogate the ntp server more closely.
|
||||
restrict 127.0.0.1
|
||||
restrict ::1
|
||||
|
||||
# Needed for adding pool entries
|
||||
restrict source notrap nomodify noquery
|
||||
5
roles/ntp/templates/ntp.keys.j2
Normal file
5
roles/ntp/templates/ntp.keys.j2
Normal file
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if ntp_broadcast_key is defined %}
|
||||
22 M {{ ntp_broadcast_key }}
|
||||
{% endif %}
|
||||
165
roles/postfix/defaults/main.yml
Normal file
165
roles/postfix/defaults/main.yml
Normal file
@@ -0,0 +1,165 @@
|
||||
postfix_mynetworks: []
|
||||
|
||||
postfix_mydestination_local:
|
||||
- "{{ ansible_hostname }}.maruntiel.net"
|
||||
- "localhost"
|
||||
- "localhost.{{ ansible_domain }}"
|
||||
|
||||
postfix_mydestination_extra: []
|
||||
|
||||
# main.cf settings
|
||||
postfix_settings:
|
||||
|
||||
compatibility_level: 2
|
||||
|
||||
myhostname: "{{ ansible_hostname }}.maruntiel.net"
|
||||
myorigin: /etc/mailname
|
||||
|
||||
mydestination: "{{ postfix_mydestination_local + postfix_mydestination_extra }}"
|
||||
mynetworks: "10.11.0.0/16 62.171.160.169/32 207.244.234.58/32 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 {{ postfix_mynetworks | join(' ') }}"
|
||||
|
||||
relayhost: ""
|
||||
|
||||
alias_maps: hash:/etc/aliases
|
||||
alias_database: hash:/etc/aliases
|
||||
biff: no
|
||||
mailbox_command:
|
||||
home_mailbox: Maildir/
|
||||
mailbox_size_limit: 0
|
||||
recipient_delimiter: +
|
||||
append_dot_mydomain: no
|
||||
readme_directory: no
|
||||
dovecot_destination_recipient_limit: 1
|
||||
|
||||
tls_random_source: dev:/dev/urandom
|
||||
|
||||
default_transport: smtp
|
||||
relay_transport: smtp
|
||||
relay_domains: ""
|
||||
|
||||
inet_protocols: ipv4
|
||||
inet_interfaces: all
|
||||
|
||||
virtual_mailbox_domains:
|
||||
- /etc/postfix/virtual_domains
|
||||
virtual_mailbox_base:
|
||||
- /var/mail/vhosts
|
||||
virtual_mailbox_maps:
|
||||
- hash:/etc/postfix/vmailbox
|
||||
virtual_alias_maps:
|
||||
- hash:/etc/postfix/virtual_alias
|
||||
virtual_minimum_uid:
|
||||
- 100
|
||||
virtual_uid_maps:
|
||||
- static:5000
|
||||
virtual_gid_maps:
|
||||
- static:5000
|
||||
virtual_transport:
|
||||
- virtual
|
||||
virtual_alias_domains:
|
||||
- maruntiel.net
|
||||
- maruntiel.com
|
||||
- stillmob.ro
|
||||
- pedimedic.ro
|
||||
|
||||
|
||||
# SMTP SETTINGS
|
||||
smtp_use_tls: yes
|
||||
smtp_tls_security_level: may
|
||||
smtp_tls_note_starttls_offer: yes
|
||||
smtp_tls_session_cache_database: "btree:${data_directory}/smtp_scache"
|
||||
|
||||
# SMTPD SETTINGS
|
||||
smtpd_use_tls: yes
|
||||
smtpd_tls_auth_only: no
|
||||
smtpd_tls_security_level: may
|
||||
smtpd_tls_loglevel: 1
|
||||
smtpd_tls_received_header: yes
|
||||
smtpd_tls_session_cache_timeout: 3600s
|
||||
smtpd_tls_session_cache_database: "btree:${data_directory}/smtpd_scache"
|
||||
smtpd_tls_cert_file: "/etc/letsencrypt/live/maruntiel.net/fullchain.pem"
|
||||
smtpd_tls_key_file: "/etc/letsencrypt/live/maruntiel.net/privkey.pem"
|
||||
smtpd_banner: "$myhostname ESMTP $mail_name"
|
||||
smtpd_client_restrictions:
|
||||
- permit_mynetworks
|
||||
- permit_sasl_authenticated
|
||||
- reject_invalid_hostname
|
||||
- reject_unknown_client
|
||||
- reject_rbl_client sbl-xbl.spamhaus.org
|
||||
smtpd_sender_restrictions:
|
||||
- permit_mynetworks
|
||||
- reject_unknown_address
|
||||
- reject_unknown_sender_domain
|
||||
- reject_non_fqdn_sender
|
||||
smtpd_recipient_limit: 250
|
||||
smtpd_recipient_restrictions:
|
||||
- reject_invalid_hostname
|
||||
- reject_non_fqdn_sender
|
||||
- reject_non_fqdn_recipient
|
||||
- reject_unlisted_sender
|
||||
- permit_mynetworks
|
||||
- permit_sasl_authenticated
|
||||
- reject_unauth_pipelining
|
||||
- reject_unauth_destination
|
||||
- check_policy_service unix:private/policyd-spf
|
||||
- reject_non_fqdn_hostname
|
||||
- reject_unknown_sender_domain
|
||||
- reject_rbl_client bl.spamcop.net
|
||||
- reject_rbl_client zen.spamhaus.org
|
||||
- permit
|
||||
|
||||
smtpd_relay_restrictions:
|
||||
- reject_invalid_hostname
|
||||
- reject_non_fqdn_sender
|
||||
- reject_non_fqdn_recipient
|
||||
- reject_unlisted_sender
|
||||
- permit_mynetworks
|
||||
- permit_sasl_authenticated
|
||||
- reject_unauth_pipelining
|
||||
- reject_unauth_destination
|
||||
- check_policy_service unix:private/policyd-spf
|
||||
- reject_non_fqdn_hostname
|
||||
- reject_unknown_sender_domain
|
||||
- reject_rbl_client bl.spamcop.net
|
||||
- reject_rbl_client zen.spamhaus.org
|
||||
- permit
|
||||
|
||||
smtpd_client_connection_rate_limit: 10
|
||||
smtpd_client_message_rate_limit: 10
|
||||
|
||||
# SASL
|
||||
smtpd_sasl_auth_enable: yes
|
||||
smtpd_sasl_type: dovecot
|
||||
smtpd_sasl_path: private/auth
|
||||
broken_sasl_auth_clients: yes
|
||||
smtpd_sasl_local_domain: \$mydomain
|
||||
smtpd_sasl_security_options: noanonymous
|
||||
|
||||
# Other
|
||||
header_checks:
|
||||
- regexp:/etc/postfix/header_checks
|
||||
|
||||
# DKIM
|
||||
milter_default_action: accept
|
||||
milter_protocol: 6
|
||||
smtpd_milters: local:opendkim/opendkim.sock
|
||||
non_smtpd_milters: $smtpd_milters
|
||||
|
||||
# SPF
|
||||
policyd-spf_time_limit: 3600
|
||||
|
||||
postfix_opendkim: "{{ postfix_dkim_domains|count > 0 }}"
|
||||
postfix_relay: no
|
||||
postfix_smtpd_public: yes
|
||||
postfix_firewall: "{{ firewall_enabled|default(true) }}"
|
||||
|
||||
postfix_dkim_domains: []
|
||||
|
||||
virtual_mailbox_domains: /etc/postfix/virtual_domains
|
||||
virtual_mailbox_base: /var/mail/vhosts
|
||||
virtual_mailbox_maps: hash:/etc/postfix/vmailbox
|
||||
virtual_alias_maps: hash:/etc/postfix/virtual_alias
|
||||
virtual_minimum_uid: 100
|
||||
virtual_uid_maps: static:5000
|
||||
virtual_gid_maps: static:5000
|
||||
virtual_transport: virtual
|
||||
12
roles/postfix/handlers/main.yml
Normal file
12
roles/postfix/handlers/main.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
- name: Restart postfix
|
||||
service:
|
||||
name: "postfix@-"
|
||||
state: restarted
|
||||
|
||||
- name: Rebuild postfix map files
|
||||
shell: postmap /etc/postfix/*.map
|
||||
|
||||
- name: Restart opendkim
|
||||
service:
|
||||
name: opendkim
|
||||
state: restarted
|
||||
4
roles/postfix/meta/main.yml
Normal file
4
roles/postfix/meta/main.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
dependencies:
|
||||
|
||||
- role: firewall
|
||||
when: postfix_firewall
|
||||
151
roles/postfix/tasks/main.yml
Normal file
151
roles/postfix/tasks/main.yml
Normal file
@@ -0,0 +1,151 @@
|
||||
---
|
||||
|
||||
- name: Install postfix
|
||||
apt:
|
||||
pkg:
|
||||
- postfix
|
||||
- postfix-pcre
|
||||
state: present
|
||||
tags: packages
|
||||
|
||||
- name: Install postfix configs
|
||||
template:
|
||||
dest: "/etc/postfix/{{ item }}"
|
||||
src: "etc_postfix_{{ item }}.j2"
|
||||
mode: 0644
|
||||
owner: root
|
||||
group: root
|
||||
with_items:
|
||||
- main.cf
|
||||
- master.cf
|
||||
- header_checks
|
||||
notify: Restart postfix
|
||||
tags: configs
|
||||
|
||||
- name: Install postfix maps
|
||||
template:
|
||||
dest: "/etc/postfix/{{ item }}"
|
||||
src: "etc_postfix_{{ item }}.j2"
|
||||
mode: 0640
|
||||
owner: root
|
||||
group: postfix
|
||||
with_items:
|
||||
- sasl_passwd.map
|
||||
- transport.map
|
||||
# - virtual.map
|
||||
notify: Rebuild postfix map files
|
||||
tags: configs
|
||||
|
||||
- name: Install empty postfix maps
|
||||
copy:
|
||||
dest: "/etc/postfix/{{ item }}"
|
||||
content: ""
|
||||
force: no
|
||||
mode: 0644
|
||||
owner: root
|
||||
group: root
|
||||
with_items:
|
||||
- virtual.map
|
||||
notify: Rebuild postfix map files
|
||||
tags: configs
|
||||
|
||||
- name: Install postfix-policyd-spf
|
||||
apt:
|
||||
pkg:
|
||||
- postfix-policyd-spf-python
|
||||
state: present
|
||||
tags: packages
|
||||
|
||||
- name: Ensure postfix is running
|
||||
service:
|
||||
name: postfix
|
||||
state: started
|
||||
enabled: yes
|
||||
tags: configs
|
||||
|
||||
- name: Install the postfix firewall config
|
||||
template:
|
||||
dest: /etc/firewall/rules-v4.d/40_postfix.sh
|
||||
src: etc_firewall_rules-v4.d_40_postfix.sh.j2
|
||||
mode: 0644
|
||||
owner: root
|
||||
group: root
|
||||
when: postfix_firewall
|
||||
notify: Restart firewall
|
||||
tags:
|
||||
- configs
|
||||
- firewall
|
||||
|
||||
# =====================================================================
|
||||
|
||||
- name: Install opendkim
|
||||
apt:
|
||||
pkg:
|
||||
- opendkim
|
||||
- opendkim-tools
|
||||
state: present
|
||||
when: postfix_opendkim
|
||||
tags: packages
|
||||
|
||||
- name: Ensure postfix is a member of opendkim
|
||||
user:
|
||||
name: postfix
|
||||
groups: opendkim
|
||||
append: yes
|
||||
when: postfix_opendkim
|
||||
notify: Restart postfix
|
||||
tags: configs
|
||||
|
||||
- name: Ensure /etc/opendkim dir exists
|
||||
file:
|
||||
path: /etc/opendkim
|
||||
state: directory
|
||||
mode: 0755
|
||||
owner: root
|
||||
group: root
|
||||
when: postfix_opendkim
|
||||
tags: configs
|
||||
|
||||
- name: Ensure /etc/opendkim/keys dir exists
|
||||
file:
|
||||
path: /etc/opendkim/keys
|
||||
state: directory
|
||||
mode: 0750
|
||||
owner: root
|
||||
group: opendkim
|
||||
when: postfix_opendkim
|
||||
tags: configs
|
||||
|
||||
- name: Install opendkim configs
|
||||
template:
|
||||
dest: "/{{ item }}"
|
||||
src: "{{ item | replace('/', '_') }}.j2"
|
||||
mode: 0644
|
||||
owner: root
|
||||
group: root
|
||||
with_items:
|
||||
- etc/opendkim.conf
|
||||
- etc/opendkim/key.table
|
||||
- etc/opendkim/signing.table
|
||||
- etc/opendkim/trusted.hosts
|
||||
when: postfix_opendkim
|
||||
notify: Restart opendkim
|
||||
tags: configs
|
||||
|
||||
- name: Ensure /var/spool/postfix/opendkim dir exists
|
||||
file:
|
||||
path: /var/spool/postfix/opendkim
|
||||
state: directory
|
||||
mode: 0755
|
||||
owner: opendkim
|
||||
group: postfix
|
||||
when: postfix_opendkim
|
||||
tags: configs
|
||||
|
||||
- name: Ensure opendkim is running
|
||||
service:
|
||||
name: postfix
|
||||
state: started
|
||||
enabled: yes
|
||||
when: postfix_opendkim
|
||||
tags: configs
|
||||
@@ -0,0 +1,11 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% if postfix_smtpd_public %}
|
||||
iptables -A INPUT -p tcp --dport 25 -m comment --comment "postfix-smtp" -j ACCEPT
|
||||
{% elif postfix_relay %}
|
||||
iptables -A internal-in -p tcp --dport 25 -m comment --comment "postfix-smtp" -j ACCEPT
|
||||
{% endif %}
|
||||
|
||||
{% if firewall_output_default_drop %}
|
||||
iptables -A OUTPUT -p tcp --dport 25 -m owner --gid-owner postfix -m comment --comment "smtp" -j ACCEPT
|
||||
{% endif %}
|
||||
38
roles/postfix/templates/etc_opendkim.conf.j2
Normal file
38
roles/postfix/templates/etc_opendkim.conf.j2
Normal file
@@ -0,0 +1,38 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# This is a basic configuration that can easily be adapted to suit a standard
|
||||
# installation. For more advanced options, see opendkim.conf(5) and/or
|
||||
# /usr/share/doc/opendkim/examples/opendkim.conf.sample.
|
||||
|
||||
Syslog yes
|
||||
LogWhy yes
|
||||
PidFile /var/run/opendkim/opendkim.pid
|
||||
Socket local:/var/spool/postfix/opendkim/opendkim.sock
|
||||
UMask 002
|
||||
UserID opendkim
|
||||
|
||||
# Map domains in From addresses to keys used to sign messages
|
||||
KeyTable file:/etc/opendkim/key.table
|
||||
SigningTable file:/etc/opendkim/signing.table
|
||||
|
||||
# Hosts to ignore when verifying signatures
|
||||
ExternalIgnoreList /etc/opendkim/trusted.hosts
|
||||
InternalHosts /etc/opendkim/trusted.hosts
|
||||
|
||||
# Commonly-used options; the commented-out versions show the defaults.
|
||||
Canonicalization relaxed/simple
|
||||
Mode sv
|
||||
SubDomains yes
|
||||
#ADSPAction continue
|
||||
AutoRestart yes
|
||||
AutoRestartRate 10/1M
|
||||
Background yes
|
||||
DNSTimeout 5
|
||||
SignatureAlgorithm rsa-sha256
|
||||
|
||||
# Always oversign From (sign using actual From and a null From to prevent
|
||||
# malicious signatures header fields (From and/or others) between the signer
|
||||
# and the verifier. From is oversigned by default in the Debian package
|
||||
# because it is often the identity key used by reputation systems and thus
|
||||
# somewhat security sensitive.
|
||||
OversignHeaders From
|
||||
5
roles/postfix/templates/etc_opendkim_key.table.j2
Normal file
5
roles/postfix/templates/etc_opendkim_key.table.j2
Normal file
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% for domain, info in postfix_dkim_domains | dictsort %}
|
||||
mail._domainkey.{{ domain }} {{ domain }}:mail:/etc/opendkim/keys/{{ domain }}/mail.private
|
||||
{% endfor %}
|
||||
6
roles/postfix/templates/etc_opendkim_signing.table.j2
Normal file
6
roles/postfix/templates/etc_opendkim_signing.table.j2
Normal file
@@ -0,0 +1,6 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% for domain, info in postfix_dkim_domains | dictsort %}
|
||||
{{ domain }} mail._domainkey.{{ domain }}
|
||||
.{{ domain }} mail._domainkey.{{ domain }}
|
||||
{% endfor %}
|
||||
4
roles/postfix/templates/etc_opendkim_trusted.hosts.j2
Normal file
4
roles/postfix/templates/etc_opendkim_trusted.hosts.j2
Normal file
@@ -0,0 +1,4 @@
|
||||
127.0.0.0/8
|
||||
[::ffff:127.0.0.0]/104
|
||||
[::1]/128
|
||||
{{ postfix_mynetworks | join("\n") }}
|
||||
5
roles/postfix/templates/etc_postfix_header_checks.j2
Normal file
5
roles/postfix/templates/etc_postfix_header_checks.j2
Normal file
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% for item in postfix_header_checks | default([]) %}
|
||||
{{ item }}
|
||||
{% endfor %}
|
||||
13
roles/postfix/templates/etc_postfix_main.cf.j2
Normal file
13
roles/postfix/templates/etc_postfix_main.cf.j2
Normal file
@@ -0,0 +1,13 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# See /usr/share/postfix/main.cf.dist for a commented, more complete version
|
||||
|
||||
{% for key, value in postfix_settings | dictsort %}
|
||||
{% if value is sequence and value is not string %}
|
||||
{{ key }} = {{ value | flatten | join(",\n\t") }}
|
||||
{% elif value is sameas true or value is sameas false %}
|
||||
{{ key }} = {{ 'yes' if value else 'no' }}
|
||||
{% else %}
|
||||
{{ key }} = {{ value }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
132
roles/postfix/templates/etc_postfix_master.cf.j2
Normal file
132
roles/postfix/templates/etc_postfix_master.cf.j2
Normal file
@@ -0,0 +1,132 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
#
|
||||
# Postfix master process configuration file. For details on the format
|
||||
# of the file, see the master(5) manual page (command: "man 5 master" or
|
||||
# on-line: http://www.postfix.org/master.5.html).
|
||||
#
|
||||
# Do not forget to execute "postfix reload" after editing this file.
|
||||
#
|
||||
# ==========================================================================
|
||||
# service type private unpriv chroot wakeup maxproc command + args
|
||||
# (yes) (yes) (no) (never) (100)
|
||||
# ==========================================================================
|
||||
smtp inet n - y - - smtpd
|
||||
#smtp inet n - y - 1 postscreen
|
||||
#smtpd pass - - y - - smtpd
|
||||
#dnsblog unix - - y - 0 dnsblog
|
||||
#tlsproxy unix - - y - 0 tlsproxy
|
||||
#submission inet n - y - - smtpd
|
||||
# -o syslog_name=postfix/submission
|
||||
# -o smtpd_tls_security_level=encrypt
|
||||
# -o smtpd_sasl_auth_enable=yes
|
||||
# -o smtpd_reject_unlisted_recipient=no
|
||||
# -o smtpd_client_restrictions=$mua_client_restrictions
|
||||
# -o smtpd_helo_restrictions=$mua_helo_restrictions
|
||||
# -o smtpd_sender_restrictions=$mua_sender_restrictions
|
||||
# -o smtpd_recipient_restrictions=
|
||||
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
||||
# -o milter_macro_daemon_name=ORIGINATING
|
||||
smtps inet n - y - - smtpd
|
||||
# -o syslog_name=postfix/smtps
|
||||
# -o smtpd_tls_wrappermode=yes
|
||||
# -o smtpd_sasl_auth_enable=yes
|
||||
# -o smtpd_reject_unlisted_recipient=no
|
||||
# -o smtpd_client_restrictions=$mua_client_restrictions
|
||||
# -o smtpd_helo_restrictions=$mua_helo_restrictions
|
||||
# -o smtpd_sender_restrictions=$mua_sender_restrictions
|
||||
# -o smtpd_recipient_restrictions=
|
||||
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
|
||||
# -o milter_macro_daemon_name=ORIGINATING
|
||||
#628 inet n - y - - qmqpd
|
||||
pickup unix n - y 60 1 pickup
|
||||
cleanup unix n - y - 0 cleanup
|
||||
qmgr unix n - n 300 1 qmgr
|
||||
#qmgr unix n - n 300 1 oqmgr
|
||||
tlsmgr unix - - y 1000? 1 tlsmgr
|
||||
rewrite unix - - y - - trivial-rewrite
|
||||
bounce unix - - y - 0 bounce
|
||||
defer unix - - y - 0 bounce
|
||||
trace unix - - y - 0 bounce
|
||||
verify unix - - y - 1 verify
|
||||
flush unix n - y 1000? 0 flush
|
||||
proxymap unix - - n - - proxymap
|
||||
proxywrite unix - - n - 1 proxymap
|
||||
smtp unix - - y - - smtp
|
||||
relay unix - - y - - smtp
|
||||
-o smtp_fallback_relay=
|
||||
# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
|
||||
showq unix n - y - - showq
|
||||
error unix - - y - - error
|
||||
retry unix - - y - - error
|
||||
discard unix - - y - - discard
|
||||
local unix - n n - - local
|
||||
virtual unix - n n - - virtual
|
||||
lmtp unix - - y - - lmtp
|
||||
anvil unix - - y - 1 anvil
|
||||
scache unix - - y - 1 scache
|
||||
{% if ansible_lsb.major_release|int >= 10 %}
|
||||
postlog unix-dgram n - n - 1 postlogd
|
||||
{% endif %}
|
||||
#
|
||||
# ====================================================================
|
||||
# Interfaces to non-Postfix software. Be sure to examine the manual
|
||||
# pages of the non-Postfix software to find out what options it wants.
|
||||
#
|
||||
# Many of the following services use the Postfix pipe(8) delivery
|
||||
# agent. See the pipe(8) man page for information about ${recipient}
|
||||
# and other message envelope options.
|
||||
# ====================================================================
|
||||
#
|
||||
# maildrop. See the Postfix MAILDROP_README file for details.
|
||||
# Also specify in main.cf: maildrop_destination_recipient_limit=1
|
||||
#
|
||||
maildrop unix - n n - - pipe
|
||||
flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
|
||||
#
|
||||
# ====================================================================
|
||||
#
|
||||
# Recent Cyrus versions can use the existing "lmtp" master.cf entry.
|
||||
#
|
||||
# Specify in cyrus.conf:
|
||||
# lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4
|
||||
#
|
||||
# Specify in main.cf one or more of the following:
|
||||
# mailbox_transport = lmtp:inet:localhost
|
||||
# virtual_transport = lmtp:inet:localhost
|
||||
#
|
||||
# ====================================================================
|
||||
#
|
||||
# Cyrus 2.1.5 (Amos Gouaux)
|
||||
# Also specify in main.cf: cyrus_destination_recipient_limit=1
|
||||
#
|
||||
#cyrus unix - n n - - pipe
|
||||
# user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
|
||||
#
|
||||
# ====================================================================
|
||||
# Old example of delivery via Cyrus.
|
||||
#
|
||||
#old-cyrus unix - n n - - pipe
|
||||
# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
|
||||
#
|
||||
# ====================================================================
|
||||
#
|
||||
# See the Postfix UUCP_README file for configuration details.
|
||||
#
|
||||
uucp unix - n n - - pipe
|
||||
flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
|
||||
#
|
||||
# Other external delivery methods.
|
||||
#
|
||||
ifmail unix - n n - - pipe
|
||||
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
|
||||
bsmtp unix - n n - - pipe
|
||||
flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
|
||||
scalemail-backend unix - n n - 2 pipe
|
||||
flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
|
||||
mailman unix - n n - - pipe
|
||||
flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
|
||||
${nexthop} ${user}
|
||||
|
||||
policyd-spf unix - n n - 0 spawn
|
||||
user=policyd-spf argv=/usr/bin/policyd-spf
|
||||
5
roles/postfix/templates/etc_postfix_sasl_passwd.map.j2
Normal file
5
roles/postfix/templates/etc_postfix_sasl_passwd.map.j2
Normal file
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% for key, value in postfix_sasl_passwd_map | default({}) | dictsort %}
|
||||
{{ key }} {{ value.username }}:{{ value.password }}
|
||||
{% endfor %}
|
||||
5
roles/postfix/templates/etc_postfix_transport.map.j2
Normal file
5
roles/postfix/templates/etc_postfix_transport.map.j2
Normal file
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% for key, value in postfix_transport_map | default({}) | dictsort %}
|
||||
{{ key }} {{ value }}
|
||||
{% endfor %}
|
||||
5
roles/postfix/templates/etc_postfix_virtual.map.j2
Normal file
5
roles/postfix/templates/etc_postfix_virtual.map.j2
Normal file
@@ -0,0 +1,5 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
{% for key, value in postfix_virtual_map | default({}) | dictsort %}
|
||||
{{ key }} {{ value }}
|
||||
{% endfor %}
|
||||
43
roles/ssh/defaults/main.yml
Normal file
43
roles/ssh/defaults/main.yml
Normal file
@@ -0,0 +1,43 @@
|
||||
---
|
||||
|
||||
ssh_client_settings:
|
||||
# Host:
|
||||
# - Host: "*"
|
||||
# SendEnv: LANG LC_*
|
||||
# HashKnownHosts: yes
|
||||
ForwardAgent: yes
|
||||
HashKnownHosts: yes
|
||||
|
||||
|
||||
ssh_server_settings:
|
||||
Port: 22
|
||||
Protocol: 2
|
||||
HostKey:
|
||||
- /etc/ssh/ssh_host_rsa_key
|
||||
- /etc/ssh/ssh_host_ecdsa_key
|
||||
- /etc/ssh/ssh_host_ed25519_key
|
||||
SyslogFacility: AUTH
|
||||
LogLevel: INFO
|
||||
PermitRootLogin: prohibit-password
|
||||
PubkeyAuthentication: yes
|
||||
PermitEmptyPasswords: no
|
||||
AuthenticationMethods publickey,keyboard-interactive
|
||||
ChallengeResponseAuthentication: yes
|
||||
PasswordAuthentication: no
|
||||
X11Forwarding: no
|
||||
PrintMotd: no
|
||||
PrintLastLog: yes
|
||||
AcceptEnv: LANG LC_*
|
||||
Subsystem:
|
||||
- sftp /usr/lib/openssh/sftp-server
|
||||
UsePAM: yes
|
||||
|
||||
# Hardened cipher list
|
||||
KexAlgorithms: curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256
|
||||
Ciphers: chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
|
||||
MACs: hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256,hmac-sha2-512
|
||||
HostKeyAlgorithms: ssh-rsa,ssh-ed25519
|
||||
|
||||
# Match:
|
||||
# - Match: "*"
|
||||
# AllowAgentForwarding: yes
|
||||
4
roles/ssh/handlers/main.yml
Normal file
4
roles/ssh/handlers/main.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
|
||||
- name: Restart SSH
|
||||
service: name=ssh state=restarted
|
||||
45
roles/ssh/tasks/main.yml
Normal file
45
roles/ssh/tasks/main.yml
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
# Tasks to install and configure OpenSSH
|
||||
|
||||
- name: Make sure the SSH server and client packages are installed
|
||||
apt:
|
||||
pkg:
|
||||
- openssh-client
|
||||
- openssh-server
|
||||
state: present
|
||||
tags: ssh
|
||||
|
||||
- name: Configure the SSH Client
|
||||
template:
|
||||
src: etc_ssh_ssh_config.j2
|
||||
dest: /etc/ssh/ssh_config
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0644
|
||||
tags: ssh
|
||||
|
||||
- name: Configure the SSH Server
|
||||
template:
|
||||
src: etc_ssh_sshd_config.j2
|
||||
dest: /etc/ssh/sshd_config
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0644
|
||||
notify: Restart SSH
|
||||
tags: ssh
|
||||
|
||||
#- name: Update ssh_known_hosts
|
||||
# lineinfile:
|
||||
# dest: /etc/ssh/ssh_known_hosts
|
||||
# regexp: "^{{ hostvars[item].ansible_hostname }},"
|
||||
# line: >
|
||||
# {{ hostvars[item].ansible_hostname }},{{ hostvars[item].ansible_fqdn }},{{ hostvars[item].ansible_default_ipv4.address }}
|
||||
# ssh-rsa {{ hostvars[item].ansible_ssh_host_key_rsa_public }}
|
||||
# state: present
|
||||
# create: yes
|
||||
# owner: root
|
||||
# group: root
|
||||
# mode: 0644
|
||||
# with_items: "{{ groups.all|sort }}"
|
||||
# when: item in hostvars
|
||||
# tags: ssh
|
||||
8
roles/ssh/templates/etc_ssh_ssh_config.j2
Normal file
8
roles/ssh/templates/etc_ssh_ssh_config.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# See the ssh_config(5) manpage for details
|
||||
|
||||
{% from 'ssh_common.j2' import ssh_config with context %}
|
||||
{% call ssh_config(ssh_client_settings) %}{% endcall %}
|
||||
|
||||
# EOF
|
||||
8
roles/ssh/templates/etc_ssh_sshd_config.j2
Normal file
8
roles/ssh/templates/etc_ssh_sshd_config.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
# {{ ansible_managed }}
|
||||
|
||||
# See the sshd_config(5) manpage for details
|
||||
|
||||
{% from 'ssh_common.j2' import ssh_config with context %}
|
||||
{% call ssh_config(ssh_server_settings) %}{% endcall %}
|
||||
|
||||
# EOF
|
||||
25
roles/ssh/templates/ssh_common.j2
Normal file
25
roles/ssh/templates/ssh_common.j2
Normal file
@@ -0,0 +1,25 @@
|
||||
# {{ ansible_managed }}
|
||||
{% macro ssh_config(settings, caller='') %}
|
||||
{% set sections = ('Host', 'Match') %}
|
||||
|
||||
{%- for key, value in settings|dictsort if key not in sections %}
|
||||
{% if value is sequence and value is not string %}
|
||||
{% for item in value %}
|
||||
{{ key }} {{ item }}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{{ key }} {{ ['no','yes'][value|int] if value in (False,True) else value }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{%- for section in sections if section in settings %}
|
||||
|
||||
{% for item in settings[section] %}
|
||||
{{ section }} {{ item[section] }}
|
||||
{% for key, value in item|dictsort if key != section %}
|
||||
{{ key }} {{ ['no','yes'][value|int] if value in (False,True) else value }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endfor -%}
|
||||
|
||||
{% endmacro %}
|
||||
Reference in New Issue
Block a user