Merge branch 'develop' into DLAB-1594-2
diff --git a/infrastructure-provisioning/scripts/deploy_dlab.py b/infrastructure-provisioning/scripts/deploy_dlab.py
index 40b1485..df9fb06 100644
--- a/infrastructure-provisioning/scripts/deploy_dlab.py
+++ b/infrastructure-provisioning/scripts/deploy_dlab.py
@@ -143,6 +143,13 @@
 parser.add_argument('--conf_stepcerts_kid', type=str, default='', help='Step KID')
 parser.add_argument('--conf_stepcerts_kid_password', type=str, default='', help='Step KID password')
 parser.add_argument('--conf_stepcerts_ca_url', type=str, default='', help='Step CA URL')
+parser.add_argument('--conf_letsencrypt_enabled', type=str, default='false', help='Enable or disable Let`s Encrypt certificates')
+parser.add_argument('--conf_letsencrypt_domain_name', type=str, default='', help='Domain names to apply. '
+                         'For multiple domains enter a comma separated list of domains as a parameter'
+                         'ssn.domain_name will be used for ssn_node, DNS A record have to exist during deployment')
+parser.add_argument('--conf_letsencrypt_email', type=str, default='', help='Email that will be entered during '
+                         'certificate obtaining and can be user for urgent renewal and security notices. '
+                         'Use comma to register multiple emails, e.g. u1@example.com,u2@example.com.')
 parser.add_argument('--action', required=True, type=str, default='', choices=['build', 'deploy', 'create', 'terminate'],
                     help='Available options: build, deploy, create, terminate')
 args = parser.parse_args()
diff --git a/infrastructure-provisioning/src/general/conf/dlab.ini b/infrastructure-provisioning/src/general/conf/dlab.ini
index 597b260..e11158e 100644
--- a/infrastructure-provisioning/src/general/conf/dlab.ini
+++ b/infrastructure-provisioning/src/general/conf/dlab.ini
@@ -77,6 +77,12 @@
 # stepcerts_kid_password =
 ### Step certificates CA URL
 # stepcerts_ca_url =
+### Enable or disable Lets Encrypt certificates
+letsencrypt_enabled = false
+### Domain names to apply
+# letsencrypt_domain_name =
+### email address to use
+# letsencrypt_email =
 ### Prefix of the private subnet
 private_subnet_prefix = 24
 ### Range of subnets defined by user
diff --git a/infrastructure-provisioning/src/general/lib/os/debian/common_lib.py b/infrastructure-provisioning/src/general/lib/os/debian/common_lib.py
index a252cf2..296d9ab 100644
--- a/infrastructure-provisioning/src/general/lib/os/debian/common_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/debian/common_lib.py
@@ -164,3 +164,54 @@
             sudo('touch /home/{}/.ensure_dir/step_ensured'.format(user))
     except:
         sys.exit(1)
+
+def install_certbot(os_family):
+    try:
+        print('Installing Certbot')
+        if os_family == 'debian':
+            sudo('apt-get -y update')
+            sudo('apt-get -y install software-properties-common')
+            sudo('add-apt-repository -y universe')
+            sudo('add-apt-repository -y ppa:certbot/certbot')
+            sudo('apt-get -y update')
+            sudo('apt-get -y install certbot')
+        elif os_family == 'redhat':
+            print('This OS family is not supported yet')
+    except Exception as err:
+        traceback.print_exc()
+        print('Failed Certbot install: ' + str(err))
+        sys.exit(1)
+
+def run_certbot(domain_name, node, email=''):
+    try:
+        print('Running  Certbot')
+        sudo('service nginx stop')
+        if email != '':
+            sudo('certbot certonly --standalone -n -d {}.{} -m {}'.format(node, domain_name, email))
+        else:
+            sudo('certbot certonly --standalone -n -d {}.{} --register-unsafely-without-email --agree-tos'.format(node, domain_name))
+    except Exception as err:
+        traceback.print_exc()
+        print('Failed to run Certbot: ' + str(err))
+        sys.exit(1)
+
+def configure_nginx_LE(domain_name, node):
+    try:
+        server_name_line ='    server_name {}.{};'.format(node, domain_name)
+        cert_path_line = '    ssl_certificate  /etc/letsencrypt/live/{}.{}/fullchain.pem;'.format(node, domain_name)
+        cert_key_line = '    ssl_certificate_key /etc/letsencrypt/live/{}.{}/privkey.pem;'.format(node, domain_name)
+        certbot_service = "ExecStart = /usr/bin/certbot -q renew --pre-hook 'service nginx stop' --post-hook 'service nginx start'"
+        certbot_service_path = '/lib/systemd/system/certbot.service'
+        if node == 'ssn':
+            nginx_config_path = '/etc/nginx/conf.d/nginx_proxy.conf'
+        else:
+            nginx_config_path = '/etc/nginx/conf.d/proxy.conf'
+        sudo('sed -i "s|.*    server_name .*|{}|" {}'.format(server_name_line, nginx_config_path))
+        sudo('sed -i "s|.*    ssl_certificate .*|{}|" {}'.format(cert_path_line, nginx_config_path))
+        sudo('sed -i "s|.*    ssl_certificate_key .*|{}|" {}'.format(cert_key_line, nginx_config_path))
+        sudo('sed -i "s|.*ExecStart.*|{}|" {}'.format(certbot_service, certbot_service_path))
+        sudo('systemctl restart nginx')
+    except Exception as err:
+        traceback.print_exc()
+        print('Failed to run Certbot: ' + str(err))
+        sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/lib/os/debian/edge_lib.py b/infrastructure-provisioning/src/general/lib/os/debian/edge_lib.py
index 958a53c..836fd64 100644
--- a/infrastructure-provisioning/src/general/lib/os/debian/edge_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/debian/edge_lib.py
@@ -26,6 +26,9 @@
 from fabric.api import *
 from fabric.contrib.files import exists
 from dlab.common_lib import manage_pkg
