Traefik is an open-source, cloud-native reverse proxy and load balancer that simplifies the deployment and management of applications across multiple servers or containers. With Traefik, developers can easily and seamlessly route traffic to the appropriate service instance and ensure high availability, reliability, and security. In this article, I'll explore the features and limitations of Traefik as a reverse proxy and load balancer for containers.
We take a look at Uptime Kuma, an open-source, self-hosted monitoring tool for websites, APIs, and services. It allows you to keep track of the uptime, downtime, and response times of your applications. One of the recommended ways to deploy Uptime Kuma is to use Docker containers, as they allow for easy installation, scaling, and management.
HashiCorp Nomad is a powerful orchestration and scheduler tool that can be an easily operated Kubernetes alternative. Nomad provides an orchestrator for containers, virtual machines, and other resources. The de facto standard for a container orchestrator today is Kubernetes. However, Kubernetes is extremely challenging and complex. It requires a specialized skillset that can present a barrier to entry regarding running production workloads in self-hosted clusters.
Il faut comprendre que la surveillance n'est pas une finalité, mais un cheminement. Les organisations étant de plus en plus nombreuses à migrer dans le cloud, elles doivent apprendre à se protéger et à détecter où elles se situent et la maturité de leurs équipes qui gèrent des projets dans le cloud.
A Docker registry allows your organization's users to store and distribute Docker images, which are used to create and run containers. There are two main types of registries in Docker: public and private. In this post, you will learn how to configure a private Docker registry.
Using a private DNS server improves the security, privacy, and performance of your network. In this post, you will learn how to configure a private DNS server in Docker.
Portainer allows you to manage Docker containers and Kubernetes with a graphical user interface (GUI) without ever touching the command line. Aside from this, what else is Portainer good for? Read on as we delve into the benefits of using Portainer.
Microk8s is a production-grade, easy-to-use Kubernetes distribution from the Ubuntu maker Canonical that provides quick time to value for development and production use cases. Microk8s aims to alleviate many of the challenges of working with Kubernetes clusters.
In my previous article, we discussed the MacVLAN network in Docker. Today, I will outline the differences between IPvlan and MacVLAN, explain the advantages of IPvlan, and show you how to create a VLAN with IPvlan.
Docker Desktop for Windows allows you to get a graphical user interface (GUI)-based handle on your Docker environment. It aims to make it easier for you to view and manage the state of containers and related artifacts in your environment.
The macvlan network driver allows you to assign a MAC address to Docker containers, which enables your containerized application to connect directly to your physical network.
Je travaille sur des environnements AWS depuis plus de 6 ans maintenant. Que ce soit en tant qu'Ops, architecte, ou architecte sécurité, il y toujours une constante que je constate autour de moi : l'IAM d'AWS est très souvent mal utilisé.
Dans ce billet, je vous propose de faire un petit tour d'horizon des raisons probables.
Parce que la doc vous indique de mettre du wildcard
La documentation est censée être le pilier sur lequel s'appuyer. Toutefois, force est d'admettre que la documentation d'AWS est loin d'être un exemple en ce qui concerne l'IAM.
Bien que la firme prône le least privilege, beaucoup de ses documentations en sont très loin.
Petit exemple tiré de la documentation officielle
De mon point de vue, la documentation est censé montrer des exemples les plus sécurisés possible pour "pousser" les utilisateurs à adopter les bons réflexes. Force est d'admettre que ce n'est pas le cas.
Parce que les APIs sont inconsistantes
Principal souci du modèle d'AWS, qui fait que chaque équipe produit est autonome : L'inconsistance des API.
Les même actions ne correspondent pas forcément au même verbes API...
Ainsi la simple action de créer un tag peut avoir plusieurs nom différents en fonction des services, comme par exemple :
elasticloadbalancing:addTags
ec2:createTags
ecr:tagResource
Mais comme ce serait trop simple, toutes les API n'ont pas forcément les mêmes type de cible.
Ainsi si je veux cibler des ressources en fonction de leurs tags, j'ai encore une fois des filtres différents :
Lorsqu'on met en place un modèle zero trust basé sur le least privilege, on va vouloir cloisonner au mieux les droits que l'on donne pour éviter toute action non désirée.
Maintenant on arrive au vrai problème.
En fonction des ressources, on pourra (ou non) filtrer correctement, mais pas forcément au même niveau.
Certaines ressources ont des ARN prévisibles, dans ce cas il est simple filtrer en amont (avant même que la moindre ressource soit créé).
D'autres fonctionne sur des identifiants internes créés par AWS, comme les security group par exemple.
Dans ce cas, il est parfois possible de filtrer sur la présence de certains tags, mais une fois de plus, pas tout le temps!
En effet, tous les services n'appliquent pas les tags de la même manière. Certains vont l'appliquer dès la création, d'autres après. Parfois tout se fait en un seul appel API, parfois en plusieurs...
Parce qu'il y a de multiples type de policies
J'aime à dire que l'IAM d'AWS est sans doute l'un des plus complet à ce jour. Toutefois, sa complétude vient aussi avec une complexité certaine : Le nombre de policies et les différentes couches qui s'appliquent à chaque évaluation.
Commençons par le plus simple : les policy IAM "classiques", que l'on appelle aussi "Identity based policies", ce sont les politiques que tout le monde exploite directement lorsque vous vous connectez à AWS. Ce sont aussi ces dernières qui sont utilisées quand vous utilisez des roles AWS.
Ensuite, il y a les "resource based policies", qui au contraire des précédentes sont directement attachées à un service, comme S3, SQS ou IAM (pour les trusts)
Puis viennent les boundaries, ces policies sont attachées à des roles ou utilisateurs pour filtrer les droits, un peu comme un tamis.
On pourrait aussi parler des SCP, qui englobent tout un compte ou une OU du service AWS Organization, pour appliquer des boundaries globales.
il y a enfin des policies qui peuvent être crée à la connexion avec un utilisateur fédéré : les session policies
Cinq type des policies qui peuvent toutes être utlisées en même temps lorsque vous accédez à un service, cinq!
Je ne peux que comprendre ceux qui se perdent dans ces multiples niveaux d'abstraction.
Parce qu'il y a beaucoup de limitations
Comme tous les services d'AWS, l'IAM a ses propres limitations.
Par exemple, un role IAM ne peut pas avoir plus de 10 managed policies d'attachées, et chacune de ces policies ne peut pas dépasser 6144 bytes (sans les espaces/sauts de ligne).
Un role ou un utilisateur ne peut pas avoir plus d'une boundary attachées.
Ces limitations empêchent de pouvoir composer des roles ou utilisateurs de manière optimale car si l'on veut restreindre au maximum, on est obligé de recréer des policy pour chaque ressource!
De plus quand on veut pouvoir donner des accès console + CLI, on est parfois obligé de donner plus de droit que souhaité car sinon on empêche la console de fonctionner correctement.
Parce que même le support y perd son latin
Mon dernier point et non des moindre : le support lui même s'y perd!
j'ai déjà eu à contacter le support à de multiples reprises pour des soucis d'IAM, et force est d'admettre que très souvent le support tatône pour trouver une policy fonctionnelle ou comprendre d'où peuvent venir les blocages.
Entre l'inconsistance des API, des ressources, des filtres et la complexité de certaines policies lorsqu'on veut filtrer efficacement, c'est parfois compliqué de suivre le fil.
Petit exemple de policy avec une condition (source : documentation officielle)
Comment améliorer les choses ?
Malgré tout les points que j'ai cité, il est toujours possible de faire "proprement" des policies (du moins du mieux possible), toutefois, ca demande du temps et de l'outillage.
Pour ma part, voici ce que j'utilise très (très) souvent :
La documentation officielle de toutes les API, avec leurs filtres : Cette documentation est relativement bien tenue à jour et vous permet d'avoir déjà une bonne vision d'ensemble
Le simulateur de policy d'AWS : qui vous permet de tester une policy sur une action particulière, très utile quand on veut filtrer sur des ARN ou tags par exemple.
Des linter de policy, que ce soit celui intégré dans AWS Access Analyzer ou des outils tiers comme Parliament par exemple
Il faut garder en tête que l'IAM d'AWS reste complexe de part sa puissance. Pour ma part, même après des années à en faire quotidiennement, je suis très loin d'en maîtriser 100% de ses aspects...
Sur les réseaux sociaux, blog et autres publications, on parle très souvent de nos réussites (moi le premier). Aujourd’hui, j’ai décidé de vous parler d’un de mes "échecs" (notez les guillemets) récents : le jour où j’ai compris que je ne faisais pas du bon code.
Résumé d’un drame en trois actes.
Situation initiale : seul au monde
J’ai commencé chez mon client actuel (le groupe SeLoger) en octobre 2019. À ce moment, je remplace quelqu’un de mon ESN (WeScale) qui quitte ce client.
Ma mission consiste a évaluer la sécurité AWS des comptes, puis de proposer des solutions, voire les mettre en place.
L’un des piliers que je propose et développe (en repartant de ce que mon prédécesseur avait fait) est donc de mettre un IAM (Identity and Access Management) fort sur AWS.
Vu mon passé d’Ops/FinOps/Architecte, l’automatisation, la fiabilité et la vitesse d’exécution sont des critères importants.
De même, je ne veux pas créer un gouffre entre les équipes DevOps et moi et j’ai donc besoin d’un outil que tout le monde (ou presque) puisse prendre en main.
J’ai donc développé plusieurs outils, principalement en python, dont le job principal est de déployer des permissions et de faire des liens avec des utilisateurs, de manière automatisée.
Je commence donc l’onboarding des applications, et de 25 repositories exploitant ces permissions, on arrive au bout d’un an à plusieurs centaines.
C’est là que les choses commencent à se gâter…
L’élément perturbateur : le scaling
Je commence à percevoir les limites de ce que j’ai mis en place :
Les permissions IAM ne sont pas optimisées, et sont parfois redondantes
Je tape parfois des limites de tailles de policies AWS suite au point précédent (J'en ai d'ailleurs parlé dans le passé)
Le déploiement des droits utilisateurs tombe parfois en timeout (et dure plusieurs heures !)
Je dois ajouter des fonctionnalités, mais mon script est devenu un gros tas de scotch au fur et à mesure des patches
De là, mon constat : un refacto est nécessaire. Si je veux pouvoir continuer d’ajouter des fonctionnalités quand les nouveaux besoins se manifestent, il me faut une base de code remise à plat.
Je défends donc cette idée auprès de mon manager (client) qui comprend effectivement l’intérêt et me donne donc le go pour faire ce travail.
Tout seul, on va vite, ensemble, on va loin
Nous sommes à ce moment en octobre-novembre 2020. Ce refacto est donc dans mon backlog, et il est prévu que je m’attarde dessus fin décembre/début janvier.
Au début de l’année, du renfort qui arrive. Un de mes collègues de WeScale arrive sur la mission pour me prêter main forte. Ce dernier a un bagage plus teinté développeur, là où j’ai un bagage très teinté Ops de mon côté.
Je lui présente donc un peu ce que j’ai fait, et je perçois assez vite qu’il voit des choses complexes ou qui ne sont pas à l’état de l’art.
J’essaie de le rassurer en lui disant que je travaille sur une remise au propre de tout ça pour repartir sur des bases saines.
Je travaille donc sur mon refacto, et assez vite, je lui soumets donc en code review mon code. J’échange avec lui en partageant la PR, et là, je me rends compte que la réaction n’est pas celle que j’attendais.
En effet, en échangeant avec lui, je perçois que ça reste bien trop complexe, et pas vraiment "clean", même sur ma nouvelle version.
Sur le coup, mon ego en prend un coup, et je me braque un peu. C’était en soirée, on arrête là, en se disant qu’on en reparlera au calme le lendemain.
Bien entendu, le soir, je cogite. Je me rends assez vite compte qu’il n’a pas tort : je ne suis pas un développeur. C’est le constat que je fais, jusqu’à présent, j’ai scripté des choses pour répondre à des besoins, mais je n’ai jamais vraiment développé.
Le lendemain, en discutant, je lui explique donc ce point : j’ai besoin d’aide pour savoir ce que je dois (re) voir. S’en suit une (très) longue discussion dans lequel il m’expose certains points qui pour lui ne vont pas :
Mon code est un seul script, ce qui empêche de l’étendre facilement
Le code est dans le même repository que la configuration des projets, ce qui ne lui permet pas d’avoir son cycle de vie propre
En l’état, on ne peut pas tester ce que j’ai fait
Le découpage de mon code n’est pas clair, certaines fonctions ont une complexité trop élevée
Une fois de plus, grosse claque pour l’ego, bien que les propos soit bienveillants, ce que j’entends c’est "ton code c’est de la merde" (ce qui n’était pas du tout le discours de mon collègue).
Le dénouement : apprendre à développer
Je n’ai pas de honte à le dire, ça a été une période assez violente pour moi, j’ai en effet dû appréhender beaucoup de concepts de développement assez rapidement :
Structurer physiquement mon code (structure des répertoires)
Structurer fonctionnellement mon code (logique du code)
Apprendre à packager proprement
Apprendre la base des tests unitaires
Basculer sur une logique d’objet
Revoir l’algorithmie
Et j’oublie sans doute des sujets. De plus, je suis donc dans une grosse remise en question sur la qualité de mon travail.
L’autre point que j’ai dû apprendre est de faire du développement "partagé", que quelqu’un d’autre doit être en mesure de comprendre/reprendre. Jusqu’à présent, bien que je sois en équipe, je développais souvent pour les besoins de mes projets, en solo.
La semaine suivante, je relivrais une préversion de mon script, qui était devenu entre temps une vraie application python, avec son repository, son pipeline de test, des precommit, et un push sur un Nexus du paquet final.
J’ai senti dès lors que le positionnement de mon collègue avait changé. Déjà, nous avions validé ensemble (dans les grandes lignes) la logique du code, ce qui faisait que l’ensemble était de fait plus lisible. Ensuite, j’avais aussi pris en compte au maximum ses remarques, et j’avais même poussé certains points plus loin que ce qu’il m’avait indiqué.
La structure même du code était, même pour moi, bien plus pertinente, et je pouvais voir facilement comment l’étendre en fonction des besoins.
Après quelques aller-retour sur des points qu’il avait remarqués (wording, algorithme, axes d’amélioration du code, etc.), ma PR était validée, et nous poussions la nouvelle version de l’application (dont 95 % du code avait changé) en production.
En conclusion : ce que j’ai appris
Pour conclure ce billet, je dirais que l’un des points les plus importants que j’ai appris durant ces derniers mois, c’est qu’il n’y a pas de honte à ne pas savoir. Pour ma part, je suis dans une démarche d’amélioration continue, et j’aime apprendre de nouvelles choses. Je considère que c’est une grosse partie de la richesse de nos métiers : nous n’avons jamais fini d’apprendre.
De plus, j’ai aussi compris qu’on ne s’improvise pas développeur, il y a beaucoup de concepts à appréhender :
Lisibilité du code
Testing
Algorihmie
Complexité
Documentation
Développer aujourd’hui, mais préparer demain en ayant un code potentiellement extensible
Ce sont des points sur lesquels je suis encore en train de monter en compétence (notamment la partie test qui est loin d’être simple pour quelqu’un qui débute).
De plus, cela a changé aussi ma manière de développer, je commence à avoir le réflexe de créer quelques tests avant d’écrire le code associé, je découpe beaucoup plus mon code en petites fonctions atomiques qui n’ont qu’un rôle bien défini, j’essaie d’utiliser des structures optimisées en fonction de mon besoin et j’en passe.
Enfin, l’un des points importants est que la critique peut parfois faire mal, mais c’est ce qui permet d’avancer. À ce sujet, je partage d’ailleurs beaucoup de choses remontées sur le blog jesuisundev par Mehdi Zed :
J’espère que ce billet vous a plu, et n’oubliez pas : l’échec, même temporaire, n’est pas une fatalité, c’est en faisant des erreurs que j’ai le plus appris pour ma part ! En soi, le code que j’avais fourni à l’origine n’était pas catastrophique, il répondait à mon besoin à l’instant T, mais il ne permettait pas de répondre aux besoins futurs.
Aujourd’hui, quand je regarde le code que j’ai fourni ces derniers mois, je sens bien que je ne suis plus au même niveau, et j’avoue que suis fier d’arriver un livrer un code bien plus propre et maintenable.