Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Dockerfile.buildkit.plus
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ ENV PROXY_CACHE_VALID_OK "1h"
ENV PROXY_CACHE_VALID_NOTFOUND "1m"
ENV PROXY_CACHE_VALID_FORBIDDEN "30s"

ENV PROXY_CACHE_VALID_OK "1h"
ENV PROXY_CACHE_VALID_NOTFOUND "1m"
ENV PROXY_CACHE_VALID_FORBIDDEN "30s"
ENV CORS_ENABLED 0

COPY plus/usr /usr

# Copy files from the OSS NGINX Docker container such that the container
Expand Down
1 change: 1 addition & 0 deletions Dockerfile.oss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ ENV NJS_VERSION 0.7.9
ENV PROXY_CACHE_VALID_OK "1h"
ENV PROXY_CACHE_VALID_NOTFOUND "1m"
ENV PROXY_CACHE_VALID_FORBIDDEN "30s"
ENV CORS_ENABLED 0

# We modify the nginx base image by:
# 1. Adding configuration files needed for proxying private S3 buckets
Expand Down
1 change: 1 addition & 0 deletions Dockerfile.plus
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ ENV XSLT_VERSION 28-1
ENV PROXY_CACHE_VALID_OK "1h"
ENV PROXY_CACHE_VALID_NOTFOUND "1m"
ENV PROXY_CACHE_VALID_FORBIDDEN "30s"
ENV CORS_ENABLED 0

COPY plus/etc/ssl /etc/ssl
COPY plus/usr /usr
Expand Down
4 changes: 3 additions & 1 deletion common/docker-entrypoint.d/00-check-for-required-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ set -e
failed=0

required=("S3_BUCKET_NAME" "S3_SERVER" "S3_SERVER_PORT" "S3_SERVER_PROTO"
"S3_REGION" "S3_STYLE" "ALLOW_DIRECTORY_LIST" "AWS_SIGS_VERSION")
"S3_REGION" "S3_STYLE" "ALLOW_DIRECTORY_LIST" "AWS_SIGS_VERSION"
"CORS_ENABLED")

# Require some form of authentication to be configured.

Expand Down Expand Up @@ -107,3 +108,4 @@ echo "Directory Listing Enabled: ${ALLOW_DIRECTORY_LIST}"
echo "Provide Index Pages Enabled: ${PROVIDE_INDEX_PAGE}"
echo "Append slash for directory enabled: ${APPEND_SLASH_FOR_POSSIBLE_DIRECTORY}"
echo "Stripping the following headers from responses: x-amz-;${HEADER_PREFIXES_TO_STRIP}"
echo "CORS Enabled: ${CORS_ENABLED}"
32 changes: 31 additions & 1 deletion common/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
#!/usr/bin/env bash
#
# Copyright 2020 F5 Networks
#
Expand All @@ -19,11 +19,41 @@

set -e

parseBoolean() {
case "$1" in
TRUE | true | True | YES | Yes | 1)
echo 1
;;
*)
echo 0
;;
esac
}

# This line is an addition to the NGINX Docker image's entrypoint script.
if [ -z ${DNS_RESOLVERS+x} ]; then
export DNS_RESOLVERS="$(cat /etc/resolv.conf | grep nameserver | cut -d' ' -f2 | xargs)"
fi

# Normalize the CORS_ENABLED environment variable to a numeric value
# so that it can be easily parsed in the nginx configuration.
export CORS_ENABLED="$(parseBoolean "${CORS_ENABLED}")"

# By enabling CORS, we also need to enable the OPTIONS method which
# is not normally used as part of the gateway. The following variable
# defines the set of acceptable headers.
if [ "${CORS_ENABLED}" == "1" ]; then
export LIMIT_METHODS_TO="GET HEAD OPTIONS"
export LIMIT_METHODS_TO_CSV="GET, HEAD, OPTIONS"
else
export LIMIT_METHODS_TO="GET HEAD"
export LIMIT_METHODS_TO_CSV="GET, HEAD"
fi
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(posting for visibility, not a change request) I had questions about whether it was necessary to fork the logic here just to exclude OPTIONS since it has general usage outside the context of CORS. However it seems that for S3 it's only really applicable to the CORS case

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it seems unnecessary because this approach is stemming from my security paranoia. I don't want to provide any paths to allow for proxying requests to the underlying S3 bucket beyond the narrow operations defined. As such, I'm going out of my way here to lock down the HTTP verbs to only GET/HEAD or in the case of CORS GET/HEAD/OPTIONS.


if [ -z "${CORS_ALLOWED_ORIGIN+x}" ]; then
export CORS_ALLOWED_ORIGIN="*"
fi

# Nothing is modified under this line

if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then
Expand Down
21 changes: 20 additions & 1 deletion common/etc/nginx/templates/default.conf.template
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ server {
}

