Skip to content

Commit

Permalink
Update nginx configs and fix gh action multi line output. (#615)
Browse files Browse the repository at this point in the history
* Update nginx configs and fix gh action multi line output.

* Update multi line GH output.
  • Loading branch information
EarthlingDavey authored Jul 29, 2024
1 parent ca995f9 commit 84d28ab
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 19 deletions.
11 changes: 8 additions & 3 deletions .github/workflows/ip-ranges-configure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
with:
repository: 'ministryofjustice/moj-ip-addresses'
ref: 'main'
# This is a fine grained PAT, it's scoped to the moj-ip private repository
# This is a fine-grained PAT, it's scoped to the moj-ip private repository
# with the single permission: Content: Read-only.
# The token is pending approval: https://github.com/settings/personal-access-tokens/3669004
token: ${{ secrets.MOJ_IP_ADDRESSES_RO_PAT }}
Expand All @@ -28,12 +28,17 @@ jobs:
uses: mikefarah/yq@master
with:
cmd: |
# Transform IPs into nginx geo format. 1 IP range per line, each range is followed by it's value.
# Transform IPs into nginx geo format. 1 IP range per line, each range is followed by its value.
# @see https://nginx.org/en/docs/http/ngx_http_geo_module.html
ALLOW_VALUE=1
DEPRI_VALUE=2
ALLOW_FORMATTED=$(yq 'explode(.) | .allow_access_to_moj_intranet | flatten | map(. + " '$ALLOW_VALUE';") | join("\n")' moj-cidr-addresses.yml)
DEPRI_FORMATTED=$(yq 'explode(.) | .deprecating_access_to_moj_intranet | flatten | map(. + " '$DEPRI_VALUE';") | join("\n")' moj-cidr-addresses.yml)
echo "ips_formatted=$ALLOW_FORMATTED"$'\n'"$DEPRI_FORMATTED" >> $GITHUB_OUTPUT
{
echo 'ips_formatted<<EOF'
echo "$ALLOW_FORMATTED"
echo "$DEPRI_FORMATTED"
echo EOF
} >> $GITHUB_OUTPUT
10 changes: 1 addition & 9 deletions deploy/config/local/nginx/server.conf
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,6 @@ server {
error_page 500 /app/themes/clarity/error-pages/500.html;
error_page 503 /app/themes/clarity/error-pages/maintenance.html;

location /app/themes/clarity/error-pages/401.html {
allow all;
}

location /app/themes/clarity/error-pages/403.html {
allow all;
}

# Empty location blocks to allow access when "/" location
# sends an HTTP 503 during maintenance mode
location /app/themes/clarity/error-pages/ { }
Expand Down Expand Up @@ -109,7 +101,7 @@ server {
set $skip_cache 1;
}

# ...it's from a logged in user, the cookie 'wordpress_no_cache' exists, or we're mid moj-auth flow.
# ...it's from a logged in user, the cookie 'wordpress_no_cache' exists.
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
Expand Down
12 changes: 12 additions & 0 deletions deploy/config/php-fpm-auth.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Config file to pass requests to specific scripts in the fpm container.
# Used for *some* auth requests where we don't want to load WordPress.

# Prepare and pass the request to fpm.
fastcgi_param SCRIPT_FILENAME $document_root$script_name;
include fastcgi_params;
# override SCRIPT_NAME which was set in fastcgi_params
fastcgi_param SCRIPT_NAME $script_name;
fastcgi_pass fpm;

# This is needed to be set explicitly, as this endpoint is hit as a subrequest.
fastcgi_no_cache 1;
78 changes: 71 additions & 7 deletions deploy/config/server.conf
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ fastcgi_cache_use_stale updating error timeout invalid_header http_500;
fastcgi_cache_key "$request_method$host$request_uri:$cookie_dw_agency";
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;


geo $ip_group {
default 0;
include /etc/nginx/geo.conf;
}

server {
listen 8080 default_server; # For default requests.
server_name localhost;
Expand All @@ -45,7 +51,7 @@ server {
}

error_page 400 /app/themes/clarity/error-pages/400.html;
error_page 401 /app/themes/clarity/error-pages/401.html;
error_page 401 /auth/401; # Use a dynamic 401 page, to conditionally rediect to login.
error_page 403 /app/themes/clarity/error-pages/403.html;
error_page 404 /app/themes/clarity/error-pages/404.html;
error_page 500 /app/themes/clarity/error-pages/500.html;
Expand All @@ -61,6 +67,11 @@ server {
rewrite ^/wp-content/uploads/(.*)$ /app/uploads/$1 permanent;
}

# We use the header X-Moj-Ip-Group internally, if the client sends this header return Bad Request.
if ($http_x_moj_ip_group) {
return 400;
}

##
# CACHING
##
Expand All @@ -82,18 +93,74 @@ server {
set $skip_cache 1;
}

# ...it's from a logged in user, or the cookie 'wordpress_no_cache' exists
# Don't cache any auth paths.
if ($request_uri ~* "^/auth/") {
set $skip_cache 1;
}

# ...it's from a logged in user, the cookie 'wordpress_no_cache' exists.
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}

# Skip cache if the concatenated value doesn't contain 200 - the user is not allowed.
# Use concatenation and !~ regex because we cant use the OR operator in nginx
if ($auth_status !~ 200) {
set $skip_cache 1;
}

location ~ /purge-cache(/.*) {
fastcgi_cache_purge mojiCache "$request_method$host$1:*";
}

location = /purge-all-cache {
fastcgi_cache_purge mojiCache "$request_method$host*";
}

location / {
# Every request must go through this subrequest.
auth_request /auth/verify;
# Concatenate the status returned by $ip_group and fpm query.
auth_request_set $auth_status $status$upstream_status;

# First attempt to serve request as file, then
# as a directory, then pass the request to
# WordPress's front controller.
try_files $uri $uri/ /index.php?$args;
}

# @see https://gock.net/blog/2020/nginx-subrequest-authentication-server
location = /auth/verify {
# Internal only, so /auth/verify can not be accessed from outside.
internal;

if ( $ip_group != 0 ) {
add_header X-Moj-Ip-Group $ip_group;
add_header Content-Type text/plain;
return 200;
}

# The subrequest handler, WordPress is not loaded in this file.
set $script_name /app/mu-plugins/moj-auth/verify.php;
include /etc/nginx/php-fpm-auth.conf;
}

location ~ ^/auth/(401) {
# Internal only, so /auth/verify can not be accessed from outside.
internal;

# The 401 handler, WordPress is not loaded in this file.
set $script_name /app/mu-plugins/moj-auth/$1.php;
include /etc/nginx/php-fpm-auth.conf;
}

# Rewrite auth endpoints to fpm (WordPress's index.php)
location ~ ^/auth/(login|callback) {
auth_request off;
fastcgi_param HTTP_X_MOJ_IP_GROUP $ip_group;
rewrite /auth/* /index.php?$args;
}

# deny access to dotfiles accept .well-known
# this will deny access to .git, .htaccess, .env, and other sensitive files
location ~ /\.(?!well-known).* {
Expand All @@ -114,11 +181,6 @@ server {
deny all;
}

location ~ /purge-cache(/.*) {
limit_req zone=flood burst=5 nodelay;
fastcgi_cache_purge mojiCache "$request_method$host$1:*";
}

# WordPress admin rate limit
location = /wp/wp-login.php {
limit_req zone=flood burst=5 nodelay;
Expand All @@ -127,6 +189,8 @@ server {
}

location ~ \.php$ {
# Send the IP status along, to use in in the application.
fastcgi_param HTTP_X_MOJ_IP_GROUP $ip_group;
include /etc/nginx/php-fpm.conf;
fastcgi_pass fpm;
}
Expand Down

0 comments on commit 84d28ab

Please sign in to comment.