class

Beryl::Apply::AcmeCert

Inherits Beryl::Apply::Primitive < Reference < Object

Primitive acme-cert : émet et installe un certificat Let's Encrypt (via acme.sh, cf. recette acme) pour un ou plusieurs domaines, de façon IDEMPOTENTE — beryl n'a pas de primitive « exec » générique, mais celle-ci encapsule le geste d'émission stateful.

Idempotent : si le fullchain existe déjà ET reste valide au-delà de renew_days, la primitive skippe (le renouvellement courant est porté par le cron de la recette acme, via le reloadcmd enregistré ici à l'installation). Sinon elle émet + installe.

TROIS méthodes de validation (method:) :

  • standalone (défaut) — acme.sh ouvre lui-même le port 80. Renseignez stop_service (ex. nginx) pour le libérer le temps de l'émission : le service est RESTAURÉ en trap EXIT, même si acme.sh échoue.
  • webroot + webroot: <racine servie sur :80> — sans coupure.
  • dns + dns_provider: <plugin dnsapi> — validation DNS-01 : aucun port requis, donc AUCUNE coupure, et seule méthode qui gère les WILDCARDS (*.example.com). Le renouvellement par le cron acme est entièrement automatique (acme.sh persiste les credentials DNS).

Pré-requis (recette acme) : acme.sh + socat installés. En http-01 (standalone/webroot) chaque domaine doit pointer sur l'hôte AVANT l'émission ; en dns seul l'accès à l'API DNS est nécessaire.

Conventions du port FreeBSD : acme.sh tourne en utilisateur acme (user:), home /var/db/acme/.acme.sh (home:), certificats laissés dans /var/db/acme/certs (cert_home:) — fullchain/key ne servent qu'à copier ailleurs si une recette l'exige.

- acme-cert:
    domains: [www.example.net, example.net]   # 1er = primaire, suivants = SAN
    method: dns
    dns_provider: dns_ovh
    reloadcmd: "/usr/local/bin/sudo /usr/sbin/service nginx reload"

# Wildcard (DNS-01, sans coupure) — le wildcard NE couvre PAS l'apex
# ni les sous-sous-domaines : listez les deux, un seul niveau.
- acme-cert:
    domains: [example.net, "*.example.net"]
    method: dns
    dns_provider: dns_ovh
    reloadcmd: "/usr/local/bin/sudo /usr/sbin/service nginx reload"

Constants

ACME_BIN = "/usr/local/sbin/acme.sh"
DEFAULT_CERT_HOME = "/var/db/acme/certs"
DEFAULT_HOME = "/var/db/acme/.acme.sh"

Conventions du port FreeBSD security/acme.sh (pkg-plist, pkg-message, account.conf.sample) : home ~acme/.acme.sh, certificats ~acme/certs, acme.sh exécuté par l'utilisateur acme (créé par le paquet).

DEFAULT_USER = "acme"
DNS_CREDENTIAL_MAP = {"dns_ovh" => {"OVH_AK" => "OVH_APPLICATION_KEY", "OVH_AS" => "OVH_APPLICATION_SECRET", "OVH_CK" => "OVH_CONSUMER_KEY"}, "dns_gandi_livedns" => {"GANDI_LIVEDNS_KEY" => "GANDI_PAT"}}

Traduction credentials beryl → variables attendues par les plugins dnsapi d'acme.sh : les NOMS diffèrent (beryl est explicite, acme.sh abrège). Clé = variable acme.sh, valeur = variable beryl. Pour câbler un nouveau provider DNS, ajoutez son entrée ici.

LOG_PATH = "/var/log/acme.sh.log"

Journal d'acme.sh selon la convention du port (LOG_FILE de account.conf, posé par la recette acme) : cité dans le message d'échec.

SCRIPT_PATH = "/tmp/beryl-acme-cert.sh"

Class methods

cert_home_fullchain(cert_home : String, domain : String, keylength : String) : String

Fullchain tel que rangé par acme.sh dans CERT_HOME : <domaine>_ecc/ pour une clé EC, <domaine>/ sinon. Pur, exposé pour test.

Source
dns_credentials(provider : String, env = ENV) : Hash(String, String)

Credentials DNS à exporter pour le plugin dnsapi, lus depuis l'environnement (renseigné par apply_all_credentials_to_env! du host). Renvoie un hash vide si le provider n'est pas câblé / rien en env.

Source
domain_flags(domains : Array(String), aliases : Hash(String, String)) : String

-d de chaque domaine, avec le « mode alias DNS » d'acme.sh (wiki DNS-alias-mode) : un domaine dont la zone n'est pas accessible avec nos identifiants DNS est validé via un CNAME _acme-challenge.<domaine> → _acme-challenge.<alias> posé une fois ; acme.sh écrit alors le TXT dans la zone de l'alias. Dès qu'un alias existe, les autres domaines reçoivent --challenge-alias no (mélange documenté, section 5). Pur, exposé pour test.

Source
failure_summary(stdout : String, stderr : String, exit_code : Int32) : String

Résumé lisible d'un échec acme.sh : ses lignes d'ERREUR (les 5 dernières), pas sa dernière ligne qui n'est qu'un lien vers le wiki. Repli : les 3 dernières lignes non vides. Pur, exposé pour test.

Source
issue_script(domains : Array(String), fullchain : String | Nil, key : String | Nil, reloadcmd : String | Nil, home : String, server : String, method : String, webroot : String | Nil, stop_service : String | Nil, keylength : String, pre_hook : String | Nil, post_hook : String | Nil, dns_provider : String | Nil = nil, dns_env : Hash(String, String) = {} of String => String, cert_home : String = DEFAULT_CERT_HOME, aliases : Hash(String, String) = {} of String => String) : String

Script d'émission + installation (lancé sur l'hôte). Pur, exposé pour test. Pas de set -e : on capture le code de retour de --issue (0 = émis, 2 = inchangé/déjà valide côté acme.sh — tous deux acceptables).

Source
ovh_end_point(raw : String | Nil) : String

Endpoint OVH au format acme.sh. beryl stocke eu/ca/us (ou kimsufi_eu…), acme.sh attend ovh-eu/kimsufi-eu… Pur, testable.

Source

Instance methods

apply(shell : Shell, params : Hash(String, YAML::Any), dry_run : Bool, context : Context) : StepResult

params est le hash brut du step YAML (ex: {"packages" => [...]}), déjà interpolé par l'Executor. context porte les infos dérivées du host (cf. Context).

Source
name

Nom kebab-case utilisé comme clé de step dans les recettes (« pkg-install », « service-enable », …).

Source