Skip to content
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

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

Merged
merged 4 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
mo-expansion.yml
expansions.sh
212 changes: 120 additions & 92 deletions src/client-side-encryption/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,124 +4,152 @@ 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
* Configuration options that are used by specific KMS providers during key generation, encryption, and decryption.
*
* Named KMS providers _are not supported_ for automatic KMS credential fetching.
*/
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