<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Blog Point Base]]></title><description><![CDATA[Blog Point Base]]></description><link>https://blog.pointbase.fr</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 21:14:06 GMT</lastBuildDate><atom:link href="https://blog.pointbase.fr/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Comment choisir le bon Flux OAuth 2.0/OIDC et Serveur d’autorisation Okta pour votre Infrastructure]]></title><description><![CDATA[Introduction
Dans l'écosystème du développement moderne, la sécurisation des applications repose sur deux fondamentaux : l'authentification (qui est l'utilisateur ?) et l'autorisation (que peut-il faire ?). Si OAuth 2.0 et OpenID Connect se sont impo...]]></description><link>https://blog.pointbase.fr/flux-oauth2-oidc</link><guid isPermaLink="true">https://blog.pointbase.fr/flux-oauth2-oidc</guid><category><![CDATA[IAM,MFA,Access key ID,Secret access key]]></category><category><![CDATA[okta]]></category><category><![CDATA[identity-access-management]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Aguibou Barry]]></dc:creator><pubDate>Mon, 03 Nov 2025 19:09:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761732858170/2a300f1e-cda3-49cd-9b15-c698c666bfa7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>Dans l'écosystème du développement moderne, la sécurisation des applications repose sur deux fondamentaux : l'authentification (qui est l'utilisateur ?) et l'autorisation (que peut-il faire ?). Si OAuth 2.0 et OpenID Connect se sont imposés comme standards incontournables, leur mise en œuvre concrète soulève souvent de nombreuses questions : quel flux d'autorisation utiliser ? Comment configurer son serveur d'autorisation ? Quelle stratégie adopter selon le type d'application ?</p>
<p>Avec Okta, ces choix techniques deviennent encore plus cruciaux : entre les multiples flux OAuth 2.0/OIDC disponibles et les deux types de serveurs d'autorisation (Org Authorization Server vs Custom Authorization Server), il est essentiel de comprendre les implications de chaque décision pour garantir à la fois la sécurité et la maintenabilité de votre système.</p>
<p>Cet article vous accompagne dans cette réflexion stratégique en clarifiant :</p>
<ul>
<li><p><strong>Les différents flux d'authentification/autorisation</strong> et leurs cas d'usage selon votre architecture (application web traditionnelle, SPA, application mobile, API, ou service backend)</p>
</li>
<li><p><strong>Les critères de choix</strong> entre l'Org Authorization Server et un Custom Authorization Server</p>
</li>
<li><p><strong>Les bonnes pratiques</strong> pour implémenter une solution robuste et évolutive</p>
</li>
</ul>
<p>Que vous débutiez avec Okta ou que vous cherchiez à optimiser une intégration existante, ce guide vous donnera les clés pour prendre les bonnes décisions techniques.</p>
<p>Dans le développement moderne d’applications, l’authentification et l’autorisation sont devenues des piliers essentiels de la sécurité. Entre OAuth 2.0, OpenID Connect, et les serveurs d’autorisation d’Okta, il est parfois difficile de savoir quel flux choisir pour son application ou quel serveur utiliser.</p>
<p>Cet article vous guide pas à pas pour comprendre <strong>quel flux d’authentification</strong> correspond à votre <strong>type d’application</strong> (Web, SPA, mobile, ou service), et <strong>quel serveur d’autorisation</strong> (Org ou Custom) répond le mieux à vos besoins.</p>
<p><em>Avant de détailler OAuth 2.0 et OpenID Connect, faisons un point sur les serveurs d’autorisation (Org et Custom)</em></p>
<h3 id="heading-questce-quun-serveur-dautorisation-vue-fonctionnelle">Qu’est‑ce qu’un serveur d’autorisation (vue fonctionnelle)</h3>
<p>Un <strong>serveur d’autorisation</strong> est le composant qui <strong>contrôle l’accès</strong> à des ressources protégées dans un domaine de sécurité. Dans OAuth 2.0 / OIDC, il <strong>reçoit des demandes</strong> de la part d’applications clientes, <strong>authentifie</strong> l’utilisateur ou le client, <strong>recueille le consentement</strong>, <strong>applique des politiques d’accès</strong> (scopes, audiences, groupes, conditions), puis <strong>émet des jetons</strong> signés (Access Token, ID Token, et éventuellement Refresh Token). Chaque serveur est identifié par un <strong>issuer (URI)</strong> et publie sa <strong>clé publique</strong> pour que les API puissent vérifier les jetons.</p>
<p><strong>Entrées → Traitements → Sorties</strong></p>
<ul>
<li><p><strong>Entrées</strong> : paramètres de la demande (client_id, redirect_uri, scope, code_challenge PKCE…), identifiants/preuves d’authentification (utilisateur ou client), consentement.</p>
</li>
<li><p><strong>Traitements</strong> : authentification, évaluation des <strong>policies</strong>, génération et signature des jetons, journalisation.</p>
</li>
<li><p><strong>Sorties</strong> : redirection avec <strong>authorization code</strong> (selon le flow), <strong>Access Token</strong>, <strong>ID Token</strong>, <strong>Refresh Token</strong> ou erreurs normalisées.</p>
</li>
</ul>
<h3 id="heading-les-endpoints-standard-dun-serveur-dautorisation-okta">Les endpoints standard d’un serveur d’autorisation Okta</h3>
<p>Chaque serveur (Org ou Custom) expose des URLs bien définies. Voici les plus importantes :</p>
<ul>
<li><p><strong>Discover</strong></p>
<ul>
<li><p><a target="_blank" href="https://wandj-iga.okta.com/.well-known/openid-configuration">https://yourOktaDomain.com/.well-known/openid-configuration</a> → Retourne toute la configuration OIDC (endpoints, scopes supportés, clés, etc.).</p>
</li>
<li><p><a target="_blank" href="https://wandj-iga.okta.com/.well-known/oauth-authorization-server">https://</a><a target="_blank" href="https://wandj-iga.okta.com/.well-known/openid-configuration">yourOktaDomain</a><a target="_blank" href="https://wandj-iga.okta.com/.well-known/oauth-authorization-server">.com/.well-known/oauth-authorization-server</a> → Version OAuth 2.0 pure (moins courante).</p>
</li>
</ul>
</li>
<li><p><strong>Autorisation</strong></p>
<ul>
<li><a target="_blank" href="https://wandj-iga.okta.com/oauth2/%7Bauth_server_id%7D/v1/authorize">https://</a><a target="_blank" href="https://wandj-iga.okta.com/.well-known/openid-configuration">yourOktaDomain</a><a target="_blank" href="https://wandj-iga.okta.com/oauth2/%7Bauth_server_id%7D/v1/authorize">.com/oauth2/{auth_server_id}/v1/authorize</a> → Démarre le flux : affiche la page de login, gère le consentement, redirige avec un code.</li>
</ul>
</li>
<li><p><strong>Émission de jetons</strong></p>
<ul>
<li><a target="_blank" href="https://wandj-iga.okta.com/oauth2/%7Bauth_server_id%7D/v1/token">https://</a><a target="_blank" href="https://wandj-iga.okta.com/.well-known/openid-configuration">yourOktaDomain</a><a target="_blank" href="https://wandj-iga.okta.com/oauth2/%7Bauth_server_id%7D/v1/token">.com/oauth2/{auth_server_id}/v1/token</a> → Échange un code contre des tokens (Authorization Code + PKCE), ou délivre un token via client_credentials.</li>
</ul>
</li>
<li><p><strong>Vérification et informations</strong></p>
<ul>
<li><p>/v1/keys → Clés publiques (JWKS) pour vérifier la signature des tokens.</p>
</li>
<li><p>/v1/userinfo → Retourne les données de l’utilisateur (email, nom, etc.) avec un Access Token valide.</p>
</li>
<li><p>/v1/introspect → Vérifie si un token est actif, expiré ou révoqué (uniquement sur Custom Server).</p>
</li>
<li><p>/v1/revoke → Révoque un token immédiatement (logout forcé, sécurité).</p>
</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>Note</strong> : Remplace {auth_server_id} par default (Custom Server par défaut) ou ton ID personnalisé. Pour l’<strong>Org Authorization Server</strong>, les chemins sont en /oauth2/v1/... sans auth_server_id.</p>
</blockquote>
<h3 id="heading-comprendre-les-fondamentaux-oauth-20-et-openid-connect">Comprendre les fondamentaux : OAuth 2.0 et OpenID Connect</h3>
<p>Okta prend en charge plusieurs protocoles d'authentification et d'autorisation : SAML 2.0, Secure Web Authentication (SWA), ainsi que les standards modernes OAuth 2.0 et OpenID Connect (OIDC). Ces deux derniers se sont imposés comme les piliers des intégrations d'applications web, mobiles et API.</p>
<p>Alors que SAML et SWA répondent encore à des cas d'usage legacy, OAuth 2.0 et OIDC offrent une approche plus flexible et standardisée. Mais avant de plonger dans leurs subtilités, posons-nous les bonnes questions : avez-vous besoin de savoir <strong>qui</strong> se connecte (identité), <strong>à quoi</strong> il peut accéder (autorisations), ou s'agit-il d'un <strong>service qui appelle un autre service</strong> sans utilisateur humain ? Ces distinctions orientent directement vos choix d'architecture.</p>
<p><strong>OAuth 2.0 vs OpenID Connect : deux protocoles complémentaires</strong></p>
<ul>
<li><p><strong>OAuth 2.0</strong> contrôle et délègue l'autorisation d'accès à une ressource protégée. Il assure la sécurité des APIs via des <strong>Access Tokens</strong> à portée limitée (scopes), sans exposer les identifiants utilisateur.</p>
</li>
<li><p><strong>OIDC</strong> étend OAuth 2.0 en ajoutant l'authentification et le Single Sign-On (SSO). Il fournit un <strong>ID Token</strong> (JWT signé) contenant l'identité vérifiée de l'utilisateur : nom, email, rôle, photo de profil.</p>
</li>
</ul>
<p><strong>En pratique avec Okta</strong> La majorité des applications nécessitent les deux protocoles. Lors d'un flux complet, Okta délivre à la fois un ID Token (identité) et un Access Token (autorisation). Okta propose des modèles de déploiement qui abstraient ces protocoles, vous n'avez donc pas à les manipuler directement.</p>
<p>Comprendre cette complémentarité vous permet de choisir le bon flux et d'éviter les erreurs courantes : utiliser un Access Token pour l'identité, exposer un ID Token à une API tierce, ou mal dimensionner la durée de vie des tokens</p>
<h3 id="heading-choisir-le-flux-oauth-20-openid-connect-adapte-a-votre-type-dapplication">Choisir le flux OAuth 2.0 / OpenID Connect adapté à votre type d’application</h3>
<p>Lors de la création d’une nouvelle intégration d’application dans Okta, comme illustré dans la capture ci-dessous, vous êtes invité à choisir une <strong>méthode de connexion (Sign-in method)</strong> et un <strong>type d’application (Application type)</strong>.</p>
<p>Ces deux choix déterminent directement le <strong>flux d’authentification OAuth 2.0 / OIDC</strong> que votre application utilisera.</p>
<p>Okta propose plusieurs méthodes d’intégration, chacune adaptée à un cas d’usage particulier.</p>
<ul>
<li><p><strong>SAML 2.0</strong> : un standard basé sur XML, principalement utilisé dans les environnements d’entreprise pour le Single Sign-On (SSO). Il reste adapté aux applications existantes qui ne prennent pas en charge OAuth 2.0 ou OIDC.</p>
</li>
<li><p><strong>SWA (Secure Web Authentication)</strong> : une méthode propre à Okta, utile lorsque l’application ne supporte ni SAML ni OIDC. Elle repose sur une authentification simulée via un formulaire web.</p>
</li>
<li><p><strong>API Services</strong> : utilisée pour les intégrations sans utilisateur (machine-to-machine), basée sur le flux <em>Client Credentials</em> d’OAuth 2.0.</p>
</li>
</ul>
<p>Cependant, pour la plupart des applications modernes – web, mobiles ou orientées API – le choix recommandé est <strong>OIDC – OpenID Connect</strong>, qui s’appuie sur la puissance et la flexibilité du protocole OAuth 2.0.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761767004220/0cc332f5-eb00-4ebd-9510-50b37d9f2435.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p>La section <strong>Sign-in method</strong> permet de sélectionner le protocole d’authentification :</p>
<ul>
<li><p><strong>OIDC – OpenID Connect</strong> (recommandé pour les applications modernes basées sur OAuth 2.0),</p>
</li>
<li><p><strong>SAML 2.0</strong>,</p>
</li>
<li><p><strong>SWA (Secure Web Authentication)</strong>,</p>
</li>
<li><p>ou <strong>API Services</strong> pour les échanges machine-to-machine.</p>
</li>
</ul>
</li>
<li><p>La section <strong>Application type</strong> définit l’environnement et le flux approprié :</p>
<ul>
<li><p><strong>Web Application</strong> → flux <em>Authorization Code</em> (  + PKCE : Optionnel mais fortement recommandé )</p>
</li>
<li><p><strong>Single-Page Application</strong> → flux <em>Authorization Code with PKCE</em>,</p>
</li>
<li><p><strong>Native Application</strong> → flux <em>Authorization Code with PKCE</em>,</p>
</li>
<li><p><strong>API Services</strong> → flux <em>Client Credentials</em>.</p>
</li>
</ul>
</li>
</ol>
<p>En combinant ces deux paramètres, Okta détermine automatiquement <strong>le flux OAuth 2.0 ou OIDC le plus adapté</strong> à votre architecture — qu’il s’agisse d’une application web, d’un front-end SPA, d’une app mobile ou d’un service backend.</p>
<blockquote>
<h3 id="heading-oidc-le-standard-moderne-pour-lauthentification-et-lautorisation"><strong>OIDC : le standard moderne pour l’authentification et l’autorisation</strong></h3>
</blockquote>
<p><strong>OpenID Connect (OIDC)</strong> étend le protocole <strong>OAuth 2.0</strong> en ajoutant une couche d’authentification.</p>
<p>Alors qu’OAuth 2.0 se concentre sur le contrôle d’accès aux ressources (autorisation), OIDC permet d’identifier l’utilisateur de manière sécurisée.</p>
<ul>
<li><h2 id="heading-authorization-code-flow"><strong>Authorization Code Flow :</strong></h2>
</li>
</ul>
<p>Le <strong>Authorization Code Flow</strong> (ou Code Flow) est défini par la spécification OAuth 2.0 (<a target="_blank" href="https://datatracker.ietf.org/doc/html/rfc6749#section-4.1">RFC 6749, section 4.1</a>). C'est le flux le plus couramment utilisé pour les applications web côté serveur et constitue la base des intégrations OAuth/OIDC modernes.</p>
<p>Ce flux est conçu pour offrir un haut niveau de sécurité en séparant l'authentification de l'utilisateur (qui se déroule dans le navigateur) de l'échange de tokens (qui se produit de manière sécurisée entre serveurs backend). Les tokens d'accès ne transitent jamais directement dans le navigateur, réduisant ainsi les risques d'exposition.</p>
<p><img src="https://developer.okta.com/img/authorization/oauth-auth-code-grant-flow.png" alt="Sequence diagram that displays the interactions between the resource owner, authorization server, and resource server for Authorization Code flow&quot;" /></p>
<blockquote>
<p><strong>Étapes du flux Authorization Code</strong></p>
</blockquote>
<ol>
<li><p><strong>Ton application demande un code d’autorisation</strong> Elle redirige l’utilisateur vers Okta (/authorize).</p>
</li>
<li><p><strong>Okta affiche la page de connexion</strong> L’utilisateur voit le login Okta dans son navigateur.</p>
</li>
<li><p><strong>L’utilisateur se connecte et donne son accord</strong> Il entre ses identifiants, accepte les permissions demandées.</p>
</li>
<li><p><strong>Okta renvoie un code d’autorisation au navigateur</strong> Le code arrive dans l’URL de redirection (ex: ?code=abc123).</p>
</li>
<li><p><strong>Ton application envoie le code + le client secret à Okta</strong> Appel backend vers /token (pas dans le navigateur !).</p>
</li>
<li><p><strong>Okta répond avec les tokens</strong> Tu reçois :</p>
<ul>
<li><p>access_token (pour appeler l’API)</p>
</li>
<li><p>id_token (identité de l’utilisateur)</p>
</li>
<li><p>refresh_token (optionnel, pour renouveler)</p>
</li>
</ul>
</li>
<li><p><strong>Ton application appelle l’API avec l’access_token</strong> En-tête : Authorization: Bearer &lt;token&gt;</p>
</li>
<li><p><strong>L’API vérifie le token avant de répondre</strong> Elle utilise les clés publiques d’Okta (/keys) pour valider la signature.</p>
</li>
</ol>
<blockquote>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong><em>Recommandation</em></strong>: Franchement, mettez PKCE partout — SPA, mobile, ou même backend</div>
</div>

<p>En fait, depuis 2023, il est <strong>fortement recommandé d’utiliser le flux “Authorization Code Flow with PKCE”</strong>, y compris pour les applications web côté serveur.</p>
<p>Cette approche, initialement conçue pour les applications mobiles et SPA, ajoute une couche de sécurité supplémentaire au flux classique en protégeant l’échange du code d’autorisation.</p>
<p>Nous reviendrons plus loin sur le fonctionnement détaillé du <strong>PKCE (Proof Key for Code Exchange)</strong> et sur les raisons de son adoption généralisée.</p>
<p><strong>Référence :</strong> <a target="_blank" href="https://developer.okta.com/docs/concepts/oauth-openid/">Okta Developer Docs – Authorization Code Flow with PKCE</a></p>
</blockquote>
<ul>
<li><h2 id="heading-authorization-code-flow-with-pkce-la-version-renforcee-du-code-flow"><strong>Authorization Code Flow with PKCE : la version renforcée du Code Flow</strong></h2>
</li>
</ul>
<p>Le <strong>Authorization Code Flow with PKCE (Proof Key for Code Exchange)</strong> est une évolution du flux d’autorisation classique décrite dans la <strong>RFC 7636</strong>.</p>
<p>À l’origine, ce mécanisme a été conçu pour les <strong>applications mobiles et Single Page Applications (SPA)</strong>, où le client_secret ne peut pas être protégé.</p>
<p>Il est aujourd’hui <strong>recommandé pour toutes les applications</strong>, y compris celles côté serveur, car il renforce la sécurité du processus d’échange de tokens.</p>
<blockquote>
<p><strong>Principe de fonctionnement</strong></p>
</blockquote>
<p>Le fonctionnement reste globalement identique au <em>Code Flow classique</em>, à une différence majeure :</p>
<p>l’application génère une <strong>clé temporaire unique</strong>, appelée code_verifier, qu’elle transforme en un <strong>code challenge</strong> (haché).</p>
<p>Cette clé permet au serveur d’autorisation (Okta) de vérifier que le code d’autorisation échangé n’a pas été intercepté ou modifié pendant le processus.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761768916324/3a05c0cf-e069-4a72-8d3b-ccf3d933a012.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>Étapes du flux Authorization Code avec PKCE</strong></p>
</blockquote>
<ol>
<li><p>Génération de la clé PKCE<br /> L’application commence par générer un <em>code verifier</em> (clé aléatoire) et en déduit un <em>code challenge</em> (sa version hachée). Ces deux éléments serviront à prouver l’identité de l’application lors de l’échange du code d’autorisation.</p>
</li>
<li><p>Demande d’un code d’autorisation<br /> L’application redirige l’utilisateur vers le serveur d’autorisation Okta (/authorize), en incluant le code_challenge.</p>
</li>
<li><p>Affichage de la page de connexion<br /> Okta affiche la page de connexion à l’utilisateur. Celui-ci choisit une méthode d’authentification (identifiant/mot de passe, SSO, etc.).</p>
</li>
<li><p>Authentification et consentement<br /> L’utilisateur s’identifie et, si nécessaire, accepte les autorisations demandées par l’application (scopes).</p>
</li>
<li><p>Redirection vers l’application<br /> Une fois authentifié, Okta redirige le navigateur vers l’application avec un <strong>code d’autorisation temporaire</strong>.</p>
</li>
<li><p>Échange du code d’autorisation contre des tokens<br /> L’application envoie ce code à Okta, accompagné du code_verifier, pour prouver qu’elle est bien à l’origine de la demande.</p>
</li>
<li><p>Validation du code PKCE<br /> Okta compare le code_verifier reçu avec le code_challenge initial afin de vérifier l’intégrité de la requête.</p>
</li>
<li><p>Remise des tokens<br /> Si tout est correct, Okta renvoie un <strong>Access Token</strong>, un <strong>ID Token</strong>, et éventuellement un <strong>Refresh Token</strong>.</p>
</li>
<li><p>Accès aux ressources protégées<br /> L’application utilise l’Access Token pour interroger une API (le <em>Resource Server</em>) au nom de l’utilisateur.</p>
</li>
<li><p>Réponse du serveur de ressources<br />L’API valide le token et renvoie les données demandées.</p>
</li>
</ol>
<blockquote>
<p>Exemple de code : Authorization code flow + PKCE</p>
</blockquote>
<pre><code class="lang-javascript"><span class="hljs-comment">// On commence par générer deux valeurs aléatoires et uniques pour chaque connexion :</span>
<span class="hljs-comment">// 1. code_verifier : une chaîne longue et imprévisible (minimum 43 caractères)</span>
<span class="hljs-comment">//    Elle sert à prouver que c'est bien notre application qui a initié la demande.</span>
<span class="hljs-comment">//    On la garde en mémoire (session ou stockage local) pour la réutiliser plus tard.</span>
<span class="hljs-keyword">const</span> { generators } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'openid-client'</span>);
<span class="hljs-keyword">const</span> code_verifier = generators.codeVerifier();

<span class="hljs-comment">// 2. state : une autre valeur aléatoire, différente à chaque fois.</span>
<span class="hljs-comment">//    Elle empêche les attaques CSRF : si quelqu'un essaie de forcer une redirection,</span>
<span class="hljs-comment">//    cette valeur ne correspondra pas à celle qu'on a envoyée.</span>
<span class="hljs-keyword">const</span> state = <span class="hljs-built_in">require</span>(<span class="hljs-string">'crypto'</span>).randomBytes(<span class="hljs-number">32</span>).toString(<span class="hljs-string">'hex'</span>);

<span class="hljs-comment">// On calcule le code_challenge à partir du code_verifier (hash en SHA256)</span>
<span class="hljs-keyword">const</span> code_challenge = generators.codeChallenge(code_verifier);

<span class="hljs-comment">// On construit l'URL complète pour rediriger l'utilisateur vers Okta</span>
<span class="hljs-keyword">const</span> authUrl = <span class="hljs-string">`https://my-domaine.okta.com/oauth2/default/v1/authorize?`</span> +
  <span class="hljs-string">`client_id=0oaxxx`</span> +
  <span class="hljs-string">`&amp;response_type=code`</span> +
  <span class="hljs-string">`&amp;scope=openid profile email`</span> +
  <span class="hljs-string">`&amp;redirect_uri=http://localhost:3000/callback`</span> +
  <span class="hljs-string">`&amp;state=<span class="hljs-subst">${state}</span>`</span> +              <span class="hljs-comment">// Valeur aléatoire, vérifiée au retour</span>
  <span class="hljs-string">`&amp;code_challenge=<span class="hljs-subst">${code_challenge}</span>`</span> +  <span class="hljs-comment">// Preuve que le code vient bien de nous</span>
  <span class="hljs-string">`&amp;code_challenge_method=S256`</span>;

