Envoyer des emails avec un relai smtp hébergé chez Orange (FreeBSD & Sendmail)

Envoyer des emails avec un relai smtp hébergé chez Orange (FreeBSD & Sendmail)

Il existe beaucoup d’articles sur ce sujet mais aucun avec la configuration que j’ai mise en place. Du coup je ne sais pas si cela va servir à quelqu’un mais dans le doute je me permets d’expliquer ma configuration. Le but de cet article est d’expliquer comment envoyer des emails depuis votre serveur de messagerie personnel.

L’auto-herbergement de ces types de services (serveur web, serveur mail, serveur de fichiers, etc.) augmente régulièrement depuis de nombreuses années et avec l’arrivée des micro-ordinateurs (comme Raspberry), cette tendance ne fait que de s’amplifier. J’ai donc décidé d’héberger mon serveur de messagerie personnel.

Pour héberger un serveur de messagerie pour lequel vous souhaitez envoyer et recevoir des emails depuis le réseau Internet, vous devez au préalable avoir un enregistrement DNS type MX valide. Pour cela, j’utilise le service de « DNS Dynamic » noip. J’associe à mon enregistrement DNS type A, un enregistrement DNS type MX portant le même nom.

$ host server.noipdomain.net
myserver.mydomain.net has address x.x.x.x
myserver.mydomain.net mail is handled by 10 myserver.mydomain.net.

J’ai mis en place l’environnement technique suivant :

  • Micro-ordinateur Raspberry 3 Model B
  • Image RaspBSD (r313109M) (FreeBSD 11.0 pour arm64)
  • Sendmail avec le support de SASL

La difficulté n’est pas tant de recevoir les emails depuis Internet mais bien de les envoyer depuis votre serveur de messagerie vers Internet. En effet pour éviter la diffusion de SPAM les opérateurs télécoms ont bloqués les connexions (depuis les box) vers les serveurs de messageries. Il est donc nécessaire d’utiliser un relai SMTP valide pour envoyer un email.

Mon fournisseur d’accès Internet est Orange, j’utilise donc leur relai de messagerie (smtp.orange.fr). La connexion au relai de messagerie chez Orange nécessite une authentification (d’où le support de SASL pour Sendmail). Pour une question de sécurité, j’ai créé un compte de messagerie spécifique. La procédure de création d’une boîte aux lettres secondaire est décrite ici.

Vérifier le support de SASL dans Sendmail via la commande suivante :

# /usr/local/sbin/sendmail -d0.1 -bv root
Version x.xx.x
 Compiled with: DNSMAP IPV6_FULL LOG MAP_REGEX MATCHGECOS MILTER
MIME7TO8 MIME8TO7 NAMED_BIND NETINET NETINET6 NETUNIX NEWDB NIS
PICKY_HELO_CHECK PIPELINING SASLv2 SCANF STARTTLS TCPWRAPPERS
USERDB XDEBUG

============ SYSTEM IDENTITY (after readcf) ============
      (short domain name) $w = myserver
  (canonical domain name) $j = myserver.mydomain.net
         (subdomain name) $m = mydomain.net
              (node name) $k = myserver
========================================================

root... deliverable: mailer local, user root

Si le support de SASL n’est pas disponible dans Sendmail, je vous invite à suivre la procédure de compilation d’écrite dans le Handbook de FreeBSD.

Il faut créer le fichier d’authentification au serveur relai de messagerie. J’utilise ici le compte de messagerie spécifique que j’ai créé :

# cat authinfo
AuthInfo:smtp.orange.fr "U:root" "I:xxx@orange.fr" "P:pass" "M:LOGIN"
AuthInfo:smtp.orange.fr:587 "U:root" "I:xxx@orange.fr" "P:pass" "M:LOGIN"

Une fois le fichier généré, il faut créer la table correspondante :

# makemap hash authinfo < authinfo

Il faut insérer les macros suivante à votre configuration de sendmail (modifier le ficher <server>.mc) :

