Aller au contenu principal

· 6 minutes de lecture
TheBidouilleur

[ Cet article provient de mon ancien-blog, celui-ci sera également disponible dans la partie "Documentation" du site ]

Introduction

Bientot 7 ans que mon infra principale est sous Proxmox. C'est l'hyperviseur dans lequel j'ai le plus confiance, et qui est également gratuit. Dès que je dois déployer plus de 2 machines virtuelles et qu eje peux choisir l'environnement : Proxmox sera mon premier choix. Il propose une webui complète et efficace, sans oublier l'avantage des outils en cli. Je n'exclue pas qu'un jour, je puisse changer d'environnement. Et aujourd'hui, j'ai de nouveaux besoins dans mon hyperviseur : Automatiser un déploiement complet de mon infrastructure, et comme je vais pas réinstaller chaque machine individuellement, je dois partir d'une "base" qui servira de template pour que le système des machines soit pré-configuré comme je le souhaite. Et cette fameuse template, je peux la faire à la main.... ou je peux la déployer automatiquement via Packer !

Qu'est ce que Packer?

Packer est un outil développé par hashicorp (une entreprise qui fourni des programmes open-sources dans l'univers du devops) promettant de déployer une machine virtuelle de template de manière automatique.

Dans un cas pratique, Packer va se connecter à votre cloud-publique(aws, oracle, scaleway) / hyperviseur(proxmox, qemu, esxi) pour envoyer les instructions permettant d'installer la machine virtuelle

Dans mon cas, je me suis amusé à déployer des templates Alpine et debian sous Qemu et Proxmox.

Comment fonctionne Packer ?

Packer possède peu de dépendances, il a besoin d'un hyperviseur/cloud publique, d'un accès à "l'écran" de la machine virtuelle, et d'un accès ssh pour que Packer vérifie que l'installation s'est bien terminée (et également pour lancer un outil de gestion de config comme ansible.

Un peu de vocabulaire#

On appelle Builder l'endroit où Packer déploie la VM, dans mon cas : c'est Proxmox ! Et le terme provisionner désigne l'outil qui va finir la configuration de la VM après Packer (Ex: Ansible).

Créer notre première template

Avant de s'attaquer à un gros poisson comme debian, on va commencer par un système plus simple à installer : Alpine. L'installateur de Alpine va poser une dizaine de questions, une à une. Il existe un système de fichier-réponse qui va répondre automatiquement aux questions mais je n'ai pas réussi à executer ce fichier sous alpine. (Uniquement sous Alpine, le fichier réponse fonctionne sous debian).

Si le sujet vous interesse, je vous renvoie vers ce lien: Wiki Alpine Answer-file.

Comme je ne peux pas utiliser de fichier réponse : nous allons répondre aux questions manuellement.

Retrouvez le code source

Dans la suite de cet article, je vais présenter le fonction de ce dépot : packer-alpine-proxmox.

Voici mon fichier Packer répondant aux questions:

{    "description": "Build Alpine Linux 3 x86_64 Proxmox template",    "variables": {
        "proxmox_url": "{{env `proxmox_url`}}",        "proxmox_username":"{{env `proxmox_user`}}",         "proxmox_password": "{{env `proxmox_password`}}",         "proxmox_host": "{{env `proxmox_node`}}",
        "storage_name": "{{env `storage_name`}}",        "bridge": "{{env `bridge`}}",        "vm_id": "9001",        "vm_name": "alpine3-tf",        "template_description": "Alpine Linux 3.11 x86_64 template built with packer",        "vm_memory": "1024",
        "ssh_username": "root",        "ssh_password": "{{env `ssh_password`}}"    },    "sensitive-variables": ["proxmox_password", "ssh_password" ],    "provisioners": [      {        "type": "ansible",        "playbook_file": "./playbook/provisioning.yml",        "ansible_env_vars": ["ANSIBLE_FORCE_COLOR=True" ]      }    ],    "builders": [        {            "type": "proxmox",            "proxmox_url":  "{{user `proxmox_url`}}",            "insecure_skip_tls_verify": true,            "username": "{{user `proxmox_username`}}",            "password": "{{user `proxmox_password`}}",            "vm_id":  "{{user `vm_id`}}",            "vm_name": "{{user `vm_name`}}",            "template_description":"{{user `template_description`}}",            "memory": "{{user `vm_memory`}}",            "cores": "2",            "os": "l26",            "http_directory": "http",
            "node": "{{user `proxmox_host`}}",            "network_adapters": [              {                "model": "virtio",                "bridge": "{{user `bridge`}}"              }            ],            "disks": [              {                "type": "virtio",                "disk_size": "16G",                "storage_pool": "{{user `storage_name`}}",                "storage_pool_type": "directory",                "format": "qcow2"              }            ],            "ssh_username": "{{user `ssh_username`}}",            "ssh_password": "{{user `ssh_password`}}",            "ssh_timeout": "15m",            "ssh_certificate_file": "/root/id_rsa",             "iso_file": "{{user `storage_name`}}:iso/alpine-virt-3.15.0-x86_64.iso",            "unmount_iso": true,            "boot_wait": "15s",            "boot_command": [                "<wait25>root<enter><wait4>",                "setup-alpine<enter><wait8>",                "<enter><wait4>",                "alpine-tf<enter><wait4><enter><wait4>",                "dhcp<enter>",                "<wait5>n<enter><wait5>",                "{{user `ssh_password`}}<enter><wait5>",                "{{user `ssh_password`}}<enter><wait>",                "<wait5>",                "Europe/Paris <enter><wait2><enter><wait5>",                "n<enter>",                "<wait1>1<enter><wait3>",                "<enter><wait2>",                "vda<enter>",                "lvm<enter>",                "sys<enter>",                "<wait2>",                "y<enter><wait35>",
                                "reboot <enter>",                "<wait65>",                                "root<enter><wait8>",                "{{user `ssh_password`}}<enter><wait5> ",                "<wait10>",
                "apk update && apk add curl<enter>",                "mkdir -p ~/.ssh<enter>",                "touch ~/.ssh/authorized_keys<enter><wait5>chmod 600 ~/.ssh/authorized_keys<enter><wait5>",                "curl http://{{ .HTTPIP }}:{{ .HTTPPort }}/authorized_keys >> ~/.ssh/authorized_keys<enter>",                "echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config <enter>",                wait2>service sshd restart <enter> <wait2>",                "curl http://{{ .HTTPIP }}:{{ .HTTPPort }}/repositories > /etc/apk/repositories<enter>",                "<wait>apk update <enter>",
                "apk add python3<enter><wait1>",                "curl https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py<enter> <wait2>",                "python3 /tmp/get-pip.py <enter> <wait2>",
                "apk add qemu-guest-agent<enter><wait3>",                "rc-update add qemu-guest-agent<enter>",                "service qemu-guest-agent start<enter>"

            ]        }    ]}

Nous allons rapidement décortiquer la structure de ce Packer :

  • la partie "Variable" concerne les variables statiques et/ou variables d'environnements (On va voir ça un peu plus tard)
  • Provisionner designe la commande que l'on va lancer après la création de la template
  • et ce qui concerne la template elle-même (paramètres, hyperviseurs...) est dans la partie builder

et la partie boot_command dans Builder est la liste de toutes les entrées au clavier que Packer va taper, On y place souvent le téléchargement du Preseed de Packer vers la VM.

petite explication sur le transfert de fichier de packer vers la template : Packer, à son lancement, va créer un serveur web avec le contenu du dossier http/, si on y place des fichiers à l'interieur, on peut dire à packer de taper la commande suivante pour récupérer des fichiers. (Ex: Preseed, clés ssh etc..)

curl  http://{{ .HTTPIP }}:{{ .HTTPPort }}/fichier

Ainsi, dans cette installation d'Alpine, je vais répondre une à une aux questions, avec des timer pré-configurés (qui se comptent en seconde). Et à la fin de l'installation, nous lançons le playbook provisionning qui me permet d'installer les dépendances utiles à mes VMs. Il n'est pas necessaire d'aller très loin dans le playbook : ça reste une template.

Build.sh, Vault, et la création de authorized_keys#

Si vous êtes allé voir mon dépot (dont le lien est plus haut), vous avez surement vu le fichier buid.sh.

#!/bin/bash#export ssh_password=$(vault kv get -field root_password secrets/password)export proxmox_password=$(vault kv get -field proxmox_password kv/wysux)export proxmox_user=$(vault kv get -field proxmox_user kv/wysux)export proxmox_node=$(vault kv get -field proxmox_node kv/wysux)export proxmox_url=$(vault kv get -field proxmox_url kv/wysux)
export ssh_password="toto13"
export bridge="vmbr0"export storage_name="local"
rm http/authorized_keys || truefor f in ssh/*.pub; do        name_of_key=$(echo $f | cut -d "/" -f2 )    echo -e "#$name_of_key" >> http/authorized_keys     key=$(cat $f)    echo -e "$key" >> http/authorized_keysdone
packer build alpine-3-amd64-proxmox.json

ce fichier va donner les paramètres essentiels à Packer. Les premières variables sont les identifiants pour se connecter à proxmox

si vous n'utilisez pas vault, n'hésitez pas à remplacer les commandes le concernant par le contenu des variables.

· 6 minutes de lecture
TheBidouilleur

[ Cet article provient de mon ancien-blog, celui-ci sera également disponible dans la partie "Documentation" du site ]

Introduction#

Bientot 7 ans que mon infra principale est sous Proxmox. C'est l'hyperviseur dans lequel j'ai le plus confiance, et qui est également gratuit. Dès que je dois déployer plus de 2 machines virtuelles et qu eje peux choisir l'environnement : Proxmox sera mon premier choix. Il propose une webui complète et efficace, sans oublier l'avantage des outils en cli. Je n'exclue pas qu'un jour, je puisse changer d'environnement. Et aujourd'hui, j'ai de nouveaux besoins dans mon hyperviseur : Automatiser un déploiement complet de mon infrastructure, et comme je vais pas réinstaller chaque machine individuellement, je dois partir d'une "base" qui servira de template pour que le système des machines soit pré-configuré comme je le souhaite. Et cette fameuse template, je peux la faire à la main.... ou je peux la déployer automatiquement via Packer !

· 8 minutes de lecture
TheBidouilleur

[ Cet article provient de mon ancien-blog, celui-ci sera également disponible dans la partie "Documentation" du site ]

Introduction

Depuis que jai commencé l'informatique (depuis un peu moins d'une dizaine d'année), je ne me suis jamais préoccupé de comment je visualisais mes logs. Un petit view par ci, un gros grep par là.. mais aucune gestion avancée.

J'ai basé ma supervision sur Zabbix et Grafana qui m'affichent les metriques de chaque machine virtuelle individuellement. Et même si c'est bien pratique, je n'ai presque aucun visuel sur l'état de mes applications ! J'ai donc décidé de me renseigner sur Graylog et Elastic Search proposant un stack assez fiable et facile à mettre en place. Puis en voyant les ressources demandées, j'ai remis ce besoin à "plus tard", et j'ai remis "plus tard" à l'année prochaine.. Et ainsi de suite !

2 ans plus tard...

Aujourd'hui (Decembre 2021), une grosse faille 0day est dévoilée concernant Log4J, et on ne parle pas d'une "petite" faille, c'est une bonne grosse RCE comme on les aime !

Je ne suis pas concerné par Log4J, ce n'est pas utilisé dans Jenkins, et je n'ai aucune autre application basée sur Java ouverte sur internet. Mais j'aurai bien aimé savoir si mon serveur a été scanné par les mêmes IP que l'on retrouve sur les listes à bannir. Et c'est avec cet évenement que j'ai décidé de me renseigner sur "Comment centraliser et visualiser ses logs?".

Le choix du stack

Un stack est un groupement de logiciel permettant de répondre à une fonction. Un exemple classique est celui du stack "G.I.T." (et non pas comme l'outil de versioning!) :

  • Grafana
  • Influxdb
  • Telegraf

C'est un stack qui permet de visualiser les mectriques de différentes machines, InfluxDB est la base de donnée stockant les informations, Telegraf est l'agent qui permet aux machines d'envoyer les métriques, et Grafana est le service web permettant de les visualiser.

Comme dit dans l'introduction, j'utilise Zabbix qui me permet de monitorer et collecter les metriques, et j'y ai couplé Grafana pour les afficher avec beaucoup de paramètrages.

Dans la centralisation de logs (et la visualisation), on parle souvent du stack suivant:

ELK:

  • ElasticSearch
  • Logstash
  • Kibana

Mais ce stack n'est pas à déployer dans n'importe quel environnement, il est efficace, mais très lourd.

Dans ma quête pour trouver un stack permettant la centralisation de logs, j'apprécierai utiliser des services que je dispose déjà.
Et voici le miracle à la mode de 2021 ! Le Stack GLP : Grafana, Loki, Promtail.

Stack GLP#

Là où j'apprécie particulièrement ce stack, c'est qu'il est léger. Beaucoup plus léger que ELK qui, même si très efficace, demande beaucoup.

De même que Graylog2 + Elastic Search (une très bonne alternative) qui demande presque un serveur baremetal low-cost à lui seul.

Alors que Grafana / Loki ne demanderont que 2Go pour fonctionner efficacement et sans contraintes. (Grand maximum, à mon échelle : j'utiliserai beaucoup moins que 2Go)

Installer notre stack

Je pars du principe que tout le sait installer un Grafana, c'est souvent vers ce service que les gens commencent l'auto-hebergement (en même temps, les graphiques de grafana sont super sexy !).

Mais si vous n'avez pas encore installé votre Grafana (dans ce cas, quittez la salle et revenez plus tard), voici un lien qui vous permettra de le faire assez rapidement

Par simplicité, je ne vais pas utiliser Docker dans cette installation.

Partie Loki#

J'ai installé Loki sur un conteneur LXC en suivant le guide sur le site officiel ici. Je passe par systemd pour lancer l'executable, et je créé à l'avance un fichier avec le minimum syndical (qui est disponible sur le github de Grafana)

auth_enabled: false
server:  http_listen_port: 3100  grpc_listen_port: 9096
common:  path_prefix: /tmp/loki  storage:    filesystem:      chunks_directory: /tmp/loki/chunks      rules_directory: /tmp/loki/rules  replication_factor: 1  ring:    instance_addr: 127.0.0.1    kvstore:      store: inmemory
schema_config:  configs:    - from: 2020-10-24      store: boltdb-shipper      object_store: filesystem      schema: v11      index:        prefix: index_        period: 24h

Je n'ai pas pris la peine d'activer l'authentification en sachant que je suis dans un LAN avec uniquement mes machines virtuelles. Je considère pas que mon Loki comme un point sensible de mon infra.

Après seulement 2-3 minutes de configuration, notre Loki est déjà disponible !

On peut dès maintenant l'ajouter en tant que datasource sur notre Grafana : !()[https://i.imgur.com/G3tWx1r.png]

(J'utilise localhost car la machine possédant le grafana héberge également le Loki)

Il se peut que Grafana rale un peu car notre base de donnée Loki est vide.

Partie Promtail#

Promtail est l'agent qui va nous permettre d'envoyer nos logs à Loki, j'ai écris un role Ansible assez simple me permettant d'installer notre agent sur de nombreuses machines en surveillant les logs provenant de Docker, varlog et syslog.

Voici ma template Jinja2 à propos de ma configuration :

server:  http_listen_port: 9080  grpc_listen_port: 0
positions:  filename: /tmp/positions.yaml
clients:{% if loki_url is defined %}  - url: {{ loki_url }}{% endif %} 

scrape_configs:

- job_name: authlog  static_configs:  - targets:      - localhost    labels:{% if ansible_hostname is defined %}      host: {{ ansible_hostname }}{% endif %}       job: authlog      __path__: /var/log/auth.log

- job_name: syslog  static_configs:  - targets:      - localhost    labels:{% if ansible_hostname is defined %}      host: {{ ansible_hostname }}{% endif %}      job: syslog      __path__: /var/log/syslog
- job_name: Containers  static_configs:  - targets:      - localhost    labels:{% if ansible_hostname is defined %}      host: {{ ansible_hostname }}{% endif %}      job: containerslogs      __path__: /var/lib/docker/containers/*/*-json.log
- job_name: DaemonLog  static_configs:  - targets:      - localhost    labels:{% if ansible_hostname is defined %}      host: {{ ansible_hostname }}{% endif %}      job: daemon      __path__: /var/log/daemon.log

Si vous n'êtes pas à l'aise avec des templates Jinja2, vous trouverez une version "pure" de la config ici

Vous pouvez bien evidemment adapter cette template à vos besoins. Mon idée première est d'avoir une "base" que je peux mettre sur chaque machine (en sachant aussi que si aucun log n'est disponible, comme pour Docker, Promtail ne causera pas une erreur en ne trouvant pas les fichiers)

Une fois Promtail configuré, on peut le démarrer : via l'executable directement :

/opt/promtail/promtail -config.file /opt/promtail/promtail-local-config.yaml

ou via systemd (automatique si vous passez par mon playbook) :
systemctl start promtail

Une fois cet agent un peu partout, on va directement aller s'amuser sur Grafana !

Faire des requetes à Loki depuis Grafana#

On va faire quelque chose d'assez contre-intuitif : nous n'allons pas commencer par faire un Dashboard : on va d'abord tester nos requetes ! Scrollez pas, je vous jure que c'est la partie la plus fun !

Sur Grafana, nous avons un onglet "Explore". Celui-ci va nous donner accès à Loki en écrivant des requetes, celles-ci sont assez simple, et surtout en utilisant l'outil "click-o-drome" en dépliant le Log Browser

Pardon j'ai un chouïa avancé sans vous...

Avec la template que je vous ai donné, vous aurez 4 jobs :

  • daemon
  • authlog
  • syslog
  • containersjobs

Ces jobs permettent de trier les logs, on va tester ça ensemble. Nous allons donc selectionner la machine "Ansible", puis demander le job "authlog". Je commence par cliquer sur Ansible, puis Authlog. Grafana me proposera exactement si je souhaite choisir un fichier spécifique. Si on ne précise pas de fichier(filename) Grafana prendra tous les fichiers (donc aucune importance si nous n'avons qu'un seul fichier)

(vous remarquerez plus tard que dès notre 1ere selection, grafana va cacher les jobs/hôte/fichier qui ne concernent pas notre début de requete)

En validant notre requete (bouton show logs)

Nous avons donc le résultat de la requete vers Loki dans le lapse de temps configuré dans Grafana (1h pour moi). Mon authlog n'est pas très interessant, et mon syslog est pollué par beaucoup de message pas très pertinents.

Nous allons donc commencer à trier nos logs !

En cliquant sur le petit "?" au dessus de notre requete, nous avons une "cheatsheet" résumant les fonctions basiques de Loki. Nous découvrons comment faire une recherche exacte avec |=, comment ignorer les lignes avec != et comment utiliser une expression regulière avec |~

Je vous partage également une cheatsheet un peu plus complète que j'ai trouvé sur un blog : ici

Ainsi, on peut directement obtenir des logs un peu plus colorés qui nous permettrons de cibler l'essentiel !

(L'idée est de cibler les logs sympas avec les couleurs qui vont avec)

Conclusion

Si on entend souvent parler de la suite ELK, ça n'est pas non-plus une raison pour s'en servir à tout prix ! Loki est une bonne alternative proposant des fonctionnalitées basiques qui suffiront pour la plupart.

· 3 minutes de lecture
TheBidouilleur

Changelog (janv 2022) - Aujourd'hui, j'ai remplacé Caddy par Traefik, à voir dans un futur article

Dans ma courte vie d'informaticien, je n'ai toujours eu qu'une seule IP publique. Celle de mon serveur OVH sur lequel vous visualisez le site actuellement. Et en sachant que j'ai de nombreux services Web, il m'a rapidement été nécéssaire de chercher les différents solutions permettant d'installer un Reverse Proxy efficace qui servirait à rediriger mes utilisateurs vers l'application voulue en fonction du domaine.

Dans ma longue quête (qui n'est certainement pas achevée), j'ai eu l'occassion de tester de nombreuses solutions comme Haproxy, Apache2, Nginx et maintenant.. Caddy

Haproxy a été pour moi le plus facile et le plus pratique pour démarrer, bonne documentation, incorpore de nombreux outils permettant de vérifier la configuration, ou rajouter des authentifications. J'ai été satisfait durant quelques années.

(Je ne compte pas Apache2, qui a été pratique pour débuter sans installer un service dédié à mon besoin de redirection)

Ensuite, j'ai utilisé aaPanel (dont vous trouverez un article sur ce site) me permettant d'avoir une toute un panel web pour mes sites et mes redirections ! J'ai abandonné en sachant que c'était un système bien ficelé dans lequel j'avais peu de liberté en terme d'édition de config

Puis mon besoin inutile d'avoir une interface Web m'a mené vers NPM (Nginx Proxy Manager) dont vous trouverez plus d'information ici. Qui m'était très pratique en sachant qu'il était sous forme de conteneur Docker, et proposant une interface gérant la création de redirection ainsi que le SSL, toujours chez let's encrypt. Mais à chaque expiration de certificat, NPM m'obligeait à aller manuellement séléctionner un-par-un chaque certificat à update : et ça, c'était impensable en sachant le nombre de domaine que j'ai créé.

Aujourd'hui, mon attention se porte vers Caddy qui, pour l'instant, correspond exactement à ce que je souhaite, et avec une simplicité incroyable.

Caddy

Caddy est, comme vous l'aurez compris, un reverse-proxy assez polyvalent et très utilisé dans certains conteneurs Docker ! Celui-ci génère automatiquement vos certificats (et configure les redirections automatiquement) sans aucun soucis avec Let's Encrypt. Caddy est assez léger et vous évitera les configurations à ralonge, voici un exemple bête :

thoughtless.eu {    reverse_proxy 192.168.5.125:8062    log {        output file /var/log/caddy/thoughtless.eu_access.log    }}

Cette ligne créera une redirection en reverse-proxy avec la configuration par défault :

  • Caddy updatera / generera des certificats chaque fois que c'est nécéssaire
  • Il redirigera automatiquement les requetes en http:// vers le https://
  • Il écriera des logs des accès dans un fichier

En apache2 / Haproxy, ça aurait pris un chouïa + de lignes.

Mais attendons de voir, Caddy est encore très neuf pour moi, et je suis sûr que mon prochain besoin m'orientera vers une autre solution telle que Traefik par exemple !

Bonne courage dans votre longue quête autour des reverse-proxy

· 6 minutes de lecture
TheBidouilleur

[ Cet article provient de mon ancien-blog, celui-ci sera également disponible dans la partie "Documentation" du site ]

Docker Swarm

Introduction#

Le monde de la conteneurisation a apporté de nombreuses choses dans l'administration système, et a actualisé le concept de DevOps. Mais une des choses principales que nous apporte les conteneurs (et particulièrement Docker), c'est l'automatisation. Et bien que Docker soit déjà complet avec le déploiement de service, on peut aller un peu plus loin en automatisant la gestion des conteneurs ! Et pour répondre à ça : Docker Inc. propose un outil adapté pour l'orchestration automatique d'instance : Docker Swarm.