+from dlab.common_lib import install_certbot
+from dlab.common_lib import run_certbot
+from dlab.common_lib import configure_nginx_LE
 
 
 def configure_http_proxy_server(config):
@@ -149,6 +152,14 @@
             sudo('mkdir /usr/local/openresty/nginx/conf/locations')
             sudo('systemctl start openresty')
             sudo('touch /tmp/nginx_installed')
+            if os.environ['conf_letsencrypt_enabled'] == 'true':
+                print("Configuring letsencrypt certificates.")
+                install_certbot(os.environ['conf_os_family'])
+                if 'conf_letsencrypt_email' in os.environ:
+                    run_certbot(os.environ['conf_letsencrypt_domain_name'], os.environ['project_name'], os.environ['conf_letsencrypt_email'])
+                else:
+                    run_certbot(os.environ['conf_letsencrypt_domain_name'], os.environ['project_name'])
+                configure_nginx_LE(os.environ['conf_letsencrypt_domain_name'], os.environ['project_name'])
     except Exception as err:
         print("Failed install nginx with ldap: " + str(err))
         sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/lib/os/debian/ssn_lib.py b/infrastructure-provisioning/src/general/lib/os/debian/ssn_lib.py
index af0cdae..0c38603 100644
--- a/infrastructure-provisioning/src/general/lib/os/debian/ssn_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/debian/ssn_lib.py
@@ -173,7 +173,6 @@
         print('Failed to install MongoDB: ', str(err))
         sys.exit(1)
 
