/var/www/yatta47.log

/var/www/yatta47.log

やったのログ置場です。スクラップみたいな短編が多いかと。

Terraform × Proxmox: "unable to authenticate user over SSH" の原因と対処法

bpg/proxmox providerで proxmox_virtual_environment_file(snippets)を作ろうとしたらSSH認証エラーになった。調べてみたところ、providerがファイルアップロードだけSSH/SFTP経由で行うためだった。ってことで、APIトークンとは別にSSH接続の設定が必要だということがわかったという記録です。

エラー内容

bpg/proxmox providerでcloud-init用のsnippetsをアップロードしようとしたら、こういうエラーが出たんですよ。

Error: failed to open SSH client: unable to authenticate user "" over SSH
to "192.168.11.50:22".
Please verify that ssh-agent is correctly loaded with an authorized key
via 'ssh-add -L'
(NOTE: configurations in ~/.ssh/config are not considered by the provider):
failed to dial 192.168.11.50:22: ssh: handshake failed:
ssh: unable to authenticate, attempted methods [none password],
no supported methods remain

APIトークンはちゃんと設定してあって、VM作成とか起動停止は普通に動いてたんですよね。なのにsnippetsのアップロードだけSSH?ってなりました。

原因

bpg/proxmox providerは、操作の種類によって通信経路を使い分けてます。

Terraform (bpg/proxmox provider)
  │
  ├─ VM作成・設定変更・起動停止
  │    └─→ Proxmox REST API (port 8006)
  │         認証: APIトークン
  │
  └─ ファイルアップロード (snippets等、APIが非対応なファイル)
       └─→ SSH/SFTP (port 22)
            認証: SSH鍵 + ssh-agent
操作 経路 認証 ポート
VM作成、設定変更、起動停止 Proxmox REST API APIトークン 8006
snippets等のアップロード SSH/SFTP SSH鍵 22

Proxmox APIのアップロードエンドポイント(/nodes/{node}/storage/{storage}/upload)はISOやvztmplなど一部のファイルタイプしか対応していなくて、snippetsのような任意テキストファイルは対象外なんですよね。だからproviderがSSH/SFTPでProxmoxホストに直接ファイルを置きに行く設計になってます。

providerのバグじゃなくて、Proxmox API側の制約をSSHで補っている形。GitHub上でも「SSHなしでsnippetsをアップロードしたい」というIssue(#2112)が立ってます。

解決方法

3ステップです。

1. Proxmoxホストに鍵認証でSSH接続できるようにする

ssh-copy-id root@<proxmox-host>

接続確認:

ssh root@<proxmox-host> hostname
# → pve(Proxmoxのホスト名が返ればOK)

2. providerにsshブロックを追加する

provider "proxmox" {
  endpoint  = var.proxmox_endpoint
  api_token = var.proxmox_api_token
  insecure  = true

  ssh {
    agent    = true
    username = "root"
  }
}

username = "root" がないとSSHユーザー名が空のままになって、冒頭の unable to authenticate user "" が出ます。

3. ssh-agentを起動して鍵をロードする

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

確認:

ssh-add -l
# → 256 SHA256:xxxxx ... (ED25519) のように鍵が表示されればOK
# (エラーメッセージ中の -L は公開鍵全文の出力、-l はフィンガープリント一覧。確認用途はどちらでもOK)

ここまでやって terraform apply でSSHエラーが消えれば設定完了。terraform plan ではSSH接続を試さない場合があるので、最終確認は apply で行ってください。

eval "$(ssh-agent -s)" はシェルセッション限りなので、ターミナルを閉じると無効になります。CI/CDやsystemd timerから実行する場合は、providerの private_key オプションで鍵ファイルを直接指定する方法を検討してください。

  ssh {
    username    = "root"
    private_key = file(pathexpand("~/.ssh/id_ed25519"))
    # ssh-agentが使えないCI環境向け。agent = true は不要
  }

秘密鍵ファイルの配置場所とパーミッションには注意してください。

なぜ気づきにくいか

このハマりが厄介なのは、段階的に表面化するところです。

  1. VM作成まではAPIトークンだけで正常に動く → 「認証設定は完了した」と思い込む
  2. cloud-initのsnippetsを追加した途端にSSHエラーが出る → 「何も変えてないのに壊れた」感覚
  3. エラーメッセージにSSHと書いてあるけど、Terraform providerの文脈でSSHが出てくると思ってない

providerのドキュメントにSSH設定の必要性は書いてあるんですけど、「VM作成」のチュートリアルだけ読んで進めるとSSH設定を飛ばしがち。

あと、~/.ssh/config の設定はproviderに無視されるので注意。エラーメッセージにも configurations in ~/.ssh/config are not considered by the provider って書いてあります。

セットアップチェックリスト

bpg/proxmox providerでsnippetsを使う場合、最初に確認しておくべきことをまとめておきます。

□ APIトークン設定済み(provider.endpoint + api_token)
□ SSH鍵認証設定済み(ssh-copy-id + provider.ssh ブロック)
□ ssh-agentが起動している(ssh-add -l で確認)
□ Proxmoxストレージで Snippets コンテンツタイプが有効

4番目の「Snippetsコンテンツタイプの有効化」も忘れがちです。SSH設定が完了してもストレージ側でsnippetsが無効だと別のエラーになります。有効化はProxmox UIから「データセンター → ストレージ → local → 編集」でSnippetsにチェックを入れるのが安全です。CLIで pvesm set local --content ... を使う場合は既存の設定を上書きするので、先に pvesm config local で現在のcontent設定を確認してからにしてください。

まとめ

bpg/proxmox providerでsnippetsがSSHエラーになるのは、Proxmox APIがsnippetsのアップロードに対応していなくて、providerがSSH/SFTPで代替しているから。APIトークンとSSH鍵認証は別の認証経路なので、両方を設定する必要があります。

参考