[ansible] on-fire-within setup
diff --git a/ansible/.gitignore b/ansible/.gitignore
new file mode 100644
index 00000000..fe756772
--- /dev/null
+++ b/ansible/.gitignore
@@ -0,0 +1,2 @@
+hosts.yml
+host_vars
diff --git a/ansible/README.md b/ansible/README.md
new file mode 100644
index 00000000..362fa086
--- /dev/null
+++ b/ansible/README.md
@@ -0,0 +1,26 @@
+# ansible
+
+## Raspberry Pi
+
+1. [Download Raspberian Stretch Lite](https://www.raspberrypi.org/downloads/raspbian/)
+1. Install Etcher: `brew cask install balenaetcher`
+1. [Flash the SD card](https://www.raspberrypi.org/documentation/installation/installing-images/README.md)
+
+1. [Enable SSH](https://www.raspberrypi.org/documentation/remote-access/ssh/)
+
+1. Run the Ansible playbooks
+ 1. Add the host to the `pi_bootstrap` group and set the `password` variable
+ on the host
+ 1. Connect to the host via SSH (so Ansible can piggyback off the existing
+ connection and not have to deal with password shenanigans)
+ 1. `ansible-playbook playbooks/pi/bootstrap.yml`
+ 1. `ansible-playbook {{ host }}/main.yml`
+
+### etc
+
+1. Use `raspi-config` to set up the WiFi
+ - [Additional setup](https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md)
+ - Add `scan_ssid=1` to `/etc/wpa_supplicant/wpa_supplicant.conf`
+ - Restart WiFi: `wpa_cli -i wlan0 reconfigure`
+1. Use `raspi-config` to set the keyboard layout
+
diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg
index 37366f16..d2e82a16 100644
--- a/ansible/ansible.cfg
+++ b/ansible/ansible.cfg
@@ -1,5 +1,5 @@
[defaults]
-inventory = hosts.private
+inventory = hosts.yml
retry_files_enabled = False
pipelining = True
host_key_checking = False
diff --git a/ansible/ddclient/Dockerfile b/ansible/ddclient/Dockerfile
new file mode 100644
index 00000000..44d5a1da
--- /dev/null
+++ b/ansible/ddclient/Dockerfile
@@ -0,0 +1,22 @@
+FROM armhf/alpine
+
+# https://wiki.alpinelinux.org/wiki/Ddclient
+
+RUN apk update && apk upgrade && \
+ apk add \
+ curl \
+ make \
+ perl \
+ perl-io-socket-ssl
+RUN cpan install Test::Requires && cpan Data::Validate::IP
+
+RUN cd tmp && \
+ curl --location https://github.com/ddclient/ddclient/archive/v3.9.0.tar.gz > ddclient-3.9.0.tar.gz && \
+ tar xvz < ddclient-3.9.0.tar.gz && \
+ cp ddclient-3.9.0/ddclient /usr/sbin && \
+ mkdir /etc/ddclient && \
+ mkdir -p /var/cache/ddclient
+
+VOLUME /etc/ddclient
+
+ENTRYPOINT [ "ddclient", "-foreground" ]
diff --git a/ansible/on-fire-within/README.md b/ansible/on-fire-within/README.md
new file mode 100644
index 00000000..31c91bf0
--- /dev/null
+++ b/ansible/on-fire-within/README.md
@@ -0,0 +1,16 @@
+# On Fire Within
+
+## Setup
+
+- [Installing Hass.io](https://www.home-assistant.io/hassio/installation/)
+
+1. `ansible-playbook playbooks/pi/bootstrap.yml`
+1. `ansible-playbook on-fire-within/bootstrap.yml`
+1. `curl -fsSL get.docker.com | sh`
+ - `sudo usermod -aG docker alpha`
+1. `curl -sL "https://raw.githubusercontent.com/home-assistant/hassio-installer/master/hassio_install.sh" | bash -s -- -m raspberrypi4`
+1. `ansible-playbook on-fire-within/main.yml`
+
+## Notes
+
+- `/usr/share/hassio`
diff --git a/ansible/on-fire-within/hass-io.yml b/ansible/on-fire-within/hass-io.yml
new file mode 100644
index 00000000..30070c19
--- /dev/null
+++ b/ansible/on-fire-within/hass-io.yml
@@ -0,0 +1,29 @@
+# https://www.home-assistant.io/hassio/installation/
+
+- hosts: on_fire_within
+ become: yes
+ tasks:
+ # Forgot what I need this for...
+ - name: install software-properties-common
+ apt: name=software-properties-common
+
+ - name: install other dependencies for hass.io
+ apt:
+ name:
+ - apparmor-utils
+ - apt-transport-https
+ - avahi-daemon
+ - ca-certificates
+ - curl
+ - dbus
+ - jq
+ - network-manager
+ - socat
+ update_cache: yes
+ - service:
+ name: ModemManager
+ enabled: false
+
+ # homekit
+ - name: install dependenies for homekit
+ apt: name=libavahi-compat-libdnssd-dev
diff --git a/ansible/on-fire-within/main.yml b/ansible/on-fire-within/main.yml
new file mode 100644
index 00000000..774ac079
--- /dev/null
+++ b/ansible/on-fire-within/main.yml
@@ -0,0 +1,166 @@
+- import_playbook: ../playbooks/pi/security.yml
+- import_playbook: hass-io.yml
+
+- hosts: on_fire_within
+ become: yes
+ tasks:
+ - name: install dependencies
+ apt:
+ name:
+ - git
+ - vim
+
+ # Needed for Docker stuff
+ - docker-compose
+ - python-pip
+ - python-backports-shutil-get-terminal-size
+ - python-backports.ssl-match-hostname
+
+ - name: install python docker packages
+ pip:
+ name:
+ - docker
+ - docker-compose
+ state: latest
+
+ - name: create conf dirs
+ file:
+ path: "{{ item }}"
+ state: directory
+ with_items:
+ - /etc/ddclient
+ - /etc/traefik
+
+ - name: configure ddclient
+ copy:
+ content: |
+ daemon=300
+
+ use=web
+ ssl=yes
+ protocol=googledomains
+
+ {% for host in hosts %}
+ login={{ host.login }}, password={{ host.password }} {{ host.host }}
+ {% endfor %}
+ dest: /etc/ddclient/ddclient.conf
+ mode: 0600
+ vars:
+ hosts: "{{ ddclient.hosts }}"
+ notify: restart ddclient
+
+ - name: traefik static configuration
+ copy:
+ content: |
+ [providers]
+ [providers.docker]
+ exposedByDefault = false
+ [providers.file]
+ filename = "/etc/traefik/dynamic_conf.toml"
+ watch = true
+
+ [entryPoints]
+ [entryPoints.http]
+ address = ":80"
+
+ [entryPoints.https]
+ address = ":443"
+
+ [certificatesResolvers.le.acme]
+ email = "{{ email }}"
+ storage = "/etc/traefik/acme.json"
+ [certificatesResolvers.le.acme.httpChallenge]
+ entryPoint = "http"
+
+ [api]
+ insecure = true
+ dest: /etc/traefik/traefik.toml
+ mode: 0600
+
+ - name: docker all the things!
+ docker_compose:
+ project_name: on-fire-within
+ definition:
+ version: '2'
+ services:
+ ddclient:
+ image: kejadlen/ddclient:latest
+ container_name: ddclient
+ volumes:
+ - /etc/ddclient:/etc/ddclient
+ restart: always
+ pihole:
+ image: pihole/pihole:latest
+ container_name: pihole
+ ports:
+ - 53:53/tcp
+ - 53:53/udp
+ environment:
+ TZ: America/Los_Angeles
+ VIRTUAL_HOST: "{{ pihole.host }}"
+ WEBPASSWORD: "{{ pihole.password }}"
+ volumes:
+ - /etc/pihole:/etc/pihole
+ - /etc/dnsmasq.d:/etc/dnsmasq.d
+ dns:
+ - 127.0.0.1
+ - 1.1.1.1
+ labels:
+ - traefik.enable=true
+ - traefik.http.routers.pihole.rule=Host(`{{ traefik.host_rules.pihole }}`)
+ - traefik.http.routers.pihole.tls=true
+ - traefik.http.routers.pihole.tls.certresolver=le
+ - traefik.http.services.pihole.loadbalancer.server.port=80
+ restart: always
+ traefik:
+ image: traefik:latest
+ container_name: traefik
+ ports:
+ - 80:80
+ - 8080:8080
+ - 443:443
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+ - /etc/traefik:/etc/traefik
+ labels:
+ - traefik.enable=true
+ - traefik.http.middlewares.auth.basicauth.users=alpha:{{ traefik.password | password_hash("md5") | replace("$", "$$") }}
+ - traefik.http.routers.traefik.rule=Host(`{{ traefik.host_rules.traefik }}`)
+ - traefik.http.routers.traefik.tls=true
+ - traefik.http.routers.traefik.tls.certresolver=le
+ - traefik.http.routers.traefik.middlewares=auth
+ - traefik.http.routers.traefik.service=api@internal
+ restart: always
+
+ - name: get docker ip
+ block:
+ # - shell: ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+' | head -n 1
+ - shell: docker network inspect on-fire-within_default | jq --raw-output .[0].IPAM.Config[0].Gateway
+ register: docker_ip_result
+ - set_fact:
+ docker_ip: "{{ docker_ip_result.stdout | trim }}"
+
+ - name: traefik dynamic configuration
+ copy:
+ content: |
+ [http.routers]
+ [http.routers.hassio]
+ rule = "Host(`{{ traefik.host_rules.hassio }}`)"
+ service = "hassio"
+ [http.routers.hassio.tls]
+ certResolver = "le"
+
+ [http.services]
+ [http.services.hassio.loadBalancer]
+ [[http.services.hassio.loadBalancer.servers]]
+ url = "http://{{ docker_ip }}:8123/"
+ dest: /etc/traefik/dynamic_conf.toml
+ mode: 0600
+
+ handlers:
+ - name: restart ddclient
+ docker_container:
+ name: ddclient
+ restart: yes
+ ignore_errors: yes
+
diff --git a/ansible/playbooks/bootstrap.yml b/ansible/playbooks/bootstrap.yml
deleted file mode 100644
index 86d529a1..00000000
--- a/ansible/playbooks/bootstrap.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-- hosts: linux
- become: yes
- tasks:
-
- - name: create user
- user:
- name: alpha
- password: "{{ password | password_hash('sha512') }}"
- shell: /bin/bash
-
- - name: give user sudo access
- lineinfile:
- path: /etc/sudoers.d/alpha
- line: "alpha ALL=(ALL) NOPASSWD: ALL"
- create: yes
- validate: visudo -cf %s
-
- - name: add ssh keys
- authorized_key:
- user: alpha
- key: https://github.com/kejadlen.keys
-
diff --git a/ansible/playbooks/pi/bootstrap.yml b/ansible/playbooks/pi/bootstrap.yml
new file mode 100644
index 00000000..5b0b5739
--- /dev/null
+++ b/ansible/playbooks/pi/bootstrap.yml
@@ -0,0 +1,44 @@
+- hosts: pi_bootstrap
+ become: yes
+ tasks:
+
+ - name: change hostname to {{ hostname }}
+ hostname:
+ name: "{{ hostname }}"
+ notify: reboot
+
+ - name: update hostname in /etc/hosts
+ replace:
+ path: /etc/hosts
+ regexp: '(\s+)raspberrypi(\s+.*)?$'
+ replace: '\1{{ hostname }}\2'
+ notify: reboot
+
+ - name: disable wifi
+ lineinfile:
+ path: /boot/config.txt
+ insertafter: dtoverlay
+ line: dtoverlay=pi3-disable-wifi
+ notify: reboot
+
+ - name: create user
+ user:
+ name: alpha
+ password: "{{ password | password_hash('sha512') }}"
+ shell: /bin/bash
+
+ - name: give user sudo access
+ lineinfile:
+ path: /etc/sudoers.d/alpha
+ line: "alpha ALL=(ALL) NOPASSWD: ALL"
+ create: yes
+ validate: visudo -cf %s
+
+ - name: add ssh keys
+ authorized_key:
+ user: alpha
+ key: https://github.com/kejadlen.keys
+
+ handlers:
+ - name: reboot
+ reboot:
diff --git a/ansible/playbooks/pi/security.yml b/ansible/playbooks/pi/security.yml
new file mode 100644
index 00000000..76d1e31e
--- /dev/null
+++ b/ansible/playbooks/pi/security.yml
@@ -0,0 +1,44 @@
+# https://www.raspberrypi.org/documentation/configuration/security.md
+
+- hosts: pi
+ become: yes
+ tasks:
+ - name: disable ssh password logins
+ lineinfile:
+ path: /etc/ssh/sshd_config
+ regexp: '^(#\s*)?{{ item }} '
+ line: "{{ item }} no"
+ notify: reload ssh
+ with_items:
+ - ChallengeResponseAuthentication
+ - PasswordAuthentication
+ - UsePAM
+
+ - name: disable pi user
+ user:
+ name: pi
+ password: !
+
+ - name: install fail2ban
+ package:
+ name: fail2ban
+ state: present
+
+ - name: create jail.local
+ copy:
+ content: |
+ [sshd]
+ enabled = true
+ dest: /etc/fail2ban/jail.local
+ notify: reload fail2ban
+
+ handlers:
+ - name: reload ssh
+ service:
+ name: ssh
+ state: reloaded
+
+ - name: reload fail2ban
+ service:
+ name: fail2ban
+ state: reloaded