3

I have a weird problem with PGAdmin4.

My setup

  • pgadmin 4.1 deployed on kubernetes using the chorss/docker-pgadmin4 image. One POD only to simplify troubleshooting;
  • Nginx ingress controller as reverse proxy on the cluster;
  • Classic ELB in front to load balance incoming traffic on the cluster.

ELB <=> NGINX <=> PGADMIN

From a DNS point of view, the hostname of pgadmin is a CNAME towards the ELB.

The problem

Application is correctly reachable, users can login and everything works just fine. Problem is that after a couple of (roughly 2-3) minutes the session is invalidated and users are requested to login again. This happens regardless of the fact that pgadmin is actively used or not.

After countless hours of troubleshooting, I found out that the problem happens when the DNS resolution of ELB's CNAME switches to another IP address.

In fact, I tried:

  • connecting to the pod directly by connecting to the k8s service's node port directly => session doesn't expire;
  • connecting to nginx (bypassing the ELB) directly => session doesn't expire;
  • mapping one of the ELB's IP addresses in my hosts file => session doesn't expire.

Given the above test, I'd conclude that the Flask app (PGAdmin4 is a Python Flask application apparently) is considering my cookie invalid after the remote address changes for my hostname.

Any Flask developer that can help me fix this problem? Any other idea about something I might be missing?

whites11
  • 12,008
  • 3
  • 36
  • 53

3 Answers3

2

PGadmin 4 seems to use Flask-Security for authentication:

pgAdmin utilised the Flask-Security module to manage application security and users, and provides options for self-service password reset and password changes etc.

https://www.pgadmin.org/docs/pgadmin4/dev/code_overview.html

Flask-Security seems to use Flask-Login:

Many of these features are made possible by integrating various Flask extensions and libraries. They include: Flask-Login ...

https://pythonhosted.org/Flask-Security/

Flask-Login seems to have a feature called "session protection":

When session protection is active, each request, it generates an identifier for the user’s computer (basically, a secure hash of the IP address and user agent). If the session does not have an associated identifier, the one generated will be stored. If it has an identifier, and it matches the one generated, then the request is OK.

https://flask-login.readthedocs.io/en/latest/#session-protection

I would assume setting login_manager.session_protection = None would solve the issue, but unfortunately I don't know how to set it in PGadmin. Hope it might help you somehow.

Pampy
  • 959
  • 7
  • 15
  • Makes total sense to me, will give it a try asap. Thanks @Pampy – whites11 Feb 19 '19 at 09:38
  • Another approach would be, depending on how Flask-Login gets the IP for the client: If you're using ELB (with TCP) you can enable the proxy protocol (https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-proxy-protocol.html) - if you're using an ELB with HTTP or ALB it should be enabled by default. That should set the client IP in a X-Forwarded-For header. If that's enabled the session should also stay valid, even when switching the ELB IP. Which ELB are you using? Classic Load Balancer or Application Load Balancer? How is the target defined (TCP/HTTP/HTTPS?) – Pampy Feb 19 '19 at 10:12
  • Classic ELB with TCP targets – whites11 Feb 19 '19 at 10:34
  • That could be the reason. You should switch to HTTP/HTTPS if there's no other reason to use TCP. Alternatively you can try enabling the proxy protocol or switch to ALB. – Pampy Feb 19 '19 at 15:44
  • A little feedback. I tried adding `session_protection = None` to the codebase inside the pod, but it didn't work. I'm pretty sure that's the problem though, so I probably made some kind of mistake (python newbie here). I cannot change the ELB type because it is handled automatically and I need a Classic ELB for other parts of my system. Updates ASAP. – whites11 Feb 21 '19 at 09:28
  • I'll grant you the bounty in any case, because you've been of great help. – whites11 Feb 21 '19 at 09:29
  • Thank you! Maybe you'll find a way to modify your ELB - that would probably be the cleaner solution. Good luck! – Pampy Feb 21 '19 at 12:42
1

For those looking for a solution, You need to add below to config.py or config_distro.py or config_local.py

config_local.py

SESSION_PROTECTION = None
Tarun Lalwani
  • 142,312
  • 9
  • 204
  • 265
0

Faced similar issue in GKE Load balancer , Cleaner solution which worked for me is disabling cookie protection based on Ip address. Add below flag to config_local.py

#Disable Cookie generation base on Ip address 
ENHANCED_COOKIE_PROTECTION = False