-
 def start_ss(keyfile, host_string, dlab_conf_dir, web_path,
              os_user, mongo_passwd, keystore_passwd, cloud_provider,
              service_base_name, tag_resource_id, billing_tag, account_id, billing_bucket,
diff --git a/infrastructure-provisioning/src/general/lib/os/redhat/common_lib.py b/infrastructure-provisioning/src/general/lib/os/redhat/common_lib.py
index ea5d4f2..7047633 100644
--- a/infrastructure-provisioning/src/general/lib/os/redhat/common_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/redhat/common_lib.py
@@ -140,3 +140,29 @@
             sudo('touch /home/{}/.ensure_dir/step_ensured'.format(user))
     except:
         sys.exit(1)
+
+def install_certbot(os_family):
+    try:
+        print('Installing Certbot')
+        print('Redhat is not supported yet. Skipping....')
+    except Exception as err:
+        traceback.print_exc()
+        print('Failed Certbot install: ' + str(err))
+        sys.exit(1)
+
+def run_certbot(domain_name, email=''):
+    try:
+        print('Running  Certbot')
+        print('Redhat is not supported yet. Skipping....')
+    except Exception as err:
+        traceback.print_exc()
+        print('Failed to run Certbot: ' + str(err))
+        sys.exit(1)
+
+def configure_nginx_LE(domain_name):
+    try:
+        print('Redhat is not supported yet. Skipping....')
+    except Exception as err:
+        traceback.print_exc()
+        print('Failed to run Certbot: ' + str(err))
+        sys.exit(1)
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/general/lib/os/redhat/edge_lib.py b/infrastructure-provisioning/src/general/lib/os/redhat/edge_lib.py
index 8dde808..3ee832e 100644
--- a/infrastructure-provisioning/src/general/lib/os/redhat/edge_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/redhat/edge_lib.py
@@ -111,6 +111,8 @@
                 sudo('systemctl daemon-reload')
                 sudo('systemctl enable step-cert-manager.service')
             else:
+                if os.environ['conf_letsencrypt_enabled'] == 'true':
+                    print('Lets Encrypt certificates are not supported for redhat in dlab. Using self signed certificates')
                 sudo('openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/ssl/certs/dlab.key \
                      -out /etc/ssl/certs/dlab.crt -subj "/C=US/ST=US/L=US/O=dlab/CN={}"'.format(hostname))
             sudo('mkdir -p /tmp/lua')
diff --git a/infrastructure-provisioning/src/general/lib/os/redhat/ssn_lib.py b/infrastructure-provisioning/src/general/lib/os/redhat/ssn_lib.py
index ddda21f..a0022da 100644
--- a/infrastructure-provisioning/src/general/lib/os/redhat/ssn_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/redhat/ssn_lib.py
@@ -356,6 +356,8 @@
                     sudo('keytool -importcert -trustcacerts -alias ssn -file /etc/ssl/certs/dlab.crt -noprompt '
                          '-storepass changeit -keystore {0}/lib/security/cacerts'.format(java_path))
                 else:
+                    if os.environ['conf_letsencrypt_enabled'] == 'true':
+                        print('Lets Encrypt certificates are not supported for redhat in dlab. Using self signed certificates')
                     sudo('keytool -genkeypair -alias ssn -keyalg RSA -validity 730 -storepass {1} -keypass {1} \
                          -keystore /home/{0}/keys/ssn.keystore.jks -keysize 2048 -dname "CN=localhost"'.format(
                         os_user, keystore_passwd))
diff --git a/infrastructure-provisioning/src/general/scripts/aws/ssn_configure.py b/infrastructure-provisioning/src/general/scripts/aws/ssn_configure.py
index bb8c555..759c417 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/ssn_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/ssn_configure.py
@@ -456,6 +456,62 @@
                     'key': 'STEP_CA_URL',
                     'value': os.environ['conf_stepcerts_ca_url']
                 })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_ENABLED',
+                    'value': 'false'
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_DOMAIN_NAME',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_EMAIL',
+                    'value': ''
+                })
+        elif os.environ['conf_letsencrypt_enabled'] == 'true':
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_ENABLED',
+                    'value': os.environ['conf_letsencrypt_enabled']
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_DOMAIN_NAME',
+                    'value': os.environ['conf_letsencrypt_domain_name']
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_EMAIL',
+                    'value': os.environ['conf_letsencrypt_email']
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_CERTS_ENABLED',
+                    'value': 'false'
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_ROOT_CA',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_KID_ID',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_KID_PASSWORD',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_CA_URL',
+                    'value': ''
+                })
         else:
             cloud_params.append(
                 {
@@ -482,6 +538,21 @@
                     'key': 'STEP_CA_URL',
                     'value': ''
                 })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_ENABLED',
+                    'value': 'false'
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_DOMAIN_NAME',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_EMAIL',
+                    'value': ''
+                })
         logging.info('[CONFIGURE SSN INSTANCE UI]')
         print('[CONFIGURE SSN INSTANCE UI]')
         params = "--hostname {} " \
diff --git a/infrastructure-provisioning/src/general/scripts/azure/ssn_configure.py b/infrastructure-provisioning/src/general/scripts/azure/ssn_configure.py
index 4557c67..fa3f827 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/ssn_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/ssn_configure.py
@@ -359,6 +359,62 @@
                     'key': 'STEP_CA_URL',
                     'value': os.environ['conf_stepcerts_ca_url']
                 })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_ENABLED',
