7.6. HAProxyで認証する場合の設定例

7.6.1. レスポンス用ファイルの例

認証エラー時のレスポンスデータファイルの例は、以下の通りです。

HTTP/1.1 401 Unauthorized
Connection: close
Content-Type: application/json

{"error":"Invalid Client Certificate"}

7.6.2. HAProxyのコンフィギュレーションの例

HAProxyのコンフィギュレーションの例は、以下の通りです。

frontendの設定

例では事前に用意した証明書、エラーファイルを /etc/haproxy/ 配下に格納しています。

frontend  main
    # *:8080  ... 全IPアドレスのTCP 8080ポートでリクエストの待ち受けを行う
    # ssl     ... 通信にssl(https)を使用します
    # crt     ... サーバ証明書ファイル(pemフォーマット)
    #             サーバ証明書、サーバ証明書の秘密鍵、中間CA証明書(存在する場合)をcatコマンドで結合したファイル
    # ca-file ... クライアント証明書の発行元CAの証明書(pemフォーマット)
    # verify optional ... クライアント証明書が存在する場合は検証を行う
    #                     クライアント証明書認証を必須とする場合は、verify requiredを指定する
    # crt-ignore-err all ... クライアント証明書の検証が失敗した場合も処理を継続する
    # no-sslv3 ... SSLv3を無効にする
    # crl-file ... 証明書失効リスト
    #              クライアント証明書発行元のCAが提供するCRLを、定期的に取得・更新すること
    bind    *:8080 ssl crt /etc/haproxy/certs/server_cert.pem  ca-file /etc/haproxy/certs/cacert.pem verify optional crt-ignore-err all no-sslv3 crl-file /etc/haproxy/certs/crl.pem

    # L7 modeを使用する
    mode http
    # クライアントが付与した"X-SSL"で始まるヘッダを削除する
    # 予期しないヘッダ転送を避けるため必ず設定すること
    reqdel ^X-SSL

    # クライアント証明書認証に失敗したケース(証明書なしの場合は除く)
    use_backend invalid-cert-detected unless { ssl_c_verify 0 }
    # クライアント証明書認証に成功したケース
    use_backend with-client-cert if { ssl_c_used }
    # クライアント証明書が付与されないケース(通常認証)
    default_backend no-certificate

警告

HAProxyで使用するサーバ証明書ファイルは、秘密鍵を含みます。 適切なアクセス権限を設定し、外部への漏えいが発生しないよう管理してください。

backendの設定

# クライアント証明書認証に失敗
backend invalid-cert-detected
    mode   http
    option httpclose
    # 転送先のバックエンドサーバの指定を行っていないため、haproxyに503エラーが発生
    # その結果、指定した/etc/haproxy/errors/401.httpファイルの内容がクライアントに返却される
    errorfile  503 /etc/haproxy/errors/401.http

# クライアント証明書認証に成功
backend with-client-cert
    mode    http
    balance roundrobin
    # 転送先のバックエンドサーバを指定
    # 複数のBaaS APIサーバが存在する場合は列挙すること
    server    certapi01  10.0.1.1:80
    # server  certapi02  10.0.1.2:80

    option  forwardfor

    # バックエンドに送信する証明書情報ヘッダ
    http-request set-header X-SSL-Client-CertAuth-Validated    1
    http-request set-header X-SSL-Client-Serial         %[ssl_c_serial,hex]
    http-request set-header X-SSL-Client-CN             %{+Q}[ssl_c_s_dn(cn)]
    http-request set-header X-SSL-Client-UID            %{+Q}[ssl_c_s_dn(uid)]
    http-request set-header X-SSL-Issuer-DN             %{+Q}[ssl_c_i_dn]
    # X-SSL-Validate-Tokenにはシステム毎に異なる値を設定すること
    http-request set-header X-SSL-Validate-Token        a3bbc802-4619-49de-8c74-b42ab4b9c2b5

# 通常認証
backend no-certificate
    mode    http
    balance roundrobin
    # 転送先のバックエンドサーバを指定
    # 複数のBaaS APIサーバが存在する場合は列挙すること
    server  certapi01  10.0.1.1:80
    #server  certapi02  10.0.1.2:80

    option  forwardfor

    http-request set-header X-SSL-Client-CertAuth-Validated 0

7.6.3. CRL更新用スクリプトの例

CRL更新用スクリプトの例は、以下の通りです。

#!/bin/sh

CONFIG_PATH=/etc/haproxy
HOST=10.0.255.75
CRL_FILE=crl.pem
CRL_TMP_FILE=crl.pem.tmp

CRL_FILE_PATH=${CONFIG_PATH}/${CRL_FILE}
CRL_TMP_FILE_PATH=${CONFIG_PATH}/${CRL_TMP_FILE}

# 作業ファイルが残っていれば削除
if [ -e ${CRL_TMP_FILE_PATH} ]; then
    echo "remove old tmp crl"
    rm –f ${CRL_TMP_FILE_PATH}
fi

# サーバからCRLを取得
wget http://${HOST}/${CRL_FILE} -O ${CRL_TMP_FILE_PATH}

# 取得成功した場合
if [ $? -eq 0 ] && [ -e ${CRL_TMP_FILE_PATH} ]; then
    # 既にCRLファイルが存在する場合
    if [ -e ${CRL_FILE_PATH} ]; then
    if diff -q ${CRL_FILE_PATH} ${CRL_TMP_FILE_PATH} > /dev/null ; then
        # CRLファイルが更新されていなかった
            echo "no update"
        else
            echo "crl update. reload service"
        # CRLファイルが更新されていた場合はファイルを置き換えて再読み込み
            mv ${CRL_TMP_FILE_PATH} ${CRL_FILE_PATH}
            sudo service haproxy reload
        fi
    else
    # CRLファイルが存在しない場合はサービス起動に失敗している 再起動する
        echo "get crl first time. restart service."
        mv ${CRL_TMP_FILE_PATH} ${CRL_FILE_PATH}
        sudo service haproxy restart
    fi
else
    echo "failed to get new crl" 1>&2
fi