Data Mastery
Data Mastery

Reputation: 2085

Keycloak and Docker Swarm redirect loop with Replicas

version: '3.7'
services:
  shinyproxy:
    build: /home/administrator/shinyproxy
    deploy: 
      replicas: 3
      #placement: 
        #constraints: 
          #- node.hostname==node1
    user: root:root
    hostname: shinyproxy
    image: localhost:5000/shinyproxy-example
    networks:
      - sp-example-net
    volumes:
      - type: bind
        source: /var/run/docker.sock
        target: /var/run/docker.sock
      - type: bind
        source: /home/administrator/shinyproxy/application.yml
        target: /opt/shinyproxy/application.yml  
    ports:
      - 4000:4000
  mariadb:
    image: mariadb
    networks:
      - sp-example-net
    volumes:
      - type: bind
        source: /home/administrator/mariadbdata
        target: /var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: keycloak
      MYSQL_USER: keycloak
      MYSQL_PASSWORD: password
    deploy: 
      placement: 
        constraints: 
          - node.hostname==spm1anadev1 
  keycloak:
    image: jboss/keycloak
    networks:
      - sp-example-net
    volumes:
      - type: bind
        source: /home/administrator/certs/fullchain.pem
        target: /etc/x509/https/tls.crt
      - type: bind
        source: /home/administrator/certs//privkey.pem
        target: /etc/x509/https/tls.key
      #- /theme/govuk-social-providers/:/opt/jboss/keycloak/themes/govuk-social-providers/
    environment:
      - PROXY_ADDRESS_FORWARDING=true
      - KEYCLOAK_USER=myadmin
      - KEYCLOAK_PASSWORD=mypassword
    ports:
      - 8443:8443
    deploy: 
      placement: 
        constraints: 
          - node.hostname==node1


networks:
  sp-example-net:
    driver: overlay
    attachable: true

I use the following setup for my docker-swarm cluster. Deployment works fine, but when I create 3 replicas of my shinyproxy service, I end up in a redirect loop. The issue might be that keycloak does not know from which replica of the service the redirect comes from, so I get send back and forth from shinyproxy instance to keycloak authetification.

I guess I am not the first person with this issue, but I did not find any solution for this. Can anyone help me?

Thank you!

Edit: I use the following Dockerfile to create my Shinyproxy service.

FROM openjdk:8-jre

COPY certificate.pfx $JAVA_HOME/jre/lib/security/certificate.pfx

RUN \
    cd $JAVA_HOME/jre/lib/security \
    keytool -importkeystore -srckeystore certificate.pfx -srcstorepass -changeit -srcstoretype pkcs12 -destkeystore cacerts -deststorepass changeit -deststoretype JKS

RUN mkdir -p /opt/shinyproxy/
RUN wget https://www.shinyproxy.io/downloads/shinyproxy-2.3.0.jar -O /opt/shinyproxy/shinyproxy.jar
COPY application.yml /opt/shinyproxy/application.yml
COPY templates /opt/shinyproxy/templates

WORKDIR /opt/shinyproxy/
CMD ["java", "-jar", "/opt/shinyproxy/shinyproxy.jar"]

This service also uses an application.yml which uses keycloaks credential secrets to authenticate:

proxy:
  port: 4000
  template-path: /opt/shinyproxy/templates/2col
  authentication: keycloak
  admin-groups: admins
  container-backend: docker-swarm
  docker:
      internal-networking: true
      container-network: test_sp-example-net
  specs:
  - id: 01_hello
    display-name: Hello Application
    description: Application which demonstrates the basics of a Shiny app
    container-cmd: ["R", "-e", "shinyproxy::run_01_hello()"]
    container-image: openanalytics/shinyproxy-demo
    container-network: "${proxy.docker.container-network}"
    access-groups: test
  - id: euler
    display-name: Euler's number
    container-cmd: ["R", "-e", "shiny::runApp('/root/euler')"]
    container-image: euler-docker
    container-network: "${proxy.docker.container-network}"
    access-groups: test
  keycloak:
      realm: master
      auth-server-url: https://analytics.data-mastery.com/auth/
      resource: shinyoid
      credentials-secret: xxx
      
      
logging:
  file:
    shinyproxy.log

Upvotes: 2

Views: 1465

Answers (1)

Jan Garaj
Jan Garaj

Reputation: 28646

https://support.openanalytics.eu/t/setting-kubernetes-pod-fields-and-using-multiple-replica-sets/783/2

ShinyProxy is a stateful application

Stateful app = each shinyproxy container manages own state. So when you are logged in first replica, second/third replicas don't know about it -> they redirect browser to Keycloak. There is already opened IDP session, so Keycloak redirects with auth code response immediately. However that auth code can be processed by another container -> so there will be redirect again and again. Only because shinyproxies don't share single state, but each replica has own state.

If you need horizontal scaling, then use sticky session (e.g. traefik in front of Shinyproxy service - link), so each request will be processed by the same shinyproxy replica. Otherwise scale shinyproxy vertically (more CPU/mem resources).

Upvotes: 1

Related Questions