+                    'value': 'false'
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_DOMAIN_NAME',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_EMAIL',
+                    'value': ''
+                })
+        elif os.environ['conf_letsencrypt_enabled'] == 'true':
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_ENABLED',
+                    'value': os.environ['conf_letsencrypt_enabled']
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_DOMAIN_NAME',
+                    'value': os.environ['conf_letsencrypt_domain_name']
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_EMAIL',
+                    'value': os.environ['conf_letsencrypt_email']
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_CERTS_ENABLED',
+                    'value': 'false'
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_ROOT_CA',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_KID_ID',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_KID_PASSWORD',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_CA_URL',
+                    'value': ''
+                })
         else:
             cloud_params.append(
                 {
@@ -385,6 +441,21 @@
                     'key': 'STEP_CA_URL',
                     'value': ''
                 })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_ENABLED',
+                    'value': 'false'
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_DOMAIN_NAME',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_EMAIL',
+                    'value': ''
+                })
 
         if os.environ['azure_datalake_enable'] == 'false':
             cloud_params.append(
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/ssn_configure.py b/infrastructure-provisioning/src/general/scripts/gcp/ssn_configure.py
index dd622d2..c7b94b1 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/ssn_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/ssn_configure.py
@@ -396,6 +396,69 @@
                     'key': 'STEP_CA_URL',
                     'value': os.environ['conf_stepcerts_ca_url']
                 })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_ENABLED',
+                    'value': 'false'
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_DOMAIN_NAME',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_EMAIL',
+                    'value': ''
+                })
+        elif os.environ['conf_letsencrypt_enabled'] == 'true':
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_ENABLED',
+                    'value': os.environ['conf_letsencrypt_enabled']
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_DOMAIN_NAME',
+                    'value': os.environ['conf_letsencrypt_domain_name']
+                })
+            if 'conf_letsencrypt_email' in os.environ:
+                cloud_params.append(
+                    {
+                        'key': 'LETS_ENCRYPT_EMAIL',
+                        'value': os.environ['conf_letsencrypt_email']
+                    })
+            else:
+                cloud_params.append(
+                    {
+                        'key': 'LETS_ENCRYPT_EMAIL',
+                        'value': ''
+                    })
+            cloud_params.append(
+                {
+                    'key': 'STEP_CERTS_ENABLED',
+                    'value': 'false'
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_ROOT_CA',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_KID_ID',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_KID_PASSWORD',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'STEP_CA_URL',
+                    'value': ''
+                })
         else:
             cloud_params.append(
                 {
@@ -422,6 +485,21 @@
                     'key': 'STEP_CA_URL',
                     'value': ''
                 })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_ENABLED',
+                    'value': 'false'
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_DOMAIN_NAME',
+                    'value': ''
+                })
+            cloud_params.append(
+                {
+                    'key': 'LETS_ENCRYPT_EMAIL',
+                    'value': ''
+                })
         params = "--hostname {} --keyfile {} --dlab_path {} --os_user {} --os_family {} --billing_enabled {} " \
                  "--request_id {} --billing_dataset_name {} \
                  --resource {} --service_base_name {} --cloud_provider {} --default_endpoint_name {} " \
diff --git a/infrastructure-provisioning/src/ssn/scripts/configure_ssn_node.py b/infrastructure-provisioning/src/ssn/scripts/configure_ssn_node.py
index abcf761..53614d2 100644
--- a/infrastructure-provisioning/src/ssn/scripts/configure_ssn_node.py
+++ b/infrastructure-provisioning/src/ssn/scripts/configure_ssn_node.py
@@ -186,7 +186,6 @@
                     use_sudo=True)
                 sudo('systemctl daemon-reload')
                 sudo('systemctl enable step-cert-manager.service')
-
             else:
                 sudo('openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/ssl/certs/dlab.key \
                      -out /etc/ssl/certs/dlab.crt -subj "/C=US/ST=US/L=US/O=dlab/CN={}"'.format(hostname))
@@ -253,6 +252,15 @@
     print("Configuring nginx.")
     configure_nginx(deeper_config, args.dlab_path, args.hostname)
 
+    if os.environ['conf_letsencrypt_enabled'] == 'true':
+        print("Configuring letsencrypt certificates.")
+        install_certbot(os.environ['conf_os_family'])
+        if 'conf_letsencrypt_email' in os.environ:
+            run_certbot(os.environ['conf_letsencrypt_domain_name'], 'ssn', os.environ['conf_letsencrypt_email'])
+        else:
+            run_certbot(os.environ['conf_letsencrypt_domain_name'], 'ssn')
+        configure_nginx_LE(os.environ['conf_letsencrypt_domain_name'], 'ssn')
+
     #print("Installing jenkins.")
     #ensure_jenkins(args.dlab_path)