Înapoi la microservicii împreună cu Istio. Partea 3

Înapoi la microservicii împreună cu Istio. Partea 3

Nota traducătorului.: Partea întâi această parte a fost dedicată familiarizării cu capabilitățile Istio și demonstrării acestora în practică, a doua — rutare fin ajustabilă și gestionarea traficului de rețea. Acum vom discuta despre securitate: pentru a demonstra funcționalitățile de bază asociate, autorul folosește serviciul de identitate Auth0, însă, prin analogie cu acesta, pot fi configurate și alți furnizori.

Am configurat un cluster Kubernetes, în care am desfășurat Istio și un exemplu de aplicație microservicii Analiza Sentimentelor, demonstrând astfel capabilitățile Istio.

Cu ajutorul Istio am reușit să menținem dimensiunea mică a serviciilor, deoarece acestea nu mai necesită implementarea unor „straturi” precum încercările de reconectare (Retries), timpii de așteptare (Timeouts), siguranțele automate (Circuit Breakers), trasarea (Tracing), monitorizarea (Monitoring). În plus, am utilizat tehnici avansate de testare și desfășurare: testare A/B, mirroring și lansări canary.

Înapoi la microservicii împreună cu Istio. Partea 3

În noul material, ne vom ocupa de straturile finale pe drumul către valoarea de business: autentificarea și autorizarea — și în Istio aceasta este o plăcere adevărată!

Autentificarea și autorizarea în Istio

Niciodată nu m-aș fi gândit că voi fi inspirat de autentificare și autorizare. Ce poate oferi Istio din punct de vedere tehnologic pentru a face aceste subiecte captivante și chiar mai mult — pentru a le face să vă inspire și pe voi?

Răspunsul este simplu: Istio mută responsabilitatea pentru aceste capabilități de la serviciile dumneavoastră pe proxy-ul Envoy. Când cererile ajung la servicii, acestea sunt deja autentificate și autorizate, așa că tot ce trebuie să faceți este să scrieți cod util pentru business.

Sună bine? Să ne uităm înăuntru!

Autentificare cu Auth0

Ca server pentru gestionarea identității și accesului, vom folosi Auth0, care are o versiune de încercare, este intuitiv de utilizat și pur și simplu îmi place. Totuși, aceleași principii pot fi aplicate și în raport cu orice altă implementare OpenID Connect: KeyCloak, IdentityServer și multe altele.

Pentru început, accesați Portalul Auth0 cu contul dumneavoastră, creați un tenant (tenant — „chirias”, unitate logică de izolare, mai multe detalii în documentation — nota trad.) și accesați Applications > Default App, alegând Domeniu, așa cum se arată în captura de ecran de mai jos:

Înapoi la microservicii împreună cu Istio. Partea 3

Specificați acest domeniu în fișierul resource-manifests/istio/security/auth-policy.yaml (sursă):

apiVersion: authentication.istio.io/v1alpha1
kind: Policy
metadata:
  name: auth-policy
spec:
  targets:
  - name: sa-web-app
  - name: sa-feedback
  origins:
  - jwt:
      issuer: "https://{YOUR_DOMAIN}/"
      jwksUri: "https://{YOUR_DOMAIN}/.well-known/jwks.json"
  principalBinding: USE_ORIGIN

Dispunând de o astfel de resursă, Pilot (una dintre cele trei componente de bază ale Control Plane în Istio — nota trad.) configurează Envoy pentru a autentifica cererile înainte de a le redirecționa către servicii: sa-web-app și sa-feedback. În același timp, configurația nu se aplică la Envoy-urile serviciului sa-frontend, permițându-ne să lăsăm frontend-ul neautentificat. Pentru a aplica politica (Policy) executați comanda:

$ kubectl apply -f resource-manifests/istio/security/auth-policy.yaml
policy.authentication.istio.io “auth-policy” creat

