Kubernetes behind proxy misses CSRF token - apache

I have a problem. On my local laptop I can build my docker image and run it. A Ruby-On-Rails application is then running on localhost:3000. Going to that page gives me a login screen and I can successfully login. Now when I publish this code to my docker repository and run it in a kubernetes cluster, I get the following error:
With status code:
Status Code: 422 Unprocessable Entity
After some googling and debugging, I read some stuff about having the correct headers in Nginx-Ingress and Apache to handle the CSRF requests. Using this I tried many ways of allowing headers and manually adding RequestHeaders, but all resulted in the same error.
In both pages I can see in the network tab the cookie in the page. The cookie in local environment contains:
csrftoken=7tzlvuigfaUatDBMTEJUBE53OREXHxOJ1ZzJ8h4cuHvnvUza0xLH2lglIFZ1gS4S; __profilin=p=t; _app_session=BBr2bnKi6qYJwW4yvQUU0J3Q2K8JW2i9DZ5zJS0qQmCc48uRNbPrThJhbzhnGXrxLDwD/Y8ZAW5w/x2VhXeotq3TWjWcjVucUzNPA6u6ePMcN8O7XVfcIwV2HR/aGpJ1oxB1B/TbsAcfB4LaSqckVWMZ70anWDOD+xFz0xkKPiOkd++NwnMuWix2TyaicqXmQ+JsK1yWacS2dnTWvC70xyX38JjuC/VUqu2hUFIQHeNuK7Gfp7lMCh0MEJeob43lFhgFZLOJXTC+rPYIUxMTN3aIwD0=--LsM3EqEzNEglvj6H--RHcx/5CRIYG/CWJMUER1eQ==
In my production environment, I can see that the entire csrftoken part is missing:
__profilin=p=t; _app_session=FWpoSIJ8zzB8nkRsF2A30f552HjyAVlwbMva/HN4vnKaTECnPWzfWoc/+P9k/xO+fpmd2j9ntxLFOnflB5vttwxpLL1RtjZWcPmpCWfdR0nqG3EOLPLK9yR0xrvmfKMbFsYeJ2F/hZrJIs+4iOO92CioXo1s51sZX5E3R6c9XIKn5NjHUKWKuEArVV/4MibTg/CSqPWyH3lg1bjxKoZvixSZUBdtxTq1sW5NKsJnnwPgC0ZSkQzsSquCwcxKEf9L1wPxgZQTLGRREY7JeD/+mUc0WL4=--n+JNO4hoF17EGI5K--vY2DcanQEF7ICpZwDxq9tg==
Why is the CSRF token not comming through in a production environment? I already tried setting RAILS_ENV to development in the production environment, so it uses a different config, but that also gives the Status Code: 422 Unprocessable Entity
IMPORTANT
All trafic goes to my portal proxy server, which runs Apache2 and handles the SSL certificates for my domain. Apache forwards the traffic in my internal network using HTTP. Nginx-Ingress-Controller only handles http traffic because of this setup. I am not really sure if Nginx is the problem then, or Apache2?
How can I fix this CSRF issue ASAP?
UPDATE
I looked into the rails logs and found the following which might cause the problem:
I, [2022-12-12T08:16:40.202890 #1] INFO -- : [f785b7f7f797c67c0ab0f008e8a0eb83] Started POST "/login" for 192.168.1.10 at 2022-12-12 08:16:40 +0000
I, [2022-12-12T08:16:40.204343 #1] INFO -- : [f785b7f7f797c67c0ab0f008e8a0eb83] Processing by AuthController#login as HTML
I, [2022-12-12T08:16:40.204460 #1] INFO -- : [f785b7f7f797c67c0ab0f008e8a0eb83] Parameters: {"authenticity_token"=>"[FILTERED]", "login"=>{"email"=>"myemail#gmail.com", "password"=>"[F
W, [2022-12-12T08:16:40.204795 #1] WARN -- : [f785b7f7f797c67c0ab0f008e8a0eb83] HTTP Origin header (https://my.site.com) didn't match request.base_url (http://my.site.com)
I, [2022-12-12T08:16:40.205536 #1] INFO -- : [f785b7f7f797c67c0ab0f008e8a0eb83] Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms | Allocations: 192)
F, [2022-12-12T08:16:40.207591 #1] FATAL -- : [f785b7f7f797c67c0ab0f008e8a0eb83]
In my Ingress resource I now have the following:
annotations:
nginx.org/proxy-connect-timeout: 3600s
nginx.org/proxy-read-timeout: 3600s
nginx.org/proxy-send-timeout: 3600s
nginx.org/proxy-pass-headers: "Set-Cookie"
nginx.ingress.kubernetes.io/proxy-body-size: "8g"
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "Host $http_host";
more_set_headers "X-Real-IP $remote_addr";
more_set_headers "X-Forwarded-Proto $scheme";
more_set_headers "X-Forwarded-For $proxy_add_x_forwarded_for";
And my apache conf looks like this:
<VirtualHost *:80>
ServerName my.site.com
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPreserveHost on
ProxyPass / http://192.168.1.8/
ProxyPassReverse / http://192.168.1.8
RewriteEngine on
RewriteCond %{SERVER_NAME} =my.site.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName my.site.com
ProxyRequests Off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
SSLProxyEngine On
SSLProxyCheckPeerCN on
SSLProxyCheckPeerExpire on
ProxyPreserveHost on
ProxyPass / http://192.168.1.8/
ProxyPassReverse / http://192.168.1.8
Include /etc/letsencrypt/options-ssl-apache.conf
ErrorLog /var/log/apache2/sites/my.site.com/error.log
CustomLog /var/log/apache2/sites/my.site.com/access.log combined
SSLCertificateFile /etc/letsencrypt/live/my.site.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/my.site.com/privkey.pem
</VirtualHost>
</IfModule>
I already tried adding to my Apache conf:
RequestHeader set X-Forwarded-Proto "https"
but that doesn't change anything...
Can someone tell me what I should change here to get this to work?

I would propose adding the origin header in nginx. You probably also have to set it in your apache configuration to the external URL.
annotations:
nginx.org/proxy-connect-timeout: 3600s
nginx.org/proxy-read-timeout: 3600s
nginx.org/proxy-send-timeout: 3600s
nginx.org/proxy-pass-headers: "Set-Cookie"
nginx.ingress.kubernetes.io/proxy-body-size: "8g"
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "Host $http_host";
more_set_headers "X-Real-IP $remote_addr";
more_set_headers "X-Forwarded-Proto $scheme";
more_set_headers "X-Forwarded-For $proxy_add_x_forwarded_for";
more_set_headers "origin $remote_addr";

Related

Apache proxy says hostname from SNI doesn't match hostname from HTTP

I'm setting up a forward proxy on Apache 2.4, and I'm finding that every request for an HTTPS url results in a 400 response.
The apache error log shows:
[ssl:error] AH02032: Hostname my.example.net provided via SNI and hostname stanford.edu provided via HTTP are different
What could I be doing wrong? My config is as follows:
Listen 3443
<VirtualHost *:3443>
SSLEngine on
ProxyRequests on
ProxyVia off
<Proxy *>
Allow from all
</Proxy>
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/my.example.net/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/my.example.net/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/my.example.net/chain.pem
ErrorLog /var/log/httpd/myerr.log
</VirtualHost>
I've tried adding all of the following but to no effect:
SSLProxyEngine with both on and off
SSLProxyVerify none
AllowCONNECT 443
I test the proxy by running:
https_proxy='https://my.example.net:3443/' curl 'https://stanford.edu/'
My server my.example.net is running Apache 2.4 on CentOS 7
The curl command appears to be the issue: instead of using an https scheme for the https_proxy variable, use http (so that there is only one TLS connection, and it goes right through to the destination host):
https_proxy='http://my.example.net:3443/' curl 'https://stanford.edu/'

Apache reverse proxy https config leads to 503 error

Hope someone can point me in the right direction. I've been trying to get this to work for many hours :(
Scenario - I have a DMZ where I've set up the Apache server. I need to securely talk to the internal server where I have set up another Apache server which is reverse proxied again to a localhost app within the server.. So, basically..
outside world > internet (https://app1.com) > dmz (apache reverse proxy) > internal server (apache reverse proxy - https://app1prod.com) > (http) > localhost:8080
Now, in dmz, I can directly access https://app1prod.com without issues. But, I can't for the life of me get https://app1.com to work from dmz. I get a '503 service unavailable' message :( Here is my apache config in dmz..
<VirtualHost *:443>
ServerName app1.com
ProxyRequests off
SSLProxyCheckPeerName off
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerExpire off
LogLevel debug
SSLEngine on
SSLProxyEngine on
SSLCertificateFile "xxx/cert.crt"
SSLCertificateKeyFile "xxx/key.key"
SSLCertificateChainFile "xxx/certchain.crt"
ProxyPass / https://app1prod.com/
ProxyPassReverse / https://app1prod.com/
<Proxy *>
order deny,allow
Allow from all
</Proxy>
ProxyPreserveHost on
ProxyTimeout 1200
</VirtualHost>
On my httpd.conf, I have the following modules loaded in addition to the defaults..
mod_proxy.so
mod_proxy_connect.so
mod_proxy_http.so
mod_ssl
mod_rewrite.so
mod_socache_shmcb.so
mod_ssl.so
What am I doing wrong? Please help! Thanks a lot..
Try removing ProxyPreserveHost on.
With that directive enabled, the proxied requests will be send to server defined in ProxyPass directive, but the HTTP Host: header will be preserved from initial request. In your case, the requests sent by Apache to app1prod.com will have Host: app1.com header, and app1prod.com i not configured (probably deliberately) to respond to such request.

Apache reverse proxy and Wicket CsrfPreventionRequestCycleListener

Since integrating CsrfPreventionRequestCycleListener into our Apache Wicket (7.6.0) application, we have a problem operating the application behind an Apache reverse proxy.
Our configuration terminates SSL at Apache, and the reverse proxy passes the requests via http to our Wildfly 10 application server. This allows us to offload TLS/SSL among other things.
But since adding the CsrfPreventionRequestCycleListener, we are seeing the following in the server.log file and connections are aborted:
[org.apache.wicket.protocol.http.CsrfPreventionRequestCycleListener]
(default task-12) Possible CSRF attack, request URL:
http://example.com/example/portal/wicket/page,
Origin: https://example.com, action: aborted with error
400 Origin does not correspond to request
The problematic Apache config:
<VirtualHost example.com:443>
ServerName example.com
LogLevel debug
SSLEngine On
SSLCertificateFile /var/example/example.com/signed.crt
SSLCertificateKeyFile /var/example/example.com/domain.key
SSLCACertificateFile /var/example/example.com/intermediate.pem
SSLProtocol +TLSv1.2 +TLSv1.1 +TLSv1
SSLOpenSSLConfCmd DHParameters "/usr/local/apache2/1024dhparams.pem"
SSLProxyEngine on
ProxyPass / http://localhost:8390/ timeout=600
ProxyPassReverse / http://localhost:8390/ timeout=600
ProxyPreserveHost On
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Credentials "true"
Header edit Location ^http(\:\/\/.*)$ https$1
We found a solution using http2 but would prefer one without http2 (for reasons, see in https://http2.pro/doc/Apache).
The working Apache configuration using http2
<VirtualHost example.com:443>
ServerName example.com
LogLevel debug
SSLEngine On
SSLCertificateFile /var/example/example.com/signed.crt
SSLCertificateKeyFile /var/example/example.com/domain.key
SSLCACertificateFile /var/example/example.com/intermediate.pem
SSLProtocol +TLSv1.2 +TLSv1.1 +TLSv1
SSLOpenSSLConfCmd DHParameters "/usr/local/apache2/1024dhparams.pem"
SSLProxyEngine On
ProxyPreserveHost On
# Settings for http2 communication
Protocols h2 http/1.1
ProxyPass / https://localhost:8754/ timeout=600
ProxyPassReverse / https://localhost:8754/ timeout=600
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Credentials "true"
# Header edit Location ^http(\:\/\/.*)$ https$1
</VirtualHost>
Can anyone help us create a valid apache reverse proxy configuration that works with the CsrfPreventionRequestCycleListener without the http2 module?
I think I had a similar issue here and solved it just now. I think you might have solved your issue by now but maybe anyone else is falling over this topic.
You might want to look into a network dump to verify the problem. For me, apache sent requests to the locally running service (your case to http://localhost:8754) while some request headers were still referring the public name https://example.com. This was detected as a security risk and the connection refused by the underlying service.
I made sure, that mod_headers was enabled in apache and added the line
RequestHeader edit Referer "https://example.com" "http://localhost:8754"
After that no more references to anything related to example.com was in my tcp dumps and the connection was opened successfully.
You might need to adopt according to your setup (maybe you need multiple headers corrected or something similar). I cannot try it out at the moment.

422 Unprocessable Entity, JS Files, gitlab 8.17, apache ssl

yesterday a make a new gitlab 8.17.0 installation on ubuntu 16.04 installation and confgure it like the old one which I have documented. I am running a apache2 which letsencrypt as a proxy. It looks as if everything runs well, but a few JS files are not loaded. I get "422 Unprocessable Entity" https at
domain/assets/webpack/application-XXX.js
domain/assets/webpack/lib_dX.js
domain/assets/webpack/users-X.js
domain/assets/webpack/lib_d3-X.js
domain/assets/webpack/users-X.js
/etc/gitlab/gitlab.rb
external_url 'https://gitlab.example.com'
nginx['listen_address'] = 'localhost'
nginx['listen_port'] = 8080
nginx['listen_https'] = false
web_server['external_users'] = ['www-data']
nginx['enable'] = false
/etc/apache2/sites-available/gitlab.example.com.conf
<VirtualHost *:80>
ServerName gitlab.example.com
ServerAdmin mail#gitlab.example.com
ErrorLog /var/log/apache2/gitlab.example.com/error.log
CustomLog /var/log/apache2/gitlab.example.com/access.log combined
Redirect 301 / https://gitlab.example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName gitlab.example.com
ServerAdmin mail#gitlab.example.com
ErrorLog /var/log/apache2/gitlab.example.com/error.log
CustomLog /var/log/apache2/gitlab.example.com/access.log combined
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
ProxyPreserveHost On
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/gitlab.example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/gitlab.example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/gitlab.example.com/chain.pem
<Proxy http://localhost:8080/>
Order deny,allow
Allow from all
</Proxy>
</VirtualHost>
Does anyone have ideas to solve the problem?
Thank you! I wish you a nice Sunday.
I had same problem with serving mentioned static files but behind nginx proxy. In /var/log/gitlab/gitlab-rails/production.log file there were errors:
Started GET "/assets/webpack/application-0b895f7016d93748393a-v2.js" for 127.0.0.1 at 2017-03-05 11:14:21 +0100
Processing by ApplicationController#route_not_found as JS
Parameters: {"unmatched_route"=>"assets/webpack/application-0b895f7016d93748393a-v2"}
Security warning: an embedded <script> tag on another site requested protected JavaScript.
If you know what you're doing, go ahead and disable forgery protection on this action to
permit cross-origin JavaScript embedding.
Completed 422 Unprocessable Entity in 28ms (ActiveRecord: 1.8ms)
ActionController::InvalidCrossOriginRequest (Security warning: an embedded
<script> tag on another site requested protected JavaScript. If you know
what you're doing, go ahead and disable forgery protection on this action to
permit cross-origin JavaScript embedding.):
lib/gitlab/middleware/multipart.rb:93:in `call'
lib/gitlab/request_profiler/middleware.rb:14:in `call'
lib/gitlab/middleware/go.rb:16:in `call'
So I've made changes in /opt/gitlab/embedded/service/gitlab-rails/config/environments/production.rb:
config.action_controller.allow_forgery_protection = false
# Disable Rails's static asset server (Apache or nginx will already do this)
config.serve_static_files = true
and restarted gitlab (gitlab-ctl restart). Now it works, however I suppose that security of my server is weakened.
This is an issue in 8.17 thas hasn't been fixed yet.
Just downgrade to 8.16 sudo apt-get install gitlab-ce=8.16.6-ce.0

Reverse proxy for external URL - Apache

I configured my apache so that it can forward my requests to external URL like google.com, but the reverse proxy doesn't work.
<VirtualHost *:443>
ServerName authtest.com
ProxyRequests Off
ProxyPreserveHost On
<Proxy *>
Order allow,deny
Allow from All
</Proxy>
<LocationMatch "/google">
ProxyPass https://www.google.com/
ProxyPassReverse https://www.google.com/
</LocationMatch>
</VirtualHost>
Is it possible for me to reverse proxy external websites?
Is it possible for me to reverse proxy external websites?
Yes but with significant downsides.
Note: when I tried your configuration, I got SSL Proxy requested for [...] but not enabled [Hint: SSLProxyEngine] in the logs so I added SSLProxyEngine on.
Host issue
When you make a HTTP/1.1 request to a server, you automatically add the hostname in the request. When you proxy them, you have two possibilites:
[browser] --(Host: authtest.com)--> [apache proxy] --(Host: authtest.com)--> Google
or
[browser] --(Host: authtest.com)--> [apache proxy] --(Host: google.com)--> Google
The first one is what you get with ProxyPreserveHost On. Google servers won't handle requests for authtest.com, you should remove this line.
Even in the second case, you can have issues. ProxyPassReverse will handle redirects but only for the given domain: I'm in France, google.com redirects me to google.fr (a different domain) and the reverse proxy doesn't rewrite the redirect.
An other issue is the referer: if a service sees requests for images/css/js coming from a different web site it may consider it as bandwidth leeching and block them. Now, you need to rewrite the html of the response too (mod_proxy_html will help but it's not a silver bullet).
Path issue
In your example, you proxy <authtest>/google to <google>/. Like above, you need to rewrite the html: absolute links/resources won't work unless your server adds /google everywhere. Same for relative links/resources (but with more edge cases). If you owned the backend server, you could have checked urls in html/css/js files. Here, if the url is built dynamically in the browser using js you can't do anything.
If you can proxy / to / (or /whatever to /whatever) you will avoid a lot of issues here.
Chech this GIT Repo
I forked a GIT Repo and customized it to work with scenario:
[browser] --(Host: google.local)--> [apache proxy] --(Host: google.nl)--> Google
The Apache config as follows:
<VirtualHost *:80>
ServerName google.local
SSLProxyEngine on
ProxyRequests Off
<Proxy *>
Order allow,deny
Allow from All
</Proxy>
ProxyPass / https://www.google.nl/
ProxyPassReverse / https://www.google.nl/
ErrorLog /var/log/apache2/google.local-error.log
CustomLog /var/log/apache2/google.local-access.log combined
</VirtualHost>