インストール

# yum install mod_ssl

自己署名証明書

  • SAN 項目を追加した設定ファイルを作成。

    # cd /etc/pki/tls/
    # cp openssl.cnf openssl-san.cnf
  • openssl.cnf と openssl-san.cnf の差分

    --- openssl.cnf
    +++ openssl-san.cnf
    @@ -104,7 +104,7 @@
     ####################################################################
     [ req ]
     default_bits           = 2048
    -default_md             = sha1
    +default_md             = sha256
     default_keyfile        = privkey.pem
     distinguished_name     = req_distinguished_name
     attributes             = req_attributes
    @@ -222,6 +222,11 @@
    
     basicConstraints = CA:FALSE
     keyUsage = nonRepudiation, digitalSignature, keyEncipherment
    +subjectAltName=@alt_names
    +
    +[ alt_names ]
    +DNS.1=takeash.net
    +DNS.2=*.takeash.net
    
    [ v3_ca ]
    
  • 証明書フォルダへ移動
    # cd certs/
  • サーバー用秘密鍵作成 (server.key)
    # openssl genrsa -aes128 2048 > server.key
  • パスフレーズ削除
    httpd 再起動時にパスフレーズが要求されないようにするため。
    # openssl rsa -in server.key -out server.key
  • サーバー用自己署名証明書作成 (server.crt)

    # openssl req -utf8 -new -key server.key -x509 -days 3650 -out server.crt -set_serial 0 \
        -subj '/C=JP/ST=Tokyo/L=Chuo-ku/O=TakeAsh.net/CN=takeash.net' -extensions v3_req -config ../openssl-san.cnf
    • サブジェクト例 (TakeAsh.net)

      項目 用途 サンプル
      C 国名コード JP
      ST 都道府県 Tokyo
      L 区市町村 Chuo-ku
      O 組織名 TakeAsh.net
      CN コモンネーム(ドメイン名) takeash.net
    • 証明書確認
      「X509v3 extensions - X509v3 Subject Alternative Name」項目が存在すれば SAN が含まれている。

      # openssl x509 -in server.crt -text
      ...
          X509v3 Subject Alternative Name:
              DNS:takeash.net, DNS:*.takeash.net
      ...
  • /etc/httpd/conf.d/ssl.conf (抜粋)

    SSLCertificateFile /etc/pki/tls/certs/server.crt
    SSLCertificateKeyFile /etc/pki/tls/certs/server.key
    DocumentRoot "/var/www/html"
    SSLProtocol all -SSLv2 -SSLv3
  • httpd 再起動

    • CentOS 6
      # service httpd restart
    • CentOS 7
      # systemctl restart httpd
  • 動作テスト

Certbot

  • Certbot 使用前準備

    • ホスト名が正引きできること。(ワイルドカード不可)
    • バーチャルホストのサーバ名と要求するドメイン名のどれかが一致すること。
    • インターネットから https でアクセス可能になっていること。
      • https ポート解放
      # firewall-cmd --permanent --add-service=https
      
    • CertBot は Apache が稼働しているサーバ上で実行する。
  • Certbot インストール (EPEL リポジトリ)

    # yum install python-certbot-apache
  • 証明書取得
    取得に成功すると「/etc/letsencrypt/live/<ドメイン1>/」に証明書が作成される。

    # certbot certonly --apache \
        -m <メールアドレス> --agree-tos \
        -d <ドメイン1> [-d <ドメイン2> ...]
  • /etc/httpd/conf.d/ssl.conf (抜粋)

    Listen 443 https
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/<ドメイン1>/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/<ドメイン1>/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/<ドメイン1>/chain.pem
  • /etc/httpd/conf.d/VirtualHosts.conf (抜粋)
    バーチャルホスト毎に SSL 設定が必要。

    <VirtualHost *:80 *:443>
            ServerName      vh1.<ドメイン1>
            DocumentRoot    /var/www/vh1-html/
            SSLEngine on
            SSLCertificateFile /etc/letsencrypt/live/<ドメイン1>/cert.pem
            SSLCertificateKeyFile /etc/letsencrypt/live/<ドメイン1>/privkey.pem
            SSLCertificateChainFile /etc/letsencrypt/live/<ドメイン1>/chain.pem
            <Directory "/var/www/vh1-html">
                    AllowOverride   All
            </Directory>
    </VirtualHost>
  • 自動更新スクリプト /etc/cron.monthly/certbot.sh

    #!/bin/bash
    /bin/certbot renew

