From adb93ecc5cbb899c2c9427a400240443eac95d6a Mon Sep 17 00:00:00 2001 From: Julien Palard Date: Thu, 20 Dec 2018 23:48:31 +0100 Subject: [PATCH] Ansible playbook to deploy pycon galleries. --- .gitignore | 8 +++ ansible.cfg | 2 + group_vars/all | 6 ++ inventory | 2 + playbook.yml | 4 ++ roles/common/tasks/common.yml | 60 +++++++++++++++++++ roles/common/tasks/main.yml | 4 ++ roles/gallery/defaults/main.yml | 7 +++ roles/gallery/handlers/main.yml | 4 ++ roles/gallery/meta/main.yml | 6 ++ roles/gallery/tasks/main.yml | 51 ++++++++++++++++ roles/gallery/templates/nginx-vhost | 33 ++++++++++ roles/letsencrypt/tasks/letsencrypt.yml | 56 +++++++++++++++++ roles/letsencrypt/tasks/main.yml | 4 ++ .../letsencrypt/templates/letsencrypt.conf.j2 | 19 ++++++ 15 files changed, 266 insertions(+) create mode 100644 .gitignore create mode 100644 ansible.cfg create mode 100644 group_vars/all create mode 100644 inventory create mode 100644 playbook.yml create mode 100644 roles/common/tasks/common.yml create mode 100644 roles/common/tasks/main.yml create mode 100644 roles/gallery/defaults/main.yml create mode 100644 roles/gallery/handlers/main.yml create mode 100644 roles/gallery/meta/main.yml create mode 100644 roles/gallery/tasks/main.yml create mode 100644 roles/gallery/templates/nginx-vhost create mode 100644 roles/letsencrypt/tasks/letsencrypt.yml create mode 100644 roles/letsencrypt/tasks/main.yml create mode 100644 roles/letsencrypt/templates/letsencrypt.conf.j2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..968c501 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ + +# Created by https://www.gitignore.io/api/ansible +# Edit at https://www.gitignore.io/?templates=ansible + +### Ansible ### +*.retry + +# End of https://www.gitignore.io/api/ansible diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..f8fc6cd --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,2 @@ +[defaults] +inventory = inventory diff --git a/group_vars/all b/group_vars/all new file mode 100644 index 0000000..a76c695 --- /dev/null +++ b/group_vars/all @@ -0,0 +1,6 @@ +--- + +ansible_python_interpreter: "/usr/bin/python3" +ansible_user: root +authorized_keys: + - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKA7DgTQ0G7+kdsX0lIUOAAOllwGSCu8s8TxPvr/61Y8q+pIO5mrZycI0xYcKP5NZaABqlFyXUUNfLj7RLqteBxqq2QZP4NOJ1MutYRIkzJ9YW0f565jHaOqSguz0MY+1sCHtuEPiUUZoNexkKN7SIx60SfoaMEvGjAj46txA7VFbJUuKcJtA1Yvmn0C0KoXUUQ/G+JqvjQ7QuKLQYdTZ8S9OEvNaqNfwNSwvy1/LCnuajFw0O+H5bz7AcS5Iuj+9k8wgHPK1a1rQEdteOcn2XBCvta/VOVlFLv6/9K3iU3EJ1pyaZ88UkuJef8aWnH/AJGaF2gLqUbBuL+UeXyD41 julien+yubikey@palard.fr" diff --git a/inventory b/inventory new file mode 100644 index 0000000..546480a --- /dev/null +++ b/inventory @@ -0,0 +1,2 @@ +[gallery] +163.172.45.2 diff --git a/playbook.yml b/playbook.yml new file mode 100644 index 0000000..38a8b0d --- /dev/null +++ b/playbook.yml @@ -0,0 +1,4 @@ +--- + +- hosts: gallery + roles: [common, gallery] diff --git a/roles/common/tasks/common.yml b/roles/common/tasks/common.yml new file mode 100644 index 0000000..549b76a --- /dev/null +++ b/roles/common/tasks/common.yml @@ -0,0 +1,60 @@ +--- + +- name: Remove /etc/apt/sources.list (May contain cdroms…) + file: + path: /etc/apt/sources.list + state: absent + +- name: Add stretch repositories + apt_repository: + repo: "{{ item }}" + state: present + with_items: + - "deb http://ftp.fr.debian.org/debian/ stretch main non-free contrib" + - "deb http://security.debian.org/ stretch/updates main contrib non-free" + - "deb http://ftp.fr.debian.org/debian stretch-backports main" + - "deb http://ftp.fr.debian.org/debian stretch-updates main" + +- name: Update via apt + apt: update_cache=yes + +- name: apt-get some packages + apt: + state: present + name: + - aptitude + - ntp + - rsync + - fail2ban + - emacs25-nox + - vim-nox + - htop + - ncdu + - tcpdump + - python3 + - python3-pip + - python3-dev + - python3-venv + - python3-setuptools + - python3-wheel + +- name: Set some authorized keys + authorized_key: user=root key="{{item}}" + with_items: "{{ authorized_keys }}" + +- name: Drop mlocate or locate + apt: + name: ["mlocate", "locate"] + state: absent + +- name: Drop all Python packages installed globall (Please use venvs) + file: + path: "/usr/local/lib/python{{ item }}" + state: absent + with_items: + - 2.7 + - 3.3 + - 3.4 + - 3.5 + - 3.6 + - 3.7 diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml new file mode 100644 index 0000000..29664e0 --- /dev/null +++ b/roles/common/tasks/main.yml @@ -0,0 +1,4 @@ +--- + +- include: common.yml + tags: common diff --git a/roles/gallery/defaults/main.yml b/roles/gallery/defaults/main.yml new file mode 100644 index 0000000..1169c12 --- /dev/null +++ b/roles/gallery/defaults/main.yml @@ -0,0 +1,7 @@ +--- + +gallery_user: gallery +gallery_https: false +gallery_domain: paullaroid.pycon.fr +gallery_repo: https://github.com/AFPy/pycon-fr-gallery.git +gallery_home: /srv/gallery/ diff --git a/roles/gallery/handlers/main.yml b/roles/gallery/handlers/main.yml new file mode 100644 index 0000000..bcf145d --- /dev/null +++ b/roles/gallery/handlers/main.yml @@ -0,0 +1,4 @@ +--- + +- name: reload nginx + service: name=nginx state=reloaded diff --git a/roles/gallery/meta/main.yml b/roles/gallery/meta/main.yml new file mode 100644 index 0000000..ed7a4c8 --- /dev/null +++ b/roles/gallery/meta/main.yml @@ -0,0 +1,6 @@ +--- + +dependencies: + - role: letsencrypt + when: gallery_https + domains: "{{ gallery_domain }}" diff --git a/roles/gallery/tasks/main.yml b/roles/gallery/tasks/main.yml new file mode 100644 index 0000000..0b092cd --- /dev/null +++ b/roles/gallery/tasks/main.yml @@ -0,0 +1,51 @@ +--- + +- name: Install nginx + apt: + name: [nginx, git, python3, python3-venv] + state: present + +- name: Gallery user + user: + name: "{{ gallery_user }}" + shell: /bin/false + system: yes + home: "{{ gallery_home }}" + +- name: Clone gallery repo + git: + repo: "{{ gallery_repo }}" + dest: "{{ gallery_home }}/repo" + register: clone_repo + +- name: pip install sigal + pip: + name: sigal + virtualenv_command: /usr/bin/python3 -m venv + virtualenv: "{{ gallery_home }}/venv" + +- name: Ensure sigal can write in its output dir + file: + path: "{{ gallery_home }}/repo/_build/" + state: directory + owner: "{{ gallery_user }}" + mode: 0755 + +- name: Build gallery + when: clone_repo.changed + command: "{{ gallery_home }}/venv/bin/sigal build" + args: + chdir: "{{ gallery_home }}/repo" + become: true + become_method: su + become_user: "{{ gallery_user }}" + become_flags: "-s /bin/sh" + +- name: Configure nginx + template: + src: nginx-vhost + dest: "/etc/nginx/conf.d/{{ gallery_domain }}.conf" + owner: root + group: root + mode: 0644 + notify: reload nginx diff --git a/roles/gallery/templates/nginx-vhost b/roles/gallery/templates/nginx-vhost new file mode 100644 index 0000000..dd1f307 --- /dev/null +++ b/roles/gallery/templates/nginx-vhost @@ -0,0 +1,33 @@ +{% if gallery_https %} +server { + listen 80; + server_name {{ gallery_domain }}; + + location / { + return 301 https://{{ gallery_domain }}$request_uri; + } +} + +server +{ + listen 443 ssl; + server_name {{ gallery_domain }}; + + include snippets/letsencrypt-{{ gallery_domain }}.conf; + + location / { + root {{ gallery_home }}/repo/_build/; + try_files $uri $uri/ =404; + } +} +{% else %} +server { + listen 80; + server_name {{ gallery_domain }}; + + location / { + root {{ gallery_home }}/repo/_build/; + try_files $uri $uri/ =404; + } +} +{% endif %} diff --git a/roles/letsencrypt/tasks/letsencrypt.yml b/roles/letsencrypt/tasks/letsencrypt.yml new file mode 100644 index 0000000..5f877d2 --- /dev/null +++ b/roles/letsencrypt/tasks/letsencrypt.yml @@ -0,0 +1,56 @@ +--- + +- name: Install certbot + apt: + state: present + default_release: stretch-backports + name: + - certbot + - python-certbot-nginx + +- name: Create ssl dhparam + command: openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096 + args: + creates: /etc/ssl/certs/dhparam.pem + +- name: check if certificate exist + stat: + path: '/etc/letsencrypt/live/{{ item }}' + with_items: '{{ domains }}' + register: st + +- name: check if nginx is running + stat: + path: /var/run/nginx.pid + register: ng + +- name: create a new certificate + shell: 'certbot certonly --cert-name {{ item.item }} -n --agree-tos -d {{ item.item }} -m admin@meltygroup.com {{ ng.stat.exists | ternary("--nginx", "--standalone") }} --rsa-key-size 4096' + with_items: '{{ st.results }}' + when: not item.stat.exists + loop_control: + label: "{{ item.item }}" + +- name: Create letsencrypt snippets + template: + src: letsencrypt.conf.j2 + dest: '/etc/nginx/snippets/letsencrypt-{{ item.item }}.conf' + with_items: '{{ st.results }}' + loop_control: + label: "{{ item.item }}" + +- name: Choose installer-nginx for the cron to work properly + lineinfile: + path: "/etc/letsencrypt/renewal/{{ item }}.conf" + state: present + regexp: '^installer =' + line: 'installer = nginx' + with_items: '{{ domains }}' + +- name: Choose installer-nginx for the cron to work properly + lineinfile: + path: "/etc/letsencrypt/renewal/{{ item }}.conf" + state: present + regexp: '^authenticator =' + line: 'authenticator = nginx' + with_items: '{{ domains }}' diff --git a/roles/letsencrypt/tasks/main.yml b/roles/letsencrypt/tasks/main.yml new file mode 100644 index 0000000..9fd414a --- /dev/null +++ b/roles/letsencrypt/tasks/main.yml @@ -0,0 +1,4 @@ +--- + +- include: letsencrypt.yml + tags: letsencrypt diff --git a/roles/letsencrypt/templates/letsencrypt.conf.j2 b/roles/letsencrypt/templates/letsencrypt.conf.j2 new file mode 100644 index 0000000..27ce251 --- /dev/null +++ b/roles/letsencrypt/templates/letsencrypt.conf.j2 @@ -0,0 +1,19 @@ +#https://wiki.openssl.org/index.php/Manual:Ciphers(1) + +# 2016-11 (afpy inspired) https://blog.imirhil.fr/2015/09/02/cryptcheck-verifiez-implementations-tls.html +ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:AES256+EECDH:AES256+EDH"; +ssl_protocols TLSv1.1 TLSv1.2; + + +ssl_prefer_server_ciphers on; +ssl_session_cache shared:ssl_session_cache:10m; +ssl_certificate /etc/letsencrypt/live/{{ item.item }}/fullchain.pem; +ssl_certificate_key /etc/letsencrypt/live/{{ item.item }}/privkey.pem; +ssl_dhparam /etc/ssl/certs/dhparam.pem; + +# Uncomment to enable HSTS: +# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; + +# Uncomment to enable CSPs: +# add_header Content-Security-Policy upgrade-insecure-requests; +# add_header Content-Security-Policy block-all-mixed-content;