Secrets(シークレット)
API key、パスワード、証明書などの機密データを安全に保存・管理します。
Secrets を使う理由
アプリケーションには機密性の高い認証情報が必要です。サードパーティサービス用の API key、データベースのパスワード、認証トークンなどです。これらをコードにハードコードするのはセキュリティ上のリスクであり、環境変数だけではローテーションやアクセス制御を提供できません。
Squid secrets を使うと、認証情報を安全に保存し、実行時にバックエンドコードからアクセスできます。
@executable()
async sendEmail(to: string, subject: string, body: string): Promise<void> {
// Access the secret securely without exposing it to the client
const apiKey = this.secrets['SENDGRID_API_KEY'];
await sendgrid.send({ to, subject, body, apiKey });
}
ハードコードされた値は不要です。認証情報を露出しません。Secrets は実行時に注入されます。
概要
Squid secrets は、機密データのための安全な key-value ストアを提供します。Secrets は保存時に暗号化され、パフォーマンスのためにキャッシュされ、実行時に this.secrets を介してバックエンドコードからアクセスできます。
Squid は 2 種類の secrets をサポートしています。
| Type | Description | Value | Example use case |
|---|---|---|---|
| Custom secrets | 外部システム由来の認証情報向けに、ユーザーが定義する key-value ペア | 値はユーザーが指定 | SendGrid API key や DB パスワードの保存 |
| API keys | プラットフォームと認証するための Squid 管理のアプリケーションキー | Squid が自動生成 | バックエンドの Squid への認証 |
Secrets を使う場面
- サードパーティ API key や認証トークンを安全に保存する
- データベース認証情報を管理する
- schedulers を使ってスケジュールに従い API key をプログラム的にローテーションする
- クライアントに認証情報を露出せずに executables 経由で安全な API 呼び出しを行う
仕組み
- Squid Console から、または Client SDK を通じてプログラム的に secrets を作成する
- Squid が secrets を暗号化して安全に保存する
- バックエンドサービスで
this.secrets['SECRET_NAME']を通じて secrets にアクセスする - プログラムによる管理(ローテーション、動的作成)には
squid.admin().secrets()を使用する
クイックスタート
前提条件
- バックエンドプロジェクトを含む Squid アプリケーション
@squidcloud/backendパッケージがNPMからインストールされていること
Step 1: Squid Console で secret を追加する
Squid Console で対象アプリケーションに移動し、Secrets に進んで、key を MY_API_SECRET、値を任意の値として新しい secret を追加します。
Step 2: バックエンドから secret にアクセスする
import { executable, SquidService } from '@squidcloud/backend';
export class ExampleService extends SquidService {
@executable()
async getProtectedData(): Promise<string> {
const apiKey = this.secrets['MY_API_SECRET'];
const response = await fetch('https://api.example.com/data', {
headers: { Authorization: `Bearer ${apiKey}` },
});
return (await response.json()) as string;
}
}
Step 3: バックエンドをデプロイする
実行時に secret が利用できるように、バックエンドをデプロイします。バックエンドディレクトリで次のコマンドを実行してください。
squid deploy
デプロイの詳細は、deploying your backend を参照してください。
Step 4: クライアントから呼び出す
const data = await squid.executeFunction('getProtectedData');
console.log(data);
認証と設定
Client SDK を介したプログラムによる secret 管理では、apiKey オプションを使用してアプリケーションの API key でクライアントを初期化する必要があります。ユーザー向けアプリケーションから 絶対に これを行わないでください。secret 管理は Squid Backend などの安全な環境でのみ実行してください。
secrets をプログラム的に管理するには、API key を使って Squid client を初期化します。
import { Squid } from '@squidcloud/client';
const squid = new Squid({
appId: 'YOUR_APP_ID',
region: 'us-east-1.aws',
apiKey: 'YOUR_API_KEY', // Required for programmatic secret management
});
API key がない場合、secrets の管理を試みると UNAUTHORIZED エラーになります。
コアコンセプト
Secret entry
すべての secret 操作は SecretEntry オブジェクトを返します。
interface SecretEntry {
key: string; // The secret name
value: string; // The secret value (always stored as a string)
lastUpdated: number; // Timestamp in milliseconds since epoch
}
upsert メソッドは string、number、boolean を受け取れますが、すべての値は文字列として保存され、文字列として返されます。
Custom secrets と API keys の違い
Squid では、用途が異なりライフサイクル要件も異なるため、secrets を 2 つのカテゴリに分けています。
Custom secrets はユーザーが制御する値を保存します。サードパーティの API key、データベースパスワード、OAuth トークンなど、外部システム由来の認証情報に使用します。値はユーザーが設定し、認証情報が変更された際の更新もユーザーの責任で行います。
API keys は、Squid が生成・管理する認証キーです。アプリケーションがリクエストを認証するための安全で一意なキー(例: バックエンドを Squid プラットフォームに対して認証する)として使用します。値は選べず、Squid が作成します。upsert を再度呼び出すことでローテーション(新しい値の生成)できます。
| Feature | Custom secrets | API keys |
|---|---|---|
| Value source | 値はユーザーが指定 | Squid が自動生成 |
| Use case | サードパーティ認証情報、パスワード、トークン | アプリケーション認証キー |
| Create/Update | secrets.upsert(key, value) | secrets.apiKeys.upsert(key) |
| Batch operations | upsertMany, deleteMany | 利用不可 |
| Force delete | サポートあり(force パラメータ) | サポートなし |
要点: すでに値を持つ認証情報を安全に保存したい場合は custom secret を使います。Squid にキーを生成・管理させたい場合は API key を使います。
バックエンドからのアクセス
Squid のバックエンドサービスでは、secrets は this.secrets を通じて読み取り専用の key-value マップとして利用できます。
// Access the value directly by key
const apiKey = this.secrets['MY_API_KEY'];
const dbPassword = this.secrets['DB_PASSWORD'];
このマップは実行時に自動的に生成されます。バックエンドから secrets を読み取るために API key や特別な設定は不要です。
Force delete
custom secret を削除する際、force パラメータを渡せます。デフォルトでは force は false で、secret が connector で使用中の場合は削除が失敗します。これにより、誤って connector 設定を壊してしまうことを防げます。
const secrets = squid.admin().secrets();
// Default: fails if 'DB_PASSWORD' is used by a connector
await secrets.delete('DB_PASSWORD');
// Force delete regardless of usage
await secrets.delete('DB_PASSWORD', true);
Custom Secrets
プログラムによる secret 管理はすべて squid.admin().secrets() クライアントを使用します。
const secrets = squid.admin().secrets();
Secret を取得する
名前で単一の secret を取得します。secret が存在しない場合は SecretEntry ではなく undefined を返します。
const secrets = squid.admin().secrets();
const entry = await secrets.get('SECRET_NAME');
if (entry) {
console.log(entry.key); // 'SECRET_NAME'
console.log(entry.value); // 'your_value'
console.log(entry.lastUpdated); // 1692306991724
}
すべての secrets を取得する
すべての custom secrets を、secret 名をキーとする SecretEntry のマップとして取得します。
const secrets = squid.admin().secrets();
const allSecrets = await secrets.getAll();
// {
// 'SECRET_NAME': { key: 'SECRET_NAME', value: 'your_value', lastUpdated: 1692306991724 },
// 'OTHER_SECRET': { key: 'OTHER_SECRET', value: 'other_value', lastUpdated: 1692306991725 }
// }
Secret を作成または更新する
upsert を使って新しい secret を作成するか、既存の secret を更新します。string、number、boolean を受け取れますが、すべての値は文字列として保存され、文字列として返されます。
const secrets = squid.admin().secrets();
const entry = await secrets.upsert('SECRET_NAME', 'your_new_value');
// { key: 'SECRET_NAME', value: 'your_new_value', lastUpdated: 1692306991724 }
複数の secret を一括で作成または更新するには upsertMany を使用します。
const secrets = squid.admin().secrets();
const entries = await secrets.upsertMany([
{ key: 'API_KEY_1', value: 'key-value-1' },
{ key: 'API_KEY_2', value: 'key-value-2' },
]);
// Returns an array of SecretEntry objects
Secret を削除する
名前で単一の secret を削除します。
const secrets = squid.admin().secrets();
await secrets.delete('SECRET_NAME');
複数の secret を一括削除します。
const secrets = squid.admin().secrets();
await secrets.deleteMany(['SECRET_NAME', 'OTHER_SECRET']);
connector により使用中の secrets を強制削除するには、第 2 引数に true を渡します。
const secrets = squid.admin().secrets();
// Force delete even if used by a connector
await secrets.delete('SECRET_NAME', true);
await secrets.deleteMany(['SECRET_NAME', 'OTHER_SECRET'], true);
API Keys
Squid API keys は secret クライアントの apiKeys プロパティから管理します。custom secrets と異なり、キーの値は Squid が自動生成します。
const apiKeys = squid.admin().secrets().apiKeys;
API key を取得する
名前で API key を取得します。キーが存在しない場合は SecretEntry ではなく undefined を返します。
const apiKeys = squid.admin().secrets().apiKeys;
const entry = await apiKeys.get('API_KEY_NAME');
if (entry) {
console.log(entry.value); // 'a123b456-cd78-9e90-f123-gh45i678j901'
}
すべての API keys を取得する
すべての API keys を SecretEntry オブジェクトのマップとして取得します。
const apiKeys = squid.admin().secrets().apiKeys;
const allKeys = await apiKeys.getAll();
// {
// 'API_KEY_NAME': {
// key: 'API_KEY_NAME',
// value: 'a123b456-cd78-9e90-f123-gh45i678j901',
// lastUpdated: 1692306991724
// }
// }
API key を作成またはローテーションする
キー名を指定して upsert を呼び出します。新しい値は Squid が自動生成します。
const apiKeys = squid.admin().secrets().apiKeys;
const entry = await apiKeys.upsert('API_KEY_NAME');
console.log(entry.value); // New auto-generated key value
API key を削除する
const apiKeys = squid.admin().secrets().apiKeys;
await apiKeys.delete('API_KEY_NAME');
エラーハンドリング
よくあるエラー
| Error | Cause | Solution |
|---|---|---|
UNAUTHORIZED | 有効な API key で client が初期化されていない | client 初期化時に apiKey オプションで API key を渡す |
| Secret in use | force=false で connector が使用中の secret を削除しようとした | 先に connector 依存を解除するか、force に true を渡す |
undefined result | secret が存在しない | key 名を確認する。存在しない場合 get は undefined を返す |
| Request timeout | サーバーが操作のためのロックを取得できなかった | 少し待ってから再試行する |
エラーの扱い方
const secrets = squid.admin().secrets();
try {
await secrets.upsert('MY_SECRET', 'new-value');
} catch (error) {
if (error.message === 'UNAUTHORIZED') {
console.error('API key is missing or invalid');
} else {
console.error('Failed to update secret:', error.message);
}
}
ベストプラクティス
セキュリティ
- クライアントで secrets を絶対に露出しない。 secrets へのアクセスはフロントエンドコードではなく、executables やその他のバックエンドコードで行ってください。
- API key の使用を制限する。
apiKeyを指定して Squid client を初期化するのは、Squid Backend などの安全なサーバーサイド環境でのみ行ってください。 - サードパーティサービスには connectors を使う。 Squid の connectors は認証情報の注入を自動で行うため、手動で secrets を管理する必要性を減らせます。
ローテーション
- スケジュールで secrets をローテーションする。 schedulers を使用して API keys や認証情報を定期的にローテーションします。
- ローテーション前に
lastUpdatedを確認する。 secret の経過時間を先に確認し、不要なローテーションを避けます。
運用
- 一括変更にはバッチメソッドを使う。 複数の secrets を管理する場合、個別呼び出しより
upsertManyとdeleteManyの方が効率的です。 - デフォルトで force delete を避ける。 デフォルト動作(
force=false)は、connector 設定を誤って壊すことを防ぎます。
コード例
スケジュールで API key をローテーションする
secret 管理と scheduler を組み合わせて、API keys を自動でローテーションします。
import { CronExpression, scheduler, SquidService } from '@squidcloud/backend';
export class KeyRotationService extends SquidService {
@scheduler('rotate-api-key', CronExpression.EVERY_DAY_AT_MIDNIGHT)
async rotateApiKey(): Promise<void> {
const entry = await this.squid.admin().secrets().apiKeys.get('MY_API_KEY');
if (!entry) return;
// Rotate if the key is over 30 days old
const thirtyDaysMs = 30 * 24 * 60 * 60 * 1000;
if (entry.lastUpdated < Date.now() - thirtyDaysMs) {
await this.squid.admin().secrets().apiKeys.upsert('MY_API_KEY');
console.log('API key rotated successfully');
}
}
}
サードパーティ API を安全に呼び出す
executable を使用して API keys をサーバー側に保持したまま、クライアントが呼び出しをトリガーできるようにします。
import { executable, SquidService } from '@squidcloud/backend';
interface EmailRequest {
to: string;
subject: string;
body: string;
}
export class EmailService extends SquidService {
@executable()
async sendEmail(request: EmailRequest): Promise<{ success: boolean }> {
const apiKey = this.secrets['SENDGRID_API_KEY'];
const response = await fetch('https://api.sendgrid.com/v3/mail/send', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
personalizations: [{ to: [{ email: request.to }] }],
from: { email: 'noreply@example.com' },
subject: request.subject,
content: [{ type: 'text/plain', value: request.body }],
}),
});
if (!response.ok) {
throw new Error(`Email send failed: ${response.status}`);
}
return { success: true };
}
}
const result = await squid.executeFunction('sendEmail', {
to: 'user@example.com',
subject: 'Welcome!',
body: 'Thanks for signing up.',
});
関連項目
- Executables - クライアントからバックエンド関数を呼び出す
- Schedulers - スケジュールに従ってコードを実行する
- Connectors - 管理された認証情報でサードパーティサービスに接続する