From fa8561f2a8819a99c5bbad8b7981252aa1da32ec Mon Sep 17 00:00:00 2001 From: Olivier Navas Date: Sun, 29 May 2022 12:20:38 +0200 Subject: [PATCH] Commit initial --- README.md | 101 ++++++++++++++++++++++++++++++ defaults/main.yml | 16 +++++ handlers/main.yml | 10 +++ tasks/configure_reverse_proxy.yml | 11 ++++ tasks/main.yml | 54 ++++++++++++++++ templates/.env.production | 76 ++++++++++++++++++++++ templates/0_vhost.conf | 2 + templates/1_vhost_additional.conf | 12 ++++ templates/2_mds_exclusion.conf | 4 ++ templates/docker-compose.yml | 95 ++++++++++++++++++++++++++++ 10 files changed, 381 insertions(+) create mode 100644 README.md create mode 100644 defaults/main.yml create mode 100644 handlers/main.yml create mode 100644 tasks/configure_reverse_proxy.yml create mode 100644 tasks/main.yml create mode 100644 templates/.env.production create mode 100644 templates/0_vhost.conf create mode 100644 templates/1_vhost_additional.conf create mode 100644 templates/2_mds_exclusion.conf create mode 100644 templates/docker-compose.yml diff --git a/README.md b/README.md new file mode 100644 index 0000000..2223f7d --- /dev/null +++ b/README.md @@ -0,0 +1,101 @@ +# Role : docker_mastodon + + +## Services fournis + +Installation d'un serveur mastodon sur serveur docker_host + + + +## Variables + +```yaml +docker_mastodon_fqdn: mastodon.example.com +docker_mastodon_data_dir: /data1 +docker_mastodon_service_id: mastodon +docker_mastodon_image_version: x.y.z +docker_mastodon_local_domain: example.com +docker_mastodon_db_name: mastodondb +docker_mastodon_db_user: user_proprietaire_bdd +docker_mastodon_db_password: mdp_proprietaire_bdd +docker_mastodon_secret_key_base: inserer_le_secret_key_base_voir_premiere_installation +docker_mastodon_otp_secret: inserer_ici_otp_secret_voir_premiere_installation +docker_mastodon_vapid_private_key: inserer_ici_vapid_private_key_voir_premiere_installation +docker_mastodon_vapid_public_key: inserer_ici_vapid_public_key_voir_premiere_installation +docker_mastodon_mail_smtp_server: smtp.example.com +docker_mastodon_mail_smtp_port: 587 +docker_mastodon_mail_from: nepasrepondre@example.com + +docker_mastodon_oidc_enabled: true +docker_mastodon_oidc_display_name: "Libretic" +docker_mastodon_oidc_issuer: https://login.example.com/auth/realms/example-space +docker_mastodon_oidc_discovery: true +docker_mastodon_oidc_scopes: "openid,profile" +docker_mastodon_oidc_uid_field: uid +docker_mastodon_oidc_client_id: masto-oidc +docker_mastodon_oidc_redirect_uri: https://mastodon.example.com/auth/auth/openid_connect/callback +docker_mastodon_oidc_security_assume_email_is_verified: true +docker_mastodon_oidc_client_secret: oidc_client_secret + +docker_mastodon_rp_cert: LE +docker_mastodon_rp_docker_host: machine.domaine.local +docker_mastodon_rp_access_policy: OpenAccessPolicy +docker_mastodon_rp_indexing: Empty +docker_mastodon_rp_waf: "On" +``` + +| Option | Valeur par défaut | Description | +|--------------------------------------------------------|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| +| docker_mastodon_fqdn | | Nom de domaine pour lequel le service mastodon répond | +| docker_mastodon_data_dir | | L'emplacement dans lequel se trouvent les volumes de donnees docker pour le service | +| docker_mastodon_service_id | | Le nom de service souhaité : conditionne le nommage des volumes et le routage par traefik | +| docker_mastodon_image_version | | Version de mastodon et de l'image docker | +| docker_mastodon_local_domain | | Domaine des utilisateurs permettant l'emploi d'adresses mastodon de la forme @user@domain (nécessite la mise en place de webfinger sur le domaine) | +| docker_mastodon_db_name | | Nom de la base de données | +| docker_mastodon_db_user | | Nom du proprietaire_de la base | +| docker_mastodon_db_password | | MDP du proprietaire_de la base | +| docker_mastodon_secret_key_base | | Valeur de secret_key_base généré pour la première installation | +| docker_mastodon_otp_secret | | Valeur de otp_secret généré pour la première installation | +| docker_mastodon_vapid_private_key | | Valeur de vapid_private_key généré pour la première installation | +| docker_mastodon_vapid_public_key | | Valeur de vapid_public_key généré pour la première installation | +| docker_mastodon_mail_smtp_server | | Serveur smtp par lequel mastodon envoie des emails | +| docker_mastodon_mail_smtp_port | 587 | Port d'envoi des emails | +| docker_mastodon_mail_smtp_login | vide | | +| docker_mastodon_mail_smtp_password | vide | | +| docker_mastodon_mail_from | | Adresse d'expéditeur par laquelle mastodon envoie des emails | +| docker_mastodon_oidc_enabled | false | Permet d'activer l'authentification par OpenID Connect | +| docker_mastodon_oidc_display_name | | Nom affiché pour la connection via OpenID Connect | +| docker_mastodon_oidc_issuer | | Url "issuer" de la fédération OpenID Connect | +| docker_mastodon_oidc_discovery | true | | +| docker_mastodon_oidc_scopes | openid,profile | Scopes récupérés via OpenID Connect | +| docker_mastodon_oidc_uid_field | uid | Attribut utilisé pour constituer l'identifiant Mastodon | +| docker_mastodon_oidc_client_id | | Identifiant de client OpenID Connect de l'instance | +| docker_mastodon_oidc_client_secret | | Secret de client OpenID Connect de l'instance | +| docker_mastodon_oidc_redirect_uri | cf. defaults | Url de redirection après une connection via OpenID Connect | +| docker_mastodon_oidc_security_assume_email_is_verified | true | Indique à mastodon qu'il n'est pas nécessaire de valilder l'adresse email pour un utilisateur OpenID Connect | +| docker_mastodon_rp_docker_host | | Pour configure_reverse_proxy.yml: fqdn de la machine contenant le conteneur docker | +| docker_mastodon_rp_cert | LE | Type de certificat pour le reverse proxy (LE = letsencrypt) | +| docker_mastodon_rp_access_policy | | Modèle d'autorisation d'accès du reverse proxy | +| docker_mastodon_rp_indexing | | Stratégie du reverse proxy vis à vis des robots | +| docker_mastodon_rp_waf | | Activation websecurity du reverse proxy | + + + +## Première installation + + +- provisionner l'environnement une première fois en positionnant la variable docker_mastodon_gen_secrets à true ; le playbook va générer des valeurs à copier/coller dans les variables de playbook de l'environnement + + ansible-playbook -i inventory/vms -i inventory/mastodon setup_mastodon.yml -e "docker_mastodon_gen_secrets=true" + +- pour le premier démarrage uniquement, lancer le playbook avec la variable `docker_mastodon_docker_mastodon_initialize_data` positionnée à `true` ; attention, cela efface les données et initialise une instance de mastodon vide + + ansible-playbook -i inventory/vms -i inventory/mastodon setup_mastodon.yml -e "docker_mastodon_docker_mastodon_initialize_data=true" + +- enregistrer un premier utilisateur (éventuellement via une connexion OpenID Connect) +- lui donner le droit administrateur + + docker exec -it mastodon_streaming_1 /bin/bash + mastodon@76beca2b858d:~$ RAILS_ENV=production bin/tootctl accounts modify --role admin + + diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..88e111e --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,16 @@ +docker_mastodon_rp_cert: LE + +docker_mastodon_mail_smtp_port: 587 +docker_mastodon_mail_smtp_login: "" +docker_mastodon_mail_smtp_password: "" + +docker_mastodon_oidc_enabled: "false" +docker_mastodon_oidc_discovery: "true" +docker_mastodon_oidc_scopes: "openid,profile" +docker_mastodon_oidc_uid_field: uid +docker_mastodon_oidc_security_assume_email_is_verified: "true" +docker_mastodon_oidc_redirect_uri: https://{{ docker_mastodon_fqdn }}/auth/auth/openid_connect/callback + + +docker_mastodon_gen_secrets: false +docker_mastodon_initialize_data: false diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..73eea88 --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,10 @@ +- name: docker-compose-up + shell: | + docker-compose up -d + args: + chdir: /opt/{{ docker_mastodon_service_id }}/ + +- name: reverse-proxy-reload + service: + name: apache2 + state: reloaded diff --git a/tasks/configure_reverse_proxy.yml b/tasks/configure_reverse_proxy.yml new file mode 100644 index 0000000..9f0ef64 --- /dev/null +++ b/tasks/configure_reverse_proxy.yml @@ -0,0 +1,11 @@ +- name: prepare reverse_proxy + template: + src: "{{ item }}" + dest: /etc/apache2/vhosts.d/{{ docker_mastodon_fqdn }}/ + with_items: + - 0_vhost.conf + - 1_vhost_additional.conf + - 2_mds_exclusion.conf + notify: reverse-proxy-reload + + diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..8ed4fcf --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,54 @@ +- name: docker directory + file: + path: /opt/{{ docker_mastodon_service_id }}/ + state: directory + +- name: prepare docker-compose.yml + template: + src: "{{ item }}" + dest: /opt/{{ docker_mastodon_service_id }}/ + with_items: + - docker-compose.yml + - .env.production + + +- name: generate secrets + when: docker_mastodon_gen_secrets is true + block: + + - name: docker-compose-gen-secrets + shell: | + docker-compose down + echo "Placer les valeurs suivantes dans les variables du playbook mastodon :" + echo SECRET_KEY_BASE=$(docker-compose run --rm web bundle exec rake secret) + echo OTP_SECRET=$(docker-compose run --rm web bundle exec rake secret) + docker-compose run --rm web bundle exec rake mastodon:webpush:generate_vapid_key + args: + chdir: /opt/{{ docker_mastodon_service_id }}/ + register: secrets + + - debug: + msg: "{{ secrets.stdout_lines }}" + +- name: Playbook stops here if docker_mastodon_gen_secrets is set + assert: + that: + - docker_mastodon_gen_secrets is false + +### initialize-data +- name: docker-compose-initialize-data + shell: | + docker-compose down + rm -rf "{{ docker_mastodon_data_dir }}/{{ docker_mastodon_service_id }}" + docker-compose run --rm web rails db:migrate + docker-compose run --rm web rails assets:precompile + docker-compose down + args: + chdir: /opt/{{ docker_mastodon_service_id }}/ + when: docker_mastodon_initialize_data is true + +- name: docker-compose-up + shell: | + docker-compose up -d + args: + chdir: /opt/{{ docker_mastodon_service_id }}/ diff --git a/templates/.env.production b/templates/.env.production new file mode 100644 index 0000000..cb6bbbe --- /dev/null +++ b/templates/.env.production @@ -0,0 +1,76 @@ +# {{ ansible_managed }} + +# Federation +# ---------- +# This identifies your server and cannot be changed safely later +# ---------- +LOCAL_DOMAIN={{ docker_mastodon_local_domain }} +WEB_DOMAIN={{ docker_mastodon_fqdn }} + +# Redis +# ----- +REDIS_HOST=redis +REDIS_PORT=6379 + +# PostgreSQL +# ---------- +DB_HOST=db +DB_USER={{ docker_mastodon_db_user }} +DB_NAME={{ docker_mastodon_db_name }} +DB_PASS={{ docker_mastodon_db_password }} +DB_PORT=5432 + +# Elasticsearch (optional) +# ------------------------ +ES_ENABLED=false +ES_HOST=localhost +ES_PORT=9200 +# Authentication for ES (optional) +ES_USER=elastic +ES_PASS=password + +# Secrets +# ------- +# Make sure to use `rake secret` to generate secrets +# ------- +SECRET_KEY_BASE={{ docker_mastodon_secret_key_base }} +OTP_SECRET={{ docker_mastodon_otp_secret }} + +# Web Push +# -------- +# Generate with `rake mastodon:webpush:generate_vapid_key` +# -------- +VAPID_PRIVATE_KEY={{ docker_mastodon_vapid_private_key }} +VAPID_PUBLIC_KEY={{ docker_mastodon_vapid_public_key }} + +# Sending mail +# ------------ +SMTP_SERVER={{ docker_mastodon_mail_smtp_server }} +SMTP_PORT={{ docker_mastodon_mail_smtp_port }} +SMTP_LOGIN={{ docker_mastodon_mail_smtp_login }} +SMTP_PASSWORD={{ docker_mastodon_mail_smtp_password }} +SMTP_FROM_ADDRESS={{ docker_mastodon_mail_from }} + +# File storage (optional) +# ----------------------- +S3_ENABLED=false +S3_BUCKET=files.example.com +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +S3_ALIAS_HOST=files.example.com + + +{% if docker_mastodon_oidc_enabled is true %} +# OpenID Connect configuration +# -------------------------- +OIDC_ENABLED={{ docker_mastodon_oidc_enabled }} +OIDC_DISPLAY_NAME={{ docker_mastodon_oidc_display_name }} +OIDC_ISSUER={{ docker_mastodon_oidc_issuer }} +OIDC_DISCOVERY={{ docker_mastodon_oidc_discovery }} +OIDC_SCOPE="{{ docker_mastodon_oidc_scopes }}" +OIDC_UID_FIELD={{ docker_mastodon_oidc_uid_field }} +OIDC_CLIENT_ID={{ docker_mastodon_oidc_client_id }} +OIDC_CLIENT_SECRET={{ docker_mastodon_oidc_client_secret }} +OIDC_REDIRECT_URI={{ docker_mastodon_oidc_redirect_uri }} +OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED={{ docker_mastodon_oidc_security_assume_email_is_verified }} +{% endif %} \ No newline at end of file diff --git a/templates/0_vhost.conf b/templates/0_vhost.conf new file mode 100644 index 0000000..1593212 --- /dev/null +++ b/templates/0_vhost.conf @@ -0,0 +1,2 @@ +# {{ ansible_managed }} +Use vhost_HTTPS_Generic {{ docker_mastodon_fqdn }} {{ docker_mastodon_rp_cert }} http {{ docker_mastodon_rp_docker_host }} info {{ docker_mastodon_rp_access_policy }} {{ docker_mastodon_rp_indexing }} {{ docker_mastodon_rp_waf }} diff --git a/templates/1_vhost_additional.conf b/templates/1_vhost_additional.conf new file mode 100644 index 0000000..3579009 --- /dev/null +++ b/templates/1_vhost_additional.conf @@ -0,0 +1,12 @@ +# {{ ansible_managed }} + +Header set Content-Security-Policy "default-src 'self' data:; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; object-src 'none'" + +# websockets + + ProxyPass ws://{{ docker_mastodon_rp_docker_host }} + + + +ProxyErrorOverride off + diff --git a/templates/2_mds_exclusion.conf b/templates/2_mds_exclusion.conf new file mode 100644 index 0000000..f3b8d04 --- /dev/null +++ b/templates/2_mds_exclusion.conf @@ -0,0 +1,4 @@ +# {{ ansible_managed }} + +SecRuleRemoveById 911100 +SecRuleRemoveById 949110 diff --git a/templates/docker-compose.yml b/templates/docker-compose.yml new file mode 100644 index 0000000..ef239c0 --- /dev/null +++ b/templates/docker-compose.yml @@ -0,0 +1,95 @@ +# {{ ansible_managed }} +version: '3' +services: + db: + restart: always + image: postgres:14 + shm_size: 256mb + networks: + - mastodon + healthcheck: + test: ['CMD', 'pg_isready', '-U', 'postgres'] + volumes: + - {{ docker_mastodon_data_dir }}/{{ docker_mastodon_service_id }}/db_data:/var/lib/postgresql/data + environment: + POSTGRES_DB: "{{ docker_mastodon_db_name }}" + POSTGRES_USER: "{{ docker_mastodon_db_user }}" + POSTGRES_PASSWORD: "{{ docker_mastodon_db_password }}" + + redis: + restart: always + image: redis:6-alpine + networks: + - mastodon + healthcheck: + test: ['CMD', 'redis-cli', 'ping'] + volumes: + - {{ docker_mastodon_data_dir }}/{{ docker_mastodon_service_id }}/redis_data:/data + + web: + image: tootsuite/mastodon:{{ docker_mastodon_image_version }} + restart: always + env_file: .env.production + command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000" + networks: + - traefik + - mastodon + healthcheck: + # prettier-ignore + test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:3000/health || exit 1'] + depends_on: + - db + - redis + volumes: + - {{ docker_mastodon_data_dir }}/{{ docker_mastodon_service_id }}/mastodon_public_system:/mastodon/public/system + labels: + - traefik.enable=true + - traefik.docker.network=traefik + - traefik.http.routers.{{ docker_mastodon_service_id }}.entrypoints=web + - traefik.http.routers.{{ docker_mastodon_service_id }}.rule=Host(`{{ docker_mastodon_fqdn }}`) + - traefik.http.services.{{ docker_mastodon_service_id }}.loadbalancer.server.port=3000 + + + streaming: + image: tootsuite/mastodon:{{ docker_mastodon_image_version }} + restart: always + env_file: .env.production + command: node ./streaming + networks: + - traefik + - mastodon + healthcheck: + # prettier-ignore + test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:4000/api/v1/streaming/health || exit 1'] + labels: + - traefik.enable=true + - traefik.docker.network=traefik + - traefik.http.routers.{{ docker_mastodon_service_id }}-streaming.entrypoints=web + - traefik.http.routers.{{ docker_mastodon_service_id }}-streaming.rule=Host(`{{ docker_mastodon_fqdn }}`) && PathPrefix(`/api/v1/streaming`) + - traefik.http.services.{{ docker_mastodon_service_id }}-streaming.loadbalancer.server.port=4000 + depends_on: + - db + - redis + + sidekiq: + image: tootsuite/mastodon:{{ docker_mastodon_image_version }} + restart: always + env_file: .env.production + command: bundle exec sidekiq + depends_on: + - db + - redis + networks: + - traefik + - mastodon + volumes: + - {{ docker_mastodon_data_dir }}/{{ docker_mastodon_service_id }}/mastodon_public_system:/mastodon/public/system + healthcheck: + test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"] + + +networks: + traefik: + external: true + mastodon: + internal: true