Repository: emissary-ingress/emissary

Issue:
Users need SSL support
At minimum, they need to be able to specify a cert for the listener, and whether to use SSL to the back end.


Discussion:

Resolving patch:
diff --git a/ambassador/ambassador.py b/ambassador/ambassador.py
--- a/ambassador/ambassador.py
+++ b/ambassador/ambassador.py
@@ -15,7 +15,7 @@
 
 import VERSION
 
-from envoy import EnvoyStats, EnvoyConfig
+from envoy import EnvoyStats, EnvoyConfig, TLSConfig
 from utils import RichStatus, SystemInfo, DelayTrigger
 
 __version__ = VERSION.Version
@@ -196,17 +196,21 @@ def ambassador_stats():
 
     return jsonify(app.stats.stats)
 
-def new_config(envoy_base_config=None, envoy_config_path=None, envoy_restarter_pid=None):
+def new_config(envoy_base_config=None, envoy_tls_config=None,
+               envoy_config_path=None, envoy_restarter_pid=None):
     if not envoy_base_config:
         envoy_base_config = app.envoy_base_config
 
+    if not envoy_tls_config:
+        envoy_tls_config = app.envoy_tls_config
+
     if not envoy_config_path:
         envoy_config_path = app.envoy_config_path
 
     if not envoy_restarter_pid:
         envoy_restarter_pid = app.envoy_restarter_pid
 
-    config = EnvoyConfig(envoy_base_config)
+    config = EnvoyConfig(envoy_base_config, envoy_tls_config)
 
     rc = fetch_all_services()
     num_services = 0
@@ -273,6 +277,13 @@ def main():
 
     # Load the base config.
     app.envoy_base_config = json.load(open(app.envoy_template_path, "r"))
+
+    # Set up the TLS config stuff.
+    app.envoy_tls_config = TLSConfig(
+        "AMBASSADOR_CHAIN_PATH", "/etc/certs/fullchain.pem",
+        "AMBASSADOR_PRIVKEY_PATH", "/etc/certs/privkey.pem"
+    )
+
     app.stats = EnvoyStats()
 
     # Learn the PID of the restarter.
diff --git a/ambassador/envoy.py b/ambassador/envoy.py
--- a/ambassador/envoy.py
+++ b/ambassador/envoy.py
@@ -1,6 +1,7 @@
 import copy
 import json
 import logging
+import os
 import time
 
 import dpath
@@ -14,6 +15,33 @@ def percentage(x, y):
         return int(((x * 100) / y) + 0.5)
 
 
+class TLSConfig (object):
+    def __init__(self, chain_env, chain_default_path, privkey_env, privkey_default_path):
+        self.chain_path = os.environ.get(chain_env, chain_default_path)
+        self.privkey_path = os.environ.get(privkey_env, privkey_default_path)
+
+    def check_file(self, path):
+        found = False
+
+        try:
+            statinfo = os.stat(path)
+            found = True
+        except FileNotFoundError:
+            pass
+
+        return found
+
+    def config_block(self):
+        if (self.check_file(self.chain_path) and
+            self.check_file(self.privkey_path)):
+            return {
+                "cert_chain_file": self.chain_path,
+                "private_key_file": self.privkey_path
+            }
+        else:
+            return {}
+
+
 class EnvoyConfig (object):
     route_template = '''
     {{
@@ -73,9 +101,10 @@ class EnvoyConfig (object):
         }
     ]
 
-    def __init__(self, base_config):
+    def __init__(self, base_config, tls_config):
         self.services = {}
         self.base_config = base_config
+        self.tls_config = tls_config
 
     def add_service(self, name, prefix):
         self.services[name] = {
@@ -127,6 +156,21 @@ def write_config(self, path):
             clusters
         )
 
+        ssl_context = self.tls_config.config_block()
+
+        if ssl_context:
+            dpath.util.new(
+                config,
+                "/listeners/0/ssl_context",
+                ssl_context
+            )
+
+            dpath.util.set(
+                config,
+                "/listeners/0/address",
+                "tcp://0.0.0.0:443"
+            )
+
         output_file = open(path, "w")
 
         json.dump(config, output_file, 


Test patch: