diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js index 52bdd66d..bc66ecfe 100644 --- a/backend/internal/nginx.js +++ b/backend/internal/nginx.js @@ -157,7 +157,11 @@ const internalNginx = { for (let i = 0; i < host.locations.length; i++) { let locationCopy = Object.assign({}, {access_list_id: host.access_list_id}, {certificate_id: host.certificate_id}, {ssl_forced: host.ssl_forced}, {caching_enabled: host.caching_enabled}, {block_exploits: host.block_exploits}, - {allow_websocket_upgrade: host.allow_websocket_upgrade}, {http2_support: host.http2_support}, + {allow_websocket_upgrade: host.allow_websocket_upgrade}, {enable_proxy_protocol: host.enable_proxy_protocol}, + {stream_enable_proxy_protocol: host.stream_enable_proxy_protocol}, + {stream_allow_proxy_protocol: host.stream_allow_proxy_protocol}, + {stream_load_balancer_ip: host.stream_load_balancer_ip}, + {load_balancer_ip: host.load_balancer_ip}, {http2_support: host.http2_support}, {hsts_enabled: host.hsts_enabled}, {hsts_subdomains: host.hsts_subdomains}, {access_list: host.access_list}, {certificate: host.certificate}, host.locations[i]); diff --git a/backend/migrations/20221011000001_stream_proxy_protocol.js b/backend/migrations/20221011000001_stream_proxy_protocol.js new file mode 100644 index 00000000..f62d6f68 --- /dev/null +++ b/backend/migrations/20221011000001_stream_proxy_protocol.js @@ -0,0 +1,80 @@ +const migrate_name = 'stream_proxy_protocol'; +const logger = require('../logger').migrate; + +/** + * Migrate + * + * @see http://knexjs.org/#Schema + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.up = function (knex/*, Promise*/) { + knex.schema.table('stream', function (stream) { + stream.dropColumn('stream_access_proxy_protocol'); + }) + .then(() => { + logger.info('[' + migrate_name + '] stream Table altered - ERRANT Column fixed!'); + }).catch((err) => { + logger.error('[' + migrate_name + '] stream Table error while removing errant column: ' + err); + }); + + logger.info('[' + migrate_name + '] Migrating PROXY_HOST Table Up...'); + knex.schema.table('proxy_host', function (proxy_host) { + proxy_host.integer('enable_proxy_protocol').notNull().unsigned().defaultTo(0); + }) + .then(() => { + logger.info('[' + migrate_name + '] proxy_host Table altered - "enable_proxy_protocol" added'); + }).catch((err) => { + logger.error('[' + migrate_name + '] proxy_host Table error migrating up: ' + err); + }); + knex.schema.table('proxy_host', function (proxy_host) { + proxy_host.string('load_balancer_ip').notNull().defaultTo(''); + }) + .then(() => { + logger.info('[' + migrate_name + '] proxy_host Table altered - "load_balancer_ip" added'); + }).catch((err) => { + logger.error('[' + migrate_name + '] proxy_host Table error migrating up: ' + err); + }); + + logger.info('[' + migrate_name + '] Migrating STREAM Table Up...'); + knex.schema.table('stream', function (stream) { + stream.integer('stream_allow_proxy_protocol').notNull().unsigned().defaultTo(0); + }) + .then(() => { + logger.info('[' + migrate_name + '] stream Table altered - "stream_allow_proxy_protocol" added'); + }).catch((err) => { + logger.error('[' + migrate_name + '] stream Table error migrating up: ' + err); + }); + knex.schema.table('stream', function (stream) { + stream.integer('stream_enable_proxy_protocol').notNull().unsigned().defaultTo(0); + }) + .then(() => { + logger.info('[' + migrate_name + '] stream Table altered - "stream_enable_proxy_protocol" added'); + }).catch((err) => { + logger.error('[' + migrate_name + '] stream Table error migrating up: ' + err); + }); + + knex.schema.table('stream', function (stream) { + stream.string('stream_load_balancer_ip').notNull().defaultTo(''); + }) + .then(() => { + logger.info('[' + migrate_name + '] stream Table altered - "stream_load_balancer_ip" added'); + }).catch((err) => { + logger.error('[' + migrate_name + '] stream Table error migrating up: ' + err); + }); + return Promise.resolve(true); +}; + +/** + * Undo Migrate + * + * @param {Object} knex + * @param {Promise} Promise + * @returns {Promise} + */ +exports.down = function (knex, Promise) { + logger.warn('[' + migrate_name + '] You can\'t migrate down this one.'); + return Promise.resolve(true); +}; \ No newline at end of file diff --git a/backend/schema/endpoints/proxy-hosts.json b/backend/schema/endpoints/proxy-hosts.json index 9a3fff2f..74392aa5 100644 --- a/backend/schema/endpoints/proxy-hosts.json +++ b/backend/schema/endpoints/proxy-hosts.json @@ -58,6 +58,17 @@ "example": true, "type": "boolean" }, + "enable_proxy_protocol": { + "description": "Enable PROXY Protocol support (Pass through)", + "example": true, + "type": "boolean" + }, + "load_balancer_ip": { + "description": "Authorized TCP Load Balancer IP / CIDR for setting 'set_real_ip_from'", + "type": "string", + "minLength": 0, + "maxLength": 255 + }, "access_list_id": { "$ref": "../definitions.json#/definitions/access_list_id" }, @@ -155,6 +166,12 @@ "allow_websocket_upgrade": { "$ref": "#/definitions/allow_websocket_upgrade" }, + "enable_proxy_protocol": { + "$ref": "#/definitions/enable_proxy_protocol" + }, + "load_balancer_ip": { + "$ref": "#/definitions/load_balancer_ip" + }, "access_list_id": { "$ref": "#/definitions/access_list_id" }, @@ -245,6 +262,12 @@ "allow_websocket_upgrade": { "$ref": "#/definitions/allow_websocket_upgrade" }, + "enable_proxy_protocol": { + "$ref": "#/definitions/enable_proxy_protocol" + }, + "load_balancer_ip": { + "$ref": "#/definitions/load_balancer_ip" + }, "access_list_id": { "$ref": "#/definitions/access_list_id" }, @@ -318,6 +341,12 @@ "allow_websocket_upgrade": { "$ref": "#/definitions/allow_websocket_upgrade" }, + "enable_proxy_protocol": { + "$ref": "#/definitions/enable_proxy_protocol" + }, + "load_balancer_ip": { + "$ref": "#/definitions/load_balancer_ip" + }, "access_list_id": { "$ref": "#/definitions/access_list_id" }, diff --git a/backend/schema/endpoints/streams.json b/backend/schema/endpoints/streams.json index 159c8036..1eaf5b2f 100644 --- a/backend/schema/endpoints/streams.json +++ b/backend/schema/endpoints/streams.json @@ -46,6 +46,21 @@ "udp_forwarding": { "type": "boolean" }, + "stream_enable_proxy_protocol": { + "description": "Enable PROXY Protocol creation and override", + "example": true, + "type": "boolean" + }, + "stream_allow_proxy_protocol": { + "description": "Enable PROXY Protocol pass through", + "example": true, + "type": "boolean" + }, + "stream_load_balancer_ip": { + "type": "string", + "minLength": 0, + "maxLength": 255 + }, "enabled": { "$ref": "../definitions.json#/definitions/enabled" }, @@ -78,6 +93,15 @@ "udp_forwarding": { "$ref": "#/definitions/udp_forwarding" }, + "stream_allow_proxy_protocol": { + "$ref": "#/definitions/stream_allow_proxy_protocol" + }, + "stream_enable_proxy_protocol": { + "$ref": "#/definitions/stream_enable_proxy_protocol" + }, + "stream_load_balancer_ip": { + "$ref": "#/definitions/stream_load_balancer_ip" + }, "enabled": { "$ref": "#/definitions/enabled" }, @@ -88,7 +112,7 @@ "links": [ { "title": "List", - "description": "Returns a list of Steams", + "description": "Returns a list of Streams", "href": "/nginx/streams", "access": "private", "method": "GET", @@ -137,6 +161,15 @@ "udp_forwarding": { "$ref": "#/definitions/udp_forwarding" }, + "stream_allow_proxy_protocol": { + "$ref": "#/definitions/stream_allow_proxy_protocol" + }, + "stream_enable_proxy_protocol": { + "$ref": "#/definitions/stream_enable_proxy_protocol" + }, + "stream_load_balancer_ip": { + "$ref": "#/definitions/stream_load_balancer_ip" + }, "meta": { "$ref": "#/definitions/meta" } @@ -177,6 +210,15 @@ "udp_forwarding": { "$ref": "#/definitions/udp_forwarding" }, + "stream_allow_proxy_protocol": { + "$ref": "#/definitions/stream_allow_proxy_protocol" + }, + "stream_enable_proxy_protocol": { + "$ref": "#/definitions/stream_enable_proxy_protocol" + }, + "stream_load_balancer_ip": { + "$ref": "#/definitions/stream_load_balancer_ip" + }, "meta": { "$ref": "#/definitions/meta" } @@ -190,7 +232,7 @@ }, { "title": "Delete", - "description": "Deletes a existing Stream", + "description": "Deletes an existing Stream", "href": "/nginx/streams/{definitions.identity.example}", "access": "private", "method": "DELETE", @@ -204,7 +246,7 @@ }, { "title": "Enable", - "description": "Enables a existing Stream", + "description": "Enables an existing Stream", "href": "/nginx/streams/{definitions.identity.example}/enable", "access": "private", "method": "POST", @@ -218,7 +260,7 @@ }, { "title": "Disable", - "description": "Disables a existing Stream", + "description": "Disables an existing Stream", "href": "/nginx/streams/{definitions.identity.example}/disable", "access": "private", "method": "POST", diff --git a/backend/templates/_listen.conf b/backend/templates/_listen.conf index 730f3a7c..d73d9b44 100644 --- a/backend/templates/_listen.conf +++ b/backend/templates/_listen.conf @@ -1,15 +1,25 @@ +{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true%} + listen 88 proxy_protocol; +{% if ipv6 -%} + listen [::]:88 proxy_protocol; +{% endif %} +{% else -%} listen 80; {% if ipv6 -%} listen [::]:80; -{% else -%} - #listen [::]:80; +{% endif %} {% endif %} {% if certificate -%} +{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true%} + listen 444 ssl{% if http2_support %} http2{% endif %} proxy_protocol; +{% if ipv6 -%} + listen [::]:444 ssl{% if http2_support %} http2{% endif %} proxy_protocol; +{% endif %} +{% else -%} listen 443 ssl{% if http2_support %} http2{% endif %}; {% if ipv6 -%} listen [::]:443 ssl{% if http2_support %} http2{% endif %}; -{% else -%} - #listen [::]:443; +{% endif %} {% endif %} {% endif %} server_name {{ domain_names | join: " " }}; diff --git a/backend/templates/_proxy_protocol.conf b/backend/templates/_proxy_protocol.conf new file mode 100644 index 00000000..cba0424f --- /dev/null +++ b/backend/templates/_proxy_protocol.conf @@ -0,0 +1,6 @@ +{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true %} +{% if load_balancer_ip != '' %} + set_real_ip_from {{ load_balancer_ip }}; + real_ip_header proxy_protocol; +{% endif %} +{% endif %} diff --git a/backend/templates/_stream_proxy_protocol.conf b/backend/templates/_stream_proxy_protocol.conf new file mode 100644 index 00000000..7275e4e5 --- /dev/null +++ b/backend/templates/_stream_proxy_protocol.conf @@ -0,0 +1,5 @@ +{%if stream_allow_proxy_protocol == 1 or stream_allow_proxy_protocol == true %} +{% if stream_load_balancer_ip != '' %} + set_real_ip_from {{ stream_load_balancer_ip }}; +{% endif %} +{% endif %} diff --git a/backend/templates/dead_host.conf b/backend/templates/dead_host.conf index d94dff57..b632933b 100644 --- a/backend/templates/dead_host.conf +++ b/backend/templates/dead_host.conf @@ -6,6 +6,7 @@ server { {% include "_certificates.conf" %} {% include "_hsts.conf" %} {% include "_forced_ssl.conf" %} +{% include "_proxy_protocol.conf" %} access_log /data/logs/dead-host-{{ id }}_access.log standard; error_log /data/logs/dead-host-{{ id }}_error.log warn; diff --git a/backend/templates/default.conf b/backend/templates/default.conf index ec68530c..9099f6ef 100644 --- a/backend/templates/default.conf +++ b/backend/templates/default.conf @@ -2,19 +2,25 @@ # Default Site # ------------------------------------------------------------ {% if value == "congratulations" %} -# Skipping output, congratulations page configration is baked in. +# Skipping output, congratulations page configuration is baked in. {%- else %} server { +{% if enable_proxy_protocol == 1 or enable_proxy_protocol == true%} + listen 88 proxy_protocol; +{% if ipv6 -%} + listen [::]:88 proxy_protocol; +{% endif %} +{% else -%} listen 80 default; {% if ipv6 -%} listen [::]:80 default; -{% else -%} - #listen [::]:80 default; +{% endif %} {% endif %} server_name default-host.localhost; access_log /data/logs/default-host_access.log combined; error_log /data/logs/default-host_error.log warn; {% include "_exploits.conf" %} +{% include "_proxy_protocol.conf"} include conf.d/include/letsencrypt-acme-challenge.conf; diff --git a/backend/templates/proxy_host.conf b/backend/templates/proxy_host.conf index ec30cca0..d733c853 100644 --- a/backend/templates/proxy_host.conf +++ b/backend/templates/proxy_host.conf @@ -12,6 +12,7 @@ server { {% include "_exploits.conf" %} {% include "_hsts.conf" %} {% include "_forced_ssl.conf" %} +{% include "_proxy_protocol.conf" %} {% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %} proxy_set_header Upgrade $http_upgrade; diff --git a/backend/templates/redirection_host.conf b/backend/templates/redirection_host.conf index 339fe72e..3e7e7eba 100644 --- a/backend/templates/redirection_host.conf +++ b/backend/templates/redirection_host.conf @@ -8,6 +8,7 @@ server { {% include "_exploits.conf" %} {% include "_hsts.conf" %} {% include "_forced_ssl.conf" %} +{% include "_proxy_protocol.conf" %} access_log /data/logs/redirection-host-{{ id }}_access.log standard; error_log /data/logs/redirection-host-{{ id }}_error.log warn; diff --git a/backend/templates/stream.conf b/backend/templates/stream.conf index 76159a64..5cce27cf 100644 --- a/backend/templates/stream.conf +++ b/backend/templates/stream.conf @@ -5,13 +5,16 @@ {% if enabled %} {% if tcp_forwarding == 1 or tcp_forwarding == true -%} server { - listen {{ incoming_port }}; + listen {{ incoming_port }}{% if stream_allow_proxy_protocol == 1 or stream_allow_proxy_protocol == true%} proxy_protocol{% endif %}; {% if ipv6 -%} - listen [::]:{{ incoming_port }}; + listen [::]:{{ incoming_port }}{% if stream_allow_proxy_protocol == 1 or stream_allow_proxy_protocol == true%} proxy_protocol{% endif %}; {% else -%} #listen [::]:{{ incoming_port }}; {% endif %} - +{%if stream_enable_proxy_protocol == 1 or stream_enable_proxy_protocol == true%} + proxy_protocol on; +{% endif %} + {% include '_stream_proxy_protocol.conf' %} proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; # Custom diff --git a/docker/Dockerfile b/docker/Dockerfile index 88f0b6e8..acb59359 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -24,6 +24,7 @@ ENV SUPPRESS_NO_CONFIG_WARNING=1 \ MODSEC_ENABLE="0" \ MODSEC_ADMIN_PANEL="0" \ CROWDSEC_UPDATE_DIR='/cs-update' \ + CROWDSEC_TEMPLATES='/crowdsec/templates' \ GEOLITE_DB_GRAB="0" \ GEOLITE2_DB_GRAB="0" \ GEOIP_DIR="/geoip_db" \ diff --git a/frontend/js/app/nginx/proxy/form.ejs b/frontend/js/app/nginx/proxy/form.ejs index 56868f55..9c30f13c 100644 --- a/frontend/js/app/nginx/proxy/form.ejs +++ b/frontend/js/app/nginx/proxy/form.ejs @@ -72,7 +72,7 @@ -