diff options
author | Christian Pointner <equinox@spreadspace.org> | 2023-12-28 03:43:54 +0100 |
---|---|---|
committer | Christian Pointner <equinox@spreadspace.org> | 2023-12-28 03:43:54 +0100 |
commit | c51bc2b05c810db3a4c42353b97799733709106c (patch) | |
tree | bd405cb865d74da27ecfa8244b15a6452c3a7ce1 | |
parent | add apps/upstream role (diff) |
apps/node-red: 80% done but still (WIP)
-rw-r--r-- | chaos-at-home/ch-apps.yml | 1 | ||||
-rw-r--r-- | files/chaos-at-home/bind-zones/db.chaos-at-home.org | 4 | ||||
-rw-r--r-- | inventory/group_vars/appspublishzone-chaos-at-home/vars.yml | 1 | ||||
-rw-r--r-- | inventory/host_vars/ch-apps/node-red.yml | 50 | ||||
-rw-r--r-- | roles/apps/node-red/instance/tasks/main.yml | 126 | ||||
-rw-r--r-- | roles/apps/node-red/instance/templates/pod-spec.yml.j2 | 4 | ||||
-rw-r--r-- | roles/apps/publish/base/defaults/main.yml | 1 | ||||
-rw-r--r-- | roles/apps/publish/base/filter_plugins/publish.py | 9 | ||||
-rw-r--r-- | roles/apps/publish/base/tasks/main.yml | 1 |
9 files changed, 192 insertions, 5 deletions
diff --git a/chaos-at-home/ch-apps.yml b/chaos-at-home/ch-apps.yml index 2fe70485..447e9b0f 100644 --- a/chaos-at-home/ch-apps.yml +++ b/chaos-at-home/ch-apps.yml @@ -18,3 +18,4 @@ - role: monitoring/prometheus/exporter - role: kubernetes/base - role: kubernetes/standalone/base + - role: apps/node-red diff --git a/files/chaos-at-home/bind-zones/db.chaos-at-home.org b/files/chaos-at-home/bind-zones/db.chaos-at-home.org index a27f0c1d..ed9d541f 100644 --- a/files/chaos-at-home/bind-zones/db.chaos-at-home.org +++ b/files/chaos-at-home/bind-zones/db.chaos-at-home.org @@ -2,7 +2,7 @@ $origin chaos-at-home.org. $TTL 1h @ SOA ns0 hostmaster ( - 2023111200 + 2023122800 1h 15m 30d @@ -60,6 +60,7 @@ magenta.web cNAME magenta.router magenta.mail CNAME magenta.router magenta.passwd CNAME magenta.router magenta.login CNAME magenta.router +magenta.node-red CNAME magenta.router router 600 CNAME magenta.router jump 600 CNAME magenta.jump @@ -67,6 +68,7 @@ web 600 CNAME magenta.web mail 600 CNAME magenta.mail passwd 600 CNAME magenta.passwd login 600 CNAME magenta.login +node-red 600 CNAME magenta.node-red imap CNAME mail webmail CNAME web diff --git a/inventory/group_vars/appspublishzone-chaos-at-home/vars.yml b/inventory/group_vars/appspublishzone-chaos-at-home/vars.yml index 761b3937..03209554 100644 --- a/inventory/group_vars/appspublishzone-chaos-at-home/vars.yml +++ b/inventory/group_vars/appspublishzone-chaos-at-home/vars.yml @@ -36,6 +36,7 @@ chaos_at_home_apps_publish_ca_cert: | apps_publish_zone__chaos_at_home: name: chaos-at-home + publisher: ch-http-proxy certificate_provider: static-ca certificate_ca_config: cert_content: "{{ chaos_at_home_apps_publish_ca_cert }}" diff --git a/inventory/host_vars/ch-apps/node-red.yml b/inventory/host_vars/ch-apps/node-red.yml index c84d151c..157043d1 100644 --- a/inventory/host_vars/ch-apps/node-red.yml +++ b/inventory/host_vars/ch-apps/node-red.yml @@ -16,3 +16,53 @@ node_red_instances: extended_key_usage_critical: yes create_subject_key_identifier: yes not_after: +100w + publish: + zone: "{{ apps_publish_zone__chaos_at_home }}" + hostnames: + - node-red.chaos-at-home.org + tls: + certificate_provider: acmetool + certificate_config: + request: + challenge: + http-self-test: false + vhost_extra_directives: | + include snippets/whawty-sso-chaos-at-home.conf; + + location = /healthz { + auth_request off; + return 200; + } + location_extra_directives: | + auth_request_set $username $upstream_http_x_username; + proxy_set_header X-Username $username; + proxy_set_header Authorization ""; + custom_image: + dockerfile: | + RUN npm install passport-trusted-header + extra_settings: | + adminAuth: { + type: "strategy", + strategy: { + name: "trusted-header", + label: "SSO login", + autoLogin: true, + strategy: require("passport-trusted-header").Strategy, + options: { + headers: ['x-username'], + verify: function(requestHeaders, done) { + var username = requestHeaders['x-username'] + if(username === '') { + done("x-username HTTP-Header is empty", null) + } + done(null, { username: username }); + } + }, + }, + users: [ + { username: "equinox", permissions: ["*"] } + ], + default: { + permissions: "read" + } + } diff --git a/roles/apps/node-red/instance/tasks/main.yml b/roles/apps/node-red/instance/tasks/main.yml index ec9b9dff..3533ab09 100644 --- a/roles/apps/node-red/instance/tasks/main.yml +++ b/roles/apps/node-red/instance/tasks/main.yml @@ -16,7 +16,7 @@ owner: 1000 mode: 0700 -- name: generate/install/fetch TLS certificate +- name: generate/install/fetch TLS certificates for mqtt when: "'mqtt_tls' in node_red_instances[node_red_instance]" vars: x509_certificate_name: "node-red-{{ node_red_instance }}_mqtt" @@ -45,6 +45,85 @@ include_role: name: "x509/{{ node_red_instances[node_red_instance].mqtt_tls.certificate_provider }}/cert" +- name: generate/install TLS certificates for publishment + vars: + x509_certificate_name: "node-red-{{ node_red_instance }}_publish" + x509_certificate_hostnames: [] + x509_certificate_config: + ca: "{{ node_red_instances[node_red_instance].publish.zone.certificate_ca_config }}" + cert: + common_name: "node-red-{{ node_red_instance }}" + extended_key_usage: + - serverAuth + extended_key_usage_critical: yes + create_subject_key_identifier: yes + not_after: +100w + x509_certificate_renewal: + install: + - dest: "{{ node_red_instance_basepath }}/tls/publish-crt.pem" + src: + - fullchain + owner: root + group: 1000 + mode: "0644" + - dest: "{{ node_red_instance_basepath }}/tls/publish-key.pem" + src: + - key + owner: root + group: 1000 + mode: "0640" + - dest: "{{ node_red_instance_basepath }}/tls/publish-ca-crt.pem" + src: + - ca_cert + owner: root + group: 1000 + mode: "0644" + include_role: + name: "x509/{{ node_red_instances[node_red_instance].publish.zone.certificate_provider }}/cert" + +- name: build custom image + when: "'custom_image' in node_red_instances[node_red_instance]" + block: + - name: create build directory for custom image + file: + path: "{{ node_red_instance_basepath }}/build" + state: directory + + - name: generate Dockerfile for custom image + copy: + content: | + FROM {{ node_red_instances[node_red_instance].custom_image.from | default('nodered/node-red:' + node_red_instances[node_red_instance].version + '-debian') }} + + {{ node_red_instances[node_red_instance].custom_image.dockerfile }} + dest: "{{ node_red_instance_basepath }}/build/Dockerfile" + register: node_red_custom_image_docker + + - name: build custom image + docker_image: + name: "nodered/node-red/{{ node_red_instance }}:{{ node_red_instances[node_red_instance].version }}-debian" + state: present + force_source: "{{ node_red_custom_image_docker is changed }}" + source: build + build: + path: "{{ node_red_instance_basepath }}/build" + network: host + pull: yes + +## TODO: settings.js: +# +# module.exports = { +# credentialSecret: "geheim", +# https: { +# key: require("fs").readFileSync('/tls/publish-key.pem'), +# cert: require("fs").readFileSync('/tls/publish-crt.pem'), +# ca: require("fs").readFileSync('/tls/publish-ca-crt.pem'), +# requestCert: true, +# minVersion: 'TLSv1.3' +# }, +# {{ node_red_instances[node_red_instance].extra_settings }} +# } +# + - name: install pod manifest vars: kubernetes_standalone_pod: @@ -52,3 +131,48 @@ spec: "{{ lookup('template', 'pod-spec.yml.j2') }}" include_role: name: kubernetes/standalone/pod + +- name: configure nginx vhost for publishment + vars: + nginx_vhost__yaml: | + {% if node_red_instances[node_red_instance].publish.zone.publisher == inventory_hostname %} + name: "node-red-{{ node_red_instance }}" + {% else %} + name: "node-red-{{ node_red_instance }}-{{ inventory_hostname }}" + {% endif %} + template: generic + {% if 'tls' in node_red_instances[node_red_instance].publish %} + tls: + {{ node_red_instances[node_red_instance].publish.tls | to_nice_yaml(indent=2) | indent(2) }} + {% endif %} + hostnames: + {% for hostname in node_red_instances[node_red_instance].publish.hostnames %} + - {{ hostname }} + {% endfor %} + locations: + '/': + {% if node_red_instances[node_red_instance].publish.zone.publisher == inventory_hostname %} + proxy_pass: "https://127.0.0.1:{{ node_red_instances[node_red_instance].port }}" + {% else %} + proxy_pass: "https://{{ ansible_default_ipv4.address }}:{{ node_red_instances[node_red_instance].port }}" + {% endif %} + proxy_ssl: + certificate: "/etc/ssl/apps-publish-{{ node_red_instances[node_red_instance].publish.zone.name }}/apps-publish-{{ node_red_instances[node_red_instance].publish.zone.name }}-crt.pem" + certificate_key: "/etc/ssl/apps-publish-{{ node_red_instances[node_red_instance].publish.zone.name }}/apps-publish-{{ node_red_instances[node_red_instance].publish.zone.name }}-key.pem" + trusted_certificate: "/etc/ssl/apps-publish-{{ node_red_instances[node_red_instance].publish.zone.name }}/apps-publish-{{ node_red_instances[node_red_instance].publish.zone.name }}-ca-crt.pem" + verify: "on" + name: "node-red-{{ node_red_instance }}" + protocols: "TLSv1.3" + {% if 'location_extra_directives' in node_red_instances[node_red_instance].publish %} + extra_directives: | + {{ node_red_instances[node_red_instance].publish.location_extra_directives | indent(6) }} + {% endif %} + {% if 'vhost_extra_directives' in node_red_instances[node_red_instance].publish %} + extra_directives: | + {{ node_red_instances[node_red_instance].publish.vhost_extra_directives | indent(2) }} + {% endif %} + nginx_vhost: "{{ nginx_vhost__yaml | from_yaml }}" + include_role: + name: nginx/vhost + apply: + delegate_to: "{{ node_red_instances[node_red_instance].publish.zone.publisher }}" diff --git a/roles/apps/node-red/instance/templates/pod-spec.yml.j2 b/roles/apps/node-red/instance/templates/pod-spec.yml.j2 index 29f2161a..1e60c122 100644 --- a/roles/apps/node-red/instance/templates/pod-spec.yml.j2 +++ b/roles/apps/node-red/instance/templates/pod-spec.yml.j2 @@ -1,6 +1,10 @@ containers: - name: node-red +{% if 'custom_image' in node_red_instances[node_red_instance] %} + image: "nodered/node-red/{{ node_red_instance }}:{{ node_red_instances[node_red_instance].version }}-debian" +{% else %} image: "nodered/node-red:{{ node_red_instances[node_red_instance].version }}-debian" +{% endif %} volumeMounts: - name: tls mountPath: /tls diff --git a/roles/apps/publish/base/defaults/main.yml b/roles/apps/publish/base/defaults/main.yml index 5a01bc97..32e1af9f 100644 --- a/roles/apps/publish/base/defaults/main.yml +++ b/roles/apps/publish/base/defaults/main.yml @@ -1,5 +1,6 @@ --- # apps_publish_zone__example: # name: example +# publisher: invetory-hostname-of-publishing-machine # certificate_provider: ... # certificate_ca_config: .... diff --git a/roles/apps/publish/base/filter_plugins/publish.py b/roles/apps/publish/base/filter_plugins/publish.py index e0e1463d..4052df20 100644 --- a/roles/apps/publish/base/filter_plugins/publish.py +++ b/roles/apps/publish/base/filter_plugins/publish.py @@ -9,9 +9,12 @@ from ansible import errors def apps_publish_zones(vars): try: result = [] - for var in vars.keys(): - if var.startswith('apps_publish_zone__'): - result.append(vars[var]) + thishost = vars['inventory_hostname'] + for varname in vars.keys(): + if varname.startswith('apps_publish_zone__'): + zone = vars[varname] + if zone['publisher'] == thishost: + result.append(zone) return result except Exception as e: raise errors.AnsibleFilterError("apps_publish_zones(): %s" % str(e)) diff --git a/roles/apps/publish/base/tasks/main.yml b/roles/apps/publish/base/tasks/main.yml index 9384b53f..1eb3ddca 100644 --- a/roles/apps/publish/base/tasks/main.yml +++ b/roles/apps/publish/base/tasks/main.yml @@ -19,3 +19,4 @@ - nginx include_role: name: "x509/{{ item.certificate_provider }}/cert" + allow_duplicates: yes |