Certbot (ワイルドカード, 手動)

  • Certbot インストール (EPEL リポジトリ)

    # yum -y install yum-utils
    # yum-config-manager --enable rhui-REGION-rhel-server-extras rhui-REGION-rhel-server-optional
    # yum install certbot-apache
  • 証明書取得(手動)
    途中HTTPへのテキストファイルの配置とDNSへのTXTレコードの追加を指示されるので、追加してからEnterを押して先へ進む。
    取得に成功すると「/etc/letsencrypt/live/<ドメイン>/」に証明書が作成される。

    # certbot certonly --manual \
        --server https://acme-v02.api.letsencrypt.org/directory \
        -d "*.example.com" -d example.com
  • /etc/httpd/conf.d/ssl.conf (抜粋)

    Listen 443 https
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/<ドメイン>/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/<ドメイン>/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/<ドメイン>/chain.pem
  • /etc/httpd/conf.d/VirtualHosts.conf (抜粋)
    バーチャルホスト毎に SSL 設定が必要。

    <VirtualHost *:80 *:443>
            ServerName      vh1.<ドメイン1>
            DocumentRoot    /var/www/vh1-html/
            SSLEngine on
            SSLCertificateFile /etc/letsencrypt/live/<ドメイン1>/cert.pem
            SSLCertificateKeyFile /etc/letsencrypt/live/<ドメイン1>/privkey.pem
            SSLCertificateChainFile /etc/letsencrypt/live/<ドメイン1>/chain.pem
            <Directory "/var/www/vh1-html">
                    AllowOverride   All
            </Directory>
    </VirtualHost>
  • apache 再起動
    CentOS 7

    # systemctl restart httpd
  • 証明書更新
    「--manual」で取得した場合は「renew」による自動更新ができないので、既存の証明書を削除し同名で取得し直す。

    # certbot delete

