feat: kms support

This commit is contained in:
Daniel Hougaard
2025-09-16 15:22:33 +04:00
parent d20d88a4bf
commit b4646476a8
5 changed files with 535 additions and 64 deletions

61
src/api/endpoints/kms.ts Normal file
View File

@@ -0,0 +1,61 @@
import { ApiClient } from "../base";
import {
CreateKmsKeyOptions,
CreateKmsKeyResponse,
DeleteKmsKeyOptions,
DeleteKmsKeyResponse,
GetKmsKeyByNameOptions,
GetKmsKeyByNameResponse,
KmsDecryptDataOptions,
KmsDecryptDataResponse,
KmsEncryptDataOptions,
KmsEncryptDataResponse,
KmsGetPublicKeyOptions,
KmsGetPublicKeyResponse,
KmsListSigningAlgorithmsOptions,
KmsListSigningAlgorithmsResponse,
KmsSignDataOptions,
KmsSignDataResponse,
KmsVerifyDataOptions,
KmsVerifyDataResponse
} from "../types/kms";
export class KmsApi {
constructor(private apiClient: ApiClient) {}
async createKmsKey(data: CreateKmsKeyOptions): Promise<CreateKmsKeyResponse> {
return this.apiClient.post<CreateKmsKeyResponse>("/api/v1/kms/keys", data);
}
async deleteKmsKey(data: DeleteKmsKeyOptions): Promise<DeleteKmsKeyResponse> {
return this.apiClient.delete<DeleteKmsKeyResponse>(`/api/v1/kms/keys/${data.keyId}`);
}
async getKmsKeyByName(data: GetKmsKeyByNameOptions): Promise<GetKmsKeyByNameResponse> {
return this.apiClient.get<GetKmsKeyByNameResponse>(`/api/v1/kms/keys/key-name/${encodeURIComponent(data.name)}?projectId=${data.projectId}`);
}
async encryptData(data: KmsEncryptDataOptions): Promise<KmsEncryptDataResponse> {
return this.apiClient.post<KmsEncryptDataResponse>(`/api/v1/kms/keys/${data.keyId}/encrypt`, data);
}
async decryptData(data: KmsDecryptDataOptions): Promise<KmsDecryptDataResponse> {
return this.apiClient.post<KmsDecryptDataResponse>(`/api/v1/kms/keys/${data.keyId}/decrypt`, data);
}
async signData(data: KmsSignDataOptions): Promise<KmsSignDataResponse> {
return this.apiClient.post<KmsSignDataResponse>(`/api/v1/kms/keys/${data.keyId}/sign`, data);
}
async verifyData(data: KmsVerifyDataOptions): Promise<KmsVerifyDataResponse> {
return this.apiClient.post<KmsVerifyDataResponse>(`/api/v1/kms/keys/${data.keyId}/verify`, data);
}
async listSigningAlgorithms(data: KmsListSigningAlgorithmsOptions): Promise<KmsListSigningAlgorithmsResponse> {
return this.apiClient.get<KmsListSigningAlgorithmsResponse>(`/api/v1/kms/keys/${data.keyId}/signing-algorithms`);
}
async getSigningPublicKey(data: KmsGetPublicKeyOptions): Promise<KmsGetPublicKeyResponse> {
return this.apiClient.get<KmsGetPublicKeyResponse>(`/api/v1/kms/keys/${data.keyId}/public-key`);
}
}

135
src/api/types/kms.ts Normal file
View File

