Let's EncryptでSSL証明書の新規作成と自動更新(dns-01編)

Let's Encrypt とは

  • Lets' Encrypt は認証局(Certificate Authority)のブランドの一つである。

  • これは「Symantec(旧Verisign)セキュア・サーバーID」「CyberTrust SureServer」「SecomTrust セコムパスポート for Web3.0」「GlobalSign クイック認証SSL」「GeoTrust RapidSSL」「Comodo PositiveSSL」などの一つと考えれば良い。

  • たぶんどれかは聞いたことあるはずと思う。アレが抜けてるというツッコミは却下で:-)。
  • 他の認証局と同じような点は、
    • 1証明書をどのように(複数IP、複数バックエンド、複数プロトコル)使用しても1取得で済む(安い認証局は大抵そうだよね)。
    • 親ドメインをまたぐ、マルチドメイン証明書(Subject Alternative Names)に対応している(全ての認証局で対応してるね)。
    • いよいよワイルドカード証明書に対応(対応してるブランドと対応してないブランドとあるね)。

    • DV(Domain Validation)証明書のみ提供(DVだけでなくOV・EVにも対応してるブランドもあるね)。

    • ただしOV(Organization Validation)証明書やEV(Extended Validation)証明書との純技術的な優劣は無い。

  • 他の認証局と明確に違う点は、
    • 無償。
    • RSA(2048bit3072bit4096bit), ECDSA(prime256v1secp384r1) の5種類の鍵が選べる(ここまで選べるブランドは限られるね)。DSAが無い?時代だ。諦めろ。

    • ACME(Automated Certificate Management Environment)プロトコルによる証明書の認証から発行までの一連のバッチ化(自動化)が可能。

    • 今どき誤差だけど、扱える端末が(他の認証局と比べて)少ない。
    • ごく一部のエンドユーザーが粘り強く使用しているような、全アクセスの0.1%未満の端末であってもサポートしないといけない用途であるならお勧めしない。
    • 逆に今どきのメジャーどころの端末・ブラウザは対応している。
    • よってPC相手にはほぼ問題無い(Windows XP? IE6? 知らんがな)。

    • 取得数制限(特に単位時間あたりの)があるので注意。詳しくは Rate Limits を参照のこと。

    • 検証(ステージング)用認証局も用意されているので、セットアップ時の検証や、ACMEクライアントの開発といった用途ではこちらを使う。

    • 「現在の」ルート証明書は「IdentTrust|DST(Digital Signature Trust) Root CA X3」である。

    • IdentTrust なの? DST なの? については旧会社のブランドも残ってるらしい、としか自分は認識してない。詳しくは会社概要でも読んでくれい。

    • 少なくとも中間証明書の発行者(Issuer)はそうである(Let's Encrypt運用元の ISRG - Internet Security Research Group ではない)。

    • このルート証明書がインストールされた端末が対応端末となる。
    • 中間証明書(Subject)は「Let's Encrypt Authority X3」である(場合によってはこっち「も」入ってることがあるかもしれない)。

  • なおツールとしては certbot が代表的だが、他にもたくさんのツールが存在する。

  • ここでは全て dehydrated を使用を前提に解説する。certbotdehydratedの違いについては特に解説しない。

  • dehydratedを選んだ理由は、

    • dehydratedはBash/ZSH依存スクリプトであるため、特別な言語環境(Python)を必要としない。

    • certbotの場合、Pythonに依存する分には問題無いが、依存するPythonモジュールが極めて大量にあって維持が大変。

    • dehydratedはまだ依存が少ない(curl のせいでずいぶん増えてるが)。

    • dehydratedの場合、わけわかんなくなっても、シェルスクリプトなのでソースコード読んで理解できる。また長いコードではない。

    • dehydratedはWebサーバー機能を内蔵していないため、Webサーバーとの競合に配慮しなくてよい。

    • dehydratedはエイリアス機能により、同じコモンネームでRSA/ECDSA両方の証明書取得が可能である。

dns-01 とは

目次

検証環境

想定サーバー・ドメイン

DNSコンテンツサーバー側

SSLサーバー側

インストール

DNSコンテンツサーバー側の設定

named.conf の設定(一部)例

include "ダイナミックアップデートキーファイル名";

zone "example.jp" {
    type master;
    file "example.jpゾーンファイル名";
};

zone "_acme-challenge.www.example.jp" {
    type master;
    file "_acme-challenge.www.example.jpゾーンファイル名";
    update-policy {
        grant ダイナミックアップデートキー名 name _acme-challenge.www.example.jp. TXT;
    };
};

example.jp ゾーンファイルの設定例

$TTL               300

@                       IN SOA ns.example.jp. domain.example.jp. (
                               2017032201 ; serial
                               7200       ; refresh (2 hours)
                               900        ; retry (15 minutes)
                               2419200    ; expire (4 weeks)
                               86400      ; minimum (1 day)
                               )
                        IN NS ns
_acme-challenge.www     IN NS ns

_acme-challenge.www.example.jp ゾーンファイルの設定例

$TTL               300

@                       IN SOA ns.example.jp. domain.example.jp. (
                               2017032201 ; serial
                               7200       ; refresh (2 hours)
                               900        ; retry (15 minutes)
                               2419200    ; expire (4 weeks)
                               86400      ; minimum (1 day)
                               )
                        IN NS ns

ダイナミックアップデートキーファイルの設定例

key "キー名" {
    algorithm hmac-sha256;
    secret "シークレットキー(BASE64表現)";
};

上記ファイルは以下のコマンドにより生成することができる。

tsig-keygen -a hmac-sha256 キー名 > ダイナミックアップデートキーファイル名
chmod 0400 ダイナミックアップデートキーファイル名

本例における具体的設定例

key "ns-www." {
    algorithm hmac-sha256;
    secret "PfzeGvXiOqtPOwQJY/iNFrvlD3/eKAHRZ0TbyK5GYII=";
};

SSLサーバー側の設定

/etc/periodic.conf

weekly_dehydrated_enable="YES"

自動更新設定(YES=自動更新する)。 periodic(8)にある通り、毎週土曜日3時に実行される。

なお今回、weekly_dehydrated_deployscript は指定しない(後述の HOOK 設定参照のこと)。

/usr/local/etc/dehydrated/ns-www.key

これは先に tsig-keygen コマンドで作成されたファイルである。 DNSコンテンツサーバーと同一になるように設定すること。

/usr/local/etc/dehydrated/config

alias openssl="/usr/bin/openssl"

CHALLENGETYPE="dns-01"
HOOK="${BASEDIR}/hook.sh"
RENEW_DAYS="30"
KEY_ALGO="rsa" KEYSIZE="2048"
#KEY_ALGO="prime256v1"
CONTACT_EMAIL="メールアドレス"
#テスト発行したい場合、以下の2行を有効にすること。
#CA="https://acme-staging.api.letsencrypt.org/directory"
#CA_TERMS="https://acme-staging.api.letsencrypt.org/terms"

/usr/local/etc/dehydrated/domains.txt

example.org www.example.org
example.com www.example.com wiki.example.com

本ファイルの設定については コモンネームの設定に準拠するものとする(例)。

/usr/local/etc/dehydrated/hook.sh

TTL="300"
DNSSERVER="ns.example.jp"
alias nsupdate="/usr/local/bin/nsupdate -k ${BASEDIR}/ns-www.key"

function deploy_challenge {
    local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}"
    printf 'server %s\nupdate add _acme-challenge.%s. %d TXT "%s"\nsend\n' "${DNSSERVER}" "${DOMAIN}" "${TTL}" "${TOKEN_VALUE}" | nsupdate
}

function clean_challenge {
    local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}"
    printf 'server %s\nupdate delete _acme-challenge.%s. TXT\nsend\n' "${DNSSERVER}" "${DOMAIN}" | nsupdate
}

function deploy_cert {
    /usr/sbin/service apache24 restart && /usr/local/bin/dehydrated -gc
}

function unchanged_cert {
    # NOTHING TO DO #
}

function invalid_challenge() {
    # NOTHING TO DO #
}

function request_failure() {
    # NOTHING TO DO #
}

function exit_hook() {
    # NOTHING TO DO #
}

HANDLER=$1; shift; $HANDLER $@

HOOK ファイルのひな形として、/usr/local/etc/dehydrated/hook.sh.example を参照すること。

/usr/local/etc/dehydrated/deploy.sh

参考文献