From: Julien Moutinho Date: Sat, 16 Feb 2013 16:31:30 +0000 (+0100) Subject: Modification : vm_host{,ed} : paravirtualised machine (PV). X-Git-Url: http://git.cyclocoop.org/?p=lhc%2Fateliers.git;a=commitdiff_plain;h=1f1550e467bccfbac8a8f88b93db6355745794be Modification : vm_host{,ed} : paravirtualised machine (PV). --- diff --git a/README b/README new file mode 100644 index 0000000..b4b463b --- /dev/null +++ b/README @@ -0,0 +1,40 @@ +DESCRIPTION: + ce fichier donne une idée des commandes à effectuer + pour effectuer diverses tâches. +ATTENTION: + il peut y avoir des oublis ; + ne pas hésiter donc à bien relire les règles + _avant_ de les exécuter. +NOTE: + à priori les règles sont pensées pour être exécutées + plusieurs fois selon les erreurs que l'on rencontre + ou les modifications que l'on y apporte. + +TASK: obtenir une installation chrootable + @host % export TRACE=1 + @host % ./vm_host disk_mount + @host % ./vm_host disk_format + @host % ./vm_host part_lvm_format + @host % ./vm_host part_root_format + @host % ./vm_host part_boot_format + @host % ./vm_host part_swap_format + @host % ./vm_host part_var_format + @host % ./vm_host part_home_format + @host % ./vm_host debian_install + @host % ./vm_host disk_umount +TASK: obtenir une installation démarable + @host % ./vm_host chroot + @host % export TRACE=1 LANG=C LC_CTYPE=C + @host % /root/tool/vm/vm_hosted init + @host % exit +TASK: initialiser la VM + @host % vm_host vm_init + @host % vm_host vm_start + @hosted % vm_hosted user_init +TASK: démarrer la VM + @host % vm_host vm_start +TASK: ajouter un administrateur + @hosted % vm_hosted user_admin_add $user # NOTE: remplacer $user +TASK: démarrer la VM + @host % vm_host vm_start + @remote % vm_remote disk_send_key diff --git a/ateliers_host b/ateliers_host deleted file mode 100755 index 46ef940..0000000 --- a/ateliers_host +++ /dev/null @@ -1,382 +0,0 @@ -#!/bin/sh -set -e -f ${DRY_RUN:+-n} -u - -tool=${0%/*} -. "$tool"/env.sh -. "$tool"/inc.sh - -rule_help () { - cat >&2 <<-EOF - DESCRIPTION: ce script regroupe des fonctions utilitaires - pour gérer la VM des ateliers _depuis_ son hôte ; - il sert à la fois d'outil et de documentation. - Voir \`$tool/ateliers_hosted' pour les utilitaires côté VM hébergée. - SYNTAX: $0 \$RULE \${RULE}_SYNTAX - RULES: - $(sed -ne 's/^rule_\([^_][^ ]*\) () {\( *#.*\|\)/\t\1\2/p' "$tool"/env.sh "$0") - ENVIRONMENT: - TRACE # affiche les commandes avant leur exécution - $(sed -ne 's/^readonly \([^ ][^ =]*\).*}\( *#.*\|\)$/\t$\1\2/p' "$tool"/env.sh "$0") - EOF - } - -readonly vm_dev_disk=/dev/mapper/domU-$(printf %s "$vm_fqdn-disk" | sed -e 's/-/--/g') -readonly vm_dev_disk_boot="${vm_dev_disk}1" - -rule_xen_config_init () { - sudo tee /etc/xen/$vm_fqdn.cfg <<-EOF - # -*- mode: python; -*- - import os, re - name = "$vm_fqdn" - arch = os.uname()[4] - memory = 2048 - vcpus = 1 - vif = ['mac=$vm_mac,bridge=$vm_bridge'] - disk = ['phy:/dev/domU/$vm_fqdn-disk,hda,w'] - kernel = "/usr/lib/xen-4.0/boot/hvmloader" - builder = 'hvm' - device_model = 'qemu-dm' - acpi = 1 - apic = 1 - # boot on floppy (a), hard disk (c) or CD-ROM (d) - #boot = 'd' - - #vnc = 1 - #sdl = 0 - #vncconsole = 0 - #vnclisten = "0.0.0.0" - #vncpasswd = "" - #usbdevice = 'tablet' - - keymap = 'fr' - serial = 'pty' - on_poweroff = 'destroy' - on_reboot = 'restart' - on_crash = 'restart' - EOF - } -rule_xen_on () { - sudo xm create $vm_fqdn.cfg - } -rule_xen_off () { - sudo xm shutdown $vm_fqdn.cfg - } - -rule_disk_mount () { # DESCRIPTION: montage du disque de la VM depuis l'hôte - sudo kpartx -a -v /dev/domU/$vm_fqdn-disk - #sudo xm block-attach 0 phy:/dev/domU/$vm_fqdn-disk $vm_dev_disk w - } -rule_disk_umount () { # DESCRIPTION: démontage du disque de la VM depuis l'hôte - rule_part_boot_umount - case $vm_use_lvm in - (yes) - rule_part_lvm_umount - ;; - (no) - rule_part_root_umount - rule_part_var_umount - rule_part_home_umount - ;; - (*) exit 1;; - esac - sudo kpartx -d -v /dev/domU/$vm_fqdn-disk - #sudo xm block-detach 0 $vm_dev_disk - # XXX: DANGEREUX ; si jamais il bloque parce que le disque était encore utilisé : - # utiliser xm block-detach 0 $vm_dev_disk --force ; - # ôter les éventuels mappages LVM concernés avec dmsetup table et dmsetup remove --force ; - # ôter les mappages concernés dans /etc/lvm/cache/.cache, - # et pour bien trouver tous les mappages : - # % sudo find /dev -type l -exec sh -c 'printf "%s -> " "$@"; readlink "$@"' - {} \; | grep $vm_dev_disk - # enfin, ôter l'éventuel verrou dans /var/lock/lvm/ - } - -case $vm_use_lvm in - (no) - readonly vm_dev_disk_swap="${vm_dev_disk}5" - readonly vm_dev_disk_root="${vm_dev_disk}6" - readonly vm_dev_disk_var="${vm_dev_disk}7" - readonly vm_dev_disk_home="${vm_dev_disk}8" - ;; - (yes) - readonly vm_lvm_pv="${vm_dev_disk}2" - readonly vm_dev_disk_swap=/dev/$vm_lvm_vg/${vm_lvm_lv}_swap - readonly vm_dev_disk_root=/dev/$vm_lvm_vg/${vm_lvm_lv}_root - readonly vm_dev_disk_var=/dev/$vm_lvm_vg/${vm_lvm_lv}_var - readonly vm_dev_disk_home=/dev/$vm_lvm_vg/${vm_lvm_lv}_home - ;; - (*) - exit 1;; - esac - -rule_disk_format () { # DESCRIPTION: partitionnage du disque de la VM - case $vm_use_lvm in - (no) - sudo sfdisk $vm_dev_disk <<-EOF - # partition table of $vm_dev_disk - unit: sectors - - ${vm_dev_disk}1 : start= 63, size= 497952, Id=83, bootable - ${vm_dev_disk}2 : start= 498015, size=418927005, Id= 5 - ${vm_dev_disk}3 : start= 0, size= 0, Id= 0 - ${vm_dev_disk}4 : start= 0, size= 0, Id= 0 - ${vm_dev_disk}5 : start= 498078, size= 1959867, Id=82 - ${vm_dev_disk}6 : start= 2458008, size= 29302497, Id=83 - ${vm_dev_disk}7 : start= 31760568, size= 9767457, Id=83 - ${vm_dev_disk}8 : start= 41528088, size=377896932, Id=83 - EOF - ;; - (yes) - sudo sfdisk $vm_dev_disk <<-EOF - # partition table of $vm_dev_disk - unit: sectors - - ${vm_dev_disk}1 : start= 63, size= 497952, Id=83, bootable - ${vm_dev_disk}2 : start= 498015, size=418927005, Id=8E - EOF - ;; - (*) exit 1;; - esac - #sudo partprobe $vm_dev_disk - sudo kpartx -u -v /dev/domU/$vm_fqdn-disk - } - -rule_part_lvm_format () { - rule_part_lvm_umount - ! sudo vgs | grep -q "^ $vm_lvm_vg " || - sudo vgremove $vm_lvm_vg - sudo pvcreate --dataalignment 512k $vm_lvm_pv - sudo vgcreate --dataalignment 512k $vm_lvm_vg $vm_lvm_pv - sudo lvcreate --contiguous y -n ${vm_lvm_lv}_swap -L 1G $vm_lvm_vg - sudo lvcreate --contiguous y -n ${vm_lvm_lv}_root -L 15G $vm_lvm_vg - sudo lvcreate --contiguous y -n ${vm_lvm_lv}_var -L 5G $vm_lvm_vg - sudo lvcreate --contiguous y -n ${vm_lvm_lv}_home -l 99%FREE $vm_lvm_vg - rule_part_lvm_umount - } -rule_part_lvm_mount () { - sudo vgchange -a y $vm_lvm_vg - sudo lvchange -a y $vm_lvm_lv - } -rule_part_lvm_umount () { - rule_part_root_umount - rule_part_var_umount - rule_part_home_umount - if sudo vgs | grep -q "^ $vm_lvm_vg " - then - sudo lvchange -a n $vm_lvm_vg - sudo vgchange -a n $vm_lvm_vg - fi - } - -rule_part_randomize () { # SYNTAX: $part # NOTE: à anticiper - local part=$1 - eval "sudo dd if=/dev/urandom of=\$vm_dev_disk_$part" - } -rule_part_randomize_stat () { # SYNTAX: $part # DESCRIPTION: fait afficher la progression de rule_part_clean - local part=$1 - eval "pkill -USR1 -f \"^dd if=/dev/urandom of=\$vm_dev_disk_$part\"" - } -rule__part_encrypted_format () { # SYNTAX: $part # DESCRIPTION: formatage d'une partition distincte de / - # NOTE: la clef de chiffrement est dérivée de celle de /, - # / doit être déchiffrée pour que cela fonctionne. - local part=$1 - eval "local dev=\$vm_dev_disk_$part" - test ! -e /dev/mapper/${vm}_root_deciphered || - sudo /bin/sh -c "/lib/cryptsetup/scripts/decrypt_derived ${vm}_root_deciphered | - cryptsetup luksFormat --hash=sha512 --key-size=512 \ - --cipher=aes-xts-essiv:sha256 --key-file=- --align-payload=8 $dev" - } -rule__part_encrypted_mount () { # SYNTAX: $part - local part=$1 - eval "local dev=\$vm_dev_disk_$part" - test -e /dev/mapper/${vm}_${part}_deciphered || - sudo /bin/sh -c "/lib/cryptsetup/scripts/decrypt_derived ${vm}_root_deciphered | - cryptsetup luksOpen --key-file=- $dev ${vm}_${part}_deciphered" - } -rule__part_encrypted_umount () { # SYNTAX: $part - local part=$1 - eval "local dev=\$vm_dev_disk_$part" - test ! -e /dev/mapper/${vm}_${part}_deciphered || - sudo cryptsetup luksClose ${vm}_${part}_deciphered - } - -rule_part_root_format () { - if ! mount | grep -q "^$vm_dev_disk_root " - then - sudo cryptsetup luksFormat --hash=sha512 --key-size=512 \ - --cipher=aes-xts-essiv:sha256 --key-file=- --align-payload=8 $vm_dev_disk_root - sudo cryptsetup luksOpen --key-file=- $vm_dev_disk_root ${vm}_root_deciphered - sudo mke2fs -t ext4 -c -c -m 5 -T ext4 -b $vm_e2fs_block_size \ - -E resize=30G${vm_e2fs_extended_options} \ - -L ${vm}_root \ - /dev/mapper/${vm}_root_deciphered - ! mountpoint -q /mnt/$vm_fqdn - sudo mount -v /dev/mapper/${vm}_root_deciphered /mnt/$vm_fqdn - mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/boot - mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/dev - mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/home - mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/proc - mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/sys - mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/var - mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/root - mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/root/tool - mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/root/tool/ateliers - sudo umount -v /mnt/$vm_fqdn - sudo cryptsetup luksClose ${vm}_root_deciphered - fi - } -rule_part_root_mount () { - test -e /dev/mapper/${vm}_root_deciphered || - sudo cryptsetup luksOpen $vm_dev_disk_root ${vm}_root_deciphered - mountpoint -q /mnt/$vm_fqdn || - sudo mount -v -t ext4 /dev/mapper/${vm}_root_deciphered /mnt/$vm_fqdn - } -rule_part_root_umount () { - ! mountpoint -q /mnt/$vm_fqdn || - sudo umount -v /mnt/$vm_fqdn - ! test -e /dev/mapper/${vm}_root_deciphered || - sudo cryptsetup luksClose ${vm}_root_deciphered - } -rule_part_root_backup_luks () { - sudo cryptsetup luksHeaderBackup $vm_dev_disk_root --header-backup-file ./root.luks - } -rule_part_swap_format () { - rule__part_encrypted_format swap - rule__part_encrypted_mount swap - sudo mkswap -f -L ${vm}_swap /dev/mapper/${vm}_swap_deciphered - rule__part_encrypted_umount swap - } -rule_part_boot_format () { - mount | grep -q "^$vm_dev_disk_boot " || - sudo mke2fs -t ext2 -c -c -m 5 -T small \ - -E resize=1G${vm_e2fs_extended_options} \ - -L ${vm}_boot $vm_dev_disk_boot - } -rule_part_boot_mount () { - mountpoint -q /mnt/$vm_fqdn - test -d /mnt/$vm_fqdn/boot - mountpoint -q /mnt/$vm_fqdn/boot || - sudo mount -v -t ext2 $vm_dev_disk_boot /mnt/$vm_fqdn/boot - } -rule_part_boot_umount () { - ! mountpoint -q /mnt/$vm_fqdn/boot || - sudo umount -v /mnt/$vm_fqdn/boot - } -rule_part_var_format () { - rule__part_encrypted_format var - rule__part_encrypted_mount var - sudo mke2fs -t ext4 -c -c -m 5 -T ext4 -b $vm_e2fs_block_size \ - -E resize=10G${vm_e2fs_extended_options} \ - -L ${vm}_var \ - /dev/mapper/${vm}_var_deciphered - rule__part_encrypted_umount var - } -rule_part_var_mount () { - rule__part_encrypted_mount var - mountpoint -q /mnt/$vm_fqdn/var || - sudo mount -v -t ext4 /dev/mapper/${vm}_var_deciphered /mnt/$vm_fqdn/var - } -rule_part_var_umount () { - ! mountpoint -q /mnt/$vm_fqdn/var || - sudo umount -v /mnt/$vm_fqdn/var - rule__part_encrypted_umount var - } -rule_part_home_format () { - rule__part_encrypted_format home - rule__part_encrypted_mount home - sudo mke2fs -t ext4 -c -c -m 0 -T ext4 -b $vm_e2fs_block_size \ - -E resize=400G${vm_e2fs_extended_options} \ - -L ${vm}_home \ - /dev/mapper/${vm}_home_deciphered - # NOTE: -O quota pas supporté par e2fsprogs/squeeze - rule__part_encrypted_umount home - } -rule_part_home_mount () { - rule__part_encrypted_mount home - mountpoint -q /mnt/$vm_fqdn/home || - sudo mount -v -t ext4 /dev/mapper/${vm}_home_deciphered /mnt/$vm_fqdn/home - } -rule_part_home_umount () { - ! mountpoint -q /mnt/$vm_fqdn/home || - sudo umount -v /mnt/$vm_fqdn/home - rule__part_encrypted_umount home - } - -rule_debian_install () { - rule_part_root_mount - rule_part_boot_mount - rule_part_var_mount - sudo DEBOOTSTRAP_DIR=/usr/share/debootstrap/ debootstrap \ - --arch=$vm_arch --verbose --keyring=/usr/share/keyrings/debian-archive-keyring.gpg \ - --exclude=vim-tiny \ - --include=$(printf '%s,' \ - acl \ - bsdmainutils \ - busybox \ - ca-certificates \ - console-setup \ - cryptsetup \ - dash \ - dnsutils \ - dropbear \ - etckeeper \ - hashalot \ - htop \ - ifupdown \ - initramfs-tools \ - kbd \ - less \ - mosh \ - ncurses-term \ - openssh-client \ - openssh-server \ - openssl \ - pciutils \ - procps \ - quota \ - quotatool \ - rsync \ - screen \ - sudo \ - sysprofile \ - vim-nox \ - wget \ - zsh \ - ) \ - $vm_lsb_name /mnt/$vm_fqdn/ \ - http://ftp.fr.debian.org/debian/ - } -rule_chroot () { - rule_part_root_mount - rule_part_boot_mount - rule_part_var_mount - #rule_part_home_mount - mountpoint -q /mnt/$vm_fqdn/proc || - sudo mount -t proc proc /mnt/$vm_fqdn/proc - mountpoint -q /mnt/$vm_fqdn/sys || - sudo mount -t sysfs sys /mnt/$vm_fqdn/sys - mountpoint -q /mnt/$vm_fqdn/dev || - sudo mount --bind /dev /mnt/$vm_fqdn/dev - mountpoint -q /mnt/$vm_fqdn/root/tool/ateliers || - sudo mount --bind "$tool" /mnt/$vm_fqdn/root/tool/ateliers - sudo chroot /mnt/$vm_fqdn /bin/dash || true - rule__chroot_clean - } -rule__chroot_clean () { - ! sudo mountpoint -q /mnt/$vm_fqdn/root/tool/ateliers || - sudo umount -v /mnt/$vm_fqdn/root/tool/ateliers - ! mountpoint -q /mnt/$vm_fqdn/dev || - sudo umount -v /mnt/$vm_fqdn/dev - ! mountpoint -q /mnt/$vm_fqdn/sys || - sudo umount -v /mnt/$vm_fqdn/sys - ! mountpoint -q /mnt/$vm_fqdn/proc || - sudo umount -v /mnt/$vm_fqdn/proc - rule_part_home_umount - rule_part_var_umount - rule_part_boot_umount - rule_part_root_umount - } - -rule=${1:-help} -${1+shift} -set "${TRACE:+-x}" -rule_$rule "$@" diff --git a/ateliers_hosted b/ateliers_hosted deleted file mode 100755 index 3359fb6..0000000 --- a/ateliers_hosted +++ /dev/null @@ -1,556 +0,0 @@ -#!/bin/sh -set -e -f ${DRY_RUN:+-n} -u -tool=${0%/*} -. "$tool"/env.sh -. "$tool"/inc.sh - -rule_help () { - cat >&2 <<-EOF - DESCRIPTION: ce script regroupe des fonctions utilitaires - pour gérer la VM des ateliers _depuis_ la VM hébergée ; - il sert à la fois d'outil et de documentation. - Voir \`$tool/ateliers_host' pour les utilitaires côté machine hôte. - SYNTAX: $0 \$RULE \${RULE}_SYNTAX - RULES: - $(sed -ne 's/^rule_\([^_][^ ]*\) () {\( *#.*\|\)/\t\1\2/p' "$tool"/env.sh "$0") - ENVIRONMENT: - TRACE # affiche les commandes avant leur exécution - $(sed -ne 's/^readonly \([^ ][^ =]*\).*}\( *#.*\|\)$/\t$\1\2/p' "$tool"/env.sh "$0") - EOF - } - -rule_filesystem_init () { - mk_reg mod= own= --append /etc/sysctl.conf <<-EOF - vm.swappiness = 10 # NOTE: n'utilise le swap qu'en cas d'absolue nécessité - vm.vfs_cache_pressure=50 - EOF - } -rule_shell_source () { - . /etc/profile - } -rule_network_init () { - mk_reg mod= own= /etc/hostname <<-EOF - $vm - EOF - grep -q " $vm\$" /etc/hosts || - mk_reg mod= own= --append /etc/hosts <<-EOF - 127.0.0.1 $vm_fqdn $vm - EOF - mk_reg mod= own= /etc/network/interfaces <<-EOF - auto lo - iface lo inet loopback - - auto eth0=grenode - iface grenode inet static - address $vm_ipv4 - gateway $vm_ipv4 # NOTE: proxy_arp sur la passerelle permet d'utiliser la même adresse - network $vm_ipv4 - broadcast $vm_ipv4 - netmask 255.255.255.255 - mtu 1300 # TODO: voir si c'est nécessaire à Lyon - up ip address add $vm_ipv4/32 dev \$IFACE - down ip address delete $vm_ipv4/32 dev \$IFACE - EOF - } -rule_apt_init () { - mk_reg mod= own= /etc/apt/sources.list <<-EOF - deb http://ftp.fr.debian.org/debian $vm_lsb_name main contrib non-free - EOF - mk_reg mod= own= /etc/apt/sources.list.d/openerp.list <<-EOF - deb http://nightly.openerp.com/trunk/nightly/deb/ ./ - EOF - mk_reg mod= own= /etc/apt/sources.list.d/$vm_lsb_name-backports.list <<-EOF - deb http://backports.debian.org/debian-backports $vm_lsb_name-backports main contrib non-free - EOF - mk_reg mod= own= /etc/apt/preferences <<-EOF - Package: * - Pin: release a=$vm_lsb_name - Pin-Priority: 170 - - Package: * - Pin: release a=$vm_lsb_name-backports - Pin-Priority: 200 - EOF - } -rule_boot_init () { - mk_reg mod= own= /etc/fstab <<-EOF - # - LABEL=boot /boot ext2 defaults,no-auto 0 0 - proc /proc proc defaults 0 0 - sysfs /sys sysfs defaults 0 0 - tmpfs /tmp tmpfs rw,nosuid,nodev,auto,size=200m,nr_inodes=1000k,mode=1777,noatime,nodiratime 0 0 - /dev/mapper/${vm}_root_deciphered / ext4 defaults,errors=remount-ro,acl,noatime 0 1 - /dev/mapper/${vm}_var_deciphered /var ext4 defaults,errors=remount-ro,acl,noatime 0 1 - /dev/mapper/${vm}_home_deciphered /home ext4 defaults,errors=remount-ro,acl,noatime,usrquota,grpquota 0 0 - /dev/mapper/${vm}_swap_deciphered swap swap sw 0 0 - EOF - mk_reg mod= own= /etc/crypttab <<-EOF - # - ${vm}_root_deciphered LABEL=${vm}_root ${vm}_root luks - ${vm}_var_deciphered LABEL=${vm}_var ${vm}_root_deciphered luks,lvm=$vm_lvm_vg,keyscript=/lib/cryptsetup/scripts/decrypt_derived - ${vm}_swap_deciphered LABEL=${vm}_swap ${vm}_root_deciphered luks,lvm=$vm_lvm_vg,keyscript=/lib/cryptsetup/scripts/decrypt_derived - ${vm}_home_deciphered LABEL=${vm}_home ${vm}_root_deciphered luks,lvm=$vm_lvm_vg,keyscript=/lib/cryptsetup/scripts/decrypt_derived - EOF - mk_reg mod= own= /etc/initramfs-tools/modules <<-EOF - #loop - sha1_generic - sha256_generic - sha512_generic - aes-x86_64 - xts - EOF - mk_reg mod= own= --append /etc/default/grub <<-EOF - GRUB_CMDLINE_LINUX="vt.default_utf8=1 rootfstype=ext4 loglevel=5 console=hvc0 resume=/dev/mapper/${vm}_swap_deciphered" - EOF - } -rule_user_admin_add () { # SYNTAX: - admin=$1 - ! id "$admin" || adduser "$admin" - eval home="~$admin" - adduser "$admin" sudo - mk_reg mod=0400 own="$admin:$admin" "$home"/etc/ssh/authorized_keys <"$tool"/key/"$admin".ssh.pub - } -rule_user_mail_format () { - mk_dir mod=0770 own=root:adm /etc/skel/etc/procmail - mk_dir mod=0770 own=root:adm /etc/skel/var/mail - mk_dir mod=0770 own=root:adm /etc/skel/var/cache/procmail - mk_reg mod=0660 own=root:adm /etc/skel/etc/procmail/delivery.rc <<-EOF - # vim: ft=procmail - - # NOTE: paramètres passés par postfix - SENDER=\$1 - RECIPIENT=\$2 - USER=\$3 - EXTENSION=\$4 - DOMAIN=\$5 - ORIGINAL_RECIPIENT=\$6 - - PATH="\$HOME/bin:/usr/local/bin:/usr/bin:/bin" - MAILDIR="\$HOME/var/mail/" - DEFAULT="\$MAILDIR" - #LOGFILE=`cd="\$HOME/var/log/procmail/" d=\$(date +"%Y-%m-%d"); ln -fns "\$d.log" "\$cd/current.log"; printf %s "\$cd/\$d.log"` - LOGFILE="/dev/null" - LOGABSTRACT=all - LOGABSTRACT - VERBOSE - SHELL=/bin/sh - SHELLMETAS=&|<>~;?*%{} - - # DESCRIPTION: supprime les doublons en fonction du champ Message-Id - #:0 Wh: "\$HOME/var/cache/procmail/msgid\$LOCKEXT" - #| formail -D 8192 "\$HOME/var/cache/procmail/msgid" - - # DESCRIPTION: fait suivre à l'adresse configurée dans /etc/passwd ; on peut aussi utiliser ~/.forward - EMAIL=`sed /etc/passwd -ne "/^\$USER:/s/[^:]*:[^:]*:[^:]*:[^:]*:[^,]*,[^,]*,[^,]*,[^,]*,\([^:]*\):.*/\1/p"` - # NOTE: récupère l’adresse courriel dans le champ GECOS - FROM_=`formail -c -x "From " | sed -e 's/^\s*\([^ \t]*\).*/\1/g'` - # NOTE: récupère l’expéditeur inscrit sur l’enveloppe - :0 - | \$SENDMAIL -i -bm -f "\$FROM_" "\${EMAIL/@/\${EXTENSION:++\${EXTENSION}}@}" - - # DESCRIPTION: IMAP - #:0 - #| /usr/lib/dovecot/deliver -f "\$SENDER" -a "\$RECIPIENT" - - # DESCRIPTION: UUCP - #:0 - #| /usr/bin/uux \ - # -I "\$HOME/etc/uucp/uucp.cfg" \ - # --nouucico \ - # --notification=error \ - # --requestor "\$USER" \ - # - "\$USER!rmail" "(\$USER)" - EOF - mk_reg mod=0664 own=root:root /etc/postfix/main.cf <<-EOF - # /etc/postfix/main.cf - # SEE: http://postfix.traduc.org/index.php/TLS_README.html - - parent_domain_matches_subdomains = - #debug_peer_list - #fast_flush_domains - #mynetworks - #permit_mx_backup_networks - #qmqpd_authorized_clients - #smtpd_access_maps - mydomain = $vm_domainname - myorigin = \$mydomain - myhostname = $vm_hostname.\$mydomain - mail_name = \$myhostname - mydestination = - $vm_hostname - \$myhostname - \$myorigin - mynetworks = - 127.0.0.0/8 - #[::1]/128 - inet_protocols = ipv4 - # "all" to activate IPv6 - inet_interfaces = all - permit_mx_backup_networks = - - alias_database = - hash:/etc/aliases - # NOTE: fichier de hash contenant une table d’alias mail. - # Celle-ci est éditable dans /etc/aliases, puis (indispensable) - # regénérée en hash grâce à la commande newaliases qui produit /etc/aliases.db - alias_maps = - hash:/etc/aliases - recipient_delimiter = + - # NOTE: séparateur entre le nom d’utilisateur - # et les extensions d’adresse (par défaut le signe +). - #virtual_alias_domains = - virtual_alias_maps = - hash:/etc/postfix/\$mydomain/virtual - # NOTE: do not specify virtual alias domain names in the main.cf - # mydestination or relay_domains configuration parameters. - # - # With a virtual alias domain, the Postfix SMTP server - # accepts mail for known-user@virtual-alias.domain, and - # rejects mail for unknown-user@virtual-alias.domain as - # undeliverable. - #relayhost = - relay_clientcerts = - hash:/etc/postfix/\$mydomain/smtpd/tls/relay_clientcerts - relay_domains = - \$mydestination - # NOTE: ajouter les domaines pour lesquels on est backup MX ici, - # pas dans mydestination ou virtual_alias... - - maximal_queue_lifetime = 5d - - header_checks = - regexp:/etc/postfix/\$mydomain/header_checks - mime_header_checks = - nested_header_checks = - milter_header_checks = - body_checks = - - #content_filter = amavisfeed:[127.0.0.1]:10024 - #receive_override_options = no_address_mappings - # no_unknown_recipient_checks - # Do not try to reject unknown recipients (SMTP server only). - # This is typically specified AFTER an external content filter. - # no_address_mappings - # Disable canonical address mapping, virtual alias map expansion, - # address masquerading, and automatic BCC (blind carbon-copy) recipients. - # This is typically specified BEFORE an external content filter (eg. amavis). - # no_header_body_checks - # Disable header/body_checks. This is typically specified AFTER an external content filter. - # no_milters - # Disable Milter (mail filter) applications. This is typically specified AFTER an external content filter. - #local_header_rewrite_clients = - transport_maps = - hash:/etc/postfix/\$mydomain/transport_maps - mailbox_command = - /usr/bin/procmail -t -a "\$SENDER" -a "\$RECIPIENT" -a "\$USER" -a "\$EXTENSION" -a "\$DOMAIN" -a "\$ORIGINAL_RECIPIENT" "\$HOME/etc/procmail/delivery.rc" - mailbox_size_limit = 0 - biff = no - # Activer la notification en cas de réception de nouveaux e-mails dans la console (yes / no). - append_dot_mydomain = no - # appending .domain is the MUA's job. - - #tls_random_source = - # dev:/dev/urandom - # Non-blocking - #tls_random_reseed_period = 3600s - #tls_random_exchange_name = - # \${data_directory}/prng_exch - # NOTE: à ne pas mettre dans la cage chroot - #tls_random_bytes = 32 - #tls_random_prng_update_period = 3600s - #tls_high_cipherlist = AES256-SHA - # NOTE: postconf(5) déconseille de changer ceci - - #smtp_cname_overrides_servername = no - smtp_connect_timeout = 60s - #smtp_tls_CAfile = /etc/postfix/\$mydomain/smtp/tls/ca/crt.pem - #smtp_tls_CApath = /etc/postfix/\$mydomain/smtp/tls/ca/ - #smtp_tls_cert_file = /etc/postfix/\$mydomain/smtp/tls/crt.pem - #smtp_tls_key_file = /etc/postfix/\$mydomain/smtp/tls/key.pem - #smtp_tls_per_site = hash:/etc/postfix/\$mydomain/smtp/tls/per_site - # NOTE: déprécié en faveur de smtp_tls_policy_maps - smtp_tls_policy_maps = hash:/etc/postfix/\$mydomain/smtp/tls/policy - smtp_tls_fingerprint_digest = sha1 - smtp_tls_scert_verifydepth = 5 - #smtp_tls_secure_cert_match = nexthop, dot-nexthop - #smtp_tls_verify_cert_match = hostname - #smtp_tls_note_starttls_offer = yes - smtp_tls_loglevel = 1 - smtp_tls_protocols = !SSLv2, !SSLv3 - # Only allow TLSv* - smtp_tls_session_cache_database = btree:/var/lib/postfix/smtp_tls_session_cache - #smtp_tls_session_cache_timeout = 3600s - smtp_tls_security_level = may - smtp_header_checks = regexp:/etc/postfix/\$mydomain/smtp/header_checks - smtp_body_checks = - smtp_mime_header_checks = - smtp_nested_header_checks = - - smtpd_starttls_timeout = 300s - smtpd_banner = - \$myhostname ESMTP \$mail_name (Debian/GNU) - - # Restrictions - smtpd_helo_required = yes - strict_rfc821_envelopes = yes - smtpd_authorized_xclient_hosts = 127.0.0.1 - # NOTE: utile pour tester les restrictions - - smtpd_helo_restrictions = - reject_invalid_helo_hostname - reject_non_fqdn_helo_hostname - #reject_unknown_helo_hostname - # NOTE: pourrait pourtant être utile pour lutter contre le spam - permit - - smtpd_sender_restrictions = - permit_mynetworks - permit_tls_clientcerts - permit_sasl_authenticated - check_sender_access hash:/etc/postfix/\$mydomain/smtpd/sender_access - check_sender_access hash:/etc/postfix/sender_blacklist - reject_unauth_pipelining - reject_non_fqdn_sender - #reject_unknown_sender_domain - # NOTE: temporaire - permit - - smtpd_client_new_tls_session_rate_limit = 0 - smtpd_client_event_limit_exceptions = \$mynetworks - smtpd_client_recipient_rate_limit = 0 - smtpd_client_connection_count_limit = 50 - smtpd_client_connection_rate_limit = 0 - smtpd_client_message_rate_limit = 0 - smtpd_client_port_logging = no - - smtpd_client_restrictions = - check_client_access hash:/etc/postfix/client_blacklist - - policy_time_limit = 3600 - default_extra_recipient_limit = 5000 - duplicate_filter_limit = 5000 - smtpd_recipient_limit = 5000 - smtpd_recipient_overshoot_limit = 5000 - smtpd_recipient_restrictions = - reject_non_fqdn_recipient - #reject_invalid_hostname - # NOTE: postfix < 2.3. voir reject_invalid_helo_hostname - # dans smtpd_helo_restrictions - reject_unknown_recipient_domain - #reject_non_fqdn_sender - # NOTE: dans smtpd_sender_restrictions - reject_unauth_pipelining - # NOTE: dans smtpd_client_restrictions ou smtpd_data_restrictions - permit_mynetworks - permit_tls_clientcerts - permit_sasl_authenticated - reject_unauth_destination - # NOTE: ne pas passer par SPFCheck / Postgrey si le mail n'est pas pour nous - # ou quelqu'un pour lequel on tient lieu de backup_mx - check_policy_service inet:127.0.0.1:10023 - # NOTE: Postgrey (greylisting) - check_policy_service unix:private/spfcheck - permit_auth_destination - # NOTE: une fois Postgrey passé, on accepte ce qui nous est destiné - # (voir permit_auth_destination) ; sans doute redondant - reject - #check_relay_domains <- removed from postfix - #reject_unknown_sender_domain - # aurait probablement été mieux dans smtpd_sender_restrictions - #reject_rbl_client bl.spamcop.net - #reject_rbl_client list.dsbl.org - #reject_rbl_client zen.spamhaus.org - #reject_rbl_client dnsbl.sorbs.net - - smtpd_data_restrictions = - reject_unauth_pipelining - # NOTE: obliger le serveur en face à attendre qu'on lui aie dit OK - permit - - #smtpd_end_of_data_restrictions = - - #smtpd_restriction_classes = - - smtpd_error_sleep_time = 5 - # NOTE: forcer quelqu'un qui nous embête à attendre cinq secondes. - - # SASL - smtpd_sasl_auth_enable = yes - smtpd_sasl_type = dovecot - smtpd_sasl_path = private/auth - smtpd_sasl_security_options = noanonymous - smtpd_sasl_domain = \$mydomain - - # SMTPD TLS - smtpd_discard_ehlo_keywords = starttls - # NOTE: les clients mails tentant d'utiliser le chiffrement opportuniste - # se mangent une erreur en tentant un starttls - smtpd_tls_fingerprint_digest = sha1 - # sha512 ? - smtpd_tls_mandatory_protocols = TLSv1 - smtpd_tls_mandatory_ciphers = high - smtpd_tls_ciphers = high - # restrictif. s/high/medium/ ? - smtpd_tls_CAfile = /etc/postfix/\$mydomain/smtpd/tls/ca/crt+crl.slf.pem - smtpd_tls_CApath = /etc/postfix/\$mydomain/smtpd/tls/ca/ - smtpd_tls_cert_file = /etc/postfix/\$mydomain/smtpd/tls/crt+crl.slf.pem - smtpd_tls_key_file = /etc/postfix/\$mydomain/smtpd/tls/key.pem - ## - #smtpd_tls_received_header = no - smtpd_tls_session_cache_database = - btree:/var/lib/postfix/smtpd_tls_session_cache - #smtpd_tls_session_cache_timeout = 3600s - smtpd_tls_security_level = may - # Postfix 2.3 and later - # encrypt - # Mandatory TLS encryption: announce STARTTLS support to SMTP clients, and require that clients use TLS - # encryption. According to [1720]RFC 2487 this MUST NOT be applied in case of a publicly-referenced - # SMTP server. Instead, this option should be used only on dedicated servers. - smtpd_tls_loglevel = 1 - smtpd_tls_ccert_verifydepth = 5 - smtpd_tls_auth_only = yes - # Pas d'AUTH SASL sans TLS - smtpd_tls_ask_ccert = no - smtpd_tls_req_ccert = no - #smtpd_tls_always_issue_session_ids = yes - smtpd_peername_lookup = yes - # Nécessaire pour postgrey, etc - smtpd_milters = - non_smtpd_milters = - line_length_limit = 2048 - queue_minfree = 0 - message_size_limit = 20480000 - #smtpd_enforce_tls # NOTE: obsolète - #smtpd_use_tls # NOTE: obsolète - #smtpd_tls_cipherlist # NOTE: obsolète - - readme_directory = no - #delay_warning_time = 4h - # NOTE: uncomment the previous line to generate "delayed mail" warnings - #debug_peer_level = 4 - #debug_peer_list = .\$myhostname - EOF - mk_reg mod=0664 own=root:root /etc/dovecot/dovecot.conf <<-EOF - auth_ssl_username_from_cert = yes - listen = * - log_timestamp = "%Y-%m-%d %H:%M:%S " - mail_debug = yes - mail_location = maildir:~/var/mail - mail_privileged_group = mail - passdb { - args = /home/%u/etc/dovecot/passwd - driver = passwd-file - } - protocols = imap - service auth { - unix_listener /var/spool/postfix/private/auth { - group = postfix - mode = 0660 - user = postfix - } - user = root - } - ssl_ca = /dev/sda{1,2,3} -# /dev/sdb -> /dev/sdb{1,2,3} -# RAID1 logiciel -# /dev/sd{a,b}1 -> /dev/md0 -# /dev/sd{a,b}2 -> /dev/md1 -# /dev/sd{a,b}3 -> /dev/md2 -# LVM -# /dev/md0 -> dom0 -# /dev/md2 -> domU -> /dev/mapper/$vm_fqdn-disk -# LVM -# /dev/mapper/$vm_fqdn-disk -> /dev/xvda{1,2} -# /dev/xvda2 -> /dev/mapper/${vm_lvm_vg}-${vm_lvm_lv}_{swap,root,var,home} - -case $vm_use_lvm in - (no) - ;; - (yes) - readonly vm_lvm_vg=$vm_fqdn - readonly vm_lvm_lv=$vm - ;; - (*) - exit 1;; - esac - -readonly vm_raid_effective_disks=1 # NOTE: RAID1 (mirroring) - # NOTE: julm@rouf:~$ sudo pvs /dev/md2 -o+pe_start - # PV VG Fmt Attr PSize PFree 1st PE - # /dev/md2 domU lvm2 a- 925,64g 470,64g 192,00k <- pas adapté au TRIM SSD, mais on utilise du SATA2 -readonly vm_e2fs_block_size=4096 - # NOTE: valeur standard pour un disque avec des secteurs de 512 octets : - # julm@rouf:~$ grep . /sys/block/sd{a,b}/queue/*_block_size - # /sys/block/sda/queue/logical_block_size:512 - # /sys/block/sda/queue/physical_block_size:512 - # /sys/block/sdb/queue/logical_block_size:512 - # /sys/block/sdb/queue/physical_block_size:512 -readonly vm_e2fs_stripe_size= - # NOTE: égal au chunk size de mdadm --detail ; - # mais ne concerne pas RAID1 où il n'y a pas de changement de disque à effectuer, - # et donc pas de chunk size. -readonly vm_e2fs_stride=${vm_e2fs_stripe_size:+$((vm_e2fs_stripe_size / vm_e2fs_block_size))} -readonly vm_e2fs_stripe_width=${vm_e2fs_stride:+$((vm_e2fs_stride * vm_raid_effective_disks))} - vm_e2fs_extended_options=${vm_e2fs_stride:+,stride=$vm_e2fs_stride}${vm_e2fs_stripe_width:+,stripe_width=$vm_e2fs_stripe_width} - -readonly vm_arch="amd64" -readonly vm_bridge="br-gresille" -readonly vm_ipv4="91.216.110.42" # NOTE: IPv4 publique assignée par Grésille -readonly vm_lsb_name="wheezy" -readonly vm_mac="00:16:3E:E5:98:42" # NOTE: addresse MAC assignée par Grésille - # NOTE: on part sur wheezy dès le début - # dans l'idée de ne pas s'embêter avec - # une migration squeeze -> wheezy dans deux mois ; - # et parce qu'on juge wheezy « suffisamment stable ». - -rule_env () { # DESCRIPTION: affiche les $vm_* - set | grep '^vm_' - } diff --git a/functions.sh b/functions.sh new file mode 100644 index 0000000..1f2c97a --- /dev/null +++ b/functions.sh @@ -0,0 +1,58 @@ +#!/bin/sh +# DESCRIPTION: ce fichier regroupe des utilitaires très génériques + +mk_dir () { + local mod=${1#mod=}; shift + local own=${1#own=}; shift + sudo mkdir -p "$@" + ! [ ${mod:+set} ] || sudo chmod $mod "$@" + ! [ ${own:+set} ] || sudo chown $own "$@" + } +mk_reg () { + local mod=${1#mod=}; shift + local own=${1#own=}; shift + local append + if [ "x${1#--append}" = "x" ] + then append='-a'; shift + else append='' + fi + sudo tee >&2 $append "$@" + ! [ ${mod:+set} ] || sudo chmod $mod "$@" + ! [ ${own:+set} ] || sudo chown $own "$@" + } +mk_lnk () { + sudo ln -fns "$@" + } +ssh_key_add () { + local user=${1#user=}; shift + local in=$1 + local out=$2 + local tmp=$(mktemp -t "$vm.ssh.XXXXXXXXX.tmp") + # NOTE: ssh-keygen ne sait lire que depuis un fichier.. + while IFS= read -r key + do + # DESCRIPTION: ajoute dans le compte de root les clefs SSH de l'admin non déjà ajoutées. + has= + cat >"$tmp" <<-EOF + $key + EOF + key_fpr=$(ssh-keygen -l -f "$tmp" | cut -d ' ' -f 1,2) + while IFS= read -r auth_key + do + cat >"$tmp" <<-EOF + $auth_key + EOF + auth_key_fpr=$(ssh-keygen -l -f "$tmp" | cut -d ' ' -f 1,2) + if [ "$key_fpr" = "$auth_key_fpr" ] + then has=1; break + fi + done <<-EOF + $(sudo cat /root/etc/ssh/authorized_keys) + EOF + [ ${has:+set} ] || + mk_reg mod=640 own="$user:$user" --append "$out" <<-EOF + $key + EOF + done <"$in" + rm -f "$tmp" + } diff --git a/inc.sh b/inc.sh deleted file mode 100644 index 28df016..0000000 --- a/inc.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -# DESCRIPTION: ce fichier regroupe des utilitaires très génériques - -mk_dir () { - local mod=${1#mod=}; shift - local own=${1#own=}; shift - sudo mkdir -p "$@" - ! [ ${mod:+set} ] || sudo chmod $mod "$@" - ! [ ${own:+set} ] || sudo chown $own "$@" - } -mk_reg () { - local mod=${1#mod=}; shift - local own=${1#own=}; shift - sudo tee >/dev/null "$@" - ! [ ${mod:+set} ] || sudo chmod $mod "$@" - ! [ ${own:+set} ] || sudo chown $own "$@" - } diff --git a/key/julm.gpg.pub b/key/julm.gpg.pub new file mode 100644 index 0000000..3de477b --- /dev/null +++ b/key/julm.gpg.pub @@ -0,0 +1,245 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.12 (GNU/Linux) + +mQINBEwLbc8BEADCuF5LsUUDDH5Rc22BMGkBxVtVBX2+8xFHR1hN50kfSECrpYCS +pC3OcSS2NzbB8ePtLNnyRtQZ3ee6ONd8oXK6bUkqIrXr0s3mEZsi6rHkWViEt3qh +yZ4ZCeDowMMflvA6eZ1pT1LZ296I768wmuZzh0XLQLJtITWCVdaIsp//PPnh4AQf +TOEvg3xtMSAN//SLNRH6cgNEzE9d6C7SU5QtJM8bK4aJNfa2ufI2nonsxgPrEOvu +T95uwajQCV81vB1c0hrOaXfSkPE4WbeZrlIhse4HLbC9sFt9BPRpuxMitKQAJSyq +FqzXVBa2H2Q++Vx1trRYiLr3tFri4UixCwJ3VoWdpGUjfp0Gka+ssXtfCSikHvhI +d4CBezUC+tYLDOiI0fhpzlK+YgZf/iXY1IwUyF4rWLzqTENdMkvmnZjvtfY2e/TK +LqShd9QGR3DmoRv7SgcK8rQ4t59K5IFQ5xTRtMQcWx23bjnwiWzSXrG8s7XAOpm4 +iUUjQKU/aYLPCUiCCqVsUtUvgSSlY4U5JV3OHoPJ2Xjkh9rvT5TktcEt4NOCM7lc +8Q8zTcOc77oeq/SuaewQTzls8RTmGAX8qntP0KOgJnnnL0XVgsCffIxPWTBsG/tx +rCxC3ggWiIS097/k4uu1t4F3HgzUP9WQwFWHHeE4HpORs4bsDZ0xAcmaHwARAQAB +tCFKdWxpZW4gTW91dGluaG8gPGp1bG1AcmlzZXVwLm5ldD6JAmIEEwEKAEwCGwMF +CQXoLFEGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheABQJPvTxPIxhodHRwOi8vYXV0 +b2dlcmVlLm5ldC9+anVsbS9wdWIuZ3BnAAoJENFa9/Rn6CmbO58P/i0PYhcmJTOI +f1kox5kK10QdrQIPIMTI9iEkwbvdbqUy0PyKVz0dLdg8H8CPIk567aduuig6GFZ5 +E28YL0ogA5t3dxbf+J/dokNmCSWAf8+zJHUP3vviguzA0f19eKvhR7rYgZbPgi+2 +IdJhWojTOrItpn3Otk/WHCbv4pcM14SbugSa1qptcTZzhJ8NFzY9X4+yEmLoUQ4z +nhFxrccnFos2WeBWCFGL/DhrweONlF6thJda9lw5ukJzJlzRXn9yO29E1LrPmWzV +ittrJYjXg5c4lPJIO2TBmm4l2xZTH9DM3DK11V3X42nKlVHlCn1J9g7ow5ymipBs +4kz/c17itg4LPuZaGF7kWmsoIdmDlWLb74agJz/ql8zy3+X4NkGPrPUbYW4R8436 +87R/pkAPPHx8B6W+v8mOWysyZyEaGvo4E/86sTbVqd9gWzLNUtvVpQ0CsnZZWUok +SPZSsNK+S7IuKYtyPsxcR8lM+nHF4UOwU9TeVFy3ddjHDkDibjNeUtY5oOVNuqUG +nGy3cp/yEVp+YVkFT4JDFl/wmSMkxSTrkqDnO1OpTcRg9Uh3sbezy0h8EAheVA2V +WA+V8RrOV7OWkZUabb4EPhBSTDbe9e1Mr3UIvW5+UipD6FGM2IUSPL6nzD8SdWdW +mYHA2oW0kIuRo7vYpNkXp9QtONF54JqKtCVKdWxpZW4gTW91dGluaG8gPGp1bG1A +Z3Jlbm91aWxsZS5jb20+iQJiBBMBCgBMAhsDBQkF6CxRBgsJCAcDAgYVCAIJCgsE +FgIDAQIeAQIXgAUCT708TyMYaHR0cDovL2F1dG9nZXJlZS5uZXQvfmp1bG0vcHVi +LmdwZwAKCRDRWvf0Z+gpmz4MD/4ix0DBAtY3zvDcNMjn1YaRLVv3EAQvs8kipaay +a5o/55bZWrb2VWSLVrfas/ADvEHqBHQxdhbUQiraCD7QIbdt8+5i2UR6/KsvuYIe +/xqO/QL2/rICheR5QnD1zgC3hC9uHK0ojtDRTi0AFHkTMCkU+p0yPIvUSOovueaR +iJpkJSsCLYMQEZVKOnw7GDDAqLaXHeVreWbo2GVphD6hsgRfIDKhVDutkHjmXjSX +qjG/T9H2y+u+wFRcoKc/LVNVTrD3JU290UHNMHoEV8iwaVWpz6plIaPs/S5VBzwA +ZdsVHNNLuRUc1BHKXCsc2D8C96xnNLYFcEbvxteiAe/OM9BaX3xRcJ7JmPGXT0wH +nyfx0eX9IfdTeGkX0vwg/9QxlzveFoC6x3BtMKIWZXwT4t9YNuzRq9Tij9Wg/sUP +NgKr/6JUkL858vvKFPB9q2p0TDFPoqNOkIBObhvqrbCEM20pnlOqZ4X+3Lx16142 +xUmznxZjB/JDCicAMIGyb1mwUNUqAJcoR+qO6iddpjgmyyv8OJwG0jN2M5hRSon5 +8PNza/IKHAPPi7jI06hFroItG/ekftXhAJwkSzPfa/3UQdOHa0Nco9bBl7ZkC4Nd +k9NDiftSLPaNUZ36hAJ08VLP7j79KkSWO6C1uu0WCEP8fuGTUqly6dSDJtUY0Lv4 +OzRIGbQeSnVsaWVuIE1vdXRpbmhvIDxqdWxtQGxpcDYuZnI+iQKRBBMBCgB7AhsD +Ah4BAheAAwsKCQYVCgkICwIFFgMCAQAwFIAAAAAAFQAScGthLWFkZHJlc3NAZ251 +cGcub3JnanVsbUBhdXRvZ2VyZWUubmV0IxhodHRwOi8vYXV0b2dlcmVlLm5ldC9+ +anVsbS9wdWIuZ3BnBQJOV2IlBQkF6CxRAAoJENFa9/Rn6CmbXRAP/RXMI1LzU8tR +G5UVm7FYKx0BBEgLg50JBRJ0HbqyYqp5wy5aqIyQyYkq2Dc0Oxqmxppfje7UXr9m +cP7euhiIdBlxmvJYFakCi4ox+wIE1pygE/SeN5Ob21Gw4r/7ilqjuzgLYwYpqxlJ +o6Q67qAGitIWbUMfY6wMg8ejV9QgZkBxJ8X79E+zIPHecVHSPgTgE/qfScCD2Sq8 +CYClfFiesT5iGLGvk4fhY/lC9aVuk+KHVwywMa8qraisR5iH8zQRKyUzmKJZnldE +whaQaU6yKPUCtzr4T9NKNoOt5jY8zoqbeODWWs5e6Al87/dcl2Tavlz/iGwoOfwg +s8PZz2eYaK3rryT0GU/6Bv1BfpVG3T6miRvSYEsFY/OMMm1WwW5PiQ7Vx/yMzaXe +3087it3X+LEtfLl+4DTdEaFl39xl0fC3incVgUQ24EEM1mQm+Ng2srZRlz0nb2/2 +8Kl8wvEGdWXj3CvvUD7DBrDk+StQlCrygvdr07flpIA8hQAj/vp6LcNW8BYXBm2i +8zwkfCE/O3FTfEE/fIaea6/SMIR7JaDkfIBMGVU7cnTq03Ij093F4yrN2nFbI0iu +Wyksk1uUNgy83Het6WPWrWSa1z0NxGdSiR3CsbWZX2w/yz2rDQ6RXh+hGHH0Jjgc +ImfjWvL33N+OZcU2x0c4w/5SIl/xXfvjtCBKdWxpZW4gTW91dGluaG8gPGp1bG1A +cG9vbHAub3JnPokCkQQTAQoAewIbAwIeAQIXgAMLCgkGFQoJCAsCBRYDAgEAMBSA +AAAAABUAEnBrYS1hZGRyZXNzQGdudXBnLm9yZ2p1bG1AYXV0b2dlcmVlLm5ldCMY +aHR0cDovL2F1dG9nZXJlZS5uZXQvfmp1bG0vcHViLmdwZwUCTldiJgUJBegsUQAK +CRDRWvf0Z+gpm41aEACAJ2a7Dfk8FOabL50ntxBkd7F6Rk5kuYU2JwtUWlvZ0e9w +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 +MPW60kuSKRmx07BXUXV44LRO1th2fY+krMg9IzqAlLlZXqa/fsv+VgVWxKWVBKLE +zIxlpBgW8rQuSnVsaWVuIE1vdXRpbmhvIDxqdWxtQHNhdmluZXMuYWxwZXMuZnIu +ZXUub3JnPokCmwQTAQoAhQIbAwIeAQIXgDoUgAAAAAAVABxwa2EtYWRkcmVzc0Bn +bnVwZy5vcmdqdWxtQHNhdmluZXMuYWxwZXMuZnIuZXUub3JnAwsKCQYVCgkICwIF +FgMCAQAjGGh0dHA6Ly9hdXRvZ2VyZWUubmV0L35qdWxtL3B1Yi5ncGcFAk5XYiUF +CQXoLFEACgkQ0Vr39GfoKZubAxAAtg6UK6qULT2mUxbPfdSzzC7MZtf4JqR80FOm +6/5IX+syZNltBw0K7+L7lr/h31LEtNyj5XkXyZZzZvuit/YBNBrLLtO7Seknl/fq +UGswrH/+cmvO7+GXtc2HwRY+RU9HJu9r/m2mjjeucUIzr3ngEpDDSLgEjJji8/6A +jYJ6/eEkvsn9l8Sy9OHVuDcI1p9eUBe55M1cM6uAWPL9XMHNzVclL9jajHMQwcLg +7CxdcIU5NGVi0/yET2w4c877sRCezkzuJw3HFRdXvxPjvVcQJZrvtLGpy1KDaxdY +4AbseGO8nwSj0Yg8mKhk9cD5bRg5PAW+0cDiZ2eH9BLzc2YLVB2lXwnt2WePVzud +9zPwxnGsaV56lI3cDfMYuJZOR3wrc9WKfJb4hFNgxu/6bnWJIfP+wSxWBaPGmOKh +hmd7ZZvDxBm51SYtRQwsbyq5wXN99E8n59AkLwng1BtF8kMh4qxAldpobveQzreC +izGqlkzyAU2Ou9Mlb1aS5N6neSwcgTznMQEVQyfcc8BQrneVAsVnLZwhyxXVCV7b +VaSVbARWXfoHWnPtWkc6XQpOCVIYx5lHMMkFDjmvK5YHx9PqGBMm6Y6gis9JHbY2 +g+UrLVpBn1maW7HesqfjjHUub1jVsTX03JjyRFuiyOhX+iqftaIHwyYTTmtA0MmJ +MQMK7+S0L0p1bGllbiBNb3V0aW5obyA8anVsbUBpbnRlcm5ldC5hbHBlcy5mci5l +dS5vcmc+iQJIBDABCgAyBQJQTNMCKx0gaW50ZXJuZXQuYWxwZXMuZnIuZXUub3Jn +IC0+IGF1dG9nZXJlZS5uZXQACgkQ0Vr39GfoKZt9zA//blGui+A6+4bx3WixRMi/ +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 ++JOXylIEam3Nybo/mSRCHxYjz499KHM= +=RsTM +-----END PGP PUBLIC KEY BLOCK----- diff --git a/key/ssh.known_hosts b/key/ssh.known_hosts new file mode 100644 index 0000000..4376a5e --- /dev/null +++ b/key/ssh.known_hosts @@ -0,0 +1,4 @@ +rouf.grenode.net,91.216.110.98 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCWolyL7ErNN/uHTAoQFIylOOC9sixbd4i0CNxAcGN0Ht7Z7HpquzwAmRj4JHNgRRTkUFnW0GBOB/E3Py5ckU1CZ8SBZyqt3zrBwO0xybZ6ZWNlzebdgiMU3Ke2p9WfZsAd0HKG9oJjeNJFDVATI/ez0IT8pKFR0AT5wO1u5HHDX3szPl19F5Blk8S3XYc//ZypVTokpH7EDgq+tj8FPERAuwIYl3qAJesR0omwn5Gro87pUhTgqK+9mkXcWacUYsLA6m0uR+1DhdTIHwcsHFoVI+DjwOGmfeI5ZallbgRdmoeTUi1lf1RVu5myoBl6eRob9dLWCtp+7zjp0fmPEDaJ root@rouf +init.ateliers.heureux-cyclage.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAmQZqrcEum8Ixy6kKU6AhENis9EmHOg8z0IPjCrF9glZjet66PLTPCulYcPdiBFhPJjxBFiKKp+bY/qiiVphSO7LXYutgzcbH9dKn681w4vsiAxTYIkgQao0AhrmsIMgoY+PZs3spoKt/E8GQq7SLXb9v7VuRcvQbkKIxp+HIc5uvaf8pZnhT2ODJLW1MiYlyIlJp+ZjvrBKd8/2TZaLOAW6P3XUqNQKCocngnDwDJQnq6EbVhrBjfU4CuFPXk9QY5dJjvSdyb5oCXDabHcQNymZwIYFsfdSjswpoDQH/bzqN0LhlvKYTauUoZNvMQ6FhHb5eiSBOv4vfJM8bJ/EftcT+Lz27u3KD7RePZudNJen75rB99UPWfcc1HkWS6I7pX4wzKtd9cUyx7qqpN7wn9G1RLYDbZ2Zo7AFJeHGdkIZ+SBEdFXuPc7W7p33A7VoRG1U/2Cq8DAiD6FpBYYYscFiacW2oGr913sYKWbSF1QxzmHHIefyio6+GthNHXebXkj3mS7DZGhEDtMq5WO5yhd3kGKsA5z67K0tdf5yte9ACOIVPJ7Ttg/adDHYVKM9Hr8PLX1OpCEuZu4CtX3F+BBH0dn3mLkBFpnHlXdN5mGNw/FDHFSO63t61xSJjM7PJG2/KOREr/5naYhEypG4FwLrbvjFq7dCwcywh+A0a4t6w98= +ateliers.heureux-cyclage.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCs2PjhfXSTUryiFfbzB3Qc5lF2bvMR56tzDTmrKGtBFXifzQuAltftPAgKTFeuFohOl1jXD3KzeZS6EAk8iZ7hUzBCbPGx5nrIizw9Kak8Jvy477uHzRNuCSbdgxzpwRr8nOKkohwARxFgkRQxM08rKBZyuSYU8N+Z9OSEwMQqv+uU+/NUHWZC0JVfWwfBunwc9mQBmxzt5Y+zhKk3qzEu2Iqu4ilr8FolAwGkWp60ruffrQrnJYFpIwFGsE+k/WAd4RgGyASclCPA5upVLKiSnwx5vnyXggYX0mXNrch3Uak99rrOVH/0YpGUy1dJY91UT+BESWyvMFDbK8fQWTR39kCnESS02F8/FnVTB9tP1XRPBWWUMtavOQIL0BxsgmvbM8rJEHImiRfLCwH/6oXP5JkPQnKQZlu++WPjWxuMraPNwvFsrqBdfPuYY97L4cXiI4loea5/eEBhEyz5RVBSHXoy3BUceSsXloGH1/2iC50k5IpZJIRthYi+OJ9ZjDBLk0YioVsf4TjADythqLu2zOT+ota63trJ/AMEV2tGX1mPGiFJgJ69cHN5CIsSDJH6VcbswPWxGa3n9r/b1Wnzadp4wiNFODoe5a20qbvLg3jrOJldxowKhNHExZpgPXuEKA/gSBKnyvhnZBerFwAGBKqaQOmfDMlknQtzg1fGyQ== +|1|p+07/BQvEHNha3nWzaQimjM242U=|Ouc4VzPcrmZoCecGIJb27ztT/Og= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCs2PjhfXSTUryiFfbzB3Qc5lF2bvMR56tzDTmrKGtBFXifzQuAltftPAgKTFeuFohOl1jXD3KzeZS6EAk8iZ7hUzBCbPGx5nrIizw9Kak8Jvy477uHzRNuCSbdgxzpwRr8nOKkohwARxFgkRQxM08rKBZyuSYU8N+Z9OSEwMQqv+uU+/NUHWZC0JVfWwfBunwc9mQBmxzt5Y+zhKk3qzEu2Iqu4ilr8FolAwGkWp60ruffrQrnJYFpIwFGsE+k/WAd4RgGyASclCPA5upVLKiSnwx5vnyXggYX0mXNrch3Uak99rrOVH/0YpGUy1dJY91UT+BESWyvMFDbK8fQWTR39kCnESS02F8/FnVTB9tP1XRPBWWUMtavOQIL0BxsgmvbM8rJEHImiRfLCwH/6oXP5JkPQnKQZlu++WPjWxuMraPNwvFsrqBdfPuYY97L4cXiI4loea5/eEBhEyz5RVBSHXoy3BUceSsXloGH1/2iC50k5IpZJIRthYi+OJ9ZjDBLk0YioVsf4TjADythqLu2zOT+ota63trJ/AMEV2tGX1mPGiFJgJ69cHN5CIsSDJH6VcbswPWxGa3n9r/b1Wnzadp4wiNFODoe5a20qbvLg3jrOJldxowKhNHExZpgPXuEKA/gSBKnyvhnZBerFwAGBKqaQOmfDMlknQtzg1fGyQ== diff --git a/machine-ateliers.txt b/machine-ateliers.txt new file mode 100644 index 0000000..c41c688 --- /dev/null +++ b/machine-ateliers.txt @@ -0,0 +1,5 @@ +- script de grenode pour définir son mot-de-passe +- voir gunicorn +- script de grenode/gresille pour les oublis de commit dans etc ... +- voir xoe: http://sisalp.fr/index.php/post/Installation-OpenERP-procedure-totalement-automatisee-d-installation-de-xoe-et-d-OpenERP +- \ No newline at end of file diff --git a/vm.sh b/vm.sh new file mode 100644 index 0000000..eb4b556 --- /dev/null +++ b/vm.sh @@ -0,0 +1,95 @@ +#!/bin/sh +# DESCRIPTION: ce fichier regroupe les variables propres à la VM + +readonly PATH=$PATH:/usr/sbin:/sbin +readonly vm_domainname="heureux-cyclage.org" +readonly vm_hostname="ateliers" +readonly vm_fqdn="$vm_hostname.$vm_domainname" +readonly vm=$vm_hostname +readonly vm_host="rouf.grenode.net" + +readonly vm_use_lvm="yes" + # - sans LVM : + # - on a accès au LVM de l'hôte, mais c'est pas très propre. + # - pour l'extension de mémoire, on peut soit : + # 1.1. étendre avec lvresize /dev/domU/$vm_fqdn-disk + # 1.2. étendre avec sfdisk $vm_dev_disk_home + # 1.3. étendre avec resize2fs /dev/mapper/${vm_lvm_lv}_home_deciphered + # soit : + # 2.1. créer une nouvelle partition sur le LVM de l'hôte + # 2.2. l'ajouter comme un disque supplémentaire dans /etc/xen/$vm_fqdn.cfg + # 2.3. le monter sur /home2 en pensant à changer DHOME=/home2 dans /etc/adduser.conf + # - pour la sauvegarde: on peut soit : + # 1. sauvegarder au niveau applicatif (pgdump, mysqldump, etckeeper, git) + # 2. sauvegarder incrémentalement avec (duplicity, backup-ninja, BackupPC), + # depuis l'hôte pour avoir un snapshot LVM. + # - avec LVM : + # - question ouverte de la performance du LVM dans du LVM. + # - pour l'extension de mémoire, on peut soit : + # 1.1. étendre avec lvresize /dev/domU/$vm_fqdn-disk + # 1.1. étendre avec pvextend $vm_lvm_pv + # 1.1. étendre avec lvresize /dev/${vm_lvm_vg}/${vm_lvm_lv}_home + # 1.3. étendre avec resize2fs /dev/mapper/${vm_lvm_lv}_home_deciphered + # - pour la sauvegarde: on peut soit : + # 1. sauvegarder au niveau applicatif (pgdump, mysqldump, etckeeper, git) + # 2. sauvegarder incrémentalement avec (duplicity, backup-ninja, BackupPC), + # depuis la VM pour avoir un snapshot LVM. + +# Cartographie de la mémoire morte : +# SATA2 * 2 (/dev/sd{a,b}) +# /dev/sda -> /dev/sda{1,2,3} +# /dev/sdb -> /dev/sdb{1,2,3} +# RAID1 logiciel +# /dev/sd{a,b}1 -> /dev/md0 +# /dev/sd{a,b}2 -> /dev/md1 +# /dev/sd{a,b}3 -> /dev/md2 +# LVM +# /dev/md0 -> dom0 +# /dev/md2 -> domU -> /dev/mapper/$vm_fqdn-disk +# LVM +# /dev/mapper/$vm_fqdn-disk -> /dev/xvda{1,2} +# /dev/xvda2 -> /dev/mapper/${vm_lvm_vg}-${vm_lvm_lv}_{swap,root,var,home} + +case $vm_use_lvm in + (no) + ;; + (yes) + readonly vm_lvm_vg=$vm_fqdn + readonly vm_lvm_lv=$vm + ;; + (*) + exit 1;; + esac + +readonly vm_raid_effective_disks=1 # NOTE: RAID1 (mirroring) + # NOTE: julm@rouf:~$ sudo pvs /dev/md2 -o+pe_start + # PV VG Fmt Attr PSize PFree 1st PE + # /dev/md2 domU lvm2 a- 925,64g 470,64g 192,00k <- pas adapté au TRIM SSD, mais on utilise du SATA2 +readonly vm_e2fs_block_size=4096 + # NOTE: valeur standard pour un disque avec des secteurs de 512 octets : + # julm@rouf:~$ grep . /sys/block/sd{a,b}/queue/*_block_size + # /sys/block/sda/queue/logical_block_size:512 + # /sys/block/sda/queue/physical_block_size:512 + # /sys/block/sdb/queue/logical_block_size:512 + # /sys/block/sdb/queue/physical_block_size:512 +readonly vm_e2fs_stripe_size= + # NOTE: égal au chunk size de mdadm --detail ; + # mais ne concerne pas RAID1 où il n'y a pas de changement de disque à effectuer, + # et donc pas de chunk size. +readonly vm_e2fs_stride=${vm_e2fs_stripe_size:+$((vm_e2fs_stripe_size / vm_e2fs_block_size))} +readonly vm_e2fs_stripe_width=${vm_e2fs_stride:+$((vm_e2fs_stride * vm_raid_effective_disks))} + vm_e2fs_extended_options=${vm_e2fs_stride:+,stride=$vm_e2fs_stride}${vm_e2fs_stripe_width:+,stripe_width=$vm_e2fs_stripe_width} + +readonly vm_arch="amd64" +readonly vm_bridge="br-gresille" +readonly vm_ipv4="91.216.110.42" # NOTE: IPv4 publique assignée par Grésille +readonly vm_lsb_name="wheezy" +readonly vm_mac="00:16:3E:E5:98:42" # NOTE: addresse MAC assignée par Grésille + # NOTE: on part sur wheezy dès le début + # dans l'idée de ne pas s'embêter avec + # une migration squeeze -> wheezy dans deux mois ; + # et parce qu'on juge wheezy « suffisamment stable ». + +rule_env () { # DESCRIPTION: affiche les $vm_* + set | grep '^vm_' + } diff --git a/vm_host b/vm_host new file mode 100755 index 0000000..f754547 --- /dev/null +++ b/vm_host @@ -0,0 +1,438 @@ +#!/bin/sh +set -e -f ${DRY_RUN:+-n} -u +tool=${0%/*} +. "$tool"/functions.sh +. "$tool"/vm.sh +test "$(hostname --fqdn)" = "$vm_host" + +rule_help () { + cat >&2 <<-EOF + DESCRIPTION: ce script regroupe des fonctions utilitaires + pour gérer la VM _depuis_ son hôte ; + il sert à la fois d'outil et de documentation. + Voir \`$tool/vm_hosted' pour les utilitaires côté VM hébergée. + SYNTAX: $0 \$RULE \${RULE}_SYNTAX + RULES: + $(sed -ne 's/^rule_\([^_][^ ]*\) () {\( *#.*\|\)/\t\1\2/p' "$tool"/vm.sh "$0") + ENVIRONMENT: + TRACE # affiche les commandes avant leur exécution + $(sed -ne 's/^readonly \([^ ][^ =]*\).*}\( *#.*\|\)$/\t$\1\2/p' "$tool"/vm.sh "$0") + EOF + } + +readonly vm_dev_disk=/dev/mapper/domU-$(printf %s "$vm_fqdn-disk" | sed -e 's/-/--/g') +readonly vm_dev_disk_boot="${vm_dev_disk}1" + +rule_git_reset () { + ( + cd "$tool" + #git checkout -f -B master origin + # NOTE: pas de -B sous squeeze + git checkout HEAD'^' && + git branch -f master origin && + git checkout master + git clean -f -d -x + ) + } + +rule_vm_init () { + mk_reg mod=644 own=root:root /etc/xen/$vm_fqdn.cfg <<-EOF + # -*- mode: python; -*- + # DOC: http://wiki.xen.org/wiki/Xen_Linux_PV_on_HVM_drivers + import os, re + name = "$vm_fqdn" + arch = os.uname()[4] + memory = 2048 + vcpus = 1 + pae = 1 + acpi = 1 + apic = 1 + vif = ['mac=$vm_mac,bridge=$vm_bridge'] + disk = ['phy:/dev/domU/$vm_fqdn-disk,hda,w'] + device_model = 'qemu-dm' + # HVM : + #kernel = "/usr/lib/xen-4.0/boot/hvmloader" + #builder = 'hvm' + #xen_platform_pci = 1 # NOTE: the guest VM can use optimized PV on HVM drivers + # PV : + #kernel = "pv-grub.gz" # NOTE: pas encore dans Debian car il ne fonctionne qu'avec grub-legacy + #extra = "(hd0,0)/grub/grub.cfg" + bootloader = '/usr/bin/pygrub' + + # boot on floppy (a), hard disk (c) or CD-ROM (d) + #boot = 'd' + + #vnc = 1 + #sdl = 0 + #vncconsole = 0 + #vnclisten = "0.0.0.0" + #vncpasswd = "" + #usbdevice = 'tablet' + + keymap = 'fr' + serial = 'pty' + on_poweroff = 'destroy' + on_reboot = 'restart' + on_crash = 'restart' + EOF + } +rule_vm_start () { + test ! -e /dev/domU/$vm_fqdn-disk1 + sudo xm create $vm_fqdn.cfg + rule_vm_attach + } +rule_vm_attach () { + cat <<-EOF + NOTE: Ctrl-] pour se détacher de la console + EOF + sudo xm console $vm_fqdn + } +rule_vm_stop () { + sudo xm shutdown $vm_fqdn + } +rule_vm_stop_force () { + sudo xm destroy $vm_fqdn + } + +rule_disk_mount () { # DESCRIPTION: montage du disque de la VM depuis l'hôte + sudo kpartx -a -v /dev/domU/$vm_fqdn-disk + #sudo xm block-attach 0 phy:/dev/domU/$vm_fqdn-disk $vm_dev_disk w + } +rule_disk_umount () { # DESCRIPTION: démontage du disque de la VM depuis l'hôte + rule_part_boot_umount + case $vm_use_lvm in + (yes) + rule_part_lvm_umount + ;; + (no) + rule_part_root_umount + rule_part_var_umount + rule_part_home_umount + ;; + (*) exit 1;; + esac + sudo kpartx -d -v /dev/domU/$vm_fqdn-disk + #sudo xm block-detach 0 $vm_dev_disk + # XXX: DANGEREUX ; si jamais il bloque parce que le disque était encore utilisé : + # utiliser xm block-detach 0 $vm_dev_disk --force ; + # ôter les éventuels mappages LVM concernés avec dmsetup table et dmsetup remove --force ; + # ôter les mappages concernés dans /etc/lvm/cache/.cache, + # et pour bien trouver tous les mappages : + # % sudo find /dev -type l -exec sh -c 'printf "%s -> " "$@"; readlink "$@"' - {} \; | grep $vm_dev_disk + # enfin, ôter l'éventuel verrou dans /var/lock/lvm/ + } + +case $vm_use_lvm in + (no) + readonly vm_dev_disk_swap="${vm_dev_disk}5" + readonly vm_dev_disk_root="${vm_dev_disk}6" + readonly vm_dev_disk_var="${vm_dev_disk}7" + readonly vm_dev_disk_home="${vm_dev_disk}8" + ;; + (yes) + readonly vm_lvm_pv="${vm_dev_disk}2" + readonly vm_dev_disk_swap=/dev/$vm_lvm_vg/${vm_lvm_lv}_swap + readonly vm_dev_disk_root=/dev/$vm_lvm_vg/${vm_lvm_lv}_root + readonly vm_dev_disk_var=/dev/$vm_lvm_vg/${vm_lvm_lv}_var + readonly vm_dev_disk_home=/dev/$vm_lvm_vg/${vm_lvm_lv}_home + ;; + (*) exit 1;; + esac + +rule_disk_format () { # DESCRIPTION: partitionnage du disque de la VM + case $vm_use_lvm in + (no) + sudo sfdisk $vm_dev_disk <<-EOF + # partition table of $vm_dev_disk + unit: sectors + + ${vm_dev_disk}1 : start= 63, size= 497952, Id=83, bootable + ${vm_dev_disk}2 : start= 498015, size=418927005, Id= 5 + ${vm_dev_disk}3 : start= 0, size= 0, Id= 0 + ${vm_dev_disk}4 : start= 0, size= 0, Id= 0 + ${vm_dev_disk}5 : start= 498078, size= 1959867, Id=82 + ${vm_dev_disk}6 : start= 2458008, size= 29302497, Id=83 + ${vm_dev_disk}7 : start= 31760568, size= 9767457, Id=83 + ${vm_dev_disk}8 : start= 41528088, size=377896932, Id=83 + EOF + ;; + (yes) + sudo sfdisk $vm_dev_disk <<-EOF + # partition table of $vm_dev_disk + unit: sectors + + ${vm_dev_disk}1 : start= 63, size= 497952, Id=83, bootable + ${vm_dev_disk}2 : start= 498015, size=418927005, Id=8E + EOF + ;; + (*) exit 1;; + esac + #sudo partprobe $vm_dev_disk + sudo kpartx -u -v /dev/domU/$vm_fqdn-disk + } + +rule_part_lvm_format () { + rule_part_lvm_umount + ! sudo vgs | grep -q "^ $vm_lvm_vg " || + sudo vgremove $vm_lvm_vg + sudo pvcreate --dataalignment 512k $vm_lvm_pv + sudo vgcreate --dataalignment 512k $vm_lvm_vg $vm_lvm_pv + sudo lvcreate --contiguous y -n ${vm_lvm_lv}_swap -L 1G $vm_lvm_vg + sudo lvcreate --contiguous y -n ${vm_lvm_lv}_root -L 15G $vm_lvm_vg + sudo lvcreate --contiguous y -n ${vm_lvm_lv}_var -L 5G $vm_lvm_vg + sudo lvcreate --contiguous y -n ${vm_lvm_lv}_home -l 99%FREE $vm_lvm_vg + rule_part_lvm_umount + } +rule_part_lvm_mount () { + case $vm_use_lvm in + (yes) + sudo vgchange -a y $vm_lvm_vg + ;; + (*) exit 1;; + esac + } +rule_part_lvm_umount () { + case $vm_use_lvm in + (yes) + rule_part_root_umount + rule_part_var_umount + rule_part_home_umount + ! sudo vgs | grep -q "^ $vm_lvm_vg " || + sudo vgchange -a n $vm_lvm_vg + ;; + (*) exit 1;; + esac + } + +rule_part_randomize () { # SYNTAX: $part # NOTE: à anticiper + local part=$1 + eval "sudo dd if=/dev/urandom of=\$vm_dev_disk_$part" + } +rule_part_randomize_stat () { # SYNTAX: $part # DESCRIPTION: fait afficher la progression de rule_part_clean + local part=$1 + eval "pkill -USR1 -f \"^dd if=/dev/urandom of=\$vm_dev_disk_$part\"" + } +rule__part_encrypted_format () { # SYNTAX: $part # DESCRIPTION: formatage d'une partition distincte de / + # NOTE: la clef de chiffrement est dérivée de celle de /, + # / doit être déchiffrée pour que cela fonctionne. + local part=$1 + eval "local dev=\$vm_dev_disk_$part" + test ! -e /dev/mapper/${vm_lvm_lv}_root_deciphered || + sudo /bin/sh -c "/lib/cryptsetup/scripts/decrypt_derived ${vm_lvm_lv}_root_deciphered | + cryptsetup luksFormat --hash=sha512 --key-size=512 \ + --cipher=aes-xts-essiv:sha256 --key-file=- --align-payload=8 $dev" + } +rule__part_encrypted_mount () { # SYNTAX: $part + local part=$1 + eval "local dev=\$vm_dev_disk_$part" + test -e /dev/mapper/${vm_lvm_lv}_${part}_deciphered || + sudo /bin/sh -c "/lib/cryptsetup/scripts/decrypt_derived ${vm_lvm_lv}_root_deciphered | + cryptsetup luksOpen --key-file=- $dev ${vm_lvm_lv}_${part}_deciphered" + } +rule__part_encrypted_umount () { # SYNTAX: $part + local part=$1 + eval "local dev=\$vm_dev_disk_$part" + test ! -e /dev/mapper/${vm_lvm_lv}_${part}_deciphered || + sudo cryptsetup luksClose ${vm_lvm_lv}_${part}_deciphered + } + +rule_part_root_format () { + if ! mount | grep -q "^$vm_dev_disk_root " + then + sudo cryptsetup luksFormat --hash=sha512 --key-size=512 \ + --cipher=aes-xts-essiv:sha256 --key-file=- --align-payload=8 $vm_dev_disk_root + sudo cryptsetup luksOpen --key-file=- $vm_dev_disk_root ${vm_lvm_lv}_root_deciphered + sudo mke2fs -t ext4 -c -c -m 5 -T ext4 -b $vm_e2fs_block_size \ + -E resize=30G${vm_e2fs_extended_options} \ + -L ${vm_lvm_lv}_root \ + /dev/mapper/${vm_lvm_lv}_root_deciphered + ! mountpoint -q /mnt/$vm_fqdn + sudo mount -v /dev/mapper/${vm_lvm_lv}_root_deciphered /mnt/$vm_fqdn + mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/boot + mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/dev + mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/home + mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/proc + mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/sys + mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/var + mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/root + mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/root/tool + mk_dir mod=0770 own=root:root /mnt/$vm_fqdn/root/tool/ateliers + sudo umount -v /mnt/$vm_fqdn + sudo cryptsetup luksClose ${vm_lvm_lv}_root_deciphered + fi + } +rule_part_root_mount () { + test -e /dev/mapper/${vm_lvm_lv}_root_deciphered || + sudo cryptsetup luksOpen $vm_dev_disk_root ${vm_lvm_lv}_root_deciphered + mountpoint -q /mnt/$vm_fqdn || + sudo mount -v -t ext4 /dev/mapper/${vm_lvm_lv}_root_deciphered /mnt/$vm_fqdn + } +rule_part_root_umount () { + ! mountpoint -q /mnt/$vm_fqdn || + sudo umount -v /mnt/$vm_fqdn + ! test -e /dev/mapper/${vm_lvm_lv}_root_deciphered || + sudo cryptsetup luksClose ${vm_lvm_lv}_root_deciphered + } +rule_part_root_backup_luks () { + sudo cryptsetup luksHeaderBackup $vm_dev_disk_root --header-backup-file ./root.luks + } +rule_part_swap_format () { + rule__part_encrypted_format swap + rule__part_encrypted_mount swap + sudo mkswap -f -L ${vm_lvm_lv}_swap \ + /dev/mapper/${vm_lvm_lv}_swap_deciphered + rule__part_encrypted_umount swap + } +rule_part_boot_format () { + mount | grep -q "^$vm_dev_disk_boot " || + sudo mke2fs -t ext2 -c -c -m 5 -T small \ + -E resize=1G${vm_e2fs_extended_options} \ + -L ${vm_lvm_lv}_boot $vm_dev_disk_boot + } +rule_part_boot_mount () { + mountpoint -q /mnt/$vm_fqdn + test -d /mnt/$vm_fqdn/boot + mountpoint -q /mnt/$vm_fqdn/boot || + sudo mount -v -t ext2 $vm_dev_disk_boot /mnt/$vm_fqdn/boot + } +rule_part_boot_umount () { + ! mountpoint -q /mnt/$vm_fqdn/boot || + sudo umount -v /mnt/$vm_fqdn/boot + } +rule_part_var_format () { + rule__part_encrypted_format var + rule__part_encrypted_mount var + sudo mke2fs -t ext4 -c -c -m 5 -T ext4 -b $vm_e2fs_block_size \ + -E resize=10G${vm_e2fs_extended_options} \ + -L ${vm_lvm_lv}_var \ + /dev/mapper/${vm_lvm_lv}_var_deciphered + rule__part_encrypted_umount var + } +rule_part_var_mount () { + rule__part_encrypted_mount var + mountpoint -q /mnt/$vm_fqdn/var || + sudo mount -v -t ext4 /dev/mapper/${vm_lvm_lv}_var_deciphered /mnt/$vm_fqdn/var + } +rule_part_var_umount () { + ! mountpoint -q /mnt/$vm_fqdn/var || + sudo umount -v /mnt/$vm_fqdn/var + rule__part_encrypted_umount var + } +rule_part_home_format () { + rule__part_encrypted_format home + rule__part_encrypted_mount home + sudo mke2fs -t ext4 -c -c -m 0 -T ext4 -b $vm_e2fs_block_size \ + -E resize=400G${vm_e2fs_extended_options} \ + -L ${vm_lvm_lv}_home \ + /dev/mapper/${vm_lvm_lv}_home_deciphered + # NOTE: -O quota pas supporté par e2fsprogs/squeeze + rule__part_encrypted_umount home + } +rule_part_home_mount () { + rule__part_encrypted_mount home + mountpoint -q /mnt/$vm_fqdn/home || + sudo mount -v -t ext4 /dev/mapper/${vm_lvm_lv}_home_deciphered /mnt/$vm_fqdn/home + } +rule_part_home_umount () { + ! mountpoint -q /mnt/$vm_fqdn/home || + sudo umount -v /mnt/$vm_fqdn/home + rule__part_encrypted_umount home + } + +rule_debian_install () { + rule_disk_mount + rule_part_lvm_mount + rule_part_root_mount + rule_part_boot_mount + rule_part_var_mount + sudo DEBOOTSTRAP_DIR=/usr/share/debootstrap/ LANG=C LC_CTYPE=C debootstrap \ + --arch=$vm_arch --verbose --keyring=/usr/share/keyrings/debian-archive-keyring.gpg \ + --exclude=vim-tiny \ + --include=$(printf '%s,' \ + acl \ + bsdmainutils \ + busybox \ + ca-certificates \ + console-setup \ + cryptsetup \ + dash \ + dnsutils \ + dropbear \ + etckeeper \ + gnupg \ + hashalot \ + htop \ + ifupdown \ + initramfs-tools \ + kbd \ + less \ + locales \ + lvm2 \ + mosh \ + molly-guard \ + ncurses-term \ + openssh-client \ + openssh-server \ + openssl \ + pciutils \ + procps \ + quota \ + quotatool \ + rsync \ + screen \ + sudo \ + sysprofile \ + vim-nox \ + wget \ + zsh \ + ) \ + $vm_lsb_name /mnt/$vm_fqdn/ \ + http://ftp.fr.debian.org/debian/ + rule_part_var_umount + rule_part_boot_umount + rule_part_root_umount + } + +rule_chroot () { + rule_disk_mount + rule_part_lvm_mount + rule_part_root_mount + rule_part_boot_mount + rule_part_var_mount + #rule_part_home_mount + mountpoint -q /mnt/$vm_fqdn/proc || + sudo mount -t proc proc /mnt/$vm_fqdn/proc + mountpoint -q /mnt/$vm_fqdn/sys || + sudo mount -t sysfs sys /mnt/$vm_fqdn/sys + mountpoint -q /mnt/$vm_fqdn/dev || + sudo mount --bind /dev /mnt/$vm_fqdn/dev + if test -d /mnt/$vm_fqdn/root/tool/vm/.git + then + mountpoint -q /mnt/$vm_fqdn/root/tool/vm || + sudo mount --bind "$tool" /mnt/$vm_fqdn/root/tool/vm + else + rsync -a "$tool"/ /mnt/$vm_fqdn/root/tool/vm + fi + sudo chroot /mnt/$vm_fqdn /bin/bash || true + rule__chroot_clean + } +rule__chroot_clean () { + ! sudo mountpoint -q /mnt/$vm_fqdn/root/tool/vm || + sudo umount -v /mnt/$vm_fqdn/root/tool/$vm + ! mountpoint -q /mnt/$vm_fqdn/dev || + sudo umount -v /mnt/$vm_fqdn/dev + ! mountpoint -q /mnt/$vm_fqdn/sys || + sudo umount -v /mnt/$vm_fqdn/sys + ! mountpoint -q /mnt/$vm_fqdn/proc || + sudo umount -v /mnt/$vm_fqdn/proc + rule_part_home_umount + rule_part_var_umount + rule_part_boot_umount + rule_part_root_umount + rule_disk_umount + } + +rule=${1:-help} +${1+shift} +set "${TRACE:+-x}" +rule_$rule "$@" diff --git a/vm_hosted b/vm_hosted new file mode 100755 index 0000000..56e1ee0 --- /dev/null +++ b/vm_hosted @@ -0,0 +1,804 @@ +#!/bin/sh +set -e -f ${DRY_RUN:+-n} -u +tool=${0%/*} +. "$tool"/functions.sh +. "$tool"/vm.sh +test "$(hostname --fqdn)" = "$vm_fqdn" + +rule_help () { + cat >&2 <<-EOF + DESCRIPTION: ce script regroupe des fonctions utilitaires + pour gérer la VM _depuis_ la VM hébergée ; + il sert à la fois d'outil et de documentation. + Voir \`$tool/vm_host' pour les utilitaires côté machine hôte. + SYNTAX: $0 \$RULE \${RULE}_SYNTAX + RULES: + $(sed -ne 's/^rule_\([^_][^ ]*\) () {\( *#.*\|\)/\t\1\2/p' "$tool"/vm.sh "$0") + ENVIRONMENT: + TRACE # affiche les commandes avant leur exécution + $(sed -ne 's/^readonly \([^ ][^ =]*\).*}\( *#.*\|\)$/\t$\1\2/p' "$tool"/vm.sh "$0") + EOF + } + +rule_git_reset () { + ( + cd "$tool" + git checkout -f -B master origin + git clean -f -d -x + ) + } + +rule_chrooted () { + export LANG=C + export LC_CTYPE=C + . /etc/profile + } + +rule__etckeeper_init () { + mk_reg mod=644 own=root:root /etc/etckeeper/etckeeper.conf <<-EOF + VCS=git + GIT_COMMIT_OPTIONS="" + AVOID_DAILY_AUTOCOMMITS=1 + #AVOID_SPECIAL_FILE_WARNING=1 + #AVOID_COMMIT_BEFORE_INSTALL=1 + HIGHLEVEL_PACKAGE_MANAGER=apt + LOWLEVEL_PACKAGE_MANAGER=dpkg + EOF + } +rule__locale_init () { + mk_reg mod=644 own=root:root /etc/locale.gen <<-EOF + fr_FR.UTF-8 UTF-8 + EOF + sudo update-locale + } +rule__network_init () { + mk_reg mod= own= /etc/hostname <<-EOF + $vm + EOF + grep -q " $vm\$" /etc/hosts || + mk_reg mod= own= --append /etc/hosts <<-EOF + 127.0.0.1 $vm_fqdn $vm + EOF + mk_reg mod= own= /etc/network/interfaces <<-EOF + auto lo + iface lo inet loopback + + auto eth0=grenode + iface grenode inet static + address $vm_ipv4 + gateway $vm_ipv4 # NOTE: proxy_arp sur la passerelle permet d'utiliser la même adresse + network $vm_ipv4 + broadcast $vm_ipv4 + netmask 255.255.255.255 + mtu 1300 # TODO: voir si c'est nécessaire à Lyon + post-up ip address add $vm_ipv4/32 dev \$IFACE + pre-down ip address delete $vm_ipv4/32 dev \$IFACE + EOF + } +rule__apt_init () { + mk_reg mod= own= /etc/apt/sources.list <<-EOF + deb http://ftp.fr.debian.org/debian $vm_lsb_name main contrib non-free + EOF + mk_reg mod= own= /etc/apt/sources.list.d/$vm_lsb_name-backports.list <<-EOF + deb http://backports.debian.org/debian-backports $vm_lsb_name-backports main contrib non-free + EOF + mk_reg mod= own= /etc/apt/preferences <<-EOF + Package: * + Pin: release a=$vm_lsb_name + Pin-Priority: 170 + + Package: * + Pin: release a=$vm_lsb_name-backports + Pin-Priority: 200 + EOF + mk_reg mod= own= /etc/apt/sources.list.d/openerp.list <<-EOF + deb http://nightly.openerp.com/trunk/nightly/deb/ ./ + EOF + } +rule__filesystem_init () { + mk_reg mod=644 own=root:root /etc/fstab <<-EOF + # + LABEL=${vm_lvm_lv}_boot /boot ext2 defaults 0 0 + proc /proc proc defaults 0 0 + sysfs /sys sysfs defaults 0 0 + tmpfs /tmp tmpfs rw,nosuid,nodev,auto,size=200m,nr_inodes=1000k,mode=1777,noatime,nodiratime 0 0 + /dev/mapper/${vm_lvm_lv}_root_deciphered / ext4 defaults,errors=remount-ro,acl,noatime 0 1 + /dev/mapper/${vm_lvm_lv}_var_deciphered /var ext4 defaults,errors=remount-ro,acl,noatime 0 1 + /dev/mapper/${vm_lvm_lv}_home_deciphered /home ext4 defaults,errors=remount-ro,acl,noatime,usrquota,grpquota 0 0 + /dev/mapper/${vm_lvm_lv}_swap_deciphered swap swap sw 0 0 + EOF + mk_reg mod=644 own=root:root /etc/crypttab <<-EOF + # + ${vm_lvm_lv}_root_deciphered /dev/$vm_lvm_vg/${vm_lvm_lv}_root none luks,lvm=$vm_lvm_vg + ${vm_lvm_lv}_var_deciphered /dev/$vm_lvm_vg/${vm_lvm_lv}_var ${vm_lvm_lv}_root_deciphered luks,lvm=$vm_lvm_vg,keyscript=/lib/cryptsetup/scripts/decrypt_derived + ${vm_lvm_lv}_home_deciphered /dev/$vm_lvm_vg/${vm_lvm_lv}_home ${vm_lvm_lv}_root_deciphered luks,lvm=$vm_lvm_vg,keyscript=/lib/cryptsetup/scripts/decrypt_derived + ${vm_lvm_lv}_swap_deciphered /dev/$vm_lvm_vg/${vm_lvm_lv}_swap ${vm_lvm_lv}_root_deciphered luks,lvm=$vm_lvm_vg,keyscript=/lib/cryptsetup/scripts/decrypt_derived + EOF + mk_reg mod=644 own=root:root /etc/sysctl.d/local-swap.conf <<-EOF + vm.swappiness = 10 # NOTE: n'utilise le swap qu'en cas d'absolue nécessité + vm.vfs_cache_pressure=50 + EOF + } +rule__login_init () { + grep -q hvc0 /etc/securetty || + mk_reg mod= own= --append /etc/securetty <<-EOF + hvc0 + EOF + grep -q xvc0 /etc/securetty || + mk_reg mod= own= --append /etc/securetty <<-EOF + xvc0 + EOF + mk_reg mod=644 own=root:root /etc/inittab <<-EOF + # /etc/inittab: init(8) configuration. + + # The default runlevel. + id:2:initdefault: + + # Boot-time system configuration/initialization script. + # This is run first except when booting in emergency (-b) mode. + si::sysinit:/etc/init.d/rcS + + # What to do in single-user mode. + ~~:S:wait:/sbin/sulogin + + # /etc/init.d executes the S and K scripts upon change + # of runlevel. + # + # Runlevel 0 is halt. + # Runlevel 1 is single-user. + # Runlevels 2-5 are multi-user. + # Runlevel 6 is reboot. + + l0:0:wait:/etc/init.d/rc 0 + l1:1:wait:/etc/init.d/rc 1 + l2:2:wait:/etc/init.d/rc 2 + l3:3:wait:/etc/init.d/rc 3 + l4:4:wait:/etc/init.d/rc 4 + l5:5:wait:/etc/init.d/rc 5 + l6:6:wait:/etc/init.d/rc 6 + # Normally not reached, but fallthrough in case of emergency. + z6:6:respawn:/sbin/sulogin + + # What to do when CTRL-ALT-DEL is pressed. + ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now + + # What to do when the power fails/returns. + pf::powerwait:/etc/init.d/powerfail start + pn::powerfailnow:/etc/init.d/powerfail now + po::powerokwait:/etc/init.d/powerfail stop + + # Xen hypervisor console + hvc:2345:respawn:/sbin/getty 38400 hvc0 + #xvc:2345:respawn:/sbin/getty 38400 xvc0 + EOF + mk_reg mod=644 own=root:root /etc/login.defs <<-EOF + MAIL_DIR /var/mail + FAILLOG_ENAB yes + LOG_UNKFAIL_ENAB no + LOG_OK_LOGINS no + SYSLOG_SU_ENAB yes + SYSLOG_SG_ENAB yes + FTMP_FILE /var/log/btmp + SU_NAME su + HUSHLOGIN_FILE .hushlogin + ENV_SUPATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + ENV_PATH PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + # NOTE: met les sbin/ dans ENV_PATH ; + # - ça n'apporte aucune protection de ne pas les mettre ; + # - ça frustre de ne pas les trouver. + TTYGROUP tty + TTYPERM 0600 + ERASECHAR 0177 + KILLCHAR 025 + # NOTE: rwxrwx--- ; + # - donne une même confiance au groupe propriétaire qu'au propriétaire ; + # - facilite l'utilisation des ACL, qui sont dépendantes des droits du groupe propriétaire. + UMASK 007 + PASS_MAX_DAYS 99999 + PASS_MIN_DAYS 0 + PASS_WARN_AGE 7 + UID_MIN 1000 + UID_MAX 60000 + GID_MIN 1000 + GID_MAX 60000 + LOGIN_RETRIES 3 + LOGIN_TIMEOUT 60 + CHFN_RESTRICT rwh + DEFAULT_HOME yes + USERGROUPS_ENAB yes + ENCRYPT_METHOD SHA512 + EOF + grep -q '^session optional pam_umask.so\>' /etc/pam.d/common-session || + mk_reg mod= own= --append /etc/pam.d/common-session <<-EOF + session optional pam_umask.so + EOF + } +rule__user_root_init () { + mk_dir mod=750 own=root:root /root/etc + mk_dir mod=750 own=root:root /root/etc/ssh + mk_dir mod=750 own=root:root /root/etc/gpg + mk_lnk etc/gpg /root/.gnupg + mk_lnk etc/ssh /root/.ssh + getent group sudo | + while IFS=: read -r group x x users + do while IFS=, read -r user + do eval local home\; home="~$user" + cat "$home"/etc/ssh/authorized_keys + done <<-EOF + $users + EOF + done | + mk_reg mod=640 own=root:root /root/etc/ssh/authorized_keys + sudo find "$tool"/key -type f -name '*.gpg.pub' -exec gpg --import {} \; + } +rule__initramfs_init () { + mk_reg mod=644 own=root:root /etc/initramfs-tools/initramfs.conf <<-EOF + MODULES=most + BUSYBOX=y + KEYMAP=y + COMPRESS=gzip + DEVICE=eth0 + EOF + mk_reg mod=644 own=root:root /etc/modprobe.d/xen-pv.conf <<-EOF + alias eth0 xennet + alias scsi_hostadapter xenblk + EOF + mk_reg mod=644 own=root:root /etc/modules <<-EOF + sha1_generic + sha256_generic + sha512_generic + aes-x86_64 + xts + # NOTE: pour Xen en mode HVM : + #modprobe xen-platform-pci + EOF + mk_reg mod=644 own=root:root /etc/initramfs-tools/modules <<-EOF + EOF + sudo sed -e '/^configure_networking /s/ &$//' \ + -i /usr/share/initramfs-tools/scripts/init-premount/dropbear + # NOTE: corrige une vermine : dropbear doit attendre que le réseau soit configuré.. + sudo rm -f \ + /etc/initramfs-tools/etc/dropbear/dropbear_dss_host_key \ + /etc/initramfs-tools/etc/dropbear/dropbear_dss_host_key.pub \ + /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key \ + /etc/initramfs-tools/etc/dropbear/dropbear_rsa_host_key.pub + #mk_reg mod=640 own=root:root /dev/null || echo Debian\` + GRUB_CMDLINE_LINUX_DEFAULT="quiet" + GRUB_CMDLINE_LINUX="vt.default_utf8=1 rootfstype=ext4 loglevel=5 console=hvc0 ip=$vm_ipv4::$vm_ipv4:255.255.255.254:$vm:eth0:off resume=/dev/mapper/${vm}_swap_deciphered" + GRUB_DISABLE_RECOVERY="true" + #GRUB_PRELOAD_MODULES="lvm" + EOF + mk_reg mod=644 own=root:root /boot/grub/device.map <<-EOF + (hd0) /dev/xvda + (hd0) /dev/mapper/domU-$(printf %s $vm_fqdn-disk | sed -e 's/-/--/g') + EOF + sudo update-grub2 # NOTE: prend en compte /boot/grub/device.map + rule__initramfs_init + } +rule__bin_init () { + mk_lnk "$tool"/vm_hosted /usr/local/sbin/ + } +rule_init () { + rule__etckeeper_init + rule__locale_init + rule__network_init + rule__apt_init + rule__filesystem_init + rule__login_init + rule__user_root_init + rule__boot_init + rule__bin_init + } + +rule_disk_key_change () { + sudo cryptsetup luksChangeKey /dev/$vm_lvm_vg/${vm_lvm_lv}_root + } + +rule_user_init () { + mk_dir mod=750 own="root:adm" /etc/skel/etc + mk_dir mod=770 own="root:adm" /etc/skel/etc/apache2 + mk_dir mod=770 own="root:adm" /etc/skel/etc/ssh + mk_dir mod=700 own="root:adm" /etc/skel/var + mk_dir mod=700 own="root:adm" /etc/skel/var/log + mk_dir mod=700 own="root:adm" /etc/skel/var/cache + mk_dir mod=700 own="root:adm" /etc/skel/var/cache/ssh + mk_dir mod=700 own="root:adm" /etc/skel/tmp + mk_dir mod=700 own="root:adm" /etc/skel/tmp + mk_lnk etc/ssh /etc/skel/.ssh + mk_lnk etc/gpg /etc/skel/.gnupg + ssh-keygen -F "$vm_fqdn" -f "$tool"/key/ssh.known_hosts | + ( while IFS= read -r line + do case $line in (*" RSA") return 0; break;; esac + done; return 1 ) || + sudo ssh-keygen -t rsa -b 4096 -N '' -f /etc/ssh/ssh_host_rsa_key + sudo rm -f \ + /etc/ssh/ssh_host_dsa_key \ + /etc/ssh/ssh_host_dsa_key.pub \ + /etc/ssh/ssh_host_ecdsa_key \ + /etc/ssh/ssh_host_ecdsa_key.pub + # NOTE: clefs générées par Debian + mk_reg mod=664 own=root:root /etc/ssh/sshd_config <<-EOF + Port 22 + ListenAddress $vm_ipv4 + #ListenAddress :: + Protocol 2 + Compression yes + HostKey /etc/ssh/ssh_host_rsa_key + UsePrivilegeSeparation yes + KeyRegenerationInterval 3600 + ServerKeyBits 768 + SyslogFacility AUTH + LogLevel INFO + LoginGraceTime 120 + PermitRootLogin yes + StrictModes yes + RSAAuthentication yes + PubkeyAuthentication yes + AuthorizedKeysFile %h/etc/ssh/authorized_keys + IgnoreRhosts yes + RhostsRSAAuthentication no + HostbasedAuthentication no + IgnoreUserKnownHosts no + PermitEmptyPasswords no + ChallengeResponseAuthentication no + PasswordAuthentication no + KerberosAuthentication no + GSSAPIAuthentication no + X11Forwarding no + X11DisplayOffset 10 + PrintMotd no + DebianBanner no + PrintLastLog yes + TCPKeepAlive yes + ClientAliveInterval 0 + AcceptEnv LANG LC_* + Subsystem sftp /usr/lib/openssh/sftp-server + UsePAM yes + EOF + sudo service ssh restart + mk_reg mod=440 own=root:root /etc/sudoers.d/passwd-init <<-EOF + %sudo ALL=(ALL) NOPASSWD: /bin/sh -e -f -u -c \\ + case \$(/usr/bin/passwd --status "\$SUDO_USER") in \\ + ("\$SUDO_USER L "*) /usr/bin/passwd \$SUDO_USER;; esac + EOF + mk_reg mod=440 own=root:root /etc/sudoers.d/etckeeper-unclean <<-EOF + %sudo ALL=(ALL) NOPASSWD: /usr/sbin/etckeeper unclean + EOF + mk_reg mod=440 own=root:root /etc/sudoers.d/env_keep <<-EOF + Defaults env_keep = " \\ + EDITOR \\ + GIT_AUTHOR_NAME \\ + GIT_AUTHOR_EMAIL \\ + GIT_COMMITTER_NAME \\ + GIT_COMMITTER_EMAIL \\ + " + EOF + mk_reg mod=555 own=root:root /usr/local/sbin/passwd-init <<-EOF + #!/bin/sh + sudo /bin/sh -e -f -u -c \ + 'case \$(/usr/bin/passwd --status "\$SUDO_USER") in ("\$SUDO_USER L "*) /usr/bin/passwd \$SUDO_USER;; esac' + EOF + } +rule_user_admin_add () { # SYNTAX: $user + local user=$1 + id "$user" >/dev/null || + sudo adduser --disabled-password "$user" + # NOTE: le mot-de-passe doit être initialisé par l'utilisateur à l'aide de passwd-init . + eval local home\; home="~$user" + sudo adduser "$user" sudo + ssh_key_add user=$user "$tool"/key/"$user".ssh.pub "$home"/etc/ssh/authorized_keys + rule__initramfs_init + rule__user_root_init + sudo gpg --import "$tool"/key/"$user".gpg.pub + } +rule_user_mail_format () { + mk_dir mod=770 own=root:adm /etc/skel/etc/procmail + mk_dir mod=770 own=root:adm /etc/skel/var/mail + mk_dir mod=770 own=root:adm /etc/skel/var/cache/procmail + mk_reg mod=660 own=root:adm /etc/skel/etc/procmail/delivery.rc <<-EOF + # vim: ft=procmail + + # NOTE: paramètres passés par postfix + SENDER=\$1 + RECIPIENT=\$2 + USER=\$3 + EXTENSION=\$4 + DOMAIN=\$5 + ORIGINAL_RECIPIENT=\$6 + + PATH="\$HOME/bin:/usr/local/bin:/usr/bin:/bin" + MAILDIR="\$HOME/var/mail/" + DEFAULT="\$MAILDIR" + #LOGFILE=`cd="\$HOME/var/log/procmail/" d=\$(date +"%Y-%m-%d"); ln -fns "\$d.log" "\$cd/current.log"; printf %s "\$cd/\$d.log"` + LOGFILE="/dev/null" + LOGABSTRACT=all + LOGABSTRACT + VERBOSE + SHELL=/bin/sh + SHELLMETAS=&|<>~;?*%{} + + # DESCRIPTION: supprime les doublons en fonction du champ Message-Id + #:0 Wh: "\$HOME/var/cache/procmail/msgid\$LOCKEXT" + #| formail -D 8192 "\$HOME/var/cache/procmail/msgid" + + # DESCRIPTION: fait suivre à l'adresse configurée dans /etc/passwd ; on peut aussi utiliser ~/.forward + EMAIL=`sed /etc/passwd -ne "/^\$USER:/s/[^:]*:[^:]*:[^:]*:[^:]*:[^,]*,[^,]*,[^,]*,[^,]*,\([^:]*\):.*/\1/p"` + # NOTE: récupère l’adresse courriel dans le champ GECOS + FROM_=`formail -c -x "From " | sed -e 's/^\s*\([^ \t]*\).*/\1/g'` + # NOTE: récupère l’expéditeur inscrit sur l’enveloppe + :0 + | \$SENDMAIL -i -bm -f "\$FROM_" "\${EMAIL/@/\${EXTENSION:++\${EXTENSION}}@}" + + # DESCRIPTION: IMAP + #:0 + #| /usr/lib/dovecot/deliver -f "\$SENDER" -a "\$RECIPIENT" + + # DESCRIPTION: UUCP + #:0 + #| /usr/bin/uux \ + # -I "\$HOME/etc/uucp/uucp.cfg" \ + # --nouucico \ + # --notification=error \ + # --requestor "\$USER" \ + # - "\$USER!rmail" "(\$USER)" + EOF + mk_reg mod=664 own=root:root /etc/postfix/main.cf <<-EOF + # /etc/postfix/main.cf + # SEE: http://postfix.traduc.org/index.php/TLS_README.html + + parent_domain_matches_subdomains = + #debug_peer_list + #fast_flush_domains + #mynetworks + #permit_mx_backup_networks + #qmqpd_authorized_clients + #smtpd_access_maps + mydomain = $vm_domainname + myorigin = \$mydomain + myhostname = $vm_hostname.\$mydomain + mail_name = \$myhostname + mydestination = + $vm_hostname + \$myhostname + \$myorigin + mynetworks = + 127.0.0.0/8 + #[::1]/128 + inet_protocols = ipv4 + # "all" to activate IPv6 + inet_interfaces = all + permit_mx_backup_networks = + + alias_database = + hash:/etc/aliases + # NOTE: fichier de hash contenant une table d’alias mail. + # Celle-ci est éditable dans /etc/aliases, puis (indispensable) + # regénérée en hash grâce à la commande newaliases qui produit /etc/aliases.db + alias_maps = + hash:/etc/aliases + recipient_delimiter = + + # NOTE: séparateur entre le nom d’utilisateur + # et les extensions d’adresse (par défaut le signe +). + #virtual_alias_domains = + virtual_alias_maps = + hash:/etc/postfix/\$mydomain/virtual + # NOTE: do not specify virtual alias domain names in the main.cf + # mydestination or relay_domains configuration parameters. + # + # With a virtual alias domain, the Postfix SMTP server + # accepts mail for known-user@virtual-alias.domain, and + # rejects mail for unknown-user@virtual-alias.domain as + # undeliverable. + #relayhost = + relay_clientcerts = + hash:/etc/postfix/\$mydomain/smtpd/tls/relay_clientcerts + relay_domains = + \$mydestination + # NOTE: ajouter les domaines pour lesquels on est backup MX ici, + # pas dans mydestination ou virtual_alias... + + maximal_queue_lifetime = 5d + + header_checks = + regexp:/etc/postfix/\$mydomain/header_checks + mime_header_checks = + nested_header_checks = + milter_header_checks = + body_checks = + + #content_filter = amavisfeed:[127.0.0.1]:10024 + #receive_override_options = no_address_mappings + # no_unknown_recipient_checks + # Do not try to reject unknown recipients (SMTP server only). + # This is typically specified AFTER an external content filter. + # no_address_mappings + # Disable canonical address mapping, virtual alias map expansion, + # address masquerading, and automatic BCC (blind carbon-copy) recipients. + # This is typically specified BEFORE an external content filter (eg. amavis). + # no_header_body_checks + # Disable header/body_checks. This is typically specified AFTER an external content filter. + # no_milters + # Disable Milter (mail filter) applications. This is typically specified AFTER an external content filter. + #local_header_rewrite_clients = + transport_maps = + hash:/etc/postfix/\$mydomain/transport_maps + mailbox_command = + /usr/bin/procmail -t -a "\$SENDER" -a "\$RECIPIENT" -a "\$USER" -a "\$EXTENSION" -a "\$DOMAIN" -a "\$ORIGINAL_RECIPIENT" "\$HOME/etc/procmail/delivery.rc" + mailbox_size_limit = 0 + biff = no + # Activer la notification en cas de réception de nouveaux e-mails dans la console (yes / no). + append_dot_mydomain = no + # appending .domain is the MUA's job. + + #tls_random_source = + # dev:/dev/urandom + # Non-blocking + #tls_random_reseed_period = 3600s + #tls_random_exchange_name = + # \${data_directory}/prng_exch + # NOTE: à ne pas mettre dans la cage chroot + #tls_random_bytes = 32 + #tls_random_prng_update_period = 3600s + #tls_high_cipherlist = AES256-SHA + # NOTE: postconf(5) déconseille de changer ceci + + #smtp_cname_overrides_servername = no + smtp_connect_timeout = 60s + #smtp_tls_CAfile = /etc/postfix/\$mydomain/smtp/tls/ca/crt.pem + #smtp_tls_CApath = /etc/postfix/\$mydomain/smtp/tls/ca/ + #smtp_tls_cert_file = /etc/postfix/\$mydomain/smtp/tls/crt.pem + #smtp_tls_key_file = /etc/postfix/\$mydomain/smtp/tls/key.pem + #smtp_tls_per_site = hash:/etc/postfix/\$mydomain/smtp/tls/per_site + # NOTE: déprécié en faveur de smtp_tls_policy_maps + smtp_tls_policy_maps = hash:/etc/postfix/\$mydomain/smtp/tls/policy + smtp_tls_fingerprint_digest = sha1 + smtp_tls_scert_verifydepth = 5 + #smtp_tls_secure_cert_match = nexthop, dot-nexthop + #smtp_tls_verify_cert_match = hostname + #smtp_tls_note_starttls_offer = yes + smtp_tls_loglevel = 1 + smtp_tls_protocols = !SSLv2, !SSLv3 + # Only allow TLSv* + smtp_tls_session_cache_database = btree:/var/lib/postfix/smtp_tls_session_cache + #smtp_tls_session_cache_timeout = 3600s + smtp_tls_security_level = may + smtp_header_checks = regexp:/etc/postfix/\$mydomain/smtp/header_checks + smtp_body_checks = + smtp_mime_header_checks = + smtp_nested_header_checks = + + smtpd_starttls_timeout = 300s + smtpd_banner = + \$myhostname ESMTP \$mail_name (Debian/GNU) + + # Restrictions + smtpd_helo_required = yes + strict_rfc821_envelopes = yes + smtpd_authorized_xclient_hosts = 127.0.0.1 + # NOTE: utile pour tester les restrictions + + smtpd_helo_restrictions = + reject_invalid_helo_hostname + reject_non_fqdn_helo_hostname + #reject_unknown_helo_hostname + # NOTE: pourrait pourtant être utile pour lutter contre le spam + permit + + smtpd_sender_restrictions = + permit_mynetworks + permit_tls_clientcerts + permit_sasl_authenticated + check_sender_access hash:/etc/postfix/\$mydomain/smtpd/sender_access + check_sender_access hash:/etc/postfix/sender_blacklist + reject_unauth_pipelining + reject_non_fqdn_sender + #reject_unknown_sender_domain + # NOTE: temporaire + permit + + smtpd_client_new_tls_session_rate_limit = 0 + smtpd_client_event_limit_exceptions = \$mynetworks + smtpd_client_recipient_rate_limit = 0 + smtpd_client_connection_count_limit = 50 + smtpd_client_connection_rate_limit = 0 + smtpd_client_message_rate_limit = 0 + smtpd_client_port_logging = no + + smtpd_client_restrictions = + check_client_access hash:/etc/postfix/client_blacklist + + policy_time_limit = 3600 + default_extra_recipient_limit = 5000 + duplicate_filter_limit = 5000 + smtpd_recipient_limit = 5000 + smtpd_recipient_overshoot_limit = 5000 + smtpd_recipient_restrictions = + reject_non_fqdn_recipient + #reject_invalid_hostname + # NOTE: postfix < 2.3. voir reject_invalid_helo_hostname + # dans smtpd_helo_restrictions + reject_unknown_recipient_domain + #reject_non_fqdn_sender + # NOTE: dans smtpd_sender_restrictions + reject_unauth_pipelining + # NOTE: dans smtpd_client_restrictions ou smtpd_data_restrictions + permit_mynetworks + permit_tls_clientcerts + permit_sasl_authenticated + reject_unauth_destination + # NOTE: ne pas passer par SPFCheck / Postgrey si le mail n'est pas pour nous + # ou quelqu'un pour lequel on tient lieu de backup_mx + check_policy_service inet:127.0.0.1:10023 + # NOTE: Postgrey (greylisting) + check_policy_service unix:private/spfcheck + permit_auth_destination + # NOTE: une fois Postgrey passé, on accepte ce qui nous est destiné + # (voir permit_auth_destination) ; sans doute redondant + reject + #check_relay_domains <- removed from postfix + #reject_unknown_sender_domain + # aurait probablement été mieux dans smtpd_sender_restrictions + #reject_rbl_client bl.spamcop.net + #reject_rbl_client list.dsbl.org + #reject_rbl_client zen.spamhaus.org + #reject_rbl_client dnsbl.sorbs.net + + smtpd_data_restrictions = + reject_unauth_pipelining + # NOTE: obliger le serveur en face à attendre qu'on lui aie dit OK + permit + + #smtpd_end_of_data_restrictions = + + #smtpd_restriction_classes = + + smtpd_error_sleep_time = 5 + # NOTE: forcer quelqu'un qui nous embête à attendre cinq secondes. + + # SASL + smtpd_sasl_auth_enable = yes + smtpd_sasl_type = dovecot + smtpd_sasl_path = private/auth + smtpd_sasl_security_options = noanonymous + smtpd_sasl_domain = \$mydomain + + # SMTPD TLS + smtpd_discard_ehlo_keywords = starttls + # NOTE: les clients mails tentant d'utiliser le chiffrement opportuniste + # se mangent une erreur en tentant un starttls + smtpd_tls_fingerprint_digest = sha1 + # sha512 ? + smtpd_tls_mandatory_protocols = TLSv1 + smtpd_tls_mandatory_ciphers = high + smtpd_tls_ciphers = high + # restrictif. s/high/medium/ ? + smtpd_tls_CAfile = /etc/postfix/\$mydomain/smtpd/tls/ca/crt+crl.slf.pem + smtpd_tls_CApath = /etc/postfix/\$mydomain/smtpd/tls/ca/ + smtpd_tls_cert_file = /etc/postfix/\$mydomain/smtpd/tls/crt+crl.slf.pem + smtpd_tls_key_file = /etc/postfix/\$mydomain/smtpd/tls/key.pem + ## + #smtpd_tls_received_header = no + smtpd_tls_session_cache_database = + btree:/var/lib/postfix/smtpd_tls_session_cache + #smtpd_tls_session_cache_timeout = 3600s + smtpd_tls_security_level = may + # Postfix 2.3 and later + # encrypt + # Mandatory TLS encryption: announce STARTTLS support to SMTP clients, and require that clients use TLS + # encryption. According to [1720]RFC 2487 this MUST NOT be applied in case of a publicly-referenced + # SMTP server. Instead, this option should be used only on dedicated servers. + smtpd_tls_loglevel = 1 + smtpd_tls_ccert_verifydepth = 5 + smtpd_tls_auth_only = yes + # Pas d'AUTH SASL sans TLS + smtpd_tls_ask_ccert = no + smtpd_tls_req_ccert = no + #smtpd_tls_always_issue_session_ids = yes + smtpd_peername_lookup = yes + # Nécessaire pour postgrey, etc + smtpd_milters = + non_smtpd_milters = + line_length_limit = 2048 + queue_minfree = 0 + message_size_limit = 20480000 + #smtpd_enforce_tls # NOTE: obsolète + #smtpd_use_tls # NOTE: obsolète + #smtpd_tls_cipherlist # NOTE: obsolète + + readme_directory = no + #delay_warning_time = 4h + # NOTE: uncomment the previous line to generate "delayed mail" warnings + #debug_peer_level = 4 + #debug_peer_list = .\$myhostname + EOF + mk_reg mod=664 own=root:root /etc/dovecot/dovecot.conf <<-EOF + auth_ssl_username_from_cert = yes + listen = * + log_timestamp = "%Y-%m-%d %H:%M:%S " + mail_debug = yes + mail_location = maildir:~/var/mail + mail_privileged_group = mail + passdb { + args = /home/%u/etc/dovecot/passwd + driver = passwd-file + } + protocols = imap + service auth { + unix_listener /var/spool/postfix/private/auth { + group = postfix + mode = 0660 + user = postfix + } + user = root + } + ssl_ca = &2 <<-EOF + DESCRIPTION: ce script regroupe des fonctions utilitaires + pour gérer la VM _depuis_ une machine distante ; + il sert à la fois d'outil et de documentation. + Voir \`$tool/vm_host' pour les utilitaires côté machine hôte. + Voir \`$tool/vm_hosted' pour les utilitaires côté VM hébergée. + SYNTAX: $0 \$RULE \${RULE}_SYNTAX + RULES: + $(sed -ne 's/^rule_\([^_][^ ]*\) () {\( *#.*\|\)/\t\1\2/p' "$tool"/vm.sh "$0") + ENVIRONMENT: + TRACE # affiche les commandes avant leur exécution + $(sed -ne 's/^readonly \([^ ][^ =]*\).*}\( *#.*\|\)$/\t$\1\2/p' "$tool"/vm.sh "$0") + EOF + } + +rule_git_config () { + ( + cd "$tool" + git config remote.host.url >/dev/null || + git remote add host $vm_host:tool/vm + git config --replace remote.host HEAD:refs/heads/origin + git config remote.$vm.url >/dev/null || + git remote add vm root@$vm_fqdn:tool/vm + git config --replace remote.$vm HEAD:refs/heads/origin + ) + } +rule_git_push () { # SYNTAX: $remote $options + local remote=${1#remote=}; shift + git add . && + git commit -a -C HEAD "$@" && + local pwd=$(cd "$tool" && cd -) + GIT_SSH=./vm_ssh git push -v -f "$remote" + } + +rule_ssh () { + "$tool"/vm_ssh $vm_fqdn "$@" + } +rule__ssh_known_hosts_update () { + "$tool"/vm_ssh $vm_fqdn "$@" \ + -o StrictHostKeyChecking=no \ + -o CheckHostIP=no \ + -o HashKnownHosts=no \ + whoami + } +rule_disk_key_send () { + gpg --decrypt key/secret/$vm_fqdn.disk.gpg | + ssh "$@" root@$vm_fqdn \ + -o CheckHostIP=no \ + -o HostKeyAlias=init.$vm_fqdn \ + -o StrictHostKeyChecking=yes \ + -o UserKnownHostsFile="$tool"/key/ssh.known_hosts \ + tee /lib/cryptsetup/passfifo \>/dev/null + } +rule_disk_key_backup () { + for part in root swap var home + do + rule_ssh sudo cryptsetup luksHeaderBackup /dev/$vm_lvm_vg/${vm_lvm_lv}_${part} | + gpg --encrypt --recipient $USER@ -o key/secret/${vm_lvm_lv}_${part}.luks.gpg + done + } +rule_disk_key_restore () { + for part in root swap var home + do + gpg --decrypt ${vm_lvm_lv}_${part}.luks | + rule_ssh sudo cryptsetup luksHeaderRestore /dev/$vm_lvm_vg/${vm_lvm_lv}_${part} + done + } + +rule=${1:-help} +${1+shift} +set "${TRACE:+-x}" +rule_$rule "$@" diff --git a/vm_ssh b/vm_ssh new file mode 100755 index 0000000..d1c0c51 --- /dev/null +++ b/vm_ssh @@ -0,0 +1,7 @@ +#!/bin/sh +set -e -f ${DRY_RUN:+-n} -u +tool=${0%/*} +ssh \ + -o StrictHostKeyChecking=yes \ + -o UserKnownHostsFile="$tool"/key/ssh.known_hosts \ + "$@" diff --git a/workflow.txt b/workflow.txt deleted file mode 100644 index e9cd3a3..0000000 --- a/workflow.txt +++ /dev/null @@ -1,9 +0,0 @@ -% export TRACE=1 -% ./ateliers_host disk_mount -% ./ateliers_host disk_format -% ./ateliers_host part_lvm_format -% ./ateliers_host part_root_format -% ./ateliers_host part_boot_format -% ./ateliers_host part_swap_format -% ./ateliers_host part_var_format -% ./ateliers_host part_home_format