From cb6eb6723b60c08dbedb3632c0f2055cd3b0ee0f Mon Sep 17 00:00:00 2001
From: Markus Scheidgen <markus.scheidgen@gmail.com>
Date: Thu, 28 Mar 2019 13:43:17 +0100
Subject: [PATCH] Added support for https.

---
 nomad/api/app.py                             | 15 +++++++++++
 nomad/api/upload.py                          |  5 +---
 nomad/config.py                              | 11 +++++---
 nomad/processing/data.py                     |  2 +-
 ops/helm/nomad/templates/api-deployment.yaml | 28 +++++++++++++-------
 ops/helm/nomad/templates/nomad-configmap.yml |  1 +
 ops/helm/nomad/values.yaml                   |  4 ++-
 7 files changed, 47 insertions(+), 19 deletions(-)

diff --git a/nomad/api/app.py b/nomad/api/app.py
index 8eb1fe28db..b23bc69a19 100644
--- a/nomad/api/app.py
+++ b/nomad/api/app.py
@@ -31,6 +31,21 @@ from nomad import config, utils
 base_path = config.services.api_base_path
 """ Provides the root path of the nomad APIs. """
 
+
+@property
+def specs_url(self):
+    """
+    Fixes issue where swagger-ui makes a call to swagger.json over HTTP.
+    This can ONLY be used on servers that actually use HTTPS.  On servers that use HTTP,
+    this code should not be used at all.
+    """
+    return flask.url_for(self.endpoint('specs'), _external=True, _scheme='https')
+
+
+if config.services.https:
+    Api.specs_url = specs_url
+
+
 app = Flask(
     __name__,
     static_url_path='/docs',
diff --git a/nomad/api/upload.py b/nomad/api/upload.py
index acfa3a8c50..5348ab3fb6 100644
--- a/nomad/api/upload.py
+++ b/nomad/api/upload.py
@@ -392,10 +392,7 @@ class UploadCommandResource(Resource):
     @login_really_required
     def get(self):
         """ Get url and example command for shell based uploads. """
-        upload_url = 'http://%s:%s%s/uploads/' % (
-            config.services.api_host,
-            config.services.api_port,
-            config.services.api_base_path)
+        upload_url = '%s/uploads' % config.api_url()
 
         upload_command = 'curl -X PUT -H "X-Token: %s" "%s" -F file=@<local_file>' % (
             g.user.get_auth_token().decode('utf-8'), upload_url)
diff --git a/nomad/config.py b/nomad/config.py
index 2ff76cee40..6422bba105 100644
--- a/nomad/config.py
+++ b/nomad/config.py
@@ -108,7 +108,8 @@ services = NomadConfig(
     api_secret='defaultApiSecret',
     admin_password='password',
     disable_reset=True,
-    not_processed_value='not processed'
+    not_processed_value='not processed',
+    https=False
 )
 
 tests = NomadConfig(
@@ -116,8 +117,12 @@ tests = NomadConfig(
 )
 
 
-def upload_url():
-    return 'http://%s:%s/%s/uploads' % (services.api_host, services.api_port, services.api_base_path[:-3])
+def api_url():
+    return '%s://%s%s/%s' % (
+        'https' if services.https else 'http',
+        services.api_host,
+        ':%s' % services.api_port if services.api_port != 80 else '',
+        services.api_base_path)
 
 
 migration_source_db = NomadConfig(
diff --git a/nomad/processing/data.py b/nomad/processing/data.py
index 933c9b93d1..e3aafb994e 100644
--- a/nomad/processing/data.py
+++ b/nomad/processing/data.py
@@ -645,7 +645,7 @@ class Upload(Proc):
             '',
             'your data %suploaded %s has completed processing.' % (
                 self.name if self.name else '', self.upload_time.isoformat()),
-            'You can review your data on your upload page: %s' % config.upload_url()
+            'You can review your data on your upload page: %s/uploads' % config.api_url()[:-3]
         ])
         try:
             infrastructure.send_mail(
diff --git a/ops/helm/nomad/templates/api-deployment.yaml b/ops/helm/nomad/templates/api-deployment.yaml
index 1864cef8e3..8d0b59d3e0 100644
--- a/ops/helm/nomad/templates/api-deployment.yaml
+++ b/ops/helm/nomad/templates/api-deployment.yaml
@@ -8,45 +8,47 @@ metadata:
     app.kubernetes.io/instance: {{ .Release.Name }}
     app.kubernetes.io/managed-by: {{ .Release.Service }}
 data:
+  gunicorn.conf: |
+    secure_scheme_headers = {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
   gunicorn.log.conf: |
     [loggers]
     keys=root, gunicorn.error, gunicorn.access
-    
+
     [handlers]
     keys=console, access, error
-    
+
     [formatters]
     keys=generic
-    
+
     [logger_root]
     level=INFO
     handlers=console
-    
+
     [logger_gunicorn.error]
     level=INFO
     handlers=error
     qualname=gunicorn.error
-    
+
     [logger_gunicorn.access]
     level=INFO
     handlers=access
     qualname=gunicorn.access
-    
+
     [handler_console]
     class=StreamHandler
     formatter=generic
     args=(sys.stdout, )
-    
+
     [handler_access]
     class=StreamHandler
     formatter=generic
     args=(sys.stdout, )
-    
+
     [handler_error]
     class=StreamHandler
     formatter=generic
     args=(sys.stdout, )
-    
+
     [formatter_generic]
     format=%(asctime)s [%(process)d] [%(levelname)s] %(message)s
     datefmt=%Y-%m-%d %H:%M:%S
@@ -83,6 +85,9 @@ spec:
         - mountPath: /app/gunicorn.log.conf
           name: gunicorn-log-conf
           subPath: gunicorn.log.conf
+        - mountPath: /app/gunicorn.conf
+          name: gunicorn-conf
+          subPath: gunicorn.conf
         - mountPath: /app/.volumes/fs/public
           name: public-volume
         - mountPath: /app/.volumes/fs/staging
@@ -96,7 +101,7 @@ spec:
           value: "{{ .Values.api.console_loglevel }}"
         - name: NOMAD_LOGSTASH_LEVEL
           value: "{{ .Values.api.logstash_loglevel }}"
-        command: ["python", "-m", "gunicorn.app.wsgiapp", "--timeout", "3600", "--log-config", "gunicorn.log.conf", "-w", "{{ .Values.api.worker }}", "-b 0.0.0.0:8000", "nomad.api:app"]
+        command: ["python", "-m", "gunicorn.app.wsgiapp", "--timeout", "3600", "--config", "gunicorn.conf", "--log-config", "gunicorn.log.conf", "-w", "{{ .Values.api.worker }}", "-b 0.0.0.0:8000", "nomad.api:app"]
         livenessProbe:
           httpGet:
             path: "{{ .Values.proxy.external.path }}/api/alive"
@@ -118,6 +123,9 @@ spec:
       - name: gunicorn-log-conf
         configMap:
           name: {{ include "nomad.fullname" . }}-api-gunicorn-log-config
+      - name: gunicorn-conf
+        configMap:
+          name: {{ include "nomad.fullname" . }}-api-gunicorn-config
       - name: nomad-conf
         configMap:
           name: {{ include "nomad.fullname" . }}-configmap
diff --git a/ops/helm/nomad/templates/nomad-configmap.yml b/ops/helm/nomad/templates/nomad-configmap.yml
index 08775d10c4..445db2e3e8 100644
--- a/ops/helm/nomad/templates/nomad-configmap.yml
+++ b/ops/helm/nomad/templates/nomad-configmap.yml
@@ -24,6 +24,7 @@ data:
       api_secret: "{{ .Values.api.secret }}"
       admin_password: "{{ .Values.api.adminPassword }}"
       disable_reset: {{ .Values.api.disableReset }}
+      https: {{ .Values.api.https }}
     rabbitmq:
       host: "{{ .Release.Name }}-rabbitmq"
     elastic:
diff --git a/ops/helm/nomad/values.yaml b/ops/helm/nomad/values.yaml
index 9c3c9a802a..50ff57690f 100644
--- a/ops/helm/nomad/values.yaml
+++ b/ops/helm/nomad/values.yaml
@@ -27,9 +27,11 @@ images:
 ## Everthing concerning the nomad api
 api:
   replicas: 1
+  https: true
   ## Number of gunicorn worker. Recommendation is 2xnum_cores+1
   worker: 10
-  port: 8000
+  ## The external port to connect to the api
+  port: 80
   console_loglevel: INFO
   logstash_loglevel: INFO
   ## Secret used as cryptographic seed
-- 
GitLab