@@ -0,0 +1,135 @@
export enum EncryptionAlgorithm {
RSA_4096 = "RSA_4096",
ECC_NIST_P256 = "ECC_NIST_P256",
AES_256_GCM = "aes-256-gcm",
AES_128_GCM = "aes-128-gcm"
}
export enum SigningAlgorithm {
// RSA PSS algorithms
// These are NOT deterministic and include randomness.
// This means that the output signature is different each time for the same input.
RSASSA_PSS_SHA_512 = "RSASSA_PSS_SHA_512",
RSASSA_PSS_SHA_384 = "RSASSA_PSS_SHA_384",
RSASSA_PSS_SHA_256 = "RSASSA_PSS_SHA_256",
// RSA PKCS#1 v1.5 algorithms
// These are deterministic and the output is the same each time for the same input.
RSASSA_PKCS1_V1_5_SHA_512 = "RSASSA_PKCS1_V1_5_SHA_512",
RSASSA_PKCS1_V1_5_SHA_384 = "RSASSA_PKCS1_V1_5_SHA_384",
RSASSA_PKCS1_V1_5_SHA_256 = "RSASSA_PKCS1_V1_5_SHA_256",
// ECDSA algorithms
// None of these are deterministic and include randomness like RSA PSS.
ECDSA_SHA_512 = "ECDSA_SHA_512",
ECDSA_SHA_384 = "ECDSA_SHA_384",
ECDSA_SHA_256 = "ECDSA_SHA_256"
}
export enum KeyUsage {
ENCRYPTION = "encrypt-decrypt",
SIGNING = "sign-verify"
}
export interface KmsKey {
id: string;
description: string;
isDisabled: boolean;
orgId: string;
name: string;
projectId: string;
keyUsage: KeyUsage;
version: number;
encryptionAlgorithm: EncryptionAlgorithm;
}
export interface CreateKmsKeyOptions {
projectId: string;
name: string;
description?: string;
keyUsage: KeyUsage;
encryptionAlgorithm: EncryptionAlgorithm;
}
export interface CreateKmsKeyResponse {
key: KmsKey;
}
export interface DeleteKmsKeyOptions {
keyId: string;
}
export interface DeleteKmsKeyResponse {
key: KmsKey;
}
export interface GetKmsKeyByNameOptions {
projectId: string;
name: string;
}
export interface GetKmsKeyByNameResponse {
key: KmsKey;
}
export interface KmsEncryptDataOptions {
keyId: string;
plaintext: string;
}
export interface KmsEncryptDataResponse {
ciphertext: string;
}
export interface KmsDecryptDataOptions {
keyId: string;
ciphertext: string;
}
export interface KmsDecryptDataResponse {
plaintext: string;
}
export interface KmsSignDataOptions {
keyId: string;
data: string;
signingAlgorithm: SigningAlgorithm;
isDigest?: boolean;
}
export interface KmsSignDataResponse {
signature: string;
keyId: string;
signingAlgorithm: SigningAlgorithm;
}
export interface KmsVerifyDataOptions {
keyId: string;
data: string; // must be base64 encoded
signature: string;
signingAlgorithm: SigningAlgorithm;
isDigest?: boolean;
}
export interface KmsVerifyDataResponse {
signatureValid: boolean;
keyId: string;
signingAlgorithm: SigningAlgorithm;
}
export interface KmsListSigningAlgorithmsOptions {
keyId: string;
}
export interface KmsListSigningAlgorithmsResponse {
signingAlgorithms: SigningAlgorithm[];
}
export interface KmsGetPublicKeyOptions {
keyId: string;
}
export interface KmsGetPublicKeyResponse {
publicKey: string;
}

124
src/custom/kms.ts Normal file
View File

@@ -0,0 +1,124 @@
import { newInfisicalError } from "./errors";
import {
CreateKmsKeyOptions,
DeleteKmsKeyOptions,
GetKmsKeyByNameOptions,
KmsDecryptDataOptions,
KmsEncryptDataOptions,
KmsGetPublicKeyOptions,
KmsListSigningAlgorithmsOptions,
KmsSignDataOptions,
KmsVerifyDataOptions
} from "../api/types/kms";
import { KmsApi } from "../api/endpoints/kms";
export default class KmsClient {
constructor(private apiClient: KmsApi) {}
keys = () => {
const create = async (options: CreateKmsKeyOptions) => {
try {
const res = await this.apiClient.createKmsKey(options);
return res.key;
} catch (err) {
throw newInfisicalError(err);
}
};
const deleteKmsKey = async (options: DeleteKmsKeyOptions) => {
try {
const res = await this.apiClient.deleteKmsKey(options);
return res.key;
} catch (err) {
throw newInfisicalError(err);
}
};
const getByName = async (options: GetKmsKeyByNameOptions) => {
try {
const res = await this.apiClient.getKmsKeyByName(options);
console.log(res);
return res.key;
} catch (err) {
throw newInfisicalError(err);
}
};
return {
create,
delete: deleteKmsKey,
getByName
};
};
encryption = () => {
const encrypt = async (options: KmsEncryptDataOptions) => {
try {
const res = await this.apiClient.encryptData(options);
return res.ciphertext;
} catch (err) {
throw newInfisicalError(err);
}
};
const decrypt = async (options: KmsDecryptDataOptions) => {
try {
const res = await this.apiClient.decryptData(options);
return res.plaintext;
} catch (err) {
throw newInfisicalError(err);
}
};
return {
encrypt,
decrypt
};
};
signing = () => {
const sign = async (options: KmsSignDataOptions) => {
try {
const res = await this.apiClient.signData(options);
return res;
} catch (err) {
throw newInfisicalError(err);
}
};
const verify = async (options: KmsVerifyDataOptions) => {
try {
const res = await this.apiClient.verifyData(options);
return res;
} catch (err) {
throw newInfisicalError(err);
}
};
const listSigningAlgorithms = async (options: KmsListSigningAlgorithmsOptions) => {
try {
const res = await this.apiClient.listSigningAlgorithms(options);
return res.signingAlgorithms;
} catch (err) {
throw newInfisicalError(err);
}
};
const getPublicKey = async (options: KmsGetPublicKeyOptions) => {
try {
const res = await this.apiClient.getSigningPublicKey(options);
return res.publicKey;
} catch (err) {
throw newInfisicalError(err);
}
};
return {
sign,
verify,
listSigningAlgorithms,
getPublicKey
};
};
}

View File

