kvtool について
kvtool は、様々な設定ファイル形式(.env、JSON、YAML、Vault、S3 など)を統一的なインターフェースで扱う CLI ツールです。
特徴
- 統一インターフェース: ローカルファイル、Vault、S3 などを同じ方法でアクセス
- マルチテナント: namespace による環境切り替え
- フォーマット変換: dotenv ↔ JSON ↔ YAML
- 接続確認: ストアの接続テスト機能
ユースケース
環境構築の初期段階で、様々な構成ファイルを統合して環境を初期化することを想定しています。
コマンド体系
kvtool
├── file (低レベル: 直接アクセス)
│ ├── load (env, vault, json, yaml, etc.)
│ └── convert (dotenv, yaml)
└── store (高レベル: 設定ファイル経由)
├── init
├── connect
├── load
└── serve (未実装)
ライセンス
MIT
インストール
ビルドとインストール
Makefileを使用
# ビルドとインストール
make install
直接ビルド
# バイナリをbin/ディレクトリに生成
go build -o bin/kvtool .
動作確認
kvtool --version
kvtool --help
必要な環境
- Go 1.21 以上
- (オプション)HashiCorp Vault(Vault 連携時)
- (オプション)AWS CLI/認証情報(S3 連携時)
クイックスタート
設定ファイルの初期化
# カレントディレクトリに .kvtool.yml を作成
kvtool store init
# グローバル設定ファイル (~/.config/kvtool/.kvtool.yml) を作成
kvtool store init --global
ストアからデータ取得
# .envストアからAPP_NAMEを取得(JSON形式で出力)
kvtool store load .env/APP_NAME
# key=value形式で出力
kvtool store load .env/APP_NAME -o raw
# Vaultから取得
kvtool store load vault/db/password
# S3から取得
kvtool store load s3config/app.json
接続確認
# 設定ファイル内の全ストアをテスト
kvtool store connect
# 特定のストアのみテスト
kvtool store connect s3-test
ファイル直接操作(低レベル)
設定ファイルを使わず、直接ファイルシステムにアクセスする場合:
# 環境変数をJSON化
kvtool file load env
# Vaultから直接取得
kvtool file load vault <path> --addr http://localhost:8200 --token root
# 標準入力からdotenv変換
cat .env | kvtool file convert dotenv
設定例
.kvtool.yml の例:
version: 0.1
namespaces:
default:
local-env:
driver: local
args:
root: ./config
transform: dotenv
vault-prod:
driver: vault
args:
addr: http://localhost:8200
token: root
mount: secret
s3-config:
driver: s3
args:
bucket: my-bucket
region: us-east-1
endpoint: http://localhost:9000
ストア構成ファイル
kvtool のストア構成ファイルは YAML 形式 (.kvtool.yml) または HCL 形式 (.kvtool.hcl) で記述できます。
設定ファイルの配置
以下の順序で設定ファイルを探します:
- カレントディレクトリの
.kvtool.ymlまたは.kvtool.hcl --configフラグで指定されたパス- グローバル設定:
~/.config/kvtool/.kvtool.yml
基本構造(YAML)
version: 0.1
namespaces:
default:
local:
driver: local
args:
root: ./config
vault:
driver: vault
args:
addr: http://localhost:8200
token: ${VAULT_TOKEN}
production:
vault-prod:
driver: vault
args:
addr: https://vault.example.com
namespaces: 環境(開発、本番など)ごとに設定を切り替える仕組み- デフォルトは
defaultnamespace を使用 - 各ドライバーの設定パラメータは ドライバー を参照
HCL 形式
HCL は変数定義や環境変数展開をサポートします。
locals {
env = "development"
}
namespaces {
namespace "default" {
vault {
driver = "vault"
args {
addr = env.VAULT_ADDR
token = env.VAULT_TOKEN
path = "secret/${local.env}/app"
}
}
local {
driver = "local"
args {
root = "./configs/${local.env}"
}
}
}
}
HCL 固有機能
| 機能 | 構文 | 説明 |
|---|---|---|
| 変数定義 | locals { ... } | 辞書形式で変数を定義 |
| 変数参照 | local.config.port | 属性アクセスで変数を参照 |
| 環境変数 | env.VAR_NAME | 環境変数を直接参照 |
| 文字列補間 | "${local.var}" | 文字列内で変数を展開 |
YAML と HCL の対応
| YAML | HCL |
|---|---|
namespaces: | namespaces { |
default: | namespace "default" { |
driver: vault | driver = "vault" |
args: | args { |
${VAR} | env.VAR |
HTTP サーバー
kvtool store serve コマンドで、設定ファイルで定義したストアを REST API として公開できます。
起動方法
# デフォルト設定(ポート 8080)
kvtool store serve
# ポート指定
kvtool store serve --port 3000
# グローバル設定を使用
kvtool store serve --global
エンドポイント
KV エンドポイント(JSON)
GET /v1/namespaces/{namespace}/kv/{store}/{path}
ファイルを JSON としてパースして返します。
# production 環境の vault ストアから app/settings を取得
curl http://localhost:8080/v1/namespaces/production/kv/vault/app/settings
# default 環境の local ストアから config.json を取得
curl http://localhost:8080/v1/namespaces/default/kv/local/config.json
Storage エンドポイント(Raw)
GET /v1/namespaces/{namespace}/storage/{store}/{path}
ファイルをそのまま(application/octet-stream)返します。
# production 環境の s3 ストアから data.bin を取得
curl http://localhost:8080/v1/namespaces/production/storage/s3/data.bin
ヘルスチェック
GET /health
curl http://localhost:8080/health
# => ok
設定例
version: 1.0
namespaces:
production:
vault:
driver: vault
args:
address: https://vault.example.com
token_env: VAULT_TOKEN
mount: secret
root: myapp
s3:
driver: s3
args:
bucket: prod-configs
region: ap-northeast-1
development:
local:
driver: local
args:
root: ./configs/dev
この設定で以下のエンドポイントが利用可能になります:
/v1/namespaces/production/kv/vault/{path}/v1/namespaces/production/kv/s3/{path}/v1/namespaces/development/kv/local/{path}
エラーレスポンス
| ステータス | 説明 |
|---|---|
| 404 | namespace、store、またはファイルが存在しない |
| 405 | GET 以外のメソッド |
| 500 | サーバー内部エラー |
CLI オプション
| オプション | 短縮 | デフォルト | 説明 |
|---|---|---|---|
--config | -c | .kvtool.yml | 設定ファイルパス |
--global | -g | false | グローバル設定を使用 |
--port | -p | 8080 | リッスンポート |
Kubernetes 連携
kvtool を Kubernetes のシークレットプロバイダーとして使用する方法を説明します。
連携方法の比較
| 方法 | 難易度 | 特徴 |
|---|---|---|
| External Secrets Operator | 低 | Webhook 連携、宣言的管理 |
| Init Container | 低 | 追加コンポーネント不要 |
| Sidecar | 中 | シークレットの自動更新 |
External Secrets Operator (ESO)
External Secrets Operator は Kubernetes でシークレットを外部プロバイダーから同期するための標準的なツールです。
ESO とは
ESO は以下の機能を提供します:
- 外部シークレットストア(Vault、AWS Secrets Manager 等)との連携
- Kubernetes Secret への自動同期
- Webhook Provider による任意の HTTP API との連携
kvtool は Webhook Provider を通じて ESO と連携します。
ESO のインストール
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets \
-n external-secrets --create-namespace
kvtool のデプロイ
# kvtool-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: kvtool
namespace: infra
spec:
replicas: 1
selector:
matchLabels:
app: kvtool
template:
metadata:
labels:
app: kvtool
spec:
containers:
- name: kvtool
image: your-registry/kvtool:latest
args: ["store", "serve", "--port", "8080"]
ports:
- containerPort: 8080
volumeMounts:
- name: config
mountPath: /app/.kvtool.yml
subPath: .kvtool.yml
volumes:
- name: config
configMap:
name: kvtool-config
---
apiVersion: v1
kind: Service
metadata:
name: kvtool
namespace: infra
spec:
selector:
app: kvtool
ports:
- port: 8080
targetPort: 8080
SecretStore の設定
ESO の Webhook Provider は URL テンプレーティングをサポートしています。remoteRef オブジェクトの値を URL に埋め込めます。
# secret-store.yaml
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: kvtool
spec:
provider:
webhook:
url: "http://kvtool.infra.svc:8080/v1/namespaces/{{ .remoteRef.property }}/kv/{{ .remoteRef.key }}"
result:
jsonPath: "$"
headers:
Content-Type: application/json
URL テンプレート変数:
| 変数 | 説明 | 使用例 |
|---|---|---|
{{ .remoteRef.key }} | ExternalSecret の remoteRef.key | vault/db/password |
{{ .remoteRef.property }} | ExternalSecret の remoteRef.property | production |
ExternalSecret の作成
# external-secret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: my-app-secrets
namespace: default
spec:
refreshInterval: 1h
secretStoreRef:
name: kvtool
kind: ClusterSecretStore
target:
name: my-app-secrets # 作成される K8s Secret の名前
creationPolicy: Owner
data:
# 単一の値を取得
- secretKey: db-password # K8s Secret のキー
remoteRef:
key: vault/db/password # kvtool の store/path
property: production # kvtool の namespace
# JSON から特定のフィールドを抽出
- secretKey: api-key
remoteRef:
key: vault/app/config
property: production
# JSONPath で値を抽出(オプション)
# result:
# jsonPath: "$.api_key"
結果の確認
# ExternalSecret の状態確認
kubectl get externalsecret my-app-secrets
# 作成された Secret の確認
kubectl get secret my-app-secrets -o yaml
# 値の確認
kubectl get secret my-app-secrets -o jsonpath='{.data.db-password}' | base64 -d
Init Container パターン
ESO を使わずに、Init Container で直接 kvtool を実行する方法です。
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
initContainers:
- name: load-secrets
image: your-registry/kvtool:latest
command:
- sh
- -c
- |
# 単一の値を取得
kvtool store load -n production vault db/password > /secrets/db-password
# .env 形式で複数の値を取得
kvtool store load -n production local env/app.env > /secrets/.env
volumeMounts:
- name: secrets
mountPath: /secrets
- name: kvtool-config
mountPath: /app/.kvtool.yml
subPath: .kvtool.yml
containers:
- name: app
image: my-app:latest
volumeMounts:
- name: secrets
mountPath: /secrets
readOnly: true
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-password-file
key: password
volumes:
- name: secrets
emptyDir:
medium: Memory # メモリ上に保持(セキュリティ向上)
- name: kvtool-config
configMap:
name: kvtool-config
Sidecar パターン
シークレットを定期的に更新する場合は、Sidecar パターンを使用します。
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: my-app:latest
volumeMounts:
- name: secrets
mountPath: /secrets
readOnly: true
- name: secret-sync
image: your-registry/kvtool:latest
command:
- sh
- -c
- |
while true; do
kvtool store load -n production vault db/password > /secrets/db-password
sleep 300 # 5分ごとに更新
done
volumeMounts:
- name: secrets
mountPath: /secrets
- name: kvtool-config
mountPath: /app/.kvtool.yml
subPath: .kvtool.yml
volumes:
- name: secrets
emptyDir:
medium: Memory
- name: kvtool-config
configMap:
name: kvtool-config
セキュリティ考慮事項
ネットワークポリシー
kvtool サービスへのアクセスを制限します:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: kvtool-access
namespace: infra
spec:
podSelector:
matchLabels:
app: kvtool
ingress:
- from:
# ESO からのアクセスのみ許可
- namespaceSelector:
matchLabels:
name: external-secrets
# または特定の namespace から
- namespaceSelector:
matchLabels:
kvtool-access: "true"
ports:
- port: 8080
RBAC
kvtool の ConfigMap へのアクセスを制限します:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: kvtool-config-reader
namespace: infra
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["kvtool-config"]
verbs: ["get"]
トラブルシューティング
ESO が Secret を作成しない
# ExternalSecret のイベント確認
kubectl describe externalsecret my-app-secrets
# ESO のログ確認
kubectl logs -n external-secrets -l app.kubernetes.io/name=external-secrets
kvtool への接続エラー
# kvtool Pod の状態確認
kubectl get pods -n infra -l app=kvtool
# kvtool のログ確認
kubectl logs -n infra -l app=kvtool
# Service への疎通確認
kubectl run -it --rm debug --image=curlimages/curl -- \
curl http://kvtool.infra.svc:8080/health
Tool コマンド
kvtool tool は UUID、タイムスタンプ、ランダム値、パスワードなどを生成するユーティリティコマンドです。
使用方法
kvtool tool <tool-name>
利用可能なツール
UUID
# UUID v7(時間ベース、ソート可能)
kvtool tool uuid7
# => 019c299f-c6ba-72dd-8d73-8bbe712f4cf0
# UUID v4(ランダム)
kvtool tool uuid4
# => 565ccde7-1f06-4c2c-92ff-6782568cd8a7
タイムスタンプ
# 現在時刻(UTC ISO8601)
kvtool tool now
# => 2024-01-15T10:30:00Z
# Unix タイムスタンプ(秒)
kvtool tool timestamp
# => 1705315800
ランダム値
# ランダムバイト(hex エンコード)
kvtool tool random/hex/16
# => a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
# ランダムバイト(base64 エンコード)
kvtool tool random/base64/32
# => SGVsbG8gV29ybGQhIFRoaXMgaXMgYSB0ZXN0
バイト数は 1〜1024 の範囲で指定できます。
パスワード
# 16文字のパスワード
kvtool tool password
# => xK9#mP2$nQ7@wL4!
パスワードは以下の文字セットから生成されます:
- 小文字: a-z
- 大文字: A-Z
- 数字: 0-9
- 記号: !@#$%^&*
ユースケース
CI/CD でのシークレット生成
# デプロイ用の一意な ID を生成
DEPLOY_ID=$(kvtool tool uuid7)
# API キーを生成
API_KEY=$(kvtool tool random/hex/32)
スクリプトでの使用
#!/bin/bash
# ログファイル名にタイムスタンプを付与
LOG_FILE="app-$(kvtool tool timestamp).log"
# セッション ID を生成
SESSION_ID=$(kvtool tool uuid7)
環境変数の設定
export SECRET_KEY=$(kvtool tool random/base64/32)
export DB_PASSWORD=$(kvtool tool password)
ドライバー
このドキュメントは自動生成されています。手動で編集しないでください。
生成コマンド: go run scripts/gen-docs.go
LocalFsConfig
LocalFsConfig はローカルファイルシステムの設定
ファイル: local.go
| パラメータ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
| root | string | . | ルートディレクトリ。このパスより上位には遡れない | |
| transform | string | json | 読み込み時の変換方法(dotenv, json など) |
設定例:
localfs:
driver: local
args:
root: ./config
transform: dotenv
S3FsConfig
S3FsConfig は S3 ファイルシステムの設定
ファイル: s3.go
| パラメータ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
| bucket | string | ✓ | - | S3 バケット名 |
| region | string | ✓ | - | AWS リージョン |
| access_key_id | string | ✓ | - | AWS アクセスキー ID |
| secret_access_key | string | ✓ | - | AWS シークレットアクセスキー |
| session_token | string | - | AWS セッショントークン(一時的な認証情報使用時) | |
| endpoint | string | - | カスタムエンドポイント(MinIO など S3 互換ストレージ用) | |
| use_path_style | bool | false | パススタイルアクセスを使用(S3 互換ストレージで必要な場合あり) | |
| transform | string | - | 読み込み時の変換方法(dotenv, json など) |
設定例:
s3fs:
driver: s3
args:
bucket: my-config-bucket
region: ap-northeast-1
access_key_id: AKIAIOSFODNN7EXAMPLE
secret_access_key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
session_token: FwoGZXIvYXdzE...
endpoint: http://localhost:9000
use_path_style: true
transform: dotenv
VaultConfig
VaultConfig は HashiCorp Vault ファイルシステムの設定
ファイル: vault.go
| パラメータ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
| addr | string | ✓ | - | Vault サーバーのアドレス |
| token | string | ✓ | - | Vault 認証トークン |
| namespace | string | - | Vault 名前空間(Enterprise 機能) | |
| mount | string | ✓ | secret | KV シークレットエンジンのマウントパス |
| kv_ver | int | 2 | KV シークレットエンジンのバージョン(現在は 2 のみサポート) | |
| version | int | 0 | 取得するシークレットのバージョン(0 = 最新) | |
| field | string | - | 取得する特定のフィールド名(省略時は全フィールド) | |
| pretty | bool | false | JSON 出力を整形するか |
設定例:
vault:
driver: vault
args:
addr: http://localhost:8200
token: root
namespace: admin
mount: secret
RestFsConfig
RestFsConfig は REST ファイルシステムの設定
ファイル: rest.go
| パラメータ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
| base_url | string | ✓ | - | ベース URL |
| auth_type | string | - | 認証タイプ(bearer, basic) | |
| token | string | - | Bearer トークン | |
| token_file | string | - | Bearer トークンファイルパス | |
| username | string | - | Basic 認証ユーザー名 | |
| password | string | - | Basic 認証パスワード | |
| ca_file | string | - | CA 証明書ファイルパス | |
| insecure | bool | false | TLS 証明書検証をスキップ |
設定例:
restfs:
driver: rest
args:
base_url: https://api.example.com
auth_type: bearer
token_file: /var/run/secrets/token
DbFsConfig
DbFsConfig はデータベースファイルシステムの設定
ファイル: db.go
| パラメータ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
| connection_string | string | ✓ | - | データベース接続文字列 |
| driver | string | - | データベースドライバー(postgres, mysql, sqlite)。省略時は接続文字列から自動判定 | |
| query | string | ✓ | - | SQL クエリ。{key} と {namespace} がプレースホルダーとして使用可能 |
| namespace | string | default | デフォルトの namespace 値 |
設定例:
dbfs:
driver: db
args:
connection_string: postgres://user:pass@localhost/db
query: SELECT value FROM config WHERE key = {key}
namespace: production
NatsFsConfig
NatsFsConfig は NATS JetStream KV ファイルシステムの設定
ファイル: nats.go
| パラメータ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
| url | string | ✓ | - | NATS サーバーの接続 URL |
| bucket | string | ✓ | - | JetStream KV バケット名 |
| token | string | - | NATS 認証トークン | |
| user | string | - | NATS ユーザー名 | |
| password | string | - | NATS パスワード | |
| creds_file | string | - | NATS 認証情報ファイルパス |
設定例:
natsfs:
driver: nats
args:
url: nats://localhost:4222
bucket: config
RedisFsConfig
RedisFsConfig は Redis ファイルシステムの設定
ファイル: redis.go
| パラメータ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
| addr | string | ✓ | - | Redis サーバーのアドレス |
| password | string | - | Redis 認証パスワード | |
| db | int | 0 | Redis データベース番号 | |
| prefix | string | - | キーのプレフィックス |
設定例:
redisfs:
driver: redis
args:
addr: localhost:6379
db: 0
prefix: config:
GitFsConfig
GitFsConfig は Git ファイルシステムの設定
ファイル: git.go
| パラメータ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
| url | string | ✓ | - | Git リポジトリ URL |
| ref | string | main | ブランチまたはタグ名 |
設定例:
gitfs:
driver: git
args:
url: https://github.com/example/config.git
ref: main
EnvFsConfig
EnvFsConfig は環境変数ファイルシステムの設定
ファイル: env.go
| パラメータ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
| include | []string | - | 許可する環境変数キーのリスト。未指定で全許可 | |
| exclude | []string | - | 除外する環境変数キーのリスト。include より優先 |
設定例:
envfs:
driver: env
args:
include: APP_NAME,DATABASE_URL
exclude: SECRET_KEY,PASSWORD
BitwardenFsConfig
BitwardenFsConfig は Bitwarden Secrets Manager ファイルシステムの設定
ファイル: bitwarden.go
| パラメータ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
| access_token | string | ✓ | - | Bitwarden アクセストークン |
| organization_id | string | ✓ | - | Bitwarden 組織 ID |
| project_id | string | - | フィルタ対象のプロジェクト ID |
設定例:
bitwardenfs:
driver: bitwarden
args:
access_token: 0.48c78342-...
organization_id: a1b2c3d4-...
project_id: e325ea69-...
ToolFsConfig
ToolFsConfig は Tool ファイルシステムの設定 設定パラメータは不要です。 利用可能なパス: uuid7, uuid4, now, timestamp, random/hex/{bytes}, random/base64/{bytes}, password
ファイル: tool.go
.env ファイル仕様
kvtool における .env ファイルの読み書き仕様を定義します。
設計方針
- Node.js dotenv ベース: 最も広く使われている実装に準拠
- 行末コメント対応: 実用性のために追加
- セキュリティ優先: 変数展開・コマンド置換は非サポート
- 読み取り専用: 書き込み操作は提供しない(下記参照)
なぜ書き込み操作を提供しないか
kvtool は設定の読み取り専用ツールです。書き込み操作(Write)は意図的にサポートしません。
セキュリティ上の理由:
# 例: もし HCL への書き込みが可能だった場合
kvtool convert env:// --to hcl > terraform.tfvars
# 環境変数に含まれる機密情報(API キー、パスワード等)が
# 意図せずファイルに書き出され、Git にコミットされるリスク
設計意図:
- 設定の「取得」と「変換」に特化
- 書き込みは既存のツール(
echo,cat, エディタ)で十分 - 機密情報の意図しない永続化を防止
機能対応表
| 機能 | 対応 | 備考 |
|---|---|---|
| ダブルクォート | ✅ | エスケープ処理あり |
| シングルクォート | ✅ | リテラル(エスケープなし) |
エスケープ \n | ✅ | 改行 |
エスケープ \r | ✅ | CR(Windows互換) |
エスケープ \" | ✅ | クォート内に " を含めるため |
エスケープ \t | ❌ | Node.js 互換で非対応 |
エスケープ \\ | ❌ | Node.js 互換で非対応 |
| 行末コメント | ✅ | KEY=value # comment |
空のキー =value | ❌ | エラー(POSIX 準拠) |
| 数字で始まるキー | ❌ | エラー(POSIX 準拠) |
| キー名検証 | ✅ | [a-zA-Z_][a-zA-Z0-9_]* (POSIX 準拠) |
| export プレフィックス | ❌ | サポートしない |
| 変数展開 ${VAR} | ❌ | リテラル扱い |
| コマンド置換 $(cmd) | ❌ | リテラル扱い |
| 複数行 (heredoc) | ❌ | サポートしない |
| UTF-8 BOM | ✅ | 自動スキップ |
| NULL 文字 \x00 | ❌ | エラー(セキュリティ) |
基本構文
キー名のルール
キー名は POSIX シェル変数名 に準拠します:
- パターン:
[a-zA-Z_][a-zA-Z0-9_]* - 英字(a-z, A-Z)またはアンダースコア(_)で開始
- 以降は英字、数字、アンダースコアのみ
# ✅ 有効なキー名
FOO=bar
_PRIVATE=value
MY_VAR_123=value
# ❌ 無効なキー名(エラーになる)
1KEY=value # 数字で始まる
MY-VAR=value # ハイフンを含む
MY.VAR=value # ドットを含む
キー=value # 非ASCII文字
KEY=VALUE 形式
# 基本形式
KEY=value
# 空の値
EMPTY_KEY=
# 値に = を含む
DATABASE_URL=postgres://user:pass@host:5432/db
クォート
# ダブルクォート: エスケープシーケンスが有効
MESSAGE="Hello\nWorld" # Hello + 改行 + World
# シングルクォート: リテラル(エスケープなし)
MESSAGE='Hello\nWorld' # Hello\nWorld(そのまま)
# クォートなし
MESSAGE=HelloWorld
エスケープシーケンス
ダブルクォート内でのみ有効:
| シーケンス | 変換後 |
|---|---|
\n | 改行 (LF) |
\r | キャリッジリターン (CR) |
\" | ダブルクォート |
非対応のエスケープ:
\t→ そのまま\tとして扱う\\→ そのまま\\として扱う
コメント
# 行頭コメント
KEY=value
KEY=value # 行末コメント(クォート外)
KEY="value # not a comment" # クォート内は値の一部
非サポート機能
以下の機能は意図的にサポートしません:
export プレフィックス
# ❌ サポートしない
export KEY=value
# ✅ 代わりにこう書く
KEY=value
理由: シンプルさを優先。bash での source .env が必要な場合は別途対応。
変数展開
# ❌ 展開しない(リテラル扱い)
BASE_URL=http://localhost
API_URL=${BASE_URL}/api # → "${BASE_URL}/api" という文字列
# ✅ 展開が必要な場合は呼び出し側で処理
理由: セキュリティと予測可能性を優先。意図しない値の漏洩を防止。
コマンド置換
# ❌ 実行しない(リテラル扱い)
DATE=$(date +%Y-%m-%d) # → "$(date +%Y-%m-%d)" という文字列
理由: セキュリティを優先。任意のコマンド実行を防止。
複数行値 (heredoc)
# ❌ サポートしない
PRIVATE_KEY="""
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
"""
# ✅ 代わりにエスケープシーケンスを使用
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
理由: シンプルさを優先。複雑な値は JSON や Vault を推奨。
他ツールとの互換性
| ツール | 互換性 | 差異 |
|---|---|---|
| Node.js dotenv | ほぼ同等 | 行末コメント追加 |
| docker-compose | 部分的 | export, 変数展開なし |
| Python python-dotenv | 部分的 | 変数展開なし |
Node.js dotenv との比較
# 両方で同じ動作
KEY="hello\nworld" # → hello + 改行 + world
# kvtool のみ対応
KEY=value # comment # → value(行末コメント)
# どちらも非対応(リテラル扱い)
KEY=${OTHER_KEY} # → "${OTHER_KEY}"
使用例
.env ファイルの読み込み
# ローカルファイルから
kvtool file load .env --transform dotenv
# ストア経由
kvtool store load config/.env
環境変数の出力
# 環境変数を .env 形式で出力
kvtool file load env:// --format raw
エンコーディング
- UTF-8 のみ: BOM 付きファイルも自動的に処理(BOM をスキップ)
- 改行コード: LF (
\n) を推奨、CRLF (\r\n) も許容
アーキテクチャ
kvtool のアーキテクチャ概要です。
レイヤー構造
Presentation (CLI)
↓
Service
↓
Infrastructure (Filesystem)
- Presentation: Cobra を使った CLI インターフェース (
cmd/) - Service: ビジネスロジック
- Infrastructure: ファイルシステムドライバー (
pkg/filesystems/)
統一インターフェース
全てのファイルシステムは以下のインターフェースを実装します (p../pkg/filesystems/core.go):
type Filesystem interface {
GetFile(path string) (File, error)
}
type File interface {
LoadAsJson() (any, error)
OpenReader() (io.ReadCloser, error)
}
ファイルシステムドライバー
実装済みドライバー
- LocalFs: ローカルファイルシステム (p../pkg/filesystems/local.go)
- VaultFs: HashiCorp Vault (p../pkg/filesystems/vault.go)
- FsEnvFilesystem: 環境変数 (p../pkg/filesystems/env_fs.go)
- S3Fs: Amazon S3 / S3互換ストレージ (p../pkg/filesystems/s3.go)
ドライバーの作成
FilesystemFactory がドライバー名から適切なファイルシステムインスタンスを生成します (p../pkg/filesystems/factory.go)。
Transform(変換機能)
ファイルを読み込む際に、特定の形式(.env など)を JSON に変換する機能です。
実装済み Transform
- dotenv: .env 形式を JSON に変換 (pkg/decoders/env_to_json.go)
テスト戦略
- 統合テスト: p../pkg/filesystems/integration_test.go で全ファイルシステムの共通動作を検証
- テーブル駆動テスト: 全てのテストはテーブル駆動テストで記述
- Docker 統合: Vault などの外部サービスは Docker で起動してテスト
詳細は CLAUDE.md を参照してください。
開発ガイド
kvtool の開発に参加する方向けのガイドです。
開発環境のセットアップ
必要なツール
- Go 1.21 以上
- Make
- Docker(統合テスト用)
テスト実行
# 全テスト実行
make test
# Vault含む統合テスト
make test-full
テスト用サービスの起動
# 全サービス起動(Vault + MinIO)
make services-up
# Vault: http://localhost:8200 (token: root)
# MinIO: http://localhost:9000 (user: minioadmin)
# 全サービス停止
make services-down
# ログ確認
make services-logs
コード規約
詳細は CLAUDE.md を参照してください。
テスト規約
- テーブル駆動テスト: 全てのテストはテーブル駆動テストで記述
- 日本語: テスト名、コメント、エラーメッセージは日本語で記述
セキュリティ規約
- パストラバーサル防止: 全てのファイルシステムは
rootより上位に遡れないようにする - 相対パスのみ: 絶対パス(
/etc/passwd)やチルダパス(~/config)は拒否
ドキュメント生成
# APIリファレンスを自動生成
make doc-gen
コード内のコメントと構造体タグから docs/api-reference.md が自動生成されます。
コード品質
# 静的解析
make lint
# コードフォーマット
make format
# 品質分析(カバレッジ + 複雑度)
make test-quality
# 開発ツールのインストール(golangci-lint)
make setup-tools
新しいファイルシステムドライバーの追加
- 仕様策定:
do../pkg/filesystems/{driver}.mdを作成 - 構造体定義: 設定構造体を定義(
doc,required,default,exampleタグを含む) - インターフェース実装:
FilesystemとFileインターフェースを実装 - テスト:
filesystems/integration_test.goにテストケースを追加 - ドキュメント生成:
make doc-genを実行
詳細は CLAUDE.md の「開発ワークフロー」セクションを参照してください。