[自分用メモ][container][docker]reverse proxyとしてTraefikを使用し、docker環境でLet’s Encryptを使用する。を1系から2.0系へ移行する。

2019-09-19 10:59:06AIX、UNIX、Linux, Containercontainer, docker, docker-compose, https, Let's Encrypt, reverse proxy, traefik

以前から一部の環境にTraefik v1を使用してcontainer環境にLet’s Encryptを提供していましたが、Traefikの2.0系が2019年9月17日にGAリリースされたので早速環境を移行することにしました。

呟き

実はdocker pullした際にtagがlatestになっていたため、v2へ予期せぬタイミングで移行してしまい、うまく動作しなくなったと焦っていたのは内緒です。

以前の記事

公式サイト

ちなみにv1からv2へのアップデートに伴い、コードそのものの見直しが行われ、設定においてTOML以外にもYAMLが使用できるようになりましたが、一方で設定項目についてはv1との互換性がありません。

v2での主な機能は以下の通り。

  • 設定ファイルについてYAMLフォーマットが使用できるようになった。
  • TCP Support with SNI Routing & Multi-Protocol Ports
    • Over TLS, Traefik routes TCP requests based on the SNI
    • HTTP & TCP on the same port? Yes, there is Traefik for that!
  • Fully Customize Your Routes with Middleware
  • A Chain to Bind Them All
  • A New Dashboard & WebUI
  • Canary Deployments with Service Load Balancers
  • Mirroring with Service Load Balancers
  • APIの拡張

個人的にはダッシュボードのUIが見直され、v1よりは見やすく、また連携も把握しやすくなったかなと思います。

公式ブログより

公式ドキュメント

移行ガイド

POINT

2019年9月26日現在、ドキュメントの整備が済んだようです。

この記事を執筆時点では大半の項目がTODOとなっており、ドキュメントの整備は間に合っていないようです。とりあえず他のページを見ながら行えば何とかなると思います。

移行してみた

Traefik側の設定

v1で使用していたTraefikの設定(traefik.toml)内容は以下の通りです。

debug = false
logLevel = "ERROR"
defaultEntryPoints = ["https", "http"]
[entryPoints]
  [entryPoints.http]
  address = ":80"
    [entryPoints.http.redirect]
    entryPoint = "https"
  [entryPoints.https]
  address = ":443"
    [entryPoints.https.tls]
      minVersion = "VersionTLS12"
      cipherSuites = [
        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
      ]
[retry]
[api]
[acme]
  email = "example@example.com"
  storage = "acme.json"
  onHostRule = true
  #caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
  caServer = "https://acme-v02.api.letsencrypt.org/directory"
  entryPoint = "https"
  acmeLogging = true
    [acme.httpChallenge]
    entryPoint = "http"
[docker]
  endpoint = "unix:///var/run/docker.sock"
  watch = true
  domain = "example.com"
  exposedByDefault = false

v2では以下のようになりました(あまり把握できていないため、もしかしたら間違いがあるかもしれません)。

[global]
  checkNewVersion = true
  sendAnonymousUsage = true
[entryPoints]
  [entryPoints.https]
  	address = ":443"
  [entryPoints.hub]
    address = ":3012"
[tls.options]
  [tls.options.default]
    minVersion = "VersionTLS12"
    cipherSuites = [
      "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
      "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
      "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
    ]
	[tls.options.mintls13]
		minVersion = "VersionTLS13"
        
[http.routers]
    [http.router.router0]
        rule = "Host('bitwarden.example.com')"
        service = "bitwarden"
        entrypoints = ["http"]
        middlewares = ["redirect"]
    [http.routers.router1]
        rule = "Host('bitwarden.example.com')"
        service = "bitwarden"
        entrypoints = ["https"]
        [http.routers.router1.tls]
[http.middlewares]
    [http.middlewares.redirect.redirectScheme]
        scheme = "https"
[tcp.routers]
    [tcp.routers.bitwarden]
    entryPoints = ["https", "hub"]
    rule = "(HostSNI(`bitwarden.example.com`) && Path(`/notifications/hub`))"
    service = "bitwarden"
[retry]
[api]
    insecure = true
    dashboard = false
    debug = false
[certificatesResolvers.sample.acme]
    #caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
    email = "example@example.com"
    storage = "/acme/acme.json"
    [certificatesResolvers.sample.acme.tlsChallenge]
[providers.docker]
    endpoint = "unix:///var/run/docker.sock"
    watch = true
    exposedByDefault = false
    network = "https-network"
    swarmMode = false
2019年9月26日:追記

httpsへのリダイレクトの設定方法が分かったので追記。

グローバルな設定はトップレベルに書いておけば良かったのが、改めて[global]というメニューが用意されそちらに記入するようになっていました。defaultEntryPointsは見つかりませんでしたが、特に使用しなくても動作はしました。

