Add ansible playbooks

This commit is contained in:
Wojciech Kozlowski 2018-12-16 00:25:02 +00:00
parent 47819c6a8d
commit f0dc46a6af
21 changed files with 2038 additions and 0 deletions

2
ansible/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.retry
secrets.yml

50
ansible/README.rst Normal file
View File

@ -0,0 +1,50 @@
Loki Ansible Playbooks
======================
Ansible playbooks for provisioning the server.
Requirements
------------
Make sure you have ``ansible`` installed.
Usage
-----
Before any provisioning
#. Copy secrets.def.yml to secrets.yml and fill out all the variables.
#. Encrypt the file with
::
ansible-vault encrypt secrets.yml
#. To run a playbook
::
ansible-playbook --vault-id @prompt playbook.yml
From this point it is assumed you have a server which can accept SSH
connections and you have setup public key authentication.
To provision the server
#. First install ``python`` on the server which is required by ``ansible``
::
ansible-playbook --vault-id @prompt python.yml
#. Configure the SSH daemon with a new port number and better security options.
::
ansible-playbook --vault-id @prompt ssh.yml
#. Run the remaining setup.
::
ansible-playbook --vault-id @prompt loki.yml

6
ansible/ansible.cfg Normal file
View File

@ -0,0 +1,6 @@
[defaults]
inventory = ./hosts
[privilege_escalation]
become=True
become_method=su

4
ansible/etc/aliases.j2 Normal file
View File

@ -0,0 +1,4 @@
# See man 5 aliases for format
postmaster: root
root: {{ postfix_alias }}
logcheck: root

View File

@ -0,0 +1,3 @@
RUN_DAILY="true"
RUN_DAILY_OPTS="-q"
DIFF_MODE="true"

View File

@ -0,0 +1 @@
GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT apparmor=1 security=apparmor"

View File

@ -0,0 +1,34 @@
# Defaults for rkhunter automatic tasks
# sourced by /etc/cron.*/rkhunter and /etc/apt/apt.conf.d/90rkhunter
#
# This is a POSIX shell fragment
#
# Set this to yes to enable rkhunter daily runs
# (default: false)
CRON_DAILY_RUN="yes"
# Set this to yes to enable rkhunter weekly database updates
# (default: false)
CRON_DB_UPDATE=""
# Set this to yes to enable reports of weekly database updates
# (default: false)
DB_UPDATE_EMAIL="false"
# Set this to the email address where reports and run output should be sent
# (default: root)
REPORT_EMAIL="root"
# Set this to yes to enable automatic database updates
# (default: false)
APT_AUTOGEN="false"
# Nicenesses range from -20 (most favorable scheduling) to 19 (least favorable)
# (default: 0)
NICE="0"
# Should daily check be run when running on battery
# powermgmt-base is required to detect if running on battery or on AC power
# (default: false)
RUN_CHECK_ON_BATTERY="false"

View File

@ -0,0 +1,24 @@
[DEFAULT]
# Setup email settings
sender = {{ fail2ban_sender }}
# Receive mail alerts
action = %(action_mw)s
# Chain variable needs to be overridden in jail.local,
# as the uppercase `chain = INPUT` declaration in jail.conf
# shadows proper lowercase declaration in nftables-common.conf
chain = input
# Use nftables instead of iptables
banaction = nftables-multiport
banaction_allports = nftables-allports
[sshd]
enabled = true
port = {{ ansible_port }}
[postfix]
enabled = true
postfix_log = %(syslog_mail)s

8
ansible/etc/hosts.j2 Normal file
View File

@ -0,0 +1,8 @@
127.0.0.1 localhost
127.0.1.1 {{ fqdn }} {{ hostname }}
127.0.0.1 wojciechkozlowski.eu cloud.wojciechkozlowski.eu wiki.wojciechkozlowski.eu gitlab.wojciechkozlowski.eu registry.wojciechkozlowski.eu
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

View File

