-
Notifications
You must be signed in to change notification settings - Fork 484
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Repair CORS support in Snap NGINX (#4644)
Closes #4627 Signed-off-by: Bryon Nevis <bryon.nevis@intel.com>
- Loading branch information
Showing
6 changed files
with
260 additions
and
146 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
254 changes: 254 additions & 0 deletions
254
snap/local/runtime-helpers/bin/security-bootstrapper-nginx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
#!/bin/bash | ||
|
||
keyfile=nginx.key | ||
certfile=nginx.crt | ||
|
||
# Check for default TLS certificate for reverse proxy, create if missing | ||
# Normally we would run the below command in the nginx container itself, | ||
# but nginx:alpine-slim does not container openssl, thus run it here instead. | ||
mkdir -p "${SNAP_DATA}/nginx" | ||
cd "${SNAP_DATA}/nginx" | ||
if test ! -f "${keyfile}" ; then | ||
# (NGINX will restart in a failure loop until a TLS key exists) | ||
# Create default TLS certificate with 1 day expiry -- user must replace in production (do this as nginx user) | ||
openssl req -x509 -nodes -days 1 -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -subj '/CN=localhost/O=EdgeX Foundry' -keyout "${keyfile}" -out "${certfile}" -addext "keyUsage = digitalSignature, keyCertSign" -addext "extendedKeyUsage = serverAuth" | ||
echo "Default TLS certificate created. Recommend replace with your own." | ||
fi | ||
|
||
|
||
# | ||
# Import CORS configuration from common config | ||
# | ||
|
||
: ${EDGEX_SERVICE_CORSCONFIGURATION_ENABLECORS:=`yq -r .all-services.Service.CORSConfiguration.EnableCORS $SNAP_DATA/config/core-common-config-bootstrapper/res/configuration.yaml`} | ||
: ${EDGEX_SERVICE_CORSCONFIGURATION_CORSALLOWCREDENTIALS:=`yq -r .all-services.Service.CORSConfiguration.CORSAllowCredentials $SNAP_DATA/config/core-common-config-bootstrapper/res/configuration.yaml`} | ||
: ${EDGEX_SERVICE_CORSCONFIGURATION_CORSALLOWEDORIGIN:=`yq -r .all-services.Service.CORSConfiguration.CORSAllowedOrigin $SNAP_DATA/config/core-common-config-bootstrapper/res/configuration.yaml`} | ||
: ${EDGEX_SERVICE_CORSCONFIGURATION_CORSALLOWEDMETHODS:=`yq -r .all-services.Service.CORSConfiguration.CORSAllowedMethods $SNAP_DATA/config/core-common-config-bootstrapper/res/configuration.yaml`} | ||
: ${EDGEX_SERVICE_CORSCONFIGURATION_CORSALLOWEDHEADERS:=`yq -r .all-services.Service.CORSConfiguration.CORSAllowedHeaders $SNAP_DATA/config/core-common-config-bootstrapper/res/configuration.yaml`} | ||
: ${EDGEX_SERVICE_CORSCONFIGURATION_CORSEXPOSEHEADERS:=`yq -r .all-services.Service.CORSConfiguration.CORSExposeHeaders $SNAP_DATA/config/core-common-config-bootstrapper/res/configuration.yaml`} | ||
: ${EDGEX_SERVICE_CORSCONFIGURATION_CORSMAXAGE:=`yq -r .all-services.Service.CORSConfiguration.CORSMaxAge $SNAP_DATA/config/core-common-config-bootstrapper/res/configuration.yaml`} | ||
|
||
echo "$(date) CORS settings dump ..." | ||
( set | grep EDGEX_SERVICE_CORSCONFIGURATION ) || true | ||
|
||
corssnippet=/tmp/cors.block.$$ | ||
touch "${corssnippet}" | ||
if test "${EDGEX_SERVICE_CORSCONFIGURATION_ENABLECORS}" = "true"; then | ||
echo " if (\$request_method = 'OPTIONS') {" >> "${corssnippet}" | ||
echo " add_header 'Access-Control-Allow-Origin' '${EDGEX_SERVICE_CORSCONFIGURATION_CORSALLOWEDORIGIN}';" >> "${corssnippet}" | ||
echo " add_header 'Access-Control-Allow-Methods' '${EDGEX_SERVICE_CORSCONFIGURATION_CORSALLOWEDMETHODS}';" >> "${corssnippet}" | ||
echo " add_header 'Access-Control-Allow-Headers' '${EDGEX_SERVICE_CORSCONFIGURATION_CORSALLOWEDHEADERS}';" >> "${corssnippet}" | ||
# Access-Control-Expose-Headers should not be set on OPTIONS request | ||
if test "${EDGEX_SERVICE_CORSCONFIGURATION_CORSALLOWCREDENTIALS}" = "true"; then | ||
# CORS specificaiton says that if not true, omit the header entirely | ||
echo " add_header 'Access-Control-Allow-Credentials' '${EDGEX_SERVICE_CORSCONFIGURATION_CORSALLOWCREDENTIALS}';" >> "${corssnippet}" | ||
fi | ||
echo " add_header 'Access-Control-Max-Age' ${EDGEX_SERVICE_CORSCONFIGURATION_CORSMAXAGE};" >> "${corssnippet}" | ||
echo " add_header 'Vary' 'origin';" >> "${corssnippet}" | ||
echo " add_header 'Content-Type' 'text/plain; charset=utf-8';" >> "${corssnippet}" | ||
echo " add_header 'Content-Length' 0;" >> "${corssnippet}" | ||
echo " return 204;" >> "${corssnippet}" | ||
echo " }" >> "${corssnippet}" | ||
echo " if (\$request_method != 'OPTIONS') {" >> "${corssnippet}" | ||
# Always add headers regardless of response code. Omit preflight-related headers (allow-methods, allow-headers, allow-credentials, max-age) | ||
echo " add_header 'Access-Control-Allow-Origin' '${EDGEX_SERVICE_CORSCONFIGURATION_CORSALLOWEDORIGIN}' always;" >> "${corssnippet}" | ||
echo " add_header 'Access-Control-Expose-Headers' '${EDGEX_SERVICE_CORSCONFIGURATION_CORSEXPOSEHEADERS}' always;" >> "${corssnippet}" | ||
echo " add_header 'Vary' 'origin' always;" >> "${corssnippet}" | ||
echo " }" >> "${corssnippet}" | ||
echo "" >> "${corssnippet}" | ||
fi | ||
|
||
# | ||
# Generate NGINX configuration based on EDGEX_ADD_PROXY_ROUTE and standard settings | ||
# | ||
|
||
echo "$(date) Generating default NGINX config ..." | ||
|
||
IFS=', ' | ||
for service in ${EDGEX_ADD_PROXY_ROUTE}; do | ||
prefix=$(echo -n "${service}" | sed -n -e 's/\([-0-9a-zA-Z]*\)\..*/\1/p') | ||
host=$(echo -n "${service}" | sed -n -e 's/.*\/\/\([-0-9a-zA-Z]*\):.*/\1/p') | ||
port=$(echo -n "${service}" | sed -n -e 's/.*:\(\d*\)/\1/p') | ||
varname=$(echo -n "${prefix}" | tr '-' '_') | ||
echo $service $prefix $host $port | ||
cat <<EOH >> "${SNAP_DATA}/nginx/conf.d/generated-routes.inc" | ||
set \$upstream_$varname $host; | ||
location /$prefix { | ||
`cat "${corssnippet}"` | ||
rewrite /$prefix/(.*) /\$1 break; | ||
resolver 127.0.0.11 valid=30s; | ||
proxy_pass http://\$upstream_$varname:$port; | ||
proxy_redirect off; | ||
proxy_set_header Host \$host; | ||
auth_request /auth; | ||
auth_request_set \$auth_status \$upstream_status; | ||
} | ||
EOH | ||
|
||
done | ||
unset IFS | ||
|
||
|
||
# This file can be modified by the user; deleted when docker volumes are pruned; | ||
# but preserved across start/up and stop/down actions | ||
if test -f "${SNAP_DATA}/nginx/conf.d/edgex-custom-rewrites.inc"; then | ||
echo "Using existing custom-rewrites." | ||
else | ||
cat <<'EOH' > "${SNAP_DATA}/nginx/conf.d/edgex-custom-rewrites.inc" | ||
# Add custom location directives to this file, for example: | ||
# set $upstream_device_virtual edgex-device-virtual; | ||
# location /device-virtual { | ||
# rewrite /device-virtual/(.*) /$1 break; | ||
# resolver 127.0.0.11 valid=30s; | ||
# proxy_pass http://$upstream_device_virtual:59900; | ||
# proxy_redirect off; | ||
# proxy_set_header Host $host; | ||
# auth_request /auth; | ||
# auth_request_set $auth_status $upstream_status; | ||
# } | ||
EOH | ||
fi | ||
|
||
cat <<EOH > "${SNAP_DATA}/nginx/conf.d/edgex-default.conf" | ||
# | ||
# Copyright (C) Intel Corporation 2023 | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# generated 2023-01-19, Mozilla Guideline v5.6, nginx 1.17.7, OpenSSL 1.1.1k, modern configuration, no HSTS, no OCSP | ||
# https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=modern&openssl=1.1.1k&hsts=false&ocsp=false&guideline=5.6 | ||
server { | ||
listen 127.0.0.1:8000; # Snap listen insecure on localhost only | ||
listen 8443 ssl; | ||
ssl_certificate "/var/snap/edgexfoundry/current/nginx/nginx.crt"; | ||
ssl_certificate_key "/var/snap/edgexfoundry/current/nginx/nginx.key"; | ||
ssl_session_tickets off; | ||
access_log syslog:server=unix:/dev/log,tag=edgexfoundry; | ||
# Subrequest authentication | ||
location /auth { | ||
internal; | ||
proxy_pass http://127.0.0.1:59842; | ||
proxy_redirect off; | ||
proxy_set_header Host \$host; | ||
proxy_set_header Content-Length ""; | ||
proxy_set_header X-Forwarded-URI \$request_uri; | ||
proxy_pass_request_body off; | ||
} | ||
# Rewriting rules (customized for snaps) | ||
location /core-data { | ||
`cat "${corssnippet}"` | ||
rewrite /core-data/(.*) /\$1 break; | ||
proxy_pass http://127.0.0.1:59880; | ||
proxy_redirect off; | ||
proxy_set_header Host \$host; | ||
auth_request /auth; | ||
auth_request_set \$auth_status \$upstream_status; | ||
} | ||
location /core-metadata { | ||
`cat "${corssnippet}"` | ||
rewrite /core-metadata/(.*) /\$1 break; | ||
proxy_pass http://127.0.0.1:59881; | ||
proxy_redirect off; | ||
proxy_set_header Host \$host; | ||
auth_request /auth; | ||
auth_request_set \$auth_status \$upstream_status; | ||
} | ||
location /core-command { | ||
`cat "${corssnippet}"` | ||
rewrite /core-command/(.*) /\$1 break; | ||
proxy_pass http://127.0.0.1:59882; | ||
proxy_redirect off; | ||
proxy_set_header Host \$host; | ||
auth_request /auth; | ||
auth_request_set \$auth_status \$upstream_status; | ||
} | ||
location /support-notifications { | ||
`cat "${corssnippet}"` | ||
rewrite /support-notifications/(.*) /\$1 break; | ||
proxy_pass http://127.0.0.1:59860; | ||
proxy_redirect off; | ||
proxy_set_header Host \$host; | ||
auth_request /auth; | ||
auth_request_set \$auth_status \$upstream_status; | ||
} | ||
location /support-scheduler { | ||
`cat "${corssnippet}"` | ||
rewrite /support-scheduler/(.*) /\$1 break; | ||
proxy_pass http://127.0.0.1:59861; | ||
proxy_redirect off; | ||
proxy_set_header Host \$host; | ||
auth_request /auth; | ||
auth_request_set \$auth_status \$upstream_status; | ||
} | ||
location /app-rules-engine { | ||
`cat "${corssnippet}"` | ||
rewrite /app-rules-engine/(.*) /\$1 break; | ||
proxy_pass http://127.0.0.1:59701; | ||
proxy_redirect off; | ||
proxy_set_header Host \$host; | ||
auth_request /auth; | ||
auth_request_set \$auth_status \$upstream_status; | ||
} | ||
location /rules-engine { | ||
`cat "${corssnippet}"` | ||
rewrite /rules-engine/(.*) /\$1 break; | ||
proxy_pass http://127.0.0.1:59720; | ||
proxy_redirect off; | ||
proxy_set_header Host \$host; | ||
auth_request /auth; | ||
auth_request_set \$auth_status \$upstream_status; | ||
} | ||
# Note: Consul implements its own authentication mechanism (only allow API, /v1, through) | ||
location /consul/v1 { | ||
`cat "${corssnippet}"` | ||
rewrite /consul/(.*) /\$1 break; | ||
proxy_pass http://127.0.0.1:8500; | ||
proxy_redirect off; | ||
proxy_set_header Host \$host; | ||
} | ||
# Note: Vault login API does not require authentication at the gateway for obvious reasons | ||
# Expose URLs to log in to vault and to get a JWT | ||
location /vault/v1/auth/userpass/login { | ||
`cat "${corssnippet}"` | ||
rewrite /vault/(.*) /\$1 break; | ||
proxy_pass http://127.0.0.1:8200; | ||
proxy_redirect off; | ||
proxy_set_header Host \$host; | ||
} | ||
location /vault/v1/identity/oidc/token { | ||
`cat "${corssnippet}"` | ||
rewrite /vault/(.*) /\$1 break; | ||
proxy_pass http://127.0.0.1:8200; | ||
proxy_redirect off; | ||
proxy_set_header Host \$host; | ||
} | ||
include /var/snap/edgexfoundry/current/nginx/conf.d/edgex-custom-rewrites.inc; | ||
} | ||
# Don't output NGINX version in Server: header | ||
server_tokens off; | ||
EOH | ||
|
||
rm -f "${corssnippet}" |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.