~xenrox/ansible

769a658f0292885fb76d301b2386a53096248145 — Thorben Günther 1 year, 11 months ago bdb88be
hedgedoc: Markdown editor

Use as a substitution for bookstack. Bookstack does not support
PostgreSQL as a database, maintaining MariaDB just for one service is a
hassle. Furthermore hedgedoc does have an official package.
M playbooks/avalon.yml => playbooks/avalon.yml +1 -0
@@ 51,3 51,4 @@
    - { role: gotify_app }
    - { role: matrix }
    - { role: coturn }
    - { role: hedgedoc }

A roles/hedgedoc/files/hedgedoc.conf => roles/hedgedoc/files/hedgedoc.conf +40 -0
@@ 0,0 1,40 @@
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
    include /etc/nginx/snippets/http.conf;
    server_name hedgedoc.xenrox.net;
}

server {
    include /etc/nginx/snippets/https.conf;
    server_name hedgedoc.xenrox.net;

    location / {
        proxy_pass http://127.0.0.1:3002;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /socket.io/ {
        proxy_pass http://127.0.0.1:3002;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }

    location = /status {
        return 403;
    }

    location = /metrics {
        return 403;
    }
}

A roles/hedgedoc/handlers/main.yml => roles/hedgedoc/handlers/main.yml +5 -0
@@ 0,0 1,5 @@
---
- name: Restart hedgedoc
  ansible.builtin.systemd:
    name: hedgedoc
    state: restarted

A roles/hedgedoc/tasks/main.yml => roles/hedgedoc/tasks/main.yml +48 -0
@@ 0,0 1,48 @@
---
- name: Get secrets
  ansible.builtin.set_fact:
    hedgedoc_secrets: "{{ lookup('community.hashi_vault.hashi_vault', 'ansible/data/hedgedoc') }}"

- name: Install
  community.general.pacman:
    name: hedgedoc
    state: present

- name: Create db user
  community.general.postgresql_user:
    name: hedgedoc
    password: "{{ hedgedoc_secrets['psql_password'] }}"
  become: true
  become_user: postgres
  no_log: true

- name: Create db
  community.general.postgresql_db:
    db: hedgedoc
    owner: hedgedoc
  become: true
  become_user: postgres

- name: Configure
  ansible.builtin.template:
    src: config.json.j2
    dest: /etc/webapps/hedgedoc/config.json
    owner: hedgedoc
    group: hedgedoc
    mode: 0600
  notify: Restart hedgedoc

- name: Start and enable
  ansible.builtin.systemd:
    name: hedgedoc
    enabled: true
    state: started

- name: Copy nginx conf
  ansible.builtin.copy:
    src: hedgedoc.conf
    dest: /etc/nginx/nginx.d/hedgedoc.conf
    owner: root
    group: root
    mode: 0644
  notify: restart nginx

A roles/hedgedoc/templates/config.json.j2 => roles/hedgedoc/templates/config.json.j2 +61 -0
@@ 0,0 1,61 @@
{
  "production": {
    "domain": "hedgedoc.xenrox.net",
    "port": 3002,
    "loglevel": "info",
    "protocolUseSSL": true,
    "allowAnonymous": false,
    "allowAnonymousEdits": true,
    "defaultPermission": "private",
    "sessionSecret": "{{ hedgedoc_secrets['session_secret'] }}",
    "email": false,
    "hsts": {
      "enable": true,
      "maxAgeSeconds": 31536000,
      "includeSubdomains": true,
      "preload": true
    },
    "csp": {
      "enable": true,
      "directives": {},
      "upgradeInsecureRequests": "true",
      "addDefaults": true,
      "addDisqus": true,
      "addGoogleAnalytics": false,
      "allowFraming": false,
      "allowPDFEmbed": false
    },
    "cookiePolicy": "lax",
    "db": {
      "username": "hedgedoc",
      "password": "{{ hedgedoc_secrets['psql_password'] }}",
      "database": "hedgedoc",
      "host": "localhost",
      "port": "5432",
      "dialect": "postgres"
    },
    "oauth2": {
      "providerName": "Keycloak",
      "userProfileURL": "https://keycloak.xenrox.net/auth/realms/xenrox/protocol/openid-connect/userinfo",
      "userProfileUsernameAttr": "preferred_username",
      "userProfileDisplayNameAttr": "name",
      "userProfileEmailAttr": "email",
      "tokenURL": "https://keycloak.xenrox.net/auth/realms/xenrox/protocol/openid-connect/token",
      "authorizationURL": "https://keycloak.xenrox.net/auth/realms/xenrox/protocol/openid-connect/auth",
      "clientID": "openid_hedgedoc",
      "clientSecret": "{{ hedgedoc_secrets['oidc_secret'] }}",
      "scope": "openid profile email roles",
      "rolesClaim": "roles",
      "accessRole": "hedgedoc"
    },
    "minio": {
      "accessKey": "{{ hedgedoc_secrets['s3_access'] }}",
      "secretKey": "{{ hedgedoc_secrets['s3_secret'] }}",
      "endPoint": "minio.xenrox.net",
      "secure": true,
      "port": 443
    },
    "s3bucket": "hedgedoc",
    "imageUploadType": "minio"
  }
}

M terraform_hetzner/locals.tf => terraform_hetzner/locals.tf +1 -1
@@ 15,7 15,7 @@ locals {
    "rooms", "pubsub",

    # oidc
    "cloud", "grafana", "keycloak", "tube", "vault", "matrix",
    "cloud", "grafana", "keycloak", "tube", "vault", "matrix", "hedgedoc",

    # minio
    "minio", "tube.minio",

M terraform_keycloak/keycloak.tf => terraform_keycloak/keycloak.tf +46 -0
@@ 362,6 362,52 @@ resource "keycloak_group_roles" "matrix" {
  role_ids = [keycloak_role.matrix.id]
}

# Hedgedoc

data "vault_generic_secret" "hedgedoc" {
  path = "ansible/hedgedoc"
}

resource "keycloak_openid_client" "hedgedoc_openid_client" {
  realm_id      = "xenrox"
  client_id     = "openid_hedgedoc"
  client_secret = data.vault_generic_secret.hedgedoc.data["oidc_secret"]

  name                  = "Hedgedoc"
  enabled               = true
  standard_flow_enabled = true

  access_type = "CONFIDENTIAL"
  valid_redirect_uris = [
    "https://hedgedoc.xenrox.net/*"
  ]
}

resource "keycloak_openid_user_realm_role_protocol_mapper" "hedgedoc_user_realm_role_mapper" {
  realm_id    = "xenrox"
  client_id   = keycloak_openid_client.hedgedoc_openid_client.id
  name        = "user realm role mapper"
  claim_name  = "roles"
  multivalued = true
}

resource "keycloak_group" "hedgedoc" {
  realm_id = "xenrox"
  name     = "Hedgedoc"
}

resource "keycloak_role" "hedgedoc" {
  realm_id    = "xenrox"
  name        = "hedgedoc"
  description = "Hedgedoc user"
}

resource "keycloak_group_roles" "hedgedoc" {
  realm_id = "xenrox"
  group_id = keycloak_group.hedgedoc.id
  role_ids = [keycloak_role.hedgedoc.id]
}

# Bookstack

data "vault_generic_secret" "bookstack" {