@ -0,0 +1,6 @@
^[[:alpha:]]{3} [ :[:digit:]]{11} {{ hostname }} docker-compose\[[0-9]+\]:
^[[:alpha:]]{3} [ :[:digit:]]{11} {{ hostname }} systemd\[[0-9]+\]: Listening on GnuPG network certificate management daemon.
^[[:alpha:]]{3} [ :[:digit:]]{11} {{ hostname }} systemd\[[0-9]+\]: Listening on GnuPG cryptographic agent
^[[:alpha:]]{3} [ :[:digit:]]{11} {{ hostname }} systemd\[[0-9]+\]: Closed GnuPG network certificate management daemon.
^[[:alpha:]]{3} [ :[:digit:]]{11} {{ hostname }} systemd\[[0-9]+\]: Closed GnuPG cryptographic agent
^[[:alpha:]]{3} [ :[:digit:]]{11} {{ hostname }} auditd\[[0-9]+\]: Audit daemon rotating log files

1
ansible/etc/mailname.j2 Normal file
View File

@ -0,0 +1 @@
{{ postfix_mailname }}

View File

@ -0,0 +1,26 @@
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0;
# accept any localhost traffic
iif lo accept
# accept traffic originated from us
ct state established,related accept
# allow ICMP packets
# note that for IPv6 nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert are needed to not break connectivity
ip6 nexthdr icmpv6 icmpv6 type { echo-request, destination-unreachable, packet-too-big, time-exceeded, parameter-problem, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept
ip protocol icmp icmp type { echo-request, destination-unreachable, router-advertisement, time-exceeded, parameter-problem } accept
# activate the following line to accept common local services
tcp dport { 80, 443, {{ ansible_port }}, {{ gitlab_ssh_port }} } ct state new accept
# count and drop any other traffic
counter drop
}
}

View File

@ -0,0 +1,54 @@
# See /usr/share/postfix/main.cf.dist for a commented, more complete version
# Debian specific: Specifying a file name will cause the first
# line of that file to be used as the name. The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname
smtpd_banner = $myhostname ESMTP
biff = no
# appending .domain is the MUA's job.
append_dot_mydomain = no
# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h
readme_directory = no
# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on
# fresh installs.
compatibility_level = 2
# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_tls_wrappermode = yes
smtp_tls_security_level = encrypt
# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = {{ fqdn }}
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = $myhostname, localhost
relayhost = [{{ postfix_smtp_server }}]:{{ postfix_smtp_port }}
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = localhost
inet_protocols = all
# SMTP settings
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_use_tls = yes
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt

View File

@ -0,0 +1 @@
[{{ postfix_smtp_server }}]:{{ postfix_smtp_port }} {{ postfix_smtp_user }}:{{ postfix_smtp_pass }}

1251
ansible/etc/rkhunter.conf.j2 Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,125 @@
# $OpenBSD: sshd_config,v 1.100 2016/08/15 12:32:04 naddy Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
Port {{ ssh_port }}
Protocol 2
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
PermitRootLogin no
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
AllowUsers {{ ansible_ssh_user }}
#PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding no
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#UsePrivilegeSeparation sandbox
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server

15
ansible/hosts Normal file
View File

@ -0,0 +1,15 @@
# - Comments begin with the '#' character
# - Blank lines are ignored
# - Groups of hosts are delimited by [header] elements
# - You can enter hostnames or ip addresses
# - A hostname/ip can be a member of multiple groups
# Cloudflare will not forward SSH connections so instead need to connect
# directly via the server's IP address. This is best done by adding
# appropriate entries to /etc/hosts.
[server]
loki
[vm]
mimir

356
ansible/loki.yml Normal file
View File

