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

Secrets

API key、password、certificate などの sensitive data を安全に保存・管理します。​

Secrets を使用する理由​

application には sensitive credential が必要です。たとえば third-party service 用の API key、database password、authentication token などです。これらを hardcode することは security risk であり、environment variable だけでは rotation や access control を提供できません。

Squid secrets を使用すると、credential を安全に保存し、runtime に backend code から access できます。

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

hardcoded value は不要です。credential を公開する必要もありません。secret は runtime に inject されます。

概要​

Squid secrets は sensitive data 用の安全な key-value store を提供します。secret は保存時に encrypt され、performance のために cache され、runtime に this.secrets を介して backend code から access できます。

Squid は 2 種類の secret をサポートします。

Type説明Value使用例
Custom secretsexternal system の credential 用に user が定義する key-value pairuser が value を指定SendGrid API key または DB password の保存
API keysplatform との authentication に使用する Squid-managed application keySquid が自動生成Squid に対する backend の authentication

Secrets を使用する場合​

  • third-party API key および authentication token を安全に保存する
  • database credential を管理する
  • schedulerを使用して、schedule に従って API key をプログラムで rotate する
  • credential を client に公開せず、executablesを通じた安全な API call を有効にする

仕組み​

  1. Squid Console または Client SDK を通じてプログラムで secret を作成します
  2. Squid が secret を encrypt して安全に保存します
  3. backend service で、this.secrets['SECRET_NAME'] を介して secret に access します
  4. プログラムによる管理(rotation、dynamic creation)には、squid.admin().secrets() を使用します

クイックスタート​

前提条件​

  • backend project を持つ Squid application
  • NPM からインストールされた @squidcloud/backend package

ステップ 1: Squid Console で secret を追加する​

Squid Console で application に移動し、Secrets を開いて、key が MY_API_SECRET で必要な value を持つ新しい secret を追加します。

ステップ 2: backend で secret に access する​

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;
}
}

ステップ 3: backend を deploy する​

runtime で secret を使用できるように、backend を deploy します。この command は backend directory から実行します。

squid deploy

deploy の詳細については、backend の deployを参照してください。

ステップ 4: client から呼び出す​

Client code
const data = await squid.executeFunction('getProtectedData');
console.log(data);

Authentication と Configuration​

注意

Client SDK によるプログラムでの secret 管理では、apiKey option を使用して application の API key で client を初期化する必要があります。user-facing application からこれを実行することは絶対にしないでください。secret 管理は Squid Backend などの secure environment からのみ実行してください。

secret をプログラムで管理するには、Squid client を API key で初期化します。

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 がない場合、secret を管理しようとすると UNAUTHORIZED error になります。

コアコンセプト​

Secret entry​

すべての secret operation は SecretEntry object を返します。

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 method は string、number、boolean value を受け入れますが、すべての value は string として保存・返却されます。

Custom secrets と API keys​

Squid は、目的と lifecycle の要件が異なるため、secret を 2 つの category に分けています。

Custom secrets は、user が制御する value を保存します。third-party API key、database password、OAuth token など、external system から取得する credential に使用します。value は user が設定し、credential が変更されたときに更新する責任があります。

API keys は、Squid が生成・管理する authentication key です。application が request の authentication 用に安全で一意の key を必要とする場合に使用します(たとえば Squid platform で backend を authentication する場合)。value を選択することはできません。Squid が作成し、upsert を再度呼び出して新しい key を生成することで rotate できます。

FeatureCustom secretsAPI keys
Value sourceuser が value を指定Squid が自動生成
Use caseThird-party credential、password、tokenApplication authentication key
Create/Updatesecrets.upsert(key, value)secrets.apiKeys.upsert(key)
Batch operationupsertMany、deleteMany利用不可
Force deleteサポート(force parameter)非サポート

要約: 安全に保存する必要がある既存の credential value がある場合は、custom secret を使用します。Squid に key の生成と管理を任せる場合は、API key を使用します。

Backend access​

Squid backend service では、this.secrets を介した read-only key-value map として secret を利用できます。

Backend code
// Access the value directly by key
const apiKey = this.secrets['MY_API_KEY'];
const dbPassword = this.secrets['DB_PASSWORD'];

この map は runtime に自動的に設定されます。backend から secret を読み取るのに API key や特別な configuration は必要ありません。

Force delete​

custom secret を delete する際は、force parameter を渡せます。default では force は false です。つまり、secret が現在 connectorで使用されている場合、deletion は失敗します。これにより、connector configuration が誤って壊れることを防止します。

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() client を使用します。

const secrets = squid.admin().secrets();

Secret の取得​

name で単一の 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
}

すべての Secret の取得​

すべての custom secret を、secret name を key とする SecretEntry object の map として取得します。

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 を更新します。method は string、number、boolean value を受け入れますが、すべての value は string として保存・返却されます。

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 の削除​

name により単一の 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 により使用されている secret を強制削除するには、2 番目の argument に 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 key は、secret client の apiKeys property を通じて管理されます。custom secret とは異なり、Squid が key value を自動生成します。

const apiKeys = squid.admin().secrets().apiKeys;

API key の取得​

name によって API key を取得します。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 key の取得​

すべての API key を SecretEntry object の map として取得します。

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 の作成または Rotation​

key name を指定して upsert を呼び出します。Squid が新しい value を自動生成します。

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 Handling​

一般的な error​

Error原因解決策
UNAUTHORIZEDclient が有効な API key で初期化されていないclient の初期化時に apiKey option で API key を渡す
Secret in useforce=false で connector に使用されている secret を delete した先に connector dependency を削除するか、force 用に true を渡す
undefined resultsecret が存在しないkey name を確認する。secret がない場合、get は undefined を返す
Request timeoutserver が operation の lock を取得できなかった少し待ってから operation を retry する

Error の処理​

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

ベストプラクティス​

Security​

  1. client に secret を公開しない。 frontend code ではなく、executablesまたはその他の backend code で secret に access します。
  2. API key の使用を制限する。 Squid client を apiKey で初期化するのは、Squid Backend などの secure な server-side environment でのみ行います。
  3. third-party service には connector を使用する。 Squid connectorは credential injection を自動的に処理するため、手動で secret を管理する必要性を減らせます。

Rotation​

  1. schedule に従って secret を rotate する。 schedulerを使用して、API key と credential を定期的に rotate します。
  2. rotation 前に lastUpdated を確認する。 まず secret の age を確認して、不要な rotation を避けます。

Operation​

  1. bulk change には batch method を使用する。 複数の secret を管理する場合、個別の call よりも upsertMany と deleteMany の方が効率的です。
  2. default では force delete を避ける。 default の動作(force=false)は、connector configuration の意図しない破損を防ぎます。

コード例​

Schedule に従って API key を rotate する​

secret management と schedulerを組み合わせ、API key を自動的に rotate します。

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

Third-party API を安全に呼び出す​

executableを使用すると、client が call を trigger できるようにしつつ、API key を server 上に保持できます。

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 - client から backend function を呼び出す
  • Schedulers - schedule に従って code を実行する
  • Connectors - managed credential を使用して third-party service に接続する