location / {
# This value is templated in based on the value of $CORS_ENABLED. When
# CORS is enabled, acceptable methods are GET, HEAD, and OPTIONS.
# Otherwise, they are GET and HEAD.
limit_except ${LIMIT_METHODS_TO} {}

# CORS is implemented by returning the appropriate headers as part of
# the response to an OPTIONS request. If you want to customize the
# CORS response, the cors.conf.template file can be overwritten and
# extended to meet one's needs.
include /etc/nginx/conf.d/gateway/cors.conf;

auth_request /aws/credentials/retrieve;

# Redirect to the proper location based on the client request - either
Expand All @@ -86,6 +97,10 @@ server {
# we plan to use.
include /etc/nginx/conf.d/gateway/v${AWS_SIGS_VERSION}_headers.conf;

# The CORS configuration needs to be imported in several places in order for
# it to be applied within different contexts.
include /etc/nginx/conf.d/gateway/cors.conf;

# Don't allow any headers from the client - we don't want them messing
# with S3 at all.
proxy_pass_request_headers off;
Expand Down Expand Up @@ -128,6 +143,10 @@ server {
# we plan to use.
include /etc/nginx/conf.d/gateway/v${AWS_SIGS_VERSION}_headers.conf;

# The CORS configuration needs to be imported in several places in order for
# it to be applied within different contexts.
include /etc/nginx/conf.d/gateway/cors.conf;

# Don't allow any headers from the client - we don't want them messing
# with S3 at all.
proxy_pass_request_headers off;
Expand Down Expand Up @@ -193,7 +212,7 @@ server {
# Provide a hint to the client on 405 errors of the acceptable request methods
error_page 405 @error405;
location @error405 {
add_header Allow "GET, HEAD" always;
add_header Allow "${LIMIT_METHODS_TO_CSV}" always;
return 405;
}

Expand Down
31 changes: 31 additions & 0 deletions common/etc/nginx/templates/gateway/cors.conf.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
set $request_cors "${request_method}_${CORS_ENABLED}";

if ($request_cors = "OPTIONS_1") {
add_header 'Access-Control-Allow-Origin' '${CORS_ALLOWED_ORIGIN}';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that this is included in a location block, could/should this be rewritten using map to avoid the "if is evil in a location block" issue?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the OPTIONS if, it seems to fall under the category of "good ifs":

There are cases where you simply cannot avoid using an if, for example, if you need to test a variable which has no equivalent directive.

As for the other ifs, I believe they are ok due to there being no ifs after them. However, I have no idea how you would be able to do the same operation with map. Ideally, I wanted to conditionally template in the cors.conf include, but that seemed a bit too clunky. I guess I could conditional set an env var with the whole include statement in docker-entrypoint.sh.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this certainly is the best for understandibility. I wouldn't add more moving parts if it's testing ok. I'm going to play around with making it work with map because I'm curious now but let's not let it hold up the PR.


if ($request_cors = "GET_1") {
add_header 'Access-Control-Allow-Origin' '${CORS_ALLOWED_ORIGIN}' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
}

if ($request_cors = "HEAD_1") {
add_header 'Access-Control-Allow-Origin' '${CORS_ALLOWED_ORIGIN}' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why Access-Control-Expose-Headers is not sent in the OPTIONS response?

}
12 changes: 11 additions & 1 deletion docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,17 @@ running as a Container or as a Systemd service.
* `PROXY_CACHE_VALID_NOTFOUND` - Sets caching time for response code 404
* `PROXY_CACHE_VALID_FORBIDDEN` - Sets caching time for response code 403
* `JS_TRUSTED_CERT_PATH` - (optional) Enables the `js_fetch_trusted_certificate` directive when retrieving AWS credentials and sets the path (on the container) to the specified path
* `HEADER_PREFIXES_TO_STRIP` - (optional) a list of HTTP header prefixes that exclude headers client responses. List should be specified in lower-case and a semicolon (;) should be used to as a deliminator between values. For example: `x-goog-;x-something-`
* `HEADER_PREFIXES_TO_STRIP` - (optional) a list of HTTP header prefixes that exclude headers client responses. List should be specified in lower-case and a semicolon (;) should be used to as a deliminator between values. For example: `x-goog-;x-something-`
* `CORS_ENABLED` - Flag (true/false) that enables CORS headers on GET
requests and enables pre-flight OPTIONS requests. If enabled, this will
add CORS headers for "fully open" cross domain requests by default,
meaning all domains are allowed, similar to the settings show in
[this example](https://enable-cors.org/server_nginx.html).
CORS settings can be fine-tuned by overwriting the
[`cors.conf.template`](/common/etc/nginx/templates/gateway/cors.conf.template) file. (default: false)
* `CORS_ALLOWED_ORIGIN` - (optional) value to set to be returned from the
CORS `Access-Control-Allow-Origin` header. This value is only used if
CORS is enabled. (default: *)

If you are using [AWS instance profile credentials](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2.html),
you will need to omit the `S3_ACCESS_KEY_ID` and `S3_SECRET_KEY` variables from
Expand Down