CORS problems in microservices architecture - nginx

After a lot of searches and tries, I have decided to post my problems around CORS.
Context
I have a web site on a local server (NGINX), located on a PI. My web site deals with a microservice through REST API.
My PI is behind my Freebox (French internet box), which redirect a specific port (ex : 28800) to the local # of my pi. FYI, I don't have (and don't want) a fixed IP. And I share my IP with others users. So, I have a range of ports between 20000 and 30000 (approximatively).
And I have a NO-IP hostname, pointed on my freebox IP completed with the specifc port.
To resume:
User -> mysite.no-ip.com ---(Translation NO-IP)---> 91.123.456.678:specifcport ---- (Redirect to my pi) ---> 192.168.0.30:80----(nginx)--->index.html
What I can do:
In my nginx site conf, I set a location /core.
When I do
mysite.no-ip.com/core/blabla, I well obtain the blabla treatment.
No problem!!
Here is my problem:
When I click on the button which launches the blabla action (throught an AJAX POST on mysite.no-ip.comm/core/blabla), I get a CORS failure.
I have tried to modify my nginx configuration, adding headers depends of OPTIONS/GET/POST request type. Nothing appends.
But, I find that my nginx is never touched by the request /core/blabla if this one is send by button. I have a CORS answer thrown by an APACHE Server. And I didn't install any APACHE Server. So, perhaps, it's a server hidden in my Freebox? Don't know how to set it to allow CORS request.
Here is a snippet of my nginx config file
server {
listen 80;
server_name mysite.no-ip.com
location / {
alias /path/to/root/production/folder/here;
}
location /core/ {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
proxy_pass http://localhost:8002/;
}
}
Thank you for your help.

Ok, Fix my problem which was solved by a combination of my Internet provider box configuration and addition of some headers on my request.

Related

with nginx, how do i pass setup authentication from a response

a bit confused about the process here:
i have a keycloak container that once i login gives me something like this:
http://10.357.35.22/mainpage/?session_state=604471e5-6ecc-454e-9839-ef57a1b4d767&code=9e59150c-8944-42c5-9590-ac1184af8e68.604471e5-6ecc-454e-9839-ef57a1b4d767.2d2b79fc-8cdc-4ed0-8ca6-1031d256a020
i have no idea what to do with this in the mainpage location:
location /mainpage/ {
alias /usr/share/nginx/html;
index index.html;
}
how would i go about check whatever headers against a secret i have.
here is the authentication location:
location / {
proxy_pass http://10.357.35.22:5555/keys/realms/my_realm/protocol/openid-connect/auth?response_type=code&client_id=landing_page&redirect_uri=http://10.357.35.22:5555/mainpage/
# allow the CROS requests
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Sinc>
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
i'm just trying to put up a login screen in front of an app...so i've spent a long time trying to get to here, but i'm honestly stuck. i could request for a token, but again, not sure how to use it in nginx.
nginx and keycloak are both in docker containers.

Nginx uinit cors

I want to handle cors on nginx unit level but I don't know how it make on nginx unit.
Example config for nginx
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, OPTIONS, DELETE, PATCH';
add_header 'Access-Control-Allow-Headers' 'Authorization,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range';
add_header 'Access-Control-Expose-Headers' 'Gc-Export-Errors';
return 204;
}
How I can do this for nginx unit?
Currently, Nginx Unit doesn't support functionality equal to add_header so if you need custom headers for 204 response it should be done using application. And configuration will looks like this:
{
"match":{
"method": "OPTIONS"
},
"action":{
"proxy": "path/to/app_return_204_with_custom_headers"
}
}

django-cors-headers and nginx config: preflight response missing CORS headers

