Initial working commit

This commit is contained in:
Bastian de Byl
2020-09-24 21:06:56 -04:00
commit e0abdbe506
32 changed files with 430 additions and 0 deletions

4
.git-crypt/.gitattributes vendored Normal file
View File

@@ -0,0 +1,4 @@
# Do not edit this file. To specify the files to encrypt, create your own
# .gitattributes file in the directory where your files are.
* !filter !diff
*.gpg binary

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
.pass.sh filter=git-crypt diff=git-crypt

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.ansible-vaultpass

BIN
.pass.sh Executable file

Binary file not shown.

44
Makefile Normal file
View File

@@ -0,0 +1,44 @@
all: lint
# Default to all ansible tags to run (passed via 'make deploy TAGS=sometag')
TAGS?=all
PASS_SRC=./.pass.sh
# Setup Definitions
VENV=.venv
VENV_BIN=.venv/bin
PIP=${VENV_BIN}/pip
ANSIBLE=${VENV_BIN}/ansible-playbook
ANSIBLE_VAULT=${VENV_BIN}/ansible-vault
LINT_ANSIBLE=${VENV_BIN}/ansible-lint
LINT_YAML=${VENV_BIN}/yamllint
VAULT_PASS_FILE=.ansible-vaultpass
# Variables
ANSIBLE_INVENTORY=ansible/inventories/home/hosts.yml
SSH_KEY=${HOME}/.ssh/id_rsa_home_ansible
${VENV}:
virtualenv -p python3 ${VENV}
${PIP}: ${VENV}
${ANSIBLE} ${ANSIBLE_VAULT} ${LINT_YAML} ${LINT_ANSIBLE}: ${VENV} requirements.txt
${PIP} install -r requirements.txt
touch $@
${VAULT_PASS_FILE}: ${ANSIBLE}
. ${PASS_SRC}; pass $$PASS_LOC > $@
# Targets
deploy: ${ANSIBLE} ${VAULT_PASS_FILE}
${ANSIBLE} --diff --private-key ${SSH_KEY} -t ${TAGS} -i ${ANSIBLE_INVENTORY} --vault-password-file ${VAULT_PASS_FILE} ansible/deploy.yml
check: ${ANSIBLE} ${VAULT_PASS_FILE}
${ANSIBLE} --check --diff --private-key ${SSH_KEY} -t ${TAGS} -i ${ANSIBLE_INVENTORY} --vault-password-file ${VAULT_PASS_FILE} ansible/deploy.yml
encrypt-string: ${ANSIBLE_VAULT} ${VAULT_PASS_FILE}
${ANSIBLE_VAULT} encrypt_string --vault-password-file ${VAULT_PASS_FILE}
lint: ${LINT_YAML} ${LINT_ANSIBLE}
@${LINT_YAML} ansible/
@${LINT_ANSIBLE} ansible/

11
ansible.cfg Normal file
View File

@@ -0,0 +1,11 @@
[defaults]
callback_whitelist = profile_tasks
# Do not gather facts by default
gathering = explicit
# Hide warnings about discovered Python interpreter
interpreter_python = auto_silent
[ssh_connection]
pipelining = true

2
ansible/deploy.yml Normal file
View File

@@ -0,0 +1,2 @@
---
- import_playbook: deploy_home.yml

5
ansible/deploy_home.yml Normal file
View File

@@ -0,0 +1,5 @@
---
- hosts: all
roles:
- role: common
- role: http

View File

@@ -0,0 +1,5 @@
---
all:
hosts:
home.bdebyl.net:
ansible_user: ansible

View File

@@ -0,0 +1,10 @@
---
deps: [
docker,
fail2ban
]
fail2ban_jails: [
sshd.local,
nginx.local
]

View File

@@ -0,0 +1,20 @@
[nginx-limit-req]
enabled = true
port = http,https
findtime = 600
bantime = 1w
maxretry = 8
[nginx-http-auth]
enabled = true
port = http,https
logpath = %(nginx_error_log)s
bantime = 2w
maxretry = 5
[nginx-botsearch]
enabled = true
port = http,https
logpath = %(nginx_error_log)s
bantime = 1w
maxretry = 5