Întoarceți-vă la pagină și faceți o cerere — veți vedea că aceasta se va încheia cu statutul 401 Unauthorized. Acum să redirecționăm utilizatorii frontend-ului către autentificarea cu Auth0.

Autentificarea cererilor cu Auth0

Pentru a autentifica cererile utilizatorului final, trebuie să creați un API în Auth0, care va reprezenta serviciile autentificate (reviews, details și ratings). Pentru a crea API, accesați Auth0 Portal > APIs > Create API și completați formularul:

Înapoi la microservicii împreună cu Istio. Partea 3

O informație importantă aici este Identifier, pe care îl vom folosi ulterior în script. Să-l notăm astfel:

  • Audience: {YOUR_AUDIENCE}

Detaliile necesare rămase se află pe Auth0 Portal în secțiunea Applications — selectați Test Application (creat automat împreună cu API-ul).

Aici vom nota:

  • Domeniu: {YOUR_DOMAIN}
  • Client Id: {YOUR_CLIENT_ID}

Derulați la Test Application câmpul text Allowed Callback URLs (URL-uri permise pentru callback), în care vom specifica URL-ul la care ar trebui să fie trimis apelul după ce autentificarea este finalizată. În cazul nostru, aceasta este:

http://{EXTERNAL_IP}/callback

Iar pentru Allowed Logout URLs (URL-uri permise pentru deconectare) adăugăm:

http://{EXTERNAL_IP}/logout

Să trecem la frontend.

Actualizarea frontend-ului

Comutați pe ramura auth0 a depozitului [istio-mastery]. În această ramură, codul frontend-ului a fost modificat astfel încât să redirecționeze utilizatorii către Auth0 pentru autentificare și să folosească un token JWT în cererile către celelalte servicii. Ultimul lucru este implementat în felul următor (App.js):

