bhyve – Guest openbsd

Bhyve – Guest openbsd

  • start_openbsd.sh
    
    #!/bin/sh
     
    grub-bhyve -m obsd57.map -r hd0,msdos1 -M 1024M openbsd < obsd57.in
     
    bhyve -w -AI -H -P -s 0:0,hostbridge  \
    -s 1:0,lpc -s 2:0,virtio-net,tap2 \
    -s 3:0,virtio-blk,./disk.img \
    -l com1,stdio -c 2 \
    -m 1024M openbsd
    
  • obsd57.in
    kopenbsd -h com0 -r sd0a (hd0,openbsd1)/bsd
    boot
    
  • obsd57.map
    (hd0) ./disk.img
    (cd0) ./install57.iso
    
  • halt.sh
     
    #!/bin/sh
    bhyvectl --destroy --vm=openbsd
    
  • FreeBSD – bhyve et libvirt , le combo parfait

    FreeBSD avec bhyve et libvirt

  • Tout d’abord; il faut installer des packages
    pkg install -y libvirt
    
  • Le configurer au démarrage dans /etc/rc.conf
    libvirtd_enable="YES"
    
  • Modifier /etc/loader.conf pour y ajouter les 2 kernel modules suivant
    vmm_load="YES"
    nmdm_load="YES"
    
  • créer un fichier vide pour l’image de la VM
    truncate alcsys-vm51.img -s 100G
    
  • Télécharger l’iso de la disto souhaitée
    wget http://xxxxx/CentOS-7-x86_64-Minimal-1511.iso
    
  • Préparer un fichier device.map
    # cat device.map
    (hd0) ./alcsys-vm51.img
    (cd0) ./CentOS-7-x86_64-Minimal-1511.iso
    
  • préparer grub
    grub-bhyve -m device.map -r cd0 -M 2048 alcsys-vm51
    
  • Puis taper dans le prompt grub>
     linux (cd0)/isolinux/vmlinuz
     initrd (cd0)/isolinux/initrd.img
     boot
    
  • Si ca marche pas; taper “ls (cd0)/” pour localiser vmlinuz sur l’iso
  • Créer une interface réseau pour la VM
    ifconfig tap1 create
    
  • Démarrer la VM
    bhyve -AI -H -P -s 0:0,hostbridge -s 1:0,lpc -s 2:0,virtio-net,tap1 -s 3:0,virtio-blk,./alcsys-vm51.img -s 4:0,ahci-cd,./CentOS-7-x86_64-Minimal-1511.iso -l com1,stdio -c 4 -m 2048M alcsys-vm51
    
  • l’installation de l’os débute; effectuez l’installation en mode non graphique
  • Une fois terminée, détruisez le domain
    bhyvectl --destroy --vm=alcsys-vm51
    
  • Préparer de nouveau grub
    grub-bhyve -m device.map -r hd0,msdos1 -M 2048M alcsys-vm51
    
  • dans le prompt grub> taper:
    configfile (hd0,msdos1)/grub2/grub.cfg
    
  • Démarrer la VM
    bhyve -AI -H -P -s 0:0,hostbridge -s 1:0,lpc -s 2:0,virtio-net,bridge0 -s 3:0,virtio-blk,./alcsys-vm51.img -l com1,stdio -c 4 -m 2048M alcsys-vm51
    
  • Vérifier que l’os est ok
  • halt de la vm et tester de passer les instructions comme ceci [A VALIDER]:
    echo "configfile (hd0,msdos1)/grub2/grub.cfg" | grub-bhyve -m device.map -r hd0,msdos1 -M 2048M alcsys-vm51
    bhyve -AI -H -P -s 0:0,hostbridge -s 1:0,lpc -s 2:0,virtio-net,bridge0 -s 3:0,virtio-blk,./alcsys-vm51.img -l com1,stdio -c 4 -m 2048M alcsys-vm51
    
  • Créer un XML pour libvirt
    
    
    
    <domain type='bhyve' id='97406'>
      <name>alcsys-vm51</name>
      <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid>
      <memory unit='KiB'>2097152</memory>
      <currentMemory unit='KiB'>2097152</currentMemory>
      <vcpu placement='static'>2</vcpu>
      <bootloader>/usr/local/sbin/grub-bhyve</bootloader>
      <bootloader_args>--directory=/grub2 --grub-cfg=grub.cfg -r hd0,msdos1 -m /vm/alcsys-vm51.map -M 2048 alcsys-vm51</bootloader_args>
      <os>
        <type arch='x86_64'>hvm</type>
      </os>
      <features>
        <acpi/>
        <apic/>
      </features>
      <clock offset='utc'/>
      <on_poweroff>destroy</on_poweroff>
      <on_reboot>restart</on_reboot>
      <on_crash>destroy</on_crash>
      <devices>
        <disk type='file' device='disk'>
          <driver name='file' type='raw'/>
          <source file='/vm/alcsys-vm51.img'/>
          <backingStore/>
          <target dev='vdb' bus='virtio'/>
          <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
        </disk>
        <controller type='pci' index='0' model='pci-root'/>
        <controller type='sata' index='0'/>
        <interface type='bridge'>
          <mac address='52:54:00:c6:2d:7c'/>
          <source bridge='bridge0'/>
          <target dev='vnet1'/>
          <model type='virtio'/>
          <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
        </interface>
        <serial type='nmdm'>
          <source master='/dev/nmdm0A' slave='/dev/nmdm0B'/>
          <target port='0'/>
        </serial>
        <console type='nmdm'>
          <source master='/dev/nmdm0A' slave='/dev/nmdm0B'/>
          <target type='serial' port='0'/>
        </console>
      </devices>
    </domain>
    
  • le fichier map n’a plus besoin du cdrom et bien s’assurer du path absolu de l’image
    # cat /vm/alcsys-vm51.map
    (hd0) /vm/alcsys-vm51.img
    
  • importer le xml
    virsh define alcsys-vm51.xml
    
  • démarrer le domain
    virsh start alcsys-vm51
    
  • Vérifier
    # virsh list
     Id    Name                           State
    ----------------------------------------------------
     37911 alcsys-vm51                    running
    
  • Accéder a la console
    virsh console alcsys-vm51 
    
  • Le log a consulter
    tail -f /var/log/libvirt/bhyve/alcsys-vm51.log
    
  • FreeBSD / Packet Filter – Rediriger le traffic http vers un serveur ayant 2 NIC

    Un petit problème s’est posé lors d’un besoin très spécifique consistant à rediriger temporairement le traffic http d’une jail vers une autre jail hébergée sur un autre serveur ayant sa propre GW.

    En image, cela sera plus parlant:

    PF RDR issue with 2 NIC - New Page

    Comme on peut le voir; avec une simple règle RDR, le traffic retour repartait sur la gw du Server B (WAN) au lieu de revenir par son chemin original (LAN).

    La solution est d’ajouter sur le ServerA une règle PF indiquant de réutiliser une interface particulière – en l’occurence la même que celle utilisée pour l’allée – pour le chemin du retour du paquet.

    La règle:

    pass in quick on vlan10 reply-to (vlan10 192.168.10.6) proto tcp from any to 192.168.10.206 port http keep state label pra.nli.http
    

    Maintenant le paquet emprunte la même interface pour l’allée et le retour.

    letsencrypt, le SSL gratuit pour tous !

    Ayant testé la beta, je suis désormais fan de ce service.

    Voici comment l’utiliser sous Freebsd:

    * Récupérer les sources

    git clone https://github.com/letsencrypt/letsencrypt.git
    

    * Installer les dépendances

     ./letsencrypt-auto --help --debug
    

    * Créer un fichier common.ini

    mkdir /usr/local/www/letsencrypt
    mkdir /usr/local/etc/letsencrypt
    vi mkdir /usr/local/etc/letsencrypt/common.ini
    
    authenticator = webroot
    webroot-path = /usr/local/www/letsencrypt
    server = https://acme-v01.api.letsencrypt.org/directory
    renew-by-default
    agree-tos
    email = xxxx@domain.com
    rsa-key-size = 4096
    

    * Editer la conf apache sur son vhost http/80

    
            ##################
            # LETS ENCRYPT
            ##################
        Alias "/.well-known/acme-challenge" "/usr/local/www/letsencrypt/.well-known/acme-challenge"
        
            Header set Content-Type "application/jose+json"
        
    
    

    * Si vous avez une rewriteRule qui redirige le http => https; il faut ajouter une condition d’exclusion:

            RewriteEngine On
            RewriteCond %{REMOTE_PORT}  !^443$
            RewriteCond %{REQUEST_URI} !^/\.well\-known/acme\-challenge/
            RewriteRule ^/(.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
    

    * Générer son certif

    root@j-transmission:~/letsencrypt # ./letsencrypt-auto --server https://acme-v01.api.letsencrypt.org/directory certonly -c /usr/local/etc/letsencrypt/common.ini -d blog.distran.org
    Updating letsencrypt and virtual environment dependencies.......
    Running with virtualenv: /root/.local/share/letsencrypt/bin/letsencrypt --server https://acme-v01.api.letsencrypt.org/directory certonly -c /usr/local/etc/letsencrypt/common.ini -d blog.distran.org
    
    IMPORTANT NOTES:
     - If you lose your account credentials, you can recover through
       e-mails sent to letsencrypt@distran.org.
     - Congratulations! Your certificate and chain have been saved at
       /etc/letsencrypt/live/blog.distran.org/fullchain.pem. Your cert
       will expire on 2016-03-11. To obtain a new version of the
       certificate in the future, simply run Let's Encrypt again.
     - Your account credentials have been saved in your Let's Encrypt
       configuration directory at /etc/letsencrypt. You should make a
       secure backup of this folder now. This configuration directory will
       also contain certificates and private keys obtained by Let's
       Encrypt so making regular backups of this folder is ideal.
     - If like Let's Encrypt, please consider supporting our work by:
    
       Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
       Donating to EFF:                    https://eff.org/donate-le
    
    

    * Editer la conf apache pour que ca pointe sur le certif

    SSLCertificateFile "/etc/letsencrypt/live/blog.distran.org/fullchain.pem"
    SSLCertificateKeyFile "/etc/letsencrypt/live/blog.distran.org/privkey.pem"
    

    * EN crontab pour une execution tous les 31 de chaque mois; donc 1 fois tous les 2 mois sachant que ca expire au bout de 3 mois:

    10 3 31 * *   ( /root/letsencrypt/letsencrypt-auto --server https://acme-v01.api.letsencrypt.org/directory certonly -c /usr/local/etc/letsencrypt/commo
    n.ini -d seed2.distran.org && /usr/local/etc/rc.d/apache24 restart ) > /tmp/cron_letsencrypt.log 2>&1
    

    Setup d’un Annuaire LDAP s’appuyant sur le backend SQL de postfixadmin

    L’idée est d’avoir une base source unique pour ses utilisateurs.
    Postfixadmin s’appuye sur une db sql et ne permet pas l’usage d’un annuaire LDAP en backend. Pourtant beaucoup d’applications s’appuyent sur du LDAP, c’est donc handicapant de n’avoir qu’une base sql.
    Alors voici un moyen d’avoir également un annuaire LDAP automatiquement mappé sur la base sql utilisateurs de postfixadmin.

    Ce setup s’appuye sur des HASH SHA512 pour le stockage des passwords.

    * /usr/local/www/postfixadmin/config.inc.php

    Par default, postfixadmin créé des hash MD5 pour stocker les password, c’est pas très rassurant, alors mettons nous plutot sur du SHA512, réputé plus solide.

    / Encrypt
    // In what way do you want the passwords to be crypted?
    // md5crypt = internal postfix admin md5
    // md5 = md5 sum of the password
    // system = whatever you have set as your PHP system default
    // cleartext = clear text passwords (ouch!)
    // mysql_encrypt = useful for PAM integration
    // authlib = support for courier-authlib style passwords
    // dovecot:CRYPT-METHOD = use dovecotpw -s 'CRYPT-METHOD'. Example: dovecot:CRAM-MD5
    $CONF['encrypt'] = 'dovecot:SHA512-CRYPT';
    

    * Cette étape n’a d’importance uniquement si vous souhaitez faire du PAM LDAP sur vos OS.

    – Ajouter une colonne id sur le schéma existant de postfixadmin de la table mailbox:
    Et Pas d’inquiétude; ca ne casse rien au bon fonctionnement de postfixadmin

    ALTER TABLE mailbox ADD id INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE KEY;
    

    – Alimenter cette colonne avec des id sur les entrées existantes; à partir de 1100 pour ne pas empiéter sur des services utilisant les ranges inférieures.

    – Installer l’annuaire Openldap

    # cd /usr/ports/net/openldap24-server
    # make config
    
    Cocher ODBC
    Cocher SHA2
    
    # make install clean
    

    – Editer /usr/local/etc/openldap/slapd.conf

    
    # See slapd.conf(5) for details on configuration options.
    # This file should NOT be world readable.
    #
    include         /usr/local/etc/openldap/schema/core.schema
    include         /usr/local/etc/openldap/schema/cosine.schema
    include         /usr/local/etc/openldap/schema/inetorgperson.schema
    include         /usr/local/etc/openldap/schema/nis.schema
    
    
    TLSCipherSuite HIGH:MEDIUM:+SSLv3
    TLSCertificateFile /usr/local/etc/openldap/cert.crt
    TLSCertificateKeyFile /usr/local/etc/openldap/cert.key
    
    
    pidfile         /var/run/openldap/slapd.pid
    argsfile        /var/run/openldap/slapd.args
    
    # Load dynamic backend modules:
    modulepath      /usr/local/libexec/openldap
    moduleload      back_sql
    
    # Module for supporting SHA512
    moduleload      pw-sha2
    
    #######################################################################
    # sql database definitions
    #######################################################################
    
    database        sql
    suffix          "dc=infranix,dc=eu"
    # You only need these if normal ldap backends are defined and hold the "root"
    rootdn          "cn=admin,dc=infranix,dc=eu"
    
    # Postfixadmin Password format (SHA512) using libcrypt)
    password-hash {CRYPT}
    password-crypt-salt-format "$6$%.16s"
    
    dbhost          192.168.X.Y
    dbname          ldap
    dbuser          ldap_user
    dbpasswd        xxxxxxxxxx
    
    lastmod off
    
    subtree_cond    "ldap_entries.dn LIKE CONCAT('%',?)"
    has_ldapinfo_dn_ru      no
    

    * Créer une db ldap

    create database ldap;
    

    La suite du schéma de la base va avoir beaucoup de vues afin d’avoir une automatisation extrême.

    * Pour privilégier un domain le schéma aura 2 vues users quasi-identiques, l’une incluant le domaine privilégié et l’autre l’excluant.

    * Vue users_publics

    drop view users_public;
    
    create view users_public AS
    
    select 
      id as id, 
      local_part as username ,
     password,
      name,
      name as surname,
      username as email,
      domain as domain
    from postfix.mailbox where mailbox.active =1 and mailbox.username  NOT LIKE '%@infranix.eu';
    

    – Vue users_people

    drop view users_people;
    
    create view users_people AS
    
    select 
      id as id, 
      local_part as username ,
     password,
      name,
      name as surname,
      username as email,
      domain as domain
    from postfix.mailbox where mailbox.active =1 and mailbox.username  LIKE '%@infranix.eu';
    
    

    – users

    drop view users
    
    create view users AS
    
    select * from users_people
    UNION
    select * from users_public
    

    – org_unit_original

    c’est à la base ce schéma qui est fourni par default.

    CREATE TABLE `org_unit_original` (
      `id` int(11) NOT NULL,
      `o` varchar(32) DEFAULT NULL,
      `dn` varchar(255) DEFAULT NULL,
      `parent` int(11) DEFAULT NULL,
      `oc_map_id` int(2) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `dn` (`dn`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
    INSERT INTO `org_unit_original` VALUES (1,'Infranix','dc=infranix,dc=eu',0,3),(2,'People','ou=People,dc=infranix,dc=eu',1,2),(3,'Groups','ou=Groups,dc=infranix,dc=eu',1,2),(4,'Public','ou=Public,dc=infranix,dc,eu',1,2),(6,'Devnix','dc=devnix.fr,dc=infranix,dc=eu',1,3),(7,'People','ou=People,dc=devnix.fr,dc=infranix,dc=eu',6,2);
    
    
    

    mysql> select id,o,dn,parent,oc_map_id from org_unit_original;
    +—-+———-+——————————————+——–+———–+
    | id | o | dn | parent | oc_map_id |
    +—-+———-+——————————————+——–+———–+
    | 1 | Infranix | dc=infranix,dc=eu | 0 | 3 |
    | 2 | People | ou=People,dc=infranix,dc=eu | 1 | 2 |
    | 3 | Groups | ou=Groups,dc=infranix,dc=eu | 1 | 2 |
    | 4 | Public | ou=Public,dc=infranix,dc,eu | 1 | 2 |
    | 6 | Devnix | dc=devnix.fr,dc=infranix,dc=eu | 1 | 3 |
    | 7 | People | ou=People,dc=devnix.fr,dc=infranix,dc=eu | 6 | 2 |
    +—-+———-+——————————————+——–+———–+

    – org_unit_distributed

    On va créé une orgUnit pour chaque domaine via une vue s’appuyant sur la vue users_distributed, elle même une vue générée par la table mailbox de postfixadmin.

    drop view org_unit_distributed;
    create view org_unit_distributed AS
    
    
       select 
        (domain) as o,
       MIN((id)+50000) as id,
       CONCAT('dc=',domain,',dc=infranix,dc=eu') AS dn, 
            3 as oc_map_id,
            1 as parent
       from users_distributed group by domain
     
    UNION 
    
    select * from org_unit_original;
    
    

    * org_unit

    Cette vue définit l’arbre du LDAP avec la relation entre niveau (parent).

    drop view org_unit;
    create view org_unit AS
    
    select id,o,dn,parent,oc_map_id from org_unit_original
    
    UNION
    
       select 
       
       MIN((id)+50000) as id,
        (domain) as o,
       CONCAT('dc=',domain,',dc=infranix,dc=eu') AS dn, 
    
            1 as parent,
                    3 as oc_map_id
       from users_distributed group by domain
     
    UNION 
    
    
        SELECT
         (users_distributed.id)+90000 as id,
            'People' ,
            CONCAT('ou=People,dc=',domain,',dc=infranix,dc=eu') AS dn, 
      
            org_unit_distributed.id as parent,
                    2 as oc_map_id
            from users_distributed, org_unit_distributed
            where org_unit_distributed.o = domain
            group by domain
    
    mysql> select * from org_unit limit 10;
    +--------+-------------------+------------------------------------------+--------+-----------+
    | id     | o                 | dn                                       | parent | oc_map_id |
    +--------+-------------------+------------------------------------------+--------+-----------+
    |     1  | Infranix          | dc=infranix,dc=eu                        |      0 |         3 |
    |     2  | People            | ou=People,dc=infranix,dc=eu              |      1 |         2 |
    |     3  | Groups            | ou=Groups,dc=infranix,dc=eu              |      1 |         2 |
    |     4  | Public            | ou=Public,dc=infranix,dc,eu              |      1 |         2 |
    |     6  | Devnix            | dc=devnix.fr,dc=infranix,dc=eu           |      1 |         3 |
    |     7  | People            | ou=People,dc=devnix.fr,dc=infranix,dc=eu |      6 |         2 |
    | 60047  | toto.net          | dc=toto.net,dc=infranix,dc=eu            |      1 |         3 |
    | 60045  | titi.com          | dc=titi.com,dc=infranix,dc=eu            |      1 |         3 |
    | 60009  | tutu.biz          | dc=tutu.biz,dc=infranix,dc=eu            |      1 |         3 |
    | 60021  | aaaa.com          | dc=aaaa.com,dc=infranix,dc=eu            |      1 |         3 |
    | 100044 | People            | ou=People,dc=toto.net,dc=infranix,dc=eu  |  60044 |         2 |
    | 100000 | People            | ou=People,dc=titi.com,dc=infranix,dc=eu  |  60000 |         2 |
    | 100007 | People            | ou=People,dc=tutu.biz,dc=infranix,dc=eu  |  60007 |         2 |
    | 100014 | People            | ou=People,dc=aaaaa.com,dc=infranix,dc=eu |  60014 |         2 |
    +--------+-------------------+------------------------------------------+--------+-----------+
    10 rows in set (0.01 sec)
    

    * ldap_entries

    drop view ldap_entries;
    
    
    CREATE VIEW ldap_entries AS 
     
    SELECT 
        org_unit.id AS id,
        org_unit.dn AS dn,
        org_unit.oc_map_id AS oc_map_id,
        org_unit.parent AS parent,
        org_unit.id AS keyval
    FROM
        org_unit
     
    
    UNION 
    
     
    SELECT 
        (users_people.id) AS id,
        CONCAT('uid=',
                        users_people.username,
                        ',ou=People,dc=infranix,dc=eu') AS dn,
        1 AS oc_map_id,
        2 AS parent,
        (users_people.id) AS keyval
    FROM
        users_people
    
    
    
     
    UNION 
     
    SELECT 
     
        (groups.id) AS id,
        CONCAT( 'cn=',
                        groups.name,
                        ',ou=Groups,dc=infranix,dc=eu') AS dn,
        5 AS oc_map_id,
        3 AS parent,
        groups.id AS id
    FROM
        groups
    
    
    UNION
    
    SELECT 
        (users_distributed.id) AS id,
        CONCAT('uid=',
                users_distributed.username,
                ',ou=People,dc=',
                users_distributed.domain,
                ',dc=infranix,dc=eu') AS dn,
        1 AS oc_map_id,
        org_unit.id AS parent,
        (users_distributed.id) AS keyval
    FROM
        users_distributed,org_unit
    WHERE
        org_unit.dn = CONCAT('ou=People,dc=',users_distributed.domain,',dc=infranix,dc=eu');
    
    

    * ldap_entry_objclasses

    Pour l’usage de pam, il fallait ajouter de nouveaux objectClass à inetOrgPerson, notamment posixAccount et shadowAccount.
    L’astuce est de créer une vue pour construire la table optionnelle ldap_entry_objclasses en l’autogénérant via la table users.

    drop view ldap_entry_objclasses;
    
    CREATE VIEW ldap_entry_objclasses AS 
     
    SELECT 
        (users.id) AS entry_id,
        'posixAccount' AS oc_name
    FROM
        users
     
    UNION 
    
    SELECT 
        (users.id) AS entry_id,
        'shadowAccount' AS oc_name
    FROM
        users
    

    * ldap_oc_mappings

    Cette table permet d’identifier la table de toutes les objectCLass

    CREATE TABLE `ldap_oc_mappings` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `name` varchar(64) NOT NULL,
      `keytbl` varchar(64) NOT NULL,
      `keycol` varchar(64) NOT NULL,
      `create_proc` varchar(255) DEFAULT NULL,
      `delete_proc` varchar(255) DEFAULT NULL,
      `expect_return` tinyint(4) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
    
    INSERT INTO `ldap_oc_mappings` VALUES (3,'organization','org_unit','id',NULL,NULL,0),(2,'organizationalUnit','org_unit','id',NULL,NULL,0),(1,'inetOrgPerson','users','id',NULL,NULL,0),(5,'posixGroup','groups','id',NULL,NULL,0),(6,'posixAccount','users','id',NULL,NULL,0);
    
    

    son contenu:

    mysql> select * from ldap_oc_mappings;
    +----+--------------------+----------+--------+-------------+-------------+---------------+
    | id | name               | keytbl   | keycol | create_proc | delete_proc | expect_return |
    +----+--------------------+----------+--------+-------------+-------------+---------------+
    |  3 | organization       | org_unit | id     | NULL        | NULL        |             0 |
    |  2 | organizationalUnit | org_unit | id     | NULL        | NULL        |             0 |
    |  1 | inetOrgPerson      | users    | id     | NULL        | NULL        |             0 |
    |  5 | posixGroup         | groups   | id     | NULL        | NULL        |             0 |
    |  6 | posixAccount       | users    | id     | NULL        | NULL        |             0 |
    +----+--------------------+----------+--------+-------------+-------------+---------------+
    

    * ldap_attr_mappings

    Cette table est cruciale; c’est elle qui définit les attributs de chaque objectClass.
    Dans mon usage pour du pam_ldap, il fallait donc bien définir homeDirectory, userPassword, uidMember, gidNumber, loginShell:

    CREATE TABLE `ldap_attr_mappings` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `oc_map_id` int(10) unsigned NOT NULL,
      `name` varchar(255) NOT NULL,
      `sel_expr` varchar(255) NOT NULL,
      `sel_expr_u` varchar(255) DEFAULT NULL,
      `from_tbls` varchar(255) NOT NULL,
      `join_where` varchar(255) DEFAULT NULL,
      `add_proc` varchar(255) DEFAULT NULL,
      `delete_proc` varchar(255) DEFAULT NULL,
      `param_order` tinyint(4) NOT NULL,
      `expect_return` tinyint(4) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=MyISAM AUTO_INCREMENT=23 DEFAULT CHARSET=utf8;
    
    INSERT INTO `ldap_attr_mappings` VALUES (1,1,'cn','users.username','','users',NULL,NULL,NULL,3,0),(2,1,'telephoneNumber','users.phone','','users','NULL',NULL,NULL,3,0),(3,1,'sn','users.name','','users',NULL,NULL,NULL,3,0),(7,1,'homeDirectory','concat(\'/home/\',users.domain, \'/\',users.username)',NULL,'users',NULL,NULL,NULL,3,0),(5,1,'mail','users.email',NULL,'users',NULL,NULL,NULL,3,0),(6,2,'ou','Groups',NULL,'groups',NULL,NULL,NULL,3,0),(13,1,'userPassword','replace(users.password, \'SHA512-CRYPT\', \'CRYPT\')',NULL,'users','users.password IS NOT NULL',NULL,NULL,3,0),(8,3,'o','org_unit.o',NULL,'org_unit',NULL,NULL,NULL,3,0),(14,1,'displayName','users.name',NULL,'users',NULL,NULL,NULL,3,0),(9,1,'loginShell','concat(\'/bin/bash\')',NULL,'users',NULL,NULL,NULL,3,0),(4,1,'uidNumber','users.id',NULL,'users',NULL,NULL,NULL,3,0),(21,5,'cn','groups.name',NULL,'groups',NULL,NULL,NULL,3,0),(15,5,'gidNumber','groups.id',NULL,'groups',NULL,NULL,NULL,3,0),(16,5,'memberUid','users.username',NULL,'groups,group_member,users','group_member.users_id=users.id and group_member.groups_id=groups.id',NULL,NULL,3,0),(11,1,'gidNumber','100',NULL,'users',NULL,NULL,NULL,3,0),(17,3,'objectClass','concat(\'top\')',NULL,'org_unit',NULL,NULL,NULL,3,0),(18,3,'objectClass','concat(\'dcObject\')',NULL,'org_unit',NULL,NULL,NULL,3,0),(19,1,'uid','users.username',NULL,'users',NULL,NULL,NULL,3,0),(20,3,'dc','org_unit.o',NULL,'org_unit',NULL,NULL,NULL,3,0);
    
    

    Le contenu des attributs de l’objectClass inetOrgPerson (id àa 1 dans la table ldap_oc_mappings ci-dessus) via un SELECT :

    
    mysql> mysql> select * from ldap_attr_mappings where oc_map_id=1;
    +----+-----------+-----------------+---------------------------------------------------+------------+-----------+----------------------------+----------+-------------+-------------+---------------+
    | id | oc_map_id | name            | sel_expr                                          | sel_expr_u | from_tbls | join_where                 | add_proc | delete_proc | param_order | expect_return |
    +----+-----------+-----------------+---------------------------------------------------+------------+-----------+----------------------------+----------+-------------+-------------+---------------+
    |  1 |         1 | cn              | users.username                                    |            | users     | NULL                       | NULL     | NULL        |           3 |             0 |
    |  2 |         1 | telephoneNumber | users.phone                                       |            | users     | NULL                       | NULL     | NULL        |           3 |             0 |
    |  3 |         1 | sn              | users.name                                        |            | users     | NULL                       | NULL     | NULL        |           3 |             0 |
    |  7 |         1 | homeDirectory   | concat('/home/',users.domain, '/',users.username) | NULL       | users     | NULL                       | NULL     | NULL        |           3 |             0 |
    |  5 |         1 | mail            | users.email                                       | NULL       | users     | NULL                       | NULL     | NULL        |           3 |             0 |
    | 13 |         1 | userPassword    | replace(users.password, 'SHA512-CRYPT', 'CRYPT')  | NULL       | users     | users.password IS NOT NULL | NULL     | NULL        |           3 |             0 |
    | 14 |         1 | displayName     | users.name                                        | NULL       | users     | NULL                       | NULL     | NULL        |           3 |             0 |
    |  9 |         1 | loginShell      | concat('/bin/bash')                               | NULL       | users     | NULL                       | NULL     | NULL        |           3 |             0 |
    |  4 |         1 | uidNumber       | users.id                                          | NULL       | users     | NULL                       | NULL     | NULL        |           3 |             0 |
    | 11 |         1 | gidNumber       | 100                                               | NULL       | users     | NULL                       | NULL     | NULL        |           3 |             0 |
    | 19 |         1 | uid             | users.username                                    | NULL       | users     | NULL                       | NULL     | NULL        |           3 |             0 |
    +----+-----------+-----------------+---------------------------------------------------+------------+-----------+----------------------------+----------+-------------+-------------+---------------+
    
    

    A suivre, je vais alimenter au fur et à mesure.

    FreeBSD 10.2 – pam_ldap howto

    – Il faut installer les packages:

    # pkg install -y nss_ldap pam_ldap openldap-client p5-Mozilla-CA
    

    – Faire la conf du client ldap

    vi /usr/local/etc/nss_ldap.conf
    
    BASE ou=People,dc=infranix,dc=eu
    URI ldaps://ldap1
    TLS_CACERTDIR /usr/local/lib/perl5/site_perl/Mozilla/CA/cacert.pem
    TLS_REQCERT allow
    SASL_NOCANON    on
    

    – Créer des symlink pour simplier la configuration vers ldap.conf

    # ln -s /usr/local/etc/nss_ldap.conf /usr/local/etc/openldap/ldap.conf
    # ln -s /usr/local/etc/nss_ldap.conf /usr/local/etc/ldap.conf
    

    – Modifier nsswitch pour qu’il s’appuye sur ldap pour passwd et group

    [root@app001 ~]# cat /etc/nsswitch.conf
    #
    # nsswitch.conf(5) - name service switch configuration file
    # $FreeBSD: releng/10.2/etc/nsswitch.conf 224765 2011-08-10 20:52:02Z dougb $
    #
    group: files ldap
    group_compat: nis
    hosts: files dns
    networks: files
    passwd: files ldap
    passwd_compat: nis
    shells: files
    services: compat
    services_compat: nis
    protocols: files
    rpc: files
    

    – Modifier /etc/pam.d/ssh

    root@app001 ~]# cat /etc/pam.d/sshd
    #
    # $FreeBSD: releng/10.2/etc/pam.d/sshd 197769 2009-10-05 09:28:54Z des $
    #
    # PAM configuration for the "sshd" service
    #
    
    # auth
    auth        sufficient  /usr/local/lib/pam_ldap.so    no_warn try_first_pass
    auth		sufficient	pam_opie.so		no_warn no_fake_prompts
    auth		requisite	pam_opieaccess.so	no_warn allow_local
    #auth		sufficient	pam_krb5.so		no_warn try_first_pass
    #auth		sufficient	pam_ssh.so		no_warn try_first_pass
    auth		required	pam_unix.so		no_warn try_first_pass
    
    # account
    account     required    /usr/local/lib/pam_ldap.so    no_warn ignore_authinfo_unavail ignore_unknown_user
    account		required	pam_nologin.so
    #account	required	pam_krb5.so
    account		required	pam_login_access.so
    account		required	pam_unix.so
    
    # session
    #session	optional	pam_ssh.so		want_agent
    session     required    /usr/local/lib/pam_mkhomedir.so
    session		required	pam_permit.so
    
    # password
    #password	sufficient	pam_krb5.so		no_warn try_first_pass
    password	required	pam_unix.so		no_warn try_first_pass
    

    – modifier /etc/pam.d/su pour mettre le bon groupe

    [root@app001 ~]# cat /etc/pam.d/su
    #
    # $FreeBSD: releng/10.2/etc/pam.d/su 219663 2011-03-15 10:13:35Z des $
    #
    # PAM configuration for the "su" service
    #
    
    # auth
    auth		sufficient	pam_rootok.so		no_warn
    auth		sufficient	pam_self.so		no_warn
    auth		requisite	pam_group.so		no_warn group=wheel,users root_only fail_safe ruser
    auth		include		system
    
    # account
    account		include		system
    
    # session
    session		required	pam_permit.so
    

    – modifier /etc/pam.d/system

    root@app001 /etc/pam.d]# cat system

    # $FreeBSD: releng/10.2/etc/pam.d/system 197769 2009-10-05 09:28:54Z des $
    #
    # System-wide defaults
    #
    
    # auth
    auth		sufficient	/usr/local/lib/pam_ldap.so   no_warn try_first_pass
    auth		sufficient	pam_opie.so		no_warn no_fake_prompts
    auth		requisite	pam_opieaccess.so	no_warn allow_local
    #auth		sufficient	pam_krb5.so		no_warn try_first_pass
    #auth		sufficient	pam_ssh.so		no_warn try_first_pass
    auth		required	pam_unix.so		no_warn try_first_pass nullok
    
    # account
    #account	required	pam_krb5.so
    account         required        /usr/local/lib/pam_ldap.so   ignore_unknown_user ignore_authinfo_unavail
    account		required	pam_login_access.so
    account		required	pam_unix.so
    
    # session
    #session	optional	pam_ssh.so		want_agent
    session		required	/usr/local/lib/pam_mkhomedir.so
    session		required	pam_lastlog.so		no_fail
    
    # password
    #password	sufficient	pam_krb5.so		no_warn try_first_pass
    password	required	pam_unix.so		no_warn try_first_pass
    

    – modifier /etc/pam.d/passwd

    [root@app001 /etc/pam.d]# cat passwd
    #
    # $FreeBSD: releng/10.2/etc/pam.d/passwd 113967 2003-04-24 12:22:42Z des $
    #
    # PAM configuration for the "passwd" service
    #
    
    # passwd(1) does not use the auth, account or session services.
    
    # password
    #password	requisite	pam_passwdqc.so		enforce=users
    #password  required    pam_ldap.so
    password	required	pam_unix.so		no_warn try_first_pass nullok
    

    – OPTIONNEL : forcer le gidMember

    vi /etc/group
    users:*:100:
    

    – pour tester

    getent passwd
    

    Adapter LDAP pour supporter le SHA512 de postfixadmin

    Dans un prochain post; je présenterais comment créer un schéma LDAP automatiquement en s’appuyant sur un backend SQL; et en l’occurence, celui de postfixadmin.
    Toujours est-il que voici en avance une astuce pour qu’openldap reconnaisse les password SHA512 de postfixadmin.

    * slapd.conf

    Il faut avant tout activer le module sha2 qui permet de supporter des hash SHA étendu (256, 512):

    moduleload      pw-sha2
    

    Le format salt ici est ‘$6$’ qui invoque une méthode hash basée sur SHA512 et fournit 16 caractères de salt.

    password-hash {CRYPT}                                                                                                                                                  
    password-crypt-salt-format "$6$%.16s"
    

    * SQL

    update ldap_attr_mappings set sel_expr='replace(users.password, \'SHA512-CRYPT\', \'CRYPT\')' where id=13;
    
    MySQL [ldap]> select * from ldap_attr_mappings where id=13;
    +----+-----------+--------------+--------------------------------------------------+------------+-----------+----------------------------+----------+-------------+-----
    --------+---------------+
    | id | oc_map_id | name         | sel_expr                                         | sel_expr_u | from_tbls | join_where                 | add_proc | delete_proc | para
    m_order | expect_return |
    +----+-----------+--------------+--------------------------------------------------+------------+-----------+----------------------------+----------+-------------+-----
    --------+---------------+
    | 13 |         1 | userPassword | replace(users.password, 'SHA512-CRYPT', 'CRYPT') | NULL       | users     | users.password IS NOT NULL | NULL     | NULL        |
         3 |             0 |
    +----+-----------+--------------+--------------------------------------------------+------------+-----------+----------------------------+----------+-------------+-----
    --------+---------------+
    1 row in set (0.01 sec)
    
    

    Authentifier Apache vers IMAP

    Authentifier Apache vers IMAP

    Pour avoir une DB user unique, je suis parti sur ma source d’utilisateur et dans mon cas c’est postfixadmin pour les mails.
    Du coup; je me suis amusé à écrire un petit bout perl qui permet à apache de s’auth vers un serveur IMAP.

  • Installer les dépendances
    apt-get install libnet-imap-simple-ssl-perl
    apt-get install libunix-syslog-perl
    apt-get install libapache2-mod-authnz-external
    
  • Protéger les pages Xymon avec l’auth IMAP
     cat /etc/apache2/conf-enabled/xymon.conf
    DefineExternalAuth dovecotpw pipe /etc/apache2/auth/dovecotpw.pl
    
    ScriptAlias /xymon-cgi "/usr/lib/xymon/cgi-bin"
    Directory "/usr/lib/xymon/cgi-bin"
        AllowOverride None
        Options ExecCGI Includes
    
        
    
            AuthType Basic
            AuthName "Xymon Administration"
            Require valid-user
            AuthBasicProvider external
            AuthExternal dovecotpw
    
        
    
  • Ensuite le code perl
     cat /etc/apache2/auth/dovecotpw.pl
    
    #!/usr/bin/perl
    use strict;
    use warnings;
    use Unix::Syslog qw(:macros :subs);
    use Net::IMAP::Simple::SSL;
    
    my $VERSION = '1.0';
    
    my $server = 'imap.distran.org';
    my $port = 993;
    my $use_ssl = 1;
    
    syslog LOG_INFO,"imap-auth: waiting for packet";
    chomp(my $user = );
    chomp(my $password = );
    my $result;
    #print "checking [$user] and [$password]\n";
    syslog(LOG_INFO,"imap-auth: request ('auth', \"$user\", '****')");
    
    # successful authentication
    if (is_valid($user, $password)){
          	$result = 0;
           	syslog(LOG_INFO,"imap-auth: -> +OK");
    } else {
             $result = 1;
    }
    
    closelog;
    exit $result;
    
    sub is_valid
    {
    	my ($user, $password) = @_;
    	my $is_valid = 0;
    
    	# Create the object
    	my $imap = Net::IMAP::Simple->new($server,
    		(
    			port => $port,
    			use_ssl => $use_ssl
    		) ) ||
    
    	die "Unable to connect to IMAP: $Net::IMAP::Simple::errstr\n";
    
    	$imap->starttls;
         	if ( $imap->login("$user", $password) ) {
    		$is_valid = 1;
           	         syslog(LOG_INFO,"imap-auth: -> +OK imap server says you're cool. Welcome.");
    	} else {
           	         syslog(LOG_INFO,"imap-auth: -> -ERR imap server has a problem with you: $! $_ $/ " . $imap->errstr);
    	}
    
    	$imap->quit;
    
    	return ($is_valid);
    }
    
    
  • Check des logs
     tail /var/log/syslog
    
    Nov 24 13:01:05 xymon-server01 perl: imap-auth: waiting for packet
    Nov 24 13:01:05 xymon-server01 perl: imap-auth: request ('auth', "user@domain.com", '****')
    Nov 24 13:01:05 xymon-server01 perl: imap-auth: -> +OK imap server says you're cool. Welcome.
    Nov 24 13:01:05 xymon-server01 perl: imap-auth: -> +OK
    
    
  • Si le serveur IMAP est local sur la meme machine
     cat /etc/apache2/auth/dovecotpw.sh
    #!/bin/bash
    read DCUSER
    read DCPASS
    /usr/bin/doveadm auth ${DCUSER} ${DCPASS}
    exit $?
    
  • Mysql m’a “tuer” ! Maia aussi !

    Tout part d’une notification du monitoring xymon à propos de portaudit concernant une vulnérabilité sur mysql56-server.

    Capture d’écran 2015-07-21 à 16.30.02

     

    S’en suit la procédure standard de mise à jour:

    root@distran:~ # portmaster mysql56-server

    Tout se déroule correctement jusqu’au moment ou je décide de vérifier l’accès á la base de données.
    Et la c’est le FAIL. Il me dit qu’il trouve pas la socket.

    Le premier réflèxe est d’aller jeter un oeil au log de mysql:

    20:06:09 UTC – mysqld got signal 11 ;
    This could be because you hit a bug. It is also possible that this binary
    or one of the libraries it was linked against is corrupt, improperly built,
    or misconfigured. This error can also be caused by malfunctioning hardware.
    We will try our best to scrape up some info that will hopefully help
    diagnose the problem, but since we have already crashed,
    something is definitely wrong and this may fail.
    Et mysql crash en boucle avec ce message sans plus de détail.
    Mes mails reposant sur postfixadmin et donc la base de données, je décide de ne pas perdre de temps et de reínstaller les bases avec les dumps nocturnes.
    La perte de données est faible voir nulle car ce sont des bases de données pour les mails et je n’ajoute pas de nouveaux utilisateurs chaque jour.
    Néanmoins, dans le cas d’une base critique fréquemment mise á jour, j’aurais utilisé les bin-log.
    Techniquement, je conserve un backup de la base broken et je recommence from scratch:
    # mv /var/db/mysql /var/db/mysql.old
    # mkdir /var/db/mysql ; chown mysql: /var/db/mysql
    # /usr/local/etc/rc.d/mysql start
    
    
    Puis utilisation des dump noctures:
    # echo « create database mysql » | mysql
    
    Je relance mysql et la rebelle tout crash en continue avec le même message que plus haut.. Youpi ! vive les backup qui marchent pas ! 🙂
    Je décide de rebuild tout sauf la db mysql et de recréer les utilisateurs via les grant d’origine á la main en récupérant les l/p dans les fichiers de conf postfixadmin et maia.
    # echo « create database postfix » | mysql
    # echo « create database maia » | mysql
    # zcat postfix_xxxxx.sql.gz | mysql  postfix;
    # cat maia_xxxxx.sql.gz | mysql maia
    # mysql
    mysql> grant all privileges to postfix.* blabla
    mysql> grant all privileges to maia.* blabla
    
    A ce point, on se dit “ouf” c’est fini.
    Et même pas, dans les logs maillog apparait ce joli message:
    Jul 19 22:31:35 distran maiad[15376]: (15376-03) TROUBLE in check_mail: Take Action! FAILED: DBD::mysql::st execute failed: Column ‘autolearn_status’ cannot be null at /usr/local/sbin/maiad line 4410, <GEN18> line 159.
    Jul 19 22:31:35 distran maiad[15376]: (15376-03) PRESERVING EVIDENCE in /var/maiad/tmp/maia-20150719T223135-15376
    Jul 19 22:31:35 distran postfix/smtp[16349]: C2D1E895191: to=<nicolas@lienard.name>, orig_to=<root@distran.org>, relay=127.0.0.1[127.0.0.1]:10024, delay=0.9, delays=0.27/0.01/0/0.62, dsn=4.5.0, status=deferred (host 127.0.0.1[127.0.0.1] said: 451 4.5.0 Error in processing, id=15376-03, Take Action! FAILED: DBD::mysql::st execute failed: Column ‘autolearn_status’ cannot be null at /usr/local/sbin/maiad line 4410, <GEN18> line 159. (in reply to end of DATA command))
     Humm, je me fais tué une 2eme fois par maia.
    il est tard, et je veux en finir. je google rapidement mais ne trouve rien sur ce bug.
    Je jete un oeil sur
     /usr/local/sbin/maiad a la ligne 4410
    UPDATE maia_mail SET score = ?, autolearn_status = ? WHERE id = ?
    
    Ok donc il y a un souci lors des updates sql de maia avec le champs autolearn_status qui ne peut plus être “null”.
    Je regarde la description de la table en question:
    mysql> desc maia_mail;
    
    +------------------+------------------+------+-----+-------------+----------------+
    | Field            | Type             | Null | Key | Default     | Extra          |
    +------------------+------------------+------+-----+-------------+----------------+
    | id               | int(10) unsigned | NO   | PRI | NULL        | auto_increment |
    | received_date    | datetime         | NO   | MUL | NULL        |                |
    | size             | int(10) unsigned | NO   |     | NULL        |                |
    | sender_email     | varbinary(255)   | NO   | MUL | NULL        |                |
    | envelope_to      | blob             | NO   |     | NULL        |                |
    | subject          | varchar(255)     | NO   | MUL | NULL        |                |
    | contents         | longblob         | NO   |     | NULL        |                |
    | score            | float            | YES  | MUL | NULL        |                |
    | autolearn_status | varchar(15)      | NO   |     | unavailable |                |
    +------------------+------------------+------+-----+-------------+————————+
    
    Le paramètre NULL est effectivement à “No”. Comment cela pouvait-il fonctionner auparavant ??
    Je regarde á l’intérieur et il y a bien des rows á null donc ca marchait comment avant ? 🙂
    Pour en finir. j’altère la table:
    mysql> alter table   maia_mail MODIFY autolearn_status varchar(15)
    
    Le résultat:
    mysql> desc maia_mail;
    
    +------------------+------------------+------+-----+-------------+----------------+
    | Field            | Type             | Null | Key | Default     | Extra          |
    +------------------+------------------+------+-----+-------------+----------------+
    | id               | int(10) unsigned | NO   | PRI | NULL        | auto_increment |
    | received_date    | datetime         | NO   | MUL | NULL        |                |
    | size             | int(10) unsigned | NO   |     | NULL        |                |
    | sender_email     | varbinary(255)   | NO   | MUL | NULL        |                |
    | envelope_to      | blob             | NO   |     | NULL        |                |
    | subject          | varchar(255)     | NO   | MUL | NULL        |                |
    | contents         | longblob         | NO   |     | NULL        |                |
    | score            | float            | YES  | MUL | NULL        |                |
    | autolearn_status | varchar(15)      | YES  |     | unavailable |                |
    +------------------+------------------+------+-----+-------------+————————+
    
    Et tout refonctionne ! OUF !