@ -0,0 +1,356 @@
---
- hosts: server
vars_files:
- secrets.yml
vars:
- debian_release: stretch
- loki_dir: /srv/loki
tasks:
# -------------------------------------------------------------------------
# Update and upgrade.
# -------------------------------------------------------------------------
- name: Update and upgrade apt packages
apt:
upgrade: yes
update_cache: yes
cache_valid_time: 86400 #One day
force_apt_get: yes
register: apt_update
# Once ansible 2.7 is available will be able to just use reboot module.
- block:
- name: Reboot
shell: "sleep 1 && reboot"
async: 1
poll: 0
- name: Wait for host to come back up
wait_for_connection:
connect_timeout: 20
sleep: 5
delay: 5
timeout: 300
when: apt_update is changed
# -------------------------------------------------------------------------
# Apparmor.
# -------------------------------------------------------------------------
- name: Install apparmor, utilities, and profiles
apt:
name: "{{ item }}"
with_items:
- apparmor
- apparmor-utils
- apparmor-profiles
- apparmor-profiles-extra
register: apparmor
- name: Ensure /etc/default/grub.d exists
file:
path: /etc/default/grub.d
state: directory
mode: 0755
- name: Enable apparmor
template:
src: ./etc/default/grub.d/apparmor.cfg.j2
dest: /etc/default/grub.d/apparmor.cfg
mode: 0644
register: apparmor_cfg
# Once ansible 2.7 is available will be able to just use reboot module.
- block:
- name: Update grub
command: update-grub
- name: Reboot
shell: "sleep 1 && reboot"
async: 1
poll: 0
- name: Wait for host to come back up
wait_for_connection:
connect_timeout: 20
sleep: 5
delay: 5
timeout: 300
when:
apparmor is changed or
apparmor_cfg is changed
# -------------------------------------------------------------------------
# Firewall.
# -------------------------------------------------------------------------
- name: Install nftables
apt:
name: nftables
register: nftables
- name: Configure nftables
template:
src: ./etc/nftables.conf.j2
dest: /etc/nftables.conf
mode: 0644
register: nftables_cfg
- name: Enable and restart nftables
service:
name: nftables
state: restarted
enabled: yes
when:
nftables is changed or
nftables_cfg is changed
# -------------------------------------------------------------------------
# Postfix.
# -------------------------------------------------------------------------
- name: Install postfix
apt:
name: "{{ item }}"
with_items:
- postfix
- ca-certificates
- libsasl2-modules
register: postfix
- name: Configure credentials
template:
src: ./etc/postfix/sasl_passwd.j2
dest: /etc/postfix/sasl_passwd
mode: 0600
register: postfix_cred
- name: Configure mailname
template:
src: ./etc/mailname.j2
dest: /etc/mailname
mode: 0644
register: postfix_mailname
- name: Configure postfix
template:
src: ./etc/postfix/main.cf.j2
dest: /etc/postfix/main.cf
mode: 0644
register: postfix_cfg
- name: Postmap
command: postmap /etc/postfix/sasl_passwd
when:
postfix_cred is changed or
postfix_mailname is changed
- name: Change DB permissions
file:
path: /etc/postfix/sasl_passwd.db
mode: 0600
- name: Set root alias
template:
src: ./etc/aliases.j2
dest: /etc/aliases
mode: 0644
register: postfix_aliases
- name: Update aliases
command: newaliases
when: postfix_aliases is changed
- name: Enable and restart postfix
service:
name: postfix
state: restarted
enabled: yes
when:
postfix is changed or
postfix_cred is changed or
postfix_mailname is changed or
postfix_cfg is changed or
postfix_aliases is changed
# -------------------------------------------------------------------------
# Fail2Ban.
# -------------------------------------------------------------------------
- name: Install fail2ban
apt:
name: fail2ban
register: fail2ban
- name: Configure fail2ban
template:
src: ./etc/fail2ban/jail.d/jail.local.j2
dest: /etc/fail2ban/jail.d/jail.local
mode: 0644
register: fail2ban_cfg
- name: Enable and restart fail2ban
service:
name: fail2ban
state: restarted
enabled: yes
when:
fail2ban is changed or
fail2ban_cfg is changed
# -------------------------------------------------------------------------
# Logcheck and Logrotate.
# -------------------------------------------------------------------------
- name: Install logcheck and logrotate
apt:
name: "{{ item }}"
with_items:
- logcheck
- logrotate
- name: Configure logcheck
template:
src: ./etc/logcheck/ignore.d.server/local-server.j2
dest: /etc/logcheck/ignore.d.server/local-server
mode: 0644
# -------------------------------------------------------------------------
# Chkrootkit and Rkhunter.
# -------------------------------------------------------------------------
- name: Install rkhunter and chkrootkit
apt:
name: "{{ item }}"
with_items:
- rkhunter
- chkrootkit
- name: Configure rkhunter
template:
src: ./etc/rkhunter.conf.j2
dest: /etc/rkhunter.conf
mode: 0644
- name: Configure rkhunter
template:
src: ./etc/default/rkhunter.j2
dest: /etc/default/rkhunter
mode: 0644
- name: Configure chkrootkit
template:
src: ./etc/chkrootkit.conf.j2
dest: /etc/chkrootkit.conf
mode: 0644
# -------------------------------------------------------------------------
# Docker CE.
# -------------------------------------------------------------------------
- name: Install packages to enable HTTPS repository
apt:
name: "{{ item }}"
with_items:
- apt-transport-https
- ca-certificates
- curl
- gnupg2
- software-properties-common
- name: Add Docker GPG key
apt_key:
id: 0EBFCD88
url: https://download.docker.com/linux/debian/gpg
state: present
- name: Add Docker repository
apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/debian "{{ debian_release }}" stable
state: present
register: docker_repo
- name: Update apt cache
apt:
update_cache: yes
force_apt_get: yes
when: docker_repo is changed
- name: Install docker-ce and docker-compose
apt:
name: "{{ item }}"
with_items:
- docker-ce
- docker-compose
# -------------------------------------------------------------------------
# Loki server.
# -------------------------------------------------------------------------
- name: Install git
apt:
name: git
- name: Clone Loki repo
git:
repo: https://github.com/Wojtek242/loki.git
dest: "{{ loki_dir }}"
register: loki_git
- block:
- name: Install Loki service
command: cp "{{ loki_dir }}"/loki-server.service /lib/systemd/system/
- name: Update service file
lineinfile:
path: /lib/systemd/system/loki-server.service
regexp: '^WorkingDirectory='
line: 'WorkingDirectory={{ loki_dir }}'
- name: Reload systemd daemon
systemd:
daemon_reload: yes
- block:
- name: Update
command: ./update.sh
args:
chdir: "{{ loki_dir }}"
rescue:
- debug:
msg: "Failed to pull containers from registry - will build locally"
when: loki_git is changed
# Hosts file must be added after the first update as otherwise the initial
# container pull will always fail
- name: Add hosts file
template:
src: ./etc/hosts.j2
dest: /etc/hosts
mode: 0644
- name: Ensure service is started
service:
name: loki-server
state: started
enabled: yes
# -------------------------------------------------------------------------
# Update rkhunter and chkrootkit databases.
# -------------------------------------------------------------------------
- name: Update rkhunter database
command: rkhunter --propupd
- name: Run chkrootkit
command: /etc/cron.daily/chkrootkit
- name: Update chkrootkit logs
command: cp -a /var/log/chkrootkit/log.today /var/log/chkrootkit/log.expected

