🔑

1Password CLIを利用したセキュアな認証

に公開

モチベーション

Terraformなどでトークンやシークレットキーなどの認証情報を扱うとき、どのような手法を利用していますか。
ハードコーディングは漏洩リスクが高いため、環境変数を利用されている方が多いと思います。あるいは、.envファイルなどに切り出して取り回しをしやすくしていることもあるかと思います。
これらの方法は実際に多くの場面で利用されていますが、依然として漏洩してしまう可能性を残しています。

  • 認証情報を切り出したファイルが.gitignoreされていないなどにより公開リポジトリにpushしてしまう
  • GitHub Copilotなどの生成AIを用いる中で外部に送信されてしまう

上記のような可能性をできるだけ排除する方法を模索していたところ、1Password CLIを用いた方法に行き着いたので紹介します。

1Passwordと1Password CLI

1Password

1PasswordはユーザID・パスワードだけでなく、クレジットカード情報やパスキーなども管理できるパスワードマネージャです。
スマホなどでは生体認証を用いてログインして情報を閲覧・利用でき、非常に便利なため筆者も日頃から利用しています。

1Password CLI

1Passwordをターミナル等のコマンドラインで操作できる公式のツールです。
https://developer.1password.com/docs/cli/
特にop runコマンドが強力で、指定したコマンドの実行中だけ、1Passwordから取得した情報を環境変数としてインジェクトできます。

1Password CLIのインストール

https://developer.1password.com/docs/cli/get-started/

使い方

先程紹介したop runを例に、使い方を簡単にご紹介します。
利用までの流れは以下のとおりです。

  • 利用する認証情報の払い出し(サービス、ツールによるため割愛)
  • 1Passwordから秘密参照(利用する認証情報への参照情報)を取得
  • 環境変数等に秘密参照を記載
  • op runの実行

1Passwordから秘密参照(利用する認証情報への参照情報)を取得

以下の画像のように、1Passwordから取得したい認証情報の秘密参照を取得できます。

環境変数等に秘密参照を記載

1Passwordに保管している認証情報の参照先(秘密参照)を指定するために、環境変数、もしくはそれを切り出したファイル(ここでは.envとします)が必要になります。

  • 環境変数
export XXX_TOKEN={対象の認証情報への秘密参照}
  • .envファイル
echo XXX_TOKEN={対象の認証情報への秘密参照} >> .env

op runの実行

op runコマンドは1Passwordから対応する情報を読み込みつつ、サブプロセスに対して環境変数として情報をわたして後続のコマンドを実行してくれます。
そのため、環境変数(読み込まれた認証情報)のスコープはサブプロセス内となるため、コマンド実行時のみ有効となります。

  • 環境変数
op run -- <認証情報を利用するコマンド>
  • .envファイル
op run --env-file=".env" -- <認証情報を利用するコマンド>

初回実行時やセッションが変わる際は以下のような1Passwordへの認証が求められます。

認証を通して以下のように出力されるとokです。

$ op run --env-file="./.env" -- <認証情報を利用するコマンド>
<concealed by 1Password>

実際に認証情報を標準出力したい場合は--no-maskingオプションを追加してください。

実際に使ってみる

実際にterraformでのproxmoxにてtokenを利用する際に1Passwordから認証情報を取得してみます。
ここでは、特にリソース作成などは行わずterraform planが実行できるかを確認することで認証情報が正しく取得できているかを確認します。

ファイルの作成

terraformでproxmoxを扱う際はトークンidとシークレットを利用します。
また、terraformでは環境変数を読み込ませる際には、環境変数の先頭に「TF_VAR_<terraformで定義する変数名>」をつける必要があります。
以上を念頭に作成していきます。

