Skip to content

feat(NODE-5801): allow multiple providers providers per type #4137

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .evergreen/config.in.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ functions:
export CLIENT_ENCRYPTION=${CLIENT_ENCRYPTION}
export RUN_WITH_MONGOCRYPTD=${RUN_WITH_MONGOCRYPTD}
export CSFLE_KMS_PROVIDERS='${CSFLE_KMS_PROVIDERS}'
export FLE_AWS_KEY2='${FLE_AWS_KEY2}'
export FLE_AWS_SECRET2='${FLE_AWS_SECRET2}'
export AWS_ACCESS_KEY_ID='${AWS_ACCESS_KEY_ID}'
export AWS_SECRET_ACCESS_KEY='${AWS_SECRET_ACCESS_KEY}'
export AWS_REGION='${AWS_REGION}'
Expand Down Expand Up @@ -193,6 +195,8 @@ functions:
export CSFLE_KMS_PROVIDERS='${CSFLE_KMS_PROVIDERS}'
export AWS_ACCESS_KEY_ID='${AWS_ACCESS_KEY_ID}'
export AWS_SECRET_ACCESS_KEY='${AWS_SECRET_ACCESS_KEY}'
export FLE_AWS_KEY2='${FLE_AWS_KEY2}'
export FLE_AWS_SECRET2='${FLE_AWS_SECRET2}'
export AWS_REGION='${AWS_REGION}'
export AWS_CMK_ID='${AWS_CMK_ID}'
export AWS_DEFAULT_REGION='us-east-1'
Expand Down Expand Up @@ -471,6 +475,8 @@ functions:
cat <<EOT > prepare_client_encryption.sh
export CLIENT_ENCRYPTION='${CLIENT_ENCRYPTION}'
export CSFLE_KMS_PROVIDERS='${CSFLE_KMS_PROVIDERS}'
export FLE_AWS_KEY2='${FLE_AWS_KEY2}'
export FLE_AWS_SECRET2='${FLE_AWS_SECRET2}'
export AWS_REGION='${AWS_REGION}'
export AWS_CMK_ID='${AWS_CMK_ID}'
export AWS_ACCESS_KEY_ID='${AWS_ACCESS_KEY_ID}'
Expand Down Expand Up @@ -908,6 +914,8 @@ functions:
cat <<EOT > prepare_client_encryption.sh
export CLIENT_ENCRYPTION='${CLIENT_ENCRYPTION}'
export CSFLE_KMS_PROVIDERS='${CSFLE_KMS_PROVIDERS}'
export FLE_AWS_KEY2='${FLE_AWS_KEY2}'
export FLE_AWS_SECRET2='${FLE_AWS_SECRET2}'
export AWS_ACCESS_KEY_ID='${AWS_ACCESS_KEY_ID}'
export AWS_SECRET_ACCESS_KEY='${AWS_SECRET_ACCESS_KEY}'
export AWS_REGION='${AWS_REGION}'
Expand Down
8 changes: 8 additions & 0 deletions .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ functions:
export CLIENT_ENCRYPTION=${CLIENT_ENCRYPTION}
export RUN_WITH_MONGOCRYPTD=${RUN_WITH_MONGOCRYPTD}
export CSFLE_KMS_PROVIDERS='${CSFLE_KMS_PROVIDERS}'
export FLE_AWS_KEY2='${FLE_AWS_KEY2}'
export FLE_AWS_SECRET2='${FLE_AWS_SECRET2}'
export AWS_ACCESS_KEY_ID='${AWS_ACCESS_KEY_ID}'
export AWS_SECRET_ACCESS_KEY='${AWS_SECRET_ACCESS_KEY}'
export AWS_REGION='${AWS_REGION}'
Expand Down Expand Up @@ -165,6 +167,8 @@ functions:
export CSFLE_KMS_PROVIDERS='${CSFLE_KMS_PROVIDERS}'
export AWS_ACCESS_KEY_ID='${AWS_ACCESS_KEY_ID}'
export AWS_SECRET_ACCESS_KEY='${AWS_SECRET_ACCESS_KEY}'
export FLE_AWS_KEY2='${FLE_AWS_KEY2}'
export FLE_AWS_SECRET2='${FLE_AWS_SECRET2}'
export AWS_REGION='${AWS_REGION}'
export AWS_CMK_ID='${AWS_CMK_ID}'
export AWS_DEFAULT_REGION='us-east-1'
Expand Down Expand Up @@ -425,6 +429,8 @@ functions:
cat <<EOT > prepare_client_encryption.sh
export CLIENT_ENCRYPTION='${CLIENT_ENCRYPTION}'
export CSFLE_KMS_PROVIDERS='${CSFLE_KMS_PROVIDERS}'
export FLE_AWS_KEY2='${FLE_AWS_KEY2}'
export FLE_AWS_SECRET2='${FLE_AWS_SECRET2}'
export AWS_REGION='${AWS_REGION}'
export AWS_CMK_ID='${AWS_CMK_ID}'
export AWS_ACCESS_KEY_ID='${AWS_ACCESS_KEY_ID}'
Expand Down Expand Up @@ -881,6 +887,8 @@ functions:
cat <<EOT > prepare_client_encryption.sh
export CLIENT_ENCRYPTION='${CLIENT_ENCRYPTION}'
export CSFLE_KMS_PROVIDERS='${CSFLE_KMS_PROVIDERS}'
export FLE_AWS_KEY2='${FLE_AWS_KEY2}'
export FLE_AWS_SECRET2='${FLE_AWS_SECRET2}'
export AWS_ACCESS_KEY_ID='${AWS_ACCESS_KEY_ID}'
export AWS_SECRET_ACCESS_KEY='${AWS_SECRET_ACCESS_KEY}'
export AWS_REGION='${AWS_REGION}'
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,9 @@ node-artifacts
# AWS SAM generated
test/lambda/.aws-sam
test/lambda/env.json