@@ -12,89 +12,83 @@ import DynamicSecretsClient from "./custom/dynamic-secrets";
import EnvironmentsClient from "./custom/environments";
import ProjectsClient from "./custom/projects";
import FoldersClient from "./custom/folders";
import { KmsApi } from "./api/endpoints/kms";
import KmsClient from "./custom/kms";
type InfisicalSDKOptions = {
siteUrl?: string;
siteUrl?: string;
};
class InfisicalSDK {
private apiClient: ApiClient;
private apiClient: ApiClient;
// API instances
private authApi: AuthApi;
private secretsApi: SecretsApi;
private dynamicSecretsApi: DynamicSecretsApi;
private environmentsApi: EnvironmentsApi;
private projectsApi: ProjectsApi;
private foldersApi: FoldersApi;
// API instances
private authApi: AuthApi;
private secretsApi: SecretsApi;
private dynamicSecretsApi: DynamicSecretsApi;
private environmentsApi: EnvironmentsApi;
private projectsApi: ProjectsApi;
private foldersApi: FoldersApi;
private kmsApi: KmsApi;
// Domain clients
private authClient: AuthClient;
private secretsClient: SecretsClient;
private dynamicSecretsClient: DynamicSecretsClient;
private environmentsClient: EnvironmentsClient;
private projectsClient: ProjectsClient;
private foldersClient: FoldersClient;
// Domain clients
private authClient: AuthClient;
private secretsClient: SecretsClient;
private dynamicSecretsClient: DynamicSecretsClient;
private environmentsClient: EnvironmentsClient;
private projectsClient: ProjectsClient;
private foldersClient: FoldersClient;
private kmsClient: KmsClient;
constructor(options?: InfisicalSDKOptions) {
const baseURL = options?.siteUrl || "https://app.infisical.com";
constructor(options?: InfisicalSDKOptions) {
const baseURL = options?.siteUrl || "https://app.infisical.com";
// Initialize the base API client
this.apiClient = new ApiClient({ baseURL });
// Initialize the base API client
this.apiClient = new ApiClient({ baseURL });
// Initialize API service instances
this.authApi = new AuthApi(this.apiClient);
this.secretsApi = new SecretsApi(this.apiClient);
this.dynamicSecretsApi = new DynamicSecretsApi(this.apiClient);
this.environmentsApi = new EnvironmentsApi(this.apiClient);
this.projectsApi = new ProjectsApi(this.apiClient);
this.foldersApi = new FoldersApi(this.apiClient);
// Initialize API service instances
this.authApi = new AuthApi(this.apiClient);
this.secretsApi = new SecretsApi(this.apiClient);
this.dynamicSecretsApi = new DynamicSecretsApi(this.apiClient);
this.environmentsApi = new EnvironmentsApi(this.apiClient);
this.projectsApi = new ProjectsApi(this.apiClient);
this.foldersApi = new FoldersApi(this.apiClient);
this.kmsApi = new KmsApi(this.apiClient);
// Initialize domain clients
this.authClient = new AuthClient(
this.authenticate.bind(this),
this.authApi
);
this.secretsClient = new SecretsClient(this.secretsApi);
this.dynamicSecretsClient = new DynamicSecretsClient(
this.dynamicSecretsApi
);
this.environmentsClient = new EnvironmentsClient(this.environmentsApi);
this.projectsClient = new ProjectsClient(this.projectsApi);
this.foldersClient = new FoldersClient(this.foldersApi);
}
// Initialize domain clients
this.authClient = new AuthClient(this.authenticate.bind(this), this.authApi);
this.secretsClient = new SecretsClient(this.secretsApi);
this.dynamicSecretsClient = new DynamicSecretsClient(this.dynamicSecretsApi);
this.environmentsClient = new EnvironmentsClient(this.environmentsApi);
this.projectsClient = new ProjectsClient(this.projectsApi);
this.foldersClient = new FoldersClient(this.foldersApi);
this.kmsClient = new KmsClient(this.kmsApi);
}
private authenticate(accessToken: string) {
// Set the token on the API client
this.apiClient.setAccessToken(accessToken);
private authenticate(accessToken: string) {
// Set the token on the API client
this.apiClient.setAccessToken(accessToken);
// Reinitialize the auth client with the token
this.authClient = new AuthClient(
this.authenticate.bind(this),
this.authApi,
accessToken
);
// Reinitialize the auth client with the token
this.authClient = new AuthClient(this.authenticate.bind(this), this.authApi, accessToken);
return this;
}
return this;
}
// Public methods to access domain clients
secrets = () => this.secretsClient;
environments = () => this.environmentsClient;
projects = () => this.projectsClient;
folders = () => this.foldersClient;
dynamicSecrets = () => this.dynamicSecretsClient;
auth = () => this.authClient;
// Public methods to access domain clients
secrets = () => this.secretsClient;
environments = () => this.environmentsClient;
projects = () => this.projectsClient;
folders = () => this.foldersClient;
dynamicSecrets = () => this.dynamicSecretsClient;
auth = () => this.authClient;
kms = () => this.kmsClient;
}
// Export main SDK class
export { InfisicalSDK };
export * from './api/types'
export * from "./api/types";
// Export types and enums from schemas
export {
TDynamicSecretProvider,
DynamicSecretProviders,
SqlProviders,
} from "./custom/schemas";
export { TDynamicSecretProvider, DynamicSecretProviders, SqlProviders } from "./custom/schemas";