ねじまきまきまき -Random Note-

やったこと忘れないための雑記

certbotコマンドのオプション指定について

cetbot用cron設定見直し

cronの設定値

現在の設定内容は以前も書いたが以下のような感じ。

certbotコマンドが正常終了となったらstone再起動用のbashを起動している。

00 00 01  \*  \* sudo /usr/bin/certbot renew && /Local/stone_run.bash 1>/dev/null 2>&1 &

ただし、わざわざ&&でコマンドをつなげることをせずともオプションとかを使用すれば、再起動できるっぽい。

certbotコマンドの再考

usageはこんな感じ。

$ certbot --help renew
usage: 

  certbot renew [--cert-name CERTNAME] [options]

optional arguments:
  -h, --help            show this help message and exit
  -c CONFIG_FILE, --config CONFIG_FILE
                        path to config file (default: /etc/letsencrypt/cli.ini
                        and ~/.config/letsencrypt/cli.ini)

renew:
  The 'renew' subcommand will attempt to renew all certificates (or more
  precisely, certificate lineages) you have previously obtained if they are
  close to expiry, and print a summary of the results. By default, 'renew'
  will reuse the options used to create obtain or most recently successfully
  renew each certificate lineage. You can try it with `--dry-run` first. For
  more fine-grained control, you can renew individual lineages with the
  `certonly` subcommand. Hooks are available to run commands before and
  after renewal; see https://certbot.eff.org/docs/using.html#renewal for
  more information on these.

  --cert-name CERTNAME  Certificate name to apply. This name is used by
                        Certbot for housekeeping and in file paths; it doesn't
                        affect the content of the certificate itself. To see
                        certificate names, run 'certbot certificates'. When
                        creating a new certificate, specifies the new
                        certificate's name. (default: the first provided
                        domain or the name of an existing certificate on your
                        system for the same domains)
  --dry-run             Perform a test run of the client, obtaining test
                        (invalid) certificates but not saving them to disk.
                        This can currently only be used with the 'certonly'
                        and 'renew' subcommands. Note: Although --dry-run
                        tries to avoid making any persistent changes on a
                        system, it is not completely side-effect free: if used
                        with webserver authenticator plugins like apache and
                        nginx, it makes and then reverts temporary config
                        changes in order to obtain test certificates, and
                        reloads webservers to deploy and then roll back those
                        changes. It also calls --pre-hook and --post-hook
                        commands if they are defined because they may be
                        necessary to accurately simulate renewal. --deploy-
                        hook commands are not called. (default: False)
  --force-renewal, --renew-by-default
                        If a certificate already exists for the requested
                        domains, renew it now, regardless of whether it is
                        near expiry. (Often --keep-until-expiring is more
                        appropriate). Also implies --expand. (default: False)
  --allow-subset-of-names
                        When performing domain validation, do not consider it
                        a failure if authorizations can not be obtained for a
                        strict subset of the requested domains. This may be
                        useful for allowing renewals for multiple domains to
                        succeed even if some domains no longer point at this
                        system. This option cannot be used with --csr.
                        (default: False)
  -q, --quiet           Silence all output except errors. Useful for
                        automation via cron. Implies --non-interactive.
                        (default: False)
  --preferred-chain PREFERRED_CHAIN
                        If the CA offers multiple certificate chains, prefer
                        the chain with an issuer matching this Subject Common
                        Name. If no match, the default offered chain will be
                        used. (default: None)
  --preferred-challenges PREF_CHALLS
                        A sorted, comma delimited list of the preferred
                        challenge to use during authorization with the most
                        preferred challenge listed first (Eg, "dns" or
                        "http,dns"). Not all plugins support all challenges.
                        See https://certbot.eff.org/docs/using.html#plugins
                        for details. ACME Challenges are versioned, but if you
                        pick "http" rather than "http-01", Certbot will select
                        the latest version automatically. (default: [])
  --pre-hook PRE_HOOK   Command to be run in a shell before obtaining any
                        certificates. Intended primarily for renewal, where it
                        can be used to temporarily shut down a webserver that
                        might conflict with the standalone plugin. This will
                        only be called if a certificate is actually to be
                        obtained/renewed. When renewing several certificates
                        that have identical pre-hooks, only the first will be
                        executed. (default: None)
  --post-hook POST_HOOK
                        Command to be run in a shell after attempting to
                        obtain/renew certificates. Can be used to deploy
                        renewed certificates, or to restart any servers that
                        were stopped by --pre-hook. This is only run if an
                        attempt was made to obtain/renew a certificate. If
                        multiple renewed certificates have identical post-
                        hooks, only one will be run. (default: None)
  --deploy-hook DEPLOY_HOOK
                        Command to be run in a shell once for each
                        successfully issued certificate. For this command, the
                        shell variable $RENEWED_LINEAGE will point to the
                        config live subdirectory (for example,
                        "/etc/letsencrypt/live/example.com") containing the
                        new certificates and keys; the shell variable
                        $RENEWED_DOMAINS will contain a space-delimited list
                        of renewed certificate domains (for example,
                        "example.com www.example.com" (default: None)
  --disable-hook-validation
                        Ordinarily the commands specified for --pre-hook
                        /--post-hook/--deploy-hook will be checked for
                        validity, to see if the programs being run are in the
                        $PATH, so that mistakes can be caught early, even when
                        the hooks aren't being run just yet. The validation is
                        rather simplistic and fails if you use more advanced
                        shell constructs, so you can use this switch to
                        disable it. (default: False)
  --no-directory-hooks  Disable running executables found in Certbot's hook
                        directories during renewal. (default: False)
  --disable-renew-updates
                        Disable automatic updates to your server configuration
                        that would otherwise be done by the selected installer
                        plugin, and triggered when the user executes "certbot
                        renew", regardless of if the certificate is renewed.
                        This setting does not apply to important TLS
                        configuration updates. (default: False)
  --no-autorenew        Disable auto renewal of certificates. (default: True)

これを見ると、cronなどで自動実行する場合はquietオプションを推奨されている。

また、pre-hook/post-hook/deploy-hookの各オプションでcertbot動作前後や証明書更新が行われた場合のみの処理も行うことが可能っぽい。

このhookオプションは/etc/letsencrypt/renewal-hooks配下にファイルを置くことでも代替できるようなので、用途を考えるとオプションよりもディレクトリにファイルを置いたほうがいいのかもしれない。

新しいcron用コマンド

上記の考察から、quietオプションとpost-hookオプションを使用するとこうなる。

sudo /usr/bin/certbot renew --quiet --post-hook /Local/stone_run.bash

stoneの起動シェルの変更

stone用の起動シェルについてもこのタイミングでいろいろ見直しを行った。

というのも、一度/etc/letsencrypt/renewal-hooks配下にシンボリックリンクを作成する想定で動作を見ていた時に不具合が発生することがわかったためだ。

以下が修正後の起動シェルになる。

例のごとく、シェルと同ディレクトリにあるstone.+confファイルの数だけ処理を繰り返すというところは変わらない。

変わったのはBASE_DIR変数の取得方法で、dirnameに直接$0を渡すのを止め、realpathコマンドをかます形になっている。

これはシンボリックリンクを動作させた場合、$0に設定されるのはシンボリックリンクのパスなので、シェルファイル自体のパスを取得するための変更となっている。

ちなみにreadlinkではなくrealpathとしているのは、この方法ではreadlinkが想定した動作をしてくれなかったためとなる。

readlinkコマンドを使って$(dirname $(readlink -e $0))みたいなことをやってみたところ、どうもうまく動作しなかったので、ワンラインで動作できたrealpathコマンドで代替した感じ。

#!/bin/bash -l

#BASE_DIR=`dirname $0`
BASE_DIR=`dirname $(realpath $0)`
cd ${BASE_DIR}

## Kill
if [ `ps -ef | egrep "stone.+conf" | egrep -v "grep|sudo|bash" | wc -l` -ne 0 ]; then
        for stone_proc in `ps -ef| egrep "stone.+conf" | egrep -v "grep|sudo|bash" | awk '{print $2}'`
        do
                sudo kill -9 ${stone_proc}
        done
fi

sleep 10

## Start
while true
do
        for target_conf in `ls stone*.conf`
        do
                        if [ `ps -ef | egrep ${target_conf} | egrep -v "grep|sudo|bash" | wc -l` -eq 0 ]; then
                                        nohup sudo /usr/local/bin/stone -C ${BASE_DIR}/${target_conf} 1>/dev/null 2>&1 &
                        fi
        done

        if [ `ps -ef | egrep "stone.+conf" | egrep -v "grep|sudo|bash" | wc -l` -eq `ls stone*.conf | wc -l` ]; then
                break
        else
                sleep 10
        fi
done

exit 0

動作検証

検証というほどでもないが、これがうまく動くことを確認するため、quietオプションを外して、dry-runオプションを付けた状態で動かしてみる。

$sudo /usr/bin/certbot renew --dry-run --post-hook /Local/stone_run.bash
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator standalone, Installer None
Starting new HTTPS connection (1): acme-staging-v02.api.letsencrypt.org
Simulating renewal of an existing certificate for example.com
Performing the following challenges:
http-01 challenge for example.com
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/example.com/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded: 
  /etc/letsencrypt/live/example.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Running post-hook command: /Local/stone_run.bash

予定通りの結果が得られたので、これでいいこととする。