まえがき
筆者はよくスクレイピングをしているのですが、アクセスしているサイトの一つに「一定期間毎にパスワード変更を要求される」ものが存在します。
手動でパスワードを変更するだけでも結構面倒なのですが、それと同時にスクレイピングしているPCの.envファイルを変更するのがあまりにもやりたくなかったので、1Passwordで全てを管理しようと試みてみました。
そこで今回は、Dockerで1Passwordを使用する方法です。個人プランでも使用可能だと思われます。(筆者は家族プランで契約しています。)
前提
1Passwordの構造は少しややこしいのですが以下のようになっています。
- vaultにitemが保存されている
- serverはvaultに対してのアクセス権限を持っている
- server毎にtokenを発行する
簡単に図示すると以下の通りです。
server - vault - item
|
token
serverは各vaultに対してそれぞれread/writeの権限を管理でき、tokenはserverの権限を超えない範囲で各vaultに対するread/writeの権限を保持できます。
serverは1Passwordのデフォルトに存在するPrivate vaultに対するアクセス権限を所持できないので、開発用の新たなvaultを作成する必要があります。(後ほど作成方法も紹介します。)
1Password Cliのインストール
tokenの発行はGUIでもできますが、CLIでも可能です。CLIで発行する場合、1Password Cliのインストールが必要ですので、その方法を説明いたします。
brewを導入済みの方は、
brew install --cask 1password-cli
でインストール可能です。
筆者の環境はversion2.16.0です。1系と2系でコマンドの形態が大きく異るため、誤って1系をインストールした場合はやり直しを推奨します。
$ op --version
> 2.16.0
それ以降の初期設定についてはこちらなどを参考にするかとよろしいかと思います。
tokenの発行
CLIで発行する場合、以下の手順になります。
$ op vault create ${vault}
ID: ${ID}
Name: ${vault}
Type: USER_CREATED
Attribute version: 1
Content version: 1
Items: 0
Created: now
Updated: now
$ op connect server create ${server}
Set up a Connect server.
UUID: ${UUID}
Credentials file: /current/directory/1password-credentials.json
$ op connect vault grant --server ${server} --vault ${vault}
Connect server ${server} ${UUID} has been successfully granted access to vault ${vault} ${ID}.
$ op connect token create ${token} --server ${server} --vault ${vault}
(ここにtokenが出力されるので控える)
この際出力されたtoken及び1password-credentials.json
はこのあと使いますので控えてください。
${vault}
, ${server}
, ${token}
にはお好みの名前を入力してください。
Dockerで1Passwordを利用する
基本的にはこちらの記事を参考にするとよろしいかと思いますが、1PasswordにアクセスするPythonファイルもDocker化したかったので多少手を加えております。
version: "3.4"
services:
py:
container_name: py
build: py
volumes:
- ./py:/root/app
environment:
TZ: $TZ
OP_CONNECT_TOKEN: $OP_CONNECT_TOKEN
VAULT_ID: $VAULT_ID
op-connect-api:
container_name: op-connect-api
image: 1password/connect-api:latest
volumes:
- "./1password-credentials.json:/home/opuser/.op/1password-credentials.json"
- "./data:/home/opuser/.op/data"
op-connect-sync:
image: 1password/connect-sync:latest
volumes:
- "./1password-credentials.json:/home/opuser/.op/1password-credentials.json"
- "./data:/home/opuser/.op/data"
同一ネットワークに属するDockerコンテナからアクセスする予定なので、ポートの開放等は必要ありません。
先程保存した1password-credentials.json
はDockerコンテナ内で使用するため、docker-compose.yml
と同一のディレクトリに保存してください。
from onepasswordconnectsdk.client import (
new_client_from_environment
)
from onepasswordconnectsdk.models import (
Item, ItemVault, Field
)
import string
import secrets
import os
from time import sleep
def pass_gen(size=64):
chars = string.ascii_uppercase + string.ascii_lowercase + string.digits
# if you want to add special characters
# chars += '!@^*-_=+?/.>,<"\\:;|]}[{\'`~%&$#()'
return ''.join(secrets.choice(chars) for x in range(size))
# creating client using OP_CONNECT_TOKEN environment variable
client = new_client_from_environment("http://op-connect-api:8080")
# creating Item
item = Item(vault=ItemVault(id=os.environ["VAULT_ID"]),
title=pass_gen(5),
category="LOGIN",
tags=["1password-connect"],
fields=[Field(
value="new_user",
purpose="USERNAME"
),
Field(
value=pass_gen(),
purpose="PASSWORD"
)],
)
created_item = client.create_item(os.environ["VAULT_ID"], item)
print('created', created_item)
item_id = created_item.id
sleep(2)
# get Item
get_item = client.get_item(item_id, os.environ["VAULT_ID"])
print('got', get_item)
sleep(2)
# update item
update_item = get_item
update_item.fields[1].value = pass_gen()
updated_item = client.update_item(item_id, os.environ["VAULT_ID"], update_item)
print('updated', updated_item)
sleep(2)
# delete item
client.delete_item(item_id, os.environ["VAULT_ID"])
vaults = client.get_vaults()
for vault in vaults:
print(vault)
補足
こちらを見るとわかりますが、VAULT_ID
はVAULT_NAME
でも構いません。
プログラムから作成した直後にアイテムにアクセスできなかったりしたので、適当にsleepを入れています。
GitHubリポジトリはこちら
こうしてPythonから1Passwordにアクセスできました
おわりに
スクレイピングを始めとする自動化はパスワード管理がネックになりがちですが、1Passwordならそれを解決することができます。みなさまも1Passwordの導入を検討してみてはいかがでしょうか。(1Passwordの広告案件ではありません。念の為。)