From 9863050d5da26dbcaaa69f7ef3a6ac01ea071936 Mon Sep 17 00:00:00 2001 From: Manuel Alejandro de Brito Fontes Date: Wed, 5 May 2021 07:51:58 -0400 Subject: [PATCH 1/4] Replace NGINX with Caddy --- .../proxy/debug/nginx-debug-logging.conf | 38 --- chart/config/proxy/lib.auth-monitor.conf | 17 -- chart/config/proxy/lib.cors-headers.conf | 34 --- chart/config/proxy/lib.cors-server.conf | 17 -- chart/config/proxy/lib.gitpod-plugins.conf | 73 ------ chart/config/proxy/lib.gzip-assets.conf | 7 - chart/config/proxy/lib.https_redirect.conf | 14 -- chart/config/proxy/lib.locations.conf | 187 -------------- chart/config/proxy/lib.log-headers.conf | 86 ------- chart/config/proxy/lib.proxy-api.conf | 12 - chart/config/proxy/lib.proxy.conf | 21 -- chart/config/proxy/lib.region-headers.conf | 3 - chart/config/proxy/lib.resolver.conf | 5 - chart/config/proxy/lib.ssl.conf | 15 -- .../proxy/lib.workspace-locations-path.conf | 17 -- .../config/proxy/lib.workspace-locations.conf | 19 -- .../proxy/lib.workspace-locations.ws.conf | 16 -- .../proxy/lib.workspace-port-locations.conf | 148 ----------- chart/config/proxy/lib.ws-sse.conf | 15 -- chart/config/proxy/nginx.conf | 58 ----- chart/config/proxy/status-endpoints.htpasswd | 1 - chart/config/proxy/vhost.cors.conf | 12 - chart/config/proxy/vhost.http-config.conf | 6 - .../proxy/vhost.map-api-request-uri.conf | 5 - chart/config/proxy/vhost.map-http-update.conf | 5 - chart/config/proxy/vhost.map-ws-sse.conf | 46 ---- .../proxy/vhost.server-8003-status.conf | 12 - chart/config/proxy/vhost.server.conf | 233 ------------------ chart/config/proxy/vhost.upstreams.conf | 30 --- chart/templates/_default.yaml | 2 - chart/templates/_helpers.tpl | 17 +- .../builtin-registry-auth-secret.yaml | 3 +- chart/templates/db-deployment.yaml | 1 - chart/templates/proxy-configmap-nginx.yaml | 23 -- chart/templates/proxy-deployment.yaml | 98 +------- .../templates/registry-facade-configmap.yaml | 7 - .../templates/registry-facade-daemonset.yaml | 12 +- chart/templates/ws-manager-configmap.yaml | 6 +- chart/templates/ws-proxy-configmap.yaml | 2 +- chart/values.yaml | 17 +- 40 files changed, 28 insertions(+), 1312 deletions(-) delete mode 100644 chart/config/proxy/debug/nginx-debug-logging.conf delete mode 100644 chart/config/proxy/lib.auth-monitor.conf delete mode 100644 chart/config/proxy/lib.cors-headers.conf delete mode 100644 chart/config/proxy/lib.cors-server.conf delete mode 100644 chart/config/proxy/lib.gitpod-plugins.conf delete mode 100644 chart/config/proxy/lib.gzip-assets.conf delete mode 100644 chart/config/proxy/lib.https_redirect.conf delete mode 100644 chart/config/proxy/lib.locations.conf delete mode 100644 chart/config/proxy/lib.log-headers.conf delete mode 100644 chart/config/proxy/lib.proxy-api.conf delete mode 100644 chart/config/proxy/lib.proxy.conf delete mode 100644 chart/config/proxy/lib.region-headers.conf delete mode 100644 chart/config/proxy/lib.resolver.conf delete mode 100644 chart/config/proxy/lib.ssl.conf delete mode 100644 chart/config/proxy/lib.workspace-locations-path.conf delete mode 100644 chart/config/proxy/lib.workspace-locations.conf delete mode 100644 chart/config/proxy/lib.workspace-locations.ws.conf delete mode 100644 chart/config/proxy/lib.workspace-port-locations.conf delete mode 100644 chart/config/proxy/lib.ws-sse.conf delete mode 100644 chart/config/proxy/nginx.conf delete mode 100644 chart/config/proxy/status-endpoints.htpasswd delete mode 100644 chart/config/proxy/vhost.cors.conf delete mode 100644 chart/config/proxy/vhost.http-config.conf delete mode 100644 chart/config/proxy/vhost.map-api-request-uri.conf delete mode 100644 chart/config/proxy/vhost.map-http-update.conf delete mode 100644 chart/config/proxy/vhost.map-ws-sse.conf delete mode 100644 chart/config/proxy/vhost.server-8003-status.conf delete mode 100644 chart/config/proxy/vhost.server.conf delete mode 100644 chart/config/proxy/vhost.upstreams.conf delete mode 100644 chart/templates/proxy-configmap-nginx.yaml diff --git a/chart/config/proxy/debug/nginx-debug-logging.conf b/chart/config/proxy/debug/nginx-debug-logging.conf deleted file mode 100644 index 1252aa4a3a3fef..00000000000000 --- a/chart/config/proxy/debug/nginx-debug-logging.conf +++ /dev/null @@ -1,38 +0,0 @@ -# helper config to debug lib.log-headers.conf - -# setup: -# apt-get install nginx nginx-extras lua-cjson lua-nginx-cookie - -# usage: -# nginx -c .conf - -# example: -# sudo nginx -c $(pwd)/charts/gitpod_io/charts/gitpod/config/proxy/debug/nginx-debug-logging.conf - -# don't fork to background -daemon off; - -include /etc/nginx/modules/*.conf; - -events { -} - -http { - lua_package_path "/usr/local/lib/lua/?/?.lua;/usr/share/lua/?/?.lua;;"; - - log_format mylogfmt escape=none $log_message_json; - - access_log /dev/stdout mylogfmt; - error_log /dev/stderr info; - - server { - - include ../lib.log-headers.conf; - listen 8080; - location / { - root html; - index index.html index.htm; - } - } -} - diff --git a/chart/config/proxy/lib.auth-monitor.conf b/chart/config/proxy/lib.auth-monitor.conf deleted file mode 100644 index 642ce0def1c1be..00000000000000 --- a/chart/config/proxy/lib.auth-monitor.conf +++ /dev/null @@ -1,17 +0,0 @@ -# Requires: -# - @error_generic - -# Internal location /auth/monitor for auth_request usage -location /auth/monitor { - include lib.proxy.conf; - internal; - - error_page 403 =200 @error_generic; - - proxy_pass http://apiserver/auth/monitor; - proxy_pass_request_body off; - proxy_set_header Content-Length ""; - proxy_set_header X-Original-URI $request_uri; - proxy_set_header X-Original-IP $remote_addr; - proxy_set_header Set-Cookie "gitpod=$cookie_gitpod"; -} diff --git a/chart/config/proxy/lib.cors-headers.conf b/chart/config/proxy/lib.cors-headers.conf deleted file mode 100644 index 93dd98842c5f11..00000000000000 --- a/chart/config/proxy/lib.cors-headers.conf +++ /dev/null @@ -1,34 +0,0 @@ -# !!! Be sure to put a -# include lib.cors-server.conf; -# into the server block you want to use this in! -# !!! - -more_set_headers "Access-Control-Allow-Origin: $cors_dynamic_origin"; -more_set_headers "Access-Control-Allow-Credentials: true"; - -# required to be able to read Authorization header in frontend -set $cors_expose_headers 'Authorization'; -if ($extra_cors_expose_headers) { - set $cors_expose_headers "${cors_expose_headers},${extra_cors_expose_headers}"; -} -more_set_headers "Access-Control-Expose-Headers: $cors_expose_headers"; - -set $cors_allowed_headers 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With'; -if ($extra_cors_allowed_headers) { - set $cors_allowed_headers "${cors_allowed_headers},${extra_cors_allowed_headers}"; -} - -set $cors_allowed_methods 'GET, POST, OPTIONS'; -if ($extra_cors_allowed_methods) { - set $cors_allowed_methods "${cors_allowed_methods},${extra_cors_allowed_methods}"; -} - -if ($cors_test = "+origin_matches+method_options") { - more_set_headers "Access-Control-Allow-Methods: $cors_allowed_methods"; - more_set_headers "Access-Control-Allow-Headers: $cors_allowed_headers"; - # Setting duration: 86400 (1 day) - more_set_headers "Access-Control-Max-Age: 60"; - more_set_headers "Content-Length: 0"; - more_set_headers "Content-Type: text/plain"; - return 200; -} diff --git a/chart/config/proxy/lib.cors-server.conf b/chart/config/proxy/lib.cors-server.conf deleted file mode 100644 index ad76043d0879cd..00000000000000 --- a/chart/config/proxy/lib.cors-server.conf +++ /dev/null @@ -1,17 +0,0 @@ -# CORS checks -# IFs need to be outside of location blocks to be processed (exception: IF block with return, e.g.) -# Is origin a subdomain of this domain? -set $cors_test ""; -if ($http_origin ~* ".*${PROXY_DOMAIN_REGEX}$") { - set $cors_test "${cors_test}+origin_matches"; -} - -# Is preflight OPTIONS request? -if ($request_method = 'OPTIONS') { - set $cors_test "${cors_test}+method_options"; -} - -# Initialize all $extra_cors_* variables -set $extra_cors_expose_headers ""; -set $extra_cors_allowed_headers ""; -set $extra_cors_allowed_methods ""; diff --git a/chart/config/proxy/lib.gitpod-plugins.conf b/chart/config/proxy/lib.gitpod-plugins.conf deleted file mode 100644 index 04863cadd36387..00000000000000 --- a/chart/config/proxy/lib.gitpod-plugins.conf +++ /dev/null @@ -1,73 +0,0 @@ -##### Gitpod Plugins -## -## 1. makes a preflight request to the Gitpod server -## - authorized using a token -## - passes to the real cloud storage url for upload/download -## -## 2. passes to the provided cloud URL -## - -set $action undefined; -set $type undefined; -if ($request_method = GET) { - set $type download; - set $action preflight; -} -if ($arg_checkin) { - set $action checkin; -} -if ($request_method = PUT) { - set $type upload; - set $action preflight; -} -# require `id` to be set -if ($arg_id ~ "^$") { - return 400 "Bad Request"; -} - -# ignore all other request types -if ($type = undefined) { - return 400 "Bad Request"; -} -set $qs "${query_string}"; -set $api_key ${SERVER_PROXY_APIKEY}; -set_by_lua_block $api_key_encoded { return ngx.encode_args({token = ngx.var.api_key}) } - -# Content-Type has to match exactly with the `getSignedUrl` request from gcloud-storage-client.ts -# otherwise the upload will fail with a "signature does not match" error. -proxy_set_header Content-Type '*/*'; - -if ($action = preflight) { - set $targetUrl "no-url"; - rewrite_by_lua_block { - url = "/plugins-preflight?type=" .. ngx.var.type .. "&" .. ngx.var.api_key_encoded .. "&" .. ngx.var.qs; - response = ngx.location.capture(url); - if response.status == ngx.HTTP_OK then - ngx.var.targetUrl = response.body; - ngx.log(ngx.ERR, " redirect to " .. ngx.var.targetUrl); - return ngx.redirect(ngx.var.targetUrl, 307); - else - ngx.log(ngx.ERR, "Bad Request: /plugins/preflight returned with code " .. response.status) - return ngx.exit(400) - end - } -} - -if ($action = checkin) { - proxy_pass http://apiserver/plugins/checkin?$api_key_encoded&$query_string; -} - -# hide original headers -proxy_hide_header x-guploader-uploadid; -proxy_hide_header etag; -proxy_hide_header x-goog-generation; -proxy_hide_header x-goog-metageneration; -proxy_hide_header x-goog-hash; -proxy_hide_header x-goog-stored-content-length; -proxy_hide_header x-gitpod-region; -proxy_hide_header x-goog-stored-content-encoding; -proxy_hide_header x-goog-storage-class; -proxy_hide_header x-goog-generation; -proxy_hide_header x-goog-metageneration; -proxy_hide_header cache-control; -proxy_hide_header expires; diff --git a/chart/config/proxy/lib.gzip-assets.conf b/chart/config/proxy/lib.gzip-assets.conf deleted file mode 100644 index a74e3ecd97bfd8..00000000000000 --- a/chart/config/proxy/lib.gzip-assets.conf +++ /dev/null @@ -1,7 +0,0 @@ -# Enable on-the-fly compression -gzip on; -gzip_types text/css application/javascript text/javascript application/wasm application/octet-stream image/svg+xml image/png; -gzip_min_length 1000; -gzip_proxied any; -# Support clients that are not able to understand gzip: -gunzip on; \ No newline at end of file diff --git a/chart/config/proxy/lib.https_redirect.conf b/chart/config/proxy/lib.https_redirect.conf deleted file mode 100644 index 6da0c986695299..00000000000000 --- a/chart/config/proxy/lib.https_redirect.conf +++ /dev/null @@ -1,14 +0,0 @@ - -set $https_test ""; - -if ($http_x_forwarded_proto != 'https' ) { - set $https_test "${https_test}+nhttps"; -} - -if ($http_x_glb_forwarded = 'true' ) { - set $https_test "${https_test}+gclb"; -} - -if ($https_test = '+nhttps+gclb') { - return 308 https://$host$request_uri; -} diff --git a/chart/config/proxy/lib.locations.conf b/chart/config/proxy/lib.locations.conf deleted file mode 100644 index e2cd618a3b3666..00000000000000 --- a/chart/config/proxy/lib.locations.conf +++ /dev/null @@ -1,187 +0,0 @@ -{{- $this := dict "root" . "gp" $.Values }} -include lib.resolver.conf; - -####################################################### -# Reverse-proxy for server service -####################################################### -##### Factory Links -location /github.com { - include lib.proxy.conf; - include lib.cors-headers.conf; - - # nginx needs a variable to be part of the proxy_pass target to rewrite the URI... - set $index_html '/index.html'; - proxy_pass http://dashboard$index_html; -} - - -##### Dashboard -location / { - include lib.proxy.conf; - include lib.cors-headers.conf; - - proxy_pass http://dashboard$request_uri; -} - -# location @error_404_dashboard { -# return 302 https://www.${PROXY_DOMAIN}$request_uri; -# } - -##### Authentication -# GitHub authentication callback endpoint does not like CORS headers -location = /auth/github/callback { - include lib.proxy.conf; - - proxy_pass http://apiserver$request_uri; -} - -# Other (GitLab) seem to do not mind -location /auth { - include lib.proxy.conf; - include lib.cors-headers.conf; - - proxy_pass http://apiserver$request_uri; -} - -##### Apps (e.g. prebuild app) -location /apps { - include lib.proxy.conf; - include lib.cors-headers.conf; - - proxy_pass http://apiserver$request_uri; -} - - -##### Gitpod plugins -location /plugins { - proxy_intercept_errors off; - proxy_cache off; - - # Set max body size to make big uploads work - client_max_body_size 2048m; - - # 1. makes a subrequest to `http://apiserver/plugins/preflight` (via the internal /plugins-preflight location) - # to obtain the target URL for upload/download - # 2. passes to a provided target URL - include lib.gitpod-plugins.conf; -} -location /plugins-preflight { - # this is an internal location used only for the subrequest (cf. /plugins) as - # it's not possible to pass from within the fetch in lua code. - internal; - proxy_read_timeout 3600s; - proxy_pass http://apiserver/plugins/preflight?$query_string; -} - - -##### Code Sync Storage -location /code-sync { - proxy_intercept_errors off; - proxy_cache off; - - set $extra_cors_allowed_methods 'DELETE'; - set $extra_cors_allowed_headers 'X-Account-Type,X-Client-Commit,X-Client-Name,X-Client-Version,X-Execution-Id,X-Machine-Id,X-Machine-Session-Id,X-User-Session-Id,If-Match,If-None-Match'; - set $extra_cors_expose_headers 'etag,x-operation-id,retry-after'; - include lib.cors-headers.conf; - - proxy_pass http://apiserver$request_uri; -} - -##### Workspace download -location /workspace-download { - set $qs "${request_uri}"; - set $targetUrl "no-url"; - rewrite_by_lua_block { - local url = "/internal-wsdl/" .. ngx.var.qs; - local response = ngx.location.capture(url); - if response.status == ngx.HTTP_OK then - ngx.var.targetUrl = response.body; - ngx.log(ngx.ERR, " redirect to " .. ngx.var.targetUrl); - return ngx.redirect(ngx.var.targetUrl, 303); - else - ngx.log(ngx.ERR, "Bad Request: /workspace-download/get returned with code " .. response.status) - return ngx.exit(400) - end - } - - # Google wants to see */* as content type due to the way we sign the URLs. - proxy_set_header content-type "*/*"; - # The browser needs to see the correct archive content type to trigger the download. - add_header content-type "application/tar+gzip"; - # Make sure we don't bleed error storage error pages - proxy_intercept_errors on; - # Don't cache the download - proxy_cache off; - - # hide original headers - proxy_hide_header x-guploader-uploadid; - proxy_hide_header etag; - proxy_hide_header x-goog-generation; - proxy_hide_header x-goog-metageneration; - proxy_hide_header x-goog-hash; - proxy_hide_header x-goog-stored-content-length; - proxy_hide_header x-gitpod-region; - proxy_hide_header x-goog-stored-content-encoding; - proxy_hide_header x-goog-storage-class; - proxy_hide_header x-goog-generation; - proxy_hide_header x-goog-metageneration; - proxy_hide_header cache-control; - proxy_hide_header expires; -} -location /internal-wsdl { - internal; - - proxy_read_timeout 3600s; - proxy_pass http://apiserver$request_uri; -} - - -##### API / auth -> server -### mapping $request_uri -> $request_uri_api_dropped: vhost.map-api-request-uri.conf - -# Websocket connections -location = /api/gitpod { - include lib.proxy-api.conf; - include lib.cors-headers.conf; - include lib.ws-sse.conf; - - proxy_pass http://ws-apiserver$request_uri_api_dropped; -} -location = /api/v1 { - include lib.proxy-api.conf; - include lib.cors-headers.conf; - include lib.ws-sse.conf; - - proxy_pass http://ws-apiserver$request_uri_api_dropped; -} - -# Default api base route -location /api { - include lib.proxy-api.conf; - include lib.cors-headers.conf; - proxy_set_header Connection ""; - - proxy_pass http://apiserver$request_uri_api_dropped; -} - -location /graphql { - include lib.proxy.conf; - include lib.cors-headers.conf; - - proxy_pass http://apiserver$request_uri; -} - -location @error_404 { - include lib.proxy.conf; - include lib.cors-headers.conf; - - # nginx needs a variable to be part of the proxy_pass target to rewrite the URI... - set $not_found '/404/'; - proxy_pass http://dashboard$not_found; -} - - -location @error_generic { - # Something really bad happened: One of the requested resources is not there, at all. Redirect to the generic error page - return 302 {{ template "gitpod.scheme" $this }}://{{.Values.hostname}}/sorry/#Error%20$upstream_status; -} diff --git a/chart/config/proxy/lib.log-headers.conf b/chart/config/proxy/lib.log-headers.conf deleted file mode 100644 index ee1ec7880111ea..00000000000000 --- a/chart/config/proxy/lib.log-headers.conf +++ /dev/null @@ -1,86 +0,0 @@ -# lua variables: https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/ -# nginx variables: http://nginx.org/en/docs/varindex.html - -# expectation1: https://cloud.google.com/logging/docs/structured-logging -# expectation2: https://cloud.google.com/error-reporting/docs/formatting-error-messages - - -set $log_message_json '{}'; - -log_by_lua_block { - local cjson = require("cjson") - local ck = require("cookie") - - -- extract all cookies - local cookie, err = ck:new() - local cookies = nil - if cookie then - local fields, err = cookie:get_all() - cookies = fields - end - - -- get sessionId from Gitpod-Session-Cookie - -- local gpCookie = ngx.var.cookie__gh_2088_staging_gitpod_io_ - local gpCookie = ngx.var.cookie_${PROXY_DOMAIN_COOKIE} - local gitpodSessionId = nil - if gpCookie then - local ss, se = string.find(gpCookie, "s%3A", 1, true) - local es, ee = string.find(gpCookie, ".", 1, true) - if se and es then - gitpodSessionId = string.sub(gpCookie, se + 1, es - 1) - end - end - - -- translate http-status-codes to GCP-severities - -- see https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity - local severity = 200 - local httpStatus = tonumber(ngx.var.status) - if httpStatus >= 500 then - severity = 500 - elseif httpStatus >= 400 then - severity = 400 - end - - local json = { - -- known fileds in 'httpRequest' get special highlighting in Stackdriver - -- see https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#httprequest - httpRequest={ - requestMethod=ngx.var.request_method, - requestUrl=ngx.var.uri, - requestSize=ngx.var.request_length, - status=ngx.var.status, - responseSize=ngx.var.bytes_sent, - userAgent=ngx.var.http_user_agent, - remoteIp=ngx.var.remote_addr, - serverIp=ngx.var.server_addr, - latency=ngx.var.request_time, - protocol=ngx.var.server_protocol, - }, - context={ - sessionId=gitpodSessionId - }, - severity=severity, - upstreamAddr=ngx.var.upstream_addr, - requestScheme=ngx.var.scheme, - requestHost=ngx.var.host, - requestTime=ngx.var.request_time, - remotePort=ngx.var.remote_port, - serverName=ngx.var.server_name, - serverPort=ngx.var.server_port, - connection=ngx.var.connection, - httpXGlbForwarded=ngx.var.http_x_glb_forwarded, - httpXTLSVersion=ngx.var.http_x_tls_version, - httpAuthorization=ngx.var.http_Authorization, - httpConnection=ngx.var.http_Connection, - httpUpgrade=ngx.var.http_Upgrade, - proxyHost=ngx.var.proxy_host, - proxyPort=ngx.var.proxy_port, - requestHeaders=ngx.req.get_headers(), - responseHeaders=ngx.resp.get_headers(), - gzipRatio=ngx.var.gzip_ratio - } - json.requestHeaders.cookie=nil - json.cookies=cookies - - ngx.var.log_message_json = cjson.encode(json) -} \ No newline at end of file diff --git a/chart/config/proxy/lib.proxy-api.conf b/chart/config/proxy/lib.proxy-api.conf deleted file mode 100644 index 559995718dca03..00000000000000 --- a/chart/config/proxy/lib.proxy-api.conf +++ /dev/null @@ -1,12 +0,0 @@ -####################################################### -# Reverse-proxy configuration -####################################################### -proxy_http_version 1.1; - -proxy_set_header Host $host; -proxy_set_header X-Real-IP $remote_addr; -proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; -proxy_set_header X-Forwarded-Proto $scheme; -proxy_set_header X-Forwarded-Host $host:$server_port; - -proxy_intercept_errors off; \ No newline at end of file diff --git a/chart/config/proxy/lib.proxy.conf b/chart/config/proxy/lib.proxy.conf deleted file mode 100644 index 380ed87948e4de..00000000000000 --- a/chart/config/proxy/lib.proxy.conf +++ /dev/null @@ -1,21 +0,0 @@ -####################################################### -# Reverse-proxy configuration -####################################################### -proxy_http_version 1.1; - -# The following two lines was added because we saw a lot of "upstream timed out (110: Connection timed out)" errors occasionally -# Googling revealed basically two answers: -# - Increase proxy_connect_timeout/proxy_read_timeout -# - Clear "Connection" header (this stackoverlfow answer, for example: https://stackoverflow.com/questions/24453388/nginx-reverse-proxy-causing-504-gateway-timeout/36589120#36589120) -# This is also suggested in the docs (without further explanation): http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive -#proxy_http_version 1.1; <-- already set above -proxy_set_header Connection ""; -# - -proxy_set_header Host $host; -proxy_set_header X-Real-IP $remote_addr; -proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; -proxy_set_header X-Forwarded-Proto $scheme; -proxy_set_header X-Forwarded-Host $host:$server_port; - -proxy_intercept_errors on; \ No newline at end of file diff --git a/chart/config/proxy/lib.region-headers.conf b/chart/config/proxy/lib.region-headers.conf deleted file mode 100644 index c4b11cefc6d386..00000000000000 --- a/chart/config/proxy/lib.region-headers.conf +++ /dev/null @@ -1,3 +0,0 @@ -{{- $this := dict "root" . "gp" $.Values }} -# Sets a header in the response which tells us from which cluster this response came from. Should be rather useful for debugging. -more_set_headers "X-Gitpod-Region: {{ template "gitpod.installation.longname" $this }}"; \ No newline at end of file diff --git a/chart/config/proxy/lib.resolver.conf b/chart/config/proxy/lib.resolver.conf deleted file mode 100644 index 159f7b6056f192..00000000000000 --- a/chart/config/proxy/lib.resolver.conf +++ /dev/null @@ -1,5 +0,0 @@ -####################################################### -# Kubernetes internal DNS server: nameserver IP is set in /etc/resolv.conf by kubernetes -# We use envsubst to replace $NAMESERVER in nginx.sh on container startup -####################################################### -resolver $NAMESERVER valid=5s ipv6=off; diff --git a/chart/config/proxy/lib.ssl.conf b/chart/config/proxy/lib.ssl.conf deleted file mode 100644 index 98f086b5f67a55..00000000000000 --- a/chart/config/proxy/lib.ssl.conf +++ /dev/null @@ -1,15 +0,0 @@ -ssl_protocols TLSv1.2; -ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'; -ssl_prefer_server_ciphers on; - -ssl_certificate /etc/nginx/certificates/fullchain.pem; -ssl_trusted_certificate /etc/nginx/certificates/fullchain.pem; -ssl_certificate_key /etc/nginx/certificates/privkey.pem; - -{{- if .Values.components.proxy.sslDHParam }} -ssl_dhparam /etc/nginx/ssl-dhparam/dh.key; -{{ end }} - -add_header Strict-Transport-Security "max-age=31557600"; -ssl_stapling on; -ssl_stapling_verify on; \ No newline at end of file diff --git a/chart/config/proxy/lib.workspace-locations-path.conf b/chart/config/proxy/lib.workspace-locations-path.conf deleted file mode 100644 index e243c5f65a7c0b..00000000000000 --- a/chart/config/proxy/lib.workspace-locations-path.conf +++ /dev/null @@ -1,17 +0,0 @@ - -location /workspace/ { - include lib.proxy.conf; - include lib.ws-sse.conf; - - # Increase connect timeout - proxy_connect_timeout 10s; - - # Set max body size to make big uploads work - client_max_body_size 2048m; - - # disable the error log to not spam our logs when the kube DNS doesn't know about the service yet - error_log off; - - proxy_set_header x-wsproxy-host $host; - proxy_pass http://wsproxy$request_uri; -} diff --git a/chart/config/proxy/lib.workspace-locations.conf b/chart/config/proxy/lib.workspace-locations.conf deleted file mode 100644 index e853dffd671abe..00000000000000 --- a/chart/config/proxy/lib.workspace-locations.conf +++ /dev/null @@ -1,19 +0,0 @@ -{{- $this := dict "root" . "gp" $.Values }} -include lib.resolver.conf; - -location / { - include lib.proxy.conf; - include lib.ws-sse.conf; - - # Increase connect timeout - proxy_connect_timeout 10s; - - # Set max body size to make big uploads work - client_max_body_size 2048m; - - # disable the error log to not spam our logs when the kube DNS doesn't know about the service yet - error_log off; - - proxy_set_header x-wsproxy-host $host; - proxy_pass https://wsproxy$request_uri; -} diff --git a/chart/config/proxy/lib.workspace-locations.ws.conf b/chart/config/proxy/lib.workspace-locations.ws.conf deleted file mode 100644 index 36744f4d3d309c..00000000000000 --- a/chart/config/proxy/lib.workspace-locations.ws.conf +++ /dev/null @@ -1,16 +0,0 @@ -include lib.proxy.conf; -include lib.ws-sse.conf; - -# Increase connect timeout -proxy_connect_timeout 10s; - -# On connection errors, redirect to workspace page -error_page 502 504 =200 @workspace_not_found; - -# CORS -include lib.cors-headers.conf; - -# disable the error log to not spam our logs when the kube DNS doesn't know about the service yet -error_log off; - -proxy_pass http://ws-${wsid}-theia.${KUBE_NAMESPACE}.svc.cluster.local:{{ .Values.components.workspace.ports.http.containerPort }}$request_uri; \ No newline at end of file diff --git a/chart/config/proxy/lib.workspace-port-locations.conf b/chart/config/proxy/lib.workspace-port-locations.conf deleted file mode 100644 index c5e86ec78400e9..00000000000000 --- a/chart/config/proxy/lib.workspace-port-locations.conf +++ /dev/null @@ -1,148 +0,0 @@ -{{- $cookieName := $.Values.hostname | replace " " "_" | replace "-" "_" | replace "." "_" | lower -}} -{{- $this := dict "root" . "gp" $.Values }} - -include lib.resolver.conf; - -{{- $wsProxy := .Values.components.wsProxy -}} -{{- if (and $wsProxy (not $wsProxy.disabled)) }} -location / { - include lib.proxy.conf; - include lib.ws-sse.conf; - - # Increase connect timeout - proxy_connect_timeout 10s; - - # Set max body size to make big uploads work - client_max_body_size 2048m; - - # disable the error log to not spam our logs when the kube DNS doesn't know about the service yet - error_log off; - - proxy_set_header x-wsproxy-host $host; - proxy_pass https://wsproxy$request_uri; -} -{{- else }} - -location / { - include lib.proxy.conf; - include lib.ws-sse.conf; - - # Increase connect timeout - proxy_connect_timeout 10s; - - # Set max body size to make big uploads work - client_max_body_size 2048m; - - # Rewrite redirects to correct protocol - proxy_redirect "http://" "{{ template "gitpod.scheme" $this }}://"; - - # Add Gitpod specific pseudo headers - add_header X-Gitpod-WorkspaceId "$wsid" always; - add_header X-Gitpod-Port "$port" always; - - # Fix iFrame headers - proxy_hide_header X-Frame-Options; - - # Authentication - auth_request /auth/workspace-port; - - # Do NOT forward Gitpod cookies (main cookie/port auth cookies) to services running inside a workspace! - # As this is too complex to put into map + regex we do this with lua - access_by_lua_block { - local ck = require("cookie") - local filtered_cookies = {} - local filtered_port_auth_cookies = {} - local cookie_obj = ck:new() - - local cookies, err = cookie_obj:get_all() - if err then - -- Cookie header is not present - return - end - - local function ends_with(str, ending) - return ending == "" or str:sub(-#ending) == ending - end - - for k, v in pairs(cookies) do - if (not ends_with(k, "_{{ $cookieName }}_")) and (not ends_with(k, "_port_auth_")) then - filtered_cookies[#filtered_cookies+1] = k .. "=" .. v - end - end - - if filtered_cookies == {} then - ngx.req.set_header("Cookie", nil) - else - ngx.req.set_header("Cookie", table.concat(filtered_cookies, "; ")) - end - } - - # Handle workspace port not open/app not running - error_page 502 504 =200 @workspace_port_not_found; - - proxy_pass http://ws-${wsid}-ports.${KUBE_NAMESPACE}.svc.cluster.local:$port$request_uri; -} -{{- end }} - -location @workspace_port_not_found { - include lib.proxy.conf; - include lib.cors-headers.conf; - - # FIXME: We accidentally break '304 Not Modified' responses by forcing the HTTP response code to - # '200 OK' (but keeping the response body empty) thus causing a pure white page in the browser. - - # To work around this, we kill any cache here. - # Source: https://stackoverflow.com/a/45285696/1035471 - add_header Last-Modified $date_gmt; - add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; - if_modified_since off; - expires off; - etag off; - - set $port_not_found '/port-not-found/'; - proxy_pass http://dashboard$port_not_found; -} - -location /auth/workspace-port { - include lib.proxy.conf; - internal; - - proxy_pass_request_body off; - proxy_set_header Content-Length ""; - client_max_body_size 0; - - proxy_set_header X-Original-URI $request_uri; - proxy_set_header X-Original-IP $remote_addr; - - # We translate the [...]_port_auth_ cookies into a single header of the form "(; )*" - set_by_lua_block $gitpod_port_auth { - local ck = require("cookie") - local filtered_port_auth_cookies = {} - local cookie_obj = ck:new() - - local cookies, err = cookie_obj:get_all() - if err then - -- Cookie header is not present - return - end - - local function ends_with(str, ending) - return ending == "" or str:sub(-#ending) == ending - end - - for k, v in pairs(cookies) do - if ends_with(k, "_port_auth_") then - filtered_port_auth_cookies[#filtered_port_auth_cookies+1] = k .. "=" .. v - end - end - - if filtered_port_auth_cookies == {} then - return nil - else - return table.concat(filtered_port_auth_cookies, "; ") - end - } - proxy_set_header X-Gitpod-Port-Auth $gitpod_port_auth; - - proxy_pass http://apiserver/auth/workspace-port/$port; -} \ No newline at end of file diff --git a/chart/config/proxy/lib.ws-sse.conf b/chart/config/proxy/lib.ws-sse.conf deleted file mode 100644 index e10f81d3d452ba..00000000000000 --- a/chart/config/proxy/lib.ws-sse.conf +++ /dev/null @@ -1,15 +0,0 @@ -# Set these values based on per-request decisions make in vhost.map-ws-sse.conf - -proxy_set_header Upgrade $connection_type_header_upgrade; -proxy_set_header Connection $connection_type_header_connection; - -proxy_cache off; - -# All these would be nice to have separate for ws/sse/default, but nginx does not support variables for them, so we set -# them to a sane lower bound -#proxy_read_timeout $connection_type_read_timeout; -proxy_read_timeout 60s; - -# Needed for SSE only! -#proxy_buffering $connection_type_buffering; -proxy_buffering off; \ No newline at end of file diff --git a/chart/config/proxy/nginx.conf b/chart/config/proxy/nginx.conf deleted file mode 100644 index df87bb18a65e9d..00000000000000 --- a/chart/config/proxy/nginx.conf +++ /dev/null @@ -1,58 +0,0 @@ -#### -# This configuration is based on the default config shipped with nginx, tweaked for handling more parallel connections. -user nobody; -pid /run/nginx.pid; - -## -# Worker and event configuration -## -# We don't rely on 'worker_processes auto;' as we run in docker -worker_processes 4; -worker_rlimit_nofile 24000; - -events { - worker_connections 20000; # Must be smaller than worker_rlimit_nofile -} - -http { - - ## - # Basic Settings (taken from default nginx.conf) - ## - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - types_hash_max_size 2048; - include /etc/nginx/mime.types; - default_type application/octet-stream; - - # Remove nginx server header - # http://nginx.org/en/docs/http/ngx_http_core_module.html#server_tokens - server_tokens off; - more_clear_headers Server; - - # See Move default writable paths to a dedicated directory (#119) - # https://github.com/openresty/docker-openresty/issues/119 - client_body_temp_path /var/run/openresty/nginx-client-body; - proxy_temp_path /var/run/openresty/nginx-proxy; - fastcgi_temp_path /var/run/openresty/nginx-fastcgi; - uwsgi_temp_path /var/run/openresty/nginx-uwsgi; - scgi_temp_path /var/run/openresty/nginx-scgi; - - ## - # Logging Settings - log_format mylogfmt escape=none $log_message_json; - access_log /dev/stdout mylogfmt; - error_log /dev/stderr info; - - ## - # Gzip Settings - ## - include /etc/nginx/lib.gzip-assets.conf; - - ## - # Virtual Host Configs - ## - include /etc/nginx/vhost.*.conf; -} diff --git a/chart/config/proxy/status-endpoints.htpasswd b/chart/config/proxy/status-endpoints.htpasswd deleted file mode 100644 index 5eaaf212625296..00000000000000 --- a/chart/config/proxy/status-endpoints.htpasswd +++ /dev/null @@ -1 +0,0 @@ -{{ .Values.components.proxy.statusAuth }} diff --git a/chart/config/proxy/vhost.cors.conf b/chart/config/proxy/vhost.cors.conf deleted file mode 100644 index 11110f65da2d3c..00000000000000 --- a/chart/config/proxy/vhost.cors.conf +++ /dev/null @@ -1,12 +0,0 @@ -# For CORS with credentials, we cannot respond with a simple '*': https://developer.mozilla.org/docs/Web/HTTP/CORS#Requests_with_credentials -# Therefore, we want to answer the incoming request with it's own $http_host - if it is a subdomain of the base domain - -# map is only allowed in context 'http' -map $http_origin $cors_dynamic_origin { - volatile; - - default $scheme://{{.Values.hostname}}; - - ~*(?.*\.${PROXY_DOMAIN_REGEX})$ $full_req_host; -} - diff --git a/chart/config/proxy/vhost.http-config.conf b/chart/config/proxy/vhost.http-config.conf deleted file mode 100644 index 628e73dce95a8f..00000000000000 --- a/chart/config/proxy/vhost.http-config.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Needed for long map s (?) -variables_hash_max_size 2048; -variables_hash_bucket_size 256; - -# Needed for long server_name s (?) -server_names_hash_bucket_size 256; \ No newline at end of file diff --git a/chart/config/proxy/vhost.map-api-request-uri.conf b/chart/config/proxy/vhost.map-api-request-uri.conf deleted file mode 100644 index 233d8654d4b12d..00000000000000 --- a/chart/config/proxy/vhost.map-api-request-uri.conf +++ /dev/null @@ -1,5 +0,0 @@ -# We want to drop the leading '/api' before forwarding requests to the server -map $request_uri $request_uri_api_dropped { - "~/api(?.*)" "$trailing"; - default $request_uri; -} \ No newline at end of file diff --git a/chart/config/proxy/vhost.map-http-update.conf b/chart/config/proxy/vhost.map-http-update.conf deleted file mode 100644 index 291399473bcac9..00000000000000 --- a/chart/config/proxy/vhost.map-http-update.conf +++ /dev/null @@ -1,5 +0,0 @@ -# Allows us to send the header 'Connection: upgrade' to workspace services only if they requested it -map $http_upgrade $ws_connection_upgrade { - default upgrade; - '' ''; -} \ No newline at end of file diff --git a/chart/config/proxy/vhost.map-ws-sse.conf b/chart/config/proxy/vhost.map-ws-sse.conf deleted file mode 100644 index b99160dd2daf36..00000000000000 --- a/chart/config/proxy/vhost.map-ws-sse.conf +++ /dev/null @@ -1,46 +0,0 @@ -# This whole file is a hack because nginx does not allow to use proxy_set_header inside if-blocks... -# This solution is problematic in that it might override default values, as we in some cases have no way in reading -# those and provide them as "default" case. But still better then nothing. - -# The decisions here lead to values being set in lib.ws-sse.conf - -# Detect connection type -# Rules (order matters!): -# - Accept: text/event-stream? => Server Side Event -# - No sse, and empty/no upgrade header => nothing -# - No sse, and Upgrade header set => websocket -map $http_upgrade:$http_accept $connection_type { - ~"*:text/event-stream" "+sse"; - ~":*" ""; - ~"*:*" "+ws"; - default ""; -} - -# proxy_set_header Upgrade $connection_type_header_upgrade; -map $connection_type $connection_type_header_upgrade { - "+ws" $http_upgrade; - "+sse" ""; - default $http_upgrade; -} - -# proxy_set_header Connection $connection_type_header_connection; -map $connection_type $connection_type_header_connection { - "+ws" "upgrade"; - "+sse" ""; - default $http_connection; -} - -# All these would be nice to have separate for ws/sse/default, but nginx does not support variables for them -# # proxy_read_timeout $connection_type_read_timeout; -# map $connection_type $connection_type_read_timeout { -# "+ws" 300s; -# "+sse" 300s; -# default 60s; -# } - -# # proxy_buffering $connection_type_buffering; -# map $connection_type $connection_type_buffering { -# "+ws" "on"; -# "+sse" "off"; -# default "on"; -# } diff --git a/chart/config/proxy/vhost.server-8003-status.conf b/chart/config/proxy/vhost.server-8003-status.conf deleted file mode 100644 index 2000ed13f7f3ba..00000000000000 --- a/chart/config/proxy/vhost.server-8003-status.conf +++ /dev/null @@ -1,12 +0,0 @@ -server { - listen 8003; - - # log is disabled - # include lib.log-headers.conf; - - location = /nginx/status { - access_log off; - default_type text/plain; - return 200 "alive"; - } -} \ No newline at end of file diff --git a/chart/config/proxy/vhost.server.conf b/chart/config/proxy/vhost.server.conf deleted file mode 100644 index 6b37179b6bf116..00000000000000 --- a/chart/config/proxy/vhost.server.conf +++ /dev/null @@ -1,233 +0,0 @@ -{{- $this := dict "root" . "gp" $.Values -}} -{{- $domain := $.Values.hostname -}} -{{- $useHttps := eq (include "gitpod.scheme" $this) "https" -}} -{{- $builtinRegistry := (index .Values "docker-registry" "enabled") -}} -{{- $builtinRegistryBypassProxy := (index .Values.components.imageBuilder.registry.bypassProxy ) -}} -{{- $builtinMinio := (index .Values "minio" "enabled") -}} -{{- $listen := index ( dict "true" "443 ssl" "false" "80" ) ( $useHttps | toString ) -}} - -{{ if $useHttps }} -server { - listen 80 default_server; - server_name ~^(?.+\.)?${PROXY_DOMAIN_REGEX}$; - - include lib.region-headers.conf; - include lib.log-headers.conf; - - return 301 https://${sdprefix}{{ $domain }}$request_uri; -} - -server { - listen 80; - server_name health.{{ $domain }}; - - include lib.region-headers.conf; - # log is disabled - # include lib.log-headers.conf; - - location = /nginx/status { - access_log off; - default_type text/plain; - return 200 "alive"; - } -} -{{ end }} - -server { - listen {{ $listen }} default_server; - - server_name {{ $domain }} www.{{ $domain }} _; - -{{- if $useHttps }} - include lib.ssl.conf; - include lib.https_redirect.conf; -{{- end }} - - include lib.cors-server.conf; - include lib.locations.conf; - include lib.region-headers.conf; - include lib.log-headers.conf; -} - -# Deprecated: Leave here for backwards compatibility during rollout -# TODO API_REMAP_CLEANUP Delete -server { - listen {{ $listen }}; - server_name api.{{ $domain }}; - -{{- if $useHttps }} - include lib.ssl.conf; - include lib.https_redirect.conf; -{{- end }} - - include lib.cors-server.conf; - include lib.region-headers.conf; - include lib.log-headers.conf; - - location / { - return 301 $scheme://{{ $domain }}/api$request_uri; - } -} - -{{- if and $builtinRegistry (not $builtinRegistryBypassProxy) }} -server { - listen {{ $listen }}; - server_name registry.{{ $domain }}; - -{{- if $useHttps }} - include lib.ssl.conf; - include lib.https_redirect.conf; -{{- end }} - - include lib.resolver.conf; - include lib.cors-server.conf; - include lib.region-headers.conf; - include lib.log-headers.conf; - include lib.proxy.conf; - - client_max_body_size 0; - - location / { - auth_basic "Docker Registry"; - auth_basic_user_file /etc/nginx/registry-auth.htpasswd; - proxy_pass https://{{ index .Values "docker-registry" "fullnameOverride" }}.{{ .Release.Namespace }}.svc.cluster.local$request_uri; - } -} -{{ end -}} - -{{- if $builtinMinio }} -server { - listen {{ $listen }}; - server_name minio.{{ $domain }}; - -{{- if $useHttps }} - include lib.ssl.conf; - include lib.https_redirect.conf; -{{- end }} - - include lib.resolver.conf; - include lib.cors-server.conf; - include lib.region-headers.conf; - include lib.log-headers.conf; - include lib.proxy.conf; - - client_max_body_size 0; - - location / { - proxy_pass http://{{ index .Values "minio" "fullnameOverride" }}.{{ .Release.Namespace }}.svc.cluster.local:9000$request_uri; - } -} -{{ end -}} - -# TODO(geropl): is there a nicer way to configure an additional ws subdomain? -{{- if .Values.components.proxy.withWsCluster }} -# Workspaces/Blobserve - proxy passing to WS proxy -server { - listen {{ $listen }}; - # Matches: - # - (webview-|browser-|extensions-)?+ foreign content prefix including UUID (optional). This must be possesive (?+) to not confuse "webview-8000-a1231-..." with a valid UUID - # - (?[a-z][0-9a-z\-]+) workspace Id or blobserve - # - \.ws(-[a-z0-9]+)? workspace base domain - server_name ~^(webview-|browser-|extensions-)?+(?[a-z0-9][0-9a-z\-]+)\.ws-{{ .Values.components.proxy.withWsCluster.shortname }}\.${PROXY_DOMAIN_REGEX}$; - -{{- if $useHttps }} - include lib.ssl.conf; - include lib.https_redirect.conf; -{{- end }} - - # include lib.workspace-locations.conf; - include lib.region-headers.conf; - include lib.log-headers.conf; - - include lib.resolver.conf; - location / { - include lib.proxy.conf; - include lib.ws-sse.conf; - - # Increase connect timeout - proxy_connect_timeout 10s; - - # Set max body size to make big uploads work - client_max_body_size 2048m; - - # disable the error log to not spam our logs when the kube DNS doesn't know about the service yet - error_log off; - - proxy_pass http://ws-proxy.{{ .Values.components.proxy.withWsCluster.namespace }}.svc.cluster.local:8080$request_uri; - } -} - -server { - listen {{ $listen }}; - # Matches: - # - (webview-|browser-|extensions-)?+ for now, we only support Theia webviews here! (TODO is there a - meaningful - way to generalize this?) - # - (?[0-9]{2,5})- port to forward to - # - (?[a-z][0-9a-z\-]+) workspace Id - # - \.ws(-[a-z0-9]+)? workspace base domain - # "" needed because of {} (nginx syntax wart) - server_name "~^(webview-|browser-|extensions-)?+(?[0-9]{2,5})-(?[a-z0-9][0-9a-z\-]+)\.ws-{{ .Values.components.proxy.withWsCluster.shortname }}\.${PROXY_DOMAIN_REGEX}$"; - -{{- if $useHttps }} - include lib.ssl.conf; - include lib.https_redirect.conf; -{{- end }} - - # include lib.workspace-port-locations.conf; - include lib.region-headers.conf; - - include lib.resolver.conf; - location / { - include lib.proxy.conf; - include lib.ws-sse.conf; - - # Increase connect timeout - proxy_connect_timeout 10s; - - # Set max body size to make big uploads work - client_max_body_size 2048m; - - # disable the error log to not spam our logs when the kube DNS doesn't know about the service yet - error_log off; - - proxy_pass http://ws-proxy.{{ .Values.components.proxy.withWsCluster.namespace }}.svc.cluster.local:8080$request_uri; - } -} -{{ end -}} - -# Workspaces/Blobserve - proxy passing to WS proxy -server { - listen {{ $listen }}; - # Matches: - # - (webview-|browser-|extensions-)?+ foreign content prefix including UUID (optional). This must be possesive (?+) to not confuse "webview-8000-a1231-..." with a valid UUID - # - (?[a-z][0-9a-z\-]+) workspace Id or blobserve - # - \.ws(-[a-z0-9]+)? workspace base domain - server_name ~^(webview-|browser-|extensions-)?+(?[a-z0-9][0-9a-z\-]+)\.ws(-[a-z0-9]+)?\.${PROXY_DOMAIN_REGEX}$; - -{{- if $useHttps }} - include lib.ssl.conf; - include lib.https_redirect.conf; -{{- end }} - - include lib.workspace-locations.conf; - include lib.region-headers.conf; - include lib.log-headers.conf; -} - -server { - listen {{ $listen }}; - # Matches: - # - (webview-|browser-|extensions-)?+ for now, we only support Theia webviews here! (TODO is there a - meaningful - way to generalize this?) - # - (?[0-9]{2,5})- port to forward to - # - (?[a-z][0-9a-z\-]+) workspace Id - # - \.ws(-[a-z0-9]+)? workspace base domain - # "" needed because of {} (nginx syntax wart) - server_name "~^(webview-|browser-|extensions-)?+(?[0-9]{2,5})-(?[a-z0-9][0-9a-z\-]+)\.ws(-[a-z0-9]+)?\.${PROXY_DOMAIN_REGEX}$"; - -{{- if $useHttps }} - include lib.ssl.conf; - include lib.https_redirect.conf; -{{- end }} - - include lib.workspace-port-locations.conf; - include lib.region-headers.conf; -} diff --git a/chart/config/proxy/vhost.upstreams.conf b/chart/config/proxy/vhost.upstreams.conf deleted file mode 100644 index 080da57325d30b..00000000000000 --- a/chart/config/proxy/vhost.upstreams.conf +++ /dev/null @@ -1,30 +0,0 @@ -# Short, namespace-relative names (like "server" or even "server.default") do not work here! -upstream apiserver { - server server.${KUBE_NAMESPACE}.svc.cluster.local:3000; - - # Keep up to 100 connections to upstream alive and re-use them for faster responses - keepalive 100; -} - -# Extra upstream that does NOT cache connections to backend -upstream ws-apiserver { - server server.${KUBE_NAMESPACE}.svc.cluster.local:3000; -} - -upstream dashboard { - server dashboard.${KUBE_NAMESPACE}.svc.cluster.local:3001; - - # Keep up to 100 connections to upstream alive and re-use them for faster responses - keepalive 100; -} - -# TODO WSPROXY: remove conditional -{{- $wsProxy := .Values.components.wsProxy -}} -{{- if (and $wsProxy (not $wsProxy.disabled)) }} -upstream wsproxy { - server ws-proxy.${KUBE_NAMESPACE}.svc.cluster.local:9090; - - # Keep up to 100 connections to upstream alive and re-use them for faster responses - keepalive 100; -} -{{- end }} \ No newline at end of file diff --git a/chart/templates/_default.yaml b/chart/templates/_default.yaml index 4d9496f9734d6b..f30c9d478889f7 100644 --- a/chart/templates/_default.yaml +++ b/chart/templates/_default.yaml @@ -25,7 +25,6 @@ metadata: spec: ports: {{- range $key, $val := $comp.ports }} - {{- if $val.expose }} - name: {{ $key | lower }} protocol: TCP {{ if $val.nodePort -}}nodePort: {{ $val.nodePort }}{{ end }} @@ -35,7 +34,6 @@ spec: {{- else -}} port: {{ $val.containerPort }} {{ end -}} - {{- end -}} {{ end }} {{- if $comp.portRange }} {{- range $index, $port := untilStep (int $comp.portRange.start) (int (add $comp.portRange.end 1)) 1 }} diff --git a/chart/templates/_helpers.tpl b/chart/templates/_helpers.tpl index 38a1c078056a30..dd50496602f9b1 100644 --- a/chart/templates/_helpers.tpl +++ b/chart/templates/_helpers.tpl @@ -160,15 +160,6 @@ affinity: {{ include "gitpod.container.dbEnv" . | indent 2 }} {{- end -}} -{{- define "gitpod.scheme" -}} -{{- $gp := .gp -}} -{{- if or $gp.certificatesSecret.secretName $gp.forceHTTPS -}} -https -{{- else -}} -http -{{- end -}} -{{- end -}} - {{- define "gitpod.container.defaultEnv" -}} {{- $ := .root -}} {{- $gp := .gp -}} @@ -179,14 +170,18 @@ env: valueFrom: fieldRef: fieldPath: metadata.namespace +- name: KUBE_DOMAIN + value: "{{ $gp.installation.kubedomain | default "svc.cluster.local" }}" {{- if not .noVersion }} - name: VERSION value: "{{ $gp.version }}" {{- end }} +- name: GITPOD_DOMAIN + value: {{ $gp.hostname | quote }} - name: HOST_URL - value: "{{- template "gitpod.scheme" . -}}://{{ $gp.hostname }}" + value: "https://{{ $gp.hostname }}" - name: GITPOD_REGION - value: "{{ $gp.installation.region }}" + value: {{ $gp.installation.region | quote }} - name: GITPOD_INSTALLATION_LONGNAME value: {{ template "gitpod.installation.longname" . }} - name: GITPOD_INSTALLATION_SHORTNAME diff --git a/chart/templates/builtin-registry-auth-secret.yaml b/chart/templates/builtin-registry-auth-secret.yaml index 4822fca5af0e2d..e8d67e95a10cfe 100644 --- a/chart/templates/builtin-registry-auth-secret.yaml +++ b/chart/templates/builtin-registry-auth-secret.yaml @@ -6,6 +6,7 @@ auths: {{ template "gitpod.builtinRegistry.name" . }}: auth: {{ printf "%s:%s" .username .password | b64enc | quote }} {{- end -}} + {{- if index .Values "docker-registry" "enabled" -}} {{- if index .Values "docker-registry" "authentication" -}} {{ $t := set . "username" (index .Values "docker-registry" "authentication" "username") }} @@ -28,4 +29,4 @@ data: .dockerconfigjson: {{ include "builtin-registry-auth-content" . | fromYaml | toJson | b64enc }} user: {{ .username | b64enc }} password: {{ .password | b64enc }} -{{- end -}} \ No newline at end of file +{{- end -}} diff --git a/chart/templates/db-deployment.yaml b/chart/templates/db-deployment.yaml index ed24730750c80a..dcfd53f67aaed6 100644 --- a/chart/templates/db-deployment.yaml +++ b/chart/templates/db-deployment.yaml @@ -14,7 +14,6 @@ metadata: kind: deployment stage: {{ .Values.installation.stage }} spec: - replicas: 1 strategy: type: RollingUpdate rollingUpdate: diff --git a/chart/templates/proxy-configmap-nginx.yaml b/chart/templates/proxy-configmap-nginx.yaml deleted file mode 100644 index acab6af0255827..00000000000000 --- a/chart/templates/proxy-configmap-nginx.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2020 Gitpod GmbH. All rights reserved. -# Licensed under the MIT License. See License-MIT.txt in the project root for license information. - -{{ define "get-proxy-config" -}} -{{- $root := . -}} -{{- range $path, $bytes := .Files.Glob "config/proxy/*" -}} -{{ base $path }}: |- -{{ $root.Files.Get $path | indent 2 }} -{{ end -}} -{{- end -}} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ .Values.components.proxy.name }}-config-nginx - labels: - app: {{ template "gitpod.fullname" $ }} - chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - release: "{{ .Release.Name }}" - heritage: "{{ .Release.Service }}" - annotations: - checksum/checksd-config: {{ tpl (include "get-proxy-config" .) . | indent 2 | sha256sum }} -data: -{{ tpl (include "get-proxy-config" .) . | indent 2 }} diff --git a/chart/templates/proxy-deployment.yaml b/chart/templates/proxy-deployment.yaml index 80110cd2299b13..a8844c8d0df72e 100644 --- a/chart/templates/proxy-deployment.yaml +++ b/chart/templates/proxy-deployment.yaml @@ -1,34 +1,9 @@ # Copyright (c) 2020 Gitpod GmbH. All rights reserved. # Licensed under the MIT License. See License-MIT.txt in the project root for license information. -{{ define "gitpod.container.configmap.volumeMounts" -}} -{{- $ := .root -}} -{{- $gp := .gp -}} -{{- $comp := .comp -}} -{{- if $comp.configmaps -}} -{{- range $name := $comp.configmaps -}} -- name: mount-{{ $name }} - mountPath: "/mnt/configmaps/{{ $name }}" -{{ end }} -{{- end }} -{{- end -}} - -{{- define "gitpod.container.configmap.volumes" -}} -{{- $ := .root -}} -{{- $comp := .comp -}} -{{- if $comp.configmaps -}} -{{- range $name := $comp.configmaps -}} -- name: mount-{{ $name }} - configMap: - name: {{ $name }} -{{ end }} -{{- end }} -{{- end -}} - {{ $comp := .Values.components.proxy -}} {{- $this := dict "root" . "gp" $.Values "comp" $comp -}} {{- $wsProxy := .Values.components.wsProxy -}} -{{- $thisWsProxy := dict "root" . "gp" $.Values "comp" $wsProxy -}} {{- if not $comp.disabled -}} kind: Deployment apiVersion: apps/v1 @@ -94,29 +69,22 @@ spec: privileged: false readinessProbe: httpGet: - path: "/nginx/status" + path: "/ready" port: 8003 - initialDelaySeconds: 0 - periodSeconds: 1 + initialDelaySeconds: 5 + periodSeconds: 5 timeoutSeconds: 1 successThreshold: 1 failureThreshold: 3 volumeMounts: - - name: config-nginx - mountPath: "/mnt/nginx" + - name: vhosts + mountPath: "/etc/caddy/vhosts" {{- if index .Values "docker-registry" "enabled" }} - name: builtin-registry-auth - mountPath: "/mnt/nginx/registry-auth" + mountPath: "/etc/caddy/registry-auth" {{- end }} -{{- if $.Values.certificatesSecret.secretName }} - name: config-certificates - mountPath: "/mnt/nginx/certificates" -{{- end }} -{{- if $comp.sslDHParam }} - - name: config-ssl-dhparam - mountPath: "/mnt/nginx/ssl-dhparam" -{{- end }} -{{ include "gitpod.container.configmap.volumeMounts" $this | indent 8 }} + mountPath: "/etc/caddy/certificates" {{ include "gitpod.container.defaultEnv" (dict "root" . "gp" $.Values "comp" $comp "noVersion" true) | indent 8 }} - name: PROXY_DOMAIN value: "{{ $.Values.hostname }}" @@ -125,66 +93,20 @@ spec: secretKeyRef: name: server-proxy-apikey key: apikey -{{- if $comp.certbot.enabled }} - - name: CERTBOT_ENABLED - value: "true" - - name: CERTBOT_EMAIL - value: "{{ $comp.certbot.email }}" -{{- end }} -{{- if (and $wsProxy (not $wsProxy.disabled) $wsProxy.portRange) }} - - name: ws-proxy - image: {{ template "gitpod.comp.imageFull" $thisWsProxy }} - args: ["run", "-v", "/config/config.json"] -{{ include "gitpod.container.imagePullPolicy" $thisWsProxy | indent 8 }} -{{ include "gitpod.container.resources" $thisWsProxy | indent 8 }} -{{ include "gitpod.container.ports" $thisWsProxy | indent 8 }} -{{- range $index, $port := untilStep (int $wsProxy.portRange.start) (int (add $wsProxy.portRange.end 1)) 1 }} - - name: "wsproxy-{{ $port }}" - containerPort: {{ $port }} -{{- end }} {{ include "gitpod.container.defaultEnv" (dict "root" . "gp" $.Values "comp" $wsProxy "noVersion" true) | indent 8 }} - volumeMounts: -{{- if (and $wsProxy (not $wsProxy.disabled) $wsProxy.portRange) }} - - name: {{ template "gitpod.comp.configMap" $thisWsProxy }} - mountPath: "/config" - readOnly: true -{{- end }} securityContext: privileged: false -{{- end }} volumes: - - name: config-nginx + - name: vhosts configMap: - name: {{ $comp.name }}-config-nginx + name: {{ template "gitpod.comp.configMap" $this }} {{- if index .Values "docker-registry" "enabled" }} - name: builtin-registry-auth secret: secretName: builtin-registry-auth {{- end }} -{{- if (and $wsProxy (not $wsProxy.disabled) $wsProxy.portRange) }} - - name: ws-proxy-config - configMap: - name: ws-proxy-config -{{- end }} -{{- if $comp.sslDHParam }} - - name: config-ssl-dhparam - secret: - secretName: server-proxy-ssl-dhparam -{{- end }} -{{- if $.Values.certificatesSecret.secretName }} - name: config-certificates secret: secretName: {{ $.Values.certificatesSecret.secretName }} -{{- if (and $.Values.certificatesSecret.fullChainName $.Values.certificatesSecret.chainName $.Values.certificatesSecret.keyName) }} - items: - - key: {{ $.Values.certificatesSecret.fullChainName }} - path: fullchain.pem - - key: {{ $.Values.certificatesSecret.chainName }} - path: chain.pem - - key: {{ $.Values.certificatesSecret.keyName }} - path: privkey.pem -{{- end }} -{{- end }} -{{ include "gitpod.container.configmap.volumes" $this | indent 6 }} {{ toYaml .Values.defaults | indent 6 }} -{{ end }} \ No newline at end of file +{{ end }} diff --git a/chart/templates/registry-facade-configmap.yaml b/chart/templates/registry-facade-configmap.yaml index 3fb1467e47e6a8..7ee28411f2edc2 100644 --- a/chart/templates/registry-facade-configmap.yaml +++ b/chart/templates/registry-facade-configmap.yaml @@ -19,17 +19,10 @@ data: "registry": { "port": {{ $comp.ports.registry.containerPort }}, {{- if (or .Values.certificatesSecret.secretName $comp.certificatesSecret.secretName) }} - {{- if (or .Values.certificatesSecret.certManager $comp.certificatesSecret.certManager) }} "tls": { "crt": "/mnt/certificates/tls.crt", "key": "/mnt/certificates/tls.key" }, - {{ else -}} - "tls": { - "crt": "/mnt/certificates/fullchain.pem", - "key": "/mnt/certificates/privkey.pem" - }, - {{ end -}} {{ end -}} "remoteSpecProvider": { "addr": "ws-manager:{{ .Values.components.wsManager.ports.rpc.containerPort }}", diff --git a/chart/templates/registry-facade-daemonset.yaml b/chart/templates/registry-facade-daemonset.yaml index 6760858a26ccc6..c19aada56d03f5 100644 --- a/chart/templates/registry-facade-daemonset.yaml +++ b/chart/templates/registry-facade-daemonset.yaml @@ -96,15 +96,11 @@ spec: - name: https-certificates secret: secretName: {{ .Values.certificatesSecret.secretName }} - {{- if (and $.Values.certificatesSecret.fullChainName $.Values.certificatesSecret.chainName $.Values.certificatesSecret.keyName) }} items: - - key: {{ $.Values.certificatesSecret.fullChainName }} - path: fullchain.pem - - key: {{ $.Values.certificatesSecret.chainName }} - path: chain.pem - - key: {{ $.Values.certificatesSecret.keyName }} - path: privkey.pem - {{- end }} + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key {{- end }} {{ toYaml .Values.defaults | indent 6 }} {{ end }} diff --git a/chart/templates/ws-manager-configmap.yaml b/chart/templates/ws-manager-configmap.yaml index 76ed2436adb361..c555d31f8fed2e 100644 --- a/chart/templates/ws-manager-configmap.yaml +++ b/chart/templates/ws-manager-configmap.yaml @@ -60,12 +60,12 @@ data: } }, "heartbeatInterval": "30s", - "hostURL": "{{- template "gitpod.scheme" $this -}}://{{ $.Values.hostname }}", + "hostURL": "https://{{ $.Values.hostname }}", "initProbe": { "timeout": "1s" }, - "urlTemplate": "{{- template "gitpod.scheme" $this -}}://{{"{{ .Prefix }}"}}.ws{{- if $.Values.installation.shortname -}}-{{ $.Values.installation.shortname }}{{- end -}}.{{ $.Values.hostname }}", - "portUrlTemplate": "{{- template "gitpod.scheme" $this -}}://{{"{{ .WorkspacePort }}"}}-{{"{{ .Prefix }}"}}.ws{{- if $.Values.installation.shortname -}}-{{ $.Values.installation.shortname }}{{- end -}}.{{ $.Values.hostname }}", + "urlTemplate": "https://{{"{{ .Prefix }}"}}.ws{{- if $.Values.installation.shortname -}}-{{ $.Values.installation.shortname }}{{- end -}}.{{ $.Values.hostname }}", + "portUrlTemplate": "https://{{"{{ .WorkspacePort }}"}}-{{"{{ .Prefix }}"}}.ws{{- if $.Values.installation.shortname -}}-{{ $.Values.installation.shortname }}{{- end -}}.{{ $.Values.hostname }}", "workspaceHostPath": "{{ .Values.components.wsDaemon.hostWorkspaceArea }}", "podTemplate": { {{- if $wscomp.templates }} diff --git a/chart/templates/ws-proxy-configmap.yaml b/chart/templates/ws-proxy-configmap.yaml index a6c3806af774ad..a734de3f760831 100644 --- a/chart/templates/ws-proxy-configmap.yaml +++ b/chart/templates/ws-proxy-configmap.yaml @@ -47,7 +47,7 @@ data: "host": "blobserve.{{- .Release.Namespace -}}.svc.cluster.local:{{ .Values.components.blobserve.ports.service.servicePort }}" }, "gitpodInstallation": { - "scheme": "{{- template "gitpod.scheme" $this -}}", + "scheme": "https", "hostName": "{{- $gp.hostname -}}", "workspaceHostSuffix": ".ws{{- if $gp.installation.shortname -}}-{{ $.Values.installation.shortname }}{{- end -}}.{{ $.Values.hostname }}" }, diff --git a/chart/values.yaml b/chart/values.yaml index 861dbe30619de7..77cd0ea5a9763f 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -15,6 +15,7 @@ installation: region: local cluster: "00" shortname: "" + kubedomain: "svc.cluster.local" license: "" installNetworkPolicies: true installPodSecurityPolicies: true @@ -252,7 +253,6 @@ components: server: name: "server" - replicas: 1 dependsOn: - "server-proxy-apikey-secret.yaml" - "auth-providers-configmap.yaml" @@ -320,32 +320,19 @@ components: proxy: name: "proxy" svcName: "proxy" - replicas: 1 dependsOn: - - "proxy-configmap-nginx.yaml" + - "proxy-configmap.yaml" - "server-proxy-apikey-secret.yaml" - - "server-proxy-ssl-dhparam.yaml" ports: http: - expose: true containerPort: 80 - # nodePort: 31080 https: expose: true containerPort: 443 - # nodePort: 31443 loadBalancerIP: null serviceType: "LoadBalancer" serviceSessionAffinity: "None" serviceExternalTrafficPolicy: null - deployIngressService: true - certbot: - enabled: false - email: "certificate@your-domain.com" - # A base64ed Diffie-Hellman parameter - # This can be generated with: openssl dhparam 4096 2> /dev/null | base64 -w 0 - # http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_dhparam - sslDHParam: wsManager: name: "ws-manager" From 98ee3376e381f81ac08c6e1347b5c91ee8bc36f5 Mon Sep 17 00:00:00 2001 From: Manuel Alejandro de Brito Fontes Date: Wed, 5 May 2021 07:52:32 -0400 Subject: [PATCH 2/4] Cleanup terraform --- install/aws-terraform/main.tf | 1 - install/aws-terraform/variables.tf | 6 ------ install/docker/gitpod-image/entrypoint.sh | 1 - install/gcp-terraform/environment/installer/main.tf | 1 - .../environment/installer/templates/values.tpl | 1 - .../gcp-terraform/environment/installer/variables.tf | 5 ----- .../modules/certmanager/templates/values.tpl | 3 --- install/installer/cmd/aws.go | 10 +--------- install/installer/cmd/gcp.go | 10 +--------- 9 files changed, 2 insertions(+), 36 deletions(-) diff --git a/install/aws-terraform/main.tf b/install/aws-terraform/main.tf index 647d6d02d6284b..d88c7b2adf0316 100644 --- a/install/aws-terraform/main.tf +++ b/install/aws-terraform/main.tf @@ -56,7 +56,6 @@ module "gitpod" { # simply setting "{}" does not work as it does not override: https://github.com/helm/helm/issues/5407 certificatesSecret: secretName: "" - forceHTTPS: ${var.force_https} installation: region: ${var.region} diff --git a/install/aws-terraform/variables.tf b/install/aws-terraform/variables.tf index c24890da45ab71..51478801a9d19e 100644 --- a/install/aws-terraform/variables.tf +++ b/install/aws-terraform/variables.tf @@ -35,12 +35,6 @@ variable "image_prefix" { description = "Image prefix for the registry in which the images for the components are hosted" } -variable "force_https" { - type = bool - default = false - description = "Force the domain to use HTTPS" -} - variable "certbot_enabled" { type = bool default = false diff --git a/install/docker/gitpod-image/entrypoint.sh b/install/docker/gitpod-image/entrypoint.sh index ca946226c9f76c..037ce242412c29 100755 --- a/install/docker/gitpod-image/entrypoint.sh +++ b/install/docker/gitpod-image/entrypoint.sh @@ -108,7 +108,6 @@ fi case "$DOMAIN" in *ip.mygitpod.com) cat << EOF > /default_values/03_ip_mygitpod_com.yaml -forceHTTPS: true components: imageBuilder: registry: diff --git a/install/gcp-terraform/environment/installer/main.tf b/install/gcp-terraform/environment/installer/main.tf index b3e7558e08c95c..04755d6f8250ca 100644 --- a/install/gcp-terraform/environment/installer/main.tf +++ b/install/gcp-terraform/environment/installer/main.tf @@ -62,7 +62,6 @@ data "template_file" "values" { loadbalancer_ip = google_compute_address.gitpod.address certbot_enabled = var.certbot_enabled certbot_email = var.certificate_email - force_https = var.force_https } } module "gitpod" { diff --git a/install/gcp-terraform/environment/installer/templates/values.tpl b/install/gcp-terraform/environment/installer/templates/values.tpl index da3958d8ed54f2..99badde4f0ad88 100644 --- a/install/gcp-terraform/environment/installer/templates/values.tpl +++ b/install/gcp-terraform/environment/installer/templates/values.tpl @@ -13,5 +13,4 @@ components: end: 11000 installPodSecurityPolicies: true -forceHTTPS: ${force_https} authProviders: [] diff --git a/install/gcp-terraform/environment/installer/variables.tf b/install/gcp-terraform/environment/installer/variables.tf index be1e349d75e75d..3cd237455b65bd 100644 --- a/install/gcp-terraform/environment/installer/variables.tf +++ b/install/gcp-terraform/environment/installer/variables.tf @@ -41,11 +41,6 @@ variable "image_prefix" { default = "eu.gcr.io/gitpod-core-dev/build/" } -variable "force_https" { - type = bool - default = false -} - variable "certbot_enabled" { type = bool default = false diff --git a/install/gcp-terraform/modules/certmanager/templates/values.tpl b/install/gcp-terraform/modules/certmanager/templates/values.tpl index 98db5e238c83f6..48dc026ac1f21f 100644 --- a/install/gcp-terraform/modules/certmanager/templates/values.tpl +++ b/install/gcp-terraform/modules/certmanager/templates/values.tpl @@ -1,8 +1,5 @@ certificatesSecret: secretName: ${secret_name} - keyName: ${key_name} - chainName: ${chain_name} - fullChainName: ${full_chain_name} components: restarter: diff --git a/install/installer/cmd/aws.go b/install/installer/cmd/aws.go index 1d7db6ba56f9d8..5a5db29c0f6bb8 100644 --- a/install/installer/cmd/aws.go +++ b/install/installer/cmd/aws.go @@ -73,10 +73,6 @@ var awsCmd = &cobra.Command{ } } else if !strings.Contains(domain, "ip.mygitpod.com") { err = terraform.PersistVariable(tfvarsfn, - terraform.PersistVariableOpts{ - Name: "force_https", - Sources: []terraform.VariableValueSource{func(name string, spec terraform.VariableSpec) (value string, ok bool) { return "true", true }}, - }, terraform.PersistVariableOpts{ Name: "certbot_enabled", Sources: []terraform.VariableValueSource{func(name string, spec terraform.VariableSpec) (value string, ok bool) { return "true", true }}, @@ -134,11 +130,7 @@ var awsCmd = &cobra.Command{ }, }, ForceOverwrite: true, - }, terraform.PersistVariableOpts{Name: "force_https", ForceOverwrite: true, Sources: []terraform.VariableValueSource{ - func(name string, spec terraform.VariableSpec) (value string, ok bool) { - return "true", true - }, - }}) + }) if err != nil { ui.Fatalf("cannot update the \"domain\" terraform variables - please re-run this installer.\n\t%q", err) } diff --git a/install/installer/cmd/gcp.go b/install/installer/cmd/gcp.go index 041e84e5e94c73..4ae1570e7a1c28 100644 --- a/install/installer/cmd/gcp.go +++ b/install/installer/cmd/gcp.go @@ -69,10 +69,6 @@ var gcpCmd = &cobra.Command{ } } else if !strings.Contains(domain, "ip.mygitpod.com") { err = terraform.PersistVariable(tfvarsfn, - terraform.PersistVariableOpts{ - Name: "force_https", - Sources: []terraform.VariableValueSource{func(name string, spec terraform.VariableSpec) (value string, ok bool) { return "true", true }}, - }, terraform.PersistVariableOpts{ Name: "certbot_enabled", Sources: []terraform.VariableValueSource{func(name string, spec terraform.VariableSpec) (value string, ok bool) { return "true", true }}, @@ -121,11 +117,7 @@ var gcpCmd = &cobra.Command{ }, }, ForceOverwrite: true, - }, terraform.PersistVariableOpts{Name: "force_https", ForceOverwrite: true, Sources: []terraform.VariableValueSource{ - func(name string, spec terraform.VariableSpec) (value string, ok bool) { - return "true", true - }, - }}) + }) if err != nil { ui.Fatalf("cannot update the \"domain\" terraform variables - please re-run this installer:\n\t%q", err) } From 0cd00d63a8c9003bb03a9cdecea5a4d764929a77 Mon Sep 17 00:00:00 2001 From: Manuel Alejandro de Brito Fontes Date: Wed, 5 May 2021 07:53:02 -0400 Subject: [PATCH 3/4] Remove NGINX configuration --- components/proxy/README.md | 8 - .../proxy/conf/lua-prometheus/README.md | 2 - .../proxy/conf/lua-prometheus/prometheus.lua | 535 ------------------ .../conf/lua-prometheus/prometheus_test.lua | 334 ----------- components/proxy/nodomain-certs/cert.pem | 30 - components/proxy/nodomain-certs/fullchain.pem | 56 -- components/proxy/nodomain-certs/privkey.pem | 28 - components/proxy/startup/nginx.sh | 86 --- 8 files changed, 1079 deletions(-) delete mode 100644 components/proxy/README.md delete mode 100644 components/proxy/conf/lua-prometheus/README.md delete mode 100644 components/proxy/conf/lua-prometheus/prometheus.lua delete mode 100644 components/proxy/conf/lua-prometheus/prometheus_test.lua delete mode 100644 components/proxy/nodomain-certs/cert.pem delete mode 100644 components/proxy/nodomain-certs/fullchain.pem delete mode 100644 components/proxy/nodomain-certs/privkey.pem delete mode 100755 components/proxy/startup/nginx.sh diff --git a/components/proxy/README.md b/components/proxy/README.md deleted file mode 100644 index db83cff1dab23b..00000000000000 --- a/components/proxy/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Nginx - -## Performance tuning - -Several links which were used to create the current nginx configuration: - - https://www.nginx.com/blog/tuning-nginx/ - - https://www.slideshare.net/Nginx/nginx-installation-and-tuning - - https://engineering.gosquared.com/optimising-nginx-node-js-and-networking-for-heavy-workloads diff --git a/components/proxy/conf/lua-prometheus/README.md b/components/proxy/conf/lua-prometheus/README.md deleted file mode 100644 index 42c43368f128ba..00000000000000 --- a/components/proxy/conf/lua-prometheus/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# knyar/nginx-lua-prometheus -https://github.com/knyar/nginx-lua-prometheus diff --git a/components/proxy/conf/lua-prometheus/prometheus.lua b/components/proxy/conf/lua-prometheus/prometheus.lua deleted file mode 100644 index 161a7a55dfc6e4..00000000000000 --- a/components/proxy/conf/lua-prometheus/prometheus.lua +++ /dev/null @@ -1,535 +0,0 @@ --- vim: ts=2:sw=2:sts=2:expandtab --- --- This module uses a single dictionary shared between Nginx workers to keep --- all metrics. Each counter is stored as a separate entry in that dictionary, --- which allows us to increment them using built-in `incr` method. --- --- Prometheus requires that (a) all samples for a given metric are presented --- as one uninterrupted group, and (b) buckets of a histogram appear in --- increasing numerical order. We satisfy that by carefully constructing full --- metric names (i.e. metric name along with all labels) so that they meet --- those requirements while being sorted alphabetically. In particular: --- --- * all labels for a given metric are presented in reproducible order (the one --- used when labels were declared). "le" label for histogram metrics always --- goes last; --- * bucket boundaries (which are exposed as values of the "le" label) are --- presented as floating point numbers with leading and trailing zeroes. --- Number of of zeroes is determined for each bucketer automatically based on --- bucket boundaries; --- * internally "+Inf" bucket is stored as "Inf" (to make it appear after --- all numeric buckets), and gets replaced by "+Inf" just before we --- expose the metrics. --- --- For example, if you define your bucket boundaries as {0.00005, 10, 1000} --- then we will keep the following samples for a metric `m1` with label --- `site` set to `site1`: --- --- m1_bucket{site="site1",le="0000.00005"} --- m1_bucket{site="site1",le="0010.00000"} --- m1_bucket{site="site1",le="1000.00000"} --- m1_bucket{site="site1",le="Inf"} --- m1_count{site="site1"} --- m1_sum{site="site1"} --- --- "Inf" will be replaced by "+Inf" while publishing metrics. --- --- You can find the latest version and documentation at --- https://github.com/knyar/nginx-lua-prometheus --- Released under MIT license. - - --- Default set of latency buckets, 5ms to 10s: -local DEFAULT_BUCKETS = {0.005, 0.01, 0.02, 0.03, 0.05, 0.075, 0.1, 0.2, 0.3, - 0.4, 0.5, 0.75, 1, 1.5, 2, 3, 4, 5, 10} - --- Metric is a "parent class" for all metrics. -local Metric = {} -function Metric:new(o) - o = o or {} - setmetatable(o, self) - self.__index = self - return o -end - --- Checks that the right number of labels values have been passed. --- --- Args: --- label_values: an array of label values. --- --- Returns: --- an error message or nil -function Metric:check_label_values(label_values) - if self.label_names == nil and label_values == nil then - return - elseif self.label_names == nil and label_values ~= nil then - return "Expected no labels for " .. self.name .. ", got " .. #label_values - elseif label_values == nil and self.label_names ~= nil then - return "Expected " .. #self.label_names .. " labels for " .. - self.name .. ", got none" - elseif #self.label_names ~= #label_values then - return "Wrong number of labels for " .. self.name .. ". Expected " .. - #self.label_names .. ", got " .. #label_values - else - for i, k in ipairs(self.label_names) do - if label_values[i] == nil then - return "Unexpected nil value for label " .. k .. " of " .. self.name - end - end - end -end - -local Counter = Metric:new() --- Increase a given counter by `value` --- --- Args: --- value: (number) a value to add to the counter. Defaults to 1 if skipped. --- label_values: an array of label values. Can be nil (i.e. not defined) for --- metrics that have no labels. -function Counter:inc(value, label_values) - local err = self:check_label_values(label_values) - if err ~= nil then - self.prometheus:log_error(err) - return - end - self.prometheus:inc(self.name, self.label_names, label_values, value or 1) -end - -local Gauge = Metric:new() --- Set a given gauge to `value` --- --- Args: --- value: (number) a value to set the gauge to. Should be defined. --- label_values: an array of label values. Can be nil (i.e. not defined) for --- metrics that have no labels. -function Gauge:set(value, label_values) - if value == nil then - self.prometheus:log_error("No value passed for " .. self.name) - return - end - local err = self:check_label_values(label_values) - if err ~= nil then - self.prometheus:log_error(err) - return - end - self.prometheus:set(self.name, self.label_names, label_values, value) -end - -local Histogram = Metric:new() --- Record a given value in a histogram. --- --- Args: --- value: (number) a value to record. Should be defined. --- label_values: an array of label values. Can be nil (i.e. not defined) for --- metrics that have no labels. -function Histogram:observe(value, label_values) - if value == nil then - self.prometheus:log_error("No value passed for " .. self.name) - return - end - local err = self:check_label_values(label_values) - if err ~= nil then - self.prometheus:log_error(err) - return - end - self.prometheus:histogram_observe(self.name, self.label_names, label_values, value) -end - -local Prometheus = {} -Prometheus.__index = Prometheus -Prometheus.initialized = false - --- Generate full metric name that includes all labels. --- --- Args: --- name: string --- label_names: (array) a list of label keys. --- label_values: (array) a list of label values. --- Returns: --- (string) full metric name. -local function full_metric_name(name, label_names, label_values) - if not label_names then - return name - end - local label_parts = {} - for idx, key in ipairs(label_names) do - local label_value = (string.format("%s", label_values[idx]) - :gsub("[^\032-\126]", "") -- strip non-printable characters - :gsub("\\", "\\\\") - :gsub('"', '\\"')) - table.insert(label_parts, key .. '="' .. label_value .. '"') - end - return name .. "{" .. table.concat(label_parts, ",") .. "}" -end - --- Construct bucket format for a list of buckets. --- --- This receives a list of buckets and returns a sprintf template that should --- be used for bucket boundaries to make them come in increasing order when --- sorted alphabetically. --- --- To re-phrase, this is where we detect how many leading and trailing zeros we --- need. --- --- Args: --- buckets: a list of buckets --- --- Returns: --- (string) a sprintf template. -local function construct_bucket_format(buckets) - local max_order = 1 - local max_precision = 1 - for _, bucket in ipairs(buckets) do - assert(type(bucket) == "number", "bucket boundaries should be numeric") - -- floating point number with all trailing zeros removed - local as_string = string.format("%f", bucket):gsub("0*$", "") - local dot_idx = as_string:find(".", 1, true) - max_order = math.max(max_order, dot_idx - 1) - max_precision = math.max(max_precision, as_string:len() - dot_idx) - end - return "%0" .. (max_order + max_precision + 1) .. "." .. max_precision .. "f" -end - --- Extract short metric name from the full one. --- --- Args: --- full_name: (string) full metric name that can include labels. --- --- Returns: --- (string) short metric name with no labels. For a `*_bucket` metric of --- histogram the _bucket suffix will be removed. -local function short_metric_name(full_name) - local labels_start, _ = full_name:find("{") - if not labels_start then - -- no labels - return full_name - end - local suffix_idx, _ = full_name:find("_bucket{") - if suffix_idx and full_name:find("le=") then - -- this is a histogram metric - return full_name:sub(1, suffix_idx - 1) - end - -- this is not a histogram metric - return full_name:sub(1, labels_start - 1) -end - --- Makes a shallow copy of a table -local function copy_table(table) - local new = {} - if table ~= nil then - for k, v in ipairs(table) do - new[k] = v - end - end - return new -end - --- Check metric name and label names for correctness. --- --- Regular expressions to validate metric and label names are --- documented in https://prometheus.io/docs/concepts/data_model/ --- --- Args: --- metric_name: (string) metric name. --- label_names: label names (array of strings). --- --- Returns: --- Either an error string, or nil of no errors were found. -local function check_metric_and_label_names(metric_name, label_names) - if not metric_name:match("^[a-zA-Z_:][a-zA-Z0-9_:]*$") then - return "Metric name '" .. metric_name .. "' is invalid" - end - for _, label_name in ipairs(label_names or {}) do - if label_name == "le" then - return "Invalid label name 'le' in " .. metric_name - end - if not label_name:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then - return "Metric '" .. metric_name .. "' label name '" .. label_name .. - "' is invalid" - end - end -end - --- Initialize the module. --- --- This should be called once from the `init_by_lua` section in nginx --- configuration. --- --- Args: --- dict_name: (string) name of the nginx shared dictionary which will be --- used to store all metrics --- prefix: (optional string) if supplied, prefix is added to all --- metric names on output --- --- Returns: --- an object that should be used to register metrics. -function Prometheus.init(dict_name, prefix) - local self = setmetatable({}, Prometheus) - self.dict = ngx.shared[dict_name or "prometheus_metrics"] - self.help = {} - if prefix then - self.prefix = prefix - else - self.prefix = '' - end - self.type = {} - self.registered = {} - self.buckets = {} - self.bucket_format = {} - self.initialized = true - - self:counter("nginx_metric_errors_total", - "Number of nginx-lua-prometheus errors") - self.dict:set("nginx_metric_errors_total", 0) - return self -end - -function Prometheus:log_error(...) - ngx.log(ngx.ERR, ...) - self.dict:incr("nginx_metric_errors_total", 1) -end - -function Prometheus:log_error_kv(key, value, err) - self:log_error( - "Error while setting '", key, "' to '", value, "': '", err, "'") -end - --- Register a counter. --- --- Args: --- name: (string) name of the metric. Required. --- description: (string) description of the metric. Will be used for the HELP --- comment on the metrics page. Optional. --- label_names: array of strings, defining a list of metrics. Optional. --- --- Returns: --- a Counter object. -function Prometheus:counter(name, description, label_names) - if not self.initialized then - ngx.log(ngx.ERR, "Prometheus module has not been initialized") - return - end - - local err = check_metric_and_label_names(name, label_names) - if err ~= nil then - self:log_error(err) - return - end - - if self.registered[name] then - self:log_error("Duplicate metric " .. name) - return - end - self.registered[name] = true - self.help[name] = description - self.type[name] = "counter" - - return Counter:new{name=name, label_names=label_names, prometheus=self} -end - --- Register a gauge. --- --- Args: --- name: (string) name of the metric. Required. --- description: (string) description of the metric. Will be used for the HELP --- comment on the metrics page. Optional. --- label_names: array of strings, defining a list of metrics. Optional. --- --- Returns: --- a Gauge object. -function Prometheus:gauge(name, description, label_names) - if not self.initialized then - ngx.log(ngx.ERR, "Prometheus module has not been initialized") - return - end - - local err = check_metric_and_label_names(name, label_names) - if err ~= nil then - self:log_error(err) - return - end - - if self.registered[name] then - self:log_error("Duplicate metric " .. name) - return - end - self.registered[name] = true - self.help[name] = description - self.type[name] = "gauge" - - return Gauge:new{name=name, label_names=label_names, prometheus=self} -end - - --- Register a histogram. --- --- Args: --- name: (string) name of the metric. Required. --- description: (string) description of the metric. Will be used for the HELP --- comment on the metrics page. Optional. --- label_names: array of strings, defining a list of metrics. Optional. --- buckets: array if numbers, defining bucket boundaries. Optional. --- --- Returns: --- a Histogram object. -function Prometheus:histogram(name, description, label_names, buckets) - if not self.initialized then - ngx.log(ngx.ERR, "Prometheus module has not been initialized") - return - end - - local err = check_metric_and_label_names(name, label_names) - if err ~= nil then - self:log_error(err) - return - end - - for _, suffix in ipairs({"", "_bucket", "_count", "_sum"}) do - if self.registered[name .. suffix] then - self:log_error("Duplicate metric " .. name .. suffix) - return - end - self.registered[name .. suffix] = true - end - self.help[name] = description - self.type[name] = "histogram" - - self.buckets[name] = buckets or DEFAULT_BUCKETS - self.bucket_format[name] = construct_bucket_format(self.buckets[name]) - - return Histogram:new{name=name, label_names=label_names, prometheus=self} -end - --- Set a given dictionary key. --- This overwrites existing values, so it should only be used when initializing --- metrics or when explicitly overwriting the previous value of a metric. -function Prometheus:set_key(key, value) - local ok, err = self.dict:safe_set(key, value) - if not ok then - self:log_error_kv(key, value, err) - end -end - --- Increment a given counter by `value`. --- --- Args: --- name: (string) short metric name without any labels. --- label_names: (array) a list of label keys. --- label_values: (array) a list of label values. --- value: (number) value to add. Optional, defaults to 1. -function Prometheus:inc(name, label_names, label_values, value) - local key = full_metric_name(name, label_names, label_values) - if value == nil then value = 1 end - if value < 0 then - self:log_error_kv(key, value, "Value should not be negative") - return - end - - local newval, err = self.dict:incr(key, value) - if newval then - return - end - -- Yes, this looks like a race, so I guess we might under-report some values - -- when multiple workers simultaneously try to create the same metric. - -- Hopefully this does not happen too often (shared dictionary does not get - -- reset during configuration reload). - if err == "not found" then - self:set_key(key, value) - return - end - -- Unexpected error - self:log_error_kv(key, value, err) -end - --- Set the current value of a gauge to `value` --- --- Args: --- name: (string) short metric name without any labels. --- label_names: (array) a list of label keys. --- label_values: (array) a list of label values. --- value: (number) the new value for the gauge. -function Prometheus:set(name, label_names, label_values, value) - local key = full_metric_name(name, label_names, label_values) - self:set_key(key, value) -end - --- Record a given value into a histogram metric. --- --- Args: --- name: (string) short metric name without any labels. --- label_names: (array) a list of label keys. --- label_values: (array) a list of label values. --- value: (number) value to observe. -function Prometheus:histogram_observe(name, label_names, label_values, value) - self:inc(name .. "_count", label_names, label_values, 1) - self:inc(name .. "_sum", label_names, label_values, value) - - -- we are going to mutate arrays of label names and values, so create a copy. - local l_names = copy_table(label_names) - local l_values = copy_table(label_values) - - -- Last bucket. Note, that the label value is "Inf" rather than "+Inf" - -- required by Prometheus. This is necessary for this bucket to be the last - -- one when all metrics are lexicographically sorted. "Inf" will get replaced - -- by "+Inf" in Prometheus:collect(). - table.insert(l_names, "le") - table.insert(l_values, "Inf") - self:inc(name .. "_bucket", l_names, l_values, 1) - - local label_count = #l_names - for _, bucket in ipairs(self.buckets[name]) do - if value <= bucket then - -- last label is now "le" - l_values[label_count] = self.bucket_format[name]:format(bucket) - self:inc(name .. "_bucket", l_names, l_values, 1) - end - end -end - --- Present all metrics in a text format compatible with Prometheus. --- --- This function should be used to expose the metrics on a separate HTTP page. --- It will get the metrics from the dictionary, sort them, and expose them --- aling with TYPE and HELP comments. -function Prometheus:collect() - ngx.header.content_type = "text/plain" - if not self.initialized then - ngx.log(ngx.ERR, "Prometheus module has not been initialized") - return - end - - local keys = self.dict:get_keys(0) - -- Prometheus server expects buckets of a histogram to appear in increasing - -- numerical order of their label values. - table.sort(keys) - - local seen_metrics = {} - local output = {} - for _, key in ipairs(keys) do - local value, err = self.dict:get(key) - if value then - local short_name = short_metric_name(key) - if not seen_metrics[short_name] then - if self.help[short_name] then - table.insert(output, string.format("# HELP %s%s %s\n", - self.prefix, short_name, self.help[short_name])) - end - if self.type[short_name] then - table.insert(output, string.format("# TYPE %s%s %s\n", - self.prefix, short_name, self.type[short_name])) - end - seen_metrics[short_name] = true - end - -- Replace "Inf" with "+Inf" in each metric's last bucket 'le' label. - if key:find('le="Inf"', 1, true) then - key = key:gsub('le="Inf"', 'le="+Inf"') - end - table.insert(output, string.format("%s%s %s\n", self.prefix, key, value)) - else - self:log_error("Error getting '", key, "': ", err) - end - end - ngx.print(output) -end - -return Prometheus diff --git a/components/proxy/conf/lua-prometheus/prometheus_test.lua b/components/proxy/conf/lua-prometheus/prometheus_test.lua deleted file mode 100644 index 4909bb6b4fc76c..00000000000000 --- a/components/proxy/conf/lua-prometheus/prometheus_test.lua +++ /dev/null @@ -1,334 +0,0 @@ --- vim: ts=2:sw=2:sts=2:expandtab -luaunit = require('luaunit') -prometheus = require('prometheus') - --- Simple implementation of a nginx shared dictionary -local SimpleDict = {} -SimpleDict.__index = SimpleDict -function SimpleDict:set(k, v) - if not self.dict then self.dict = {} end - self.dict[k] = v - return true, nil, false -- success, err, forcible -end -function SimpleDict:safe_set(k, v) - if k:find("willnotfit") then - return nil, "no memory" - end - self:set(k, v) - return true, nil -- ok, err -end -function SimpleDict:incr(k, v) - if not self.dict[k] then return nil, "not found" end - self.dict[k] = self.dict[k] + v - return self.dict[k], nil -- newval, err -end -function SimpleDict:get(k) - return self.dict[k], 0 -- value, flags -end -function SimpleDict:get_keys(k) - local keys = {} - for key in pairs(self.dict) do table.insert(keys, key) end - return keys -end - --- Global nginx object -local Nginx = {} -Nginx.__index = Nginx -Nginx.ERR = {} -Nginx.WARN = {} -Nginx.header = {} -function Nginx.log(level, ...) - if not ngx.logs then ngx.logs = {} end - table.insert(ngx.logs, table.concat({...}, " ")) -end -function Nginx.print(printed) - if not ngx.printed then ngx.printed = {} end - for str in string.gmatch(table.concat(printed, ""), "([^\n]+)") do - table.insert(ngx.printed, str) - end -end - --- Finds index of a given object in a table -local function find_idx(table, element) - for idx, value in pairs(table) do - if value == element then - return idx - end - end -end - -TestPrometheus = {} -function TestPrometheus:setUp() - self.dict = setmetatable({}, SimpleDict) - ngx = setmetatable({shared={metrics=self.dict}}, Nginx) - self.p = prometheus.init("metrics") - self.counter1 = self.p:counter("metric1", "Metric 1") - self.counter2 = self.p:counter("metric2", "Metric 2", {"f2", "f1"}) - self.gauge1 = self.p:gauge("gauge1", "Gauge 1") - self.gauge2 = self.p:gauge("gauge2", "Gauge 2", {"f2", "f1"}) - self.hist1 = self.p:histogram("l1", "Histogram 1") - self.hist2 = self.p:histogram("l2", "Histogram 2", {"var", "site"}) -end -function TestPrometheus:testInit() - luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 0) - luaunit.assertEquals(ngx.logs, nil) -end -function TestPrometheus:testErrorUnitialized() - local p = prometheus - p:counter("metric1") - p:histogram("metric2") - p:gauge("metric3") - - luaunit.assertEquals(#ngx.logs, 3) -end -function TestPrometheus:testErrorNoMemory() - local counter3 = self.p:counter("willnotfit") - self.counter1:inc(5) - counter3:inc(1) - - luaunit.assertEquals(self.dict:get("metric1"), 5) - luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 1) - luaunit.assertEquals(self.dict:get("willnotfit"), nil) - luaunit.assertEquals(#ngx.logs, 1) -end -function TestPrometheus:testErrorInvalidMetricName() - local h = self.p:histogram("name with a space", "Histogram") - local g = self.p:gauge("nonprintable\004characters", "Gauge") - local c = self.p:counter("0startswithadigit", "Counter") - - luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 3) - luaunit.assertEquals(#ngx.logs, 3) -end -function TestPrometheus:testErrorInvalidLabels() - local h = self.p:histogram("hist1", "Histogram", {"le"}) - local g = self.p:gauge("count1", "Gauge", {"le"}) - local c = self.p:counter("count1", "Counter", {"foo\002"}) - - luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 3) - luaunit.assertEquals(#ngx.logs, 3) -end -function TestPrometheus:testErrorDuplicateMetrics() - self.p:counter("metric1", "Another metric 1") - self.p:counter("l1_count", "Conflicts with Histogram 1") - self.p:counter("l2_sum", "Conflicts with Histogram 2") - self.p:counter("l2_bucket", "Conflicts with Histogram 2") - self.p:gauge("metric1", "Conflicts with Metric 1") - self.p:histogram("l1", "Conflicts with Histogram 1") - self.p:histogram("metric2", "Conflicts with Metric 2") - - luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 7) - luaunit.assertEquals(#ngx.logs, 7) -end -function TestPrometheus:testErrorNegativeValue() - self.counter1:inc(-5) - - luaunit.assertEquals(self.dict:get("metric1"), nil) - luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 1) - luaunit.assertEquals(#ngx.logs, 1) -end -function TestPrometheus:testErrorIncorrectLabels() - self.counter1:inc(1, {"should-be-no-labels"}) - self.counter2:inc(1, {"too-few-labels"}) - self.counter2:inc(1) - self.gauge1:set(1, {"should-be-no-labels"}) - self.gauge2:set(1, {"too-few-labels"}) - self.gauge2:set(1) - self.hist2:observe(1, {"too", "many", "labels"}) - self.hist2:observe(1, {nil, "label"}) - self.hist2:observe(1, {"label", nil}) - - luaunit.assertEquals(self.dict:get("metric1"), nil) - luaunit.assertEquals(self.dict:get("l1_count"), nil) - luaunit.assertEquals(self.dict:get("gauge1"), nil) - luaunit.assertEquals(self.dict:get("gauge2"), nil) - luaunit.assertEquals(self.dict:get("l1_count"), nil) - luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 9) - luaunit.assertEquals(#ngx.logs, 9) -end -function TestPrometheus:testNumericLabelValues() - self.counter2:inc(1, {0, 15.5}) - self.gauge2:set(1, {0, 15.5}) - self.hist2:observe(1, {-3, 90000}) - - luaunit.assertEquals(self.dict:get('metric2{f2="0",f1="15.5"}'), 1) - luaunit.assertEquals(self.dict:get('gauge2{f2="0",f1="15.5"}'), 1) - luaunit.assertEquals(self.dict:get('l2_sum{var="-3",site="90000"}'), 1) - luaunit.assertEquals(ngx.logs, nil) -end -function TestPrometheus:testNonPrintableLabelValues() - self.counter2:inc(1, {"foo", "baz\189\166qux"}) - self.gauge2:set(1, {"z\001", "\002"}) - self.hist2:observe(1, {"\166omg", "fooшbar"}) - - luaunit.assertEquals(self.dict:get('metric2{f2="foo",f1="bazqux"}'), 1) - luaunit.assertEquals(self.dict:get('gauge2{f2="z",f1=""}'), 1) - luaunit.assertEquals(self.dict:get('l2_sum{var="omg",site="foobar"}'), 1) - luaunit.assertEquals(ngx.logs, nil) -end -function TestPrometheus:testNoValues() - self.counter1:inc() -- defaults to 1 - self.gauge1:set() -- should produce an error - self.hist1:observe() -- should produce an error - - luaunit.assertEquals(self.dict:get("metric1"), 1) - luaunit.assertEquals(self.dict:get("nginx_metric_errors_total"), 2) - luaunit.assertEquals(#ngx.logs, 2) -end -function TestPrometheus:testCounters() - self.counter1:inc() - self.counter1:inc(4) - self.counter2:inc(1, {"v2", "v1"}) - self.counter2:inc(3, {"v2", "v1"}) - - luaunit.assertEquals(self.dict:get("metric1"), 5) - luaunit.assertEquals(self.dict:get('metric2{f2="v2",f1="v1"}'), 4) - luaunit.assertEquals(ngx.logs, nil) -end -function TestPrometheus:testLatencyHistogram() - self.hist1:observe(0.35) - self.hist1:observe(0.4) - self.hist2:observe(0.001, {"ok", "site1"}) - self.hist2:observe(0.15, {"ok", "site1"}) - - luaunit.assertEquals(self.dict:get('l1_bucket{le="00.300"}'), nil) - luaunit.assertEquals(self.dict:get('l1_bucket{le="00.400"}'), 2) - luaunit.assertEquals(self.dict:get('l1_bucket{le="00.500"}'), 2) - luaunit.assertEquals(self.dict:get('l1_bucket{le="Inf"}'), 2) - luaunit.assertEquals(self.dict:get('l1_count'), 2) - luaunit.assertEquals(self.dict:get('l1_sum'), 0.75) - luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site1",le="00.005"}'), 1) - luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site1",le="00.100"}'), 1) - luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site1",le="00.200"}'), 2) - luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site1",le="Inf"}'), 2) - luaunit.assertEquals(self.dict:get('l2_count{var="ok",site="site1"}'), 2) - luaunit.assertEquals(self.dict:get('l2_sum{var="ok",site="site1"}'), 0.151) - luaunit.assertEquals(ngx.logs, nil) -end -function TestPrometheus:testLabelEscaping() - self.counter2:inc(1, {"v2", "\""}) - self.counter2:inc(5, {"v2", "\\"}) - self.gauge2:set(1, {"v2", "\""}) - self.gauge2:set(5, {"v2", "\\"}) - self.hist2:observe(0.001, {"ok", "site\"1"}) - self.hist2:observe(0.15, {"ok", "site\"1"}) - - luaunit.assertEquals(self.dict:get('metric2{f2="v2",f1="\\""}'), 1) - luaunit.assertEquals(self.dict:get('metric2{f2="v2",f1="\\\\"}'), 5) - luaunit.assertEquals(self.dict:get('gauge2{f2="v2",f1="\\""}'), 1) - luaunit.assertEquals(self.dict:get('gauge2{f2="v2",f1="\\\\"}'), 5) - luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site\\"1",le="00.005"}'), 1) - luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site\\"1",le="00.100"}'), 1) - luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site\\"1",le="00.200"}'), 2) - luaunit.assertEquals(self.dict:get('l2_bucket{var="ok",site="site\\"1",le="Inf"}'), 2) - luaunit.assertEquals(self.dict:get('l2_count{var="ok",site="site\\"1"}'), 2) - luaunit.assertEquals(self.dict:get('l2_sum{var="ok",site="site\\"1"}'), 0.151) - luaunit.assertEquals(ngx.logs, nil) -end -function TestPrometheus:testCustomBucketer1() - local hist3 = self.p:histogram("l3", "Histogram 3", {"var"}, {1,2,3}) - self.hist1:observe(0.35) - hist3:observe(2, {"ok"}) - hist3:observe(0.151, {"ok"}) - - luaunit.assertEquals(self.dict:get('l1_bucket{le="00.300"}'), nil) - luaunit.assertEquals(self.dict:get('l1_bucket{le="00.400"}'), 1) - luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="1.0"}'), 1) - luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="2.0"}'), 2) - luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="3.0"}'), 2) - luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="Inf"}'), 2) - luaunit.assertEquals(self.dict:get('l3_count{var="ok"}'), 2) - luaunit.assertEquals(self.dict:get('l3_sum{var="ok"}'), 2.151) - luaunit.assertEquals(ngx.logs, nil) -end -function TestPrometheus:testCustomBucketer2() - local hist3 = self.p:histogram("l3", "Histogram 3", {"var"}, - {0.000005,5,50000}) - hist3:observe(0.000001, {"ok"}) - hist3:observe(3, {"ok"}) - hist3:observe(7, {"ok"}) - hist3:observe(70000, {"ok"}) - - luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="00000.000005"}'), 1) - luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="00005.000000"}'), 2) - luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="50000.000000"}'), 3) - luaunit.assertEquals(self.dict:get('l3_bucket{var="ok",le="Inf"}'), 4) - luaunit.assertEquals(self.dict:get('l3_count{var="ok"}'), 4) - luaunit.assertEquals(self.dict:get('l3_sum{var="ok"}'), 70010.000001) - luaunit.assertEquals(ngx.logs, nil) -end -function TestPrometheus:testCollect() - local hist3 = self.p:histogram("b1", "Bytes", {"var"}, {100, 2000}) - self.counter1:inc(5) - self.counter2:inc(2, {"v2", "v1"}) - self.counter2:inc(2, {"v2", "v1"}) - self.gauge1:set(3) - self.gauge2:set(2, {"v2", "v1"}) - self.gauge2:set(5, {"v2", "v1"}) - self.hist1:observe(0.000001) - self.hist2:observe(0.000001, {"ok", "site2"}) - self.hist2:observe(3, {"ok", "site2"}) - self.hist2:observe(7, {"ok", "site2"}) - self.hist2:observe(70000, {"ok","site2"}) - hist3:observe(50, {"ok"}) - hist3:observe(50, {"ok"}) - hist3:observe(150, {"ok"}) - hist3:observe(5000, {"ok"}) - self.p:collect() - - assert(find_idx(ngx.printed, "# HELP metric1 Metric 1") ~= nil) - assert(find_idx(ngx.printed, "# TYPE metric1 counter") ~= nil) - assert(find_idx(ngx.printed, "metric1 5") ~= nil) - - assert(find_idx(ngx.printed, "# TYPE metric2 counter") ~= nil) - assert(find_idx(ngx.printed, 'metric2{f2="v2",f1="v1"} 4') ~= nil) - - assert(find_idx(ngx.printed, "# TYPE gauge1 gauge") ~= nil) - assert(find_idx(ngx.printed, 'gauge1 3') ~= nil) - - assert(find_idx(ngx.printed, "# TYPE gauge2 gauge") ~= nil) - assert(find_idx(ngx.printed, 'gauge2{f2="v2",f1="v1"} 5') ~= nil) - - assert(find_idx(ngx.printed, "# TYPE b1 histogram") ~= nil) - assert(find_idx(ngx.printed, "# HELP b1 Bytes") ~= nil) - assert(find_idx(ngx.printed, 'b1_bucket{var="ok",le="0100.0"} 2') ~= nil) - assert(find_idx(ngx.printed, 'b1_sum{var="ok"} 5250') ~= nil) - - assert(find_idx(ngx.printed, 'l2_bucket{var="ok",site="site2",le="04.000"} 2') ~= nil) - assert(find_idx(ngx.printed, 'l2_bucket{var="ok",site="site2",le="+Inf"} 4') ~= nil) - - -- check that type comment exists and is before any samples for the metric. - local type_idx = find_idx(ngx.printed, '# TYPE l1 histogram') - assert (type_idx ~= nil) - assert (ngx.printed[type_idx-1]:find("^l1") == nil) - assert (ngx.printed[type_idx+1]:find("^l1") ~= nil) - luaunit.assertEquals(ngx.logs, nil) -end - -function TestPrometheus:testCollectWithPrefix() - local p = prometheus.init("metrics", "test_pref_") - local counter1 = p:counter("metric1", "Metric 1") - local gauge1 = p:gauge("gauge1", "Gauge 1") - local hist1 = p:histogram("b1", "Bytes", {"var"}, {100, 2000}) - counter1:inc(5) - gauge1:set(3) - hist1:observe(50, {"ok"}) - hist1:observe(50, {"ok"}) - hist1:observe(150, {"ok"}) - hist1:observe(5000, {"ok"}) - p:collect() - - assert(find_idx(ngx.printed, "# HELP test_pref_metric1 Metric 1") ~= nil) - assert(find_idx(ngx.printed, "# TYPE test_pref_metric1 counter") ~= nil) - assert(find_idx(ngx.printed, "test_pref_metric1 5") ~= nil) - - assert(find_idx(ngx.printed, "# HELP test_pref_gauge1 Gauge 1") ~= nil) - assert(find_idx(ngx.printed, "# TYPE test_pref_gauge1 gauge") ~= nil) - assert(find_idx(ngx.printed, "test_pref_gauge1 3") ~= nil) - - assert(find_idx(ngx.printed, "# TYPE test_pref_b1 histogram") ~= nil) - assert(find_idx(ngx.printed, "# HELP test_pref_b1 Bytes") ~= nil) - assert(find_idx(ngx.printed, 'test_pref_b1_bucket{var="ok",le="0100.0"} 2') ~= nil) - assert(find_idx(ngx.printed, 'test_pref_b1_sum{var="ok"} 5250') ~= nil) -end - -os.exit(luaunit.run()) diff --git a/components/proxy/nodomain-certs/cert.pem b/components/proxy/nodomain-certs/cert.pem deleted file mode 100644 index bd67aee4b76e02..00000000000000 --- a/components/proxy/nodomain-certs/cert.pem +++ /dev/null @@ -1,30 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFKTCCBBGgAwIBAgISA06dh/EuO0Z9/3vqvc5pUp+1MA0GCSqGSIb3DQEBCwUA -MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD -EwJSMzAeFw0yMDEyMTAyMDQxNDdaFw0yMTAzMTAyMDQxNDdaMBwxGjAYBgNVBAMM -ESouaXAubXlnaXRwb2QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEA1Smcud7ax7qichVCrZari9BnBNSUdwMReNp3wr4PaRDPiUAOCtxvFDlSLLzN -78HUsM6v6oFpifs5HGnMIy1zu+cM8ri5jQtfGM21OTFcvnKmWRruoc0KuiSyniq8 -+Ou5cgK4xFlRoNHgOGoJWBdSKfSlp35/E5Ev70yYx4pxOaoDo+aTBDmlLRhbU1XV -JZtWJDqQRz7IdKSsQmVtxgPe8JJHNApctrRSWgoi+oOj04DcpCgWZbwP0Zt8WO6V -CllbEqXDuaHju1uFh3XGM81YCvL+awqkgL0Zy78qK4Fq5b0bBPTxmiaXWEbJ9/D7 -GyyvnSU+grYTQ1A0uwP2s0BSLQIDAQABo4ICTTCCAkkwDgYDVR0PAQH/BAQDAgWg -MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0G -A1UdDgQWBBTworVujAZdUvNFFpTf2sGzOpesPzAfBgNVHSMEGDAWgBQULrMXt1hW -y65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6 -Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iu -b3JnLzAcBgNVHREEFTATghEqLmlwLm15Z2l0cG9kLmNvbTBMBgNVHSAERTBDMAgG -BmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3Bz -LmxldHNlbmNyeXB0Lm9yZzCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB2AESUZS6w -7s6vxEAH2Kj+KMDa5oK+2MsxtT/TM5a1toGoAAABdk6aW10AAAQDAEcwRQIhAMcN -Hzs+ZK5jo3z9jD/1u3RzGBue0zszlGM7MJutwZxIAiBZ1PtBWlKmVPdbGAeKh3z2 -nuESoMAfC2BxZIdxDVHvigB3AH0+8viP/4hVaCTCwMqeUol5K8UOeAl/LmqXaJl+ -IvDXAAABdk6aW6UAAAQDAEgwRgIhAJxMfsShji0opY170FyYH0075U+lR+0tQp5i -SJMd/CvhAiEAtAliQtVxUGQRm/jJHU8eLRBAKSlHy4CsUNyNIz01tiEwDQYJKoZI -hvcNAQELBQADggEBAI+CyB3fNbx1QilfEjNT00N2O6DM2jOQp3LxT+cc2c3ecGNn -QXc4E1tPGjnyJbNLG3TbHBGxY0vf9afAS9PH3fkikkh8jJvxKn4y53y3z5upRMTX -CVszAKtICHOWV35GK7GyymRF6u4v1rzBKn8Cy+P7ceo0QlpwxTTIqS8fFFl54c0t -uVq0TjmHpU75qLViyMAI85hvZs5Y6AHVvnae3iMw/f6z4LK4k71JCiLPGmc9rX9X -oRedO0pOK+fpYfoybLnVIrxWBv/ZRA1bToJ2c9bmvuwd7HdRQcKyDL+MlD1nyWCR -WlqQ/kLj80ipKlsVEponvNp7LBBJraRg/gfYjyo= ------END CERTIFICATE----- diff --git a/components/proxy/nodomain-certs/fullchain.pem b/components/proxy/nodomain-certs/fullchain.pem deleted file mode 100644 index 4ecfe4ac3d06f1..00000000000000 --- a/components/proxy/nodomain-certs/fullchain.pem +++ /dev/null @@ -1,56 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFKTCCBBGgAwIBAgISA06dh/EuO0Z9/3vqvc5pUp+1MA0GCSqGSIb3DQEBCwUA -MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD -EwJSMzAeFw0yMDEyMTAyMDQxNDdaFw0yMTAzMTAyMDQxNDdaMBwxGjAYBgNVBAMM -ESouaXAubXlnaXRwb2QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEA1Smcud7ax7qichVCrZari9BnBNSUdwMReNp3wr4PaRDPiUAOCtxvFDlSLLzN -78HUsM6v6oFpifs5HGnMIy1zu+cM8ri5jQtfGM21OTFcvnKmWRruoc0KuiSyniq8 -+Ou5cgK4xFlRoNHgOGoJWBdSKfSlp35/E5Ev70yYx4pxOaoDo+aTBDmlLRhbU1XV -JZtWJDqQRz7IdKSsQmVtxgPe8JJHNApctrRSWgoi+oOj04DcpCgWZbwP0Zt8WO6V -CllbEqXDuaHju1uFh3XGM81YCvL+awqkgL0Zy78qK4Fq5b0bBPTxmiaXWEbJ9/D7 -GyyvnSU+grYTQ1A0uwP2s0BSLQIDAQABo4ICTTCCAkkwDgYDVR0PAQH/BAQDAgWg -MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0G -A1UdDgQWBBTworVujAZdUvNFFpTf2sGzOpesPzAfBgNVHSMEGDAWgBQULrMXt1hW -y65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6 -Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iu -b3JnLzAcBgNVHREEFTATghEqLmlwLm15Z2l0cG9kLmNvbTBMBgNVHSAERTBDMAgG -BmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3Bz -LmxldHNlbmNyeXB0Lm9yZzCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB2AESUZS6w -7s6vxEAH2Kj+KMDa5oK+2MsxtT/TM5a1toGoAAABdk6aW10AAAQDAEcwRQIhAMcN -Hzs+ZK5jo3z9jD/1u3RzGBue0zszlGM7MJutwZxIAiBZ1PtBWlKmVPdbGAeKh3z2 -nuESoMAfC2BxZIdxDVHvigB3AH0+8viP/4hVaCTCwMqeUol5K8UOeAl/LmqXaJl+ -IvDXAAABdk6aW6UAAAQDAEgwRgIhAJxMfsShji0opY170FyYH0075U+lR+0tQp5i -SJMd/CvhAiEAtAliQtVxUGQRm/jJHU8eLRBAKSlHy4CsUNyNIz01tiEwDQYJKoZI -hvcNAQELBQADggEBAI+CyB3fNbx1QilfEjNT00N2O6DM2jOQp3LxT+cc2c3ecGNn -QXc4E1tPGjnyJbNLG3TbHBGxY0vf9afAS9PH3fkikkh8jJvxKn4y53y3z5upRMTX -CVszAKtICHOWV35GK7GyymRF6u4v1rzBKn8Cy+P7ceo0QlpwxTTIqS8fFFl54c0t -uVq0TjmHpU75qLViyMAI85hvZs5Y6AHVvnae3iMw/f6z4LK4k71JCiLPGmc9rX9X -oRedO0pOK+fpYfoybLnVIrxWBv/ZRA1bToJ2c9bmvuwd7HdRQcKyDL+MlD1nyWCR -WlqQ/kLj80ipKlsVEponvNp7LBBJraRg/gfYjyo= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEZTCCA02gAwIBAgIQQAF1BIMUpMghjISpDBbN3zANBgkqhkiG9w0BAQsFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTIwMTAwNzE5MjE0MFoXDTIxMDkyOTE5MjE0MFow -MjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxCzAJBgNVBAMT -AlIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuwIVKMz2oJTTDxLs -jVWSw/iC8ZmmekKIp10mqrUrucVMsa+Oa/l1yKPXD0eUFFU1V4yeqKI5GfWCPEKp -Tm71O8Mu243AsFzzWTjn7c9p8FoLG77AlCQlh/o3cbMT5xys4Zvv2+Q7RVJFlqnB -U840yFLuta7tj95gcOKlVKu2bQ6XpUA0ayvTvGbrZjR8+muLj1cpmfgwF126cm/7 -gcWt0oZYPRfH5wm78Sv3htzB2nFd1EbjzK0lwYi8YGd1ZrPxGPeiXOZT/zqItkel -/xMY6pgJdz+dU/nPAeX1pnAXFK9jpP+Zs5Od3FOnBv5IhR2haa4ldbsTzFID9e1R -oYvbFQIDAQABo4IBaDCCAWQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E -BAMCAYYwSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5p -ZGVudHJ1c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTE -p7Gkeyxx+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEE -AYLfEwEBATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2Vu -Y3J5cHQub3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0 -LmNvbS9EU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYf -r52LFMLGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0B -AQsFAAOCAQEA2UzgyfWEiDcx27sT4rP8i2tiEmxYt0l+PAK3qB8oYevO4C5z70kH -ejWEHx2taPDY/laBL21/WKZuNTYQHHPD5b1tXgHXbnL7KqC401dk5VvCadTQsvd8 -S8MXjohyc9z9/G2948kLjmE6Flh9dDYrVYA9x2O+hEPGOaEOa1eePynBgPayvUfL -qjBstzLhWVQLGAkXXmNs+5ZnPBxzDJOLxhF2JIbeQAcH5H0tZrUlo5ZYyOqA7s9p -O5b85o3AM/OJ+CktFBQtfvBhcJVd9wvlwPsk+uyOy2HI7mNxKKgsBTt375teA2Tw -UdHkhVNcsAKX1H7GNNLOEADksd86wuoXvg== ------END CERTIFICATE----- diff --git a/components/proxy/nodomain-certs/privkey.pem b/components/proxy/nodomain-certs/privkey.pem deleted file mode 100644 index 22343b9a49d70d..00000000000000 --- a/components/proxy/nodomain-certs/privkey.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDVKZy53trHuqJy -FUKtlquL0GcE1JR3AxF42nfCvg9pEM+JQA4K3G8UOVIsvM3vwdSwzq/qgWmJ+zkc -acwjLXO75wzyuLmNC18YzbU5MVy+cqZZGu6hzQq6JLKeKrz467lyArjEWVGg0eA4 -aglYF1Ip9KWnfn8TkS/vTJjHinE5qgOj5pMEOaUtGFtTVdUlm1YkOpBHPsh0pKxC -ZW3GA97wkkc0Cly2tFJaCiL6g6PTgNykKBZlvA/Rm3xY7pUKWVsSpcO5oeO7W4WH -dcYzzVgK8v5rCqSAvRnLvyorgWrlvRsE9PGaJpdYRsn38PsbLK+dJT6CthNDUDS7 -A/azQFItAgMBAAECggEADyxUHKLxXdA6Kfa7dVHJSj1+Z8id/M66GqkqZzFSNX9d -1n45waopOf5OjCKwYgWhFyjPOtkVYx3/1bbuMf7VQyXSNSDTDGgnz8MsyDJsUJ4m -mycgn2HSBqgAEuQl6W4WGDh7YHafKdxmon1hxuR6E8R3WjHV59Wo3NbN9T40iw8e -t1W3xFrfGOUHjOw2FlOWsbA6NknB2f0TgC5MxnqOHHgiDFoEM423qn8o3GUqKawP -26QAuG5Qq00gTMHdfMKYMmY7zEJTqNYGN+HeLMxbQkW3fbP30IPnr6BvR7WV0oq7 -oN9aIiWCtKO0a1ivlFmLcyvKZkqu4Ijm/BKDTnDQQQKBgQD6QkPB+k3sDNbYLtZ7 -Sv+GiQWVhreH0+c6mHT8ZFk+JeY61MkLRjDrrYz6FdgHCxIM/tysH3Wsn2iqAT91 -0x5hzUr0Ry8YLOeVvJpxognZrnhIE5Hzu/hz4Y8ijEmyFRF9smRFOZZw1LkdykRe -kucI1UWCY7VPLozX87geaiAhcQKBgQDaDXxzvoo8u7b6nKK+9lbUa5QIDw8ChXhh -2GA6rnnPb4ImIzdo80n86iADqAe4SP8pqOyRfNILFciaJ7Z2RVRGNVyqUscXHOAY -hB2sVes4oh6IRu2oyPRFI07ED47IOn9DyQuKw+jW4SaOUpm86Fq8MsK6hnDsu5m8 -wmKLBZDefQKBgDr8WWokLC+iCxWjXIxs7fNw4m8O9L1AFfU6sAA5SsuaNTzSoJxW -q/swydS8R1HJqzSC8dJkC+FnJU1ExAdqfnPA5pTTHmeNVfx2GtUDw1yageFDM5iG -SpZNqOYUuN4PlzLQVE/4tdvcV9GMtjawW2I6moqUI80JBMt1t4T7sJ0RAoGAbDMU -9jouTkS3X1QqTaffHjjjk7wlLpMcUTEVTwkU2KH0awg+jo1qwV1L1YSjkAZo1ztD -aE4PzABbMmNSXw23676+5KV+tTFW4dNtBf78YXXQwL6xX3eX/lau1wsBRsoALJqu -Z4UfHMFMaIMEVoDVxV1K01Oy5UWR2+B5FZMFd+ECgYBPxaPSBixAMFcTDK0HcPYI -jqzEkP//5PWVoOSu4WySTnDH2pBhlAAb/MODU4kpVeCGDBf2cceWKyID7/IbO7Ga -u5zg+k/z4gqggj4RXMeD0fgWtwhftrluN7xoRCAWe2uWWLPAqEv9WO3C8PFy3jZ4 -7pO3vD2nsH1aI4stgWBXEQ== ------END PRIVATE KEY----- diff --git a/components/proxy/startup/nginx.sh b/components/proxy/startup/nginx.sh deleted file mode 100755 index b9ddef830e9c13..00000000000000 --- a/components/proxy/startup/nginx.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash -# Copyright (c) 2020 Gitpod GmbH. All rights reserved. -# Licensed under the GNU Affero General Public License (AGPL). -# See License-AGPL.txt in the project root for license information. - - -# If not set, read nameserver from resolv.conf (set by kubernetes) -if [ "$NAMESERVER" == "" ]; then - export NAMESERVER=`cat /etc/resolv.conf | grep "nameserver" | awk '{print $2}' | tr '\n' ' '` -fi - -export PROXY_DOMAIN_REGEX=${PROXY_DOMAIN//./\\.} -export PROXY_DOMAIN_COOKIE=${PROXY_DOMAIN//-/_} -export PROXY_DOMAIN_COOKIE=_${PROXY_DOMAIN_COOKIE//./_}_ -ORG_PATH=$PWD -cd /etc/nginx/ - -replaceEnvVars() { - echo "Updating $i" - envsubst '$KUBE_NAMESPACE,$PROXY_DOMAIN,$PROXY_DOMAIN_REGEX,$PROXY_DOMAIN_COOKIE,$NAMESERVER,$SERVER_PROXY_APIKEY' < $1 > /tmp/foo; - cp -f /tmp/foo $i -} - -### nginx config -# Clear existing config -cp /usr/local/openresty/nginx/conf/* /etc/nginx - -# Copy the gitpod-core config -# (-L does "unlink" and copies the target, not the symlink) -cp -RL /mnt/nginx/* /etc/nginx/ - -# Copy content of other configmaps if there: Copy it, too -if [ -d "/mnt/configmaps" ]; then - find /mnt/configmaps/*/* -maxdepth 1 | xargs -I % cp -RL % /etc/nginx/ -fi - -# Make readable and substitute variables -chmod -R +r /etc/nginx/ -for i in $(find . -name "*.conf"); do - replaceEnvVars $i -done - -### create certbot certificate -if [ ! -z "${CERTBOT_ENABLED}" ]; then - lama -d /var/www/lama -p 8003 & - LAMA_PID=$! - sleep 10 - certbot certonly --standalone --non-interactive -d ${PROXY_DOMAIN} -m ${CERTBOT_EMAIL} --agree-tos - kill -9 $LAMA_PID - mkdir -p /etc/nginx/certificates - cp -RL /etc/letsencrypt/archive/${PROXY_DOMAIN}/*.pem /etc/nginx/certificates/ - chmod -R +r /etc/nginx/certificates -fi - -### certificates -if [ -d /mnt/nginx/certificates/ ]; then - mkdir -p /etc/nginx/certificates; - cp -RL /mnt/nginx/certificates/*.pem /etc/nginx/certificates/ - chmod -R +r /etc/nginx/certificates -fi - -if [[ "$PROXY_DOMAIN" =~ .*ip.mygitpod.com ]]; then - echo "Domain is a ip.mygitpod.com domain - installing HTTPS certs" - mkdir -p /etc/nginx/certificates - cp /nodomain-certs/* /etc/nginx/certificates/ -fi - -### htpasswd for registry -if [ -d /mnt/nginx/registry-auth ]; then - cat /mnt/nginx/registry-auth/password | htpasswd -i -c /etc/nginx/registry-auth.htpasswd `cat /mnt/nginx/registry-auth/user` -fi - -if [ -d /mnt/nginx/ssl-dhparam/ ]; then - mkdir -p /etc/nginx/ssl-dhparam; - cp -RL /mnt/nginx/ssl-dhparam/*.key /etc/nginx/ssl-dhparam/ - chmod -R +r /etc/nginx/ssl-dh-param -fi - -echo "Using nginx config:" -find . -name "*.conf" - - -cd $ORG_PATH - -echo "Starting nginx" -exec nginx -c /etc/nginx/nginx.conf -g "daemon off;" \ No newline at end of file From d98dc058e1ec911786efc7d742ef17224dd95b3d Mon Sep 17 00:00:00 2001 From: Manuel Alejandro de Brito Fontes Date: Wed, 5 May 2021 07:54:18 -0400 Subject: [PATCH 4/4] [proxy] Configure Caddy --- .werft/values.dev.yaml | 4 - chart/templates/proxy-configmap.yaml | 50 ++++ components/proxy/BUILD.yaml | 3 +- components/proxy/Dockerfile | 50 +--- components/proxy/conf/Caddyfile | 244 ++++++++++++++++++ components/proxy/conf/vhost.empty | 1 + .../proxy/plugins/workspace/cors_origin.go | 122 +++++++++ .../plugins/workspace/download_workspace.go | 131 ++++++++++ components/proxy/plugins/workspace/go.mod | 8 + 9 files changed, 560 insertions(+), 53 deletions(-) create mode 100644 chart/templates/proxy-configmap.yaml create mode 100644 components/proxy/conf/Caddyfile create mode 100644 components/proxy/conf/vhost.empty create mode 100644 components/proxy/plugins/workspace/cors_origin.go create mode 100644 components/proxy/plugins/workspace/download_workspace.go create mode 100644 components/proxy/plugins/workspace/go.mod diff --git a/.werft/values.dev.yaml b/.werft/values.dev.yaml index dbb389ac9b1d64..b582f1abf7e926 100644 --- a/.werft/values.dev.yaml +++ b/.werft/values.dev.yaml @@ -8,11 +8,7 @@ hostname: staging.gitpod-dev.com imagePrefix: eu.gcr.io/gitpod-core-dev/build/ certificatesSecret: secretName: proxy-config-certificates - fullChainName: tls.crt - chainName: tls.crt - keyName: tls.key version: not-set -forceHTTPS: false imagePullPolicy: Always affinity: nodeAffinity: diff --git a/chart/templates/proxy-configmap.yaml b/chart/templates/proxy-configmap.yaml new file mode 100644 index 00000000000000..649489691f3340 --- /dev/null +++ b/chart/templates/proxy-configmap.yaml @@ -0,0 +1,50 @@ +# Copyright (c) 2021 Gitpod GmbH. All rights reserved. +# Licensed under the MIT License. See License-MIT.txt in the project root for license information. + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.components.proxy.name }}-config + labels: + app: {{ template "gitpod.fullname" $ }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +data: + vhost.empty: | + # Placeholder to avoid errors loading files using a glob pattern +{{- if index .Values "minio" "enabled" }} + vhost.minio: | + https://minio.{$GITPOD_DOMAIN} { + import enable_log + import remove_server_header + import ssl_configuration + + reverse_proxy {{ index .Values "minio" "fullnameOverride" }}.{{ .Release.Namespace }}.{$KUBE_DOMAIN}:9000 { + flush_interval -1 + } + } +{{- end }} +{{- if index .Values "docker-registry" "enabled" }} +{{- if index .Values "docker-registry" "authentication" -}} +{{ $t := set . "username" (index .Values "docker-registry" "authentication" "username") }} +{{ $t := set . "password" (index .Values "docker-registry" "authentication" "password") }} +{{- else }} +{{ $t := set . "username" (randAlphaNum 20) }} +{{ $t := set . "password" (randAlphaNum 20) }} +{{- end }} + vhost.docker-registry: | + https://minio.{$GITPOD_DOMAIN} { + import enable_log + import remove_server_header + import ssl_configuration + + basicauth bcrypt "Docker Registry" { + {{ .username }} {{ bcrypt .password | b64enc }} + } + + reverse_proxy https://{{ index .Values "docker-registry" "fullnameOverride" }}.{{ .Release.Namespace }}.{$KUBE_DOMAIN} { + flush_interval -1 + } + } +{{- end }} diff --git a/components/proxy/BUILD.yaml b/components/proxy/BUILD.yaml index a31ef3570b2509..f97969bdbb4fed 100644 --- a/components/proxy/BUILD.yaml +++ b/components/proxy/BUILD.yaml @@ -3,8 +3,7 @@ packages: type: docker srcs: - "conf/**" - - "startup/**" - - "nodomain-certs/**" + - "plugins/**" argdeps: - imageRepoBase config: diff --git a/components/proxy/Dockerfile b/components/proxy/Dockerfile index 993c78329f67b2..e8a00d4801cd80 100644 --- a/components/proxy/Dockerfile +++ b/components/proxy/Dockerfile @@ -2,55 +2,11 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License-AGPL.txt in the project root for license information. -FROM openresty/openresty:1.19.3.1-3-alpine - -ENV TRIGGER_REBUILD 1 +FROM aledbf/caddy-http2:0.5 # Debug convenience ENV TERM=xterm ENV SHELL=/bin/bash -RUN apk add --no-cache \ - vim \ - less \ - bind-tools \ - curl \ - apache2-utils \ - gettext \ - bash - -# Include certbot into the proxy for HTTPS termination -RUN curl -o /usr/bin/lama -sSL https://github.com/csweichel/lama/releases/download/v0.3.0/lama_0.3.0_Linux_x86_64 \ - && chmod +x /usr/bin/lama \ - && mkdir -p /var/www/lama/nginx \ - && touch /var/www/lama/nginx/status - -RUN apk add --no-cache \ - procps \ - certbot \ - certbot-nginx - -RUN set -e \ - && apk add --no-cache git \ - && cd /tmp \ - && git clone https://github.com/cloudflare/lua-resty-cookie/ \ - && cp lua-resty-cookie/lib/resty/*.lua /usr/local/openresty/site/lualib/ \ - && apk del git \ - && rm -rf /tmp/* - -# Update alpine packages -RUN apk upgrade --no-cache - -# nginx config templates... -#COPY conf/ /etc/nginx/ -# .. and startup script -COPY startup/nginx.sh /nginx.sh - -COPY conf/lua-prometheus /etc/nginx/lua-prometheus - -# ip.mygitpod.com HTTPS support -COPY nodomain-certs/* /nodomain-certs/ - -# Run! -EXPOSE 8080 -CMD ["/nginx.sh"] +COPY conf/Caddyfile /etc/caddy/Caddyfile +COPY conf/vhost.empty /etc/caddy/vhosts/vhost.empty diff --git a/components/proxy/conf/Caddyfile b/components/proxy/conf/Caddyfile new file mode 100644 index 00000000000000..877d8236b2a885 --- /dev/null +++ b/components/proxy/conf/Caddyfile @@ -0,0 +1,244 @@ +{ + # disable automatic SSL certificate generation + auto_https off + # disable admin API server + admin off + + # set default SNI for old clients + default_sni {$GITPOD_DOMAIN} + + # debug + + # configure plugin order + # https://caddyserver.com/docs/caddyfile/directives#directive-order + order gitpod.cors_origin before header + order gitpod.workspace_download before redir +} + +(compression) { + encode zstd gzip +} + +# configure headers to force HTTPS and enable more strict rules for the browser +(security_headers) { + header { + # enable HSTS + Strict-Transport-Security max-age=31536000 + # disable clients from sniffing the media type + X-Content-Type-Options nosniff + # Define valid parents that may embed a page + Content-Security-Policy "frame-ancestors self https://*.{$GITPOD_DOMAIN} https://{$GITPOD_DOMAIN}" + # keep referrer data off of HTTP connections + Referrer-Policy no-referrer-when-downgrade + # Enable cross-site filter (XSS) and tell browser to block detected attacks + X-XSS-Protection "1; mode=block" + + defer # delay changes + } +} + +(enable_log) { + log { + output stdout + format filter { + wrap json + fields { + logger delete + msg delete + size delete + status delete + resp_headers delete + request delete + } + } + } +} + +(remove_server_header) { + header { + -server + -x-powered-by + } +} + +(ssl_configuration) { + tls /etc/caddy/certificates/tls.crt /etc/caddy/certificates/tls.key { + #ca_root + } +} + +(upstream_headers) { + header_up X-Real-IP {http.request.remote.host} +} + +(upstream_connection) { + lb_try_duration 1s +} + +(debug_headers) { + header X-Gitpod-Region {$GITPOD_INSTALLATION_LONGNAME} +} + +# Kubernetes health-check +:8003 { + respond /live 200 + respond /ready 200 +} + +# always redirect to HTTPS +http:// { + redir https://{host}{uri} permanent +} + +https://{$GITPOD_DOMAIN} { + import enable_log + import remove_server_header + import ssl_configuration + import security_headers + + @workspace_download path /workspace-download* + handle @workspace_download { + header { + # The browser needs to see the correct archive content type to trigger the download. + content-type "application/tar+gzip" + -x-guploader-uploadid + -etag + -x-goog-generation + -x-goog-metageneration + -x-goog-hash + -x-goog-stored-content-length + -x-gitpod-region + -x-goog-stored-content-encoding + -x-goog-storage-class + -x-goog-generation + -x-goog-metageneration + -cache-control + -expires + + defer # delay changes + } + + gitpod.workspace_download { + service http://server.{$KUBE_NAMESPACE}.{$KUBE_DOMAIN}:3000 + } + + redir {http.gitpod.workspace_download_url} 303 + } + + @backend_wss path /api/gitpod + handle @backend_wss { + uri strip_prefix /api + reverse_proxy server.{$KUBE_NAMESPACE}.{$KUBE_DOMAIN}:3000 { + import upstream_headers + } + } + + @backend path /api/* /admin/* + handle @backend { + gitpod.cors_origin { + base_domain {$GITPOD_DOMAIN} + } + + import compression + + uri strip_prefix /api + reverse_proxy server.{$KUBE_NAMESPACE}.{$KUBE_DOMAIN}:3000 { + import upstream_headers + import upstream_connection + } + } + + @codesync path /code-sync* + handle @codesync { + gitpod.cors_origin { + base_domain {$GITPOD_DOMAIN} + } + + import compression + + reverse_proxy server.{$KUBE_NAMESPACE}.{$KUBE_DOMAIN}:3000 { + import upstream_headers + import upstream_connection + + flush_interval -1 + } + } + + @to_server path /auth/github/callback /auth /auth/* /apps /apps/* + handle @to_server { + import compression + + reverse_proxy server.{$KUBE_NAMESPACE}.{$KUBE_DOMAIN}:3000 { + import upstream_headers + import upstream_connection + } + } + + handle { + reverse_proxy dashboard.{$KUBE_NAMESPACE}.{$KUBE_DOMAIN}:3001 { + import upstream_headers + import upstream_connection + } + } + + handle_errors { + redir https://{$GITPOD_DOMAIN}/sorry/#Error%20{http.reverse_proxy.status_text} 302 + } +} + +# workspaces +https://*.*.{$GITPOD_DOMAIN} { + import enable_log + import security_headers + import remove_server_header + import ssl_configuration + import debug_headers + + @workspace_blobserve header_regexp host Host ^blobserve.ws(?P-[a-z0-9]+)?.{$GITPOD_DOMAIN} + handle @workspace_blobserve { + gitpod.cors_origin { + base_domain {$GITPOD_DOMAIN} + } + + reverse_proxy https://ws-proxy.{$KUBE_NAMESPACE}.{$KUBE_DOMAIN}:9090 { + transport http { + tls_insecure_skip_verify + } + + import upstream_headers + + header_up X-WSProxy-Host {http.request.host} + + header_down -access-control-allow-origin + } + } + + @workspace_port header_regexp host Host ^(webview-|browser-|extensions-)?(?P[0-9]{2,5})-(?P[a-z0-9][0-9a-z\-]+).ws(?P-[a-z0-9]+)?.{$GITPOD_DOMAIN} + handle @workspace_port { + reverse_proxy ws-{re.host.workspaceID}-ports.{$KUBE_NAMESPACE}.{$KUBE_DOMAIN}:{re.host.workspacePort} { + import upstream_headers + + header_up X-Gitpod-WorkspaceId {re.host.workspaceID} + header_up X-Gitpod-Port {re.host.workspacePort} + header_up X-WSProxy-Host {http.request.host} + } + } + + @workspace header_regexp host Host ^(webview-|browser-|extensions-)?(?P[a-z0-9][0-9a-z\-]+).ws(?P-[a-z0-9]+)?.{$GITPOD_DOMAIN} + handle @workspace { + reverse_proxy https://ws-proxy.{$KUBE_NAMESPACE}.{$KUBE_DOMAIN}:9090 { + transport http { + tls_insecure_skip_verify + } + + import upstream_headers + + header_up X-Gitpod-WorkspaceId {re.host.workspaceID} + header_up X-WSProxy-Host {http.request.host} + } + } + + respond "Not found" 404 +} + +import /etc/caddy/vhosts/vhost.* diff --git a/components/proxy/conf/vhost.empty b/components/proxy/conf/vhost.empty new file mode 100644 index 00000000000000..437774fd7d5f76 --- /dev/null +++ b/components/proxy/conf/vhost.empty @@ -0,0 +1 @@ +# Placeholder to avoid errors loading files using a glob pattern diff --git a/components/proxy/plugins/workspace/cors_origin.go b/components/proxy/plugins/workspace/cors_origin.go new file mode 100644 index 00000000000000..8782bcbb1c6f19 --- /dev/null +++ b/components/proxy/plugins/workspace/cors_origin.go @@ -0,0 +1,122 @@ +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package workspace + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile" + "github.com/caddyserver/caddy/v2/modules/caddyhttp" + "github.com/rs/cors" +) + +const ( + corsOriginModule = "gitpod.cors_origin" +) + +func init() { + caddy.RegisterModule(CorsOrigin{}) + httpcaddyfile.RegisterHandlerDirective(corsOriginModule, parseCorsOriginfile) +} + +// CorsOrigin implements an HTTP handler that generates a valid CORS Origin value +type CorsOrigin struct { + BaseDomain string `json:"base_domain,omitempty"` + Debug bool `json:"debug,omitempty"` +} + +// CaddyModule returns the Caddy module information. +func (CorsOrigin) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + ID: "http.handlers.gitpod_cors_origin", + New: func() caddy.Module { return new(CorsOrigin) }, + } +} + +var ( + allowedMethods = []string{http.MethodPost, http.MethodGet, http.MethodDelete, http.MethodOptions} + allowedHeaders = []string{"Accept", "Authorization", "Cache-Control", "Content-Type", "DNT", "Keep-Alive", "Origin", "User-Agent", + "If-Match", "If-Modified-Since", "If-None-Match", + "X-Requested-With", "X-Account-Type", "X-Client-Commit", "X-Client-Name", "X-Client-Version", "X-Execution-Id", "X-Machine-Id", "X-Machine-Session-Id", "X-User-Session-Id", + } + exposeHeaders = []string{"Authorization", "etag", "x-operation-id", "retry-after"} +) + +// ServeHTTP implements caddyhttp.MiddlewareHandler. +func (m CorsOrigin) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { + c := cors.New(cors.Options{ + AllowedOrigins: []string{"*." + m.BaseDomain}, + AllowedMethods: allowedMethods, + AllowedHeaders: allowedHeaders, + ExposedHeaders: exposeHeaders, + AllowCredentials: true, + MaxAge: 60, + Debug: m.Debug, + }) + + c.ServeHTTP(w, r, + func(w http.ResponseWriter, r *http.Request) { + next.ServeHTTP(w, r) + }, + ) + + return nil +} + +// UnmarshalCaddyfile implements Caddyfile.Unmarshaler. +func (m *CorsOrigin) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { + if !d.Next() { + return d.Err("expected token following filter") + } + + for d.NextBlock(0) { + key := d.Val() + var value string + d.Args(&value) + if d.NextArg() { + return d.ArgErr() + } + + switch key { + case "base_domain": + m.BaseDomain = value + case "debug": + b, err := strconv.ParseBool(value) + if err != nil { + return d.Errf("invalid boolean value for subdirective debug '%s'", value) + } + + m.Debug = b + default: + return d.Errf("unrecognized subdirective '%s'", value) + } + } + + if m.BaseDomain == "" { + return fmt.Errorf("Please configure the base_domain subdirective") + } + + return nil +} + +func parseCorsOriginfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { + m := new(CorsOrigin) + err := m.UnmarshalCaddyfile(h.Dispenser) + if err != nil { + return nil, err + } + + return m, nil +} + +// Interface guards +var ( + _ caddyhttp.MiddlewareHandler = (*CorsOrigin)(nil) + _ caddyfile.Unmarshaler = (*CorsOrigin)(nil) +) diff --git a/components/proxy/plugins/workspace/download_workspace.go b/components/proxy/plugins/workspace/download_workspace.go new file mode 100644 index 00000000000000..116b41da8aaf01 --- /dev/null +++ b/components/proxy/plugins/workspace/download_workspace.go @@ -0,0 +1,131 @@ +// Copyright (c) 2021 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package workspace + +import ( + "fmt" + "io" + "net/http" + "time" + + "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile" + "github.com/caddyserver/caddy/v2/modules/caddyhttp" +) + +const ( + workspaceDownloadModule = "gitpod.workspace_download" +) + +func init() { + caddy.RegisterModule(Download{}) + httpcaddyfile.RegisterHandlerDirective(workspaceDownloadModule, parseCaddyfile) +} + +// Download implements an HTTP handler that extracts gitpod headers +type Download struct { + Service string `json:"service,omitempty"` +} + +// CaddyModule returns the Caddy module information. +func (Download) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + ID: "http.handlers.gitpod_workspace_download", + New: func() caddy.Module { return new(Download) }, + } +} + +// ServeHTTP implements caddyhttp.MiddlewareHandler. +func (m Download) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { + repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) + + query := r.URL.RawQuery + if query != "" { + query = "?" + query + } + + url := fmt.Sprintf("%v%v%v", m.Service, r.URL.Path, query) + client := http.Client{Timeout: 5 * time.Second} + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return fmt.Errorf("Server Error: cannot download token OTS") + } + + // pass browser headers + // TODO (aledbf): check if it's possible to narrow the list + for k, vv := range r.Header { + for _, v := range vv { + req.Header.Add(k, v) + } + } + + // override content-type + req.Header.Set("Content-Type", "*/*") + + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("Server Error: cannot download token OTS") + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("Bad Request: /workspace-download/get returned with code %v", resp.StatusCode) + } + + redirectURL, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("Server error: cannot obtain redirect URL") + } + + repl.Set("http."+workspaceDownloadModule+"_url", string(redirectURL)) + + return next.ServeHTTP(w, r) +} + +// UnmarshalCaddyfile implements Caddyfile.Unmarshaler. +func (m *Download) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { + if !d.Next() { + return d.Err("expected token following filter") + } + + for d.NextBlock(0) { + key := d.Val() + var value string + d.Args(&value) + if d.NextArg() { + return d.ArgErr() + } + + switch key { + case "service": + m.Service = value + default: + return d.Errf("unrecognized subdirective '%s'", d.Val()) + } + } + + if m.Service == "" { + return fmt.Errorf("Please configure the service subdirective") + } + + return nil +} + +func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { + m := new(Download) + err := m.UnmarshalCaddyfile(h.Dispenser) + if err != nil { + return nil, err + } + + return m, nil +} + +// Interface guards +var ( + _ caddyhttp.MiddlewareHandler = (*Download)(nil) + _ caddyfile.Unmarshaler = (*Download)(nil) +) diff --git a/components/proxy/plugins/workspace/go.mod b/components/proxy/plugins/workspace/go.mod new file mode 100644 index 00000000000000..26c98625bf13dc --- /dev/null +++ b/components/proxy/plugins/workspace/go.mod @@ -0,0 +1,8 @@ +module github.com/gitpod-io/gitpod/proxy/plugins/workspace + +go 1.16 + +require ( + github.com/caddyserver/caddy/v2 v2.4.0 + github.com/rs/cors v1.6.0 +)