リモートAPI認証#

LXDデーモンとのリモート通信は、HTTPS上のJSONを使って行われます。

リモートAPIにアクセスするためには、クライアントはLXDサーバーとの間で認証を行う必要があります。 以下の認証方法がサポートされています。

TLSクライアント証明書#

認証にTLSクライアント証明書を使用する場合、クライアントとサーバーの両方が最初に起動したときにキーペアを生成します。 サーバーはそのキーペアをLXDソケットへの全てのHTTPS接続に使用します。 クライアントは、その証明書をクライアント証明書として、あらゆるクライアント・サーバー間の通信に使用します。

証明書を再生成させるには、単に古いものを削除します。 次の接続時には、新しい証明書が生成されます。

通信プロトコル#

通信プロトコルは TLS1.3 以上に対応しています。 すべての通信には完全な前方秘匿を使用し、暗号は強力な楕円曲線(ECDHE-RSA や ECDHE-ECDSA など)に限定してください。

LXD_INSECURE_TLS環境変数をクライアントとサーバーの両方で設定することによりLXDが TLS 1.2 を受け入れるようにすることはできます。 しかし、これはサポートされる構成ではなく、時代遅れな企業プロキシを使うために強制される場合にのみ使用すべきです。

生成される鍵は最低でも4096ビットのRSA、できれば384ビットのECDSAが望ましいです。 署名を使用する場合は、SHA-2署名のみを信頼すべきです。

我々はクライアントとサーバーの両方を管理しているので、壊れたプロトコルや暗号の下位互換をサポートする理由はありません。

信頼できるTLSクライアント#

LXDサーバーが信頼するTLS証明書のリストは、lxc config trust listで取得できます。

信頼できるクライアントは以下のいずれかの方法で追加できます。

サーバーとの認証を行うワークフローは、SSHの場合と同様で、未知のサーバーへの初回接続時にプロンプトが表示されます。

  1. ユーザーが lxc remote add でサーバーを追加すると、HTTPS でサーバーに接続され、その証明書がダウンロードされ、フィンガープリントがユーザーに表示されます。

  2. ユーザーは、これが本当にサーバーのフィンガープリントであることを確認するよう求められます。これは、サーバーに接続して手動で確認するか、サーバーにアクセスできる人に info コマンドを実行してフィンガープリントを比較してもらうことで確認できます。

  3. サーバーはクライアントの認証を試みます。

    • クライアント証明書がサーバーのトラストストアにある場合は、接続が許可されます。

    • クライアント証明書がサーバーのトラストストアにない場合、サーバーはユーザーにトークンまたはトラストパスワードの入力を求めます。 提供されたトークンまたはトラストパスワードが一致した場合、クライアント証明書はサーバーのトラストストアに追加され、接続が許可されます。 そうでない場合は、接続が拒否されます。

クライアントへの信頼を取り消すには、lxc config trust remove FINGERPRINTでそのクライアント証明書をサーバーから削除します。

TLSクライアントを1つまたは複数のプロジェクトに制限することが可能です。 この場合、クライアントは、グローバルな構成変更の実行や、アクセスを許可されたプロジェクトの構成(制限、制約)の変更もできなくなります。

アクセスを制限するには、lxc config trust edit FINGERPRINTを使用します。 restrictedキーをtrueに設定し、クライアントのアクセスを制限するプロジェクトのリストを指定します。 プロジェクトのリストが空の場合、クライアントはどのプロジェクトへのアクセスも許可されません。

信頼できる証明書をサーバーに追加する#

信頼できるクライアントを追加するには、そのクライアント証明書をサーバーのトラストストアに直接追加するのが望ましい方法です。 これを行うには、クライアント証明書をサーバーにコピーし、lxc config trust add <file>で登録します。

トラストパスワードを使ったクライアント証明書の追加#

クライアント側から新しい信頼関係を確立できるようにするには、サーバーにトラストパスワード(core.trust_password)を設定する必要があります。クライアントは、プロンプト時にトラストパスワードを入力することで、自分の証明書をサーバーのトラストストアに追加することができます。

本番環境では、すべてのクライアントが追加された後に、core.trust_passwordの設定を解除してください。 これにより、パスワードを推測しようとするブルートフォース攻撃を防ぐことができます。

トークンを使ったクライアント証明書の追加#

トークンを使って新しいクライアントを追加することもできます。 トークンは調整可能な時間(core.remote_token_expiry)を過ぎるか一度使用すると無効になるため、これはトラストパスワードを使用するよりも安全な方法です。

この方法を使用するには,クライアント名の入力を促す lxc config trust add を呼び出して,各クライアント用のトークンを生成します。 その後,クライアントは,トラストパスワードの入力を求められたときに生成されたトークンを提供することで,自分の証明書をサーバーのトラストストアに追加することができます。

