コンテンツにスキップ

tegata

クラウドのシークレットの保存先のための、シークレットのライフサイクルをコードで。

tegata は、シークレット(ランダムな鍵、Cloudflare や Tailscale などのサービスの API トークン、データベースのパスワード)を作り、クラウドのシークレットの保存先に置き、サーバーやアプリケーションごとに、決めたシークレットだけを読めるようにし、入れ替え、古いものを片付け、サーバーの上で設定の雛形を埋めます。

すべてを 1 つの YAML に書きます。動かしておくサーバーも Kubernetes も要りません。

クラウドのシークレットの保存先や Vault のようなサーバーは、シークレットをしまっておくのは得意です。ところが、ほかのサービスのシークレットを入れ替えるのは、たいてい自分でやることになります。サービスごとに入れ替えの関数を書くか、それぞれの管理画面で手でやるかです。tegata は、そのライフサイクルの全部を 1 か所にまとめます。

作る

リソースに、プロバイダー(random、cloudflare、tailscale …)とその設定を書きます。tegata apply が、まだないものを作ります。

置いて、読めるようにする

値は Secret Manager に置きます。シークレットごとに読み手(アイデンティティ:サーバー、アプリケーション、CI のワークフローのサービスアカウント)を書き、その読み手だけが読めます。

入れ替えて、片付ける

tegata rotate が新しい世代を作ります。サーバーが新しい値を使い始めたら、tegata prune が、古い世代のためにプロバイダーが作ったもの(古い API トークンなど)を消し、古い版を無効にします。

埋める

サーバーの上で、tegata render が雛形の __NAME__ を保存してある値で置き換えます。

届ける

シークレットの写しを、GitHub Actions の secrets(リポジトリか環境の)にも置けます。値が変わるたびに tegata が書き直すので、入れ替えたあとの次の実行から、CI は新しい値を使います。

プロバイダーは、標準入出力で JSON をやりとりする別の実行ファイルです。tegata を変えずに、どの言語でも足せます。

クラウドのアカウントなしで手元の機械で試すには、examples/minimal を見てください。

tegata.yaml
stores:
main:
gcp:
project: my-project
location: us-central1 # where secret replicas live (user-managed replication)
identities: # who reads secrets: names for IAM members
app: [serviceAccount:app-vm@my-project.iam.gserviceaccount.com]
providers: # external providers (random, manual and value are built in)
cloudflare:
source: github.com/k-kawa/tegata # installed by `tegata init`
version: "^0.3"
config: { account_id: 0123456789abcdef }
credentials: # never write secrets in the YAML
api_token: { env: TEGATA_CLOUDFLARE_TOKEN }
resources:
session_key:
provider: random
config: { bytes: 32 }
stores:
main: # where it is stored, under what name, and who reads it
- { name: SESSION_KEY, readers: [app] }
previous: { name: PREVIOUS_SESSION_KEY } # rotate copies the current value here first
releases_read:
provider: cloudflare
type: api_token
config:
name: releases read
policies:
- permissions: [Workers R2 Storage Bucket Item Read]
r2_buckets: [releases]
stores:
main: # one entry per provider output
- { output: id, name: RELEASES_ACCESS_KEY_ID, readers: [app] }
- { output: r2_secret_access_key, name: RELEASES_SECRET_ACCESS_KEY, readers: [app] }
templates/app/app.env
SESSION_KEY=__SESSION_KEY__
PREVIOUS_SESSION_KEY=__PREVIOUS_SESSION_KEY__
RELEASES_ACCESS_KEY_ID=__RELEASES_ACCESS_KEY_ID__
RELEASES_SECRET_ACCESS_KEY=__RELEASES_SECRET_ACCESS_KEY__
ターミナルウィンドウ
tegata init # install the providers, pinned in tegata.lock
tegata check app templates/app # providers, and app can read every name in templates/app
tegata apply # containers, read access, missing values
tegata status # generations, enabled versions, readers
# on the server (no YAML needed; on GCP VMs the project comes from the metadata server)
tegata render templates/app /etc/app

鍵を入れ替える:

ターミナルウィンドウ
tegata rotate session_key # new generation; the old value moves to PREVIOUS_SESSION_KEY
# ... re-run `tegata render` on the servers and restart the services ...
tegata settle session_key # PREVIOUS_SESSION_KEY = SESSION_KEY (the old value is no longer accepted)
tegata prune session_key # disable the old versions
プロバイダー 種類 作るもの
random(組み込み) ランダムなバイト列を 16 進で(bytes、既定は 32)
manual(組み込み) 手で入れる値(tegata set)
value(組み込み) data YAML に書いた、シークレットでない決まった値
tegata-provider-cloudflare api_token、tunnel_token アカウントの API トークン(R2 の鍵にも使える)、Tunnel のトークン
tegata-provider-tailscale auth_key tailnet に参加するための鍵
tegata-provider-aws ses_smtp_credentials Amazon SES の SMTP の認証情報(IAM ユーザーのアクセスキー)
tegata-provider-gcp sql_user Cloud SQL の組み込みのユーザーのパスワード
tegata-provider-terraform outputs(data) Terraform の出力から読んだ値

それぞれの設定、出力、入れ替えのふるまいはプロバイダーに、プロバイダーの書き方はプロバイダーとの約束にあります。

Functional Source License, Version 1.1, ALv2 Future License(FSL-1.1-ALv2)。

かいつまむと:tegata と競合する商用の製品やサービスとしてほかの人に提供すること以外なら、どんな目的でも使い、変え、配り直せます。会社の中で使うこと、自分たちのインフラに使うこと、客のための仕事で使うことは問題ありません。各版は、リリースから 2 年たつと Apache License 2.0 でも使えるようになります。

FSL は Fair Source のライセンスで、OSI が認めたオープンソースのライセンスではありません。組織で OSI が認めたライセンスしか使えない場合は、使う前に確認してください。