View File

@@ -0,0 +1,10 @@
[sshd]
enabled = true
filter = sshd
banaction = iptables
backend = systemd
maxretry = 5
findtime = 1d
bantime = 2w
ignoreip = 127.0.0.1/8 192.168.1.0/24
logpath = %(sshd_log)s

View File

@@ -0,0 +1,12 @@
---
- name: restart_sshd
become: true
service:
name: sshd
state: restarted
- name: restart_fail2ban
become: true
service:
name: fail2ban
state: restarted

View File

@@ -0,0 +1,7 @@
---
- name: install common dependencies
become: true
pacman:
name: "{{ deps }}"
state: present
tags: deps

View File

@@ -0,0 +1,3 @@
---
- import_tasks: deps.yml
- import_tasks: security.yml

View File

@@ -0,0 +1,31 @@
---
- name: ensure sshd disallows passwords
become: true
lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.re }}"
line: "{{ item.li }}"
with_items:
- {re: '^[# ]*PasswordAuthentication ', li: 'PasswordAuthentication no'}
- {re: '^[# ]*PermitEmptyPasswords ', li: 'PermitEmptyPasswords no'}
- {re: '^[# ]*PermitRootLogin ', li: 'PermitRootLogin no'}
notify: restart_sshd
tags: security
- name: setup fail2ban jails
become: true
copy:
src: files/fail2ban/jails/{{ item }}
dest: /etc/fail2ban/jail.d/{{ item }}
with_items: "{{ fail2ban_jails }}"
notify: restart_fail2ban
tags: security
- name: adjust fail2ban sshd filter
become: true
lineinfile:
path: /etc/fail2ban/filter.d/sshd.conf
regexp: '^[#]*filter ='
line: 'filter = sshd[mode=extra]'
notify: restart_fail2ban
tags: security

View File

@@ -0,0 +1,3 @@
---
dependencies:
- role: http

View File

@@ -0,0 +1,17 @@
---
- name: Create Drone CI container
community.general.docker_container:
name: drone
image: drone/drone
restart: true
restart_policy: on-failure
restart_retries: 3
env:
DRONE_GITHUB_CLIENT_ID: {{ drone_gh_client_id }}
DRONE_GITHUB_CLIENT_SECRET: {{ drone_gh_client_sec }}
DRONE_RPC_SECRET: {{ drone_rpc_secret }}
DRONE_SERVER_HOST: {{ ci_server_name }}
DRONE_SERVER_PROTO: {{ drone_server_proto }}
DRONE_GIT_ALWAYS_AUTH: 'true'
DRONE_USER_FILTER: {{ drone_user_filter }}

View File

@@ -0,0 +1,2 @@
---
- import_tasks: docker.yml

View File

@@ -0,0 +1,9 @@
---
ci_server_email: bastian@bdebyl.net
ci_server_name: ci.bdebyl.net
deps: [
certbot,
certbot-nginx,
nginx
]

View File