dnl SMART HOST CONFIG
define(`SMART_HOST', `smtp.orange.fr')dnl
define(`RELAY_MAILER_ARGS', `TCP $h 587')dnl
define(`confAUTH_MECHANISMS', `GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
FEATURE(`authinfo',`hash /etc/mail/authinfo.db')dnl
TRUST_AUTH_MECH(`GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl

On génère le fichier de configuration via la commande make et on n’oublie pas de recopier le fichier de configuration :

# cd /etc/mail && make
/usr/bin/m4 -D_CF_DIR_=/usr/local/share/sendmail/cf/   /usr/local/share/sendmail/cf/m4/cf.m4 server.mc > unixme.cf
/usr/bin/m4 -D_CF_DIR_=/usr/local/share/sendmail/cf/   /usr/local/share/sendmail/cf/m4/cf.m4 server.submit.mc > server.submit.cf

# cp server.cf sendmail.cf

Un arrêt / relance de sendmail est nécessaire pour prendre en compte les modifications :

# service sendmail stop
Stopping sendmail.
Waiting for PIDS: 37413.
Stopping sendmail_msp_queue.
Waiting for PIDS: 36932.

# service sendmail start
Starting sendmail.
Starting sendmail_msp_queue.

Maintenant il suffit de tester notre configuration :

$ mail -v -s Test <messagerie@test.fr>
test send
.
EOT

messagerie@test.fr... Connecting to [127.0.0.1] via relay...
220 myserver.mydomain.net ESMTP Sendmail x.xx.x/x.xx.x; Fri, 14 Apr 2017 16:16:59 +0200 (CEST)
>>> EHLO myserver.mydomain.net
250-myserver.mydomain.net Hello localhost [127.0.0.1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-AUTH DIGEST-MD5 CRAM-MD5 LOGIN PLAIN
250-STARTTLS
250-DELIVERBY
250 HELP
>>> STARTTLS
220 2.0.0 Ready to start TLS
>>> EHLO myserver.mydomain.net
250-myserver.mydomain.net Hello localhost [127.0.0.1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-AUTH DIGEST-MD5 CRAM-MD5 LOGIN PLAIN
250-DELIVERBY
250 HELP
>>> MAIL From:<moi@myserver.mydomain.net> SIZE=53 AUTH=moi@myserver.mydomain.net
250 2.1.0 <moi@myserver.mydomain.net>... Sender ok
>>> RCPT To:<messagerie@test.fr>
>>> DATA
250 2.1.5 <messagerie@test.fr>... Recipient ok
354 Enter mail, end with "." on a line by itself
>>> .
250 2.0.0 v3EEGxQi037463 Message accepted for delivery
messagerie@test.fr... Sent (v3EEGxQi037463 Message accepted for delivery)
Closing connection to [127.0.0.1]
>>> QUIT
221 2.0.0 myserver.mydomain.net closing connection

Les logs de Sendmail indique les échanges suivants :

Apr 14 16:16:59 myserver sendmail[37462]: v3EEGx4r037462: from=moi, size=53, class=0, nrcpts=1, msgid=<201704141416.v3EEGx4r037462@myserver.mydomain.net>, relay=moi@localhost
Apr 14 16:16:59 myserver sm-mta[37463]: STARTTLS=server, relay=localhost [127.0.0.1], version=TLSv1.2, verify=NO, cipher=ECDHE-RSA-AES256-GCM-SHA384, bits=256/256
Apr 14 16:16:59 myserver sendmail[37462]: STARTTLS=client, relay=[127.0.0.1], version=TLSv1.2, verify=FAIL, cipher=ECDHE-RSA-AES256-GCM-SHA384, bits=256/256
Apr 14 16:16:59 myserver sm-mta[37463]: v3EEGxQi037463: from=<moi@myserver.mydomain.net>, size=383, class=0, nrcpts=1, msgid=<201704141416.v3EEGx4r037462@myserver.mydomain.net>, proto=ESMTPS, daemon=IPv4, relay=localhost [127.0.0.1]
Apr 14 16:16:59 myserver sendmail[37462]: v3EEGx4r037462: to=messagerie@test.fr, ctladdr=moi (1000/0), delay=00:00:00, xdelay=00:00:00, mailer=relay, pri=30053, relay=[127.0.0.1] [127.0.0.1], dsn=2.0.0, stat=Sent (v3EEGxQi037463 Message accepted for delivery)
Apr 14 16:17:00 myserver sm-mta[37465]: v3EEGxQi037463: to=<messagerie@test.fr>, ctladdr=<moi@myserver.mydomain.net> (1000/0), delay=00:00:01, xdelay=00:00:01, mailer=relay, pri=30383, relay=smtp.orange.fr. [x.x.x.x], dsn=2.0.0, stat=Sent (8EGz1v00h4tU8mL03EGzx4 mail accepted for delivery)

Le relai de messagerie d’Orange a bien pris en compte l’envoi de l’email. Reste à vérifier depuis le client de messagerie distant la bonne réception de cet email. L’entête du message permet de suivre son cheminement :

...
Received: from smtp.smtpout.orange.fr (smtp08.smtpout.orange.fr [x.x.x.x])
    by in12.mail.test.fr (Postfix) with ESMTPS id 4C012FC3
    for <messagerie@test.fr>; Fri, 14 Apr 2017 16:17:00 +0200 (CEST)
Received: from myserver.mydomain.net ([x.x.x.x])
    by mwinf5d68 with ME
    id 8EGz1v00h4tU8mL03EGzx4; Fri, 14 Apr 2017 16:17:00 +0200
...

Si jamais vous avez des questions ou besoin de plus de détails sur la configuration mise en place , nécessitez pas à me les poser via un commentaire.

 

Création des dépôts locaux dans Oracle Linux 7

Création des dépôts locaux dans Oracle Linux 7

Pour changer un peu, je vous propose un petit article autour d’Oracle Linux. Je décris rapidement la création des dépôts locaux (local yum repository) pour Oracle Linux 7.

Je dispose au préalable d’un système enregistré Unbreakable Linux Network (ULN) et connecté (utile pour télécharger les paquets). La liste des dépôts enregistrés sur ce système est la suivante :

[root@droopy ~]# yum repolist
Loaded plugins: ulninfo
repo id                       repo name                                                                                       status
ol7_Dtrace_userspace/x86_64   Oracle Linux 7Server Dtrace Userspace Tools (x86_64) - Latest                                       10
ol7_UEKR4/x86_64              Unbreakable Enterprise Kernel Release 4 for Oracle Linux 7Server (x86_64) - Latest                 189
ol7_addons/x86_64             Oracle Linux 7Server Add ons (x86_64)                                                              135
ol7_internal                  Oracle Linux 7Server Internal Mirror                                                                 6
ol7_ksplice/x86_64            Ksplice for Oracle Linux 7Server (x86_64)                                                        1,377
ol7_latest/x86_64             Oracle Linux 7Server Latest (x86_64)                                                            13,745
ol7_optional_latest/x86_64    Oracle Linux 7Server Latest Optional Packages (x86_64)                                          10,422
ol7_userspace_ksplice/x86_64  Latest packages for Ksplice aware userspace packages for Oracle Linux 7Server (x86_64)             151
repolist: 26,035

Même si je dispose d’un système Oracle Linux enregistré (ULN), j’utilise une méthode différente pour créer / utiliser les dépôts que celle décrite dans cet article.

Pour ce faire, il faut au préalable installer les utilitaires relatifs à la gestion des dépôts :

[root@droopy ~]# yum install yum-utils createrepo
Loaded plugins: ulninfo
Package yum-utils-1.1.31-40.el7.noarch already installed and latest version
Package createrepo-0.9.9-26.el7.noarch already installed and latest version
Nothing to do

Dans cet exemple, les dépôts sont créés dans l’arborescence suivante :

[root@droopy yum]# mkdir -p /var/www/html/yum

Pour synchroniser les dépôts, j’utilise la syntaxe suivante :

[root@droopy yum]# /usr/bin/reposync --newest-only --repoid=ol7_latest -p /var/www/html/yum
No Presto metadata available for ol7_latest
(1/4917): 389-ds-base-libs-1.3.5.10-11.el7.x86_64.rpm                     | 663 kB  00:00:02     
(2/4917): ElectricFence-2.2.2-39.el7.i686.rpm                             |  34 kB  00:00:00 
[...]

Cette opération est à effectuer pour l’ensemble des dépôts que vous souhaitez synchroniser en local. Vous pouvez parc exemple utiliser la syntaxe suivante pour synchroniser directement plusieurs dépôts de paquets :

[root@droopy ~]# /usr/bin/reposync --newest-only --repoid=ol7_latest \
--repoid=ol7_UEKR4 --repoid=ol7_addons --repoid=ol7_ksplice \
-p /var/www/html/yum
[...]

Une fois que tous les paquets de chaque dépôts sont disponibles localement (sur votre serveur), il est nécessaire de créer les références des dépôts via la commande suivante :

[root@droopy ~]# /usr/bin/createrepo /var/www/html/yum/ol7_latest
Saving Primary metadata
Saving file lists metadata
Saving other metadata
Generating sqlite DBs
Sqlite DBs complete

Les informations concernant le dépôts sont disponibles ici :

[root@droopy ~]# ls -l /var/www/html/yum/ol7_latest/repodata
total 15376
-rw-r--r--. 1 root root 3615937 Dec  5 19:40 00aa865b08e7688b1963502040af6673808e75d4d61e7b9ff0b8994c6dc796f8-filelists.sqlite.bz2
-rw-r--r--. 1 root root 1068542 Dec  5 19:40 043ede1cdeed2a584bc4de6f95ca1421f783f8d0651a52d87d5fec4499b4375b-other.xml.gz
-rw-r--r--. 1 root root 1578249 Dec  5 19:40 3191b278e3b5f2add275a823f682a2725f95eabd1debb6047c8199823a637460-other.sqlite.bz2
-rw-r--r--. 1 root root 1903473 Dec  5 19:40 394a69663abaf011f4092d2282b5f8a905f8a62199f7f8a1e0c3d1226b1722f0-primary.xml.gz
-rw-r--r--. 1 root root 4152624 Dec  5 19:40 6a7c6b2e9efcc321dff0a6f73ce8e9bb6979e9b438a36b6813ecf219c5d40471-primary.sqlite.bz2
-rw-r--r--. 1 root root 3413472 Dec  5 19:40 75905ac43d07849dc8369c18139857e6f33145919e614678e2e2c76f0fc017d6-filelists.xml.gz
-rw-r--r--. 1 root root    3010 Dec  5 19:40 repomd.xml

Notez que cette opérations est à répéter pour l’ensemble de vos dépôts.

Maintenant que ces dépôts sont disponibles localement sur votre serveur, il est intéressant de les rendre accessibles aux autres serveurs de votre réseau. Le plus simple est d’utiliser le protocole http (donc un serveur web) pour partager ces paquets.

On installe d’abord le serveur web (ici apache) :

[root@droopy ~]# yum install httpd
Loaded plugins: ulninfo
Resolving Dependencies
--> Running transaction check
---> Package httpd.x86_64 0:2.4.6-45.0.1.el7 will be installed
--> Processing Dependency: httpd-tools = 2.4.6-45.0.1.el7 for package: httpd-2.4.6-45.0.1.el7.x86_64
--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-45.0.1.el7.x86_64
--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-45.0.1.el7.x86_64
--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-45.0.1.el7.x86_64
--> Running transaction check

[...]
Complete!

Il faut éditer la configuration du serveur apache notamment pour modifier le paramètre « ServerName ».

ServerName droopy.homeunix.org:80

Si comme moi, SELinux et le firewall sont toujours activés, n’oubliez pas de saisir les commandes suivantes :

[root@droopy ~]# /usr/sbin/semanage fcontext -a -t httpd_sys_content_t "/var/www/html/yum(/.*)?"
[root@droopy ~]# /sbin/restorecon -R -v /var/yum
[root@droopy ~]# firewall-cmd --add-service=http
[root@droopy ~]# firewall-cmd --permanent --add-service=http

Il reste plus qu’à activer le serveur web :

[root@droopy ~]# systemctl start httpd
[root@droopy ~]# systemctl enable httpd

Pour vérifier il suffit de tester le téléchargement d’un paquet depuis un autre serveur :

[root@snoopy ~]# wget http://droopy.homeunix.org/yum/ol7_latest/wget-1.14-13.el7.x86_64.rpm 
--2016-12-05 20:01:32--  http://droopy.homeunix.org/yum/ol7_latest/wget-1.14-13.el7.x86_64.rpm
Connecting to droopy.homeunix.org:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 556936 (544K) [application/x-rpm]
Saving to: ‘wget-1.14-13.el7.x86_64.rpm’

100%[=================================================================================>] 556,936     --.-K/s   in 0.003s  

2016-12-05 20:01:32 (192 MB/s) - ‘wget-1.14-13.el7.x86_64.rpm’ saved [556936/556936]

Vous pouvez maintenant mettre à jour le fichier de références de vos dépôts sur chaque client afin d’accéder à tous vos paquets.

[local_ol7_latest]
name=Oracle Linux $releasever Latest ($basearch)
baseurl=http://droopy.homeunix.org/repo/OracleLinux/OL7/latest/$basearch/
gpgkey=http://droopy.homeunix.org/RPM-GPG-KEY-oracle-ol7
gpgcheck=1
enabled=1

N’oubliez pas au préalable de copier la clé suivante sur votre serveur web :

[root@droopy ~]# cp -pr /etc/pki/rpm-gpg/RPM-GPG-KEY-oracle /var/www/html

Voilà rien de plus simple.

Panic  lors de l’installation d’Oracle RAC 12c sous Solaris (analyse)

Panic lors de l’installation d’Oracle RAC 12c sous Solaris (analyse)

Lors de l’installation d’Oracle RAC 12c sous Solaris, j’ai rencontré quelques petits soucis. A travers cet article, je vais expliquer la démarche que j’ai suivi pour diagnostiquer cet incident.

Le contexte est un peu particulier : j’utilise 2 VMs VirtualBox sous Solaris 11.3 pour les serveurs Oracle ainsi que l’image VirtualBox ZFS Appliance pour distribuer le stockage entre ces deux VMs (via le protocole iSCSI). La démarche d’analyse est beaucoup plus intéressante que le contexte. Ne vous focalisez pas dessus (pour le moment).

L’incident se produit de la manière suivante : le premier serveur du cluster Oracle RAC « panic » lors de l’exécution du script root.sh. Pour rappel ce script permet la configuration du cluster Oracle RAC.

L’analyse débute ci-dessous. Notez que j’utilise Solaris CAT.

CAT(/var/crash/2/vmcore.2/11X)> panic
panic on CPU 0
panic string:   forced crash dump initiated at user request
==== panic user (LWP_SYS) thread: 0xffffa10016511500  PID: 11187  on CPU: 0 ====
cmd: /u01/app/12.1.0/grid/bin/cssdagent
fmri: svc:/network/ssh:default
t_procp: 0xffffa1001837e300
   p_as: 0xffffa10019170900  size: 126853120  RSS: 28393472
      a_hat: 0xffffa10018c3a048
    cpuset: 0
   p_zone: 0xfffffffffc285c70 (global)
t_stk: 0xfffffffc8340cf00  sp: 0xfffffffc8340cd30  t_stkbase: 0xfffffffc83408000
t_pri: 110 (RT)  pctcpu: 0.001949
t_transience: 0  t_wkld_flags: 0
t_lwp: 0xffffa10019560100  t_tid: 15
   lwp_regs: 0xfffffffc8340cf00
   lwp_ap:   0xfffffffc8340cf10
   t_mstate: LMS_SYSTEM  ms_prev: LMS_USER
   ms_state_start: 0.000009355 seconds earlier
   ms_start: 1 minutes 10.879644595 seconds earlier
t_cpupart: 0xfffffffffc0e25d0(0)  last CPU: 0
idle: 800170590 hrticks (0.800170590s)
start: Mon Nov  7 12:16:10 2016
age: 71 seconds (1 minutes 11 seconds)
t_state:     TS_ONPROC
t_flag:      0x1800 (T_PANIC|T_LWPREUSE)
t_proc_flag: 0x100 (TP_MSACCT)
t_schedflag: 0x8003 (TS_LOAD|TS_DONT_SWAP) (missed bits 0x8000)
t_acflag:    3 (TA_NO_PROCESS_LOCK|TA_BATCH_TICKS)
p_flag:      0x4a004000 (SEXECED|SMSACCT|SAUTOLPG|SMSFORK)

pc:      unix:vpanic_common+0x13a:  addq   $0xf0,%rsp

unix:vpanic_common+0x13a()
unix:0xfffffffffb8a4810()
int genunix:kadmin+0x2b6((int)5, (int)1, (void *)0, (cred_t *)0xffffa10010f69558)
int genunix:uadmin+0x179((int)5, (int)1, (uintptr_t)0)
unix:_syscall_invoke+0x30()
-- switch to user thread's user stack --

Le « panic » est provoqué par le processus « cssdagent » via la commande Unix « uadmin ».

Après consultation de la documentation, le deamon « cssdagent » est en charge de vérifier l’état du cluster (voir deamons cssd) et fournit spécifiquement le service d’I/O fencing. En cas d’échec du deamon « ocssd.bin » (ou de ses agents cssdmonitor et cssdagent), le serveur effectue un « panic ».

Il est intéressant de voir l’avant dernier thread exécuté sur le serveur avant ce panic.

CAT(/var/crash/2/vmcore.2/11X)> sdump 0xffffa10016511500 kthread_t t_cpu 
   struct cpu *t_cpu = 0xfffffffffc0849e0 (unix(data):cpus+0)

CAT(/var/crash/2/vmcore.2/11X)> sdump 0xfffffffffc0849e0 cpu_t cpu_intr_thread
   kthread_t *cpu_intr_thread = 0xfffffffc800b9b40

CAT(/var/crash/2/vmcore.2/11X)> thread 0xfffffffc800b9b40
==== free thread: 0xfffffffc800b9b40  PID: 0  affinity CPU: 0  PIL: 2 ====
cmd: sched(unix:thread_create_intr)
kname: thread_create_intr
t_procp: 0xfffffffffc063270 (proc_sched)
   p_as: 0xfffffffffc064750 (kas)
   p_zone: 0xfffffffffc285c70 (global)
t_stk: 0xfffffffc800b9b30  sp: 0xfffffffc800b9a60  t_stkbase: 0xfffffffc800b3000
t_pri: 161 (SYS)  pctcpu: 15.889231
t_transience: 0  t_wkld_flags: 0
t_lwp: 0xffffa1001863a0c0
   lwp_regs: 0xfffffffc81729f00
   lwp_ap:   0xfffffffc81729f10
t_cpupart: 0xfffffffffc0e25d0(0)  last CPU: 0
idle: 30938061725 hrticks (30.938061725s)
interrupted (pinned) thread: 0xffffa10010eaf280
t_state:     TS_FREE
t_flag:      0x10009 (T_INTR_THREAD|T_TALLOCSTK|T_PUSHPAGE)
t_proc_flag: 0 (none set)
t_schedflag: 0x10003 (TS_LOAD|TS_DONT_SWAP) (missed bits 0x10000)
t_acflag:    4  (missed bits 0x4)
p_flag:      1 (SSYS)

pc:      unix:_resume_from_idle+0x130 resume_return:  addq   $0x8,%rsp

unix:_resume_from_idle+0x130 resume_return()
genunix(data):intr_queue+0()
-- end of free thread's stack --

Il s’agit du thread 0xffffa10010eaf280 (pinned).

CAT(/var/crash/2/vmcore.2/11X)> thread 0xffffa10010eaf280
==== user (LWP_SYS) thread: 0xffffa10010eaf280  PID: 11189 ====
cmd: /u01/app/12.1.0/grid/bin/ocssd.bin 
fmri: svc:/network/ssh:default
t_procp: 0xffffa1001837d2a0
   p_as: 0xffffa10019170040  size: 211288064  RSS: 63078400
      a_hat: 0xffffa10019d394a0
   p_zone: 0xfffffffffc285c70 (global)
t_stk: 0xfffffffc81729f00  sp: 0xfffffffc81729d40  t_stkbase: 0xfffffffc81725000
t_pri: 110 (RT)  pctcpu: 75.408707
t_transience: 0  t_wkld_flags: 0
t_lwp: 0xffffa1001863a0c0  t_tid: 13
   lwp_regs: 0xfffffffc81729f00
   lwp_ap:   0xfffffffc81729f10
   t_mstate: LMS_TRAP  ms_prev: LMS_USER
   ms_state_start: 0.000405357 seconds earlier
   ms_start: 1 minutes 11.314553986 seconds earlier
t_cpupart: 0xfffffffffc0e25d0(0)  last CPU: 0
idle: 405315 hrticks (0.000405315s)
start: Mon Nov  7 12:16:10 2016
age: 71 seconds (1 minutes 11 seconds)
t_waitrq: 0.000405315 seconds
t_state:     TS_RUN
t_flag:      0x1000 (T_LWPREUSE)
t_proc_flag: 0x100 (TP_MSACCT)
t_schedflag: 0x8013 (TS_LOAD|TS_DONT_SWAP|TS_SIGNALLED) (missed bits 0x8000)
t_acflag:    3 (TA_NO_PROCESS_LOCK|TA_BATCH_TICKS)
p_flag:      0x5a004000 (SEXECED|SMSACCT|SAUTOLPG|SNOCD|SMSFORK)

pc:      unix:_resume_from_idle+0x130 resume_return:  addq   $0x8,%rsp

unix:_resume_from_idle+0x130 resume_return()
unix:swtch - frame recycled
void unix:preempt+0xcb()
boolean_t unix:kpreempt+0x8e((int)0xffffffff)
int genunix:new_mstate+0x178((kthread_t *)0xffffa10010eaf280, (int)2)
void unix:trap+0x1ae((struct regs *)0xfffffffc81729f00, (caddr_t)0, (processorid_t)0)
-- trap data  rp: 0xfffffffc81729ed0
  trapno       0 (Divide error)
  %rfl         0 ()
  savfp 0xffff80ffbdb9a3a0
  savpc 0xffff80ffbdb9a388 (invalid text addr)

  %rbp                   2  %rsp                   0
  %rip  0x4b (invalid text addr)

  0%rdi 0xffff80ffbdb9a380  1%rsi 0xfffffffc81729f00  2%rdx 0xfffffffc81729f00
  3%rcx 0xfffffffffb800a47  4%r8                   0  5%r9  0xffff80ffadd4ea20

  %rax  0xffff80ffbdb9a820  %rbx           0x1a17090
  %r10            0xda94f8  %r11  0xffff80ffae1218c0  %r12               0x8c9
  %r13                   0  %r14  0xffff80ffbdb9a380  %r15  0xffff80ffbdb9a8c0

  %cs       0x4b (UCS_SEL)        %ds   0xffff80ffbdb9a388 (GDT unknown,KPL)
  %es   0xffff80ffbdb9a3a0 (GDT unknown,KPL)      %ss      0x400 (GDT unknown,KPL)
  %fs          0 (KFS_SEL)        %gs   0xdbb2b0 (GDT unknown,KPL)
  fsbase 0xff80ffbdb9a3a0ff
  gsbase 0xff80ffbdb9a3a0ff
-- error reading next frame @ 0xffff80ffbdb9a3a0 --

Ce qui est intéressant c’est qu’avant le panic du serveur, le dernier processus en cours d’exécution est le deamon « ocssd.bin ».

CAT(/var/crash/2/vmcore.2/11X)> proc 0xffffa1001837d2a0
       addr         PID    PPID   RUID/UID     size      RSS     swresv  lwpcnt command
================== ====== ====== ========== ========== ======== ======== ====== =====
0xffffa1001837d2a0  11189      1      54322  211288064 63078400 59850752     28 /u01/app/12.1.0/grid/bin/ocssd.bin 
        thread: 0xffffa1001111fb00  state: slp   wchan: 0xffffa1001111fcee  sobj: condition var (from genunix:lwp_park+0x157)
        thread: 0xffffa1000683d940  state: run   wchan:               NULL  sobj: none
        thread: 0xffffa10011015680  state: run   wchan:               NULL  sobj: none
        thread: 0xffffa100164dde00  state: slp   wchan: 0xffffa1001827770c  sobj: condition var (from portfs:port_getn+0x240)
        thread: 0xffffa100164f7dc0  state: slp   wchan: 0xffffa100182746ec  sobj: condition var (from portfs:port_getn+0x240)
        thread: 0xffffa100121e7480  state: slp   wchan: 0xffffa100121e766e  sobj: condition var (from genunix:lwp_park+0x157)
        thread: 0xffffa100121e3980  state: slp   wchan: 0xffffa100189656a4  sobj: condition var (from portfs:port_getn+0x240)
        thread: 0xffffa10010eb4480  state: slp   wchan: 0xffffa10018960dac  sobj: condition var (from portfs:port_getn+0x240)
        thread: 0xffffa100121e54c0  state: slp   wchan: 0xffffa100121e56ae  sobj: condition var (from genunix:lwp_park+0x157)
        thread: 0xffffa100164f5500  state: slp   wchan: 0xffffa100164f56ee  sobj: condition var (from genunix:lwp_park+0x157)
        thread: 0xffffa100164f8240  state: slp   wchan: 0xffffa100183886bc  sobj: condition var (from portfs:port_getn+0x240)
        thread: 0xffffa100164dd080  state: slp   wchan: 0xffffa100164dd26e  sobj: condition var (from genunix:lwp_park+0x157)
        thread: 0xffffa10010eaf280  state: run   wchan:               NULL  sobj: none
        thread: 0xffffa1001055cb40  state: slp   wchan: 0xffffa1001055cd2e  sobj: condition var (from genunix:lwp_park+0x157)
        thread: 0xffffa100121dab00  state: slp   wchan: 0xffffa100121dacee  sobj: condition var (from genunix:lwp_park+0x157)
        thread: 0xffffa100121e2240  state: slp   wchan: 0xffffa100121e242e  sobj: condition var (from genunix:lwp_park+0x157)
        thread: 0xffffa100121e7000  state: slp   wchan: 0xffffa1001917004a  sobj: condition var (from kaio:aio_cleanup_thread+0x1c2)
        thread: 0xffffa1001055bdc0  state: run   wchan:               NULL  sobj: none
        thread: 0xffffa1001621a200  state: run   wchan:               NULL  sobj: none
        thread: 0xffffa100164e0240  state: slp   wchan: 0xffffa10017d0fe58  sobj: semaphore (from genunix:biowait+0x7a)
        thread: 0xffffa100164ed000  state: run   wchan:               NULL  sobj: none
        thread: 0xffffa100164dd500  state: slp   wchan: 0xffffa10017d0ff50  sobj: semaphore (from genunix:biowait+0x7a)
        thread: 0xffffa100164f0280  state: run   wchan:               NULL  sobj: none
        thread: 0xffffa100164eab80  state: slp   wchan: 0xffffa100164ead6e  sobj: condition var (from genunix:lwp_park+0x157)
        thread: 0xffffa100164ec240  state: slp   wchan: 0xffffa100164ec42e  sobj: condition var (from genunix:lwp_park+0x157)
        thread: 0xffffa100164e6b40  state: slp   wchan: 0xffffa100164e6d2e  sobj: condition var (from genunix:lwp_park+0x157)
        thread: 0xffffa100164ecb40  state: slp   wchan: 0xffffa10018947af4  sobj: condition var (from portfs:port_getn+0x240)
        thread: 0xffffa100164f5080  state: run   wchan:               NULL  sobj: none

Une information importante apparait à l’affichage des thread liés au processus « ocssd.bin » : 2 thread sont en attente d’I/O (biowait). L’analyse des attentes I/O est la suivante :

CAT(/var/crash/2/vmcore.2/11X)> tlist -b 0xffffa100164e0240 biowait
thread: 0xffffa100164e0240  state: slp
  PID: 11189  cmd: /u01/app/12.1.0/grid/bin/ocssd.bin 
  idle: 28810211744 hrticks (28.810211744s)
buf @ 0xffffa10017d0fd98
   b_edev:   212,320(sd5,0)     b_blkno:   0x80011
   b_flags:  0x2200121 (BUSY|PHYS|WRITE|SHADOW|STARTED|PAGE_NOWAIT)
   b_addr:   0x1fb0000
   b_bcount: 512                b_bufsize: 0
   b_dip:    0xffffa1000761f6c8 sd#5 //P/XZ%@g600144f0908f3f600000581cac750001
   b_shadow: 0xffffa10019e47f80 (struct page **)
thread: 0xffffa100164dd500  state: slp
  PID: 11189  cmd: /u01/app/12.1.0/grid/bin/ocssd.bin 
  idle: 28810195310 hrticks (28.810195310s)
buf @ 0xffffa10017d0fe90
   b_edev:   212,320(sd5,0)     b_blkno:   0x80004
   b_flags:  0x2200061 (BUSY|PHYS|READ|SHADOW|STARTED|PAGE_NOWAIT)
   b_addr:   0x1fafa00
   b_bcount: 512                b_bufsize: 0
   b_dip:    0xffffa1000761f6c8 sd#5 //P/XZ%@g600144f0908f3f600000581cac750001
   b_shadow: 0xffffa10018c4ad70 (struct page **)                                                                            
  2 matching threads found
    in biowait()
threads in biowait() by device:

count   device (thread: max idle time)
    2   212,320(sd5,0) (0xffffa100164e0240: 1 hours 28 minutes 58.329491622 seconds)

L’analyse des thread en attente d’I/O révèle les informations suivantes :

  • Les thread sont bloqués depuis plus de 28 secondes (sémaphore)
  • Les thread sont bloqués sur le même device sd#5

Les informations sur le device sd#5 sont les suivantes.

sd5 @ 0xffffa10003566080(sd_lun)
    //P/XZ%@g600144f0908f3f600000581cac750001
    0xffffa1000761f6c8   name: scsiclass,00@g600144f0908f3f600000581cac750001   instance #: 5
      scsi device @ 0xffffa10010257298  hba_tran: 0xffffa10000088640
      target: 29336  lun: 37  sub_lun: 16 
      scsi inquiry data @ 0xffffa10010257658 :
        dtype: 0  qualifier: 0  removable: 0  
        ANSI version: 5  ECMA version: 0  ISO version: 0  length: 69 
        response format: 2  TERM I/O Proc msg: 0  async event notification: 0 
        scsi support:  
          soft rst: 0  cmdque: 1  linked cmds: 0  sync xfer: 0
          16 bit xfers: 0  32 bit xfers: 0  relative addr: 0 
        vendor id: SUN       product id: Sun Storage 7000
        revision: 1.0   serial #: 
      sd_lun @ 0xffffa10003566080, un_sd: 0xffffa10010257298
        throttle: 256, saved_throttle: 256, busy_throttle: 0

        un_rqs_bp: 0x0, un_rqs_pktp: 0x0 un_sense_isbusy: 0
        Last Request Sense Packet (using un_rqs_pktp):
        un_ncmds_in_driver: 2, un_ncmds_in_transport: 2
        open counts:
          layered (none)
          regular(char):  1
        Geometry is NOT valid
        Packet Flags for Tagged Queueing:
        FLAG_STAG - Run command as SIMPLE QUEUE tagged cmd
        Last pkt reason:
        CMD_CMPLT - no transport errors- normal completion

        State:
        SD_STATE_NORMAL
        Last state:
        SD_STATE_NORMAL
        SCSI State Change Translation: 
            No state change

        Reservation status:
        SD_RELEASE
[...]

Petit récapitulatif des informations collectées :

  1. Le « panic » a été provoqué par le « deamon cssdagent » (avec la commande uadmin)
  2. Le dernier processus actif avant le « panic » était le deamon « ocssd.bin »
  3. Le deamon « ocssd.bin » a 2 thread bloqués (+ 28 secondes) sur le device sd#5
  4. L’analyse du device sd#5 illustre deux commandes dans la queue d’exécution

 

Le fonctionnement du cluster Oracle RAC est le suivant : si un des serveurs du cluster n’accède plus au disque de vote pendant plus de 27 secondes (valeur de misscount, par défaut de 30 secondes, moins 3 secondes pour le temps du redémarrage) alors le mécanisme du cluster évacue ce serveur afin de garantir l’intégrité du système complet.

Dans notre cas le deamon « ocssd.bin » est en attente d’accès au disque de vote (sd#5) depuis plus de 28 secondes. Ce qui explique le panic du serveur.

Je reviendrai dans un prochain article pour décrire la suite de l’analyse.

 

Hack : Oracle ZFS Storage Appliance Simulator

Hack : Oracle ZFS Storage Appliance Simulator

Afin de vous familiariser avec son appliance de stockage nommée « ZFS Storage Appliance » Oracle vous propose un simulateur disponible pour VirtualBox et VMware. Le guide disponible ici, vous explique les différentes étapes pour l’activation de ce simulateur.

Le Hack concerne l’image sous VirtualBox : le but est d’agrandir l’espace de stockage du simulateur. Et pourquoi faire ? En fait, j’utilise ce simulateur pour différents besoins, du coup, la taille du stockage initiale est trop restreinte pour mes tests.

Par défaut, l’image utilise 16 disques (1 disque système et 15 disques pour le pool de données).

$ VBoxManage showvminfo <vmname>
[...]
SATA Controller (0, 0): /vbox/.../Oracle_ZFS_Storage-disk1.vmdk (UUID: c1110397-3ea2-46d2-88e8-8d8def9d2280)
SATA Controller (1, 0): /vbox/.../Oracle_ZFS_Storage-disk2.vmdk (UUID: 2de21b8d-f4d7-45ca-980d-c06d9f62f225)
SATA Controller (2, 0): /vbox/.../Oracle_ZFS_Storage-disk3.vmdk (UUID: dc95a562-5c28-4bd9-86a7-60773760305a)
[...]
SATA Controller (14, 0): /vbox/.../Oracle_ZFS_Storage-disk15.vmdk (UUID: 0e404d99-8995-4c4d-a433-f7477c92b8d7)
SATA Controller (15, 0): /vbox/.../Oracle_ZFS_Storage-disk16.vmdk (UUID: 5334b239-bde0-4d6a-a453-c315b1cd0137)
[...]

Le premier disque est utilisé par le système. Sa taille maximale est de 50 Go. Il n’y a pas de raison pour modifier ce disque.

$ VBoxManage showmediuminfo disk c1110397-3ea2-46d2-88e8-8d8def9d2280 
UUID:           c1110397-3ea2-46d2-88e8-8d8def9d2280
Parent UUID:    base
State:          created
Type:           normal (base)
Location:       /vbox/.../Oracle_ZFS_Storage-disk1.vmdk
Storage format: VMDK
Format variant: dynamic default
Capacity:       51200 MBytes
Size on disk:   5971 MBytes
Encryption:     disabled
In use by VMs:  zfssa (UUID: eb0ba008-8a6a-441f-b94d-fed79cc8c622)

Tous les autres disques de l’image sont à utiliser pour le pool de données (le pool ZFS que vous devez créer par la suite). Chaque disque a une taille de 5 Go maximale.

$ VBoxManage showmediuminfo disk 2de21b8d-f4d7-45ca-980d-c06d9f62f225
UUID:           2de21b8d-f4d7-45ca-980d-c06d9f62f225
Parent UUID:    base
State:          created
Type:           normal (base)
Location:       /vbox/.../Oracle_ZFS_Storage-disk2.vmdk
Storage format: VMDK
Format variant: dynamic default
Capacity:       5120 MBytes
Size on disk:   3863 MBytes
Encryption:     disabled
In use by VMs:  zfssa (UUID: eb0ba008-8a6a-441f-b94d-fed79cc8c622)

Selon la redondance du pool, la taille de celui-ci peut varier. S’agissant d’un simulateur, je vous conseille d’utiliser la redondance vous offrant le plus grand espace de stockage possible (il ‘agit de la redondance dite striped).

screen-shot-2016-11-02-at-20-42-29

La taille maximale du pool de données avec une redondance striped est d’environ 73 Go. On risque pas de jouer longtemps !?

Pour agrandir cette espace de stockage, il vous suffit d’effectuer les opérations suivantes après l’import de l’image et avant son activation :

  1. Détacher les disques de l’image existante
  2. Supprimer les disques détachés
  3. Créer des nouveaux disques (de la même taille)
  4. Attacher ces disques à l’image existante

 

Etape 1 : on détache les anciens disques de l’image existante

$ for i in {1..15}
do
VBoxManage storageattach <vmname> --storagectl "SATA Controller" --device 0 --port ${i} --type hdd --medium none
done

Etape 2 : on supprime les disques détachés

$ for i in {2..16}
do
UUID=`VBoxManage showmediuminfo /vbox/.../Oracle_ZFS_Storage-disk${i}.vmdk | head -1 | awk '{print $2}'`
VBoxManage closemedium disk ${UUID} --delete
done

Etape 3 : on crée des nouveaux disques (je double la taille de 5 Go à 10 Go par disque)

$ for i in {2..16}
do
VBoxManage createmedium disk --filename /vbox/.../Oracle_ZFS_Storage-disk${i}.vdi --size=10240 --variant Standard
done

Etape 4 : on attache ces nouveaux disques à l’image existante

$ for i in {1..15}
do
VBoxManage storageattach storage --storagectl "SATA Controller" --device 0 --port ${i} --type hdd --medium /vbox/.../Oracle_ZFS_Storage-disk$((1+$i)).vdi
done

Vous pouvez maintenant activer l’image afin d’effectuer les configurations nécessaires pour utiliser le simulateur.

screen-shot-2016-11-02-at-22-24-24

Comme vous pouvez le voir au-dessus, en doublant la taille des disques, nous avons à notre disposition un simulateur « ZFS Storage Appliance » un peu plus capacitif. A votre loisir de définir la taille maximale de votre image.

Utilisez des adresses SCAN sans DNS

Utilisez des adresses SCAN sans DNS

L’installation par défaut d’une couche Grid Infrastructure nécessite un certain nombre d’adresses IP (avec résolution) pour notamment l’utilisation de la fonctionnalité SCAN. Par exemple si vous utilisez deux instances systèmes pour construire une couche Grid Infrastructure, vous devez réserver au moins neuf adresses IP différentes avec des noms associés.

Explication :

  • 1 @ IP + 1 nom pour l’instance système 1 dans le réseau dit publique
  • 1 @IP + 1 nom pour l’instance système 2 dans le réseau dit publique
  • 1 @IP + 1 nom pour l’instance système 1 dans le réseau dit privé
  • 1 @IP + 1 nom pour l’instance système 2 dans le réseau dit privé
  • 1 @IP + 1 nom pour l’instance système 1 dans le réseau dit publique (VIP)
  • 1 @IP + 1 nom pour l’instance système 2 dans le réseau dit publique (VIP)
  • 3 @IP + 1 nom dans le réseau dit publique (SCAN)

Ces couples « adresses IP + noms » sont « normalement » enregistrés dans un service DNS (ce n’est pas obligatoire pour le réseau dit privé). Vous pouvez néanmoins vous passez d’un service DNS en spécifiant l’ensemble de ces adresses IP + ces noms dans le fichier hosts de chaque instance système où vous souhaitez déployer la couche Grid Infrastructure.

Ci-dessous un exemple d’entrées d’un fichier hosts pour l’installation d’une couche Grid Infrastructure sur deux instances systèmes.

#-- Nodes --#

# Public network
192.168.10.5 rac1
192.168.10.6 rac2
# Private network
192.168.100.5 rac1-priv
192.168.100.6 rac2-priv

#-- Cluster --#

# VIP address
192.168.10.100 rac1-vip
192.168.10.101 rac2-vip
# SCAN address
192.168.10.102 oraclu01-scan
192.168.10.103 oraclu01-scan
192.168.10.104 oraclu01-scan

Essayez maintenant d’installer une couche Grid Infrastructure en utilisant uniquement une résolution local sans que les enregistrements des couples adresses IP + noms soient indiqués dans le service DNS. Le défi est lancé…

Vous obtiendrez surement ces erreurs dans vos logs d’installation de la couche Grid Infrastructure. Cela fera suite à l’exécution du CVU (Cluster Verify Utility).

INFO: -----------------------------------------------
INFO: Verification Result for Node:rac2
WARNING: Result values are not available for this verification task
INFO: Error Message:PRVG-1101 : SCAN name "oraclu01-scan" failed to resolve
INFO: Cause: An attempt to resolve specified SCAN name to a list of IP addresses failed because SCAN could not be resolved in DNS or GNS using ''nslookup''.
INFO: Action: Check whether the specified SCAN name is correct. If SCAN name should be resolved in DNS, check the configuration of SCAN name in DNS. If it should be resolved in GNS make sure that GNS resource is online.
INFO: Error Message:PRVF-4657 : Name resolution setup check for "oraclu01-scan" (IP address: 192.168.10.102) failed
INFO: Cause: Inconsistent IP address definitions found for the SCAN name identified using DNS and configured name resolution mechanism(s).
INFO: Action: Look up the SCAN name with nslookup, and make sure the returned IP addresses are consistent with those defined in NIS and /etc/hosts as configured in /etc/nsswitch.conf by reconfiguring the latter. Check the Name Service Cache Daemon (/usr/sbin/nscd) by clearing its cache and restarting it.

INFO: Error Message:PRVF-4657 : Name resolution setup check for "oraclu01-scan" (IP address: 192.168.10.103) failed
INFO: Cause: Inconsistent IP address definitions found for the SCAN name identified using DNS and configured name resolution mechanism(s).
INFO: Action: Look up the SCAN name with nslookup, and make sure the returned IP addresses are consistent with those defined in NIS and /etc/hosts as configured in /etc/nsswitch.conf by reconfiguring the latter. Check the Name Service Cache Daemon (/usr/sbin/nscd) by clearing its cache and restarting it.
INFO: Cause: Inconsistent IP address definitions found for the SCAN name identified using DNS and configured name resolution mechanism(s).
INFO: Action: Look up the SCAN name with nslookup, and make sure the returned IP addresses are consistent with those defined in NIS and /etc/hosts as configured in /etc/nsswitch.conf by reconfiguring the latter. Check the Name Service Cache Daemon (/usr/sbin/nscd) by clearing its cache and restarting it.

INFO: Error Message:PRVF-4657 : Name resolution setup check for "oraclu01-scan" (IP address: 192.168.10.104) failed
INFO: Cause: Inconsistent IP address definitions found for the SCAN name identified using DNS and configured name resolution mechanism(s).
INFO: Action: Look up the SCAN name with nslookup, and make sure the returned IP addresses are consistent with those defined in NIS and /etc/hosts as configured in /etc/nsswitch.conf by reconfiguring the latter. Check the Name Service Cache Daemon (/usr/sbin/nscd) by clearing its cache and restarting it.

Etrangement l’utilitaire CVU d’Oracle tente d’obtenir une résolution DNS pour l’enregistrement SCAN (qui lui indiqué en paramètre de l’installation via la GUI ou via un fichier réponse). Que vous ayez configuré ou non un service DNS sur les instances systèmes, les erreurs ci-dessous se produiront.

L’utilitaire CVU exécute toujours une résolution DNS du nom SCAN. Si le nom SCAN est oraclu01-scan, l’utilitaire Oracle exécute la sous-commande suivante.

# /usr/sbin/nslookup oraclu01-scan

La réponse à cet incident est d’utiliser un service DNS avec des enregistrements correctes !? Et vous auriez raison de le faire. Cependant il existe une autre solution basée sur la mise en place d’un script (en lieu et place du binaire nslookup).

Ci-dessous la méthodologie à suivre pour remplacer le binaire nslookup par un script (à faire bien entendu sur toutes les instances systèmes où la couche Grid Infrastructure sera déployée).

# mv /usr/sbin/nslookup /usr/sbin/nslookup.orig
# touch /usr/sbin/nlookup
# chmod +x /usr/sbin/nslookup

Il faut éditer ce nouveau fichier nslookup et y ajouter le contenu ci-desssous en l’adaptant notamment avec vos informations réseaux.

#!/bin/bash

LISTE=$*
HOSTNAME="${@: -1}"

if [[ $HOSTNAME = "oraclu01-scan" ]];
then
    echo "Server:          192.168.112.30"
    echo "Address:         192.168.112.30#53\n"
                        
    echo "Name:     oraclu01-scan"
    echo "Address:  192.168.112.102"
    echo "Name:     oraclu01-scan"
    echo "Address:  192.168.112.103"
    echo "Name:     oraclu01-scan"
    echo "Address:  192.168.112.104"
else
    /usr/sbin/nslookup.orig $LISTE
fi

Cette solution vous permettra ainsi d’installer une couche Grid Infrastructure sans utiliser des enregistrements DNS spécifiques pour l’ensemble des couples adresses IP + noms. Cette solution est viable dans des environnements type « tests d’infrastructure », elle ne l’est certainement pas dans des environnements avec des utilisateurs.

 

Cas pratique de l’audit dans Solaris

Cas pratique de l’audit dans Solaris

Comme évoqué lors de mon précédent article, je vais détailler un cas pratique de configuration de l’audit. Le contexte technique est le suivant : enregistrer l’ensemble des exécutions provenant des utilisateurs. Le système Solaris (11.3) héberge des Zones non  Globales.

La configuration de l’audit dans les Zones non Globales s’effectue de deux manières. Soit la stratégie est opérée par la Zone Globale : la configuration est alors identique à chaque Zone non Globale, les enregistrements d’audit sont disponibles sur la Zone non Globale. Soit la stratégie est opérée pour chaque Zone non Globale : la configuration peut être adaptée à chaque environnement, les enregistrements d’audit sont disponibles sur chacun des environnements.

Un point important à spécifier, si vous exécutez des BrandZ (Solaris 10) sur la Zone Globale, la stratégie opérée par la Zone Globale ne fonctionnera pas pour les BrandZ. Seule la configuration par Zone non Globale fonctionnera dans ce contexte.

Dans ce cas pratique, j’applique la stratégie pour chaque Zone non Globale. Il faut donc ajouter la stratégie suivante sur la Zone Globale du système.

# auditconfig -setpolicy +perzone

Sur chaque Zone non Globale de ce système, le service d’audit doit être activé.

# audit -s
# auditconfig -getcond
audit condition = auditing

Le but est d’enregistrer l’ensemble des exécutions des utilisateurs. Pour obtenir des enregistrements pertinents, il est intéressant d’ajouter la stratégie argv (cela permet d’associer les arguments d’une commande). L’ajout de cette stratégie est à positionner dans chaque Zone non Globale. Sa mise en place dans la Zone Globale peut avoir sont intérêt notamment si certaines commandes (ou connexion) s’exécutent depuis celle-ci via zlogin(1M).

# auditconfig -setpolicy +argv

La stratégie d’audit sur la Zone Globale doit être la suivante.

# auditconfig -getpolicy
configured audit policies = argv,cnt,perzone
active audit policies = argv,cnt,perzone

La stratégie d’audit par Zone non Globale doit être la suivante.

# auditconfig -getpolicy
configured audit policies = argv,cnt
active audit policies = argv,cnt

La classe d’audit gérant les exécutions se nomme ex. Elle prend en compte tous les événements execve(2M) (incluant pfexec(1M) si celui est actif sur votre système).

0x0000000080000000:ex:exec
# auditrecord -c ex

execve
  system call execve               See execve(2)
  event ID    23                   AUE_EXECVE
  class       ps,ex                (0x0000000080100000)
      header
      path
      [attribute]                  omitted on error
      [exec_arguments]             output if argv policy is set
      [exec_environment]           output if arge policy is set
      subject
      [use_of_privilege]
      return

pfexec
  system call pfexec               See execve(2) with pfexec enabled
  event ID    116                  AUE_PFEXEC
  class       ps,ex,ua,as          (0x0000000080160000)
      header
      path                         pathname of the executable
      path                         pathname of working directory
      [privilege]                  privileges if the limit or inheritable                                     set are changed
      [privilege]                  privileges if the limit or inheritable
                                   set are changed
      [process]                    process if ruid, euid, rgid or egid is
                                   changed
      exec_arguments
      [exec_environment]           output if arge policy is set
      subject
      [use_of_privilege]
      return

On associe la classe d’audit « ex » à la classe d’audit « lo » (gestion des connexions utilisateurs) aussi bien pour les événements provenants d’utilisateurs que des événements provenant du système (événements attribuables et non-attribuables).

# auditconfig -setflags lo,ex
user default audit flags = ex,lo(0x80001000,0x80001000)

# auditconfig -setnaflags lo,ex
non-attributable audit flags = ex,lo(0x80001000,0x80001000)

Les classes d’audit activées sur la Zone Globale sont les suivantes.

# auditconfig -getnaflags -getflags
active non-attributable audit flags = ex,lo(0x80001000,0x80001000)
configured non-attributable audit flags = ex,lo(0x80001000,0x80001000)
active user default audit flags = ex,lo(0x80001000,0x80001000)
configured user default audit flags = ex,lo(0x80001000,0x80001000)

Les classes d’audit activées sur chaque Zone non Globale sont les suivantes.

# auditconfig -getnaflags -getflags
active non-attributable audit flags = ex,lo(0x80001000,0x80001000)
configured non-attributable audit flags = ex,lo(0x80001000,0x80001000)
active user default audit flags = ex,lo(0x80001000,0x80001000)
configured user default audit flags = ex,lo(0x80001000,0x80001000)

Pour appliquer les modifications des classes d’audit, il est nécessaire de l’indiquer au système et d’exécuter les commandes suivantes sur chaque environnement (sur la Zone Globale et sur toutes les Zones non Globales).

# auditconfig -conf
Configured 283 kernel events.

# auditconfig -aconf
Configured non-attributable event mask.

Par défaut, l’ensemble des enregistrements sont écrits via le plugin audit_binfile(5M). Un seul fichier est généré pour l’ensemble des enregistrements. A vous de voir selon votre activité, si vous devez limiter ce fichier selon sa taille ou la périodicité. J’opte souvent pour les deux.

# auditconfig -setplugin audit_binfile p_age=1d

# auditconfig -setplugin audit_binfile p_fsize=512M

# auditconfig -getplugin audit_binfile
Plugin: audit_binfile (active)
        Attributes: p_dir=/var/audit;p_minfree=1;p_fsize=512M;p_age=1d

Cette modification est à faire sur chaque environnement (sur Zone Globale et sur toutes les Zones non Globales). Pensez tout de même à mettre en place une suppression de ces fichiers (une fois qu’ils sont sauvegardés) sinon vous risquez de saturer votre pool ZFS.

# crontab –l root | grep audit
0 5 * * * find /var/share/audit -type f -mtime +4 -exec /usr/bin/rm {} \;

Il vous est maintenant possible de suivre l’activité des utilisateurs sur le(s) système(s). Par exemple, vous pouvez diagnostiquer facilement ce genre d’événement dans votre journal d’audit.

<record version="2" event="execve(2)" host="compile" iso8601="2016-09-04 16:31:31.235 +02:00">
<path>/usr/bin/rm</path>
<attribute mode="100555" uid="root" gid="bin" fsid="65538" nodeid="49437" device="18446744073709551615"/>
<exec_args><arg>rm</arg><arg>/etc/hosts
</arg></exec_args>
<subject audit-uid="bruno" uid="bruno" gid="grpadm" ruid="bruno" rgid="grpadm" pid="1062" sid="3492816039" tid="11705 136704 gw.homeunix.org"/>
<return errval="success" retval="0"/>
</record>

Configuration de l’audit dans Solaris

Configuration de l’audit dans Solaris

L’audit consiste à collecter des données sur l’utilisation des ressources système. Ces données, enregistrées sous forme d’événements, peuvent être utilisées pour déterminer la responsabilité quand aux actions survenues sur ce système.

Il y a un double avantage à activer l’audit sur les systèmes. D’un point de vue sécuritaire, cela ajoute notamment une brique complémentaire à votre « arsenal ». D’un point de vue exploitation, cela permet d’améliorer votre diagnostic, en traçant notamment l’ensemble des actions exécutées sur vos systèmes.

Chez plusieurs clients, l’activation de l’audit m’a permis d’analyser plus efficacement des événements survenus sur des serveurs sur lesquels j’opérais des actions.

Sans être exhaustif, il est important d’évoquer les concepts suivants :

  • La stratégie d’audit détermine les caractéristiques d’enregistrement d’audit,
  • Les événements (d’audit) sont regroupés en classe d’audit,
  • Les enregistrements d’audit sont collectés dans les journaux d’audit,
  • Les classes d’audit peuvent être collecter en cas de réussite, d’échec ou les deux,
  • Les classes d’audit sont modifiables (ajout de préfix par exemple),
  • Des nouvelles classes d’audit peuvent être créées (besoin spécifique),
  • Les événements attribuables proviennent des utilisateurs,
  • Les événements non attribuables proviennent soit du noyau (interruption) soit avant l’authentification d’un utilisateur,
  • Les événements synchrones sont associés à un processus dans le système.

La configuration de l’audit peut s’avérer complexe. C’est pourquoi l’étude de la configuration par défaut permet d’appréhender plus rapidement cette fonctionnalité offerte dans le système Solaris.

Let’s go !!

L’audit est configuré via un service SMF cependant pour piloter ce service il est préférable d’utiliser la commande audit(1M). Par défaut ce service est déjà activé dans Solaris, la commande auditconfig(1M) permet de le vérifier rapidement.

# auditconfig -getcond
audit condition = auditing

Dans le cas contraire, il suffit d’activer le service via la commande audit(1M).

# audit -s

La stratégie d’audit par défaut est « minimale » : afin de minimiser les exigences en matière de stockage et de réduire le nombre de demandes de traitement du système, la plupart des options de la stratégie d’audit ont donc été désactivées. Ce qui peut être judicieux lorsque la disponibilité du système est plus importante que la sécurité (attention votre RSSI dira certainement l’inverse).

# auditconfig -getpolicy
configured audit policies = cnt
active audit policies = cnt

Selon le système installé et vos besoins, la stratégie d’audit devra vraisemblablement  être adaptée. Par exemple dans un environnement exécutant des Zones non Globales (aka containers), il est judicieux de mettre en place une stratégie d’audit permettant d’enregistrer les événements de chaque Zone non Globale. La description des stratégies d’audit est consultable via l’aide mémoire de la commande auditconfig(1M).

Tout comme la stratégie d’audit, il n’y a qu’une seule classe d’audit configurée par défaut. Celle-ci enregistre uniquement les événements liés aux connexions des utilisateurs. Aussi bien pour les événements attribuables…

# auditconfig -getflags
active user default audit flags = lo(0x1000,0x1000)
configured user default audit flags = lo(0x1000,0x1000)

…que pour les événements non attribuables.

# auditconfig -getnaflags
active non-attributable audit flags = lo(0x1000,0x1000)
configured non-attributable audit flags = lo(0x1000,0x1000)

Les programmes pouvant faire l’objet d’un enregistrement liés aux connexions des utilisateurs sont consultables via la commande auditrecord(1M).

# auditrecord -c lo

Admin Server Authentication
  program     admin (various)      See SMC, WBEM, or AdminSuite
  event ID    6213                 AUE_admin_authenticate
  class       lo                   (0x0000000000001000)
      header
      subject
      [text]                       error message
      return
[...]

Il est aussi possible de vérifier à partir d’un programme que celui-ci est bien compris dans une classe d’audit. Par exemple pour vérifier si le programme « su » est lié aux connexions des utilisateurs il suffit saisir la commande suivante et de vérifier la classe d’audit.

# auditrecord -p su

su
  program     /usr/bin/su          See su(1M)
  event ID    6229                 AUE_role_logout
  class       lo                   (0x0000000000001000)
      header
      subject
      return
[...]

Les classes d’audit disponibles par défaut sont consultables directement dans le fichier audit_class. Ci-dessous une liste non exhaustif des classes d’audit configurés sur un système Solaris (version 11.3).

0x0000000000000100:nt:network
0x0000000000000200:ip:ipc
0x0000000000001000:lo:login or logout
0x0000000000008000:cy:cryptographic
0x0000000000100000:ps:process start/stop
0x0000000080000000:ex:exec

Par défaut, les journaux d’audit sont des fichiers binaires stockés sur le serveur (3 modes sont disponibles pour stocker ces journaux d’audit : en local, en remote ou via le service syslog). La configuration des ces 3 modes s’effectuent via les 3 plugins suivants.

# auditconfig -getplugin audit_binfile
Plugin: audit_binfile (active)
        Attributes: p_age=0h;p_dir=/var/audit;p_fsize=0;p_minfree=1

# auditconfig -getplugin audit_syslog
Plugin: audit_syslog (inactive)
        Attributes: p_flags=

# auditconfig -getplugin audit_remote
Plugin: audit_remote (inactive)
        Attributes: p_hosts=;p_retries=3;p_timeout=5

L’analyse des journaux d’audit (dans le cas de fichiers binaires) s’effectue via la commande praudit(1M) qu’il est judicieux de coupler avec la commande auditreduce(1M).

Par exemple, les informations concernant l’enregistrement d’une tentative de connexion root (via le programme su) sont les suivantes.

header,69,2,su,,compile,2016-08-29 18:27:57.063 +02:00
subject,bruno,root,root,root,root,2035,548799308,12281 136704 gw.homeunix.org
return,success,0

Les informations enregistrées pour chaque événements d’audit est défini par un ensemble de jetons d’audit. Chaque classe d’audit défini un certain nombre (modifiable) de jetons d’audit. Dans l’exemple ci-dessus, il y a 3 jetons d’audit pour cet enregistrement

  • header : marque le début d’un enregistrement d’audit)
  • subject : décrit un utilisateur qui exécute ou tente d’effectuer une opération
  • return : contient l’état de retour de l’appel système et la valeur de retour du processus

Pour obtenir le descriptif de chaque élément de chaque jeton d’audit, il suffit d’utiliser la commande praudit(1M).

# praudit -x 20160828220542.not_terminated.compile
[...]
<record version="2" event="su" host="compile" iso8601="2016-08-29 18:27:57.063 +02:00">
<subject audit-uid="bruno" uid="root" gid="root" ruid="root" rgid="root" pid="2035" sid="548799308" tid="12281 136704 gw.homeunix.org"/>
<return errval="success" retval="0"/>
</record>
[...]

A travers cet article, j’espère que vous vous êtes familiarisé avec cette fonctionnalité fort intéressante disponible dans Solaris. Dans un prochain article, j’aborderai la configuration de l’audit pour un système hébergeant des Zones non Globales en utilisant des classes d’audit complémentaires.