Certbot (ワイルドカード, 自動)

  • Certbot, DNS Plugin インストール (EPEL リポジトリ)

    # yum -y install yum-utils
    # yum-config-manager --enable rhui-REGION-rhel-server-extras rhui-REGION-rhel-server-optional
    # yum install certbot-apache python2-certbot-dns-rfc2136
  • BIND 用認証キーの作成
    Kcertbot-key.+165+43987.key, Kcertbot-key.+165+43987.private の2つのファイルが作成される。

    # cd /etc/named/
    # dnssec-keygen -a HMAC-SHA512 -b 512 -n HOST certbot-key
  • 認証ファイル /etc/named/certbot_rfc2136.ini , ファイルモード 600

    # Target DNS server
    dns_rfc2136_server = 127.0.0.1
    # Target DNS port
    dns_rfc2136_port = 53
    # TSIG key name
    dns_rfc2136_name = certbot-key.
    # TSIG key secret
    dns_rfc2136_secret = <Kcertbot-key.+165+43987.key のハッシュ値>
    # TSIG key algorithm
    dns_rfc2136_algorithm = HMAC-SHA512
  • /etc/named.conf に追加

    key "certbot-key." {
      algorithm hmac-sha512;
      secret "<Kcertbot-key.+165+43987.key のハッシュ値>";
    };
    
    view "internal" {
      match-clients { localhost; localnets; };
      match-destinations { localhost; localnets; };
      recursion yes;
    
      zone "." IN {
        type hint;
        file "named.ca";
      };
    
      include "/etc/named.rfc1912.zones";
      include "/etc/named.root.key";
      include "/etc/named/<ドメイン>.lan.zone";
    };
    
    view "external" {
      match-clients { any; };
      match-destinations { any; };
      recursion no;
      include "/etc/named/<ドメイン>.wan.zone";
      include "/etc/named/_acme-challenge.<ドメイン>.wan.zone";
    };
  • /etc/named/<ドメイン>.lan.zone

    zone "<ドメイン>" {
      type master;
      file "<ドメイン>.lan.db";
      update-policy {
        grant certbot-key. name _acme-challenge.<ドメイン>. txt;
      };
    };
  • /etc/named/<ドメイン>.wan.zone

    zone "<ドメイン>" {
      type master;
      file "<ドメイン>.wan.db";
      allow-query { any; };
      update-policy {
        grant certbot-key. name _acme-challenge.<ドメイン>. txt;
      };
    };
  • /etc/named/_acme-challenge.<ドメイン>.wan.zone

    zone "_acme-challenge.<ドメイン>" {
      type master;
      file "_acme-challenge.<ドメイン>.wan.db";
      allow-query { any; };
      update-policy {
        grant certbot-key. name _acme-challenge.<ドメイン>. txt;
      };
    };
  • /var/named/<ドメイン>.wan.db

    $TTL    86400
    @       IN SOA  ns1.<ドメイン>.        root.<ドメイン>. (
                            2018090500 ; Serial
                            28800      ; Refresh
                            14400      ; Retry
                            2592000    ; Expire
                            86400      ; Minimum
                    )
            IN NS   ns1.<ドメイン>.
            IN MX 10 mail.<ドメイン>.
    @       IN A    <グローバル IP アドレス>
    ns1     IN A    <グローバル IP アドレス>
    www     IN A    <グローバル IP アドレス>
    mail    IN A    <グローバル IP アドレス>
    _acme-challenge IN NS ns1.<ドメイン>.
    *       IN A    <グローバル IP アドレス>
    <ドメイン>.    IN TXT "v=spf1 a mx ~all"
  • /var/named/_acme-challenge.<ドメイン>.wan.db

    $TTL    86400
    @       IN SOA  ns1.<ドメイン>.  root.<ドメイン>. (
                            2018090500 ; Serial
                            1h      ; Refresh
                            15m     ; Retry
                            30d     ; Expire
                            1h      ; Minimum
                    )
            IN NS   ns1.<ドメイン>.
  • <ドメイン>.jnl: create: permission denied(/var/named/data/named.run) 対策

    # chmod 770 /var/named/
    # setsebool -P named_write_master_zones 1
  • 証明書取得

    # certbot certonly \
      --dns-rfc2136 \
      --dns-rfc2136-credentials /etc/named/certbot_rfc2136.ini \
      -d "*.<ドメイン>" -d <ドメイン>
  • /etc/letsencrypt/renewal-hooks/deploy/restartServices.sh

    #!/bin/bash
    
    LANG=en_us.UTF-8
    PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
    services="httpd postfix dovecot"
    
    if [ $(id -u) != 0 ]; then
      echo "This command requires root previlege." 1>&2
      exit 1
    fi
    
    for service in ${services}; do
      echo "restart ${service}"
      systemctl restart ${service} || exit $?
    done
    exit 0
  • サービス登録

    # systemctl start certbot-renew
    # systemctl enable certbot-renew
    # systemctl status certbot-renew

動作確認

証明書の内容をテキスト出力

# openssl x509 -text -in /etc/letsencrypt/live/<ドメイン>/cert.pem

証明書の有効期限を表示

getExpireDate.sh

#!/bin/bash

CommonName=example.net

NotAfter=`openssl x509 -noout -dates -in /etc/letsencrypt/live/${CommonName}/fullchain.pem | \
  grep notAfter | \
  sed -e "s/notAfter=//" | \
  date -f - --iso-8601`
echo ${NotAfter}

SSL 接続確認

$ openssl s_client -connect <ホスト>:443

設定失敗

CONNECTED(00000003)
140139752064912:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:s23_clnt.c:794:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 289 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : 0000
    Session-ID:
    Session-ID-ctx:
    Master-Key:
    Key-Arg   : None
    Krb5 Principal: None
    PSK identity: None
    PSK identity hint: None
    Start Time: 1535884386
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---

設定成功

CONNECTED(00000003)
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = *.<ドメイン1>
verify return:1
---
Certificate chain
  0 s:/CN=*.<ドメイン1>
    i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
  1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
    i:/O=Digital Signature Trust Co./CN=DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIGETCCBPmgAwIBAgISA3VBvI0cSyzAQGtpIaQKQRZxMA0GCSqGSIb3DQEBCwUA
...

リンク