You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by vn...@apache.org on 2018/09/26 12:44:38 UTC

[17/19] guacamole-server git commit: GUACAMOLE-623: Add support for SSL.

GUACAMOLE-623: Add support for SSL.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-server/commit/83a531bc
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-server/tree/83a531bc
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-server/diff/83a531bc

Branch: refs/heads/master
Commit: 83a531bc89a5c79371f42d1ec5142c484a08479a
Parents: 2e50573
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 11 03:03:17 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Sep 25 21:30:52 2018 -0700

----------------------------------------------------------------------
 configure.ac                          |   1 +
 src/protocols/kubernetes/Makefile.am  |   3 +
 src/protocols/kubernetes/client.c     |  16 +--
 src/protocols/kubernetes/client.h     |   7 +
 src/protocols/kubernetes/kubernetes.c |  46 +++----
 src/protocols/kubernetes/settings.c   |  48 +++----
 src/protocols/kubernetes/settings.h   |  24 ++--
 src/protocols/kubernetes/ssl.c        | 210 +++++++++++++++++++++++++++++
 src/protocols/kubernetes/ssl.h        |  41 ++++++
 9 files changed, 326 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index df36eab..d26db39 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1225,6 +1225,7 @@ AC_ARG_ENABLE([kubernetes],
 
 AM_CONDITIONAL([ENABLE_KUBERNETES], [test "x${enable_kubernetes}"  = "xyes" \
                                        -a "x${have_libwebsockets}" = "xyes" \
+                                       -a "x${have_ssl}"           = "xyes" \
                                        -a "x${have_terminal}"      = "xyes"])
 
 #

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/Makefile.am
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/Makefile.am b/src/protocols/kubernetes/Makefile.am
index e818ff7..56db4d6 100644
--- a/src/protocols/kubernetes/Makefile.am
+++ b/src/protocols/kubernetes/Makefile.am
@@ -29,6 +29,7 @@ libguac_client_kubernetes_la_SOURCES = \
     io.c                               \
     pipe.c                             \
     settings.c                         \
+    ssl.c                              \
     kubernetes.c                       \
     url.c                              \
     user.c
@@ -40,6 +41,7 @@ noinst_HEADERS = \
     io.h         \
     pipe.h       \
     settings.h   \
+    ssl.h        \
     kubernetes.h \
     url.h        \
     user.h
@@ -57,5 +59,6 @@ libguac_client_kubernetes_la_LIBADD = \
 libguac_client_kubernetes_la_LDFLAGS = \
     -version-info 0:0:0                \
     @PTHREAD_LIBS@                     \
+    @SSL_LIBS@                         \
     @WEBSOCKETS_LIBS@
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/client.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/client.c b/src/protocols/kubernetes/client.c
index 58f4728..331e03d 100644
--- a/src/protocols/kubernetes/client.c
+++ b/src/protocols/kubernetes/client.c
@@ -32,12 +32,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-/**
- * Static reference to the guac_client associated with the active Kubernetes
- * connection. As guacd guarantees that each main client connection is
- * isolated within its own process, this is safe.
- */
-static guac_client* guac_kubernetes_lws_log_client = NULL;
+guac_client* guac_kubernetes_lws_current_client = NULL;
 
 /**
  * Logging callback invoked by libwebsockets to log a single line of logging
@@ -53,15 +48,18 @@ static guac_client* guac_kubernetes_lws_log_client = NULL;
  *     The line of logging output to log.
  */
 static void guac_kubernetes_log(int level, const char* line) {
-    if (guac_kubernetes_lws_log_client != NULL)
-        guac_client_log(guac_kubernetes_lws_log_client, GUAC_LOG_DEBUG,
+    if (guac_kubernetes_lws_current_client != NULL)
+        guac_client_log(guac_kubernetes_lws_current_client, GUAC_LOG_DEBUG,
                 "libwebsockets: %s", line);
 }
 
 int guac_client_init(guac_client* client) {
 
+    /* Ensure reference to main guac_client remains available in all
+     * libwebsockets contexts */
+    guac_kubernetes_lws_current_client = client;
+
     /* Redirect libwebsockets logging */
-    guac_kubernetes_lws_log_client = client;
     lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO,
             guac_kubernetes_log);
 

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/client.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/client.h b/src/protocols/kubernetes/client.h
index 0b847da..ec4ba32 100644
--- a/src/protocols/kubernetes/client.h
+++ b/src/protocols/kubernetes/client.h
@@ -28,6 +28,13 @@
 #define GUAC_KUBERNETES_CLIPBOARD_MAX_LENGTH 262144
 
 /**
+ * Static reference to the guac_client associated with the active Kubernetes
+ * connection. While libwebsockets provides some means of storing and
+ * retrieving custom data in some structures, this is not always available.
+ */
+extern guac_client* guac_kubernetes_lws_current_client;
+
+/**
  * Free handler. Required by libguac and called when the guac_client is
  * disconnected and must be cleaned up.
  */

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/kubernetes.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/kubernetes.c b/src/protocols/kubernetes/kubernetes.c
index 4e7928e..f314c59 100644
--- a/src/protocols/kubernetes/kubernetes.c
+++ b/src/protocols/kubernetes/kubernetes.c
@@ -18,9 +18,11 @@
  */
 
 #include "config.h"
+#include "client.h"
 #include "common/recording.h"
 #include "io.h"
 #include "kubernetes.h"
+#include "ssl.h"
 #include "terminal/terminal.h"
 #include "url.h"
 
@@ -43,8 +45,9 @@
  *     The reason (event) that this callback was invoked.
  *
  * @param user
- *     Arbitrary data assocated with the WebSocket session. This will always
- *     be a pointer to the guac_client instance.
+ *     Arbitrary data assocated with the WebSocket session. In some cases,
+ *     this is actually event-specific data (such as the
+ *     LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERT event).
  *
  * @param in
  *     A pointer to arbitrary, reason-specific data.
@@ -60,14 +63,19 @@ static int guac_kubernetes_lws_callback(struct lws* wsi,
         enum lws_callback_reasons reason, void* user,
         void* in, size_t length) {
 
-    /* Request connection closure if client is stopped (note that the user
-     * pointer passed by libwebsockets may be NULL for some events) */
-    guac_client* client = (guac_client*) user;
-    if (client != NULL && client->state != GUAC_CLIENT_RUNNING)
+    guac_client* client = guac_kubernetes_lws_current_client;
+
+    /* Do not handle any further events if connection is closing */
+    if (client->state != GUAC_CLIENT_RUNNING)
         return lws_callback_http_dummy(wsi, reason, user, in, length);
 
     switch (reason) {
 
+        /* Complete initialization of SSL */
+        case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS:
+            guac_kubernetes_init_ssl(client, (SSL_CTX*) user);
+            break;
+
         /* Failed to connect */
         case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
             guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND,
@@ -256,29 +264,13 @@ void* guac_kubernetes_client_thread(void* data) {
     };
 
     /* If requested, use an SSL/TLS connection for communication with
-     * Kubernetes */
+     * Kubernetes. Note that we disable hostname checks here because we
+     * do our own validation - libwebsockets does not validate properly if
+     * IP addresses are used. */
     if (settings->use_ssl) {
-
-        /* Enable use of SSL/TLS */
         context_info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
-        connection_info.ssl_connection = LCCSCF_USE_SSL;
-
-        /* Bypass certificate checks if requested */
-        if (settings->ignore_cert) {
-            connection_info.ssl_connection |=
-                  LCCSCF_ALLOW_SELFSIGNED
-                | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK
-                | LCCSCF_ALLOW_EXPIRED;
-        }
-
-        /* Otherwise use the given CA certificate to validate (if any) */
-        else
-            context_info.client_ssl_ca_filepath = settings->ca_cert_file;
-
-        /* Certificate and key file for SSL/TLS client auth */
-        context_info.client_ssl_cert_filepath = settings->client_cert_file;
-        context_info.client_ssl_private_key_filepath = settings->client_key_file;
-
+        connection_info.ssl_connection = LCCSCF_USE_SSL
+            | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
     }
 
     /* Create libwebsockets context */

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/settings.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.c b/src/protocols/kubernetes/settings.c
index 122a858..4f00a44 100644
--- a/src/protocols/kubernetes/settings.c
+++ b/src/protocols/kubernetes/settings.c
@@ -31,9 +31,9 @@ const char* GUAC_KUBERNETES_CLIENT_ARGS[] = {
     "pod",
     "container",
     "use-ssl",
-    "client-cert-file",
-    "client-key-file",
-    "ca-cert-file",
+    "client-cert",
+    "client-key",
+    "ca-cert",
     "ignore-cert",
     "font-name",
     "font-size",
@@ -89,24 +89,26 @@ enum KUBERNETES_ARGS_IDX {
     IDX_USE_SSL,
 
     /**
-     * The filename of the certificate to use if performing SSL/TLS client
-     * authentication to authenticate with the Kubernetes server. If omitted,
-     * SSL client authentication will not be performed. 
+     * The certificate to use if performing SSL/TLS client authentication to
+     * authenticate with the Kubernetes server, in PEM format. If omitted, SSL
+     * client authentication will not be performed.
      */
-    IDX_CLIENT_CERT_FILE,
+    IDX_CLIENT_CERT,
 
     /**
-     * The filename of the key to use if performing SSL/TLS client
-     * authentication to authenticate with the Kubernetes server. If omitted,
-     * SSL client authentication will not be performed. 
+     * The key to use if performing SSL/TLS client authentication to
+     * authenticate with the Kubernetes server, in PEM format. If omitted, SSL
+     * client authentication will not be performed.
      */
-    IDX_CLIENT_KEY_FILE,
+    IDX_CLIENT_KEY,
 
     /**
-     * The filename of the certificate of the certificate authority that signed
-     * the certificate of the Kubernetes server.
+     * The certificate of the certificate authority that signed the certificate
+     * of the Kubernetes server, in PEM format. If omitted. verification of
+     * the Kubernetes server certificate will use the systemwide certificate
+     * authorities.
      */
-    IDX_CA_CERT_FILE,
+    IDX_CA_CERT,
 
     /**
      * Whether the certificate used by the Kubernetes server for SSL/TLS should
@@ -264,17 +266,17 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
     /* Read SSL/TLS connection details only if enabled */
     if (settings->use_ssl) {
 
-        settings->client_cert_file =
+        settings->client_cert =
             guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
-                    argv, IDX_CLIENT_CERT_FILE, NULL);
+                    argv, IDX_CLIENT_CERT, NULL);
 
-        settings->client_key_file =
+        settings->client_key =
             guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
-                    argv, IDX_CLIENT_KEY_FILE, NULL);
+                    argv, IDX_CLIENT_KEY, NULL);
 
-        settings->ca_cert_file =
+        settings->ca_cert =
             guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
-                    argv, IDX_CA_CERT_FILE, NULL);
+                    argv, IDX_CA_CERT, NULL);
 
         settings->ignore_cert =
             guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS,
@@ -378,9 +380,9 @@ void guac_kubernetes_settings_free(guac_kubernetes_settings* settings) {
     free(settings->kubernetes_container);
 
     /* Free SSL/TLS details */
-    free(settings->client_cert_file);
-    free(settings->client_key_file);
-    free(settings->ca_cert_file);
+    free(settings->client_cert);
+    free(settings->client_key);
+    free(settings->ca_cert);
 
     /* Free display preferences */
     free(settings->font_name);

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/settings.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/settings.h b/src/protocols/kubernetes/settings.h
index a86d14a..6267a18 100644
--- a/src/protocols/kubernetes/settings.h
+++ b/src/protocols/kubernetes/settings.h
@@ -103,24 +103,26 @@ typedef struct guac_kubernetes_settings {
     bool use_ssl;
 
     /**
-     * The filename of the certificate to use if performing SSL/TLS client
-     * authentication to authenticate with the Kubernetes server. If omitted,
-     * SSL client authentication will not be performed.
+     * The certificate to use if performing SSL/TLS client authentication to
+     * authenticate with the Kubernetes server, in PEM format. If omitted, SSL
+     * client authentication will not be performed.
      */
-    char* client_cert_file;
+    char* client_cert;
 
     /**
-     * The filename of the key to use if performing SSL/TLS client
-     * authentication to authenticate with the Kubernetes server. If omitted,
-     * SSL client authentication will not be performed. 
+     * The key to use if performing SSL/TLS client authentication to
+     * authenticate with the Kubernetes server, in PEM format. If omitted, SSL
+     * client authentication will not be performed.
      */
-    char* client_key_file;
+    char* client_key;
 
     /**
-     * The filename of the certificate of the certificate authority that signed
-     * the certificate of the Kubernetes server.
+     * The certificate of the certificate authority that signed the certificate
+     * of the Kubernetes server, in PEM format. If omitted. verification of
+     * the Kubernetes server certificate will use the systemwide certificate
+     * authorities.
      */
-    char* ca_cert_file;
+    char* ca_cert;
 
     /**
      * Whether the certificate used by the Kubernetes server for SSL/TLS should

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/ssl.c
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/ssl.c b/src/protocols/kubernetes/ssl.c
new file mode 100644
index 0000000..6ebafc6
--- /dev/null
+++ b/src/protocols/kubernetes/ssl.c
@@ -0,0 +1,210 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "kubernetes.h"
+#include "settings.h"
+
+#include <guacamole/client.h>
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+
+/**
+ * Tests whether the given hostname is, in fact, an IP address.
+ *
+ * @param hostname
+ *     The hostname to test.
+ *
+ * @return
+ *     Non-zero if the given hostname is an IP address, zero otherwise.
+ */
+static int guac_kubernetes_is_address(const char* hostname) {
+
+    /* Attempt to interpret the hostname as an IP address */
+    ASN1_OCTET_STRING* ip = a2i_IPADDRESS(hostname);
+
+    /* If unsuccessful, the hostname is not an IP address */
+    if (ip == NULL)
+        return 0;
+
+    /* Converted hostname must be freed */
+    ASN1_OCTET_STRING_free(ip);
+    return 1;
+
+}
+
+/**
+ * Parses the given PEM certificate, returning a new OpenSSL X509 structure
+ * representing that certificate.
+ *
+ * @param pem
+ *     The PEM certificate.
+ *
+ * @return
+ *     An X509 structure representing the given certificate, or NULL if the
+ *     certificate was unreadable.
+ */
+static X509* guac_kubernetes_read_cert(char* pem) {
+
+    /* Prepare a BIO which provides access to the in-memory CA cert */
+    BIO* bio = BIO_new_mem_buf(pem, -1);
+    if (bio == NULL)
+        return NULL;
+
+    /* Read the CA cert as PEM */
+    X509* certificate = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+    if (certificate == NULL) {
+        BIO_free(bio);
+        return NULL;
+    }
+
+    return certificate;
+
+}
+
+/**
+ * Parses the given PEM private key, returning a new OpenSSL EVP_PKEY structure
+ * representing that key.
+ *
+ * @param pem
+ *     The PEM private key.
+ *
+ * @return
+ *     An EVP_KEY representing the given private key, or NULL if the private
+ *     key was unreadable.
+ */
+static EVP_PKEY* guac_kubernetes_read_key(char* pem) {
+
+    /* Prepare a BIO which provides access to the in-memory key */
+    BIO* bio = BIO_new_mem_buf(pem, -1);
+    if (bio == NULL)
+        return NULL;
+
+    /* Read the private key as PEM */
+    EVP_PKEY* key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+    if (key == NULL) {
+        BIO_free(bio);
+        return NULL;
+    }
+
+    return key;
+
+}
+
+void guac_kubernetes_init_ssl(guac_client* client, SSL_CTX* context) {
+
+    guac_kubernetes_client* kubernetes_client =
+        (guac_kubernetes_client*) client->data;
+
+    guac_kubernetes_settings* settings = kubernetes_client->settings;
+
+    /* Bypass certificate checks if requested */
+    if (settings->ignore_cert)
+        SSL_CTX_set_verify(context, SSL_VERIFY_NONE, NULL);
+
+    /* Otherwise use the given CA certificate to validate (if any) */
+    else if (settings->ca_cert != NULL) {
+
+        /* Read CA certificate from configuration data */
+        X509* ca_cert = guac_kubernetes_read_cert(settings->ca_cert);
+        if (ca_cert == NULL) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Provided CA certificate is unreadable");
+            return;
+        }
+
+        /* Add certificate to CA store */
+        X509_STORE* ca_store = SSL_CTX_get_cert_store(context);
+        if (!X509_STORE_add_cert(ca_store, ca_cert)) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Unable to add CA certificate to certificate store of "
+                    "SSL context");
+            return;
+        }
+
+    }
+
+    /* Certificate for SSL/TLS client auth */
+    if (settings->client_cert != NULL) {
+
+        /* Read client certificate from configuration data */
+        X509* client_cert = guac_kubernetes_read_cert(settings->client_cert);
+        if (client_cert == NULL) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Provided client certificate is unreadable");
+            return;
+        }
+
+        /* Use parsed certificate for authentication */
+        if (!SSL_CTX_use_certificate(context, client_cert)) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Client certificate could not be used for SSL/TLS "
+                    "client authentication");
+            return;
+        }
+
+    }
+
+    /* Private key for SSL/TLS client auth */
+    if (settings->client_key != NULL) {
+
+        /* Read client private key from configuration data */
+        EVP_PKEY* client_key = guac_kubernetes_read_key(settings->client_key);
+        if (client_key == NULL) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Provided client private key is unreadable");
+            return;
+        }
+
+        /* Use parsed key for authentication */
+        if (!SSL_CTX_use_PrivateKey(context, client_key)) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Client private key could not be used for SSL/TLS "
+                    "client authentication");
+            return;
+        }
+
+    }
+
+    /* Enable hostname checking */
+    X509_VERIFY_PARAM *param = SSL_CTX_get0_param(context);
+    X509_VERIFY_PARAM_set_hostflags(param,
+            X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
+
+    /* Validate properly depending on whether hostname is an IP address */
+    if (guac_kubernetes_is_address(settings->hostname)) {
+        if (!X509_VERIFY_PARAM_set1_ip_asc(param, settings->hostname)) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Server IP address validation could not be enabled");
+            return;
+        }
+    }
+    else {
+        if (!X509_VERIFY_PARAM_set1_host(param, settings->hostname, 0)) {
+            guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
+                    "Server hostname validation could not be enabled");
+            return;
+        }
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/guacamole-server/blob/83a531bc/src/protocols/kubernetes/ssl.h
----------------------------------------------------------------------
diff --git a/src/protocols/kubernetes/ssl.h b/src/protocols/kubernetes/ssl.h
new file mode 100644
index 0000000..cca02bd
--- /dev/null
+++ b/src/protocols/kubernetes/ssl.h
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef GUAC_KUBERNETES_SSL_H
+#define GUAC_KUBERNETES_SSL_H
+
+#include "settings.h"
+
+#include <openssl/ssl.h>
+
+/**
+ * Initializes the given SSL/TLS context using the configuration parameters
+ * associated with the given guac_client, setting up hostname/address
+ * validation and client authentication.
+ *
+ * @param client
+ *     The guac_client associated with the Kubernetes connection.
+ *
+ * @param context
+ *     The SSL_CTX in use by libwebsockets.
+ */
+void guac_kubernetes_init_ssl(guac_client* client, SSL_CTX* context);
+
+#endif
+