--- categories: ['OpenBSD','Système','Base'] date: 2020-08-19T03:27:17+02:00 description: "Comment résoudre des erreurs de sortie du client acme sous OpenBSD…" draft: false tags: ['OpenBSD','acme-client','Erreur','astuce'] title: "OpenBSD: acme-client: bad exit" translationKey: 'openbsd-acme-client' --- ## Description Sous OpenBSD depuis 6.1, pour la génération de certificats avec l'autorité de certification {{< abbr LE "Let's Encrypt" >}}, nous avons intégré au système de base le client acme, écrit en C, reconnu pour être sécurisé. Je ne traiterais pas de la configuration, elle est très simple, et vraiment bien {{< anchor documentée documentations >}} dans le manpage ad hoc. Ce mémo existe pour répertorier quoi faire dans le cas de sortie en erreur. ## Dépannage ### bad HTTP: 400 {{< abbr "TL;DR" "Too Long; Did'nt read" >}} : Le client acme n'arrive pas à se connecter à votre serveur web. Dans les faits, il faut en passer par une investigation et une explication un peu plus poussée… **Investigation :** Par exemple, voici la fin du message verbeux d'acme : `# acme-client -v mydomain.tld`
`(…)`
`acme-client: challenge, token: L8dcjbmFhbE6N2GtSKxEi9yzhR888oSdBdgzt7GnJbc, uri: https://acme-v02.api.letsencrypt.org/acme/chall-v3/6581640382/2HdrCw, status: -1`
`(…)`
`acme-client: https://acme-v02.api.letsencrypt.org/acme/chall-v3/6460247699/ixiI9A: bad HTTP: 400`
`acme-client: transfer buffer: [{ "type": "urn:ietf:params:acme:error:malformed", "detail": "Unable to update challenge :: authorization must be pending", "status": 400 }] (144 bytes)`
`acme-client: bad exit: netproc(70635): 1` Le réflexe à avoir est de basculer en mode doublement verbeux, ce qui nous donnera plus de détail : `# acme-client -vv mydomain.tld`
`(…)`
`acme-client: transfer buffer: [{ "identifier": { "type": "dns", "value": "www.mydomain.tld" }, "status": "invalid", "expires": "2020-08-24T22:24:39Z", "challenges": [ { "type": "http-01", "status": "invalid", "error": { "type": "urn:ietf:params:acme:error:connection", "detail": "Fetching http://mydomain.tld/.well-known/acme-challenge/xCefC0pD3W1VRLeWVYHmYmJj1Bf06G1hoskXdN1xIEg: Connection refused", "status": 400 }, "url": "https://acme-v02.api.letsencrypt.org/acme/chall-v3/6603509164/7d1MkA", "token": "xCefC0pD3W1VRLeWVYHmYmJj1Bf06G1hoskXdN1xIEg", "validationRecord": [ { "url": "http://www.mydomain.tld/.well-known/acme-challenge/xCefC0pD3W1VRLeWVYHmYmJj1Bf06G1hoskXdN1xIEg", "hostname": "www.mydomain.tld", "port": "80", "addressesResolved": [ "88.136.16.221", "2001:470:cc33::3" ], "addressUsed": "2001:470:cc33::3" }, { "url": "http://www.mydomain.tld/.well-known/acme-challenge/xCefC0pD3W1VRLeWVYHmYmJj1Bf06G1hoskXdN1xIEg", "hostname": "www.mydomain.tld", "port": "80", "addressesResolved": [ "88.136.16.221", "2001:470:cc33::3" ], "addressUsed": "88.136.16.221" }, { "url": "http://mydomain.tld/.well-known/acme-challenge/xCefC0pD3W1VRLeWVYHmYmJj1Bf06G1hoskXdN1xIEg", "hostname": "mydomain.tld", "port": "80", "addressesResolved": [ "88.136.16.221", "2001:470:cc33::3" ], "addressUsed": "2001:470:cc33::3" } ] } ] }] (1712 bytes)`
`acme-client: challenge, token: xCefC0pD3W1VRLeWVYHmYmJj1Bf06G1hoskXdN1xIEg, uri: https://acme-v02.api.letsencrypt.org/acme/chall-v3/6603509164/7d1MkA, status: -1`
`(…)`
`acme-client: https://acme-v02.api.letsencrypt.org/acme/chall-v3/6603509164/7d1MkA: bad HTTP: 400`
`acme-client: transfer buffer: [{ "type": "urn:ietf:params:acme:error:malformed", "detail": "Unable to update challenge :: authorization must be pending", "status": 400 }] (144 bytes)`
`acme-client: bad exit: netproc(37360): 1` **Explications** Au dessus de la ligne terminant par `status: -1`, on remarque une nouvelle ligne. Cette ligne nous informe : * que le status est `invalid`, * que la connexion a été refusée : `Connection refused`, * qu'elle a été fermée par le client : `status: 400`, * qu'elle a échoué sur la connexion de l'adresse IPv6 du serveur : `"addressUsed": "2001:470:cc33::3"` En fait, acme-client informe qu'il n'arrive pas à se connecter sur le serveur à l'adresse IPv6. La première chose à s'assurer est que le serveur web soit joignable sur votre adresse IPv6 ! Il peut y avoir diverses raisons pour lesquelles votre serveur web ne soit pas joignable sur IPv6 : * assurez-vous que l'adresse IPv6 réponde à la commande `ping6`, puis… * l'oubli de configuration du serveur lui-même… vérifiez que vous avez bien autorisé la connexion sur IPv6. * pour httpd : `listen on votre-adresse-ipv6 port 80` * pour nginx : `listen [::]:80;` * le pare-feu local {{< abbr PF "Packet Filter" >}} qui n'autorise pas la connexion sur les ports HTTP, voire HTTPS, sur l'adresse IPv6 du serveur :
`pass in quick on egress inet6 proto tcp to votre-adresse-ipv6 port 80 flags S/SA modulate state` * Avez-vous en amont un pare-feu ? vérifiez que vos règles de parefeu redirigent bien le flux HTTP(S) vers votre serveur web… Une manière de s'en assurer est d'utiliser un scanner de port sur IPv6, par exemple celui de [ipv6scanner.com](http://www.ipv6scanner.com/cgi-bin/main.py). Si le scanner vous dit qu'aucun port correspond n'est ouvert, cherchez profondément la raison… Dans cet exemple, le serveur ne répondait pas lors de l'interrogation sur son adresse IPv6. Le `status 400` peut très bien être provoqué sur l'adresse IPv4 du serveur. Appliquez le même raisonnement pour vous assurez que votre serveur soit joignable sur son adresse IPv4. Ceci est une des raisons pour lesquelles acme-client peut retourner un statut d'erreur 400. À chaque fois, il faut analyser profondément les informations retournées. ### order.status -1 Le client acme restitue de manière sybilline ce message : `# acme-client -v mydomain.tld`
`(…)`
`acme-client: order.status -1`
`acme-client: bad exit: netproc(27643): 1` Là, il peut y avoir de multiples raisons qui empêche tout simplement le client acme de discuter avec votre serveur web. Le propos est de vérifier qu'aucune écriture de la configuration du serveur n'empêche la lecture dans le répertoire de challenge acme. Exemples pouvant générer : * pour nginx, une simple écriture telle que la suivante peut empêcher l'accès au répertoire de challenge acme :
`location ~ /\. {`
` access_log off;`
` log_not_found off;`
` deny all;`
`}` * concernant relayd, des règles filtrantes les méthodes de connexion peuvent empêcher le bon fonctionnement…
## Documentations ### Manpages * {{< man acme-client >}}, {{< man acme-client.conf 5 >}}