注釈

LXD サーバーが NAT の後ろ側にいる場合、クライアント用のリモートを追加する際には外部のパブリックアドレスを指定する必要があります。

lxc remote add <name> <IP_address>

admin パスワードのプロンプトが表示されたら、生成されたトークンを入力してください。

サーバーでトークンを生成する際、 LXD はクライアントがサーバーにアクセスするために使える IP アドレスのリストを含めます。 しかし、サーバーが NAT の後ろ側にいる場合、これらのアドレスはクライアントが接続できないローカルアドレスの場合があります。 その場合、手動で外部アドレスを指定する必要があります。

あるいは、クライアントはリモートの追加時にトークンを直接提供することもできます。lxc remote add <name> <token>.

PKI システムの使用#

PKIの設定では、システム管理者が中央のPKIを管理し、すべてのLXDクライアント用のクライアント証明書とすべてのLXDデーモン用のサーバー証明書を発行します。

PKIモードを有効にするには、以下の手順を実行します。

  1. すべてのマシンにCA(認証局)の証明書を追加します。

    • クライアントの設定ディレクトリ(~/.config/lxcまたはSnapユーザーの場合は~/snap/lxd/common/config)にclient.caファイルを配置する。

    • server.caファイルをサーバーの設定ディレクトリ(/var/lib/lxdまたはSnapユーザーの場合は/var/snap/lxd/common/lxd)に置く。

  2. CAから発行された証明書をクライアントとサーバーに配置し、自動生成された証明書を置き換える。

  3. サーバーを再起動します。

このモードでは、LXDデーモンへの接続はすべて、事前に発行されたCA証明書を使って行われます。

もしサーバー証明書がCAによって署名されていなければ、接続は単に通常の認証メカニズムを通過します。 サーバー証明書が有効でCAによって署名されていれば、ユーザに証明書を求めるプロンプトを出さずに接続を続行します。

生成された証明書は自動的には信頼されないことに注意してください。そのため、信頼できるTLSクライアントで説明している方法のいずれかで、サーバーに追加する必要があります。

OpenID Connect認証#

LXDはOpenID Connectを使用して、OIDC(OpenID Connect)アイデンティティプロバイダーを通じてユーザーを認証することをサポートしています。

注釈

OpenID Connect認証は現在開発中です。 LXD 5.13から、OpenID Connectを通じた認証がサポートされていますが、まだユーザーロールの取り扱いはありません。 設定されたOIDCアイデンティティプロバイダーを通じて認証するすべてのユーザーは、LXDへのフルアクセスを得ます。

LXDをOIDC認証を使用するように設定するには、oidc.*サーバー設定オプションを設定します。

OIDC認証で設定されたLXDサーバーを指すリモートを追加するには、lxc remote add <remote_name> <remote_address>を実行します。 その後、ウェブブラウザで認証を求められ、LXDが使用するデバイスコードを確認する必要があります。 LXDクライアントはその後、アクセストークンとリフレッシュトークンを取得し保存し、それらをLXDとのすべてのやりとりに使用します。

Candidベースの認証#

candid.*サーバーオプションによりCandid認証を使うようにLXDを設定できます。 この場合、サーバーで認証を行おうとするクライアントは、candid.api.urlで指定された認証サーバーからディスチャージトークンを取得しなければなりません。

認証サーバーの証明書は、LXDサーバーから信頼されていなければなりません。

Candid/Macaroon認証を設定したLXDサーバーにリモートポインティングを追加するには、lxc remote add REMOTE ENDPOINT --auth-type=candidを実行します。 ユーザーを確認するために、クライアントは認証サーバーが要求する認証情報の入力を求められます。 認証が成功した場合、クライアントはLXDサーバーに接続し、認証サーバーから受け取ったトークンを提示します。 LXDサーバーはトークンを検証し、リクエストを認証します。 トークンはクッキーとして保存され、クライアントがLXDにリクエストするたびに提示されます。

Candidベースの認証を設定する方法については、チュートリアルのCandid authentication for LXDを参照してください。

役割ベースのアクセスコントロール(RBAC)#

LXDはCanonicalのRBACサービスとの連携をサポートしています。RBACはUbuntu Proサブスクリプションに含まれています。 Candidベースの認証と組み合わせることで、RBACは、APIクライアントがLXD上でできることを制限するために使うことができます。

このような設定では、認証はCandidを通して行われ、RBACサービスはユーザー/グループの関係に役割を維持します。 ロールは個々のプロジェクトにも、すべてのプロジェクトにも、あるいはLXDインスタンス全体にも割り当てることができます。