16
ansible/python.yml Normal file
View File

@ -0,0 +1,16 @@
---
- hosts: server
gather_facts: no
vars_files:
- secrets.yml
pre_tasks:
- name: Use default SSH port
set_fact:
ansible_port: 22
tasks:
- name: Install python2
raw: apt-get -y install python

28
ansible/secrets.def.yml Normal file
View File

@ -0,0 +1,28 @@
---
hostname: # Output of hostname
fqdn: # OUtput of hostname --fqdn
# Ansible parameters
ansible_port:
ansible_ssh_user:
ansible_ssh_private_key_file:
ansible_become_pass:
# This value should be the same as ansible_port, but it needs to be a separate
# variable. This is because for when setting sshd_config ansible_port is
# temporarily reset to the default SSH port.
ssh_port:
# GitLab
gitlab_ssh_port:
# Postfix
postfix_smtp_server:
postfix_smtp_port:
postfix_smtp_user:
postfix_smtp_pass:
postfix_alias:
postfix_mailname:
# Fail2Ban
fail2ban_sender:

27
ansible/ssh.yml Normal file
View File

@ -0,0 +1,27 @@
---
- hosts: server
gather_facts: no
vars_files:
- secrets.yml
pre_tasks:
- name: Use default SSH port
set_fact:
ansible_port: 22
tasks:
- name: Copy sshd config
template:
src: ./etc/ssh/sshd_config.j2
dest: /etc/ssh/sshd_config
mode: 0644
register: sshd_cfg
- name: Restart SSH daemon
service:
name: sshd
state: restarted
enabled: yes
when: sshd_cfg is changed