@@ -0,0 +1,36 @@
user http;
worker_processes 1;
error_log /var/log/nginx/error.log;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
gzip on;
gzip_disable "mise6";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google-analytics.com; img-src 'self' data: https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; font-src 'self'; frame-src 'none'; object-src 'none'";
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
include etc/nginx/sites-enabled/*.conf;
}

View File

@@ -0,0 +1,6 @@
---
- name: restart_nginx
become: true
service:
name: nginx
state: restarted

View File

@@ -0,0 +1,3 @@
---
dependencies:
- role: common

View File

@@ -0,0 +1,10 @@
---
- cron: renew certbot ssl certificate weekly
cron:
name: ci_bdebyl_net_renewal
special_time: weekly
job: |
certbot --renew certonly --webroot --webroot-path=/srv/http \
-m {{ ci_server_email }} --agree-tos \
-d {{ ci_server_name }}
tags: never

View File

@@ -0,0 +1,7 @@
---
- name: install http dependencies
become: true
pacman:
name: "{{ deps }}"
state: present
tags: deps

View File

@@ -0,0 +1,56 @@
---
- name: setup nginx base configuration
become: true
copy:
src: files/nginx/nginx.conf
dest: /etc/nginx/nginx.conf
notify: restart_nginx
tags: http
- name: setup nginx directories
become: true
file:
path: "/etc/nginx/{{ item }}"
state: directory
with_items:
- sites-enabled
- sites-available
tags: http
- name: chown http user home
become: true
file:
path: /srv/http
owner: http
group: http
recurse: true
tags: http
- name: touch nginx logs, enable jail
become: true
file:
path: "/var/log/nginx/error.log"
state: file
notify: restart_fail2ban
tags: http, security
- name: template nginx http sites-available
become: true
template:
src: "templates/nginx/sites/{{ item }}.j2"
dest: "/etc/nginx/sites-available/{{ item }}"
with_items:
- "{{ ci_server_name }}.http.conf"
notify: restart_nginx
tags: http
- name: enable desired nginx http sites
become: true
file:
src: "/etc/nginx/sites-available/{{ item }}"
dest: "/etc/nginx/sites-enabled/{{ item }}"
state: link
with_items:
- "{{ ci_server_name }}.http.conf"
notify: restart_nginx
tags: http

View File

@@ -0,0 +1,4 @@
---
- import_tasks: deps.yml
- import_tasks: http.yml
- import_tasks: ssl.yml

View File

@@ -0,0 +1,59 @@
---
- name: flush existing nginx https enabled sites
become: true
file:
path: "/etc/nginx/sites-enabled/{{ item }}"
state: absent
with_items:
- "{{ ci_server_name }}.https.conf"
notify: restart_nginx
tags: ssl
- meta: flush_handlers
tags: ssl
- name: generate openssl dhparam for nginx
become: true
command: |
openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 2048
args:
creates: /etc/ssl/certs/dhparam.pem
tags: ssl
- name: create ssl certificate for ci server
become: true
command: |
certbot certonly --webroot --webroot-path=/srv/http \
-m {{ ci_server_email }} --agree-tos \
-d {{ ci_server_name }}
args:
creates: "/etc/letsencrypt/live/{{ ci_server_name }}"
tags: ssl
- name: check if certbot certificate was created
become: true
stat:
path: "/etc/letsencrypt/live/{{ ci_server_name }}"
register: stat_result
tags: ssl
- name: template nginx https sites-available
become: true
template:
src: "templates/nginx/sites/{{ item }}.j2"
dest: "/etc/nginx/sites-available/{{ item }}"
with_items:
- "{{ ci_server_name }}.https.conf"
tags: ssl
- name: enable desired nginx https sites
become: true
file:
src: "/etc/nginx/sites-available/{{ item }}"
dest: "/etc/nginx/sites-enabled/{{ item }}"
state: link
with_items:
- "{{ ci_server_name }}.https.conf"
notify: restart_nginx
when: stat_result.stat.exists
tags: ssl

View File

@@ -0,0 +1,14 @@
server {
listen 80;
listen [::]:80;
server_name {{ ci_server_name }};
location /.well-known {
root /srv/http;
try_files $uri $uri/ =404;
}
location / {
return 301 https://$host$request_uri;
}
}

View File

@@ -0,0 +1,35 @@
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name {{ ci_server_name }};
add_header Strict-Transport-Security max-age=6307200;
ssl_certificate /etc/letsencrypt/live/{{ ci_server_name }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ ci_server_name }}/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/{{ ci_server_name }}/fullchain.pem;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_post;
proxy_pass http://127.0.0.1:4242;
proxy_redirect off;
proxy_http_version 1.1;
proxy_buffering off;
chunked_transfer_encoding off;
}
}

3
requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
ansible-lint==4.3.5
ansible==2.9.13
yamllint==1.24.2