analyzeSentence() {
    fetch('/sentiment', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${auth.getAccessToken()}` // Access Token
        },
        body: JSON.stringify({ sentence: this.textField.getValue() })
    })
        .then(response => response.json())
        .then(data => this.setState(data));
}

Pentru a trece frontend-ul la utilizarea datelor tenant-ului în Auth0, deschideți sa-frontend/src/services/Auth.js și înlocuiți valorile, pe care le-am notat mai sus (Auth.js):

const Config = {
    clientID: '{YOUR_CLIENT_ID}',
    domain:'{YOUR_DOMAIN}',
    audience: '{YOUR_AUDIENCE}',
    ingressIP: '{EXTERNAL_IP}' // Folosit pentru redirecționare după autentificare
}

Aplicația este gata. Indicați ID-ul dumneavoastră Docker în comenzile de mai jos la construirea și implementarea modificărilor realizate:

$ docker build -f sa-frontend/Dockerfile 
 -t $DOCKER_USER_ID/sentiment-analysis-frontend:istio-auth0 
 sa-frontend

$ docker push $DOCKER_USER_ID/sentiment-analysis-frontend:istio-auth0

$ kubectl set image deployment/sa-frontend 
 sa-frontend=$DOCKER_USER_ID/sentiment-analysis-frontend:istio-auth0

Încercați aplicația! Veți fi redirecționat către Auth0, unde trebuie să vă conectați (sau să vă înregistrați), după care veți fi trimis înapoi pe pagina de unde se vor efectua solicitările deja autorizate. Dacă încercați comenzile menționate în primele părți ale articolului cu curl — veți primi codul 401 Status Code, care indică faptul că solicitarea nu este autorizată.

Să facem următorul pas — vom autoriza solicitările.

Autorizare cu Auth0

Autentificarea ne permite să înțelegem cine este utilizatorul, dar pentru a ști la ce are acces, este necesară autorizarea. Istio oferă instrumente și pentru acest lucru.

Ca exemplu, să creăm două grupuri de utilizatori (vezi diagrama de mai jos):

  • Utilizatori (users) — cu acces doar la serviciile SA-WebApp și SA-Frontend;
  • Moderatori (moderators) — cu acces la toate cele trei servicii.

Înapoi la microservicii împreună cu Istio. Partea 3
Conceptul de autorizare

Pentru a crea aceste grupuri, vom folosi extensia Auth0 Authorization și prin Istio le vom oferi diferite niveluri de acces.

Instalarea și configurarea Auth0 Authorization

Pe portalul Auth0, mergeți la extensii (Extensions) și instalați Auth0 Authorization. După instalare, mergeți la Authorization Extension, apoi la configurația tenant-ului, făcând clic în dreapta sus și alegând opțiunea de meniu corespunzătoare (Configuration). Activați grupurile (Groups) și faceți clic pe butonul de publicare a regulii (Publish rule).

Înapoi la microservicii împreună cu Istio. Partea 3

Crearea grupurilor

În Authorization Extension, mergeți la Grupuri și creați grupul Moderators. Deoarece vom considera toți utilizatorii autentificați ca fiind obișnuiți, nu este necesar să cream un grup suplimentar pentru ei.

Selectați grupul Moderators, faceți clic pe Add Members, adăugați-vă contul principal. Lăsați unii utilizatori fără nici un grup, pentru a vă asigura că accesul pentru ei este interzis. (Utilizatorii noi pot fi creați manual prin Auth0 Portal > Users > Create User.)

Adăugați Group Claim în Access Token

Utilizatorii au fost adăugați în grupuri, totuși aceste informații trebuie să fie reflectate și în tokenurile de acces. Pentru a respecta OpenID Connect și în același timp a returna grupurile de care avem nevoie, tokenul va trebui să adauge proprietatea sa personalizată. proprietate personalizată. Este implementat prin reguli Auth0.

Pentru a crea o regulă, accesați portalul Auth0 la Reguli, faceți clic pe Creează regulă și selectați o regulă goală din șabloane.

Înapoi la microservicii împreună cu Istio. Partea 3

Copiați codul de mai jos și salvați-l ca o nouă regulă Adăugați proprietatea grupului (namespacedGroup.js):

function (user, context, callback) {
    context.accessToken['https://sa.io/group'] = user.groups[0];
    return callback(null, user, context);
}

Notă: acest cod ia prima grupă a utilizatorului definită în Extensia de Autorizare și o adaugă în tokenul de acces ca proprietate personalizată (sub spațiul său de nume, așa cum solicită Auth0).

Întoarceți-vă la pagina Reguli și verificați că aveți două reguli, scrise în următoarea ordine:

  • extensia-autorizării-auth0
  • Adăugați proprietatea grupului

Ordinea este importantă, deoarece câmpul grup este obținut asincron folosind regula extensia-autorizării-auth0 și apoi este adăugat ca proprietate prin a doua regulă. În rezultat, se obține un token de acces de forma:

{
 "https://sa.io/group": "Moderators",
 "iss": "https://sentiment-analysis.eu.auth0.com/",
 "sub": "google-oauth2|196405271625531691872"
 // [scurtat pentru claritate]
}

Acum este necesară configurarea proxy-ului Envoy pentru a verifica accesul utilizatorului, pentru care grupul va fi extras din proprietate (https://sa.io/group) în tokenul de acces returnat. Aceasta este tema pentru următoarea secțiune a articolului.

Configurarea autorizării în Istio

Pentru ca autorizarea să funcționeze, RBAC trebuie activat pentru Istio. Vom utiliza următoarea configurare:

apiVersion: "rbac.istio.io/v1alpha1"
kind: RbacConfig
metadata:
  name: default
spec:
  mode: 'ON_WITH_INCLUSION'                     # 1
  inclusion:
    services:                                   # 2
    - "sa-frontend.default.svc.cluster.local"
    - "sa-web-app.default.svc.cluster.local"
    - "sa-feedback.default.svc.cluster.local" 

Explicații:

  • 1 — activăm RBAC doar pentru serviciile și spațiile de nume enumerate în câmpul Inclusion;
  • 2 — enumerăm lista serviciilor noastre.

Aplicăm configurația cu următoarea comandă:

$ kubectl apply -f resource-manifests/istio/security/enable-rbac.yaml
rbacconfig.rbac.istio.io/default creat

Acum toate serviciile necesită un management al accesului bazat pe roluri (Role-Based Access Control). Cu alte cuvinte, accesul la toate serviciile este interzis și va duce la un răspuns RBAC: acces negăsit. Acum vom permite accesul utilizatorilor autorizați.

Configurarea accesului pentru utilizatorii obișnuiți

Toți utilizatorii trebuie să aibă acces la serviciile SA-Frontend și SA-WebApp. Acest lucru se realizează prin următoarele resurse Istio:

  • ServiceRole — define rights that the user has;
  • ServiceRoleBinding — defines to whom this ServiceRole pertains.

For regular users, we will allow access to certain services (servicerole.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: regular-user
  namespace: default
spec:
  rules:
  - services: 
    - "sa-frontend.default.svc.cluster.local" 
    - "sa-web-app.default.svc.cluster.local"
    paths: ["*"]
    methods: ["*"]

And through regular-user-binding we will apply the ServiceRole to all page visitors (regular-user-service-role-binding.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: regular-user-binding
  namespace: default
spec:
  subjects:
  - user: "*"
  roleRef:
    kind: ServiceRole
    name: "regular-user"

Does "all users" mean that unauthenticated users will also get access to the SA WebApp? No, the policy will check the validity of the JWT token.

We will apply the configurations:

$ kubectl apply -f resource-manifests/istio/security/user-role.yaml
servicerole.rbac.istio.io/regular-user created
servicerolebinding.rbac.istio.io/regular-user-binding created

Access configurations for moderators

For moderators, we want to include access to all services (mod-service-role.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: mod-user
  namespace: default
spec:
  rules:
  - services: ["*"]
    paths: ["*"]
    methods: ["*"]

But we want such rights only for those users whose access token contains the claim https://sa.io/group cu valoarea Moderators (mod-service-role-binding.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: mod-user-binding
  namespace: default
spec:
  subjects:
  - properties:
      request.auth.claims[https://sa.io/group]: "Moderators"
  roleRef:
    kind: ServiceRole
name: "mod-user" 

We will apply the configurations:

$ kubectl apply -f resource-manifests/istio/security/mod-role.yaml
servicerole.rbac.istio.io/mod-user created
servicerolebinding.rbac.istio.io/mod-user-binding created

Due to caching in the envoy, it may take a couple of minutes for the authorization rules to take effect. After that, you can ensure that users and moderators have different access levels.

Conclusion on this part

Seriously: have you ever seen a simpler, effortless, scalable, and secure approach to authentication and authorization?

Only three Istio resources (RbacConfig, ServiceRole, and ServiceRoleBinding) were needed to achieve fine control over authentication and authorization of end-user access to services.

Moreover, we shifted the burden of these issues from our services to the envoy, achieving:

  • a reduction in boilerplate code, where security issues and bugs might occur;
  • a decrease in foolish situations where one endpoint was accessible from the outside and forgot to report that.
  • eliminarea necesității de a actualiza toate serviciile la fiecare adăugare a unei noi roluri sau a unui drept;
  • asigurarea că noile servicii rămân simple, sigure și rapide.

Ieșire

Istio permite echipelor să își concentreze resursele pe sarcinile importante pentru afaceri, fără a adăuga cheltuieli pentru servicii, readucându-le la statutul de „micro”.

Articolul (în trei părți) a oferit cunoștințe de bază și un ghid practic pentru a începe să lucrezi cu Istio în proiecte reale.

P.S. de la traducător

Citiți și în blogul nostru:

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster