La migration vers le cloud est un passage obligé pour de plus en plus d’entreprises en raison de ses avantages par rapport au modèle On Premise. Le cloud permet d’avoir à disposition des ressources à la demande et allouées dynamiquement en fonctionnement de nos besoins. Les clients ne paient que ce qu’ils consomment en échange de pouvoir faire abstraction du hardware sous-jacent.
Plusieurs modèles de services Cloud existent et diffèrent en fonction de ce qui est à la charge du fournisseur Cloud, ou à la nôtre. Si vous travaillez dans le domaine, vous connaissez forcément le schéma suivant:
Un des principaux avantages du cloud est de ne pas avoir à investir dans du matériel que l’on devra gérer et renouveler à l’avenir. Plus un service est géré du côté du fournisseur Cloud, plus il est simple d’utilisation pour les entreprises mais son coût à l’utilisation est plus élevé. La facilité qu’apporte le cloud s'accompagne donc de défis tels que la gestion des coûts et la gouvernance des ressources, c'est pourquoi de plus en plus d'entreprises adoptent l'approche FinOps.
L’adoption du FinOps
Le FinOps (contraction des termes Finance et Opération) est un framework cherchant à optimiser le rapport entre le coût d’une infrastructure cloud et sa valorisation commerciale
Ce framework repose sur un certain nombre de principes (à retrouver sur le site de la fondation FinOps):
La mise en place d’une équipe FinOps: Pour que la démarche puisse être adoptée de façon cohérente à l’échelle d’une entreprise, il faut qu’une équipe soit en mesure d’établir des standards et des bonnes pratiques.
La collaboration des équipes: Pour mettre en place une démarche FinOps, il faut que les équipes y soient sensibilisées et y soient investies. Cela peut passer par la mise en place de métriques définies par les équipes elles-mêmes et les coûts qui y sont associés.
La responsabilisation des équipes: Pour que les équipes collaborent, il faut qu’elles soient responsabilisées sur leur utilisation du cloud (une équipe peut être responsable de l’utilisation et des coûts d’un compte AWS qui lui est dédié par exemple)
La mise en place de rapport de coûts: Les métriques mises en place par les équipes et celles définies par l’équipe FinOps doivent être rendues visibles facilement pour chaque équipe afin de pouvoir travailler dessus.
La valeur commerciale est le principal argument: Le FinOps ne consiste pas seulement à déduire les coûts d’une infrastructure cloud, c’est aussi d’injecter des moyens financiers au bon endroit afin de créer de la valeur.
Tirer avantage du cloud: Le Cloud permet d’avoir à disposition des ressources illimitées en fonction de nos besoins. Il faut veiller à ce que ces ressources soient correctement utilisées et les surveiller avec les outils mis à disposition par les fournisseurs (AWS Cost Explorer par exemple).
Mais quel est le rapport entre le FinOps et le titre de cet article ? Et bien pour faciliter l’adoption du framework FinOps, un certain nombre d’outils peuvent être utilisés. Il existe par exemple des services managés chez AWS, comme Cost Explorer, qui permet de visualiser les coûts d’un compte ou d’une organisation et de cibler les coûts à éliminer. AWS Config lui, est un service qui permet de faire un inventaire des ressources au sein d’un compte et de mettre en place des règles de conformité. Un rapport est ensuite disponible via la console AWS pour voir les ressources conformes et celles qui ne le sont pas. L’objet de cet article est une alternative Open Source de AWS Config, qui tend à apporter des fonctionnalités similaires tout en étant agnostique de tout Cloud provider, Cloud Custodian.
Cloud Custodian
Cloud Custodian (Custodian ou même C7n), est un outil open source, initié par l’entreprise Capital One (une banque américaine) en Python, conçu pour automatiser la gestion des ressources cloud. En utilisant Custodian, les équipes informatiques peuvent définir des règles et des politiques pour contrôler et faciliter la gestion des ressources, garantissant ainsi la conformité, la sécurité et l'optimisation des coûts dans différents environnements cloud (AWS, GCP, Azure, Oracle Cloud Infrastructure, Tencent Cloud et même Kubernetes).
Cloud Custodian a différentes fonctionnalités, il permet notamment de :
- Faire l’inventaire des ressources: En effet, Custodian permet de lister les ressources d’un compte AWS suivant leur type et suivant d’autres filtres (présence de tag ou non, état, nom par exemple)
- Forcer le tagging des ressources: Custodian permet de refuser la création de ressources suivant leur tag ou même de taguer des ressources automatiquement.
- Sécuriser l’infrastructure Cloud. Custodian permet par exemple de refuser l’utilisation de certaines AMI pour les instances EC2 en raison de failles de sécurité détectées, certains paramétrages dangereux (créer des bucket s3 publiques, laisser tous les ports ouverts sur une instance EC2 etc). De façon générale, Custodian permet de mettre en place des pratiques communes au sein d’une organisation pour éviter les vulnérabilités.
- Mettre en place des standards : Pour des besoins de conformité, on peut être amené à créer des règles de configurations pour les ressources AWS et de supprimer toutes les ressources qui ne respectent pas ces règles.
- Réduire les coûts inutiles: Custodian permet d’éteindre les instances EC2 en dehors des heures de travail, d’éteindre celles qui ne sont pas conformes au standards (afin d’éviter de laisser des instances non utilisées sur les comptes)
- Générer des alertes: C7n-mailer est un script développé par la communauté pour envoyer des alertes (via email, Slack ou autre outils de communication).
Comment ça marche ?
Custodian repose sur la création de règles (ou “policies”) qui vont permettre de lister un ensemble de ressources, répondant à un certain nombres de critères, sur lesquelles nous allons pouvoir effectuer des actions.
La création des règles Cloud Custodian se fait dans un fichier au format Yaml.
Définissons une première policy appelée “my_policy” dans un fichier policies.yaml. Nous définissons le type de ressource sur lesquelles la policy va s’appliquer (ici les instances AWS EC2). Nous utilisons ensuite un filtre qui permet de sélectionner les ressources impliquées (ici par exemple, je souhaite qu’elle s’applique sur toutes les instances EC2 qui n’ont pas de tag permettant d’identifier un propriétaire).
La liste des filtres possibles sur AWS est disponible sur la documentation officielle, (section "Common Filters").
Il faut ensuite définir une action qui sera appliquée sur ces ressources. Nous pouvons par exemple les arrêter, les tagger, envoyer une notification à un administrateur etc. Ici, nous allons simplement l’éteindre
La liste des actions possibles sur AWS est disponible sur la documentation officielle de Custodian (section "Common Actions").
Les types de déploiement
Il existe plusieurs façons d’appliquer cette policy:
Mode pull
Dans ce mode, l’exécution de Custodian permet d’exécuter la règle ponctuellement et seulement sur les ressources déjà existantes sur le ou les comptes AWS cibles. On peut, par exemple, passer par la CLI Custodian depuis son poste de travail. Custodian va alors rechercher les ressources correspondantes aux différents filtres et effectuer les actions déclarées en utilisant les droits de l'utilisateur.
Note : ce fonctionnement peut aussi être fait au sein d’une pipeline CI/CD ou d’un cron.
Mode événementiel
Dans ce fonctionnement, utilisable en ajoutant une section “mode” dans la configuration de chaque règle, Custodian va à minima construire une ressource AWS Lambda et une ressource CloudWatch Event. La fonction Lambda sera dédiée à l'exécution d’une règle en particulier, déclenchée par CloudWatch Event. Les événements CloudWatch peuvent être paramétrés de différentes façons. Par exemple:
Déclenchement par Cloud Trail
Dans cet exemple, un événement CloudWatch est créé lorsque CloudTrail détecte la création d’une nouvelle ressource dans le compte.
Custodian ne crée pas de réelle stack, mais plutôt une fonction Lambda qui sera déclenchée par des événements.
Déclenchement périodique
Dans cet exemple, CloudWatch crée un événement à intervalles réguliers afin de déclencher la lambda.
Il existe une multitude de configurations possibles pour la lambda. Nous pouvons lui renseigner un rôle ou un autre compte sur lequel exécuter la règle Custodian (un compte de sécurité par exemple).
Il existe d’autres modes encore :
- ec2-instance-state: Custodian est exécuté dans une Lambda qui est déclenchée par un changement d’état d’une instance EC2
- asg-instance-state: Custodian est exécuté dans une Lambda qui est déclenchée par un changement d’état d’un autoscaling
- guard-duty: Custodian est exécuté dans une Lambda qui est déclenchée par un événement de AWS Guard Duty
- config-rule: Custodian est exécuté dans une Lambda qui est déclenchée AWS Config
- phd: Custodian est exécuté dans une Lambda qui est déclenchée par un événement AWS Personal Health Dashboard
c7n-mailer, le générateur de notifications
Parmi les outils ajoutés par la contribution de la communauté Open Source sur Cloud Custodian, un qui me paraît être le plus intéressant est peut-être c7n-mailer qui permet de générer des notifications et ajouter donc l’action “notify” à la liste des actions de Custodian. C7n-mailer déploie une stack composée d’un bus d’événements CloudWatch (maintenant EventBridge) et d’une ressource Lambda. Custodian va s’inscrire à la queue SQS et renvoyer les messages récupérés vers un canal de discussion ou outil d’alerting.
C7n-mailer permet d’envoyer des notifications via email, vers Datadog, Splunk ou encore Slack.
Démonstration
Contexte
Imaginons que nous sommes une équipe nommée “DevOps” dans une entreprise. Nous avons un seul compte AWS et nous souhaitons que Cloud Custodian veille à ce que :
- Chaque instance EC2 doit être taguée par le nom d’une équipe (tag:Team), si ce n’est pas le cas, elle doit être automatiquement résiliée. (Principe du FinOps: Responsabiliser les équipes)
- Chaque instance EC2 doit s'éteindre entre 20h le soir et se rallumer à 7h le lendemain pour économiser des ressources. (Principe du FinOps: Tirer avantage du cloud)
- Si une instance existe depuis plus de 120 jours, une notification doit être envoyée à l’équipe qui en est responsable via un canal slack afin de vérifier son utilité. (Principe du FinOps: La collaboration des équipes + Responsabiliser les équipes + Tirer avantage du cloud)
La policy doit être vérifiée à chaque fois qu’une nouvelle ressource est créée.
Installation de Custodian
Installer C7n:
python3 -m venv custodian
source custodian/bin/activate
pip install c7n
(L’utilisation de venv sous Python permet de créer un environnement virtuel appelé custodian sur lequel nous allons installer c7n (Cloud Custodian). La subtilité n’est pas importante ici, nous aurions pu installer directement Custodian sur notre machine.
Pour une utilisation de Custodian sur AWS, cette installation suffit. En ce qui concerne son utilisation sur d’autres providers, il faut installer d’autres packages. Par exemple, pour Azure:
pip install c7n_azure
Vérifions que nous avons bien installé l’outil:
(custodian) role-admin-sre-ops-federated:~/environment $ custodian version
> 0.9.33
Intégration de Custodian dans son IDE
Dans le cadre de cette démonstration, j'ai préféré utiliser une instance Cloud9 pour ne rien avoir à installer sur mon poste de travail et ne pas avoir à gérer de credentials AWS, mais si vous allez utiliser Custodian pour créer des règles de conformité, vous pourriez l’utiliser en local. C’est pourquoi je propose de vous montrer comment l’intégrer à votre IDE préféré. Personnellement, j’utilise VS Code. Si votre IDE supporte le protocole LSP (Langage Server Protocol), vous pouvez suivre ces différentes étapes :
Un serveur de langage est un programme qui offre des services liés à un langage de programmation spécifique. Il fournit généralement des fonctionnalités telles que l'autocomplétion, la vérification syntaxique, la documentation en temps réel, etc., pour aider les développeurs à écrire du code de manière plus efficace.
Commençons par exporter le schéma de Custodian
custodian schema --json > schema.json
Stockez le quelque part où vous pourrez le retrouver. Ensuite, rendez-vous sur votre IDE et installez un plugin YAML, par exemple, j’ai pris le premier sur lequel je suis tombé, développé par Red Hat. Allez dans les paramètres du plugin et descendez jusqu’à la section “Yaml:Schemas”
Vous pouvez alors éditer le fichier de paramètre de l’extension en ajoutant le chemin vers le schéma de Custodian.
{
…
"yaml.schemas": {
"C:/Users/boiss/Documents/schema.json":"*yml"
}
…
}
Normalement, vous devriez avoir de l’auto complétion sur votre VS Code.
Pour ma part, je ne l’ai pas trouvé très efficace, peut être que mon paramétrage n’était pas parfait.
Maintenant que la CLI Cloud Custodian est bien installée sur notre instance Cloud9, nous allons pouvoir créer nos fichiers de règles de conformité:
.
├── tag-policy.yaml
├── start-stop-policies.yaml
└── old-instances-policy.yaml
Tag des ressources
La première chose que nous souhaitons, c’est de vérifier que chacune des instances EC2 qui sera créée sera correctement taguée avec le nom de l’équipe qui est responsable de cette instance ainsi que le nom du projet dans lequel elle est utilisée. Si ce n’est pas le cas, elle devra être arrêtée.
Pour ce faire, créons une policy ec2-tag, dans un fichier que nous appellerons tag-policy.yaml.
Avec cette configuration, Custodian va faire l’inventaire des instances EC2 qui n’ont pas de tag pour le nom de l’équipe et pour le nom du projet. Une condition est rajoutée afin de ne cibler que les instances lancées dans la région Irlande afin de ne pas prendre le risque d'éteindre des ressources involontairement (dans le cadre de la démonstration j'utilise une sandbox partagée).
Lançons la CLI avec cette première configuration:
$ custodian run --dryrun -s . tag-policy.yaml
> 2024-01-01 19:16:37,242: custodian.policy:INFO policy:ec2-tag resource:ec2 region:eu-west-1 count:1 time:0.37
Cloud Custodian construit alors un dossier du nom de la policy (si plusieurs policies sont paramétrées dans le fichier, il construira un dossier pour chacune), avec 3 fichiers:
- custodian-run.log: Contenant les logs de l’exécution de la commande
- metadata.json: Contenant les paramètres de la policy
- resources.json: Contient la liste de toutes les ressources qui ont été listées par Custodian (ici celles qui n’ont pas les bons tags) ainsi que toute leur configuration.
Regardons en détail le fichier resources.json:
[
{
"AmiLaunchIndex": 0,
"ImageId": "ami-0f2e389436f620398",
"InstanceId": "i-01864dc23efc35282",
"InstanceType": "m5.large",
"LaunchTime": "2024-01-01T18:47:16+00:00",
"Monitoring": {
"State": "disabled"
},
"Placement": {
"AvailabilityZone": "eu-west-1b",
"GroupName": "",
"Tenancy": "default"
},
…………
"Tags": [
…
{
"Key": "aws:cloudformation:stack-name",
"Value": "aws-cloud9-paul-9212da96bb7447eca2097197540b82c2"
},
{
"Key": "AutoTag_CreateTime",
"Value": "2024-01-01T18:47:16Z"
},
{
"Key": "Name",
"Value": "aws-cloud9-paul-9212da96bb7447eca2097197540b82c2"
},
……
],
……
"c7n:MatchedFilters": [
"tag:Team",
"tag:Project"
]
}
]
Nous pouvons constater qu'une seule instance a été listée par Custodian. Tout son paramétrage nous est accessible : le type d’instance, l’AMI, le subnet dans lequel elle a été lancée, le moment de sa création, ses tags etc. Ici nous pouvons voir qu’il s’agit de l’instance Cloud9 sur laquelle nous travaillons.
Nous ne souhaitons pas qu’elle soit arrêtée, nous devons donc ajouter un filtre supplémentaire.
De cette façon, notre instance Cloud9 ne sera pas détectée.
Ajoutons également le mode événementiel afin que toutes les prochaines instances soient également évaluées par cette règle.
Pour ce faire, nous devons créons un rôle IAM en amont, via Terraform, qui sera utilisé par les fonctions lambda:
Ici, je prends la liberté de donner des droits étendus à la fonction Lambda qui sera crée mais dans de réelles conditions, il est plus judicieux de limiter ses droits.
Modifions ensuite la policy
Lançons cette nouvelle règle et regardons ce qu’il se passe:
(custodian) role-admin-sre-ops-federated:~/environment/conformity-rules $ custodian run -s . tag-policy.yaml
> 2024-01-01 22:46:15,378: custodian.policy:INFO Provisioning policy lambda: ec2-tag region: eu-west-1
> 2024-01-01 22:46:15,632: custodian.serverless:INFO Publishing custodian policy lambda function custodian-ec2-tag
Une ressource Lambda a bien été créée, et si nous créons une instance EC2, celle-ci va bien être détruite par Custodian.
A partir de ce moment-là, à chaque fois que je lance une instance EC2, elle est automatiquement résiliée par Custodian car ne possède pas les bons tags.
Cet article vise à faire une démonstration de Custodian, les règles ne sont pas forcément les plus judicieuses. Dans ce cas précisément, il serait plus intéressant d’avoir une règle qui permet de tagger automatiquement le nom du créateur de la ressources si celle-ci n’a pas les bons tags et de générer une notification avec une nouvelle règle pour avertir l’utilisateur de son erreur et ensuite planifier un arrêt de l’instance après quelques jours.
Extinction des instances hors des heures de travail
La deuxième exigence de notre entreprise est qu’il faut éteindre les instances en dehors des heures de travail (entre 20h et 7h le lendemain). La documentation officielle de Cloud Custodian nous fournit déjà un exemple (à noter que le paramètre default_tz a été adapté pour correspondre au fuseau horaire de la France. Pour plus de détails voir cette documentation):
L’application de cette règle va créer une lambda qui va arrêter toutes les instances EC2 âgée de plus d’une heure (afin d’éviter que quelqu’un qui travaille ne se voit arrêter son instance) et ayant le tag maid_offhours (le tag par défaut) hors des heures de travail (7:00 à 19:00). La Lambda va s'exécuter toutes les heures pour vérifier si on est dans les heures de travail ou non. Cette règle simple permet de faire quelques économies sur sa facture AWS.
Old Instance
La 3e exigence est : “Si une instance existe depuis plus de 120 jours, une notification doit être envoyée à l’équipe qui en est responsable via un canal slack afin de vérifier son utilité”.
La première chose à faire est de créer une espace de travail Slack et de créer une application qui sera capable d'envoyer des notifications en suivant ce lien de la documentation officielle de Slack. Il faut absolument activer la feature Incoming Webhooks. Une fois cela fait, vous aurez à disposition l'url du webhook par lequel Custodian devra passer pour envoyer des notifications sur Slack (cela ressemble à : https://hooks.slack.com/services/XXX/XXX/XXX).
Pour cette règle, nous allons avoir besoin d’utiliser une action de type notify. Pour ce faire, nous avons besoin d’utiliser l’extension c7n-mailer de Custodian.
Commençons par l’installer:
pip install c7n-mailer
Créons une queue SQS, via Terraform, qui sera chargée d'acheminer les messages vers la stack de notification.
Créons ensuite un fichier de configuration du mailer:
Lançons ensuite la commande de c7n-mailer:
c7n-mailer --config mailer.yaml --update-lambda
En appliquant cette commande, Custodian va créer la fonction lambda qui sera chargée de récupérer les retours des exécutions de Custodian par les autres fonctions lambda et de les envoyer vers Slack.
Puis créons notre policy Cloud Custodian:
Si tout est paramétré correctement de votre côté, vous devriez recevoir une notification de ce type dans le canal configuré lors du paramétrage de l'application Slack:
Cette notification est générique, elle nous renvoit la ressource qui a été détectée par Custodian (j'ai légèrement triché pour ne pas avoir à attendre 120 jours) mais il est possible de la personnaliser pour avoir plus de détails sur les alertes. Il suffit de suivre la documentation ou ce très bon article que j'ai trouvé.
Nettoyage de la démonstration
Après cette démonstration, j’ai voulu nettoyer la sandbox. Il existe un utilitaire développé en Python pour supprimer les lambda créés par Custodian appelé MUGC (mu Garbage Collection). Il permet d'éviter d'avoir à supprimer toutes les ressources crées par Custodian à la main, ce qui peut être pénible à l'échelle d'une organisation avec plusieurs comptes AWS.
Cloud Custodian vs AWS Config
AWS a son propre service d’évaluation de configuration dont je parlais au début de cet article, AWS Config. Ce service, accessible depuis la console AWS, permet d’avoir une vue détaillée sur les configurations des services (EC2, ECS, VPC etc) d’un compte AWS, de créer des règles . Comparons les 2 outils avec le schéma suivant:
Comme chacun de ces outils a ses avantages et ses inconvénients, on peut se poser la question d’utiliser l’un ou l’autre. Config est un service managé par AWS (donc payant) qui permet d’avoir une vue d’ensemble sur l’ensemble des configurations (et en plus elles sont versionnées) des ressources au sein de son compte AWS et permet de créer des alertes si certaines ressources ne respectent pas des règles de conformités. Il est possible de faire de la remédiation (ou correction) de ressources en passant par le service AWS Systems Manager Automation. Cloud Custodian est un outil open source qui permet de créer des règles de conformité en YAML et d’effectuer des actions directement sur les ressources qui peuvent être sur différents Cloud Provider ou même sur Kubernetes. Ces actions sont automatisables (extinction des instances la nuit par exemple) et que cette automatisation est déjà prévues par Custodian.
Conclusion
J'ai croisé Cloud Custodian dans le cadre d'une mission et son utilisation m'avait paru assez simple et amusante, malgré une documentation qui n'est pas des plus claire et fournie et malgré le fait qu'il y ait peu d'articles sur cet outil. Cloud Custodian propose à peu près les même services qu'AWS mais a l'avantage d’être compatible avec d’autres environnements (même si il faudra ré-écrire les policies) comme GCP, Azure ou encore Kubernetes. Il bénéficie, également, de l’expérience de ses utilisateurs et d'être open source pour se voir ajouter un bon nombre d’extensions permettant de répondre à des besoins encore insoupçonnés par la plupart d’entre nous. Nous avons vu dans cet article que Cloud Custodian pouvait être mis en place pour adopter certains principes du FinOps (La collaboration des équipes, Responsabiliser les équipes, Tirer avantage du cloud etc) mais il peut aussi être utilisé dans une approche Green car n'oublions qu'une ressource éteinte lorsqu'on n'en a pas besoin permet de réduire sa consommation d'électricité. N’hésitez pas à rejoindre le channel Slack du projet pour recevoir l’aide de la communauté qui est plutôt active et suivre les nouvelles fonctionnalités.
Ressources:
- Les principes du FinOps :
https://www.finout.io/blog/main-principles-of-finops
- Documentation AWS:
https://cloudcustodian.io/docs/aws/gettingstarted.html
- What is Cloud Custodian?
https://www.youtube.com/watch?v=bGtQiGQOkHs
- Controlling you cloud cost with Cloud Custodian
https://www.youtube.com/watch?v=OjI2dDeo154
- Définition du FinOps
https://www.talend.com/fr/resources/finops-definition/
- La sécurité dans le cloud démystifiée avec Cloud Custodian
https://blog.wescale.fr/la-securite-dans-le-cloud-demystifiee-avec-cloud-custodian
- Cloud Custodian et Capital One
https://www.capitalone.com/tech/cloud/cloud-custodian-cncf-donation/
- c7n-mailer: Custodian Mailer
https://cloudcustodian.io/docs/tools/c7n-mailer.html#slack
- AWS Config, Cloud Custodian, or Both?
https://spoofing.medium.com/aws-config-cloud-custodian-or-both-98908e0b24ea
- Nettoyer ses ressources créées par Cloud Custodian avec mugc
https://github.com/cloud-custodian/cloud-custodian/blob/main/tools/ops/README.md
- Utilisation du mode Cloud Trail de Custodian
https://medium.com/@zohaib.hassan78669/cloudcustodian-policy-with-cloudtrail-mode-308e6efdef1b