.env
TF_VAR_pm_api_token_id ="op://Personal/Proxmox Token for Terraform/username"
TF_VAR_pm_api_token_secret="op://Personal/Proxmox Token for Terraform/credential"
main.tf
variable "pm_api_token_id" {
  description = "Proxmox API Token ID"
  type        = string
  
}
variable "pm_api_token_secret" {
  description = "Proxmox API Token Secret"
  type        = string
}

terraform {
  required_providers {
    proxmox = {
      source  = "telmate/proxmox"
      version = "3.0.2-rc01"
    }
  }
}

provider "proxmox" {
  # Configuration options
  pm_api_url = "https://192.168.0.8:8006/api2/json"
  pm_tls_insecure = true
  pm_api_token_id = var.pm_api_token_id
  pm_api_token_secret = var.pm_api_token_secret
}

resource "proxmox_vm_qemu" "resource-name" {
  name        = "terraform-test"
  target_node = "pve"
  disks {
    ide {
      ide2 {
        cdrom {
          iso = "Fedora-Server-dvd-x86_64-36-1.5.iso"
        }
      }
    }
  }
}

terraform planの実行

$ op run --env-file=".env" -- terraform plan
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # proxmox_vm_qemu.resource-name will be created
  + resource "proxmox_vm_qemu" "resource-name" {
      + additional_wait        = 5
      + agent                  = 0
      + agent_timeout          = 90
      + automatic_reboot       = true
      + balloon                = 0
      + bios                   = "seabios"
      + boot                   = (known after apply)
      + bootdisk               = (known after apply)
      + ciupgrade              = false
      + clone_wait             = 10
      + current_node           = (known after apply)
      + default_ipv4_address   = (known after apply)
      + default_ipv6_address   = (known after apply)
      + define_connection_info = true
      + desc                   = "Managed by Terraform."
      + force_create           = false
      + full_clone             = true
      + hotplug                = "network,disk,usb"
      + id                     = (known after apply)
      + kvm                    = true
      + linked_vmid            = (known after apply)
      + memory                 = 512
      + name                   = "terraform-test"
      + onboot                 = false
      + protection             = false
      + reboot_required        = (known after apply)
      + scsihw                 = "lsi"
      + skip_ipv4              = false
      + skip_ipv6              = false
      + ssh_host               = (known after apply)
      + ssh_port               = (known after apply)
      + tablet                 = true
      + tags                   = (known after apply)
      + target_node            = "pve"
      + unused_disk            = (known after apply)
      + vm_state               = "running"
      + vmid                   = (known after apply)

      + disks {
          + ide {
              + ide2 {
                  + cdrom {
                      + iso = "Fedora-Server-dvd-x86_64-36-1.5.iso"
                    }
                }
            }
        }

      + smbios (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.

問題なく認証できていそうです。
念の為、1Password上に登録されている認証情報(id)を変更してみて、認証に失敗することも確認してみます。(変更するところは割愛します。)

$ op run --env-file=".env" -- terraform plan
Planning failed. Terraform encountered an error while generating this plan.

╷
│ Error: 401 no such token 'terraforma' for user 'root@pam'
│ 
│   with provider["registry.terraform.io/telmate/proxmox"],
│   on provider.tf line 20, in provider "proxmox":20: provider "proxmox" {
│ 
╵

idのスニペットを"terraforma"にしたため、ちゃんとUnauthorized Errorが出力されました。1Passwordの情報を見に行けていますね。

まとめ

1Password CLIを利用したセキュアな認証を紹介しました。
認証情報をPC上に平文で置くことがなくなるため、不注意による漏洩のリスクを更に低減できるのではないかと思います。
筆者は1Passwordを長く利用していましたが、CLIの活用まではできていなかったため今後は活用していこうと思います。
また、開発チームでの利用においても共有のVaultに登録することで個別の設定不要で利用できるかもしれません。(利用者を区別するために認証情報を分けるべきかもしれませんが。)
同様の方法はその他パスワードマネージャでも可能と思いますが、身近なサービスでもあることから、すでに利用している方は是非活用してみてください。

Discussion