diff --git a/recipes-connectivity/haproxy/files/haproxy.cfg b/recipes-connectivity/haproxy/files/haproxy.cfg new file mode 100644 index 0000000..f0f0f17 --- /dev/null +++ b/recipes-connectivity/haproxy/files/haproxy.cfg @@ -0,0 +1,80 @@ +# this config needs haproxy-1.1.28 or haproxy-1.2.1 + +global + log 127.0.0.1 local0 + log 127.0.0.1 local1 notice + #log loghost local0 info + maxconn 4096 + chroot /usr/share/haproxy + uid 99 + gid 99 + daemon + #debug + #quiet + +defaults + log global + mode http + option httplog + option dontlognull + retries 3 + option redispatch + maxconn 2000 + timeout connect 5000 + timeout client 50000 + timeout server 50000 + +listen appli1-rewrite 0.0.0.0:10001 + cookie SERVERID rewrite + balance roundrobin + server app1_1 192.168.34.23:8080 cookie app1inst1 check inter 2000 rise 2 fall 5 + server app1_2 192.168.34.32:8080 cookie app1inst2 check inter 2000 rise 2 fall 5 + server app1_3 192.168.34.27:8080 cookie app1inst3 check inter 2000 rise 2 fall 5 + server app1_4 192.168.34.42:8080 cookie app1inst4 check inter 2000 rise 2 fall 5 + +listen appli2-insert 0.0.0.0:10002 + option httpchk + balance roundrobin + cookie SERVERID insert indirect nocache + server inst1 192.168.114.56:80 cookie server01 check inter 2000 fall 3 + server inst2 192.168.114.56:81 cookie server02 check inter 2000 fall 3 + capture cookie vgnvisitor= len 32 + + option httpclose # disable keep-alive + rspidel ^Set-cookie:\ IP= # do not let this cookie tell our internal IP address + +listen appli3-relais 0.0.0.0:10003 + dispatch 192.168.135.17:80 + +listen appli4-backup 0.0.0.0:10004 + option httpchk /index.html + option persist + balance roundrobin + server inst1 192.168.114.56:80 check inter 2000 fall 3 + server inst2 192.168.114.56:81 check inter 2000 fall 3 backup + +listen ssl-relay 0.0.0.0:8443 + option ssl-hello-chk + balance source + server inst1 192.168.110.56:443 check inter 2000 fall 3 + server inst2 192.168.110.57:443 check inter 2000 fall 3 + server back1 192.168.120.58:443 backup + +listen appli5-backup 0.0.0.0:10005 + option httpchk * + balance roundrobin + cookie SERVERID insert indirect nocache + server inst1 192.168.114.56:80 cookie server01 check inter 2000 fall 3 + server inst2 192.168.114.56:81 cookie server02 check inter 2000 fall 3 + server inst3 192.168.114.57:80 backup check inter 2000 fall 3 + capture cookie ASPSESSION len 32 + timeout server 20000 + + option httpclose # disable keep-alive + option checkcache # block response if set-cookie & cacheable + + rspidel ^Set-cookie:\ IP= # do not let this cookie tell our internal IP address + + errorloc 502 http://192.168.114.58/error502.html + errorfile 503 /etc/haproxy/errors/503.http + diff --git a/recipes-connectivity/haproxy/files/haproxy.service b/recipes-connectivity/haproxy/files/haproxy.service new file mode 100644 index 0000000..5d22bc4 --- /dev/null +++ b/recipes-connectivity/haproxy/files/haproxy.service @@ -0,0 +1,14 @@ +[Unit] +Description=HAProxy Load Balancer +After=network.target + +[Service] +ExecStartPre=/usr/sbin/haproxy_gencert.sh +ExecStartPre=/usr/bin/haproxy -f /etc/haproxy/haproxy.cfg -c -q +ExecStart=/usr/bin/haproxy-systemd-wrapper -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid +ExecReload=/bin/kill -USR2 $MAINPID +KillMode=mixed +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/recipes-connectivity/haproxy/haproxy-1.7.11/haproxy-1.7.11-tpm-support.patch b/recipes-connectivity/haproxy/haproxy-1.7.11/haproxy-1.7.11-tpm-support.patch new file mode 100644 index 0000000..6b48214 --- /dev/null +++ b/recipes-connectivity/haproxy/haproxy-1.7.11/haproxy-1.7.11-tpm-support.patch @@ -0,0 +1,324 @@ +From 2fa8fedba0968d1c6d21d2c7fa33c903f8984815 Mon Sep 17 00:00:00 2001 +From: Jackie Huang +Date: Thu, 25 Jul 2019 15:22:49 +0800 +Subject: [PATCH] haproxy tpm support + +original author: Kam Nasim + +rebased for 1.7.11 + +Signed-off-by: Jackie Huang +--- + include/types/global.h | 13 +++++ + src/cfgparse.c | 28 ++++++++++ + src/haproxy.c | 26 ++++++++- + src/ssl_sock.c | 147 +++++++++++++++++++++++++++++++++++++++++++------ + 4 files changed, 197 insertions(+), 17 deletions(-) + +diff --git a/include/types/global.h b/include/types/global.h +index 10f3a3c..68f2138 100644 +--- a/include/types/global.h ++++ b/include/types/global.h +@@ -37,6 +37,10 @@ + #include + #endif + ++#ifdef USE_OPENSSL ++#include ++#endif ++ + #ifndef UNIX_MAX_PATH + #define UNIX_MAX_PATH 108 + #endif +@@ -79,6 +83,14 @@ enum { + SSL_SERVER_VERIFY_REQUIRED = 1, + }; + ++// WRS: Define a new TPM configuration structure ++struct tpm_conf { ++ char *tpm_object; ++ char *tpm_engine; ++ EVP_PKEY *tpm_key; ++ ENGINE *tpm_engine_ref; ++}; ++ + /* FIXME : this will have to be redefined correctly */ + struct global { + #ifdef USE_OPENSSL +@@ -101,6 +113,7 @@ struct global { + char *connect_default_ciphers; + int listen_default_ssloptions; + int connect_default_ssloptions; ++ struct tpm_conf tpm; // tpm configuration + #endif + unsigned int ssl_server_verify; /* default verify mode on servers side */ + struct freq_ctr conn_per_sec; +diff --git a/src/cfgparse.c b/src/cfgparse.c +index 3489f7e..0209874 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -1923,6 +1923,34 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) + env++; + } + } ++ else if (!strcmp(args[0], "tpm-object")) { ++ if (global.tpm.tpm_object) { ++ free(global.tpm.tpm_object); ++ } ++#ifdef USE_OPENSSL ++ if (*(args[1]) && (access(args[1], F_OK) != -1)) { ++ global.tpm.tpm_object = strdup(args[1]); ++ } ++#else ++ Alert("parsing [%s:%d] : '%s' is not implemented.\n", file, linenum, args[0]); ++ err_code |= ERR_ALERT | ERR_FATAL; ++ goto out; ++#endif ++ } ++ else if (!strcmp(args[0], "tpm-engine")) { ++ if (global.tpm.tpm_engine) { ++ free(global.tpm.tpm_engine); ++ } ++#ifdef USE_OPENSSL ++ if (*(args[1]) && (access(args[1], F_OK) != -1)) { ++ global.tpm.tpm_engine = strdup(args[1]); ++ } ++#else ++ Alert("parsing [%s:%d] : '%s' is not implemented.\n", file, linenum, args[0]); ++ err_code |= ERR_ALERT | ERR_FATAL; ++ goto out; ++#endif ++ } + else { + struct cfg_kw_list *kwl; + int index; +diff --git a/src/haproxy.c b/src/haproxy.c +index f8a0912..f61dacf 100644 +--- a/src/haproxy.c ++++ b/src/haproxy.c +@@ -1370,6 +1370,24 @@ static void deinit_stick_rules(struct list *rules) + } + } + ++static void deinit_tpm_engine() ++{ ++ /* ++ * if the tpm engine is present then ++ * deinit it, this is needed to ++ * flush the TPM key handle from TPM memory ++ */ ++ if (global.tpm.tpm_engine_ref) { ++ ENGINE_finish(global.tpm.tpm_engine_ref); ++ } ++ ++ if (global.tpm.tpm_key) { ++ EVP_PKEY_free(global.tpm.tpm_key); ++ } ++ free(global.tpm.tpm_engine); global.tpm.tpm_engine = NULL; ++ free(global.tpm.tpm_object); global.tpm.tpm_object = NULL; ++} ++ + void deinit(void) + { + struct proxy *p = proxy, *p0; +@@ -1646,7 +1664,13 @@ void deinit(void) + + free(uap); + } +- ++ ++ /* if HAProxy was in TPM mode then deinit ++ * that configuration as well. ++ */ ++ if (global.tpm.tpm_object && global.tpm.tpm_object != '\0') ++ deinit_tpm_engine(); ++ + userlist_free(userlist); + + cfg_unregister_sections(); +diff --git a/src/ssl_sock.c b/src/ssl_sock.c +index 87b2584..44d0b48 100644 +--- a/src/ssl_sock.c ++++ b/src/ssl_sock.c +@@ -51,6 +51,7 @@ + #ifndef OPENSSL_NO_DH + #include + #endif ++#include + + #include + #include +@@ -2360,6 +2361,80 @@ end: + return ret; + } + ++/* ++ * initialize the TPM engine and load the ++ * TPM object as private key within the Engine. ++ * Only do this for the first bind since TPM can ++ * only load 3-4 contexes before it runs out of memory ++ */ ++static int ssl_sock_load_tpm_key(SSL_CTX *ctx, char **err) { ++ if (!global.tpm.tpm_object || global.tpm.tpm_object[0] == '\0') { ++ /* not in TPM mode */ ++ return -1; ++ } ++ if (!global.tpm.tpm_key) { ++ Warning ("Could not find tpm_key; initializing engine\n"); ++ /* no key present; load the dynamic TPM engine */ ++ if (global.tpm.tpm_engine && global.tpm.tpm_engine[0]) { ++ ENGINE_load_dynamic(); ++ ENGINE *engine = ENGINE_by_id("dynamic"); ++ if (!engine) { ++ memprintf(err, "%s Unable to load the dynamic engine " ++ "(needed for loading custom TPM engine)\n", ++ err && *err ? *err : ""); ++ return 1; ++ } ++ ++ ENGINE_ctrl_cmd_string(engine, "SO_PATH", global.tpm.tpm_engine, 0); ++ ENGINE_ctrl_cmd_string(engine, "LOAD", NULL, 0); ++ /* stow away for ENGINE cleanup */ ++ global.tpm.tpm_engine_ref = engine; ++ ++ if (ENGINE_init(engine) != 1) { ++ const char *error_str = ERR_error_string(ERR_get_error(), NULL); ++ memprintf(err, "%s Unable to init the TPM engine (%s). Err: %s\n", ++ err && *err ? *err : "", ++ global.tpm.tpm_engine, error_str); ++ goto tpm_err; ++ } ++ EVP_PKEY *pkey = ENGINE_load_private_key(engine, ++ global.tpm.tpm_object, ++ NULL, NULL); ++ if (!pkey) { ++ const char *error_str = ERR_error_string(ERR_get_error(), NULL); ++ memprintf(err, "%s Unable to load TPM object (%s). Err: %s\n", ++ err && *err ? *err : "", ++ global.tpm.tpm_object, error_str); ++ goto tpm_err; ++ } ++ global.tpm.tpm_key = pkey; ++ } ++ else { /* no TPM engine found */ ++ memprintf(err, "%s TPM engine option not set when TPM mode expected\n", ++ err && *err ? *err : ""); ++ goto tpm_err; ++ } ++ } ++ ++ if (SSL_CTX_use_PrivateKey(ctx, global.tpm.tpm_key) <= 0){ ++ const char *error_str = ERR_error_string(ERR_get_error(), ++ NULL); ++ memprintf(err, "%s Invalid private key provided from TPM engine(%s). Err: %s\n", ++ err && *err ? *err : "", ++ global.tpm.tpm_object, error_str); ++ goto tpm_err; ++ } ++ ++ return 0; ++ ++tpm_err: ++ ENGINE_finish(global.tpm.tpm_engine_ref); ++ global.tpm.tpm_engine_ref = NULL; ++ EVP_PKEY_free(global.tpm.tpm_key); ++ global.tpm.tpm_key = NULL; ++ return 1; ++} ++ + static int ssl_sock_load_cert_file(const char *path, struct bind_conf *bind_conf, struct proxy *curproxy, char **sni_filter, int fcount, char **err) + { + int ret; +@@ -2372,26 +2447,54 @@ static int ssl_sock_load_cert_file(const char *path, struct bind_conf *bind_conf + return 1; + } + +- if (SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM) <= 0) { +- memprintf(err, "%sunable to load SSL private key from PEM file '%s'.\n", +- err && *err ? *err : "", path); +- SSL_CTX_free(ctx); +- return 1; ++ /* NOTE (knasim-wrs): US93721: TPM support ++ * This SSL context applies to SSL frontends only. ++ * If the TPM option is set then the Private key ++ * is stored in TPM. ++ * ++ * Launch the OpenSSL TPM engine and load the TPM ++ * Private Key. The Public key will still be located ++ * at the provided path and needs to be loaded as ++ * per usual. ++ */ ++ if (global.tpm.tpm_object) { ++ ret = ssl_sock_load_tpm_key(ctx, err); ++ if (ret > 0) { ++ /* tpm configuration failed */ ++ SSL_CTX_free(ctx); ++ return 1; ++ } + } +- +- ret = ssl_sock_load_cert_chain_file(ctx, path, bind_conf, sni_filter, fcount); +- if (ret <= 0) { +- memprintf(err, "%sunable to load SSL certificate from PEM file '%s'.\n", +- err && *err ? *err : "", path); +- if (ret < 0) /* serious error, must do that ourselves */ ++ else { /* non TPM mode */ ++ if (SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM) <= 0) { ++ memprintf(err, "%sunable to load SSL private key from PEM file '%s'.\n", ++ err && *err ? *err : "", path); + SSL_CTX_free(ctx); +- return 1; ++ return 1; ++ } + } + +- if (SSL_CTX_check_private_key(ctx) <= 0) { +- memprintf(err, "%sinconsistencies between private key and certificate loaded from PEM file '%s'.\n", +- err && *err ? *err : "", path); +- return 1; ++ ret = ssl_sock_load_cert_chain_file(ctx, path, bind_conf, sni_filter, fcount); ++ if (ret <= 0) { ++ memprintf(err, "%sunable to load SSL certificate from PEM file '%s'.\n", ++ err && *err ? *err : "", path); ++ if (ret < 0) /* serious error, must do that ourselves */ ++ SSL_CTX_free(ctx); ++ return 1; ++ } ++ ++ /* ++ * only match the private key to the public key ++ * for non TPM mode. This op would never work for ++ * TPM since the private key has been wrapped, whereas ++ * the public key is still the original one. ++ */ ++ if (!global.tpm.tpm_object) { ++ if (SSL_CTX_check_private_key(ctx) <= 0) { ++ memprintf(err, "%sinconsistencies between private key and certificate loaded from PEM file '%s'.\n", ++ err && *err ? *err : "", path); ++ return 1; ++ } + } + + /* we must not free the SSL_CTX anymore below, since it's already in +@@ -3068,6 +3171,18 @@ int ssl_sock_prepare_srv_ctx(struct server *srv, struct proxy *curproxy) + cfgerr++; + return cfgerr; + } ++ ++ /* NOTE (knasim-wrs): US93721: TPM support ++ * This SSL context applies to SSL backends only. ++ * Since Titanium backends don't support SSL, there ++ * is no need to offload these keys in TPM or reuse the ++ * same TPM key for the frontend engine. ++ * ++ * If SSL backends are to be supported in the future, ++ * over TPM, then create a new TPM Engine context and ++ * load the backend key in TPM, in a similar fashion to ++ * the frontend key. ++ */ + if (srv->ssl_ctx.client_crt) { + if (SSL_CTX_use_PrivateKey_file(srv->ssl_ctx.ctx, srv->ssl_ctx.client_crt, SSL_FILETYPE_PEM) <= 0) { + Alert("config : %s '%s', server '%s': unable to load SSL private key from PEM file '%s'.\n", +-- +2.7.4 + diff --git a/recipes-connectivity/haproxy/haproxy.inc b/recipes-connectivity/haproxy/haproxy.inc new file mode 100644 index 0000000..0d60212 --- /dev/null +++ b/recipes-connectivity/haproxy/haproxy.inc @@ -0,0 +1,102 @@ +SUMMARY = "TCP/HTTP proxy and load balancer for high availability environments" +DESCRIPTION = " \ +HAProxy is a TCP/HTTP reverse proxy which is particularly suited for high \ +availability environments. Indeed, it can: \ + - route HTTP requests depending on statically assigned cookies \ + - spread load among several servers while assuring server persistence \ + through the use of HTTP cookies \ + - switch to backup servers in the event a main server fails \ + - accept connections to special ports dedicated to service monitoring \ + - stop accepting connections without breaking existing ones \ + - add, modify, and delete HTTP headers in both directions \ + - block requests matching particular patterns \ + - report detailed status to authenticated users from a URI \ + intercepted by the application \ +" +HOMEPAGE = "http://www.haproxy.org/" + +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://LICENSE;md5=2d862e836f92129cdc0ecccc54eed5e0" + +DEPENDS = "libpcre openssl zlib" + +MAJOR_VER = "${@'.'.join(d.getVar('PV').split('.')[0:2])}" + +SRC_URI = "http://www.haproxy.org/download/${MAJOR_VER}/src/haproxy-${PV}.tar.gz \ + file://haproxy.service \ + file://haproxy.cfg \ + " + +inherit systemd useradd + +# create a user for running haproxy +HAP_USER_HOME = "${libdir}/haproxy" +USERADD_PACKAGES = "${PN}" +USERADD_PARAM_${PN} = "--system --home ${HAP_USER_HOME} --shell /sbin/nologin \ + --groups haproxy --gid haproxy haproxy" +GROUPADD_PARAM_${PN} = "haproxy" + +# for haproxy 1.x +HAP_TARGET = "linux2628" + +EXTRA_OEMAKE = " \ + 'CPU=generic' \ + 'TARGET=${HAP_TARGET}' \ + 'USE_GETADDRINFO=1' \ + 'USE_OPENSSL=1' \ + 'USE_PCRE=1' 'USE_PCRE_JIT=1' \ + 'USE_ZLIB=1' \ + 'USE_LINUX_TPROXY=1' \ + " + +EXTRA_OEMAKE_append_x86 = " USE_REGPARM=1" +EXTRA_OEMAKE_append_x86-64 = " USE_REGPARM=1" + + +do_configure() { + : +} + +do_compile() { + oe_runmake CC="${CC}" CFLAGS="${CFLAGS}" SBINDIR="${bindir}" \ + PREFIX="${prefix}" \ + ZLIB_INC=${STAGING_INCDIR} \ + ZLIB_LIB=${STAGING_LIBDIR} \ + PCRE_INC=${STAGING_INCDIR} \ + PCRE_LIB=${STAGING_LIBDIR} \ + SSL_INC=${STAGING_INCDIR} \ + SSL_LIB=${STAGING_LIBDIR} + oe_runmake -C contrib/halog halog + oe_runmake -C contrib/iprange iprange +} + +do_install() { + oe_runmake install-bin \ + PREFIX="${prefix}" \ + SBINDIR="${bindir}" \ + DESTDIR=${D} \ + INCLUDEDIR=${includedir} + + install -D -m 0644 ${WORKDIR}/haproxy.service ${D}${systemd_system_unitdir}/haproxy.service + install -D -m 0644 ${WORKDIR}/haproxy.cfg ${D}${sysconfdir}/haproxy/haproxy.cfg + + # install ssl folder for certificate + install -m 700 -d ${D}/${sysconfdir}/ssl/haproxy + chown haproxy:haproxy ${D}/${sysconfdir}/ssl/haproxy + + # install halog and iprange + install -D -m 755 contrib/halog/halog ${D}${bindir}/halog + install -D -m 755 contrib/iprange/iprange ${D}${bindir}/iprange +} + +FILES_${PN} = " \ + ${bindir} \ + ${sbindir} \ + ${sysconfdir} \ + ${systemd_system_unitdir} \ + " +RDEPENDS_${PN} = "openssl" + +SYSTEMD_SERVICE_${PN} = "haproxy.service" + +INSANE_SKIP_${PN} += "already-stripped" diff --git a/recipes-connectivity/haproxy/haproxy_1.7.11.bb b/recipes-connectivity/haproxy/haproxy_1.7.11.bb new file mode 100644 index 0000000..d348bdf --- /dev/null +++ b/recipes-connectivity/haproxy/haproxy_1.7.11.bb @@ -0,0 +1,6 @@ +include haproxy.inc + +SRC_URI += "file://haproxy-${PV}-tpm-support.patch" + +SRC_URI[md5sum] = "25be5ad717a71da89a65c3c24250e2eb" +SRC_URI[sha256sum] = "d564b8e9429d1e8e13cb648bf4694926b472e36da1079df946bb732927b232ea" diff --git a/recipes-core/stx-integ/base/haproxy-config.inc b/recipes-core/stx-integ/base/haproxy-config.inc index a37f38c..ddfcee9 100644 --- a/recipes-core/stx-integ/base/haproxy-config.inc +++ b/recipes-core/stx-integ/base/haproxy-config.inc @@ -1,6 +1,6 @@ PACKAGES += " haproxy-config" -RDEPENDS_haproxy-config += " bash" +RDEPENDS_haproxy-config += " bash haproxy" do_configure_prepend () { : @@ -12,16 +12,16 @@ do_compile_prepend () { do_install_prepend () { cd ${S}/base/haproxy-config - install -d -m 0755 ${D}/${systemd_system_unitdir} + install -d -m 0755 ${D}/${sysconfdir}/systemd/system install -d -m 0755 ${D}/${sysconfdir}/haproxy/errors install -d -m 0755 ${D}/${sysconfdir}/init.d install -p -m 0755 files/503.http ${D}/${sysconfdir}/haproxy/errors - install -p -m 0644 files/haproxy.service ${D}/${systemd_system_unitdir} + install -p -m 0644 files/haproxy.service ${D}/${sysconfdir}/systemd/system install -p -m 0755 files/haproxy.sh ${D}/${sysconfdir}/init.d } FILES_haproxy-config = " \ ${sysconfdir}/haproxy/errors/503.http \ - ${systemd_system_unitdir}/haproxy.service \ + ${sysconfdir}/systemd/system/haproxy.service \ ${sysconfdir}/init.d/haproxy.sh \ "