cipherSuitesはentrypoint別から[tls.options.default]へ移動になっていました。

Let’s Encrypt関連は、certificatesResolversという項目に移動になり、またACMEを利用した証明書の更新については従来のHTTP([certificatesResolvers.sample.acme.httpChallenge.entryPoint])での更新だけでなく、TLS([certificatesResolvers.sample.acme.tlsChallenge])やDNS([certificatesResolvers.sample.acme.dnsChallenge])を利用したものも使用できるようになっていました。

CAUTION

以前にも書きましたが、Let’s Encryptによる証明書を使用するとき、実稼働前にテスト用サーバで認証した方が良いです。

#- "--log.level=DEBUG"
#- "--certificatesresolvers.mytlschallenge.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"

If you uncommented the acme.caserver line, you will get an SSL error, but if you display the certificate and see it was emitted by Fake LE Intermediate X1 then it means all is good. (It is the staging environment intermediate certificate used by let’s encrypt). You can now safely comment the acme.caserver line, remove the letsencrypt/acme.json file and restart Traefik to issue a valid certificate.

https://docs.traefik.io/v2.0/user-guides/docker-compose/acme-tls/#setup

問題がなければ、caServerの行をコメントにしておけば本番向けの認証サーバで認証を行うようになります。

CAUTION

tcp.routers.bitwardenのruleについて、最初はdocker-compose file側に記載していたのですが、複数のルールを記述した場合なぜかエラーになりうまく動作しなかったので、traefik側に記述することで動作すること確認しています。

良く使用するdockerについても単独の設定項目ではなく、色々なネットワークサービスのまとまりであるprovidersにまとめられていました。

docker側の設定

以前のdocker-compose.ymlの内容は以下の通りです。

version: '3'
services:
  bitwarden:
  image: mprasil/bitwarden:alpine
  restart: always
  volumes:
    - ./bw-data/:/data/
  ports:
    - 1024:1024
  environment:
    ROCKET_PORT: "1024"
    WEBSOCKET_ENABLED: "true"
    SIGNUPS_ALLOWED: "false"
    ADMIN_TOKEN: ""
    DOMAIN: "https://bitwarden.example.com"
    SMTP_HOST: ""
    SMTP_FROM: "<bitwarden@example.com>"
    SMTP_PORT: "true"
    SMTP_SSL: "true"
    SMTP_USERNAME: ""
    SMTP_PASSWORD: ""
  labels:
    traefik.docker.network: "https-network"
    traefik.enable: "true"
    traefik.basic.port: "1024"
    traefik.basic.frontend.rule: "Host:bitwarden.example.com"
    traefik.basic.protocol: "http"
    traefik.hub.frontend.rule: "Host:bitwarden.example.com;Path:/notifications/hub"
	traefik.hub.port: "3012"
  networks:
    - https-network
    
networks:
  https-network:
    external: true

Traefik v2で使用するにあたって以下のように修正することになりました。

version: '3'
services:
 bitwarden:
  image: bitwardenrs/server
  restart: always
  volumes:
      - ./bw-data/:/data/
  labels:
      - "traefik.enable=true"
      - "traefik.http.routers.bitwarden.rule=Host(`bitwarden.example.com`)"
      - "traefik.http.routers.bitwarden.entryPoints=https"
      - "traefik.http.routers.bitwarden.tls.certresolver=sample"
      - "traefik.tcp.routers.bitwarden.entryPoints=hub"
  environment:
    DOMAIN: "https://bitwarden.example.com"
    SMTP_HOST: ""
    SMTP_FROM: "<bitwarden@example.com>"
    SMTP_PORT: "true"
    SMTP_SSL: "true"
    SMTP_USERNAME: ""
    SMTP_PASSWORD: ""
  ports:
    - 1024:80
  networks:
    - https-network
    
networks:
  https-network:
    external: true

大事なのはlabels:でこればv1と一緒ですが、設定項目が若干変わっています。

POINT

traefik.enable=trueは依然と同様にtraefikの管理下に入れるかどうかの指定となります。他の項目についてはフロントエンドからの通信を捌くということになり、 traefik.http.routers.my-container.rule=Host(my-domain)traefik.http.routers.my-container.entrypointsで、問い合わせのあったドメインについてどのポートへ着信を振り分けるか、traefik.http.routers.my-container.tls.certresolverではどのACME情報を使ってHTTPSを提供するか、

ということを指定することで、以前と同様にLet’s Encrypt環境で提供できるようになりました。

とりあえずこちらで自分の環境では以前と同様にHTTPSでのサービス提供が出来るようになりました。

ただ、ちゃんと理解できているとは言い難いので、間違い等ありましたらご指摘等頂けますと助かります。

参考にしたサイト