Skip to content

Commit

Permalink
feat(NODE-5801): allow multiple providers providers per type (#4137)
Browse files Browse the repository at this point in the history
  • Loading branch information
baileympearson authored Jun 12, 2024
1 parent 0655c73 commit 4d209ce
Show file tree
Hide file tree
Showing 23 changed files with 3,495 additions and 152 deletions.
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
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

0 comments on commit 4d209ce

Please sign in to comment.