シークレット
API キー、パスワード、証明書などの機密データを安全に保存・管理します。
シークレットを使用する理由
アプリケーションには機密性の高い認証情報が必要です。たとえば、サードパーティサービス用の API キー、データベースのパスワード、認証トークンなどです。これらをハードコードするのはセキュリティ上のリスクであり、環境変数だけではローテーション(更新)やアクセス制御を提供できません。
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 は、機密データのための安全なキー・バリューストアを提供します。Secrets は保存時に暗号化され、パフォーマンスのためにキャッシュされ、実行時に this.secrets を通じてバックエンドコードからアクセスできます。
Squid は 2 種類の secrets をサポートしています。
| Type | Description | Value | Example use case |
|---|---|---|---|
| Custom secrets | 外部システムの認証情報のための、ユーザー定義のキー・バリューペア | 値はユーザーが指定 | SendGrid API キーや DB パスワードの保存 |
| API keys | プラットフォームへの認証に使う、Squid が管理するアプリケーションキー | Squid が自動生成 | バックエンドを Squid に対して認証する |
いつ secrets を使うべきか
- サードパーティ API キーや認証トークンを安全に保存する
- データベース認証情報を管理する
- schedulers を使って、スケジュールに従い API キーをプログラムでローテーションする
- クライアントに認証情報を露出させずに、executables を通じて安全な API 呼び出しを可能にする
仕組み
- Squid Console から、または Client SDK 経由でプログラムにより secrets を作成する
- Squid が secrets を暗号化して安全に保存する
- バックエンドサービスで
this.secrets['SECRET_NAME']を通じて secrets にアクセスする - プログラムによる管理(ローテーション、動的作成)には
squid.admin().secrets()を使用する
クイックスタート
前提条件
- バックエンドプロジェクトを含む Squid application
@squidcloud/backendパッケージがインストールされていること
Step 1: Squid Console で secret を追加する
Squid Console でアプリケーションに移動し、Secrets に進み、キー 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
デプロイの詳細は、バックエンドのデプロイ を参照してください。
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 platform に対して認証する)に使用します。値は選べず、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 を通じて読み取り専用のキー・バリューマップとして利用できます。
// 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 を取得します。存在する場合は 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 }
複数の secrets を一度に作成または更新するには 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');
複数の secrets を一度に削除します。
const secrets = squid.admin().secrets();
await secrets.deleteMany(['SECRET_NAME', 'OTHER_SECRET']);
connectors によって使用中の 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 が存在しない | キー名を確認する。存在しない secret では 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 - 管理された認証情報でサードパーティサービスに接続する