1
votes

Comment effectuer une authentification personnalisée avec Kubernetes Ingress

J'ai déployé quelques services dans kubernetes et en utilisant l'entrée NGINX pour accéder à l'extérieur (en utilisant l'instance EC2 pour toute la configuration du cluster). Capable d'accéder au service via l'hôte lié à l'entrée. Maintenant, au lieu d'accéder directement au svc, j'essaie d'ajouter une authentification et avant d'accéder au service. Et en redirigeant vers la page de connexion, l'utilisateur entre les informations d'identification et doit rediriger vers la page demandée. L'extrait de code II suivant a essayé jusqu'à présent. Veuillez guider pour trouver une solution.

my-ingress.yml

 nginx.ingress.kubernetes.io/configuration-snippet: |
      auth_request_set $token5 $upstream_http_authorization;    
      add_header Set-Cookie "JWT_TOKEN=$token5";

donc d'abord, il appellera "/ token / validate" et deviendra non autorisé puis accédera à "auth / login" et la page de connexion s'affichera après avoir entré les informations d'identification en allant à "/ token / validate" et à nouveau à la page de connexion. En fait, devrait rediriger vers la page appelée.

Comment y parvenir? [Si après l'authentification réussie, si nous pouvons ajouter un en-tête dans le ling appelé, je pense que je peux le résoudre, mais je ne sais pas comment]

backend: Java Spring

nginx.ingress.kubernetes.io/auth-signin: 'https://auth.example.com/api/auth-service-ui/login'
nginx.ingress.kubernetes.io/auth-response-headers: 'UserID, Authorization, authorization'
nginx.ingress.kubernetes.io/auth-snippet: |
      auth_request_set $token $upstream_http_authorization;
      proxy_set_header Foo-Header1 $token; //not showing as request header AND this value only need LOOKS $token val is missed
      proxy_set_header Foo-Header headerfoo1; //showing as request header OK
      more_set_input_headers  'Authorization: $token';//not showing as request header AND this value only need LOOKS $token val is missed

nginx.ingress.kubernetes.io/configuration-snippet: |
      auth_request_set $token1 $upstream_http_authorization;
      add_header  authorization2 QQQAAQ1; //showing as response header OK no use
      add_header  authorization $token; //showing as response header OK how to send as request header on next call
      more_set_input_headers  'Authorization11: uuu1';//showing as request header in next call
      more_set_input_headers  'Authorization: $token1';//not showing as request header and need this val ONLY

login.html

@PostMapping("validate-user")
@ResponseBody
public ResponseEntity<?> validateUser(HttpServletRequest request, HttpServletResponse response) throws Exception {
                ...
                
    HttpStatus httpStatus=HttpStatus.FOUND;
    //calling authentication api and validating
        
    //else
    httpStatus=HttpStatus.UNAUTHORIZED;
    HttpHeaders responseHeaders= new HttpHeaders();
    responseHeaders.set("Authoriztion", token);
                
    //responseHeaders.setLocation(new URI("https://a.mysite.domain")); ALSO TRIED BUT NOT WORKED
    return new ResponseEntity<>(responseHeaders,httpStatus);        
        
        }

backend: Java Spring

    <form action="validate-user" method="post" enctype="application/x-www-form-urlencoded">  
        <label for="username">Username</label>  
        <input type="text" id="username" value="admin" name="username" autofocus="autofocus" />  <br>
        <label for="password">Password</label>  
        <input type="password" id="password" value="password" name="password" />  <br>
        
        <input id="submit" type="submit" value="Log in" />  
    </form> 

UPDATE1: J'utilise ma propre API d'authentification personnalisée, si je frappe l'URL avec l'en-tête personnalisé "Authorization": "Bearer token" de postman alors la réponse est correcte, mais à partir du navigateur pas possible, donc à partir de svc en amont uniquement (après succès login) l'en-tête doit inclure dans la page de redirection que comment pouvons-nous faire?
UNE ANNOTATION EST-CE QUE JE MANQUE?

UPDATE2: lors de la redirection après une authentification réussie, je transmets le jeton en tant que chaîne de requête comme responseHeaders.setLocation(new URI("https://a.mysite.domain/?access_token="+token) et après la redirection, il va valider. Après réussite validation va au svc en aval [attendu]. Mais quand ce svc achemine, disons a.mysite.domain/route1 chaîne de requête a disparu et l'auth svc ne peut pas obtenir à nouveau le jeton, d'où 401 Cela devrait ressembler à a.mysite.domain/route1/?access_token=token . a.mysite.domain/route1/?access_token=token moyen de le faire? Si chaque route aura la même chaîne de requête, cela fonctionnera. [Ceci est mon PLAN-B ... mais le jeton de transmission est toujours l'en-tête est ma priorité]

UPDATE3: j'ai essayé avec des annotations comme:

@RequestMapping("login")  
public String login() {  
    return "login.html";  
} 

** Quelle annotation j'ai ratée?

UPDATE4 PLAN-C: essaye maintenant de stocker le jeton jwt dans les cookies.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  namespace: mynamespace  
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/affinity: cookie
    nginx.ingress.kubernetes.io/session-cookie-name: JSESSIONID
    nginx.ingress.kubernetes.io/ssl-passthrough: "false"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    kubernetes.io/ingress.class: "nginx"
    kubernetes.io/ingress.allow-http: "false"
    nginx.ingress.kubernetes.io/auth-signin: "https://auth.mysite.domain/api/auth/login"  #will show login page
    nginx.ingress.kubernetes.io/auth-url: "https://auth.mysite.domain/api/auth/token/validate"
    nginx.ingress.kubernetes.io/auth-response-headers: "authorization"    
    
spec:
  tls:
  - hosts: 
    - mysite.domain
    #secretName: ${TLS_TOKEN_NAME}
  rules:
  - host: a.mysite.domain
    http:
      paths:
        - path: /
          backend:
            serviceName: myservice1
            servicePort: 9090 
 

Dans chaque demande, le même cookie est défini mais dans le navigateur, il est stocké à chaque fois. c'est à dire plusieurs cookies de même. Comment régler une seule fois?


8 commentaires

Quel type d'authentification externe essayez-vous d'utiliser, l'authentification de base ou OAuth2? Veuillez également fournir votre version de nginx-ingress.


@KoopaKiller image: quay.io/kubernetes-ingress-controller/nginx-ingress-controll‌ er: 0.30.0 /ingress-nginx/nginx-0.30.0 Et en utilisant la validation de jeton jwt (API d'authentification personnalisée)


Y a-t-il quelqu'un qui connaît ce concept et peut partager des connaissances à ce sujet?


Je vais essayer de reproduire le problème. Ce serait formidable si vous pouviez partager l'image que vous utilisez ou un exemple.


Toutes les ressources sont dans un réseau privé et ne seront donc pas disponibles. Pour vérifier, je viens de configurer un cluster et de déployer deux svc, un auth-svc (simple et personnalisé), un autre est le svc auquel je veux accéder. Kubedash installé à partir de github et nginx-ingress nginx-0.30.0. Essayez donc de reproduire vous-même. J'ai essayé, mais en redirigeant vers la page, je n'ai pas pu définir l'en-tête d'authentification. Si cela est fait, cela fonctionnera bien.


J'ai trouvé cette URL avec un exemple de fonctionnement de l'authentification externe. github.com/kubernetes/ingress-nginx/tree/master/docs/example‌ s /… De plus, je travaille dans les étapes de reproduction et je reviens dès que possible.


dans celui-ci, l'en-tête de l'url sécurisé pour appeler est passé, mais dans mon cas, l'url directe est appelée puis est passée à auth svc et après une redirection d'authentification réussie vers la demande. url ... donc ici aucun en-tête n'est là et ici seulement j'ai besoin d'inclure l'en-tête d'authentification ... Merci pour votre effort! en attente de la prochaine suggestion. [voir UPDATE2]


Permettez-moi d'ajouter quelques éléments au sujet sous la forme d'un article sur le wiki communautaire, car j'ai besoin d'espace pour le formatage des exemples de code ...


3 Réponses :


0
votes

Intégrez Oauth2-proxy avec le contrôleur d'entrée nginx pour activer l'authentification personnalisée auprès des services exécutés derrière l'entrée.

Suivez le lien -> https://github.com/oauth2-proxy/oauth2-proxy


1 commentaires

Merci pour votre suggestion, j'utilise ma propre API d'authentification personnalisée, si je frappe l'URL avec l'en-tête "Authorization": "bearer token" de postman alors la réponse est correcte, mais à partir du navigateur pas possible, donc pour le svc en amont uniquement le l'en-tête doit inclure dans la page de redirection que comment pouvons-nous faire?



0
votes

Vers votre PLAN-B :

passer un jeton dans l'en-tête est ma priorité.

Je ne vois aucun problème à le faire avec juste une utilisation des annotations suivantes:

     {
      "headers": {
        "Accept": "*/*", 
        "Authorization": "Bearer foobar", <---is this what you are looking for ?
        "Host": "custom.example.com", 
        "User": "centrino", 
        "User-Agent": "curl/7.58.0", 
        "Userid": "8674665223082153551", 
        "X-Forwarded-Host": "custom.example.com", 
        "X-Scheme": "http", 
        "X-Using-Nginx-Controller": "true"
      }
    } 
 

 

Suite de l'exemple officiel des en-têtes d'authentification externe :

  1. Modifiez le code source de leur service d'authentification externe afin qu'il s'introduise en cas d'authentification réussie. réponse à un en-tête souhaité ( "Authorization": "Bearer <token>" ):

         > GET /headers HTTP/1.1
         > Host: custom.example.com
         > User-Agent: curl/7.58.0
         > Accept: */*
         > User: centrino
         > 
         < HTTP/1.1 200 OK
         < Server: nginx/1.17.8
         < Date: Tue, 14 Jul 2020 11:55:43 GMT
         < Content-Type: application/json
         < Content-Length: 327
         < Connection: keep-alive
         < Vary: Accept-Encoding
         < Access-Control-Allow-Origin: *
         < Access-Control-Allow-Credentials: true
         < 
       
    
  2. Reconstruire l'image du docker et mettre à jour les spécifications du pod dans le déploiement pour appliquer votre image personnalisée

  3. Assurez-vous que votre définition Ingress est similaire:

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      annotations:
        nginx.ingress.kubernetes.io/auth-response-headers: UserID, authorization
        nginx.ingress.kubernetes.io/auth-url: http://demo-auth- 
    service.default.svc.cluster.local?code=200
    
  4. Inspectez si les en-têtes personnalisés du service d'authentification sont injectés dans l'appel Ingress à son backend (j'utilise la version déployée en cluster de httpbin.org/headers )

  5. Contenu de la demande vu du point de vue du client et du backend d'Ingress:

Demande du client:

   w.Header().Add("UserRole", "admin")
        w.Header().Add("Other", "not used")
        w.Header().Add("Authorization", "Bearer foobar" ) <--- here
        fmt.Fprint(w, "ok")

Demande client vue au backend enrichi avec l'en-tête ext-auth-svc:

nginx.ingress.kubernetes.io/auth-url: "https://auth.mysite.domain/api/auth/token/validate"
nginx.ingress.kubernetes.io/auth-response-headers: "authorization 


6 commentaires

J'ai essayé cela et j'ai également utilisé add_header mais fonctionnant de la manière attendue ... voir UPDATE 3 ce que j'ai utilisé! ... vous avez fourni pour la demande qui peut valider et envoyer auth resp et cet en-tête à svc ... mais si c'est invalide alors j'envoie à la page de connexion en utilisant l'annotation 'auth-signin' puis une fois que l'utilisateur s'est connecté en redirigeant vers la page demandée ET ici, seul l'en-tête Auth a manqué!


Pouvez-vous simplement essayer d'utiliser $ http_token au lieu de $ token dans votre extrait de configuration, ou simplement (add_header authorisation $ token1;), reportez-vous à nginx.ordg doc pour une meilleure compréhension de cette syntaxe


Essayé les deux sans résultat ... voir UPDATE4


@ UPDATE4 - Je ne suis pas l'expert de Spring Boot, mais vous devez peut-être stocker et maintenir les identifiants de session client après une connexion réussie (user.validated / token.issued). À l'heure actuelle, votre application se comporte comme celle derrière le service d'authentification de base = chaque fois que l'utilisateur doit spécifier des informations d'identification. Jetez un œil à cet exemple de code ...


... en outre, vous devez activer l' affinité de session basée sur les cookies, pour éviter que les clients ne rebondissent entre différentes répliques de vos backends.


Je pense que votre problème général est que le contrôleur nginx-ingress ne prend pas en charge l'authentification basée sur les jetons JWT et que vous essayez d'implémenter la vôtre sans utiliser le fournisseur basé sur oauth2. Jetez peut-être un coup d'œil ici à la façon dont les autres essayaient de réaliser la même chose.



0
votes

ce qui suit a fonctionné pour moi

mettez vos valeurs yaml:

 def auth():
  request_path = request.headers.get("X-Auth-Request-Redirect")
  authorization_header = request.headers.get('Authorization')
          
  if ServiceImp.auth(authorization_header,request_path):
   return Response(
                response="authorized",
                status=200, 
                mimetype="application/json"
   )
  else:
   resp = Response()
   resp.headers['WWW-Authenticate'] = 'Basic'
   return resp, 401

puis pour cette URL, vous devez implémenter un service GET qui renvoie 200 si l'autorisation a réussi ou 401 dans les autres cas.

J'ai implémenté dans flask, avec l'autorisation de base, mais vous pouvez utiliser ce que vous voulez

nginx.ingress.kubernetes.io/auth-url: "url service here"


0 commentaires