メインコンテンツまでスキップ

シークレット

API キー、パスワード、証明書などの機密データを安全に保存・管理します。

シークレットを使用する理由

アプリケーションには機密性の高い認証情報が必要です。たとえば、サードパーティサービス用の API キー、データベースのパスワード、認証トークンなどです。これらをハードコードするのはセキュリティ上のリスクであり、環境変数だけではローテーション(更新)やアクセス制御を提供できません。

Squid secrets を使うと、認証情報を安全に保存し、実行時にバックエンドコードからアクセスできます。

Backend code
@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 をサポートしています。

TypeDescriptionValueExample use case
Custom secrets外部システムの認証情報のための、ユーザー定義のキー・バリューペア値はユーザーが指定SendGrid API キーや DB パスワードの保存
API keysプラットフォームへの認証に使う、Squid が管理するアプリケーションキーSquid が自動生成バックエンドを Squid に対して認証する

いつ secrets を使うべきか

  • サードパーティ API キーや認証トークンを安全に保存する
  • データベース認証情報を管理する
  • schedulers を使って、スケジュールに従い API キーをプログラムでローテーションする
  • クライアントに認証情報を露出させずに、executables を通じて安全な API 呼び出しを可能にする

仕組み

  1. Squid Console から、または Client SDK 経由でプログラムにより secrets を作成する
  2. Squid が secrets を暗号化して安全に保存する
  3. バックエンドサービスで this.secrets['SECRET_NAME'] を通じて secrets にアクセスする
  4. プログラムによる管理(ローテーション、動的作成)には squid.admin().secrets() を使用する

クイックスタート

前提条件

  • バックエンドプロジェクトを含む Squid application
  • @squidcloud/backend パッケージがインストールされていること

Step 1: Squid Console で secret を追加する

Squid Console でアプリケーションに移動し、Secrets に進み、キー MY_API_SECRET と任意の値で新しい secret を追加します。

Step 2: バックエンドで secret にアクセスする

Backend code
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: クライアントから呼び出す

Client code
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 メソッドは stringnumberboolean を受け付けますが、すべての値は文字列として保存され、文字列として返されます。

Custom secrets と API keys

Squid は、目的が異なりライフサイクル要件も異なるため、secrets を 2 つのカテゴリに分けています。

Custom secrets は、ユーザーが管理する値を保存します。サードパーティ API key、データベースパスワード、OAuth トークンなど、外部システム由来の認証情報に使用します。値はユーザーが設定し、認証情報が変わったときに更新する責任もユーザーにあります。

API keys は、Squid が生成・管理する認証キーです。アプリケーションがリクエスト認証のために安全でユニークなキーを必要とする場合(例: バックエンドを Squid platform に対して認証する)に使用します。値は選べず、Squid が作成します。upsert を再度呼び出すことでローテーション(新しい値の生成)が可能です。

FeatureCustom secretsAPI keys
Value source値はユーザーが指定Squid が自動生成
Use caseサードパーティ認証情報、パスワード、トークンアプリケーション認証キー
Create/Updatesecrets.upsert(key, value)secrets.apiKeys.upsert(key)
Batch operationsupsertMany, deleteMany利用不可
Force delete対応(force パラメータ)非対応

要するに: すでにある認証情報の値を安全に保存したい場合は custom secret を使います。Squid にキーを生成・管理してほしい場合は API key を使います。

バックエンドからのアクセス

Squid バックエンドサービスでは、secrets は this.secrets を通じて読み取り専用のキー・バリューマップとして利用できます。

Backend code
// 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 パラメータを渡せます。デフォルトでは forcefalse であり、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 を更新します。メソッドは stringnumberboolean を受け付けますが、すべての値は文字列として保存され、文字列として返されます。

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');

エラーハンドリング

よくあるエラー

ErrorCauseSolution
UNAUTHORIZED有効な API key で Client が初期化されていないclient 初期化時に apiKey オプションで API key を渡す
Secret in useforce=false で、connector が使用中の secret を削除した先に connector の依存を外すか、forcetrue を渡す
undefined resultsecret が存在しないキー名を確認する。存在しない secret では getundefined を返す
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);
}
}

ベストプラクティス

セキュリティ

  1. クライアントで secrets を絶対に露出しない。 secrets にはフロントエンドコードではなく、executables やその他のバックエンドコードからアクセスします。
  2. API key の使用を制限する。 apiKey を使って Squid client を初期化するのは、Squid Backend などの安全なサーバーサイド環境のみにしてください。
  3. サードパーティサービスには connectors を使う。 Squid connectors は認証情報の注入を自動で処理し、secrets を手動管理する必要性を減らします。

ローテーション

  1. スケジュールに従って secrets をローテーションする。 schedulers を使って、API keys や認証情報を定期的にローテーションします。
  2. ローテーション前に lastUpdated を確認する。 secret の経過時間を先に確認し、不要なローテーションを避けます。

運用

  1. 大量変更にはバッチメソッドを使う。 複数の secrets を管理する場合、個別呼び出しよりも upsertManydeleteMany の方が効率的です。
  2. デフォルトで force delete を使わない。 デフォルト動作(force=false)は connector の設定を誤って壊すのを防ぎます。

コード例

スケジュールで API key をローテーションする

secret 管理を scheduler と組み合わせて、API keys を自動的にローテーションします。

Backend code
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 をサーバー側に保持したまま、クライアントから呼び出しをトリガーできます。

Backend code
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 };
}
}
Client code
const result = await squid.executeFunction('sendEmail', {
to: 'user@example.com',
subject: 'Welcome!',
body: 'Thanks for signing up.',
});

関連項目

  • Executables - クライアントからバックエンド関数を呼び出す
  • Schedulers - スケジュールに従ってコードを実行する
  • Connectors - 管理された認証情報でサードパーティサービスに接続する