<span class="hljs-comment">// On supprime les espaces et retours à la ligne pour une URL propre</span>
<span class="hljs-keyword">const</span> cleanUrl = authUrl.replace(<span class="hljs-regexp">/\s/g</span>, <span class="hljs-string">''</span>);

<span class="hljs-comment">// On stocke les deux valeurs secrètes avant de rediriger</span>
req.session.code_verifier = code_verifier;
req.session.state = state;

res.redirect(cleanUrl); <span class="hljs-comment">// L'utilisateur est envoyé vers la page de login Okta</span>
</code></pre>
<h2 id="heading-client-credentials-flow-le-flux-pour-les-communications-machine-to-machine"><strong>Client Credentials Flow : le flux pour les communications machine-to-machine</strong></h2>
<p>Le <strong>Client Credentials Flow</strong> est conçu pour les applications <strong>sans utilisateur final</strong> — autrement dit, pour les scénarios où <strong>une application ou un service doit accéder à une ressource protégée au nom d’elle-même</strong>.</p>
<p>Ce flux est typique dans les architectures de microservices ou pour les automatisations backend, où un service doit appeler une API sécurisée.</p>
<blockquote>
<p><strong>Principe général</strong></p>
</blockquote>
<p>Contrairement aux autres flux OAuth 2.0, celui-ci <strong>ne passe pas par une interaction utilisateur</strong>.</p>
<p>L’application cliente s’authentifie directement auprès du serveur d’autorisation à l’aide de ses propres identifiants (généralement un <em>Client ID</em> et un <em>Client Secret</em>), et obtient en retour un <strong>Access Token</strong>.</p>
<p>Ce jeton permet ensuite d’appeler les API protégées.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761769869654/e1d04397-da82-49d3-9a49-184422bb50af.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p><strong>Étapes du flux Client Credentials Flow</strong></p>
</blockquote>
<ul>
<li><p>Requête de jeton d’accès<br />  L’application envoie une requête au serveur d’autorisation Okta vers le point de terminaison /token, en s’authentifiant à l’aide de ses propres identifiants (client_id et client_secret).<br />  Ces identifiants sont configurés lors de la création de l’intégration d’application (type <em>API Services</em>).</p>
</li>
<li><p>Réponse avec le jeton d’accès<br />  Si les informations d’identification sont valides, Okta renvoie un <strong>Access Token</strong> signé, limité dans le temps et contenant les <em>scopes</em> autorisés.</p>
</li>
<li><p>Appel de l’API avec le jeton<br />  L’application utilise ce jeton d’accès pour appeler le <strong>Resource Server</strong> (votre API sécurisée). Le jeton prouve que la requête vient d’une application autorisée.</p>
</li>
<li><p>Validation et réponse<br />  Le serveur de ressources vérifie la validité du jeton auprès d’Okta avant de fournir les données ou d’exécuter l’action demandée.</p>
</li>
</ul>
<blockquote>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Points clés à retenir</strong></div>
</div>

<ul>
<li><p>Ce flux ne fournit <strong>pas d’ID Token</strong>, car <strong>aucun utilisateur n’est impliqué</strong>.</p>
</li>
<li><p>Les <strong>scopes</strong> doivent être définis avec précision afin de limiter les permissions du client.</p>
</li>
<li><p>Les identifiants (client_id et client_secret) doivent être stockés <strong>de manière sécurisée</strong> (jamais dans le code source).</p>
</li>
<li><p>En pratique, ce flux est presque toujours utilisé avec un Custom Authorization Server, car il permet de créer des tokens sur mesure pour vos propres APIs.</p>
</li>
</ul>
<p>Exemple de code : Client Credentials Flow (M2M)</p>
</blockquote>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> getApiToken = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-comment">// Prépare la requête sans utilisateur</span>
  <span class="hljs-keyword">const</span> params = <span class="hljs-keyword">new</span> URLSearchParams({
    <span class="hljs-attr">grant_type</span>: <span class="hljs-string">'client_credentials'</span>,
    <span class="hljs-attr">scope</span>: <span class="hljs-string">'api:read api:write'</span> <span class="hljs-comment">// -&gt; Scopes définis dans le Custom Server</span>
  });

  <span class="hljs-comment">// Authentifie le service avec client_id + secret, ici on pointe sur le custom serveur</span>
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://my-domain.okta.com/oauth2/default/v1/token'</span>, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Authorization'</span>: <span class="hljs-string">'Basic '</span> + Buffer.from(<span class="hljs-string">'0oayyy:secret'</span>).toString(<span class="hljs-string">'base64'</span>),
      <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/x-www-form-urlencoded'</span>
    },
    <span class="hljs-attr">body</span>: params
  });

  <span class="hljs-keyword">const</span> { access_token } = <span class="hljs-keyword">await</span> response.json();
  <span class="hljs-keyword">return</span> access_token; <span class="hljs-comment">// -&gt; Token pour appeler ton API</span>
};