# files generated by tooling in drivers-evergreen-tools
secrets-export.sh
mo-expansion.sh
mo-expansion.yml
expansions.sh
210 changes: 118 additions & 92 deletions src/client-side-encryption/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,112 @@ import { loadGCPCredentials } from './gcp';

/**
* @public
*
* A data key provider. Allowed values:
*
* - aws, gcp, local, kmip or azure
* - (`mongodb-client-encryption>=6.0.1` only) a named key, in the form of:
* `aws:<name>`, `gcp:<name>`, `local:<name>`, `kmip:<name>`, `azure:<name>`
* where `name` is an alphanumeric string, underscores allowed.
*/
export type ClientEncryptionDataKeyProvider = 'aws' | 'azure' | 'gcp' | 'local' | 'kmip';
export type ClientEncryptionDataKeyProvider = string;

/** @public */
export interface AWSKMSProviderConfiguration {
/**
* The access key used for the AWS KMS provider
*/
accessKeyId: string;

/**
* The secret access key used for the AWS KMS provider
*/
secretAccessKey: string;

/**
* An optional AWS session token that will be used as the
* X-Amz-Security-Token header for AWS requests.
*/
sessionToken?: string;
}

/** @public */
export interface LocalKMSProviderConfiguration {
/**
* The master key used to encrypt/decrypt data keys.
* A 96-byte long Buffer or base64 encoded string.
*/
key: Buffer | string;
}

/** @public */
export interface KMIPKMSProviderConfiguration {
/**
* The output endpoint string.
* The endpoint consists of a hostname and port separated by a colon.
* E.g. "example.com:123". A port is always present.
*/
endpoint?: string;
}

/** @public */
export type AzureKMSProviderConfiguration =
| {
/**
* The tenant ID identifies the organization for the account
*/
tenantId: string;

/**
* The client ID to authenticate a registered application
*/
clientId: string;

/**
* The client secret to authenticate a registered application
*/
clientSecret: string;

/**
* If present, a host with optional port. E.g. "example.com" or "example.com:443".
* This is optional, and only needed if customer is using a non-commercial Azure instance
* (e.g. a government or China account, which use different URLs).
* Defaults to "login.microsoftonline.com"
*/
identityPlatformEndpoint?: string | undefined;
}
| {
/**
* If present, an access token to authenticate with Azure.
*/
accessToken: string;
};

/** @public */
export type GCPKMSProviderConfiguration =
| {
/**
* The service account email to authenticate
*/
email: string;

/**
* A PKCS#8 encrypted key. This can either be a base64 string or a binary representation
*/
privateKey: string | Buffer;

/**
* If present, a host with optional port. E.g. "example.com" or "example.com:443".
* Defaults to "oauth2.googleapis.com"
*/
endpoint?: string | undefined;
}
| {
/**
* If present, an access token to authenticate with GCP.
*/
accessToken: string;
};