プロジェクトに適用された場合のロールの意味は以下の通りです。

  • 監査役: プロジェクトへの読み取り専用のアクセス権

  • ユーザー: 通常のライフサイクルアクション(開始、停止、...)を実行する能力。 インスタンスでのコマンド実行、コンソールへのアタッチ、スナップショットの管理など。

  • オペレーター: 上記のすべての機能に加え、インスタンスやイメージの作成、再設定、削除を行う機能 インスタンスとイメージの作成、再設定、削除

  • 管理者: 上記の機能に加えて、プロジェクト自体を再構成する機能を持つ

重要

制限のないプロジェクトでは、auditoruserのロールだけが、ホストへのルートアクセスを任せられないユーザーに適しています。

また、制限付きプロジェクト では、適切に設定されていれば、operator ロールも安全に使用することができます。

LXDサーバーでRBACを有効にするにはrbac.*サーバーオプションを設定してください。これはcandid.*オプションのスーパーセットで、LXDをRBACサービスに統合できます。

TLS サーバー証明書#

LXD は ACME サービス (例えば Let's Encrypt) を使ったサーバー証明書の発行をサポートします。

この機能を有効にするには以下のサーバー設定をしてください。

  • acme.domain: 証明書を発行するドメイン。

  • acme.email: ACME サービスのアカウントに使用する email アドレス。

  • acme.agree_tos: ACME サービスの利用規約に同意するためには true に設定する必要あり。

  • acme.ca_url: ACME サービスのディレクトリ URL。デフォルトでは LXD は "Let's Encrypt" を使用。

この機能を利用するには、 LXD は 80 番ポートを開放する必要があります。 これは HAProxy のようなリバースプロキシを使用することで実現できます。

以下は lxd.example.net をドメインとして使用する HAProxy の最小限の設定です。 証明書が発行された後、 LXD はhttps://lxd.example.net/ でアクセスできます。

# Global configuration
global
  log /dev/log local0
  chroot /var/lib/haproxy
  stats socket /run/haproxy/admin.sock mode 660 level admin
  stats timeout 30s
  user haproxy
  group haproxy
  daemon
  ssl-default-bind-options ssl-min-ver TLSv1.2
  tune.ssl.default-dh-param 2048
  maxconn 100000

# Default settings
defaults
  mode tcp
  timeout connect 5s
  timeout client 30s
  timeout client-fin 30s
  timeout server 120s
  timeout tunnel 6h
  timeout http-request 5s
  maxconn 80000

# Default backend - Return HTTP 301 (TLS upgrade)
backend http-301
  mode http
  redirect scheme https code 301

# Default backend - Return HTTP 403
backend http-403
  mode http
  http-request deny deny_status 403

# HTTP dispatcher
frontend http-dispatcher
  bind :80
  mode http

  # Backend selection
  tcp-request inspect-delay 5s

  # Dispatch
  default_backend http-403
  use_backend http-301 if { hdr(host) -i lxd.example.net }

# SNI dispatcher
frontend sni-dispatcher
  bind :443
  mode tcp

  # Backend selection
  tcp-request inspect-delay 5s

  # require TLS
  tcp-request content reject unless { req.ssl_hello_type 1 }

  # Dispatch
  default_backend http-403
  use_backend lxd-nodes if { req.ssl_sni -i lxd.example.net }

# LXD nodes
backend lxd-nodes
  mode tcp

  option tcp-check

  # Multiple servers should be listed when running a cluster
  server lxd-node01 1.2.3.4:8443 check
  server lxd-node02 1.2.3.5:8443 check
  server lxd-node03 1.2.3.6:8443 check

失敗のシナリオ#

以下のシナリオでは認証は失敗します。

サーバー証明書が変更された場合#

サーバー証明書は以下の場合に変更されるかも知れません。

  • サーバーが完全に再インストールされたため新しい証明書に変わった。

  • 接続がインターセプトされた (MITM)。

このような場合、このリモートの設定内のフィンガープリントと証明書のフィンガープリントが一致しないため、クライアントはサーバーへの接続を拒否します。

この場合サーバー管理者に連絡して証明書が実際に変更されたのかを確認するのはユーザ次第です。 実際に変更されたのであれば、証明書を新しいものに置き換えるか、リモートを削除して追加し直すことができます。

サーバーとの信頼関係が取り消された場合#

別の信頼されたクライアントまたはローカルのサーバー管理者がサーバー上で対象のクライアントの信頼エントリを削除した場合、そのクライアントに対するサーバーの信頼関係は取り消されます。

この場合、サーバーは引き続き同じ証明書を使用していますが、全ての API 呼び出しは対象のクライアントが信頼されていないことを示す 403 のステータスコードを返します。