From ddfe75225be2b79121fb3f0b5655f5051e31b666 Mon Sep 17 00:00:00 2001 From: Alpha Chen Date: Sat, 14 Dec 2019 21:51:19 -0800 Subject: [PATCH] [ansible] on-fire-within setup --- ansible/.gitignore | 2 + ansible/README.md | 26 +++++ ansible/ansible.cfg | 2 +- ansible/ddclient/Dockerfile | 22 ++++ ansible/on-fire-within/README.md | 16 +++ ansible/on-fire-within/hass-io.yml | 29 +++++ ansible/on-fire-within/main.yml | 166 +++++++++++++++++++++++++++++ ansible/playbooks/bootstrap.yml | 22 ---- ansible/playbooks/pi/bootstrap.yml | 44 ++++++++ ansible/playbooks/pi/security.yml | 44 ++++++++ 10 files changed, 350 insertions(+), 23 deletions(-) create mode 100644 ansible/.gitignore create mode 100644 ansible/README.md create mode 100644 ansible/ddclient/Dockerfile create mode 100644 ansible/on-fire-within/README.md create mode 100644 ansible/on-fire-within/hass-io.yml create mode 100644 ansible/on-fire-within/main.yml delete mode 100644 ansible/playbooks/bootstrap.yml create mode 100644 ansible/playbooks/pi/bootstrap.yml create mode 100644 ansible/playbooks/pi/security.yml diff --git a/ansible/.gitignore b/ansible/.gitignore new file mode 100644 index 0000000..fe75677 --- /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 0000000..362fa08 --- /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 37366f1..d2e82a1 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 0000000..44d5a1d --- /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 0000000..31c91bf --- /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 0000000..30070c1 --- /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 0000000..774ac07 --- /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 86d529a..0000000 --- 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 0000000..5b0b573 --- /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 0000000..76d1e31 --- /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