I use django-cors-headers 3.1.1 for handling the requests and responses between my Django-backend and Javascript-frontend apps. Transport is non-secured (i.e. http, not https).
When hosted locally, everything works fine. But after deploying on the server, I stopped seeing the CORS headers.
Here are headers in development:
and in production:
Error message:
Access to XMLHttpRequest at 'http://[HOST_IP]/api/assets/' from origin 'http://my_custom_domain.eu' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
My nginx configurations looks as follows:
server {
listen 80;
server_name [HOST_IP];
location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/[path_to_app]/app.sock;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Max-Age' 86400;
if ($request_method = 'OPTIONS') {
add_header 'Content-Type' 'text/html; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'PUT') {
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}
location /static/ {
autoindex on;
alias /home/ubuntu/[path_to_app]/site/static/;
}
}
The django-cors-headers’ settings are now identical in development and in production:
INSTALLED_APPS = (
…
"corsheaders",
…
)
MIDDLEWARE = [
…
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
…
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = ['DELETE','GET','OPTIONS','PATCH','POST','PUT']
On the client side I tried to add ‘'Access-Control-Request-Method’: ‘PUT’ header, but this was refused by the browser. There’s noting unusual in the client call:
axios({
method: 'put',
url: `${this.backendUrl}/api/assets/`,
data: formData,
headers: {
'Content-Type': 'application/octet-stream',
}
})
Also, I’m trying to host on the Amazon AWS EC2 for the first time, so perhaps there is some required AWS configuration I am not aware of. For example, is it necessary to enable CORS using the API Gateway? The documentation does not say so (‘If you are using the API Gateway Import API, you can set up CORS support using an OpenAPI file’).
The frontend application is hosted on a S3 bucket with the following CORS policy:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
What am I missing here? Is there some needed server-side (nginx especially) configuration?
Some other solutions I’ve tried:
I have doubts, whether the request/response origin is correct (e.g. APPEND_SLASH variable). But if this is the case, shouldn’t an error be raised when hosted locally?
I also tried setting proxy headers as in this question, but without knowing nginx very well this was doomed to fail.
I managed to solve this issue by changing 3 things:
AWS
I noticed that AWS documentation states:
CORS is already enabled for the Amazon EC2 API, and is ready for you
to use. You do not need to perform any additional configuration steps
to start using this feature. There is no change to the way that you
make calls to the Amazon EC2 API; they must still be signed with valid
AWS credentials to ensure that AWS can authenticate the requestor. […]
This is usually handled by AWS SDK or CLI, but in my case I used none of them, so I had to add AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. In my case I simply used aws4 library:
axios(aws4.sign({
accessKeyId: this.awsAccessKey,
secretAccessKey: this.awsSecretAccessKey,
method: 'put',
url: `${this.backendUrl}/api/assets/`,
data: formData,
body: JSON.stringify(formData),
service: 'ec2',
region: 'eu-central-1',
path: '/',
headers: {
'Content-Type': 'application/octet-stream'
}
}))
I’ve seen plenty of examples how to add AWS Signature v.4 without any additional dependency, though.
NGINX
In nginx configuration I placed all add_headers statements into conditional code-blocks. Idea came from this post.
server {
listen 80;
server_name [HOST_IP];
location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/[path_to_app]/app.sock;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
add_header 'Access-Control-Max-Age' 86400;
add_header 'Content-Type' 'text/html; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'PUT') {
add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}
location /static/ {
autoindex on;
alias /home/ubuntu/analizy/be/site/static/;
}
}
Django-cors-header
Here it sufficed to add non-default headers.
from corsheaders.defaults import default_headers
CORS_ALLOW_HEADERS = list(default_headers) + [
'X-Amz-Date',
]
Hope that this will help someone.

Setting up HTTPS for a website hosted in AWS, but points to a webAPI in the local area network

I'm working on a project where we're hosting a webpage on AWS. The webpage calls a webAPI from a local area network computer name IE: Server-24.Local.
This approach ensures data doesn't leave the network as Server-24.Local is not exposed to the internet.
This approach has worked well so far. However, I am facing issues when i enable HTTPS via certbot:
If i try proxy_pass nginx to a webapi hosted in AWS on localhost, HTTPS works fine.
However, if i proxy_pass nginx to Server-24.Local, it returns cross-origin errors.
Both webAPIs are CORS-enabled.
Might anyone have any suggestions?
you can research about Nginx CORS enabled in internet... It's about end user browser security in chrome etc...
Here is an example, put it inside location tag {}
#
# Wide-open CORS config for nginx
#
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-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;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}
you can help look at here [https://enable-cors.org/server_nginx.html] ...
hopefully this help you...

UWSGI not receiving custom headers from nginx server

The goal is for nginx server to pass a custom request header called X-PA-AUTH_TOKEN to the uwsgi server. Below is the server block in nginx.conf file.
server {
listen 9390 default_server;
server_name _;
location / {
include uwsgi_params;
uwsgi_pass_request_headers on;
uwsgi_pass unix:/run/uwsgi/irm.sock;
uwsgi_pass_header X-PA-AUTH_TOKEN;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-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,X-PA-AUTH_TOKEN';
#
# 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;
add_header 'X-PA-AUTH_TOKEN' '0';
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-PA-AUTH_TOKEN';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range,X-PA-AUTH_TOKEN';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-PA-AUTH_TOKEN';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range,X-PA-AUTH_TOKEN';
}
}
}
The uwsgi server receives the conventional headers like 'Content-Type' just fine from the nginx server.
But, the uwsgi server is still not receiving the custom request header X-PA-AUTH_TOKEN from the nginx server when, for example, a POST request is made.
What am I doing wrong here?
I believe by default nginx marks headers with underscores (X-PA-AUTH_TOKEN) as invalid so they get blocked. You can either enable underscores_in_headers: on; in nginx config (docs here) or simply rename your header to be X-PA-AUTH-TOKEN.
Note however that if you enable underscores_in_headers, what you actually receive on the flask side will be renamed to X-Pa-Auth-Token, so i guess it's better to simply rename the header in the first place and not bother with nginx setting.

Resources