/**
* @public
Expand All @@ -15,113 +119,35 @@ export interface KMSProviders {
/**
* Configuration options for using 'aws' as your KMS provider
*/
aws?:
| {
/**
* The access key used for the AWS KMS provider
*/
accessKeyId: string;

/**
* The secret access key used for the AWS KMS provider
*/
secretAccessKey: string;

/**
* An optional AWS session token that will be used as the
* X-Amz-Security-Token header for AWS requests.
*/
sessionToken?: string;
}
| Record<string, never>;
aws?: AWSKMSProviderConfiguration | Record<string, never>;

/**
* Configuration options for using 'local' as your KMS provider
*/
local?: {
/**
* The master key used to encrypt/decrypt data keys.
* A 96-byte long Buffer or base64 encoded string.
*/
key: Buffer | string;
};
local?: LocalKMSProviderConfiguration;

/**
* Configuration options for using 'kmip' as your KMS provider
*/
kmip?: {
/**
* The output endpoint string.
* The endpoint consists of a hostname and port separated by a colon.
* E.g. "example.com:123". A port is always present.
*/
endpoint?: string;
};
kmip?: KMIPKMSProviderConfiguration;

/**
* Configuration options for using 'azure' as your KMS provider
*/
azure?:
| {
/**
* The tenant ID identifies the organization for the account
*/
tenantId: string;

/**
* The client ID to authenticate a registered application
*/
clientId: string;

/**
* The client secret to authenticate a registered application
*/
clientSecret: string;

/**
* If present, a host with optional port. E.g. "example.com" or "example.com:443".
* This is optional, and only needed if customer is using a non-commercial Azure instance
* (e.g. a government or China account, which use different URLs).
* Defaults to "login.microsoftonline.com"
*/
identityPlatformEndpoint?: string | undefined;
}
| {
/**
* If present, an access token to authenticate with Azure.
*/
accessToken: string;
}
| Record<string, never>;
azure?: AzureKMSProviderConfiguration | Record<string, never>;

/**
* Configuration options for using 'gcp' as your KMS provider
*/
gcp?:
| {
/**
* The service account email to authenticate
*/
email: string;

/**
* A PKCS#8 encrypted key. This can either be a base64 string or a binary representation
*/
privateKey: string | Buffer;

/**
* If present, a host with optional port. E.g. "example.com" or "example.com:443".
* Defaults to "oauth2.googleapis.com"
*/
endpoint?: string | undefined;
}
| {
/**
* If present, an access token to authenticate with GCP.
*/
accessToken: string;
}
| Record<string, never>;
gcp?: GCPKMSProviderConfiguration | Record<string, never>;

[key: string]:
| AWSKMSProviderConfiguration
| LocalKMSProviderConfiguration
| KMIPKMSProviderConfiguration
| AzureKMSProviderConfiguration
| GCPKMSProviderConfiguration
| undefined;
}

/**
Expand Down
6 changes: 4 additions & 2 deletions src/client-side-encryption/state_machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { BufferPool, MongoDBCollectionNamespace, promiseWithResolvers } from '..
import { type DataKey } from './client_encryption';
import { MongoCryptError } from './errors';
import { type MongocryptdManager } from './mongocryptd_manager';
import { type ClientEncryptionDataKeyProvider, type KMSProviders } from './providers';
import { type KMSProviders } from './providers';

let socks: SocksLib | null = null;
function loadSocks(): SocksLib {
Expand Down Expand Up @@ -110,6 +110,8 @@ export type CSFLEKMSTlsOptions = {
kmip?: ClientEncryptionTlsOptions;
local?: ClientEncryptionTlsOptions;
azure?: ClientEncryptionTlsOptions;

[key: string]: ClientEncryptionTlsOptions | undefined;
};

/**
Expand Down Expand Up @@ -319,7 +321,7 @@ export class StateMachine {

const tlsOptions = this.options.tlsOptions;
if (tlsOptions) {
const kmsProvider = request.kmsProvider as ClientEncryptionDataKeyProvider;
const kmsProvider = request.kmsProvider;
const providerTlsOptions = tlsOptions[kmsProvider];
if (providerTlsOptions) {
const error = this.validateTlsOptions(kmsProvider, providerTlsOptions);
Expand Down
7 changes: 6 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,13 @@ export {
} from './client-side-encryption/errors';
export type { MongocryptdManager } from './client-side-encryption/mongocryptd_manager';
export type {
AWSKMSProviderConfiguration,
AzureKMSProviderConfiguration,
ClientEncryptionDataKeyProvider,
KMSProviders
GCPKMSProviderConfiguration,
KMIPKMSProviderConfiguration,
KMSProviders,
LocalKMSProviderConfiguration
} from './client-side-encryption/providers/index';
export type {
ClientEncryptionTlsOptions,
Expand Down
Loading