<span class="hljs-comment">// Exemple d'appel API</span>
<span class="hljs-keyword">const</span> token = <span class="hljs-keyword">await</span> getApiToken();
fetch(<span class="hljs-string">'https://api.monservice.com/data'</span>, {
  <span class="hljs-attr">headers</span>: { <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${token}</span>`</span> }
});
</code></pre>
<h2 id="heading-les-flux-oauth-20-deprecies-implicit-et-ropg"><strong>Les flux OAuth 2.0 dépréciés : Implicit et ROPG</strong></h2>
<p>Bien que toujours définis dans la spécification <strong>OAuth 2.0 (RFC 6749)</strong>, certains flux historiques sont aujourd’hui considérés comme <strong>obsolètes</strong> ou <strong>à usage restreint</strong>.</p>
<p>C’est notamment le cas de l’<strong>Implicit Flow</strong> et du <strong>Resource Owner Password Credentials Flow (ROPG)</strong>.</p>
<p>L’<strong>Implicit Flow</strong>, conçu à l’origine pour les applications Single-Page (SPA) dépourvues de capacités sécurisées côté serveur, permettait de récupérer un jeton d’accès directement via l’URL après redirection.</p>
<p>Mais cette approche présente plusieurs failles : exposition du jeton dans le navigateur, impossibilité de vérifier sa signature, et risques de vol via des scripts tiers.</p>
<p>C’est pourquoi Okta, comme l’ensemble de l’écosystème OAuth, recommande désormais de le remplacer par le Authorization Code avec PKCE plus sûr et universel.</p>
<p>Le <strong>Resource Owner Password Flow (ROPG)</strong>, lui, autorise une application à collecter directement les identifiants de l’utilisateur (nom d’utilisateur et mot de passe) pour obtenir un jeton d’accès.</p>
<p>Ce flux contourne toutefois la page d’authentification Okta et empêche l’application de bénéficier de mécanismes avancés tels que la <strong>MFA</strong>, la détection d’anomalies ou l’authentification adaptative.</p>
<p>Okta précise dans sa documentation officielle que ce flux ne doit être utilisé <strong>que dans les environnements de confiance</strong> ou à des fins de compatibilité technique :</p>
<p>“If your app is high-trust and you own both the client and the resource it accesses, you can use the Resource Owner Password flow. However, this flow is not compatible with multifactor authentication, and should be replaced by the Authorization Code or Interaction Code flow whenever possible.”</p>
<p>(Source : <a target="_blank" href="https://developer.okta.com/docs/concepts/oauth-openid/#resource-owner-password-flow">Okta Developer Docs – OAuth &amp; OpenID Connect Concepts</a>)</p>
<blockquote>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong>Recommandation actuelle</strong></div>
</div>

<p>Depuis 2023, les bonnes pratiques de sécurité (Okta, IETF, Auth0) convergent :</p>
<p>Utilisez le Code Flow with PKCE pour toutes les applications avec utilisateur, et le Client Credentials Flow pour les échanges entre services.</p>
</blockquote>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>On arrive au bout de ce guide, et l’essentiel tient en une idée : <strong>choisir le bon flux OAuth/OIDC et le bon serveur Okta, c’est protéger ton application sans te prendre la tête.</strong></p>
<ul>
<li><p><strong>Si tu as des utilisateurs</strong> (web, SPA, mobile) → <strong>Authorization Code avec PKCE, point final.</strong> C’est le standard depuis 2023, ça marche partout, ça supporte la MFA, et les SDK Okta le font tout seul.</p>
</li>
<li><p><strong>Si c’est du machine-to-machine</strong> → <strong>Client Credentials + Custom Authorization Server.</strong> C’est là que tu définis tes propres audiences, scopes, claims. Tes APIs deviennent vraiment à toi.</p>
</li>
<li><p><strong>Oublie l’Implicit et le ROPG.</strong> Sauf si t’as une vieille app qui traîne dans un coin… et même là, planifie la migration.</p>
</li>
</ul>
<blockquote>
<p><strong>Org vs Custom : le match en 3 lignes</strong></p>
</blockquote>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td><strong>Org Server</strong></td><td><strong>Custom Server</strong></td></tr>
</thead>
<tbody>
<tr>
<td><strong>Pourquoi ?</strong></td><td>Login, SSO, apps simples</td><td>APIs perso, microservices,</td></tr>
<tr>
<td><strong>Souplesse</strong></td><td>Scopes Okta uniquement</td><td>Tu fais ce que tu veux (scopes custom)</td></tr>
<tr>
<td><strong>Quand l’utiliser ?</strong></td><td>Prototype, SaaS, interne</td><td>Controle total</td></tr>
</tbody>
</table>
</div><blockquote>
<p><strong>Mon conseil de dev à dev</strong> : Commence avec l’<strong>Org Server</strong> — c’est prêt en 2 clics. Dès que tu a besoin d’un scope custom, une audience propre ou un claim métier → <strong>passe au Custom</strong>.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Auth0 Series [1/10] :  Introduction à Auth0]]></title><description><![CDATA[Dans un monde où les applications sont partout, l’identité des utilisateurs est devenue la clé d’entrée. Mais sécuriser cette identité n’est pas trivial.
Défi actuel
Chaque application moderne doit gérer l’authentification et l’autorisation des utili...]]></description><link>https://blog.pointbase.fr/introduction-a-auth0</link><guid isPermaLink="true">https://blog.pointbase.fr/introduction-a-auth0</guid><category><![CDATA[IAM]]></category><category><![CDATA[Auth0]]></category><category><![CDATA[ciam]]></category><category><![CDATA[identity-management]]></category><category><![CDATA[Access Management]]></category><dc:creator><![CDATA[Aguibou Barry]]></dc:creator><pubDate>Fri, 26 Sep 2025 17:00:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1758653492299/4e97a6ee-2bdf-46af-bc56-b5383d36aefd.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Dans un monde où les applications sont partout, l’identité des utilisateurs est devenue la clé d’entrée. Mais sécuriser cette identité n’est pas trivial.</p>
<h2 id="heading-defi-actuel">Défi actuel</h2>
<p>Chaque application moderne doit gérer l’authentification et l’autorisation des utilisateurs.<br />Construire ces mécanismes en interne paraît simple au départ, mais devient rapidement un <strong>casse-tête technique et sécuritaire</strong> :</p>
<ul>
<li><p>hachage et stockage sécurisé des mots de passe</p>
</li>
<li><p>gestion des sessions et des tokens (Access / Refresh)</p>
</li>
<li><p>mise en place du MFA (Multi-Factor Authentication) ou encore du SSO (SIngle sign On)</p>
</li>
<li><p>intégration avec des réseaux sociaux ou des annuaires d’entreprise,</p>
</li>
<li><p>conformité avec les réglementations (<a target="_blank" href="https://www.economie.gouv.fr/entreprises/gerer-son-entreprise-au-quotidien/assurer-sa-cybersecurite-et-la-protection-de-ses/le">RGPD</a>, <a target="_blank" href="https://www.ibm.com/fr-fr/topics/ccpa-compliance">CCPA</a>, <a target="_blank" href="https://cloud.google.com/security/compliance/hipaa-compliance?hl=fr">HIPAA</a>),</p>
</li>
<li><p>protection contre les attaques (brute force, bots, injections).</p>
</li>
</ul>
<p>Autant de sujets complexes, qui consomment un temps précieux et détournent les équipes de leur objectif principal : <strong>créer de la valeur pour l’utilisateur</strong>.</p>
<h2 id="heading-quest-ce-quauth0">Qu’est ce qu’Auth0</h2>
<p>Auth0 est une plateforme d’Identity-as-a-Service (IDaaS) qui permet aux entreprises de gérer facilement l’authentification et l’autorisation de leurs applications. Concrètement, c’est un service qui prend en charge tout ce qui concerne la gestion de l’identité des utilisateurs : connexion, inscription, fédération avec des fournisseurs externes, sécurisation des accès et contrôle granulaire des permissions.</p>
<p>Au lieu de développer et maintenir en interne ces mécanismes complexes, Auth0 fournit un ensemble d’outils prêts à l’emploi, extensibles et conformes aux standards du marché (OAuth2, OpenID Connect, SAML, etc.). Les équipes peuvent ainsi se concentrer sur leur cœur de métier, tout en bénéficiant d’une infrastructure de sécurité éprouvée et constamment mise à jour.</p>
<p>Auth0 s’adresse aussi bien aux applications B2C (grand public), B2B (clients professionnels) qu’aux usages internes (applications métiers). Sa force réside dans sa modularité : vous activez uniquement les fonctionnalités dont vous avez besoin, et vous les faites évoluer au rythme de vos projets.</p>
<h2 id="heading-la-promesse-dauth0">La promesse d’Auth0</h2>
<blockquote>
<p><em>«</em> Centralisez et gérez vos utilisateurs, qu’ils viennent de multiples fournisseurs d’identité, et offrez-leur une expérience de connexion fluide, moderne et à l’image de votre marque.<br />Grâce à un haut niveau de personnalisation, contrôlez l’accès avec précision et répondez même aux exigences de sécurité les plus complexes»<br />(<a target="_blank" href="https://auth0.com/docs">Auth0 Docs</a>)</p>
</blockquote>
<h2 id="heading-la-solution-auth0">La solution Auth0</h2>
<p>Quand on parle d’authentification <strong>et</strong> d’autorisation, chaque équipe technique se heurte aux mêmes difficultés : sécuriser les mots de passe, gérer les sessions et tokens, mettre en place du MFA, intégrer différents fournisseurs d’identité, respecter des normes de conformité et se protéger contre les attaques. Mais il faut aussi aller plus loin : <strong>définir qui a accès à quoi, dans quelles conditions et pour combien de temps</strong>. Cette granularité est essentielle pour concilier productivité et sécurité.</p>
<p>Auth0 s’impose ici comme une plateforme qui prend en charge ces problématiques de bout en bout, grâce à un ensemble de modules spécialisés et interconnectés. Elle ne se limite pas à vérifier l’identité d’un utilisateur : elle permet aussi de contrôler finement ses droits d’accès, de contextualiser les règles (selon l’appareil, l’heure, la localisation) et d’ajuster la durée de validité des permissions</p>
<ol>
<li><h3 id="heading-securiser-les-identifiants-sans-compromis">Sécuriser les identifiants sans compromis</h3>
</li>
</ol>
<p>Stocker et protéger les mots de passe n’est jamais anodin. Auth0 applique par défaut les meilleures pratiques de hachage et de stockage sécurisé, en s’appuyant sur des algorithmes éprouvés (bcrypt, argon2, etc.). Cela permet aux équipes de ne pas réinventer ces mécanismes sensibles et d’éviter les erreurs qui exposeraient les utilisateurs. Comme le rappellent les docs Auth0, déléguer cette responsabilité réduit considérablement le risque lié à une mauvaise implémentation maison.</p>
<ol start="2">
<li><h3 id="heading-gerer-efficacement-les-sessions-et-tokens">Gérer efficacement les sessions et tokens</h3>
</li>
</ol>
<p>Les applications modernes s’appuient sur OAuth2 et OpenID Connect pour sécuriser l’accès. Auth0 gère nativement le cycle de vie des Access Tokens et Refresh Tokens, ce qui garantit une authentification fluide tout en limitant la surface d’attaque. Grâce à des règles de rotation et d’expiration configurables, il est possible d’ajuster la sécurité sans sacrifier l’expérience utilisateur.</p>
<ol start="3">
<li><h3 id="heading-offrir-mfa-et-sso-simplement">Offrir MFA et SSO simplement</h3>
</li>
</ol>
<p>La mise en place du <strong>Multi-Factor Authentication (MFA)</strong> et du <strong>Single Sign-On (SSO)</strong> est souvent un chantier complexe. Auth0 propose des modules prêts à l’emploi : un clic pour activer le MFA (via SMS, email, TOTP ou push notification) et des connecteurs standardisés pour le SSO. Résultat : vos utilisateurs bénéficient d’une expérience fluide, avec une couche de sécurité renforcée qui reste simple à activer.</p>
<ol start="4">
<li><h3 id="heading-integrer-plusieurs-fournisseurs-didentite">Intégrer plusieurs fournisseurs d’identité</h3>
</li>
</ol>
<p>Un des grands atouts d’Auth0 est la capacité à fédérer plusieurs sources d’identité : authentification sociale (Google, Facebook, Apple), annuaires d’entreprise (Active Directory, LDAP), protocoles standards (SAML, OpenID Connect). Les équipes n’ont plus besoin de coder ces intégrations à la main : il suffit de configurer le provider dans le dashboard Auth0. Cette flexibilité permet de répondre aux besoins B2C, B2B et internes, sans multiplier les implémentations.</p>
<ol start="5">
<li><h3 id="heading-respecter-la-conformite-reglementaire">Respecter la conformité réglementaire</h3>
</li>
</ol>
<p>RGPD, CCPA, HIPAA : autant de sigles qui représentent des obligations fortes en matière de protection des données. Auth0 intègre des fonctionnalités de gestion de consentement, de journalisation et de contrôle granulaire des données utilisateurs. Cela facilite la conformité tout en gardant la main sur la gouvernance des identités. Les équipes gagnent du temps et limitent leur exposition légale, tout en offrant de la transparence aux utilisateurs finaux.</p>
<ol start="6">
<li><h3 id="heading-proteger-contre-les-menaces-avancees">Protéger contre les menaces avancées</h3>
</li>
</ol>
<p>Au-delà de l’authentification de base, Auth0 inclut des protections intelligentes contre les attaques les plus fréquentes : brute force, credential stuffing, bots, injections. Grâce à la détection d’anomalies, la plateforme peut bloquer ou défier une tentative suspecte en temps réel. Cela permet de renforcer la sécurité sans alourdir inutilement l’expérience des utilisateurs légitimes.</p>
<ol start="7">
<li><h3 id="heading-controler-finement-lacces-aux-ressources">Contrôler finement l’accès aux ressources</h3>
</li>
</ol>
<p>Auth0 ne se limite pas à identifier un utilisateur : la plateforme permet de gérer ses autorisations via RBAC (Role-Based Access Control) ou ABAC (Attribute-Based Access Control). Cela permet de définir précisément qui a accès à quoi, dans quelles conditions (localisation, appareil, heure) et pour combien de temps.</p>
<ol start="8">
<li><h3 id="heading-offrir-une-experience-coherente-et-personnalisee">Offrir une expérience cohérente et personnalisée</h3>
</li>
</ol>
<p>Avec <em>Universal Login</em>, Auth0 permet de proposer un écran de connexion fluide et entièrement personnalisable à votre charte graphique. L’utilisateur reste immergé dans votre univers, qu’il choisisse de se connecter avec un email, un réseau social ou un SSO d’entreprise. Résultat : une expérience moderne et sans rupture, qui renforce la confiance et l’adoption.</p>
<ol start="9">
<li><h3 id="heading-personnaliser-et-etendre-facilement">Personnaliser et étendre facilement</h3>
</li>
</ol>
<p>Chaque organisation a des besoins spécifiques en matière de gestion d’identité. Grâce aux <em>Rules</em> et <em>Actions</em>, Auth0 rend le processus d’authentification extensible : vous pouvez enrichir un token avec des données externes, appliquer des politiques dynamiques en fonction du contexte, ou encore déclencher des appels vers vos propres APIs au moment de la connexion. Cette flexibilité permet d’aligner la sécurité et l’expérience utilisateur avec vos exigences métiers les plus pointues.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>La gestion de l’identité n’est plus un simple détail technique : c’est un pilier de la sécurité, de la conformité et de l’expérience utilisateur. Construire en interne des mécanismes d’authentification et d’autorisation robustes prend du temps, multiplie les risques et détourne les équipes de leur véritable mission.</p>
<p>Avec Auth0, vous disposez d’une plateforme complète, modulaire et extensible qui prend en charge ces problématiques de bout en bout : de la protection des identifiants jusqu’à la gestion fine des accès, en passant par la conformité, la personnalisation et la détection des menaces.</p>
<p>En adoptant Auth0, vous gagnez en rapidité de mise en œuvre, en tranquillité d’esprit et en capacité à offrir une expérience fluide à vos utilisateurs. Bref, vous transformez un casse-tête technique en un véritable levier de confiance et de croissance.</p>
]]></content:encoded></item><item><title><![CDATA[ISPM & ITDR OKTA - Kezako 🤔?]]></title><description><![CDATA[Introduction
Malgré l’adoption quasi-généralisée de modèles de sécurité « Principe du moindre privilège » et/ou « ZeroTrust », plus de 60% des cyberattaques en 2024 étaient encore liées à des usurpations d’identité et/ou à des droits d’accès excessif...]]></description><link>https://blog.pointbase.fr/ispm-and-itdr-okta-kezako</link><guid isPermaLink="true">https://blog.pointbase.fr/ispm-and-itdr-okta-kezako</guid><category><![CDATA[identity-management]]></category><dc:creator><![CDATA[Nicolas Petroussenko]]></dc:creator><pubDate>Wed, 19 Feb 2025 12:08:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739966161769/19f19a5d-0620-4063-b0ab-1b40cf02c696.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Malgré l’adoption quasi-généralisée de modèles de sécurité « <strong>Principe du moindre privilège</strong> » et/ou « <strong>ZeroTrust</strong> », plus de 60% des cyberattaques en 2024 étaient encore liées à des usurpations d’identité et/ou à des droits d’accès excessifs. Les solutions IDP (IDentity Provider), telles Okta ou EntraID, ont vocation à réduire considérablement ce type de risques par la mise en place de politiques d’authentification et d’accès centralisées et sécurisées (SSO, MFA contextuel, gouvernance des identités…).</p>
<p>En théorie, avec ce type de solutions, on peut dormir tranquille, surtout si l’on utilise des facteurs dits « phishing résistants » ...<strong>Sauf que, ce n’est pas nécessairement aussi simple !</strong></p>
<p>Si le fait de mettre en place un IDP moderne réduit considérablement la surface d’attaque, il reste encore quelques angles morts ! En effet, les IDP modernes sont très efficaces pour gérer l’authentification, les politiques de droits d’accès ou encore le cycle de vie des identités, mais jusqu’à présent, ils répondaient de manière encore trop imparfaite à deux enjeux importants :</p>
<ul>
<li><p><strong>La gestion de la posture de sécurité des identités</strong></p>
</li>
<li><p><strong>La détection et la réponse aux menaces liées aux tentatives d’accès</strong></p>
</li>
</ul>
<p>Fort de ce constat, Okta a récemment lancé 2 nouveaux modules intégrés à sa solution Okta Identity Platform, qui apportent des réponses très concrètes : <strong>ISPM et ITDR</strong>.</p>
<p>L’objet de cet article est de mieux comprendre à quoi servent les modules <strong>ISPM (Identity Security Posture Management)</strong> et <strong>ITDR (Identity Threat Detection &amp; Response)</strong>.</p>
<h2 id="heading-i-gestion-de-la-posture-de-securite-des-identites-ispm">I. <strong>Gestion de la Posture de Sécurité des Identités (ISPM)</strong></h2>
<p>Commençons par une définition claire : l'ISPM sert à identifier et corriger, en amont de toute tentative d’accès, les vulnérabilités potentielles sur les identités.</p>
<p>Comme sa définition l’indique, son rôle est donc proactif (en amont). <strong>On n’attend pas que quelqu’un essaie de se connecter pour identifier et corriger les vulnérabilités potentielles</strong>.</p>
<p>Donnons quelques exemples de vulnérabilités sur les identités :</p>
<ul>
<li><p>Attribution excessive de droits/privilèges</p>
</li>
<li><p>Mots de passe faibles ou inchangés</p>
</li>
<li><p>Incohérence dans les parcours d’authentification (notamment les conditions de déclenchement du MFA ou encore les facteurs MFA eux-mêmes)</p>
</li>
<li><p>Utilisation incorrecte des comptes de service (utilisation des comptes de service comme comptes humains et réciproquement)</p>
</li>
<li><p>Gestion incomplète du cycle de vie des identités (par exemple, lors d’une suppression de compte, Okta est mis à jour mais pas l’AD ou réciproquement)</p>
</li>
<li><p>Utilisation de comptes partagés</p>
</li>
</ul>
<p>Ces exemples permettent de bien comprendre le rôle du module ISPM d’Okta : offrir une vue centralisée et complète de toutes les vulnérabilités potentielles à travers l’ensemble de l’écosystème lié à l’identité, afin de les corriger en amont, avant toute tentative d’authentification par un utilisateur !</p>
<p>Un de nos clients a résumé l’intérêt d’ISPM de la façon suivante, et je trouve sa formulation assez juste : <strong>« c’est un peu comme une sentinelle qui vérifierait en continue si l’on a bien fait les choses dans notre gestion des identités, et si ce n’est pas le cas, il nous invite à les corriger ».</strong></p>
<h2 id="heading-ii-detection-et-reponse-aux-menaces-sur-les-identites-itdr">II. <strong>Détection et Réponse aux Menaces sur les Identités (ITDR)</strong></h2>
<p>Définition : l'ITDR d'Okta se concentre sur la surveillance <strong>continue</strong> et <strong>la réponse</strong> aux menaces ciblant les identités.</p>
<p>En première lecture, cela ressemble à ce que fait l’ISPM, à l’exception près qu’il s’agît d’opérations réalisées après l’authentification. Il n’est plus question de qualifier et améliorer la posture de sécurité des identités mais de réagir et remédier en temps réel à une possible compromission.</p>
<p><strong>Exemples concrets :</strong></p>
<ul>
<li><p>Si un attaquant tente d’accéder aux comptes d’utilisateurs par force brute (il essaie des milliers de paires de login/password différents), l’adresse IP de cet attaquant sera immédiatement bloquée.</p>
</li>
<li><p>Une fuite de données sur le darkweb révèle les identifiants et mots de passe d’utilisateurs. Les comptes seront alors mis en quarantaine (« suspendus ») en attendant que les utilisateurs concernés réinitialisent leur mot de passe via une procédure sécurisée n’utilisant pas leurs credentials actuels</p>
</li>
<li><p>Détection d’un comportement anormal : un utilisateur se connecte depuis un lieu et à une heure très inhabituels. ITDR va alors identifier une activité suspecte et un deuxième facteur (par exemple) sera déclenché</p>
</li>
<li><p>Détection et réaction automatique aux attaques de Phishing (Hameçonnage). Si un employé clique par mégarde sur un lien malveillant et fournit ses identifiants, ITDR va alors identifier qu’un utilisateur utilisant les mêmes credentials essaie de se connecter depuis un lieux différent ou encore une machine différente. La réponse configurable d’ITDR peut alors être : autre facteur d’authentification requis (car finalement un utilisateur légitime peut aussi prendre l’avion et utiliser un autre ordinateur) ou encore impossibilité de se connecter depuis un autre terminal.</p>
</li>
<li><p>Universal Logout : Mécanisme qui permet de fermer toutes les sessions actives de l’utilisateur. Pas uniquement la session Okta, mais aussi (et peut-être surtout) les sessions des applications et services fédérés par Okta. Ainsi, si un attaquant récupère un token de session Okta (stocké sous forme d’un cookie sécurisé) et essaie de le jouer depuis un autre poste, ITDR le détectera et déclenchera l’universal logout sur toutes les sessions Okta actives et sur l’ensemble des sessions des applications fédérées.</p>
</li>
</ul>
<p>Les exemples donnés visent à mieux comprendre les finalités respectives d’ISPM et ITDR, le premier permettant une surveillance continue du respect des bonnes pratiques de sécurité des identités en amont (la posture), le deuxième étant une surveillance et une réponse en continue aux tentatives réelles d’authentification.</p>
<p>Ci-après un schéma récapitulatif simplifié:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739965426905/f73668e4-4917-4a37-893d-65129f55583d.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-conclusion"><strong>CONCLUSION</strong></h2>
<p>Avec l'adoption croissante des environnements multiclouds et SaaS, les équipes de sécurité rencontrent des défis pour maintenir la visibilité et le contrôle sur leur paysage d'identités. Les solutions ISPM et ITDR ont pour objet d’une part de diminuer la surface d'attaque en détectant les vulnérabilités potentielles liées aux identités, et d’autre part détecter les menaces effectives pour une remédiation rapide. En combinant ces deux approches, les organisations peuvent renforcer leur posture de sécurité globale et se protéger plus efficacement encore contre les menaces basées sur les identités.</p>
<p>De manière plus générale, Okta prenant une place de plus en plus centrale dans le SI de nombreuses organisations, l’idée d’aider ses clients à Monitorer, Surveiller, Piloter leurs identités et plus généralement réduire toute exposition au risque d’accès frauduleux est clairement une direction attendue par le marché.</p>
<p>Il y avait déjà « Okta ThreatInsight », et dorénavant, les clients d’Okta disposent de deux armes supplémentaires : <strong>ISPM</strong> et <strong>ITDR</strong>.</p>
]]></content:encoded></item><item><title><![CDATA[Understand Docker layers by example : RUN instructions Impact]]></title><description><![CDATA[I recently discussed with several people about how to build a Container and, more specifically, why it's important to minimize the usage of RUN instructions in a Dockerfile.
In this article, we will explore together the impact of unnecessarily multip...]]></description><link>https://blog.pointbase.fr/understand-docker-layers-by-example-run-instructions-impact</link><guid isPermaLink="true">https://blog.pointbase.fr/understand-docker-layers-by-example-run-instructions-impact</guid><category><![CDATA[Docker]]></category><category><![CDATA[docker images]]></category><category><![CDATA[cloud native]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[vincent ledan]]></dc:creator><pubDate>Tue, 10 Dec 2024 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p>I recently discussed with several people about how to build a Container and, more specifically, why it's important to minimize the usage of RUN instructions in a Dockerfile.</p>
<p>In this article, we will explore together the impact of unnecessarily multiplying multiple RUN instructions, as well as how to inspect the different layers of your images.</p>
<h2 id="heading-dockerfile">Dockerfile</h2>
<p>We will take the simplest possible Dockerfile for this article and compare two configurations:</p>
<p>A simple Dockerfile with only one RUN instruction: Dockerfile.1run</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Utilisation d'une image de base</span>
FROM ubuntu:latest
<span class="hljs-comment"># Create and delete secret file </span>
RUN <span class="hljs-built_in">echo</span> <span class="hljs-string">"secret_content"</span> &gt; /AAA &amp;&amp; rm /AAA
</code></pre>
<p>and another with 2 RUN instructions: Dockerfile.2run.</p>
<pre><code class="lang-bash">FROM ubuntu:latest
<span class="hljs-comment"># Create and delete secret file </span>
RUN <span class="hljs-built_in">echo</span> <span class="hljs-string">"secret_content"</span> &gt; /AAA 
RUN rm /AAA
</code></pre>
<p>The result may seem exactly the same but not really.</p>
<p>Each time you put a RUN instruction, Docker will create a new layer in the image with the state of the file system for each layer, which can sometimes pose a risk if it is also combined with other bad practices.</p>
<p>Let's look at this together and build the 2 images:</p>
<pre><code class="lang-bash">docker build -t 1run -f Dockerfile.1run 
docker build -t 2run -f Dockerfile.2run
</code></pre>
<p>Now let's analyze the image containing 2 instructions with the dive tool.</p>
<pre><code class="lang-bash">dive 2run
</code></pre>
<p>Surprisingly, we have 3 layers in this image:</p>
<ul>
<li><p><strong>1 for the base image</strong></p>
</li>
<li><p><strong>1 for our RUN instruction that creates the file</strong></p>
</li>
<li><p><strong>1 for our RUN instruction that deletes the file</strong></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702370273325/9d5ead8c-7980-41b0-bfa3-466c1d22e4f8.png" alt /></p>
<p>On the right, we can observe that the file is present in this layer.</p>
<p>Let's see how we can manage to retrieve it.</p>
<h2 id="heading-retrieve-files-from-docker-layers">Retrieve files from docker layers</h2>
<p>We have kept aside the ID of the layer, which is found in the layer details section.</p>
<p>Thanks to the docker command, we have the ability to easily extract the file system of the image.</p>
<pre><code class="lang-bash">docker save 2run -o test.tar
tar -xvf test.tar 

$ tar -xvf test.tar 

33570c3886dd27db6e7b8bd88205951f82a6a8048fd9b9292c5f556180dc894e/
33570c3886dd27db6e7b8bd88205951f82a6a8048fd9b9292c5f556180dc894e/VERSION
33570c3886dd27db6e7b8bd88205951f82a6a8048fd9b9292c5f556180dc894e/json
33570c3886dd27db6e7b8bd88205951f82a6a8048fd9b9292c5f556180dc894e/layer.tar
5a00f72ab3686152f0cf5067e06ff9937877cf31138ef4b8749a184c46b09898/
5a00f72ab3686152f0cf5067e06ff9937877cf31138ef4b8749a184c46b09898/VERSION
5a00f72ab3686152f0cf5067e06ff9937877cf31138ef4b8749a184c46b09898/json
5a00f72ab3686152f0cf5067e06ff9937877cf31138ef4b8749a184c46b09898/layer.tar
a23855d9376693f12ed1a1e68dd307dfd384615e4b1860a87978c5f9a7969120.json
d10815363623202ac07b49763f180d45a6941ef6a0ea905a92a7ddfa6bb45422/
d10815363623202ac07b49763f180d45a6941ef6a0ea905a92a7ddfa6bb45422/VERSION
d10815363623202ac07b49763f180d45a6941ef6a0ea905a92a7ddfa6bb45422/json
d10815363623202ac07b49763f180d45a6941ef6a0ea905a92a7ddfa6bb45422/layer.tar
manifest.json
repositories
</code></pre>
<p>During the <code>docker save</code> command, docker will extract all the layers of the image and create a .tar file for each layer.</p>
<p>All that's left is to extract the right layer.</p>
<p>In our case, the ID is:</p>
<p><code>d10815363623202ac07b49763f180d45a6941ef6a0ea905a92a7ddfa6bb45422</code></p>
<pre><code class="lang-bash">$ <span class="hljs-built_in">cd</span> d10815363623202ac07b49763f180d45a6941ef6a0ea905a92a7ddfa6bb45422/
$ ls 
json  layer.tar  VERSION
$ tar -xvf layer.tar 
AAA
$ cat AAA 
secret_content
</code></pre>
<p>Nous avons pu retrouver le contenu du fichier AAA.</p>
<h2 id="heading-reduce-numbers-of-run-instructions">Reduce numbers of RUN instructions</h2>
<p>Let's test our image with a single instruction combining the two instructions.</p>
<pre><code class="lang-bash">dive 1run
</code></pre>
<p>We can see on the left 2 layers:</p>
<ul>
<li><p>1 for the base image</p>
</li>
<li><p>1 for our RUN instruction (create + delete)</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702370057239/d0412ec8-0384-40e8-a476-b3d303264a2d.png" alt class="image--center mx-auto" /></p>
<p>Let's follow the same process with the ID corresponding to the ID of the layer of our RUN instruction <code>cf388386fad4ed6625a7eb438b9bdd915ab52e7be0d0a76a97f1cb4aa0ec40a5</code>:</p>
<pre><code class="lang-bash">docker save 1run -o test.tar 
tar -xvf test.tar 
<span class="hljs-built_in">cd</span> cf388386fad4ed6625a7eb438b9bdd915ab52e7be0d0a76a97f1cb4aa0ec40a5
$ <span class="hljs-built_in">cd</span> cf388386fad4ed6625a7eb438b9bdd915ab52e7be0d0a76a97f1cb4aa0ec40a5
$ ls 
json  layer.tar  VERSION
$ tar -xvf layer.tar
$ ls 
json  layer.tar  VERSION
</code></pre>
<p>It is not possible to find this file in this image.</p>
<h2 id="heading-advice">Advice</h2>
<p>Minimizing the number of RUN instructions in a Dockerfile is crucial for reducing the size of the final image, improving build and deployment performance, and enhancing security by avoiding the creation of unnecessary layers that might contain sensitive or redundant data. A best practice is to combine related commands into a single RUN instruction, thus reducing the number of layers and optimizing the image's efficiency.</p>
]]></content:encoded></item><item><title><![CDATA[DevOps et DevSecOps pour les non-informaticiens comme moi!]]></title><description><![CDATA[Préambule
Pour ceux d'entre nous qui entendent de plus en plus les termes Transformation Digitale, API, DevOps, Cloud Native, CI/CD, Repo, Containers, Kuberteness, SAST, SCA, DAST, CNAPP, ZeroTrust, CNCF, j'en passe et des meilleurs, et qui ne compre...]]></description><link>https://blog.pointbase.fr/devops-et-devsecops-pour-les-non-informaticiens-comme-moi</link><guid isPermaLink="true">https://blog.pointbase.fr/devops-et-devsecops-pour-les-non-informaticiens-comme-moi</guid><dc:creator><![CDATA[Nicolas Petroussenko]]></dc:creator><pubDate>Mon, 09 Dec 2024 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702046832980/8a2e3df2-927d-4cfd-a19d-5a7eff587b6d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-preambule">Préambule</h2>
<p>Pour ceux d'entre nous qui entendent de plus en plus les termes Transformation Digitale, API, DevOps, Cloud Native, CI/CD, Repo, Containers, Kuberteness, SAST, SCA, DAST, CNAPP, ZeroTrust, CNCF, j'en passe et des meilleurs, et qui ne comprennent pas toujours de quoi on parle, cet article a pour objectif de démythifier un peu tous ces termes jargoneux pour essayer de comprendre - de façon non technique - les raisons d'un tel engouement.<br />Nous commencerons par un peu d'histoire, pour mieux comprendre notre présent et essayer d'anticiper l'avenir, sans pour autant devenir nous-mêmes des informaticiens.</p>
<h2 id="heading-introduction">Introduction</h2>
<p>Quand on se promène dans les couloirs d'une entreprise (même pas besoin d'être en présence de développeurs), ou qu'on participe à une visioconférence en ligne, on entend souvent les phrases un peu absonces du genre: "C'est prévu dans notre plan de transformation digitale", "DevOps, c'est fait pour les entreprises Cloud Native et Agiles", ou encore "You Build it, You Run it", voire même "il faut qu'on Shifte Left notre approche".</p>
<p>On constate par ailleurs que toute personne en lien de près ou de loin avec l'informatique est devenue un XXXX_OPS (devops engineer, secops leader, devsecops architect, etctera....). Même les gens du marketing s'y mettent. Si vous ne me croyez pas, consultez les profils sur Linkedin, de moins en moins de Digital Marketing Specialists et de plus en plus de MarketingOps Specialists! Incroyable!</p>
<p>Que s'est-il donc passé? Et en quoi ça change la donne?</p>
<h2 id="heading-le-cloud-comme-genese">Le cloud comme génèse</h2>
<p>Il y a une vingtaine d'années (+ ou -), le Cloud a débarqué dans nos vies privées et professionnelles. Aujourd'hui, tout est dans le Cloud! Même un bon vieux Datacenter d'une banque avec ses bons vieux Mainframes est devenu un Cloud Privé! On est même actuellement à l'ère du MultiClouds hybride (la classe)!</p>
<p>Grâce à la virtualisation (et 2 ou 3 autres trucs), on a pu allouer des ressources informatiques à des développeurs (au début de la CPU/RAM/Stockage/Network) en quelques cliques seulement. Et ça franchement, c'était vraiment cool car jusqu'alors les développeurs devaient faire une demande au service informatique et au bout de plusieurs semaines (dans le meilleur des cas) on leur disait "le serveur (physique) est livré"... ce n'était pas fini pour autant car il fallait encore passer pas mal d'heures à configurer cette machine, la connecter au réseau, et donner les bons droits d'accès!</p>
<p>Autrement dit, d'un seul coup, les développeurs ont eu accès à de la ressource informatique d'infrastructure en quelques secondes, et ils/elles pouvaient la reconfigurer en quelques secondes également. Pour un développeur, c'était un pas de géant!</p>
<p>Mais jusque-là, cette petite révolution ne concernait que les services informatiques encore divisés en 4 grands pôles bien silotés qu'on appelait "Developpement, Test, Intégration, Production", et les projets informatiques continuaient de suivre des cycles infernaux dits de "Waterfall" ou "cycle en V", avec ces 8 phases incontourbables:</p>
<p>1- on décrit notre besoin<br />2- on spécifie fonctionnellement la solution<br />3- on en fait des spécifications techniques adossées à un joli schéma d'architecture voire d'urbanisme<br />4- on code/développe<br />5- on teste techniquement et fonctionnellement<br />6- on prend un sous-groupe d'utilisateurs pour avoir leur retour d'expérience et on se fait matraquer la tête car on a rien compris à leur besoin et que ça ne marche pas comme ça devrait<br />7- on recommence...<br />8-...et au bout d'un certain temps, après avoir refait plusieurs petits tours de manège dans ce "cycle en V" puis finalement passé avec plus ou moins de succcès les fourches caudines de l'intégration, et celles du service de sécurité du SI, on met en production...Alléluhia!</p>
<p>Certains se sont dits, "ça ne peut pas durer!"...alors on a inventé les méthodes agiles...c'était mieux, mais ça prenait encore pas mal de temps car on sortait d'une approche monolithique au profit d'une approche itérative plus courte et efficace. Pour autant, ça ne réglait pas tous les problèmes puisqu'on butait encore sur le temps de mise en production. L'infra allait plus vite, le développement aussi, mais pas tellement la capacité à "releaser" de nouvelles applications beaucoup plus vite, car les environnements de Dev, Test, Intégration, Prod restaient encore bien séparés et il y avait toujours des différences - souvent importantes - entre ces environnements. Du coup, on avait des phénomènes du type “ça marche bien en intégration mais pas en pré-prod”</p>
<p>Et puis, il y a moins de 15 ans, avec l'essor d'Internet comme notre nouveau bureau personnel et professionnel, tout le monde a commencé à faire de la Transformation Digitale. C'est peut-être une des expressions encore aujourd'hui les plus utilisées dans les entreprises.</p>
<p>Pour soutenir cette transformation, les départements informatiques ont été jugés bien trop lents et trop chers, et les grands hyperscalers américians (AWS, GCP, AZURE) et d’autres éditeurs dits de SaaS/PaaS/IaaS, ont été jugés bien plus performants à tous points de vue. Aujourd’hui, c’est le règne du Cloud pour soutenir la transformation digitale ! C’est même le règne du Multi-Clouds!</p>
<h3 id="heading-au-fait-cest-quoi-exactement-la-transformation-digitale">Au fait, c'est quoi exactement la transformation digitale?</h3>
<p>L'idée est super simple et l'objectif - comme souvent - se mesure en $.</p>
<p>Jusqu'à la fin des années 1990, presque tout le business d'une entreprise reposait sur des relations physiques avec son ecosystème. La vente se faisait essentiellement en magasin pour les particuliers, des commerciaux se déplaçaient chez leurs clients professionnels pour leur présenter puis vendre leurs produits et services, les logiciels dont on avait de plus en plus besoin dans nos processus métiers étaient installés dans nos datacenters en propre (on-premise). Certes, il y avait déjà les premiers magasins en ligne tels Amazon, PriceMinister, CDiscount et quelques autres commençaient à faire parler d'eux mais les grandes banques, assurances, les retailers, les CPG, les telco, les industriels, et surtout les professionnels de plus en plus nombreux de l'informatique ne parlaient pas de transformation digitale ni de Cloud. La première fois qu'on a pu consulter ses comptes bancaires en ligne sur Internet remonte à 1995 (banque directe), et presque toutes les banques proposaient ce service dès l'an 2000! Pourtant, les banques ont été les plus précurseurs sur le sujet, ce qui nous rappelle à quel point tout ceci est encore assez récent!</p>
<p>Beaucoup ont laissé passer le train de l'internet, puis de l'internet mobile. Et tout le monde, quelque soit son métier, s'est réveillé en même temps, avec le même mot d'ordre "si l'on ne fait rien, on va se faire ubériser par des nouveaux entrants, puis on va disparaître". C'est la célèbre phrase prononcée par Maurice Levy, patron de Publicis, qui expliquait lors d'un entretien "Tout le monde a peur de se faire ubériser".</p>
<p>La transformation digitale et son déferlement numérique étaient nés et avec eux des investissement massifs dans tous les domaines d'activités pour transformer l'entreprise en "Digital Company" afin d'exploiter les opportunités infinies qu'offrait Internet.</p>
<p>Ainsi, le Cloud est devenu la règle et avec lui, de nouvelles compétences en tous genres étaient requises. Un exemple: les API (vous savez le "bout" de code réutilisable pour permettre à une application de s'exposer à d'autres applications). En effet, il fallait bien trouver un moyen (sur Internet) de connecter des applications internes et externes avec les autres applications et services utilisés, sachant que tout ce petit beau monde n'avait pas été conçu pour discuter ensemble. Et puis, les API, c'est génial pour écrire un petit service informatique qu'on peut réutiliser autant de fois qu'on veut dans de plus gros services informatiques. Oui, mais, pour mettre en place des API SOAP puis REST (et maintenant Graph QL), il était nécessaire de réécrire un bout des applications existantes pour les "APIser" et pour cela il fallait encore plus de développeurs.</p>
<p>Bon, à ce stade, les bases étaient posées, Devops n'existait pas encore mais avec le Cloud son avènement devenait inéluctable !</p>
<h2 id="heading-la-nouvelle-mentalite-fast-amp-furious">La nouvelle mentalité "Fast &amp; Furious"</h2>
<p>On aurait pu en rester là, mais nous sommes alors entrés dans l'ère des réseaux sociaux, où tout va vite, beaucoup plus vite. A l’instar de l’information (une actualité chasse l’autre), une application chasse l’autre. C’est une course contre la montre pour développer et produire des services (presque toujours web) toujours plus rapidement, en continu, avec l’idée que - dans un monde digitalisé et pressé - la vitesse (le Time To Market pour les initiés) est devenue le critère absolu.</p>
<p>Il fallait donc trouver un moyen d’accélérer encore. Et c’est donc ça <strong>DevOps, un ensemble de méthodes, pratiques et outils pour développer et produire des services informatiques très vite et en continu grâce à une automisation toujours plus grande.</strong></p>
<p>Pour cela, il fallait que les développeurs puissent presque tout faire tout seul, et comme ce sont des développeurs, il fallait que tout soit sous forme de code, même la création des infrastructures sous-jacentes à l'exécution du code applicatif métier. On est entré dans l’ère du « You Build it, You Run it ». C’est le « Shift Left » accompagné de son automatisation la plus aboutie (Pipelines CI/CD). Le développeur peut tout faire tout seul. Adieu, les silo Dev/Test/Intégration/Production, vous n'êtes plus adaptés à notre Time-to-Market!</p>
<p>Ainsi, il fallait définitivement casser les silos Développement/Production.</p>
<p>On a tous vu cette magnifique illustration de DevOps. Une boucle qui automatise le cycle de développement logiciels en traversant toutes les étapes de création, tests, intégration, déploiement et pilotage d’applications</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701948510654/e665bba1-c93c-4419-b850-924dfb7aad78.png" alt class="image--center mx-auto" /></p>
<p>En général, quand on utilise le symbole de l’infini (le fameux lemniscate), j’ai toujours le sentiment qu’on me « vend » un truc automatisé de bout en bout, un peu comme une chaîne de fabrication industrielle parfaitement huilée avec un minimum d’interventions humaines. Ca a l'air magique !</p>
<p>En réalité, ce n’est pas si simple (il fallait s’y attendre) et pas magique du tout !</p>
<p>Prenons, par exemple, le sujet de la sécurité dont nous n'avons pas encore parlé, et dont tout le monde comprend qu’il est essentiel compte tenu du contexte réglementaire croissant et plus largement de l’explosion de cybermenaces en tous genres sur Internet.</p>
<h2 id="heading-donc-la-securite-en-question">Donc, la sécurité en question…</h2>
<p>Jusqu’à alors, on avait un(e) RSSI (responsable de la sécurité des systèmes d’information) qui – dans une approche souvent top down, un peu autoritaire mais très salutaire – essayait, avec ses équipes, d’imposer des bonnes pratiques aussi bien au niveau de l’infra, du code, de l’accès à toutes ces ressources ou encore de la nature des communications permises entre les services (réseau). Il/Elle était souvent perçu(e) comme l’empêcheur de tourner en rond, le gardien du temple qui met des bâtons dans les roues de ses petits collègues notamment les développeurs. C’était déjà assez compliqué comme cela, mais comme les équipes travaillaient en silos, il y avait encore moyen d’imposer des règles d’hygiène élémentaires de sécurité, d'autant que les COMEX avaient commencé à comprendre que la sécurité était un vrai sujet sérieux. Quand un développeur demandait - à travers un catalogue de services - un serveur (souvent une machine virtuelle), avec une version spécifique d’un système d’exploitation, et une base de données quelconque, il/elle ouvrait un ticket et sa demande passait par les fourches caudines des équipes d’infrastructure. Ce qui était livré – souvent de manière automatique et instantanée - incluait des petits programmes appelés agents dont la majorité permettait de forcer ou a minima surveiller les processus qui s’exécutaient sur le serveur, les flux de communication, etcetera. Du point de vue de la sécurité, c’était encore gérable.</p>
<p>On a compris que grâce à DevOps, les développeurs deviennent les maîtres du royaume de l’IT, puisqu’ils sont maintenant en charge de toute la chaîne de développement jusqu’à la mise en production.</p>
<p>Pour bien comprendre ce changement de paradigme, j’ai récupéré une illustration réalisée par la société <strong>Snyk</strong>, éditeur de logiciels bien connu des spécialistes dits de sécurité des applications cloud</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1701944903386/080a5b85-57b9-49b2-b1f5-70b5206e110d.png" alt class="image--center mx-auto" /></p>
<p>Cette image illustre assez bien ce changement. Dans l’ère du Cloud et du DevOps, qu’on appelle aussi <strong>Cloud Native</strong>, on comprend que <strong>dorénavant les décisions de sécurité appartiennent d'abord aux développeurs !</strong></p>
<p>Il faut donc fournir aux développeurs (dont on rappelle que la principale préoccupation est de livrer du code de qualité le plus vite posssible) un ensemble de méthodes et outils pour leur permettre de gérer seuls la sécurité du tout. Il est rare qu’un développeur ne soit pas conscient des enjeux sécuritaires, mais il est encore plus rare qu'il soit un spécialiste de la sécurité du SI.</p>
<p>Donc, on reprend....la sécurité doit être embarquée dès les phases en amont de code/développement (le fameux <strong>shift left</strong>).</p>
<p>On ne rentrera pas dans le détail de ces solutions ici, mais sachez que les outils et méthodes sécuritaires utilisés auparavant sont devenus largement obsolètes. Cela a donné naissance à une série de solutions logicielles qu’on appelle <strong>SCA, SAST, DAST, CNAPP,</strong> et encore beaucoup d’autres acronymes qui rentrent tous dans la grande famille de l'« <strong>Application Security Solutions</strong> », la sécurité des applications cloud, et dont l’objectif est de sécuriser le code, ses dépendances et bien entendu son exécution dans les fameux <strong>containers</strong> (Docker étant le plus connu) eux-mêmes orchestrés par le non moins fameux <strong>Kubernetes,</strong> sans qui rien n’est possible.</p>
<p>Si on devait résumer, il faut tout protéger mais différemment car tout est devenu CODE, à la main et sous la responsabilité du développeur. Aujourd’hui, le déploiement d’une infrastructure et de ses configurations se fait de manière automatisée par des lignes de code (yaml par exemple), avec plusieurs solutions pour y parvenir, même si les plus utilisées restent <strong>Terraform et Ansible</strong>. C’est le fameux <strong>Infrastructure as code.</strong></p>
<p>On peut - pour préparer mon prochain article - citer quelques solutions de sécurité devops (DevSecOps) qui ont pignon sur rue : Sysdig, Wiz, AccuKnox, Prisma Cloud, Snyk ou encore Veracode.</p>
<p>Rassurez-vous, je n'en dirai pas plus dans cet article destiné aux non-informaticiens, mais pour ceux que cela intéresse, je vais donc bientôt écrire un article un chouïa plus technique sur la myriade de solutions qui ont vu le jour autour de DevOps et DevSecOps.</p>
<p>A ce stade, certains d’entre vous - déjà un peu au fait du sujet - s’interrogeront sur l’absence d’acteurs majeurs dans cet article tels GitLab ou GitHub.</p>
<p>Ces derniers sont fondamentaux dans la chaîne DevOps et proposent des options de sécurité plus ou moins intégrées. En réalité, ils sont d’abord utilisés comme des Repositories, les <strong>fameux REPO</strong>, là où les développeurs déposent leurs codes, et toutes les sous-branches (un peu comme un arbre de versions de code). Et c’est au niveau du REPO que la sécurité commence. Il y a d’ailleurs 5 briques fondamentales de code à sécuriser : <strong>le code du développeur</strong>, <strong>le code open source</strong> <strong>et ses dépendances</strong> (souvent plus de 50% du code utilisé par les développeurs provient de codes sources libres de droits), <strong>les containers &amp; l’orchestrateur,</strong> et enfin <strong>l’infrastructure as code, et le Pipeline CI/CD (qui a tous les droits ou presque)</strong></p>
<p>Donc, tout démarre dans le REPO et tout recommence dans le REPO, y compris la sécurité... il est donc très important que ces derniers soient correctement protégés ! La presse spécialisée se fait régulièrement l'écho de codes sources subtilisés dans des REPO d’entreprise, car la gestion des accès est souvent très largement insuffisante.</p>
<p><strong>Le REPO c’est le temple, c’est sacré ! On ne doit pas pouvoir rentrer n'importe comment dans un temple ! Il faut montrer patte blanche.</strong></p>
<h1 id="heading-conclusion"><strong>Conclusion</strong></h1>
<p>J’espère que ce petit tour d’horizon non technique, et très « high level » (comme on dit), permettra à certains de mieux comprendre les changements de paradigme profonds en cours au sein de l’informatique et plus largement au sein des entreprises. Il est à peine exagéré de dire que toutes les entreprises deviennent des entreprises digitales, dont la croissance, l’avenir et peut-être même la survie dépendent de plus en plus de leur capacité à délivrer de nouveaux services rapidement. DEVOPS, CLOUD SECURITY, et CLOUD NATIVE sont des termes que vous n’avez pas fini d’entendre et avec eux leur cortège de solutions en tous genres pour arriver à une seule destination : « You build it, You run it, Securely ».</p>
<p>A titre personnel, n’étant pas informaticien d’origine mais baignant dans le monde informatique depuis (trop) longtemps, il m’a fallu du temps pour comprendre ces sujets, et surtout comprendre d’où ils viennent et ainsi mieux anticiper ce qui arrive !</p>
<p>J'espère que cette lecture aura su conjuguer l'utile à l'agréable.</p>
<p>Nicolas Petroussenko</p>
]]></content:encoded></item><item><title><![CDATA[Comparatif des solutions SASE/ZTNA]]></title><description><![CDATA[Les solutions SASE (Secure Access Service Edge) et ZTNA (Zero Trust Network Access) sont de plus en plusx populaires pour la sécurisation des réseaux d'entreprise dans un monde où les employés sont de plus en plus mobiles et où le cloud prend une pla...]]></description><link>https://blog.pointbase.fr/comparatif-des-solutions-saseztna</link><guid isPermaLink="true">https://blog.pointbase.fr/comparatif-des-solutions-saseztna</guid><category><![CDATA[SASE]]></category><category><![CDATA[ztna]]></category><category><![CDATA[wan]]></category><dc:creator><![CDATA[Nicolas Petroussenko]]></dc:creator><pubDate>Sat, 07 Dec 2024 23:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730827623883/baa06a8d-4641-47e5-ae11-07546a3fd714.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Les solutions SASE (Secure Access Service Edge) et ZTNA (Zero Trust Network Access) sont de plus en plusx populaires pour la sécurisation des réseaux d'entreprise dans un monde où les employés sont de plus en plus mobiles et où le cloud prend une place centrale. S’il existe encore des réseaux Voici un comparatif des principales solutions SASE et ZTNA disponibles sur le marché, incluant des leaders comme Zscaler, Cisco, Palo Alto Networks, Cloudflare, Netskope, Cato Networks ou encore des solutions certainement un peu moins connues telles Perimeter81.</p>
<p>Disclamer: Bien entendu, ce comparatif est le fruit de notre analyse, et repose sur les éléments en notre possession. Il se peut qu’il soit parfois incomplet voire incorrect. Il a pour seul objectif de partager un point de vue à la suite d’une analyse et de tests réalisés sur ces solutions.</p>
<h3 id="heading-1-zscaler">1. <strong>Zscaler</strong></h3>
<ul>
<li><p><strong>SASE</strong> : Zscaler propose une plateforme complète de SASE avec Zscaler Internet Access (ZIA) et Zscaler Private Access (ZPA) pour les applications internes.</p>
</li>
<li><p><strong>ZTNA</strong> : Zscaler utilise ZTNA pour contrôler l'accès aux applications, en passant par un cloud privé pour sécuriser les connexions.</p>
</li>
<li><p><strong>Avantages</strong> :</p>
<ul>
<li><p>Réseau mondial de data centers offrant une faible latence.</p>
</li>
<li><p>Fortes capacités de sécurité (inspection SSL, protection contre les menaces).</p>
</li>
</ul>
</li>
<li><p><strong>Inconvénients</strong> :</p>
<ul>
<li><p>Tarification élevée pour les petites entreprises.</p>
</li>
<li><p>Complexité de configuration et de gestion.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-2-cisco-umbrella-et-duo">2. <strong>Cisco (Umbrella et Duo)</strong></h3>
<ul>
<li><p><strong>SASE</strong> : Cisco propose Cisco Umbrella pour les fonctionnalités de sécurité dans le cloud, combiné à Cisco SD-WAN pour la gestion du réseau.</p>
</li>
<li><p><strong>ZTNA</strong> : Cisco Duo permet une authentification multi-facteurs et des contrôles d’accès basés sur les appareils et utilisateurs.</p>
</li>
<li><p><strong>Avantages</strong> :</p>
<ul>
<li><p>Facilement intégrable avec les autres solutions Cisco.</p>
</li>
<li><p>Interface conviviale et rapports de sécurité détaillés.</p>
</li>
</ul>
</li>
<li><p><strong>Inconvénients</strong> :</p>
<ul>
<li><p>Cisco Umbrella peut être coûteux pour des réseaux très étendus.</p>
</li>
<li><p>Besoin de formation pour gérer efficacement les multiples composants.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-3-palo-alto-networks-prisma-access">3. <strong>Palo Alto Networks (Prisma Access)</strong></h3>
<ul>
<li><p><strong>SASE</strong> : Prisma Access de Palo Alto propose une solution SASE très intégrée avec des fonctions avancées de prévention des menaces et de gestion des identités.</p>
</li>
<li><p><strong>ZTNA</strong> : Leur approche ZTNA permet un accès granulaire basé sur les identités et les appareils.</p>
</li>
<li><p><strong>Avantages</strong> :</p>
<ul>
<li><p>Excellente visibilité sur les menaces et analytics.</p>
</li>
<li><p>Intégration avec le reste des solutions Palo Alto pour une sécurité renforcée.</p>
</li>
</ul>
</li>
<li><p><strong>Inconvénients</strong> :</p>
<ul>
<li><p>Complexité dans la mise en œuvre initiale.</p>
</li>
<li><p>Coût élevé pour des fonctionnalités avancées.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-4-netskope">4. <strong>Netskope</strong></h3>
<ul>
<li><p><strong>SASE</strong> : Netskope propose une architecture SASE bien développée, intégrant CASB (Cloud Access Security Broker), ZTNA, et des services de sécurité web.</p>
</li>
<li><p><strong>ZTNA</strong> : Son approche ZTNA est centrée sur l'inspection en temps réel des données et le contrôle des applications.</p>
</li>
<li><p><strong>Avantages</strong> :</p>
<ul>
<li><p>Optimisé pour les environnements multi-cloud et les applications SaaS.</p>
</li>
<li><p>Interface utilisateur intuitive et analytics puissants.</p>
</li>
</ul>
</li>
<li><p><strong>Inconvénients</strong> :</p>
<ul>
<li><p>Performance impactée pour certaines connexions à longue distance.</p>
</li>
<li><p>Intégrations limitées avec des produits de sécurité tiers.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-5-cloudflare-cloudflare-for-teams">5. <strong>Cloudflare (Cloudflare for Teams)</strong></h3>
<ul>
<li><p><strong>SASE</strong> : Cloudflare propose un modèle SASE via Cloudflare One, incluant un proxy réseau et un pare-feu de nouvelle génération.</p>
</li>
<li><p><strong>ZTNA</strong> : Cloudflare Access permet une approche ZTNA simplifiée pour sécuriser les applications sans nécessiter de VPN.</p>
</li>
<li><p><strong>Avantages</strong> :</p>
<ul>
<li><p>Très haute performance pour les utilisateurs à distance.</p>
</li>
<li><p>Solution simple à déployer pour les entreprises de toutes tailles.</p>
</li>
</ul>
</li>
<li><p><strong>Inconvénients</strong> :</p>
<ul>
<li><p>Moins de fonctionnalités avancées que certains concurrents.</p>
</li>
<li><p>Peut nécessiter des compléments pour des besoins très spécifiques en sécurité.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-6-cato-networks">6. <strong>Cato Networks</strong></h3>
<ul>
<li><p><strong>SASE</strong> : Cato Networks propose une plateforme SASE complète intégrant SD-WAN, sécurité réseau et accès cloud via un backbone privé mondial. <a target="_blank" href="https://www.catonetworks.com/sase/">Cato Networks</a></p>
</li>
<li><p><strong>ZTNA</strong> : Leur solution Universal ZTNA offre un contrôle d'accès basé sur l'identité et le contexte, appliqué de manière cohérente sur l'ensemble des environnements: <a target="_blank" href="https://www.catonetworks.com/platform/universal-zero-trust-network-access-ztna/">Cato Networks</a></p>
</li>
<li><p><strong>Avantages</strong> :</p>
<ul>
<li><p>Réseau privé mondial offrant une faible latence et une haute disponibilité.</p>
</li>
<li><p>Gestion centralisée avec une interface unifiée pour les politiques de sécurité et de réseau.</p>
</li>
<li><p>Évolutivité permettant de s'adapter aux besoins croissants des entreprises.</p>
</li>
</ul>
</li>
<li><p><strong>Inconvénients</strong> :</p>
<ul>
<li><p>Moins de reconnaissance de la marque par rapport à certains concurrents établis.</p>
</li>
<li><p>Peut nécessiter une période d'adaptation pour les équipes IT habituées à des solutions traditionnelles.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-7-perimeter-81">7. <strong>Perimeter 81</strong></h3>
<ul>
<li><p><strong>SASE</strong> : Perimeter 81 offre une plateforme SASE intégrée, combinant des fonctionnalités de réseau et sécurité en une solution cloud unique: <a target="_blank" href="https://www.perimeter81.com/sase">Perimeter 81</a> (nouvellement rebaptisée Harmony SASE depuis le rachat de la société par Check Point)</p>
</li>
<li><p><strong>ZTNA</strong> : La solution propose un accès réseau basé sur le modèle Zero Trust, accordant des permissions en fonction de l'identité de l'utilisateur et du contexte: <a target="_blank" href="https://www.perimeter81.com/zero-trust-network-access">Perimeter 81</a>. C’est donc un sérieux avantage quand on a déjà travaillé sur la gestion des identités et des accès avec un IdP.</p>
</li>
<li><p><strong>Avantages</strong> :</p>
<ul>
<li><p>Déploiement rapide, souvent en moins d'une heure.</p>
</li>
<li><p>Gestion centralisée avec une interface intuitive.</p>
</li>
<li><p>Intégration avec des fournisseurs d'identité tels qu'Okta, Azure AD et OneLogin.</p>
</li>
</ul>
</li>
<li><p><strong>Inconvénients</strong> :</p>
<ul>
<li><p>Certaines fonctionnalités avancées, comme la prévention des pertes de données (DLP), peuvent être moins développées.</p>
</li>
<li><p>Intégrations tierces moins nombreuses ou moins profondes que celles proposées par d'autres fournisseurs.</p>
</li>
</ul>
</li>
</ul>
<h1 id="heading-tableau-recapitulatif">Tableau récapitulatif</h1>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Editeur/Solutions</strong></td><td><strong>Fonctionnalités SASE</strong></td><td><strong>Fonctionnalités ZTNA</strong></td><td><strong>Avantages</strong></td><td><strong>Inconvénients</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Perimeter 81</td><td>Plateforme SASE complète</td><td>Accès basé sur l'identité et le contexte</td><td>Déploiement rapide, gestion centralisée</td><td>Pas adapté aux sociétés de plus de 5000 salariés (trop de Gateways à payer et maintenir)</td></tr>
<tr>
<td>Zscaler</td><td>ZIA, ZPA</td><td>Contrôle granulaire des accès</td><td>Réseau mondial, forte sécurité</td><td>Coût élevé, complexité de configuration</td></tr>
<tr>
<td>Cisco</td><td>Umbrella, SD-WAN</td><td>Duo pour authentification</td><td>Intégration Cisco, convivialité</td><td>Coût important pour grands réseaux, gestion multi-composants</td></tr>
<tr>
<td>Palo Alto</td><td>Prisma Access</td><td>Accès basé sur identités</td><td>Visibilité, intégration complète</td><td>Complexité d'implémentation, coût</td></tr>
<tr>
<td>Netskope</td><td>CASB, ZTNA, sécurité web</td><td>Inspection en temps réel</td><td>Multi-cloud optimisé, interface intuitive</td><td>Performances pour longues distances</td></tr>
<tr>
<td>Cloudflare</td><td>Cloudflare One</td><td>Cloudflare Access</td><td>Réseau Mondial, haute performance, facilité de déploiement</td><td>Moins de fonctionnalités avancées mais une roadmap ambitieuse</td></tr>
<tr>
<td>Perimeter81</td><td>Plateforme SASE complète</td><td>Accès basé sur l'identité et le contexte</td><td>Déploiement ultra-rapide, gestion centralisée, intégration native avec des fournisseurs d'identité</td><td>Fonctionnalités avancées limitées, intégrations tierces moins nombreuses</td></tr>
<tr>
<td>Cato Networks</td><td>Plateforme SASE complète intégrant SD-WAN, sécurité réseau et accès cloud</td><td>Universal ZTNA offrant un contrôle d'accès basé sur l'identité et le contexte</td><td>Réseau privé mondial offrant une faible latence, gestion centralisée, évolutivité</td><td>Moindre reconnaissance de la marque, période d'adaptation nécessaire</td></tr>
</tbody>
</table>
</div><p>L’équipe SASE/ZTNA Point Base (www.pointbase.fr)</p>
]]></content:encoded></item><item><title><![CDATA[Kubernetes Pod Eviction and Preemption: How do they work?]]></title><description><![CDATA[In Kubernetes best practices, implementing quotas and limits for each namespace addresses some of the cluster's activity overload issues.
As an interesting anecdote, one day I encountered the following problem: I couldn't enforce quotas or impose lim...]]></description><link>https://blog.pointbase.fr/kubernetes-pod-eviction-and-preemption-how-do-they-work</link><guid isPermaLink="true">https://blog.pointbase.fr/kubernetes-pod-eviction-and-preemption-how-do-they-work</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[SRE]]></category><category><![CDATA[cka]]></category><category><![CDATA[AWS]]></category><category><![CDATA[GCP]]></category><category><![CDATA[Azure]]></category><category><![CDATA[EKS]]></category><category><![CDATA[gke]]></category><dc:creator><![CDATA[vincent ledan]]></dc:creator><pubDate>Tue, 05 Dec 2023 11:03:37 GMT</pubDate><content:encoded><![CDATA[<p>In Kubernetes best practices, implementing quotas and limits for each namespace addresses some of the cluster's activity overload issues.</p>
<p>As an interesting anecdote, one day I encountered the following problem: I couldn't enforce quotas or impose limits, or anything of the sort in various namespaces for non-technical reasons.</p>
<p>So, I delved into the mechanics of pod scheduling and eviction to see how I could make certain pods more prioritized than others.</p>
<p>We will revisit together the logic used by Kubernetes when it comes to eviction (killing pods due to insufficient resources) or preemption of pods (starting pods) in order to improve your resilience.</p>
<h2 id="heading-kubernetes-pod-eviction">Kubernetes pod eviction</h2>
<p>When your cluster is under saturation, you can, of course, activate auto-scaling for your nodes and pods, but this isn't instantaneous, especially for nodes. This task can be more challenging in on-premises environments, for example.</p>
<p>When your cluster reaches saturation, Kubernetes must make decisions to ensure that priority pods are not evicted from nodes under pressure. If you see pods with a "evicted" status, this should pique your interest.</p>
<p>Kubernetes assigns a Quality of Service (QoS) to each pod based on their requests and limits:</p>
<p><strong><mark>Guaranteed</mark></strong>: This QoS is the safest and provides you with more assurance of not being evicted. Each pod must have a request equal to its limit for CPU and memory.</p>
<p><strong><mark>Burstable</mark></strong>: This QoS is assigned if you have at least one "request" for your pod.</p>
<p><strong><mark>BestEffort</mark></strong>: This QoS is the first to be evicted when the node is under pressure. If you don't use any limits or requests, this QoS will be assigned to your pod.</p>
<p>Understanding the importance of setting limits and requests for your workloads is essential to better anticipate their behavior during peak loads.</p>
<h3 id="heading-kubernetes-pod-preemption"><strong>Kubernetes pod Preemption</strong></h3>
<p>We've just seen what happens with pod eviction, meaning pods that are already running. To recap, Quality of Service (QoS) is solely intended to protect pods during eviction, not during scheduling. For example, if a pod fails and needs to be rescheduled when the cluster is at 100% capacity, what comes into play is what we call pod preemption.</p>
<p>In other words, it's a priority given to pods that Kubernetes considers during scheduling. By default, there are several PriorityClasses commonly used by system components:</p>
<pre><code class="lang-bash">$ kubectl get priorityclass
NAME                      VALUE        GLOBAL-DEFAULT   AGE
system-cluster-critical   2000000000   <span class="hljs-literal">false</span>            7m56s
system-node-critical      2000001000   <span class="hljs-literal">false</span>            7m56s
</code></pre>
<p>If we take a closer look at how this works on GKE (Google Kubernetes Engine)</p>
<pre><code class="lang-bash">kubectl get pods --all-namespaces -o=custom-columns=NAME:.metadata.name,PRIORITY_CLASS:.spec.priorityClassName --sort-by=<span class="hljs-string">'.metadata.creationTimestamp'</span> | column -t

NAME                                                 PRIORITY_CLASS
kube-dns-7d5998784c-kw98d                            system-cluster-critical
kube-dns-autoscaler-9f89698b6-shzj8                  system-cluster-critical
event-exporter-gke-857959888b-kwpwm                  &lt;none&gt;
konnectivity-agent-67c68ff74f-kwfhl                  system-cluster-critical
konnectivity-agent-autoscaler-bd45744cc-49bbf        system-cluster-critical
l7-default-backend-6dc845c45d-4jt95                  &lt;none&gt;
gke-metrics-agent-hj942                              system-node-critical
fluentbit-gke-qmmbl                                  system-node-critical
pdcsi-node-x5fbb                                     system-node-critical
pdcsi-node-6n2tl                                     system-node-critical
gke-metrics-agent-gxm2s                              system-node-critical
fluentbit-gke-4bp9n                                  system-node-critical
fluentbit-gke-pd4dh                                  system-node-critical
gke-metrics-agent-wpqft                              system-node-critical
pdcsi-node-k2z6v                                     system-node-critical
kube-proxy-gke-cluster-1-default-pool-aaab76fd-85qj  system-node-critical
konnectivity-agent-67c68ff74f-5bxbk                  system-cluster-critical
kube-dns-7d5998784c-9qfnm                            system-cluster-critical
konnectivity-agent-67c68ff74f-hj2b4                  system-cluster-critical
metrics-server-v0.5.2-6bf845b67f-gslvk               system-cluster-critical
kube-proxy-gke-cluster-1-default-pool-aaab76fd-p2tk  system-node-critical
kube-proxy-gke-cluster-1-default-pool-aaab76fd-7mzj  system-node-critical
</code></pre>
<p>We can see that all the pods except 2 have high PriorityClasses and can still be rescheduled even under pressure.</p>
<h3 id="heading-use-case-kyverno">Use case Kyverno</h3>
<p>Let's imagine that we want to install Kyverno. Here are the commands to install Kyverno, for example.</p>
<pre><code class="lang-bash">helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm install kyverno kyverno/kyverno -n kyverno --create-namespace --<span class="hljs-built_in">set</span> replicaCount=3
</code></pre>
<p>By default, pods don't have any PriorityClass, but I consider this application to be very important and it should always be up and running despite possible overload. We can see that Kubernetes doesn't assign any QoS Guarantee or PriorityClass.</p>
<pre><code class="lang-bash">vincn_ledan@cloudshell:~ (medium-article-377208)$ kubectl get pods -n kyverno -o custom-columns=<span class="hljs-string">"NAME:.metadata.name, QOS:.status.qosClass, REQUESTS:.spec.containers[*].resources.requests, LIMITS:.spec.containers[*].resources.limits, PRIORITY_CLASS:.spec.priorityClassName"</span>
NAME                                          QOS         REQUESTS                     LIMITS              PRIORITY_CLASS
kyverno-5f69449d46-9gcfc                     Burstable   map[cpu:100m memory:128Mi]   map[memory:384Mi]   &lt;none&gt;
kyverno-5f69449d46-c96w6                     Burstable   map[cpu:100m memory:128Mi]   map[memory:384Mi]   &lt;none&gt;
kyverno-5f69449d46-f8dgb                     Burstable   map[cpu:100m memory:128Mi]   map[memory:384Mi]   &lt;none&gt;
kyverno-cleanup-controller-8d8cbd588-8tlrh   Burstable   map[cpu:100m memory:64Mi]    map[memory:128Mi]   &lt;none&gt;
kyverno-cleanup-controller-8d8cbd588-gcl6b   Burstable   map[cpu:100m memory:64Mi]    map[memory:128Mi]   &lt;none&gt;
kyverno-cleanup-controller-8d8cbd588-ghtf8   Burstable   map[cpu:100m memory:64Mi]    map[memory:128Mi]   &lt;none&gt;
</code></pre>
<p>Now let's ensure that these pods are in the Guaranteed QoS class and also in a specific PriorityClass. We will assign the value 999999999, which is below the value of system PriorityClasses and just below the maximum value of 1 billion.</p>
<p>Let's create the priority.yaml file and apply it:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">scheduling.k8s.io/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">PriorityClass</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">high-priority-class</span>
<span class="hljs-attr">value:</span> <span class="hljs-number">999999999</span>
<span class="hljs-attr">globalDefault:</span> <span class="hljs-literal">false</span>
<span class="hljs-attr">description:</span> <span class="hljs-string">" high priority"</span>
</code></pre>
<p>Let's reinstall Kyverno with the correct parameters:</p>
<pre><code class="lang-bash">helm install kyverno kyverno/kyverno \
  --namespace kyverno \
  --create-namespace \
  --<span class="hljs-built_in">set</span> replicaCount=3 \
  --<span class="hljs-built_in">set</span> test.resources.limits.cpu=100m \
  --<span class="hljs-built_in">set</span> test.resources.limits.memory=128Mi \
  --<span class="hljs-built_in">set</span> test.resources.requests.cpu=100m \
  --<span class="hljs-built_in">set</span> test.resources.requests.memory=128Mi \
  --<span class="hljs-built_in">set</span> resources.requests.cpu=100m \
  --<span class="hljs-built_in">set</span> resources.requests.memory=128Mi \
  --<span class="hljs-built_in">set</span> resources.limits.cpu=100m \
  --<span class="hljs-built_in">set</span> resources.limits.memory=128Mi \
  --<span class="hljs-built_in">set</span> initResources.limits.memory=64Mi \
  --<span class="hljs-built_in">set</span> initResources.limits.cpu=10m \
  --<span class="hljs-built_in">set</span> initResources.requests.memory=64Mi \
  --<span class="hljs-built_in">set</span> initResources.requests.cpu=10m \
  --<span class="hljs-built_in">set</span> cleanupController.resources.limits.memory=64Mi \
  --<span class="hljs-built_in">set</span> cleanupController.resources.limits.cpu=100m \
  --<span class="hljs-built_in">set</span> cleanupController.resources.requests.memory=64Mi \
  --<span class="hljs-built_in">set</span> cleanupController.resources.requests.cpu=100m \
  --<span class="hljs-built_in">set</span> priorityClassName=high-priority-class
</code></pre>
<p>Now we can see that the pods have the correct QoS and the correct PriorityClass.</p>
<pre><code class="lang-bash">vincn_ledan@cloudshell:~ (medium-article)$ kubectl get pods -n kyverno -o custom-columns=<span class="hljs-string">"NAME:.metadata.name, QOS:.status.qosClass, REQUESTS:.spec.containers[*].resources.requests, LIMITS:.spec.containers[*].resources.limits, PRIORITY_CLASS:.spec.priorityClassName"</span>
NAME                                          QOS          REQUESTS                     LIMITS                       PRIORITY_CLASS
kyverno-6fd6db997c-ptc8n                     Guaranteed   map[cpu:100m memory:256Mi]   map[cpu:100m memory:256Mi]   high-priority-class
kyverno-6fd6db997c-q7hwj                     Guaranteed   map[cpu:100m memory:256Mi]   map[cpu:100m memory:256Mi]   high-priority-class
kyverno-6fd6db997c-zwj5m                     Guaranteed   map[cpu:100m memory:256Mi]   map[cpu:100m memory:256Mi]   high-priority-class
</code></pre>
<p>First, we are going to stress the cluster.</p>
<pre><code class="lang-bash">kubectl apply -f https://raw.githubusercontent.com/giantswarm/kube-stresscheck/master/examples/cluster.yaml
</code></pre>
<p>Then, deploy a simple nginx pod. It can be noticed that this pod cannot be scheduled because there are no resources available.</p>
<pre><code class="lang-bash">kubectl create deploy nginxtest --image=nginx
kubectl get pods 
default       nginxtest-699448454d-8kmpb                            0/1     Pending                  0             11s
</code></pre>
<p>Now, let's delete one of the Kyverno pods; this should allow the pod to be scheduled due to its high priority compared to the nginx pod.</p>
<pre><code class="lang-bash">kubectl delete pods kyverno-6fd6db997c-q7hwj -n kyverno --force
kubectl get pods -n kyverno
NAME                                         READY   STATUS                   RESTARTS   AGE
kyverno-6fd6db997c-ptc8n                     1/1     Running                  0          16m
kyverno-6fd6db997c-xc226                     1/1     Running                  0          9m32s
kyverno-6fd6db997c-zwj5m                     1/1     Running                  0          16m
</code></pre>
<h2 id="heading-advice">Advice</h2>
<p>It is important to be able to classify your applications in order to assign them the correct QoS and PriorityClass and better manage the cluster's behavior.</p>
]]></content:encoded></item><item><title><![CDATA[Guide d'intégration de l'authentification Okta à une application Angular]]></title><description><![CDATA[Présentation de Okta
Okta est une entreprise spécialisée dans la gestion de l'identité et de l'accès, offrant une gamme complète de solutions pour l'authentification, l'autorisation et la gestion des utilisateurs. Pour notre sujet d'aujourd'hui, nous...]]></description><link>https://blog.pointbase.fr/guide-dintegration-de-lauthentification-okta-a-une-application-angular</link><guid isPermaLink="true">https://blog.pointbase.fr/guide-dintegration-de-lauthentification-okta-a-une-application-angular</guid><category><![CDATA[okta]]></category><category><![CDATA[identity-management]]></category><category><![CDATA[Application Security]]></category><category><![CDATA[Angular]]></category><dc:creator><![CDATA[Aguibou Barry]]></dc:creator><pubDate>Thu, 19 Oct 2023 11:48:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1697228612322/d943f7a9-960d-4e30-82d6-6593df970347.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-presentation-de-okta">Présentation de Okta</h2>
<p>Okta est une entreprise spécialisée dans la gestion de l'identité et de l'accès, offrant une gamme complète de solutions pour l'authentification, l'autorisation et la gestion des utilisateurs. Pour notre sujet d'aujourd'hui, nous nous concentrerons sur la composante "authentification" d'Okta. Elle joue un rôle essentiel dans la sécurisation de l'accès à notre application Angular, offrant une solution robuste pour garantir la sécurité des utilisateurs.</p>
<h2 id="heading-configuration-et-integration-de-lauthentification-okta-a-angular"><strong>Configuration et Intégration de l'authentification Okta à Angular</strong></h2>
<h3 id="heading-i-configuration-de-notre-solution-dauthentification-sur-okta"><strong>I. Configuration de notre solution d’authentification sur Okta</strong></h3>
<p>Si vous ne disposez pas d'un compte Okta, vous devez créer un compte avec votre e-mail professionnel. Pour ce faire, rendez-vous sur le <a target="_blank" href="https://www.okta.com/"><strong>site web d'Okta</strong></a> et suivez les instructions pour créer un compte. Une fois connecté, cliquez sur le bouton "<strong>ADMINISTRATION</strong>", puis sur l'onglet "<strong>Applications</strong>", ensuite sur le sous-onglet "<strong>Applications</strong>", vous aurez une vue comme suit :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697445350052/3ff95f50-b734-4887-a6a4-880009a08a21.png" alt class="image--center mx-auto" /></p>
<p>Maintenant, nous allons créer une "<strong>App Integration</strong>" (intégration d'application) qui nous permettra de lier spécifiquement notre application Angular à la plateforme Okta. Pour ce faire, cliquez sur "<strong>Create App Integration</strong>", vous obtiendrez une vue comme celle-ci :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697288089421/7df181f9-56b8-4de9-bce0-5eaa225e5fa4.png" alt class="image--center mx-auto" /></p>
<p>Lors de cette étape, nous devons spécifier deux éléments essentiels : la "<strong>méthode d'authentification</strong>" (sign-in method) et le "<strong>type d'application</strong>" à intégrer. Nous choisissons OIDC (OpenID Connect) comme méthode d'authentification en raison de ses avantages, notamment l'authentification unique (Single Sign-On), la sécurité basée sur OAuth 2.0 et l'utilisation de JWT (JSON Web Tokens). Quant au "type d'application", nous optons pour "Single-Page Application" en raison de la nature d'Angular, qui est une application de type Single-Page Application.<br />Cliquez ensuite sur "Next".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697313373968/9e22b3fc-56fc-42bd-8d65-19bf76f7c904.png" alt class="image--center mx-auto" /></p>
<p>Sur cette page, nous avons saisi des informations dans les champs suivants :</p>
<ol>
<li><p><strong>App Integration Name</strong> : Il s'agit du nom de votre intégration d'application.</p>
</li>
<li><p><strong>Grant type</strong> : Ce champ permet de spécifier la méthode par laquelle une application peut obtenir un jeton d'accès pour interagir avec une API ou un service. Dans notre cas, nous allons utiliser le flux d'autorisation par code d'autorisation (Authorization Code), qui est considéré comme la méthode la plus sécurisée.</p>
</li>
<li><p><strong>Sign-in redirect URIs</strong> : Ici, vous devez indiquer les URL de redirection une fois que l'utilisateur a été authentifié sur Okta. Dans notre cas, nous avons configuré cette URL comme <a target="_blank" href="http://localhost:4200/login/callback">http://localhost:4200/login/callback</a>. Veuillez noter que nous avons utilisé le port par défaut d'Angular, mais si vous avez modifié le port par défaut d'Angular, assurez-vous de renseigner le port correct.</p>
</li>
<li><p><strong>Sign-out redirect URIs</strong> : Cette option est similaire à "Sign-in redirect URIs", mais elle concerne la déconnexion. Ici, nous avons renseigné <a target="_blank" href="http://localhost:4200/login">http://localhost:4200/login</a> pour rediriger l'utilisateur vers la page de connexion (chemin '/login') après sa déconnexion.</p>
</li>
<li><p><strong>Assignements</strong> : Dans ce champ, vous spécifiez les personnes autorisées à s'authentifier pour utiliser votre application. Dans notre cas, nous avons choisi "Limit access to selected groups" pour indiquer que seuls les utilisateurs du groupe que nous avons créé dans Okta seront autorisés à s'authentifier et à utiliser notre application. Cependant, vous pouvez choisir de spécifier les utilisateurs ou groupes ultérieurement.</p>
</li>
</ol>
<p>Il est essentiel de noter que ces informations sont cruciales pour configurer correctement votre intégration d'application et définir qui peut y accéder. Une fois enregistrées, vous aurez besoin des informations suivantes pour lier cette intégration à votre application Angular :</p>
<ul>
<li><p><strong>issuer</strong> : 'votre-domain/oauth2/default'</p>
</li>
<li><p><strong>clientId</strong> : 'votre identifiant client' (visible directement dans l'onglet général de l'intégration que vous venez de créer)</p>
</li>
<li><p><strong>redirectUri</strong> : 'URL' (l'URL que vous avez précédemment fournie pour le champ "Sign-in redirect URIs")</p>
</li>
<li><p><strong>postLogoutRedirectUri</strong> : 'URL' (l'URL que vous avez précédemment fournie pour le champ "Sign-out redirect URIs")</p>
</li>
</ul>
<p>Veuillez noter que pour trouver votre domaine, vous pouvez cliquer sur votre adresse e-mail en haut de la page, où vous verrez votre domaine, par exemple, "<a target="_blank" href="http://trial-3408718.okta.com">trial-###...###.okta.com</a>" (dans le cas d'un domaine d'essai).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697536186005/8185211b-3547-4b28-a9f4-f730d906b94a.png" alt class="image--center mx-auto" /></p>
<p>Après avoir pris note de ces informations essentielles, nous pouvons désormais passer à la deuxième étape : l'intégration dans notre application Angular</p>
<h3 id="heading-ii-integration-de-notre-solution-dauthentification-a-angular"><strong>II. Intégration de notre solution d'authentification à Angular</strong></h3>
<p>Assurez-vous d'avoir créé votre application Angular. Une fois cela fait, installez les packages suivants :</p>
<pre><code class="lang-bash">npm install @okta/okta-auth-js
</code></pre>
<pre><code class="lang-bash">npm install @okta/okta-angular
</code></pre>
<p>Ajoutez le code suivant à votre fichier /src/environments/environment.ts, en remplaçant les valeurs par celles que vous avez notées précédemment :</p>
<ul>
<li><pre><code class="lang-javascript">      <span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> environment = {
        <span class="hljs-attr">production</span>: <span class="hljs-literal">false</span>,
        <span class="hljs-attr">oktaAuth</span> :{
        <span class="hljs-attr">issuer</span>: <span class="hljs-string">'https://trial-34##....#718.okta.com/oauth2/default'</span>,
        <span class="hljs-attr">clientId</span>: <span class="hljs-string">'08rp####....###w697'</span>,
        <span class="hljs-attr">redirectUri</span>: <span class="hljs-string">'http://localhost:4200/login/callback'</span>,
        <span class="hljs-attr">postLogoutRedirectUri</span>: <span class="hljs-string">'http://localhost:4200/login'</span>,
        <span class="hljs-attr">devMode</span>: <span class="hljs-literal">true</span>,
        }
      };
</code></pre>
</li>
</ul>
<p>Note : <em>Nous avons ajouté "devMode: true" pour afficher dans la console l'objet retourné contenant les informations de l'utilisateur et le jeton. Cette option peut être utile si vous prévoyez de traiter ces informations, car elle permet de visualiser la structure de l'objet retourné</em>.</p>
<p>À présent, dans le fichier app.module.ts, nous allons importer la variable d'environnement et configurer le module OktaAuthModule.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { NgModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { BrowserModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/platform-browser'</span>;

<span class="hljs-keyword">import</span> { AppRoutingModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app-routing.module'</span>;
<span class="hljs-keyword">import</span> { AppComponent } <span class="hljs-keyword">from</span> <span class="hljs-string">'./app.component'</span>;
<span class="hljs-keyword">import</span> { OktaAuthModule, OKTA_CONFIG } <span class="hljs-keyword">from</span> <span class="hljs-string">'@okta/okta-angular'</span>; <span class="hljs-comment">// import OktaAuthModule</span>
<span class="hljs-keyword">import</span> { OktaAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">'@okta/okta-auth-js'</span>;
<span class="hljs-keyword">import</span> { HttpClientModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/common/http'</span>;
<span class="hljs-keyword">import</span> {environment} <span class="hljs-keyword">from</span> <span class="hljs-string">'../environments/environment'</span> <span class="hljs-comment">// import environment</span>


<span class="hljs-comment">// ici crée un objet de type OktaAuth, et on initialise avec </span>
<span class="hljs-comment">// les données que nous avont recuperé depuis Okta </span>
<span class="hljs-keyword">const</span> oktaAuth = <span class="hljs-keyword">new</span> OktaAuth(environment.oktaAuth); 

@NgModule({
  <span class="hljs-attr">declarations</span>: [
    AppComponent
  ],
  <span class="hljs-attr">imports</span>: [
    BrowserModule,
    AppRoutingModule,
    OktaAuthModule.forRoot({ oktaAuth }), <span class="hljs-comment">//ici on configure avec notre objet OktaAuth </span>
    HttpClientModule
  ],
  <span class="hljs-attr">providers</span>: [],
  <span class="hljs-attr">bootstrap</span>: [AppComponent]
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppModule</span> </span>{ }
</code></pre>
<p>NB : Assurez-vous que les informations que vous renseignez ici correspondent à celles fournies dans la configuration sur Okta précédemment.</p>
<p>Maintenant, nous allons mettre en place les fonctions de connexion et de déconnexion. Pour ce faire, j'ai ajouté trois composants : Home, Navbar et Login. Le composant Home contient la page d'accueil où l'utilisateur arrive une fois authentifié. Sur cette page, un bouton de déconnexion est placé dans la Navbar (qui apparaît sur la page Home) pour permettre la déconnexion et envoyer une demande de révocation du jeton d'authentification. Le composant Login contient le bouton d'authentification.</p>
<p>Afin de sécuriser les routes de notre application, nous avons utilisé des guards. Vous pouvez les générer en utilisant la commande suivante :</p>
<pre><code class="lang-bash">ng generate guard gurads/OktaAuth
</code></pre>
<p>Les codes d'implémentations de ces différents composants :</p>
<p><strong><em>navbar.component.html</em></strong></p>
<pre><code class="lang-javascript">&lt;nav <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"navbar navbar-expand-lg navbar-light bg-light"</span>&gt;
     <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>&gt;</span>Gui-App<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-toggler"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">data-toggle</span>=<span class="hljs-string">"collapse"</span> <span class="hljs-attr">data-target</span>=<span class="hljs-string">"#navbarNav"</span>
               <span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"navbarNav"</span> <span class="hljs-attr">aria-expanded</span>=<span class="hljs-string">"false"</span> <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Toggle navigation"</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-toggler-icon"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"collapse navbar-collapse"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"navbarNav"</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-nav"</span>&gt;</span>
               <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ng-container</span> *<span class="hljs-attr">ngIf</span>=<span class="hljs-string">"(isAuthenticated$ | async) === false"</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-sm btn-outline-primary ml-auto"</span> (<span class="hljs-attr">click</span>)=<span class="hljs-string">"signIn()"</span>&gt;</span> Sign in <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">ng-container</span>&gt;</span>


     <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/nav&gt;
</code></pre>
<p>navbar.component.ts</p>
<pre><code class="lang-javascript">
<span class="hljs-keyword">import</span> { DOCUMENT } <span class="hljs-keyword">from</span> <span class="hljs-string">"@angular/common"</span>;
<span class="hljs-keyword">import</span> { Component, Inject, OnInit } <span class="hljs-keyword">from</span> <span class="hljs-string">"@angular/core"</span>;
<span class="hljs-keyword">import</span> { Router } <span class="hljs-keyword">from</span> <span class="hljs-string">"@angular/router"</span>;
<span class="hljs-keyword">import</span> { OktaAuthStateService, OKTA_AUTH } <span class="hljs-keyword">from</span> <span class="hljs-string">"@okta/okta-angular"</span>;
<span class="hljs-keyword">import</span> { AuthState, OktaAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">"@okta/okta-auth-js"</span>;
<span class="hljs-keyword">import</span> { filter, map, Observable } <span class="hljs-keyword">from</span> <span class="hljs-string">"rxjs"</span>;

@Component({
  <span class="hljs-attr">selector</span>: <span class="hljs-string">'app-navbar'</span>,
  <span class="hljs-attr">templateUrl</span>: <span class="hljs-string">'./navbar.component.html'</span>,
  <span class="hljs-attr">styleUrls</span>: [<span class="hljs-string">'./navbar.component.css'</span>]
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NavbarComponent</span> <span class="hljs-title">implements</span> <span class="hljs-title">OnInit</span> </span>{
  public isAuthenticated$!: Observable&lt;boolean&gt;;
  <span class="hljs-keyword">constructor</span>(
    private _router: Router,
    private _oktaStateService: OktaAuthStateService,
    @Inject(OKTA_AUTH) private _oktaAuth: OktaAuth
  ) {}

  public ngOnInit(): <span class="hljs-keyword">void</span> {
    <span class="hljs-built_in">this</span>.isAuthenticated$ = <span class="hljs-built_in">this</span>._oktaStateService.authState$.pipe(
      filter(<span class="hljs-function">(<span class="hljs-params">s: AuthState</span>) =&gt;</span> !!s),
      map(<span class="hljs-function">(<span class="hljs-params">s: AuthState</span>) =&gt;</span> s.isAuthenticated ?? <span class="hljs-literal">false</span>)
    );
  }

  public <span class="hljs-keyword">async</span> signIn(): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-keyword">void</span>&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>._oktaAuth.signInWithRedirect();
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error during sign-in:"</span>, error);
    }
  }


}
</code></pre>
<p>home.component.html</p>
<pre><code class="lang-javascript">&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">""</span>&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">app-navbar</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">app-navbar</span>&gt;</span></span>
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"login-page"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"login-cover"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"login-content"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-primary"</span>&gt;</span>{{userName}} ({{userEmail}})<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span> Bienvenue dans votre espace securisé<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/div&gt;
</code></pre>
<p>home.component.ts</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { DOCUMENT } <span class="hljs-keyword">from</span> <span class="hljs-string">"@angular/common"</span>;
<span class="hljs-keyword">import</span> { Component, Inject, OnInit } <span class="hljs-keyword">from</span> <span class="hljs-string">"@angular/core"</span>;
<span class="hljs-keyword">import</span> { Router } <span class="hljs-keyword">from</span> <span class="hljs-string">"@angular/router"</span>;
<span class="hljs-keyword">import</span> { OktaAuthStateService, OKTA_AUTH } <span class="hljs-keyword">from</span> <span class="hljs-string">"@okta/okta-angular"</span>;
<span class="hljs-keyword">import</span> { AuthState, OktaAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">"@okta/okta-auth-js"</span>;
<span class="hljs-keyword">import</span> { filter, map, Observable } <span class="hljs-keyword">from</span> <span class="hljs-string">"rxjs"</span>;

@Component({
  <span class="hljs-attr">selector</span>: <span class="hljs-string">"app-home"</span>,
  <span class="hljs-attr">templateUrl</span>: <span class="hljs-string">"./home.component.html"</span>,
  <span class="hljs-attr">styleUrls</span>: [<span class="hljs-string">"./home.component.css"</span>],
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomeComponent</span> <span class="hljs-title">implements</span> <span class="hljs-title">OnInit</span> </span>{
  <span class="hljs-attr">userName</span>: string = <span class="hljs-string">""</span>;
  userEmail: string = <span class="hljs-string">""</span>;

  <span class="hljs-keyword">constructor</span>(
    private _router: Router,
    private _oktaStateService: OktaAuthStateService,
    @Inject(OKTA_AUTH) private _oktaAuth: OktaAuth,
    @Inject(DOCUMENT) private _document: Document
  ) {}

   ngOnInit(): <span class="hljs-keyword">void</span> {
    <span class="hljs-built_in">this</span>._oktaStateService.authState$
      .pipe(
        filter(<span class="hljs-function">(<span class="hljs-params">authState</span>) =&gt;</span> !!authState &amp;&amp; !!authState.isAuthenticated), <span class="hljs-comment">// Vérification de nullité</span>
        map(<span class="hljs-function">(<span class="hljs-params">authState</span>) =&gt;</span> authState?.idToken?.claims) <span class="hljs-comment">// Récupère les informations de l'utilisateur depuis le jeton</span>
      )
      .subscribe(<span class="hljs-function">(<span class="hljs-params">userClaims</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (userClaims) {
          <span class="hljs-comment">// Les informations de l'utilisateur, telles que le nom et le prénom, sont stockées dans les "claims" du jeton</span>
          <span class="hljs-built_in">this</span>.userName = <span class="hljs-string">`<span class="hljs-subst">${userClaims.name}</span>`</span>;
          <span class="hljs-built_in">this</span>.userEmail = <span class="hljs-string">`<span class="hljs-subst">${userClaims.email}</span>`</span>;
        }
      });
  }
}
</code></pre>
<p>login.component.html</p>
<pre><code class="lang-javascript">&lt;div <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"login-page"</span>&gt;
     <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"login-cover"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
     <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"login-content"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Bienvenue sur Gui-App<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Veuillez vous authentifier pour accéder à votre espace sécurisé.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"  btn btn-sm btn-outline-primary ml-auto"</span> (<span class="hljs-attr">click</span>)=<span class="hljs-string">"signIn()"</span>&gt;</span>S'authentifier<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
     <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/div&gt;
</code></pre>
<p>login.component.ts</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { DOCUMENT } <span class="hljs-keyword">from</span> <span class="hljs-string">"@angular/common"</span>;
<span class="hljs-keyword">import</span> { Component, Inject, OnInit } <span class="hljs-keyword">from</span> <span class="hljs-string">"@angular/core"</span>;
<span class="hljs-keyword">import</span> { Router } <span class="hljs-keyword">from</span> <span class="hljs-string">"@angular/router"</span>;
<span class="hljs-keyword">import</span> { OktaAuthStateService, OKTA_AUTH } <span class="hljs-keyword">from</span> <span class="hljs-string">"@okta/okta-angular"</span>;
<span class="hljs-keyword">import</span> { AuthState, OktaAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">"@okta/okta-auth-js"</span>;
<span class="hljs-keyword">import</span> { filter, map, Observable } <span class="hljs-keyword">from</span> <span class="hljs-string">"rxjs"</span>;

@Component({
  <span class="hljs-attr">selector</span>: <span class="hljs-string">'app-login'</span>,
  <span class="hljs-attr">templateUrl</span>: <span class="hljs-string">'./login.component.html'</span>,
  <span class="hljs-attr">styleUrls</span>: [<span class="hljs-string">'./login.component.css'</span>]
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginComponent</span> <span class="hljs-title">implements</span> <span class="hljs-title">OnInit</span> </span>{

  <span class="hljs-keyword">constructor</span>(
    private _router: Router,
    private _oktaStateService: OktaAuthStateService,
    @Inject(OKTA_AUTH) private _oktaAuth: OktaAuth,
    @Inject(DOCUMENT) private _document: Document
  ) {}

  ngOnInit(): <span class="hljs-keyword">void</span> {
    <span class="hljs-comment">// vavigate vers home si user connecter</span>
    <span class="hljs-built_in">this</span>._oktaStateService.authState$.subscribe(<span class="hljs-function">(<span class="hljs-params">authState</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (authState.isAuthenticated) {
        <span class="hljs-built_in">this</span>._router.navigate([<span class="hljs-string">"/home"</span>]);
      }
    });
  }

    public <span class="hljs-keyword">async</span> signIn(): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-keyword">void</span>&gt; {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>._oktaAuth.signInWithRedirect();
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error during sign-in:"</span>, error);
    }
  }

}
</code></pre>
<p>okta-auth.guard.ts</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Injectable, Inject, OnInit  } <span class="hljs-keyword">from</span> <span class="hljs-string">"@angular/core"</span>;
<span class="hljs-keyword">import</span> {
  ActivatedRouteSnapshot,
  CanActivate,
  RouterStateSnapshot,
  UrlTree,
  Router,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@angular/router"</span>;
<span class="hljs-keyword">import</span> { AuthState, OktaAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">"@okta/okta-auth-js"</span>;

<span class="hljs-keyword">import</span> { OktaAuthStateService, OKTA_AUTH } <span class="hljs-keyword">from</span> <span class="hljs-string">"@okta/okta-angular"</span>;
<span class="hljs-keyword">import</span> { filter, map, Observable } <span class="hljs-keyword">from</span> <span class="hljs-string">"rxjs"</span>;

@Injectable({
  <span class="hljs-attr">providedIn</span>: <span class="hljs-string">"root"</span>,
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OktaAuthGuard</span> <span class="hljs-title">implements</span> <span class="hljs-title">CanActivate</span> </span>{

  <span class="hljs-comment">//  public isAuthenticated$!: Observable&lt;boolean&gt;;</span>

  <span class="hljs-keyword">constructor</span>(
    private _router: Router,
     private _oktaStateService: OktaAuthStateService,
    @Inject(OKTA_AUTH) private _oktaAuth: OktaAuth
  ) {}


  canActivate(route: ActivatedRouteSnapshot, <span class="hljs-attr">state</span>: RouterStateSnapshot): Observable&lt;boolean&gt; {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>._oktaStateService.authState$.pipe(
      filter(<span class="hljs-function">(<span class="hljs-params">s</span>) =&gt;</span> !!s),
      map(<span class="hljs-function">(<span class="hljs-params">authState</span>) =&gt;</span> {
        <span class="hljs-keyword">if</span> (!authState.isAuthenticated) {
          <span class="hljs-comment">// Si l'utilisateur n'est pas authentifié, redirigez-le vers la page de connexion.</span>
          <span class="hljs-built_in">this</span>._router.navigate([<span class="hljs-string">"/login"</span>]);
          <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
      })
    );
  }
}
</code></pre>
<p>app-routing.module.ts</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { NgModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/core'</span>;
<span class="hljs-keyword">import</span> { RouterModule, Routes } <span class="hljs-keyword">from</span> <span class="hljs-string">'@angular/router'</span>;
<span class="hljs-keyword">import</span> { OktaCallbackComponent } <span class="hljs-keyword">from</span> <span class="hljs-string">'@okta/okta-angular'</span>;
<span class="hljs-keyword">import</span> { HomeComponent } <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/home/home.component'</span>;
<span class="hljs-keyword">import</span> { LoginComponent } <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/login/login.component'</span>;
<span class="hljs-keyword">import</span> { OktaAuthGuard } <span class="hljs-keyword">from</span> <span class="hljs-string">'./gurads/okta-auth.guard'</span>;

<span class="hljs-keyword">const</span> routes: Routes = [
  { <span class="hljs-attr">path</span>: <span class="hljs-string">'login/callback'</span>, <span class="hljs-attr">component</span>: OktaCallbackComponent }, 
  { <span class="hljs-attr">path</span>: <span class="hljs-string">'home'</span>, <span class="hljs-attr">component</span>: HomeComponent, <span class="hljs-attr">canActivate</span>: [OktaAuthGuard]},
  { <span class="hljs-attr">path</span>: <span class="hljs-string">'login'</span>, <span class="hljs-attr">component</span>: LoginComponent},
  { <span class="hljs-attr">path</span>: <span class="hljs-string">''</span>, <span class="hljs-attr">redirectTo</span>: <span class="hljs-string">'/home'</span>, <span class="hljs-attr">pathMatch</span>: <span class="hljs-string">'full'</span> },
];

@NgModule({
  <span class="hljs-attr">imports</span>: [RouterModule.forRoot(routes)],
  <span class="hljs-attr">exports</span>: [RouterModule]
})
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppRoutingModule</span> </span>{ }
</code></pre>
<p>Si tout se passe bien et que vous démarrez votre application Angular, vous verrez une page qui ressemble à ceci, si vous avez ajouté les styles CSS et Bootstrap :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697321516154/f3881cdd-cd5e-41ce-a3d0-35f83df9b131.png" alt class="image--center mx-auto" /></p>
<p>Lorsque vous cliquez sur le bouton "S'authentifier", vous serez redirigés vers la page d'authentification Okta, qui ressemble à ceci :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697321670756/c9ccca0f-a571-4db2-ae1a-69ee232ceb5d.png" alt class="image--center mx-auto" /></p>
<p>Dans mon cas, il existe déjà un compte actif associé à l'adresse e-mail <a target="_blank" href="mailto:martin.luc@test.com">martin.luc@test.com</a>, auquel nous avons précédemment assigné, via un groupe Okta, à notre "intégration d'application" que nous avons configurée. Assurez-vous de renseigner un utilisateur actif qui est également assigné à votre intégration d'application.</p>
<p>Lorsque vous cliquez sur "Suivant", si c'est la première fois que l'utilisateur se connecte, il lui sera demandé de configurer Okta Verify, qui est une application d'authentification à deux facteurs (MFA) d'Okta. Okta Verify ajoute une couche de sécurité supplémentaire en générant un code de vérification temporaire à usage unique sur le smartphone de l'utilisateur. Ce code doit être saisi pour vérifier l'identité de l'utilisateur, renforçant ainsi la sécurité du processus de connexion. MFA (Multi-Factor Authentication) est une méthode efficace pour réduire les risques d'accès non autorisés en exigeant plus qu'un simple mot de passe pour l'authentification.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697322002271/50a002c6-6aef-42ce-923c-76a502fc5a80.png" alt class="image--center mx-auto" /></p>
<p>Une fois la configuration d'Okta Verify terminée, l'utilisateur peut désormais accéder de manière sécurisée à votre application. Il doit saisir son mot de passe une seule fois, lors de la première connexion. Cela démontre l'avantage du SSO (Single Sign-On), car lors de ses futures connexions, l'utilisateur sera simplement confirmé via l'application Okta Verify sur son téléphone. Il sera ensuite redirigé vers la page d'accueil de votre application, comme illustré ci-dessous  :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1697322348993/93b2fa32-525d-4cd1-8fe8-5fe24ebb2cb2.png" alt class="image--center mx-auto" /></p>
<p>Pour tester la déconnexion, vous pouvez cliquer sur le bouton "Se déconnecter". Le jeton d'authentification fourni par Okta sera révoqué, et vous serez déconnecté, puis redirigé vers la page de connexion.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>En conclusion, l'intégration de l'authentification Okta dans votre application Angular constitue une étape cruciale pour garantir un accès sécurisé à vos utilisateurs. Avec Okta, vous bénéficiez d'une solution de gestion de l'identité et de l'accès qui gère la sécurité, l'authentification et l'autorisation (nous aborderons la partie autorisation dans un prochain article), vous permettant ainsi de vous concentrer sur le développement des fonctionnalités essentielles de votre application. Cela vous offre l'opportunité de fournir une expérience utilisateur fluide tout en renforçant la protection de vos ressources, tout en réduisant la charge liée à la gestion des identités. En exploitant les capacités d'Okta, vous pouvez garantir un accès sécurisé et offrir une tranquillité d'esprit à vos utilisateurs, tout en restant axé sur l'innovation et la croissance de votre application Angular.</p>
]]></content:encoded></item><item><title><![CDATA[Podcast UNI5 - Comprendre Okta]]></title><description><![CDATA[https://www.youtube.com/watch?v=hgL64P0xBgk
 
Si vous croyiez connaître toutes les subtilités d'Okta, détrompez-vous ! Rejoignez Imad Bensisaid, architecte cloud chez UNi5 Technologies, et Faical Essalifi (Architecte cloud) dans cet épisode captivant...]]></description><link>https://blog.pointbase.fr/podcast-uni5-comprendre-okta</link><guid isPermaLink="true">https://blog.pointbase.fr/podcast-uni5-comprendre-okta</guid><category><![CDATA[identity-management]]></category><category><![CDATA[IAM]]></category><category><![CDATA[okta]]></category><category><![CDATA[IT]]></category><category><![CDATA[UNI5]]></category><dc:creator><![CDATA[Aguibou Barry]]></dc:creator><pubDate>Thu, 19 Oct 2023 05:49:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1696945062192/ed076fbb-03f0-4891-a877-a1e4b245936c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=hgL64P0xBgk">https://www.youtube.com/watch?v=hgL64P0xBgk</a></div>
<p> </p>
<p>Si vous croyiez connaître toutes les subtilités d'Okta, détrompez-vous ! Rejoignez Imad Bensisaid, architecte cloud chez UNi5 Technologies, et Faical Essalifi (Architecte cloud) dans cet épisode captivant du Podcast des Avengers où nous explorons l’univers fascinant d'Okta avec Laure-Anaïs de la société Point Base.</p>
]]></content:encoded></item><item><title><![CDATA[Exploration de l'Auto-Provisionnement de Configurations avec Kyverno]]></title><description><![CDATA[Kyverno, en tant que contrôleur d'admission spécialement élaboré pour les contextes Kubernetes, assume un rôle essentiel dans l'administration et la sauvegarde des clusters Kubernetes.
Dans cet article, nous explorerons des scénarios d'usage tels que...]]></description><link>https://blog.pointbase.fr/exploration-de-lauto-provisionnement-de-configurations-avec-kyverno</link><guid isPermaLink="true">https://blog.pointbase.fr/exploration-de-lauto-provisionnement-de-configurations-avec-kyverno</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[kyverno]]></category><dc:creator><![CDATA[vincent ledan]]></dc:creator><pubDate>Thu, 12 Oct 2023 14:19:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1697120357461/06d0c994-334d-4dc2-aa98-84010b074328.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Kyverno, en tant que contrôleur d'admission spécialement élaboré pour les contextes Kubernetes, assume un rôle essentiel dans l'administration et la sauvegarde des clusters Kubernetes.</p>
<p>Dans cet article, nous explorerons des scénarios d'usage tels que l'auto-approvisionnement des configurations de sécurité, tout en scrutant également comment identifier des changements ainsi que les méthodes pour automatiser certaines configurations par défaut.</p>
<p>Un contrôleur d'admission est généralement déployé pour surveiller et, si besoin bloquer les configurations qui ne sont pas en accord avec les règles de conformité définies.</p>
<p>Se positionnant au centre des interactions avec le serveur kube-api, le contrôleur d'admission détient un accès complet à tous les appels API et, par conséquent, est apte à diriger des actions de mutation ou de génération, basées sur des règles précises. Cela permet une gestion exacte et automatisée des ressources et des configurations au sein d'un cluster Kubernetes. Génération automatique de politiques réseau et quotas.</p>
<h1 id="heading-automatisation-des-configurations-par-defaut">Automatisation des configurations par defaut</h1>
<p>Cette Clusterpolicy va automatiquement créer une networkpolicy ainsi qu'un resourcequotas dès que nous créerons un nouveau namespace</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">kyverno.io/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">ClusterPolicy</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">default-policy-and-quota</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">rules:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">create-default-network-policy</span>
    <span class="hljs-attr">match:</span>
      <span class="hljs-attr">resources:</span>
        <span class="hljs-attr">kinds:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">Namespace</span>
    <span class="hljs-attr">generate:</span>
      <span class="hljs-attr">kind:</span> <span class="hljs-string">NetworkPolicy</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">default-network-policy</span>
      <span class="hljs-attr">namespace:</span> <span class="hljs-string">"<span class="hljs-template-variable">{{request.object.metadata.name}}</span>"</span>
      <span class="hljs-attr">data:</span>
        <span class="hljs-attr">spec:</span>
          <span class="hljs-attr">podSelector:</span> {}
          <span class="hljs-attr">policyTypes:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">Ingress</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">Egress</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">create-default-resource-quota</span>
    <span class="hljs-attr">match:</span>
      <span class="hljs-attr">resources:</span>
        <span class="hljs-attr">kinds:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">Namespace</span>
    <span class="hljs-attr">generate:</span>
      <span class="hljs-attr">kind:</span> <span class="hljs-string">ResourceQuota</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">default-resource-quota</span>
      <span class="hljs-attr">namespace:</span> <span class="hljs-string">"<span class="hljs-template-variable">{{request.object.metadata.name}}</span>"</span>
      <span class="hljs-attr">data:</span>
        <span class="hljs-attr">spec:</span>
          <span class="hljs-attr">hard:</span>
            <span class="hljs-attr">pods:</span> <span class="hljs-string">"10"</span>
            <span class="hljs-attr">requests.cpu:</span> <span class="hljs-string">"1000m"</span>
            <span class="hljs-attr">requests.memory:</span> <span class="hljs-string">"1Gi"</span>
            <span class="hljs-attr">limits.cpu:</span> <span class="hljs-string">"2000m"</span>
            <span class="hljs-attr">limits.memory:</span> <span class="hljs-string">"2Gi"</span>
</code></pre>
<p>Créons un namespace pour tester la policy:</p>
<pre><code class="lang-bash">ledan@vincent-Inspiron-7370:~/kyverno$ kubectl create ns top
namespace/top created

ledan@vincent-Inspiron-7370:~/kyverno$ kubectl get resourcequotas -n top

NAME                     AGE   REQUEST                                                 LIMIT
default-resource-quota   3s    pods: 0/10, requests.cpu: 0/1, requests.memory: 0/1Gi   limits.cpu: 0/2, limits.memory: 0/2Gi

ledan@vincent-Inspiron-7370:~/kyverno$ kubectl get networkpolicy -n top

NAME                     POD-SELECTOR   AGE
default-network-policy   &lt;none&gt;         11s
</code></pre>
<p>Une approche qui pourrait s'avérer intéressante consiste à appliquer cette action de manière rétroactive mais de façon maîtrisée.</p>
<p>Pour ce faire, nous allons activer l'option <code>background: true</code>.</p>
<p>Cela aura pour effet d'appliquer cette politique aux namespaces existants avec une spécificité : le "generate" ne se déclenchera qu'après une modification des namespaces (quelle qu'elle soit).</p>
<p>Pour faire preuve de prudence, nous allons également exclure certains namespaces de la règle en ajoutant</p>
<pre><code class="lang-yaml">    <span class="hljs-attr">exclude:</span>
      <span class="hljs-attr">resources:</span>
        <span class="hljs-attr">namespaces:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">kube-system</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">kube-public</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">kyverno</span>
</code></pre>
<p>Appliquons désormais la nouvelle <code>clusterpolicy :</code></p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">kyverno.io/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">ClusterPolicy</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">default-policy-and-quota</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">background:</span> <span class="hljs-literal">true</span>
  <span class="hljs-attr">rules:</span>

  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">create-default-network-policy</span>
    <span class="hljs-attr">match:</span>
      <span class="hljs-attr">resources:</span>
        <span class="hljs-attr">kinds:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">Namespace</span>
    <span class="hljs-attr">exclude:</span>
      <span class="hljs-attr">resources:</span>
        <span class="hljs-attr">namespaces:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">kube-system</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">kube-public</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">kyverno</span>
    <span class="hljs-attr">generate:</span>
      <span class="hljs-attr">kind:</span> <span class="hljs-string">NetworkPolicy</span>
      <span class="hljs-attr">apiVersion:</span> <span class="hljs-string">networking.k8s.io/v1</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">default-network-policy</span>
      <span class="hljs-attr">namespace:</span> <span class="hljs-string">"<span class="hljs-template-variable">{{request.object.metadata.name}}</span>"</span>
      <span class="hljs-attr">data:</span>
        <span class="hljs-attr">spec:</span>
          <span class="hljs-attr">podSelector:</span> {}
          <span class="hljs-attr">policyTypes:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">Ingress</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">Egress</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">create-default-resource-quota</span>
    <span class="hljs-attr">match:</span>
      <span class="hljs-attr">resources:</span>
        <span class="hljs-attr">kinds:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">Namespace</span>
      <span class="hljs-attr">exclude:</span>
        <span class="hljs-attr">resources:</span>
          <span class="hljs-attr">namespaces:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">kube-system</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">kube-public</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">kyverno</span>
    <span class="hljs-attr">generate:</span>
      <span class="hljs-attr">kind:</span> <span class="hljs-string">ResourceQuota</span>
      <span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">default-resource-quota</span>
      <span class="hljs-attr">namespace:</span> <span class="hljs-string">"<span class="hljs-template-variable">{{request.object.metadata.name}}</span>"</span>
      <span class="hljs-attr">data:</span>
        <span class="hljs-attr">spec:</span>
          <span class="hljs-attr">hard:</span>
            <span class="hljs-attr">pods:</span> <span class="hljs-string">"10"</span>
            <span class="hljs-attr">requests.cpu:</span> <span class="hljs-string">"1000m"</span>
            <span class="hljs-attr">requests.memory:</span> <span class="hljs-string">"1Gi"</span>
            <span class="hljs-attr">limits.cpu:</span> <span class="hljs-string">"2000m"</span>
            <span class="hljs-attr">limits.memory:</span> <span class="hljs-string">"2Gi"</span>
</code></pre>
<p>À présent, nous allons attribuer des labels aux namespaces éxistant afin d'activer la politique :</p>
<pre><code class="lang-bash">ledan@vincent-Inspiron-7370:~/kyverno$ kubectl label namespaces ns1 ns2 ns3 ns4 ns5 trigger-kyverno-policy=v1
namespace/ns1 labeled
namespace/ns2 labeled
namespace/ns3 labeled
namespace/ns4 labeled
namespace/ns5 labeled

ledan@vincent-Inspiron-7370:~/kyverno$ kubectl get networkpolicy -n ns4
NAME                     POD-SELECTOR   AGE
default-network-policy   &lt;none&gt;         3s
ledan@vincent-Inspiron-7370:~/kyverno$ kubectl get networkpolicy -n ns3
NAME                     POD-SELECTOR   AGE
default-network-policy   &lt;none&gt;         5s
</code></pre>
<p>Si nous testons une modification sur le nom "kube-public", aucune action ne devrait être déclenchée :</p>
<pre><code class="lang-yaml"><span class="hljs-string">ledan@vincent-Inspiron-7370:~/kyverno$</span> <span class="hljs-string">kubectl</span> <span class="hljs-string">label</span> <span class="hljs-string">namespaces</span> <span class="hljs-string">kube-public</span>  <span class="hljs-string">trigger-kyverno-policy=v1</span>
<span class="hljs-string">namespace/kube-public</span> <span class="hljs-string">labeled</span>

<span class="hljs-string">ledan@vincent-Inspiron-7370:~/kyverno$</span> <span class="hljs-string">kubectl</span> <span class="hljs-string">get</span> <span class="hljs-string">networkpolicy</span> <span class="hljs-string">-n</span> <span class="hljs-string">kube-public</span>
<span class="hljs-literal">No</span> <span class="hljs-string">resources</span> <span class="hljs-string">found</span> <span class="hljs-string">in</span> <span class="hljs-string">kube-public</span> <span class="hljs-string">namespace.</span>

<span class="hljs-string">ledan@vincent-Inspiron-7370:~/kyverno$</span> <span class="hljs-string">kubectl</span> <span class="hljs-string">label</span> <span class="hljs-string">namespaces</span>  <span class="hljs-string">default</span>  <span class="hljs-string">trigger-kyverno-policy=v1</span>
<span class="hljs-string">namespace/default</span> <span class="hljs-string">labeled</span>
<span class="hljs-string">ledan@vincent-Inspiron-7370:~/kyverno$</span> <span class="hljs-string">kubectl</span> <span class="hljs-string">get</span> <span class="hljs-string">networkpolicy</span> <span class="hljs-string">-n</span> <span class="hljs-string">default</span>
<span class="hljs-string">NAME</span>                     <span class="hljs-string">POD-SELECTOR</span>   <span class="hljs-string">AGE</span>
<span class="hljs-string">default-network-policy</span>   <span class="hljs-string">&lt;none&gt;</span>         <span class="hljs-string">5s</span>
</code></pre>
<p>Il est bien sur possible d'aller plus loin avec des controles supplémentaires comme celui-ci. le controle ci-dessous fera en sorte de n'executer la policy uniquement si le namespace ne commence pas par <code>admin.</code></p>
<pre><code class="lang-yaml">    <span class="hljs-attr">preconditions:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">key:</span> <span class="hljs-string">"<span class="hljs-template-variable">{{request.object.metadata.name}}</span>"</span>
        <span class="hljs-attr">operator:</span> <span class="hljs-string">NotEquals</span>
        <span class="hljs-attr">value:</span>  <span class="hljs-string">"admin*"</span>
</code></pre>
<p>Testons quelques exemples:</p>
<pre><code class="lang-bash">:~/kyverno$ kubectl create ns yy
namespace/yy created

:~/kyverno$ kubectl get networkpolicy -n yy
NAME                     POD-SELECTOR   AGE
default-network-policy   &lt;none&gt;         5s

:~/kyverno$ kubectl create ns admin
namespace/admin created
:~/kyverno$ kubectl get networkpolicy -n admin
No resources found <span class="hljs-keyword">in</span> admin namespace.

:~/kyverno$ kubectl create ns adminrrrrrrrr
namespace/adminrrrrrrrr created

:~/kyverno$ kubectl get networkpolicy -n adminrrrrrrrr
No resources found <span class="hljs-keyword">in</span> adminrrrrrrrr namespace.

:~/kyverno$ kubectl create ns admi
namespace/admi created

:~/kyverno$ kubectl get networkpolicy -n admi
NAME                     POD-SELECTOR   AGE
default-network-policy   &lt;none&gt;         3s
</code></pre>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Les possibilités sont aussi variées que les architectures elles-mêmes. La flexibilité et la puissance que ce puissant outil nous offre peuvent transformer non seulement comment nous gérons les configurations de sécurité, mais également comment nous envisageons l’automatisation au sein de nos clusters Kubernetes.</p>
<p>À titre d'exemple, imaginez la création automatisée de role bindings, ou de toute autre ressource et configuration, orchestrée de manière à s'aligner précisément avec les spécificités et les exigences de votre architecture.</p>
<p>Ainsi, qu'il s'agisse d’instancier des politiques de réseau, de définir des quotas ou d’automatiser la gestion des rôles et permissions, Kyverno nous offre un tableau sur lequel nous pouvons peindre, avec précision et habileté, les politiques de gestion et de conformité adaptées à notre environnement.</p>
]]></content:encoded></item><item><title><![CDATA[KubeArmor : Inline remediation security]]></title><description><![CDATA[KubeArmor est une solution de sécurité open source qui permet de renforcer la sécurité des conteneurs sur Kubernetes en temps réel. Il s'agit d'un système de protection des conteneurs qui utilise des techniques de contrôle d'accès et de remédiation e...]]></description><link>https://blog.pointbase.fr/kubearmor-inline-remediation-security</link><guid isPermaLink="true">https://blog.pointbase.fr/kubearmor-inline-remediation-security</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[Security]]></category><category><![CDATA[cloud native]]></category><dc:creator><![CDATA[vincent ledan]]></dc:creator><pubDate>Wed, 04 Oct 2023 07:38:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1696405018358/6436c8fe-3916-4206-a012-886e5380e13c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>KubeArmor est une solution de sécurité open source qui permet de renforcer la sécurité des conteneurs sur Kubernetes en temps réel. Il s'agit d'un système de protection des conteneurs qui utilise des techniques de contrôle d'accès et de remédiation en ligne ( inline remediation ) pour empêcher les attaques.</p>
<p>L'approche choisi est de bloquer directement les comportements arnormaux avant qu'ils ne se produisent sans impacter l'application.</p>
<p>KubeArmor est également utilisable en dehors de Kubernetes et s'installe sur des serveurs linux , Bare metal etc...</p>
<p><strong>Points forts de KubeArmor</strong></p>
<ul>
<li><p><strong>Protection en temps réel</strong> : KubeArmor protège les conteneurs en temps réel, ce qui permet de bloquer les attaques dès qu'elles se produisent.</p>
</li>
<li><p><strong>Rémédiation en ligne</strong> : KubeArmor peut corriger les violations de sécurité en ligne, ce qui permet de réduire les dommages.</p>
</li>
<li><p><strong>Flexibilité</strong> : KubeArmor permet aux administrateurs de définir des politiques de sécurité personnalisées pour répondre aux besoins spécifiques de leur environnement.</p>
</li>
<li><p><strong>Simplicité</strong> : KubeArmor est facile à configurer et à utiliser.</p>
</li>
<li><p><strong>Performance</strong> : KubeArmor a un impact minimal sur les performances des conteneurs.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696404761438/8311704f-4df4-4d98-a125-d7c63b319528.png" alt class="image--center mx-auto" /></p>
<p><strong>Différenciateurs</strong></p>
<ul>
<li><p><strong>Prise en charge de plusieurs LSM</strong> : KubeArmor prend en charge plusieurs modules de sécurité du noyau Linux (LSM), tels que AppArmor et Seccomp. Cela permet aux administrateurs de choisir l'LSM qui convient le mieux à leurs besoins.</p>
</li>
<li><p><strong>Audit et reporting</strong> : KubeArmor fournit des journaux d'audit et des rapports qui peuvent être utilisés pour surveiller l'activité des conteneurs.</p>
</li>
<li><p><strong>Intégration avec d'autres outils</strong> : KubeArmor peut être intégré à d'autres outils de sécurité, tels que SIEM et SOAR.</p>
</li>
</ul>
<h2 id="heading-kubearmor-installation">Kubearmor installation</h2>
<p>Installons Kubearmor</p>
<pre><code class="lang-bash">helm repo add kubearmor https://kubearmor.github.io/charts
helm repo update kubearmor
helm upgrade --install kubearmor-operator kubearmor/kubearmor-operator -n kubearmor --create-namespace
</code></pre>
<p>et appliquon la CRD Kubearmor , pour notre exemple nous avons choisi une implémentation simple ( <a target="_blank" href="https://github.com/kubearmor/KubeArmor/tree/main/deployments/helm/KubeArmorOperator">Documentation</a>)</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">operator.kubearmor.com/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">KubeArmorConfig</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">labels:</span>
    <span class="hljs-attr">app.kubernetes.io/name:</span> <span class="hljs-string">kubearmorconfig</span>
    <span class="hljs-attr">app.kubernetes.io/instance:</span> <span class="hljs-string">kubearmorconfig-sample</span>
    <span class="hljs-attr">app.kubernetes.io/part-of:</span> <span class="hljs-string">kubearmoroperator</span>
    <span class="hljs-attr">app.kubernetes.io/managed-by:</span> <span class="hljs-string">kustomize</span>
    <span class="hljs-attr">app.kubernetes.io/created-by:</span> <span class="hljs-string">kubearmoroperator</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">kubearmorconfig-default</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">kubearmor</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">defaultCapabilitiesPosture:</span> <span class="hljs-string">audit</span>
  <span class="hljs-attr">defaultFilePosture:</span> <span class="hljs-string">audit</span>
  <span class="hljs-attr">defaultNetworkPosture:</span> <span class="hljs-string">audit</span>
  <span class="hljs-attr">defaultVisibility:</span> <span class="hljs-string">process,file,network</span>
  <span class="hljs-attr">kubearmorImage:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">kubearmor/kubearmor:stable</span>
    <span class="hljs-attr">imagePullPolicy:</span> <span class="hljs-string">Always</span>
  <span class="hljs-attr">kubearmorInitImage:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">kubearmor/kubearmor-init:stable</span>
    <span class="hljs-attr">imagePullPolicy:</span> <span class="hljs-string">Always</span>
  <span class="hljs-attr">kubearmorRelayImage:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">kubearmor/kubearmor-relay-server</span>
    <span class="hljs-attr">imagePullPolicy:</span> <span class="hljs-string">Always</span>
  <span class="hljs-attr">kubearmorControllerImage:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">kubearmor/kubearmor-controller</span>
    <span class="hljs-attr">imagePullPolicy:</span> <span class="hljs-string">Always</span>
</code></pre>
<h3 id="heading-kubearmorpolicy-implementation">Kubearmorpolicy implementation</h3>
<p>Kubearmor fourni la possibilité de créer de nombreuses règles bloquant les syscall , le réseau , les capabilities kernel , les accès aux différents fichiers, les process.</p>
<p>Prenons quelques exemples</p>
<p><strong><mark>Process exemple : deny apt command</mark></strong></p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">security.kubearmor.com/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">KubeArmorPolicy</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">ksp-wordpress-block-process</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">default</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">severity:</span> <span class="hljs-number">3</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">matchLabels:</span>
      <span class="hljs-attr">app:</span> <span class="hljs-string">nginx</span>
  <span class="hljs-attr">process:</span>
    <span class="hljs-attr">matchPaths:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">path:</span> <span class="hljs-string">/usr/bin/apt</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">path:</span> <span class="hljs-string">/usr/bin/apt-get</span>
  <span class="hljs-attr">action:</span> <span class="hljs-string">Block</span>
</code></pre>
<p>Test :</p>
<pre><code class="lang-bash">vincn_ledan@cloudshell:~/kubearmor (medium-article)$ kubectl <span class="hljs-built_in">exec</span> -it nginx-77b4fdf86c-vckbc -- bash 
root@nginx-77b4fdf86c-vckbc:/<span class="hljs-comment"># apt</span>
apt 2.6.1 (amd64)
Usage: apt [options] <span class="hljs-built_in">command</span>

apt is a commandline package manager and provides commands <span class="hljs-keyword">for</span>
searching and managing as well as querying information about packages.
It provides the same functionality as the specialized APT tools,
like apt-get and apt-cache, but enables options more suitable <span class="hljs-keyword">for</span>
interactive use by default.

Most used commands:
  list - list packages based on package names
.........................................................
</code></pre>
<p>Apres application de la policy</p>
<pre><code class="lang-yaml"><span class="hljs-string">incn_ledan@cloudshell:~/kubearmor</span> <span class="hljs-string">(medium-article-377208)$</span> <span class="hljs-string">kubectl</span> <span class="hljs-string">exec</span> <span class="hljs-string">-it</span> <span class="hljs-string">nginx-77b4fdf86c-vckbc</span> <span class="hljs-string">--</span> <span class="hljs-string">bash</span> 
<span class="hljs-string">root@nginx-77b4fdf86c-vckbc:/#</span> <span class="hljs-string">apt</span>
<span class="hljs-attr">bash: /usr/bin/apt:</span> <span class="hljs-string">Permission</span> <span class="hljs-string">denied</span>
</code></pre>
<p><strong><mark>File exemple : deny cat command</mark></strong></p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">security.kubearmor.com/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">KubeArmorPolicy</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">ksp-block-read</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">default</span> <span class="hljs-comment"># use your namespace</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">matchLabels:</span>
      <span class="hljs-attr">app:</span> <span class="hljs-string">nginx</span> <span class="hljs-comment"># use your labels here</span>
  <span class="hljs-attr">file:</span>
    <span class="hljs-attr">severity:</span> <span class="hljs-number">9</span>
    <span class="hljs-attr">matchPaths:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">path:</span> <span class="hljs-string">/etc/passwd</span>
    <span class="hljs-attr">action:</span> <span class="hljs-string">Block</span>
</code></pre>
<p>le résultat est le suivant :</p>
<pre><code class="lang-bash">I have no name!@nginx-77b4fdf86c-vckbc:/<span class="hljs-comment"># cat /etc/hostname</span>
nginx-77b4fdf86c-vckbc
I have no name!@nginx-77b4fdf86c-vckbc:/<span class="hljs-comment"># cat /etc/passwd  </span>
cat: /etc/passwd: Permission denied
</code></pre>
<p>Network Kubearmor policy</p>
<pre><code class="lang-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">security.kubearmor.com/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">KubeArmorPolicy</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">ksp-block-icmp</span>
  <span class="hljs-attr">namespace:</span> <span class="hljs-string">default</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">severity:</span> <span class="hljs-number">8</span>
  <span class="hljs-attr">selector:</span>
    <span class="hljs-attr">matchLabels:</span>
      <span class="hljs-attr">app:</span> <span class="hljs-string">nginx</span>
  <span class="hljs-attr">network:</span>
    <span class="hljs-attr">matchProtocols:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">protocol:</span> <span class="hljs-string">icmp</span>
  <span class="hljs-attr">action:</span>
    <span class="hljs-string">Block</span>
</code></pre>
<p>Le résultat est le suivant :</p>
<pre><code class="lang-bash">I have no name!@nginx-77b4fdf86c-vckbc:/<span class="hljs-comment"># ping 8.8.8.8</span>
ping: 8.8.8.8: Address family <span class="hljs-keyword">for</span> hostname not supported
</code></pre>
<h3 id="heading-automatic-policy-discovery-with-accuknox">Automatic policy discovery with Accuknox</h3>
<p>Kubearmor fourni une feature très intérressante qui est l'application profiling afin de créer des policies custom basé sur le comportement des applications.</p>
<p>Nous allons utiliser la solution Accuknox pour ce faire et enregistrer simplement notre cluster GKE dans l'interface.</p>
<pre><code class="lang-bash"> helm upgrade --install accuknox-agents oci://public.ecr.aws/k9v9d5v2/accuknox-agents \
      --version <span class="hljs-string">"v0.1.5"</span> \
      --<span class="hljs-built_in">set</span> joinToken=<span class="hljs-string">"REDACTED"</span> \
      --<span class="hljs-built_in">set</span> spireHost=<span class="hljs-string">"REDACTED"</span> \
      --<span class="hljs-built_in">set</span> ppsHost=<span class="hljs-string">"REDACTED"</span> \
      --<span class="hljs-built_in">set</span> knoxGateway=<span class="hljs-string">"REDACTED"</span> \
      -n accuknox-agents --create-namespace
</code></pre>
<p>En 1 ou 2 minutes l'agent discovery engine va analyser le comportement de l'application , les calls système et créer sur mesure une KubeArmorPolicy</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696349835060/fc31fbf2-df19-48e0-b91a-82d4fb2e5f4c.png" alt class="image--center mx-auto" /></p>
<p>Nous avons uniquement à activer la policy dans l'interface ou l'exporter et appliquer une logique Gitops.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696350109008/f51847ec-bc74-41da-b328-4e56db29e2b0.png" alt class="image--center mx-auto" /></p>
<p>Lorsque la policy est en mode innactive, le deamon va détecter les nouveaux calls système , accès aux fichiers et adapter de façon automatique la policy et demander si nous validons ou non ce nouveau comportement.</p>
<h1 id="heading-next-step">Next step</h1>
<p>Dans un prochain article nous verrons les points suivants:</p>
<ul>
<li><p>Création automatique des networks policy avec Cilium et Kubearmor</p>
</li>
<li><p>App behavior visibility</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Kubernetes security  et pentest [Vidéo]]]></title><description><![CDATA[Dans cette vidéo nous avons échangé autour des problématiques de sécurité autour de kubernetes et comment mitiger les risques.
https://www.youtube.com/watch?v=ztstTAgbgsE]]></description><link>https://blog.pointbase.fr/kubernetes-security-et-pentest-video</link><guid isPermaLink="true">https://blog.pointbase.fr/kubernetes-security-et-pentest-video</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[cloud security]]></category><category><![CDATA[containers]]></category><dc:creator><![CDATA[vincent ledan]]></dc:creator><pubDate>Fri, 29 Sep 2023 12:59:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695992804857/93dcc72f-5e43-4cce-a720-8a79992a9ca5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Dans cette vidéo nous avons échangé autour des problématiques de sécurité autour de kubernetes et comment mitiger les risques.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=ztstTAgbgsE">https://www.youtube.com/watch?v=ztstTAgbgsE</a></div>
]]></content:encoded></item><item><title><![CDATA[Kubernetes Validating Admission Policy : Introduction]]></title><description><![CDATA[Depuis longtemps, au sein de l’écosystème Kubernetes, OPA (Open Policy Agent) et Kyverno sont instinctivement choisis pour mettre en place un admission controller. Plusieurs facteurs expliquent ce choix, notamment les lacunes de l’API Kubernetes à ce...]]></description><link>https://blog.pointbase.fr/kubernetes-validating-admission-policy-introduction</link><guid isPermaLink="true">https://blog.pointbase.fr/kubernetes-validating-admission-policy-introduction</guid><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[vincent ledan]]></dc:creator><pubDate>Fri, 29 Sep 2023 10:29:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695983311097/baea3d36-e2e3-4ffb-ac15-28bb4589a6ec.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Depuis longtemps, au sein de l’écosystème Kubernetes, OPA (Open Policy Agent) et Kyverno sont instinctivement choisis pour mettre en place un admission controller. Plusieurs facteurs expliquent ce choix, notamment les lacunes de l’API Kubernetes à cet égard ou la flexibilité d’utiliser OPA dans d’autres scénarios comme l’infrastructure as code. Cependant, à l’heure actuelle, Kubernetes propose-t-il nativement des solutions matures et pertinentes sur cette thématique? </p>
<p>Le concept a été lancé avec la version 1.26 de Kubernetes et a atteint le stade beta dans la version 1.28. </p>
<p>L’un des points forts de cette fonctionnalité est son intégration directe à l’API de Kubernetes, éliminant le besoin de recourir à des tiers supplémentaires. Cela diminue ainsi l’effort requis pour la maintenance.</p>
<h3 id="heading-validating-admission-components">Validating Admission components</h3>
<p>La logique de fond reste la même , si on prends l’exemple d’OPA par exemple : </p>
<p>Nous avons ces deux composants : </p>
<ul>
<li><p><strong>ConstraintTemplate</strong> qui défini la logique de la policy et qui contient le controle en language <strong>Rego</strong> à éffectuer par exemple : <em>“maximum de replicas d’un déploiement ne peux pas éxéder 5”</em></p>
</li>
<li><p><strong>Template</strong> utilise cette policy pour l’appliquer à tels ou tels composant POD , filtre la cible avec des parameters …. </p>
</li>
</ul>
<p>Si on prends l’exemple de cette même policy mais pour la version native de Kubernetes , les composants principaux sont: </p>
<ul>
<li><p><strong>ValidatingAdmissionPolicy</strong> qui défini la policy de controle mais cette fois ci en language <strong>CEL</strong> </p>
</li>
<li><p><strong>ValidatingAdmissionPolicyBinding</strong> est le même principe qu’un template il filtre le scope et parametre selon le contexte. </p>
</li>
</ul>
<h3 id="heading-validation-admission-controller-in-action">Validation admission controller in action</h3>
<p>Afin de pouvoir tester cette feature, il est important d’avoir un environnement qui le permet. Minikube est vraiment intérressant pour tester de nouvelles Features comme celle-ci. </p>
<pre><code class="lang-bash">minikube start  --feature-gates=<span class="hljs-string">'ValidatingAdmissionPolicy=true'</span> \  
--kubernetes-version=1.28.0
</code></pre>
<p>Nous aimerions restreindre la possibilité de créer des services de type “NodePort” mais plutôt de centraliser l’exposition des applications avec un ingress ou un Kubernetes API gateway.:</p>
<p>Prenons maintenant un exemple avec OPA pour ce faire : </p>
<pre><code class="lang-bash">apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8sblocknodeport
  annotations:
    metadata.gatekeeper.sh/title: <span class="hljs-string">"Block NodePort"</span>
    metadata.gatekeeper.sh/version: 1.0.0
    description: &gt;-
      Disallows all Services with <span class="hljs-built_in">type</span> NodePort.

      https://kubernetes.io/docs/concepts/services-networking/service/<span class="hljs-comment">#nodeport</span>
spec:
  crd:
    spec:
      names:
        kind: K8sBlockNodePort
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sblocknodeport

        violation[{<span class="hljs-string">"msg"</span>: msg}] {
          input.review.kind.kind == <span class="hljs-string">"Service"</span>
          input.review.object.spec.type == <span class="hljs-string">"NodePort"</span>
          msg := <span class="hljs-string">"User is not allowed to create service of type NodePort"</span>
        }
</code></pre>
<pre><code class="lang-bash">apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sBlockNodePort
metadata:
  name: block-node-port
spec:
  match:
    kinds:
      - apiGroups: [<span class="hljs-string">""</span>]
        kinds: [<span class="hljs-string">"Service"</span>]
</code></pre>
<p>Maintenant voyons comment faire cette équivalent via l’admission controller natif de kubernetes : </p>
<p><strong>Validatingadmissionpolicy</strong>: </p>
<pre><code class="lang-bash">apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingAdmissionPolicy
metadata:
  name: deny-nodeport
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   [<span class="hljs-string">""</span>]
      apiVersions: [<span class="hljs-string">"v1"</span>]
      operations:  [<span class="hljs-string">"CREATE"</span>, <span class="hljs-string">"UPDATE"</span>]
      resources:   [<span class="hljs-string">"services"</span>]
  validations:
    - expression: object.spec.type != <span class="hljs-string">"NodePort"</span>
</code></pre>
<p><strong>Validatingadmissionpolicybinding</strong>: </p>
<pre><code class="lang-bash">apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: <span class="hljs-string">"vincent-binding-test.example.com"</span>
spec:
  policyName: <span class="hljs-string">"deny-nodeport"</span>
  validationActions: [Deny]
  matchResources:
    namespaceSelector:
      matchLabels:
        env: prod
</code></pre>
<p>Le Kind ValidatingAdmissionPolicyBinding va dans notre cas appliquer cette policy sur l’ensemble des namespaces ayant un label <strong>env=prod</strong></p>
<p>Maintenant faisons un petit test en déployant un simple service N<strong>odePort</strong> dans un namespace ayant un label <strong>env=prod</strong></p>
<pre><code class="lang-bash">apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: toto
  name: toto
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: toto
  <span class="hljs-built_in">type</span>: NodePort
</code></pre>
<pre><code class="lang-bash">kubectl apply -f service.yaml -n titi 

The services <span class="hljs-string">"toto"</span> is invalid: 
: ValidatingAdmissionPolicy <span class="hljs-string">'deny-nodeport'</span> with binding 
<span class="hljs-string">'deny-service-nodeport'</span> denied request: failed expression:
 object.spec.type != <span class="hljs-string">"NodePort"</span>
</code></pre>
<p>Nous pouvons observer que la Requête à été bloquée par Kubernetes. </p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Cette feature n’est pas encore ready for production mais va dans le bon sens. si on compare à Kyverno par exemple , Kyvernoo offre plus de flexibilité ou d’automatisation , par exemple en fournissant la capacité a provisionner de façon automatique des kinds dans certains namespace. </p>
<p>Si on parle d’OPA , lui est utilisable dans bien d’autres contextes que Kubernetes , Policy as code , authentication on demand et beaucoup d’autres contextes.</p>
]]></content:encoded></item><item><title><![CDATA[New Kubernetes security workshop chez Point Base]]></title><description><![CDATA[Nous avons le plaisir de lancer notre nouveau “ Kubernetes security workshop “ chez Point Base , mais de quoi parlons nous exactement.
Tout d’abord pourquoi proposons nous cela, la réponse est plutot simple, faire prendre conscience des problématique...]]></description><link>https://blog.pointbase.fr/new-kubernetes-security-workshop-chez-point-base</link><guid isPermaLink="true">https://blog.pointbase.fr/new-kubernetes-security-workshop-chez-point-base</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[cloud native security]]></category><dc:creator><![CDATA[vincent ledan]]></dc:creator><pubDate>Fri, 29 Sep 2023 10:09:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695982276208/21b6e9c5-fb23-4aab-bbd6-e413fdc8e9b0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Nous avons le plaisir de lancer notre nouveau “ Kubernetes security workshop “ chez Point Base , mais de quoi parlons nous exactement.</p>
<p>Tout d’abord pourquoi proposons nous cela, la réponse est plutot simple, faire prendre conscience des problématiques ou mauvaises pratiques quant à la gestion et la sécurité dans ce types d’environnements.</p>
<p>Il est parfois facile de se perdre dans l’écosystème cloud natif sécurity , la sortie de nouveaux outils , des évolutions extrêmement rapides et complexes.</p>
<p>Notre Objectif est simple passer une journée avec vos équipes touchant de près ou de loin ce types écosystème ou nous repasserons en revue l’ensemble des problématiques de sécurité tant techniques mais également organisationnelles , les vecteurs d’attaques courants , les outils les plus pertinent , les dernières innovations , les bests practices dans le domaine et ce afin qu’a la fin de cette journée vous ayez une vision claire de la priorisation des efforts à mener.</p>
<p>Parfois cela pourra vous rassurer sur vos actions en cours , mais parfois cela vous fera probablement réfléchir de façon différente quant à la priorisation ou aux choix des outils.</p>
<p>Nous échangerons autour des problématiques réelles</p>
<h4 id="heading-default-cloud-configuration">Default cloud configuration :</h4>
<p>Il est très courant que nos clients utilisent les configurations par défaut des providers, ou par exemple des modules terraform. Bien souvent, ces configurations ne sont pas suffisantes en termes de sécurité. Nous verrons pourquoi.</p>
<h4 id="heading-networking">Networking :</h4>
<p>Comme j’aime le rappeler, dans un cluster Kubernetes, tous les flux sont ouverts, non chiffrés et non contrôlés. Cela concerne les interactions entre les différents pods ou namespaces, mais aussi comment les pods peuvent communiquer avec l’extérieur ou scanner votre réseau VPC, entre autres. Un autre aspect concerne le contrôle des flux entrants et sa consolidation via des logiques d’ingress ou d’API gateway.</p>
<h4 id="heading-admission-controller-et-gouvernance">Admission controller et Gouvernance :</h4>
<p>Dans un cluster Kubernetes, il est très facile de devenir admin, de corrompre les nœuds des clusters, car aucune restriction pour devenir root ou utiliser des capabilities avancées comme CAP_SYSADMIN n’est en place. La gestion des labels, la gouvernance, l’uniformité et la sécurité des déploiements, ainsi que leur protection au niveau du cluster doivent être implémentées.</p>
<h4 id="heading-runtime-protection-sandboxing">Runtime protection / Sandboxing</h4>
<p>Cette partie est souvent oubliée mais très importante. Par défaut, les hosts et l’activité des containers ne sont pas protégés contre des activités suspectes dans les containers (ex : cat /etc/…./credentials). Pour détecter ce genre d’activités, vous devez premièrement comprendre les risques et les possibilités des attaquants, mais également mettre en place un ensemble de règles pour détecter ou bloquer. Nous verrons plusieurs approches ensemble, par exemple “detection and response” ou “Block syscall”. Ce sont des décisions de sécurité.</p>
<h4 id="heading-3rd-party-risks-argocd-gitlab">3rd Party risks (argocd — gitlab…)</h4>
<p>Bien que vous contrôliez la majeure partie de vos workloads tout au long de la chaîne, certaines composantes ne peuvent être contrôlées. Alors, quelle stratégie avez-vous adoptée ? Sandboxing container, cluster isolation, whitelist container registry ?</p>
<h4 id="heading-surveillance-et-monitoring">Surveillance et monitoring</h4>
<p>Si nous faisons un focus sur les sujets de monitoring, plusieurs facteurs sont à prendre en compte. Que souhaitez-vous détecter ? Analyse comportementale des containers, activités suspectes sur le cluster, création de rôles RBAC suspects, activités suspectes sur vos buckets S3 ? Il y a beaucoup à dire sur le sujet.</p>
<h4 id="heading-quotas-et-gestion-des-ressources">Quotas et gestion des ressources</h4>
<p>À la croisée des chemins entre les préoccupations des SRE et celles de vos équipes sécurité, il est crucial de contrôler à quel point et dans quelles conditions votre infrastructure peut évoluer (scale). Imaginons qu’un container soit compromis et souhaite perturber certains services. Êtes-vous en mesure, par exemple, de gérer et d’imposer des règles sur la consommation réseau de vos pods ?</p>
<h4 id="heading-gestion-des-identites-utilisateur-et-des-workloads">Gestion des identités utilisateur et des workloads</h4>
<p>Avoir une bonne gestion des droits et des groupes IAM n’est pas une nouveauté. Toutefois, comprendre les implications ou la puissance de certains “cluster roles”, par exemple (VERBS=GET, Kind=secret = Admin), est crucial. Trouver le juste milieu entre sécurité et flexibilité n’est pas toujours aisé.</p>
<p>Ce que l’on constate souvent, c’est une gestion inadéquate de l’authentification entre vos différents pods et des services cloud tels que DynamoDB, S3 buckets ou Cloud SQL chez GCP. Historiquement, l’utilisation des “access keys” intégrées secrètement était couramment utilisée. Toutefois, depuis un certain temps, les fournisseurs cloud ont développé des mécanismes permettant une approche plus granulaire et sans clé (ex : “workload identity” chez GCP).</p>
<h4 id="heading-securite-des-workloads-et-des-containers">Sécurité des workloads et des containers</h4>
<p>Avez-vous mis en place des templates de déploiement ou des helm charts avec les configurations de sécurité les plus appropriées ? Comment vos images de containers sont-elles construites : multi-step, distroless, scan de vulnérabilités, scan du registre ? Comment priorisez-vous les dizaines de CVEs remontées par vos outils ? Autant de questions auxquelles nous <a target="_blank" href="http://xn--rflchirons-b7ac.Cloud">réfléchirons.Cloud</a> security</p>
<p>Votre flotte de clusters Kubernetes s’intégre logiquement dans une landing zone mais est-elle vraiment conçu pour être assez isoler , backuper vous vos clusters ? avez vous des procédures ou de l’automatisation pour déplacer vos workloads d’un cloud à un autre ?</p>
<h4 id="heading-day2">Day2</h4>
<p>Quand on parle de sécurité dans ce domaine, de nombreux outils open source sont efficaces. Cependant, assurez-vous d’avoir des équipes bien formées et suffisamment staffées pour garantir une continuité d’exploitation. Recourir sans cesse à de nouveaux outils pour pallier les manques d’autres n’est pas toujours la meilleure stratégie. Avez-vous mis en place des outils pour détecter les nouvelles CVEs exploitables dans vos workloads et des processus pour y remédier rapidement et à grande échelle ?</p>
<h4 id="heading-sensibilisation-a-la-securite-offensive">Sensibilisation à la sécurité offensive</h4>
<p>Il est toujours intéressant d’adopter une perspective critique et offensive lors de la sécurisation d’un cluster. Comment pourrais-je contourner cette règle ? Comment pourrais-je compromettre notre CI/CD ? La gamification est un outil puissant pour changer les mentalités. Trois heures pour devenir administrateur du cluster : en discutons-nous ?</p>
<p>Nous discuterons plus en détail sur une série d’attque éffectuée sur des environnements Kubernetes : SCARLETEEL par exemple.</p>
<h4 id="heading-gestion-multi-cluster">Gestion multi-cluster</h4>
<p>Une fois que vous avez assimilé tous les points mentionnés précédemment, posez-vous la question : mes processus et mon architecture sont-ils adaptés à une montée en puissance ? Pensez à une échelle 100 fois supérieure. Mettez en œuvre davantage d’automatisation, une approche GitOps, et choisissez une source d’information unique.</p>
<p>Contactez nous dès maintenant pour avoir plus de détails.</p>
]]></content:encoded></item><item><title><![CDATA[Falco: Surveillez et Neutralisez les Menaces dans Votre Cluster Kubernetes]]></title><description><![CDATA[Falco est un outil de détection des comportements anormaux et non désirés au sein des applications en conteneurs. Il offre une surveillance en temps réel des activités des conteneurs et des machines hôtes, aidant ainsi les équipes de sécurité à maint...]]></description><link>https://blog.pointbase.fr/falco-surveillez-et-neutralisez-les-menaces-dans-votre-cluster-kubernetes</link><guid isPermaLink="true">https://blog.pointbase.fr/falco-surveillez-et-neutralisez-les-menaces-dans-votre-cluster-kubernetes</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[#kubernetes #container ]]></category><category><![CDATA[Kubernetes Security]]></category><dc:creator><![CDATA[Aguibou Barry]]></dc:creator><pubDate>Fri, 29 Sep 2023 10:06:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695982370803/e866b4ce-b243-4d04-a670-ce7ce31969a6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Falco est un outil de détection des comportements anormaux et non désirés au sein des applications en conteneurs. Il offre une surveillance en temps réel des activités des conteneurs et des machines hôtes, aidant ainsi les équipes de sécurité à maintenir la sûreté et la conformité des systèmes. Récemment, Falco a introduit une nouvelle interface graphique, nommée Falco Sidekick UI (falcosidekick), qui vise à rendre l’utilisation et la gestion de Falco encore plus pratique et efficace.</p>
<p>Dans cet article, nous examinerons de plus près ce nouvel outil en mettant l’accent sur son déploiement ainsi que sur la création d’une règle personnalisée pour Falco. De plus, nous explorerons en détail l’interface utilisateur de Falco Sidekick UI, une addition bienvenue qui augmente la facilité d’utilisation de Falco.</p>
<p>Prérequis : Avoir un cluster Kubernetes en fonctionnement, avoir kubectl installé et installer helm.</p>
<h3 id="heading-deploiement-de-falco">Déploiement de Falco</h3>
<p>Falco offre par défaut de nombreuses règles prédéfinies se basant sur les meilleures pratiques de sécurité les plus courantes. Dans le cadre de cet article, nous allons surcharger ces règles par défaut avec nos propres règles personnalisées. Pour ce faire, nous allons créer notre fichier custom-rules.yaml.</p>
<pre><code class="lang-bash">customRules:
  custom-rules.yaml: |-
    - rule: detect_ls_command
      desc: Detect execution de la commande <span class="hljs-string">'ls'</span> dans un conteneur
      condition: evt.type = execve and evt.dir = &lt; and container.id != host and proc.name = ls
      output: <span class="hljs-string">"Execution de la commande 'ls' dans un conteneur (utilisateur=%user.name commande=%proc.cmdline)"</span>
      priority: WARNING

    - rule: detect_date_command
      desc: Detect execution de la commande <span class="hljs-string">'date'</span> dans un conteneur
      condition: evt.type = execve and evt.dir = &lt; and container.id != host and proc.name = date
      output: <span class="hljs-string">"Execution de la commande 'date' dans un conteneur (utilisateur=%user.name commande=%proc.cmdline)"</span>
      priority: CRITICAL
    - rule: detect_whoami_command
      desc: Detecte execution de la commande <span class="hljs-string">'whoami'</span> dans un conteneur
      condition: evt.type = execve and evt.dir = &lt; and container.id != host and proc.name = whoami
      output: <span class="hljs-string">"Execution de la commande 'whoami' dans un conteneur (utilisateur=%user.name commande=%proc.cmdline)"</span>
      priority: ERROR
</code></pre>
<p>Dans ce fichier custom-rules.yaml, nous avons écrit 3 règles. La première a pour objectif de détecter l’exécution de la commande ls dans le shell d’un conteneur et d’envoyer une notification de priorité WARNING. Maintenant, passons à l’installation de Falco.</p>
<pre><code class="lang-bash">helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
kubectl create ns falco
</code></pre>
<p>Dans la commande qui suit, nous procédons à l’installation de Falco et à l’activation de Falcosidekick. Cela nous offre une interface graphique et la possibilité d’envoyer des notifications sur les canaux spécifiés. Dans notre contexte, nous avons opté pour l’utilisation de Slack.</p>
<p>Note : Dans notre configuration, toutes les notifications d’un niveau supérieur ou égal à DEBUG seront transmises sur notre canal Slack.</p>
<pre><code class="lang-bash">helm install falco -n falco - namespace falco -f custom-rules.yaml - <span class="hljs-built_in">set</span> driver.kind=ebpf - <span class="hljs-built_in">set</span> tty=<span class="hljs-literal">true</span> falcosecurity/falco \
 - <span class="hljs-built_in">set</span> falcosidekick.enabled=<span class="hljs-literal">true</span> \
 - <span class="hljs-built_in">set</span> falcosidekick.webui.enabled=<span class="hljs-literal">true</span> \ 
 - <span class="hljs-built_in">set</span> falcosidekick.config.slack.webhookurl=https://hooks.slack.com/services/REDACTED \
 - <span class="hljs-built_in">set</span> falcosidekick.config.slack.minimumpriority=DEBUG \
 - <span class="hljs-built_in">set</span> falcosidekick.config.customfields=<span class="hljs-string">"user:barrybagata96"</span>
</code></pre>
<p>On vérifie que tout s’est bien passé</p>
<pre><code class="lang-bash">$ kubectl get pods -n falco
NAME                                      READY   STATUS    RESTARTS   AGE
falco-7dvcj                               2/2     Running   0          3h44m
falco-cpd44                               2/2     Running   0          3h44m
falco-falcosidekick-54fffbc85b-f2xh2      1/1     Running   0          3h44m
falco-falcosidekick-54fffbc85b-nsfn5      1/1     Running   0          3h44m
falco-falcosidekick-ui-5ffc494bf8-b8wqk   1/1     Running   0          77m
falco-falcosidekick-ui-5ffc494bf8-pqzv6   1/1     Running   0          77m
falco-falcosidekick-ui-redis-0            1/1     Running   0          3h44m
falco-rsbqg                               2/2     Running   0          3h44m
falco-sl9j8                               2/2     Running   0          3h44m
barrybagata96@cloudshell:~/exo-falco (kubernetese-project-399608)$
</code></pre>
<p>Maintenant, testons les règles Falco que nous avons écrites dans custom-rules.yaml.</p>
<pre><code class="lang-bash">kubectl create deploy nginx --image=nginx

kubectl <span class="hljs-built_in">exec</span> -it nginx-app-5c64488cdf-dnjm7 -- bash
</code></pre>
<pre><code class="lang-bash">root@nginx-app-5c64488cdf-dnjm7:/<span class="hljs-comment"># ls</span>
bin   dev                  docker-entrypoint.sh  home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc                   lib   lib64  media   opt  root  sbin  sys  usr
</code></pre>
<pre><code class="lang-bash">kubectl logs -l app.kubernetes.io/name=falco -n falco -c falco
</code></pre>
<pre><code class="lang-bash">..............................................................
..............................................................
                 logs filtrées
..............................................................
..............................................................
</code></pre>
<pre><code class="lang-bash">{<span class="hljs-string">"hostname"</span>:<span class="hljs-string">"falco-rsbqg"</span>,<span class="hljs-string">"output"</span>:<span class="hljs-string">"12:11:59.619762538: 
Warning Ex\u00e9cution de la commande 'ls' dans un conteneur 
(utilisateur=root commande=ls) container_id=fca790abe8c7 
container_image=docker.io/library/nginx container_image_tag=latest 
container_name=nginx k8s_ns=default k8s_pod_name=nginx-app-5c64488cdf-dnjm7"</span>,
<span class="hljs-string">"priority"</span>:<span class="hljs-string">"Warning"</span>,<span class="hljs-string">"rule"</span>:<span class="hljs-string">"detect_ls_command"</span>,<span class="hljs-string">"source"</span>:<span class="hljs-string">"syscall"</span>,<span class="hljs-string">"tags"</span>:[],
<span class="hljs-string">"time"</span>:<span class="hljs-string">"2023-09-28T12:11:59.619762538Z"</span>, <span class="hljs-string">"output_fields"</span>: 
{<span class="hljs-string">"container.id"</span>:<span class="hljs-string">"fca790abe8c7"</span>,<span class="hljs-string">"container.image.repository"</span>:<span class="hljs-string">"docker.io/library/nginx"</span>,
<span class="hljs-string">"container.image.tag"</span>:<span class="hljs-string">"latest"</span>,<span class="hljs-string">"container.name"</span>:<span class="hljs-string">"nginx"</span>,<span class="hljs-string">"evt.time"</span>:1695903119619762538,
<span class="hljs-string">"k8s.ns.name"</span>:<span class="hljs-string">"default"</span>,<span class="hljs-string">"k8s.pod.name"</span>:<span class="hljs-string">"nginx-app-5c64488cdf-dnjm7"</span>,
<span class="hljs-string">"proc.cmdline"</span>:<span class="hljs-string">"ls"</span>,<span class="hljs-string">"user.name"</span>:<span class="hljs-string">"root"</span>}}
</code></pre>
<p>On peut retrouver notre alerte sur slack:</p>
<p><img src="https://cdn-images-1.medium.com/max/800/0*hT9_dFhqAhNyeLe3.png" alt /></p>
<h3 id="heading-presentation-de-falco-sidekick-ui">Présentation de Falco Sidekick UI</h3>
<p>Falco fournit une interface graphique facilitant la lecture des événements et des notifications. Pour ce test, nous avons simplement exposé le service falco-falcosidekick-ui en tant que service de type LoadBalancer pour pouvoir y accéder depuis notre navigateur.</p>
<p><img src="https://cdn-images-1.medium.com/max/800/0*cgWyEI2pmF9BM3eE.png" alt /></p>
<p>Nous pouvons constater que la règle detect_ls_command a bien été affichée avec la priorité WARNING que nous avons spécifiée dans le fichier custom-rule.yaml.</p>
<p><img src="https://cdn-images-1.medium.com/max/800/0*eGBuQrs3Ei54c4K5.png" alt /></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>En conclusion, notre exploration actuelle n’a fait qu’effleurer la surface des immenses possibilités et intégrations offertes par Falco. Cet outil offre une panoplie de fonctionnalités pour la surveillance et la sécurisation de vos environnements Kubernetes, et son potentiel va bien au-delà de ce que nous avons vu jusqu’à présent. Dans les prochains articles, nous plongerons plus profondément dans les capacités de Falco, explorant davantage ses fonctionnalités avancées, ses options de configuration et d’intégration, ainsi que les meilleures pratiques pour l’utiliser efficacement dans divers scénarios. Restez à l’écoute pour en apprendre davantage sur la puissance et la flexibilité que Falco peut apporter à votre infrastructure de conteneurs !</p>
]]></content:encoded></item></channel></rss>