diff --git a/.changelog/2509.txt b/.changelog/2509.txt new file mode 100644 index 0000000000..68aab37b6a --- /dev/null +++ b/.changelog/2509.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/mongodbatlas_encryption_at_rest: Adds new `azure_key_vault_config.#.require_private_networking` field to enable connection to Azure Key Vault over private networking +``` diff --git a/.changelog/2512.txt b/.changelog/2512.txt new file mode 100644 index 0000000000..8197f201b4 --- /dev/null +++ b/.changelog/2512.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +resource/mongodbatlas_encryption_at_rest_private_endpoint +``` diff --git a/.changelog/2527.txt b/.changelog/2527.txt new file mode 100644 index 0000000000..c8acc8ea4e --- /dev/null +++ b/.changelog/2527.txt @@ -0,0 +1,3 @@ +```release-note:new-datasource +data-source/mongodbatlas_encryption_at_rest_private_endpoint +``` diff --git a/.changelog/2536.txt b/.changelog/2536.txt new file mode 100644 index 0000000000..c7f1c1323e --- /dev/null +++ b/.changelog/2536.txt @@ -0,0 +1,3 @@ +```release-note:new-datasource +data-source/mongodbatlas_encryption_at_rest_private_endpoints +``` diff --git a/.changelog/2538.txt b/.changelog/2538.txt new file mode 100644 index 0000000000..9127a008da --- /dev/null +++ b/.changelog/2538.txt @@ -0,0 +1,7 @@ +```release-note:new-datasource +data-source/mongodbatlas_encryption_at_rest +``` + +```release-note:enhancement +resource/mongodbatlas_encryption_at_rest: Adds `aws_kms_config.0.valid`, `azure_key_vault_config.0.valid` and `google_cloud_kms_config.0.valid` attribute +``` diff --git a/.github/workflows/acceptance-tests-runner.yml b/.github/workflows/acceptance-tests-runner.yml index 14ec550d01..8a51636934 100644 --- a/.github/workflows/acceptance-tests-runner.yml +++ b/.github/workflows/acceptance-tests-runner.yml @@ -86,6 +86,15 @@ on: mongodb_atlas_federated_settings_associated_domain: type: string required: true + mongodb_atlas_project_ear_pe_id: + type: string + required: true + mongodb_atlas_enable_preview: + type: string + required: true + azure_private_endpoint_region: + type: string + required: true secrets: # all secrets are passed explicitly in this workflow mongodb_atlas_public_key: required: true @@ -135,6 +144,18 @@ on: required: true azure_vnet_name_updated: required: true + azure_client_id: + required: true + azure_key_vault_name: + required: true + azure_key_identifier: + required: true + azure_key_vault_name_updated: + required: true + azure_key_identifier_updated: + required: true + azure_app_secret: + required: true env: TF_ACC: 1 @@ -238,7 +259,8 @@ jobs: data_lake: - 'internal/service/datalakepipeline/*.go' encryption: - - 'internal/service/encryptionatrest/*.go' + - 'internal/service/encryptionatrest/*.go' + - 'internal/service/encryptionatrestprivateendpoint/*.go' event_trigger: - 'internal/service/eventtrigger/*.go' federated: @@ -515,7 +537,21 @@ jobs: - name: Acceptance Tests env: MONGODB_ATLAS_LAST_VERSION: ${{ needs.get-provider-version.outputs.provider_version }} - ACCTEST_PACKAGES: ./internal/service/encryptionatrest + ACCTEST_PACKAGES: | + ./internal/service/encryptionatrest + ./internal/service/encryptionatrestprivateendpoint + MONGODB_ATLAS_PROJECT_EAR_PE_ID: ${{ inputs.mongodb_atlas_project_ear_pe_id }} + AZURE_PRIVATE_ENDPOINT_REGION: ${{ inputs.azure_private_endpoint_region }} + AZURE_CLIENT_ID: ${{ secrets.azure_client_id }} + AZURE_RESOURCE_GROUP_NAME: ${{ secrets.azure_resource_group_name }} + AZURE_SUBSCRIPTION_ID: ${{ secrets.azure_subscription_id }} + AZURE_TENANT_ID: ${{ vars.azure_tenant_id }} + AZURE_APP_SECRET: ${{ secrets.azure_app_secret }} + AZURE_KEY_VAULT_NAME: ${{ secrets.azure_key_vault_name }} + AZURE_KEY_IDENTIFIER: ${{ secrets.azure_key_identifier }} + AZURE_KEY_VAULT_NAME_UPDATED: ${{ secrets.azure_key_vault_name_updated }} + AZURE_KEY_IDENTIFIER_UPDATED: ${{ secrets.azure_key_identifier_updated }} + MONGODB_ATLAS_ENABLE_PREVIEW: ${{ inputs.mongodb_atlas_enable_preview }} run: make testacc event_trigger: diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index e02fd08675..e15be2a2c4 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -77,6 +77,12 @@ jobs: azure_subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} azure_vnet_name: ${{ secrets.AZURE_VNET_NAME }} azure_vnet_name_updated: ${{ secrets.AZURE_VNET_NAME_UPDATED }} + azure_client_id: ${{ secrets.AZURE_CLIENT_ID }} + azure_key_vault_name: ${{ secrets.AZURE_KEY_VAULT_NAME }} + azure_key_identifier: ${{ secrets.AZURE_KEY_IDENTIFIER }} + azure_key_vault_name_updated: ${{ secrets.AZURE_KEY_VAULT_NAME_UPDATED }} + azure_key_identifier_updated: ${{ secrets.AZURE_KEY_IDENTIFIER_UPDATED }} + azure_app_secret: ${{ secrets.AZURE_APP_SECRET }} with: terraform_version: ${{ inputs.terraform_version || vars.TF_VERSION_LATEST }} @@ -104,3 +110,6 @@ jobs: mongodb_atlas_gov_org_id: ${{ inputs.atlas_cloud_env == 'qa' && vars.MONGODB_ATLAS_GOV_ORG_ID_QA || vars.MONGODB_ATLAS_GOV_ORG_ID_DEV }} mongodb_atlas_gov_project_owner_id: ${{ inputs.atlas_cloud_env == 'qa' && vars.MONGODB_ATLAS_GOV_PROJECT_OWNER_ID_QA || vars.MONGODB_ATLAS_GOV_PROJECT_OWNER_ID_DEV }} mongodb_atlas_federated_settings_associated_domain: ${{ vars.MONGODB_ATLAS_FEDERATED_SETTINGS_ASSOCIATED_DOMAIN }} + mongodb_atlas_project_ear_pe_id: ${{ inputs.atlas_cloud_env == 'qa' && vars.MONGODB_ATLAS_PROJECT_EAR_PE_ID_QA || vars.MONGODB_ATLAS_PROJECT_EAR_PE_ID_DEV }} + mongodb_atlas_enable_preview: ${{ vars.MONGODB_ATLAS_ENABLE_PREVIEW }} + azure_private_endpoint_region: ${{ vars.AZURE_PRIVATE_ENDPOINT_REGION }} diff --git a/.github/workflows/code-health.yml b/.github/workflows/code-health.yml index 87b7cb3a25..652ecacdc4 100644 --- a/.github/workflows/code-health.yml +++ b/.github/workflows/code-health.yml @@ -70,13 +70,17 @@ jobs: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - run: make tools # all resources with auto-generated doc must be specified below here - name: Doc for control_plane_ip_addresses - run: export resource_name=control_plane_ip_addresses && make generate-doc + run: make generate-doc resource_name=control_plane_ip_addresses - name: Doc for push_based_log_export - run: export resource_name=push_based_log_export && make generate-doc + run: make generate-doc resource_name=push_based_log_export - name: Doc for search_deployment - run: export resource_name=search_deployment && make generate-doc + run: make generate-doc resource_name=search_deployment + - name: Doc for encryption_at_rest + run: make generate-doc resource_name=encryption_at_rest + - name: Doc for encryption_at_rest_private_endpoint + run: make generate-doc resource_name=encryption_at_rest_private_endpoint - name: Doc for project_ip_addresses - run: export resource_name=project_ip_addresses && make generate-doc + run: make generate-doc resource_name=project_ip_addresses - name: Find mutations id: self_mutation run: |- diff --git a/GNUmakefile b/GNUmakefile index 84619e6bde..d8739af884 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -124,8 +124,10 @@ scaffold-schemas: .PHONY: generate-doc -generate-doc: ## Generate the resource documentation via tfplugindocs - ./scripts/generate-doc.sh ${resource_name} +# e.g. run: make generate-doc resource_name=search_deployment +# generate the resource documentation via tfplugindocs +generate-doc: + @scripts/generate-doc.sh ${resource_name} .PHONY: update-tf-compatibility-matrix update-tf-compatibility-matrix: ## Update Terraform Compatibility Matrix documentation diff --git a/contributing/development-setup.md b/contributing/development-setup.md index ece7da2611..7d34219be7 100644 --- a/contributing/development-setup.md +++ b/contributing/development-setup.md @@ -218,15 +218,12 @@ You must also configure the following environment variables before running the t export AZURE_CLIENT_ID= export AZURE_SUBSCRIPTION_ID= export AZURE_RESOURCE_GROUP_NAME= - export AZURE_SECRET= + export AZURE_APP_SECRET= export AZURE_KEY_VAULT_NAME= export AZURE_KEY_IDENTIFIER= export AZURE_TENANT_ID= export AZURE_DIRECTORY_ID= - export AZURE_CLIENT_ID_UPDATED= - export AZURE_RESOURCE_GROUP_NAME_UPDATED= - export AZURE_SECRET_UPDATED= export AZURE_KEY_VAULT_NAME_UPDATED= export AZURE_KEY_IDENTIFIER_UPDATED= ``` diff --git a/contributing/documentation.md b/contributing/documentation.md index eaa3d9eae4..6879da6f53 100644 --- a/contributing/documentation.md +++ b/contributing/documentation.md @@ -12,5 +12,5 @@ We autogenerate the documentation of our provider resources and data sources via - Add the resource/data source templates to the [templates](https://github.com/mongodb/terraform-provider-mongodbatlas/blob/master/templates) folder. See [README.md](https://github.com/mongodb/terraform-provider-mongodbatlas/blob/master/templates/README.md) for more info. - Run the Makefile command `generate-doc` ```bash -export resource_name=search_deployment && make generate-doc +make generate-doc resource_name=search_deployment ``` diff --git a/docs/data-sources/encryption_at_rest.md b/docs/data-sources/encryption_at_rest.md new file mode 100644 index 0000000000..d5f2e240a9 --- /dev/null +++ b/docs/data-sources/encryption_at_rest.md @@ -0,0 +1,190 @@ +# Data Source: mongodbatlas_encryption_at_rest + +`mongodbatlas_encryption_at_rest` describes encryption at rest configuration for an Atlas project with one of the following providers: + +[Amazon Web Services Key Management Service](https://docs.atlas.mongodb.com/security-aws-kms/#security-aws-kms) +[Azure Key Vault](https://docs.atlas.mongodb.com/security-azure-kms/#security-azure-kms) +[Google Cloud KMS](https://docs.atlas.mongodb.com/security-gcp-kms/#security-gcp-kms) + + +~> **IMPORTANT** By default, Atlas enables encryption at rest for all cluster storage and snapshot volumes. + +~> **IMPORTANT** Atlas limits this feature to dedicated cluster tiers of M10 and greater. For more information see: https://www.mongodb.com/docs/atlas/reference/api-resources-spec/#tag/Encryption-at-Rest-using-Customer-Key-Management + +-> **NOTE:** Groups and projects are synonymous terms. You may find `groupId` in the official documentation. + + +## Example Usages + +### Configuring encryption at rest using customer key management in AWS +```terraform +resource "mongodbatlas_cloud_provider_access_setup" "setup_only" { + project_id = var.atlas_project_id + provider_name = "AWS" +} + +resource "mongodbatlas_cloud_provider_access_authorization" "auth_role" { + project_id = var.atlas_project_id + role_id = mongodbatlas_cloud_provider_access_setup.setup_only.role_id + + aws { + iam_assumed_role_arn = aws_iam_role.test_role.arn + } +} + +resource "mongodbatlas_encryption_at_rest" "test" { + project_id = var.atlas_project_id + + aws_kms_config { + enabled = true + customer_master_key_id = aws_kms_key.kms_key.id + region = var.atlas_region + role_id = mongodbatlas_cloud_provider_access_authorization.auth_role.role_id + } +} + +resource "mongodbatlas_advanced_cluster" "cluster" { + project_id = mongodbatlas_encryption_at_rest.test.project_id + name = "MyCluster" + cluster_type = "REPLICASET" + backup_enabled = true + encryption_at_rest_provider = "AWS" + + replication_specs { + region_configs { + priority = 7 + provider_name = "AWS" + region_name = "US_EAST_1" + electable_specs { + instance_size = "M10" + node_count = 3 + } + } + } +} + +data "mongodbatlas_encryption_at_rest" "test" { + project_id = mongodbatlas_encryption_at_rest.test.project_id +} + +output "is_aws_kms_encryption_at_rest_valid" { + value = data.mongodbatlas_encryption_at_rest.test.aws_kms_config.valid +} +``` + +### Configuring encryption at rest using customer key management in Azure +```terraform +resource "mongodbatlas_encryption_at_rest" "test" { + project_id = var.atlas_project_id + + azure_key_vault_config { + enabled = true + azure_environment = "AZURE" + + tenant_id = var.azure_tenant_id + subscription_id = var.azure_subscription_id + client_id = var.azure_client_id + secret = var.azure_client_secret + + resource_group_name = var.azure_resource_group_name + key_vault_name = var.azure_key_vault_name + key_identifier = var.azure_key_identifier + } +} + +data "mongodbatlas_encryption_at_rest" "test" { + project_id = mongodbatlas_encryption_at_rest.test.project_id +} + +output "is_azure_encryption_at_rest_valid" { + value = data.mongodbatlas_encryption_at_rest.test.azure_key_vault_config.valid +} +``` + +-> **NOTE:** It is possible to configure Atlas Encryption at Rest to communicate with Azure Key Vault using Azure Private Link, ensuring that all traffic between Atlas and Key Vault takes place over Azure’s private network interfaces. Please review `mongodbatlas_encryption_at_rest_private_endpoint` resource for details. + +### Configuring encryption at rest using customer key management in GCP +```terraform +resource "mongodbatlas_encryption_at_rest" "test" { + project_id = var.atlas_project_id + + google_cloud_kms_config { + enabled = true + service_account_key = "{\"type\": \"service_account\",\"project_id\": \"my-project-common-0\",\"private_key_id\": \"e120598ea4f88249469fcdd75a9a785c1bb3\",\"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEuwIBA(truncated)SfecnS0mT94D9\\n-----END PRIVATE KEY-----\\n\",\"client_email\": \"my-email-kms-0@my-project-common-0.iam.gserviceaccount.com\",\"client_id\": \"10180967717292066\",\"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\"token_uri\": \"https://accounts.google.com/o/oauth2/token\",\"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/my-email-kms-0%40my-project-common-0.iam.gserviceaccount.com\"}" + key_version_resource_id = "projects/my-project-common-0/locations/us-east4/keyRings/my-key-ring-0/cryptoKeys/my-key-0/cryptoKeyVersions/1" + } +} + +data "mongodbatlas_encryption_at_rest" "test" { + project_id = mongodbatlas_encryption_at_rest.test.project_id +} + +output "is_gcp_encryption_at_rest_valid" { + value = data.mongodbatlas_encryption_at_rest.test.google_cloud_kms_config.valid +} +``` + + +## Schema + +### Required + +- `project_id` (String) Unique 24-hexadecimal digit string that identifies your project. + +### Read-Only + +- `aws_kms_config` (Attributes) Amazon Web Services (AWS) KMS configuration details and encryption at rest configuration set for the specified project. (see [below for nested schema](#nestedatt--aws_kms_config)) +- `azure_key_vault_config` (Attributes) Details that define the configuration of Encryption at Rest using Azure Key Vault (AKV). (see [below for nested schema](#nestedatt--azure_key_vault_config)) +- `google_cloud_kms_config` (Attributes) Details that define the configuration of Encryption at Rest using Google Cloud Key Management Service (KMS). (see [below for nested schema](#nestedatt--google_cloud_kms_config)) +- `id` (String) The ID of this resource. + + +### Nested Schema for `aws_kms_config` + +Read-Only: + +- `access_key_id` (String, Sensitive) Unique alphanumeric string that identifies an Identity and Access Management (IAM) access key with permissions required to access your Amazon Web Services (AWS) Customer Master Key (CMK). +- `customer_master_key_id` (String, Sensitive) Unique alphanumeric string that identifies the Amazon Web Services (AWS) Customer Master Key (CMK) you used to encrypt and decrypt the MongoDB master keys. +- `enabled` (Boolean) Flag that indicates whether someone enabled encryption at rest for the specified project through Amazon Web Services (AWS) Key Management Service (KMS). To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`. +- `region` (String) Physical location where MongoDB Atlas deploys your AWS-hosted MongoDB cluster nodes. The region you choose can affect network latency for clients accessing your databases. When MongoDB Atlas deploys a dedicated cluster, it checks if a VPC or VPC connection exists for that provider and region. If not, MongoDB Atlas creates them as part of the deployment. MongoDB Atlas assigns the VPC a CIDR block. To limit a new VPC peering connection to one CIDR block and region, create the connection first. Deploy the cluster after the connection starts. +- `role_id` (String) Unique 24-hexadecimal digit string that identifies an Amazon Web Services (AWS) Identity and Access Management (IAM) role. This IAM role has the permissions required to manage your AWS customer master key. +- `secret_access_key` (String, Sensitive) Human-readable label of the Identity and Access Management (IAM) secret access key with permissions required to access your Amazon Web Services (AWS) customer master key. +- `valid` (Boolean) Flag that indicates whether the Amazon Web Services (AWS) Key Management Service (KMS) encryption key can encrypt and decrypt data. + + + +### Nested Schema for `azure_key_vault_config` + +Read-Only: + +- `azure_environment` (String) Azure environment in which your account credentials reside. +- `client_id` (String, Sensitive) Unique 36-hexadecimal character string that identifies an Azure application associated with your Azure Active Directory tenant. +- `enabled` (Boolean) Flag that indicates whether someone enabled encryption at rest for the specified project. To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`. +- `key_identifier` (String, Sensitive) Web address with a unique key that identifies for your Azure Key Vault. +- `key_vault_name` (String) Unique string that identifies the Azure Key Vault that contains your key. +- `require_private_networking` (Boolean) Enable connection to your Azure Key Vault over private networking. +- `resource_group_name` (String) Name of the Azure resource group that contains your Azure Key Vault. +- `secret` (String, Sensitive) Private data that you need secured and that belongs to the specified Azure Key Vault (AKV) tenant (**azureKeyVault.tenantID**). This data can include any type of sensitive data such as passwords, database connection strings, API keys, and the like. AKV stores this information as encrypted binary data. +- `subscription_id` (String, Sensitive) Unique 36-hexadecimal character string that identifies your Azure subscription. +- `tenant_id` (String, Sensitive) Unique 36-hexadecimal character string that identifies the Azure Active Directory tenant within your Azure subscription. +- `valid` (Boolean) Flag that indicates whether the Azure encryption key can encrypt and decrypt data. + + + +### Nested Schema for `google_cloud_kms_config` + +Read-Only: + +- `enabled` (Boolean) Flag that indicates whether someone enabled encryption at rest for the specified project. To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`. +- `key_version_resource_id` (String, Sensitive) Resource path that displays the key version resource ID for your Google Cloud KMS. +- `service_account_key` (String, Sensitive) JavaScript Object Notation (JSON) object that contains the Google Cloud Key Management Service (KMS). Format the JSON as a string and not as an object. +- `valid` (Boolean) Flag that indicates whether the Google Cloud Key Management Service (KMS) encryption key can encrypt and decrypt data. + +# Import +Encryption at Rest Settings can be imported using project ID, in the format `project_id`, e.g. + +``` +$ terraform import mongodbatlas_encryption_at_rest.example 1112222b3bf99403840e8934 +``` + +For more information see: [MongoDB Atlas API Reference for Encryption at Rest using Customer Key Management.](https://www.mongodb.com/docs/atlas/reference/api-resources-spec/#tag/Encryption-at-Rest-using-Customer-Key-Management) \ No newline at end of file diff --git a/docs/data-sources/encryption_at_rest_private_endpoint.md b/docs/data-sources/encryption_at_rest_private_endpoint.md new file mode 100644 index 0000000000..3cd1f2e29e --- /dev/null +++ b/docs/data-sources/encryption_at_rest_private_endpoint.md @@ -0,0 +1,42 @@ +# Data Source: mongodbatlas_encryption_at_rest_private_endpoint + +`mongodbatlas_encryption_at_rest_private_endpoint` describes a private endpoint used for encryption at rest using customer-managed keys. + +~> **IMPORTANT** The Encryption at Rest using Azure Key Vault over Private Endpoints feature is available by request. To request this functionality for your Atlas deployments, contact your Account Manager. +Additionally, you'll need to set the environment variable `MONGODB_ATLAS_ENABLE_PREVIEW=true` to use this data source. To learn more about existing limitations, see the [Manage Customer Keys with Azure Key Vault Over Private Endpoints](https://www.mongodb.com/docs/atlas/security/azure-kms-over-private-endpoint/#manage-customer-keys-with-azure-key-vault-over-private-endpoints). + +## Example Usages + +-> **NOTE:** Only Azure Key Vault with Azure Private Link is supported at this time. + +```terraform +data "mongodbatlas_encryption_at_rest_private_endpoint" "single" { + project_id = var.atlas_project_id + cloud_provider = "AZURE" + id = mongodbatlas_encryption_at_rest_private_endpoint.endpoint.id +} + +output "endpoint_connection_name" { + value = data.mongodbatlas_encryption_at_rest_private_endpoint.single.private_endpoint_connection_name +} +``` + + +## Schema + +### Required + +- `cloud_provider` (String) Label that identifies the cloud provider of the private endpoint. +- `id` (String) Unique 24-hexadecimal digit string that identifies the Private Endpoint Service. +- `project_id` (String) Unique 24-hexadecimal digit string that identifies your project. + +### Read-Only + +- `error_message` (String) Error message for failures associated with the Encryption At Rest private endpoint. +- `private_endpoint_connection_name` (String) Connection name of the Azure Private Endpoint. +- `region_name` (String) Cloud provider region in which the Encryption At Rest private endpoint is located. +- `status` (String) State of the Encryption At Rest private endpoint. + +For more information see: +- [MongoDB Atlas API - Private Endpoint for Encryption at Rest Using Customer Key Management](https://www.mongodb.com/docs/atlas/reference/api-resources-spec/v2/#tag/Encryption-at-Rest-using-Customer-Key-Management/operation/getEncryptionAtRestPrivateEndpoint) Documentation. +- [Manage Customer Keys with Azure Key Vault Over Private Endpoints](https://www.mongodb.com/docs/atlas/security/azure-kms-over-private-endpoint/). diff --git a/docs/data-sources/encryption_at_rest_private_endpoints.md b/docs/data-sources/encryption_at_rest_private_endpoints.md new file mode 100644 index 0000000000..96f3fd17b0 --- /dev/null +++ b/docs/data-sources/encryption_at_rest_private_endpoints.md @@ -0,0 +1,50 @@ +# Data Source: mongodbatlas_encryption_at_rest_private_endpoints + +`mongodbatlas_encryption_at_rest_private_endpoints` describes private endpoints of a particular cloud provider used for encryption at rest using customer-managed keys. + +~> **IMPORTANT** The Encryption at Rest using Azure Key Vault over Private Endpoints feature is available by request. To request this functionality for your Atlas deployments, contact your Account Manager. +Additionally, you'll need to set the environment variable `MONGODB_ATLAS_ENABLE_PREVIEW=true` to use this data source. To learn more about existing limitations, see the [Manage Customer Keys with Azure Key Vault Over Private Endpoints](https://www.mongodb.com/docs/atlas/security/azure-kms-over-private-endpoint/#manage-customer-keys-with-azure-key-vault-over-private-endpoints). + +## Example Usages + +-> **NOTE:** Only Azure Key Vault with Azure Private Link is supported at this time. + +```terraform +data "mongodbatlas_encryption_at_rest_private_endpoints" "plural" { + project_id = var.atlas_project_id + cloud_provider = "AZURE" +} + +output "number_of_endpoints" { + value = length(data.mongodbatlas_encryption_at_rest_private_endpoints.plural.results) +} +``` + + +## Schema + +### Required + +- `cloud_provider` (String) Human-readable label that identifies the cloud provider for the private endpoints to return. +- `project_id` (String) Unique 24-hexadecimal digit string that identifies your project. + +### Read-Only + +- `results` (Attributes List) List of returned documents that MongoDB Cloud providers when completing this request. (see [below for nested schema](#nestedatt--results)) + + +### Nested Schema for `results` + +Read-Only: + +- `cloud_provider` (String) Label that identifies the cloud provider of the private endpoint. +- `error_message` (String) Error message for failures associated with the Encryption At Rest private endpoint. +- `id` (String) Unique 24-hexadecimal digit string that identifies the Private Endpoint Service. +- `private_endpoint_connection_name` (String) Connection name of the Azure Private Endpoint. +- `project_id` (String) Unique 24-hexadecimal digit string that identifies your project. +- `region_name` (String) Cloud provider region in which the Encryption At Rest private endpoint is located. +- `status` (String) State of the Encryption At Rest private endpoint. + +For more information see: +- [MongoDB Atlas API - Private Endpoint for Encryption at Rest Using Customer Key Management](https://www.mongodb.com/docs/atlas/reference/api-resources-spec/v2/#tag/Encryption-at-Rest-using-Customer-Key-Management/operation/getEncryptionAtRestPrivateEndpointsForCloudProvider) Documentation. +- [Manage Customer Keys with Azure Key Vault Over Private Endpoints](https://www.mongodb.com/docs/atlas/security/azure-kms-over-private-endpoint/). diff --git a/docs/resources/encryption_at_rest.md b/docs/resources/encryption_at_rest.md index 5ac02ddbe4..dbf92fbc65 100644 --- a/docs/resources/encryption_at_rest.md +++ b/docs/resources/encryption_at_rest.md @@ -1,20 +1,17 @@ # Resource: mongodbatlas_encryption_at_rest -`mongodbatlas_encryption_at_rest` allows management of encryption at rest for an Atlas project with one of the following providers: +`mongodbatlas_encryption_at_rest` allows management of Encryption at Rest for an Atlas project using Customer Key Management configuration. The following providers are supported: +- [Amazon Web Services Key Management Service](https://docs.atlas.mongodb.com/security-aws-kms/#security-aws-kms) +- [Azure Key Vault](https://docs.atlas.mongodb.com/security-azure-kms/#security-azure-kms) +- [Google Cloud KMS](https://docs.atlas.mongodb.com/security-gcp-kms/#security-gcp-kms) -[Amazon Web Services Key Management Service](https://docs.atlas.mongodb.com/security-aws-kms/#security-aws-kms) -[Azure Key Vault](https://docs.atlas.mongodb.com/security-azure-kms/#security-azure-kms) -[Google Cloud KMS](https://docs.atlas.mongodb.com/security-gcp-kms/#security-gcp-kms) - -The [encryption at rest Terraform module](https://registry.terraform.io/modules/terraform-mongodbatlas-modules/encryption-at-rest/mongodbatlas/latest) makes use of this resource and simplifies its use. - -After configuring at least one Encryption at Rest provider for the Atlas project, Project Owners can enable Encryption at Rest for each Atlas cluster for which they require encryption. The Encryption at Rest provider does not have to match the cluster cloud service provider. +The [encryption at rest Terraform module](https://registry.terraform.io/modules/terraform-mongodbatlas-modules/encryption-at-rest/mongodbatlas/latest) makes use of this resource and simplifies its use. It is currently limited to AWS KMS. Atlas does not automatically rotate user-managed encryption keys. Defer to your preferred Encryption at Rest provider’s documentation and guidance for best practices on key rotation. Atlas automatically creates a 90-day key rotation alert when you configure Encryption at Rest using your Key Management in an Atlas project. See [Encryption at Rest](https://docs.atlas.mongodb.com/security-kms-encryption/index.html) for more information, including prerequisites and restrictions. -~> **IMPORTANT** Atlas encrypts all cluster storage and snapshot volumes, securing all cluster data on disk: a concept known as encryption at rest, by default. +~> **IMPORTANT** By default, Atlas enables encryption at rest for all cluster storage and snapshot volumes. ~> **IMPORTANT** Atlas limits this feature to dedicated cluster tiers of M10 and greater. For more information see: https://www.mongodb.com/docs/atlas/reference/api-resources-spec/#tag/Encryption-at-Rest-using-Customer-Key-Management @@ -23,40 +20,74 @@ See [Encryption at Rest](https://docs.atlas.mongodb.com/security-kms-encryption/ -> **IMPORTANT NOTE** To disable the encryption at rest with customer key management for a project all existing clusters in the project must first either have encryption at rest for the provider set to none, e.g. `encryption_at_rest_provider = "NONE"`, or be deleted. -## Example Usage +## Enabling Encryption at Rest for existing Atlas cluster + +After configuring at least one key management provider for an Atlas project, Project Owners can enable customer key management for each Atlas cluster for which they require encryption. For clusters defined in terraform, the [`encryption_at_rest_provider` attribute](advanced_cluster#encryption_at_rest_provider) can be used in both `mongodbatlas_advanced_cluster` and `mongodbatlas_cluster` resources. The key management provider does not have to match the cluster cloud service provider. + +Please reference [Enable Customer Key Management for an Atlas Cluster](https://www.mongodb.com/docs/atlas/security-kms-encryption/#enable-customer-key-management-for-an-service-cluster) documentation for additional considerations. + + +## Example Usages + +### Configuring encryption at rest using customer key management in AWS +The configuration of encryption at rest with customer key management, `mongodbatlas_encryption_at_rest`, needs to be completed before a cluster is created in the project. Force this wait by using an implicit dependency via `project_id` as shown in the example below. ```terraform +resource "mongodbatlas_cloud_provider_access_setup" "setup_only" { + project_id = var.atlas_project_id + provider_name = "AWS" +} + +resource "mongodbatlas_cloud_provider_access_authorization" "auth_role" { + project_id = var.atlas_project_id + role_id = mongodbatlas_cloud_provider_access_setup.setup_only.role_id + + aws { + iam_assumed_role_arn = aws_iam_role.test_role.arn + } +} + resource "mongodbatlas_encryption_at_rest" "test" { - project_id = "" + project_id = var.atlas_project_id aws_kms_config { enabled = true - customer_master_key_id = "5ce83906-6563-46b7-8045-11c20e3a5766" - region = "US_EAST_1" - role_id = "60815e2fe01a49138a928ebb" + customer_master_key_id = aws_kms_key.kms_key.id + region = var.atlas_region + role_id = mongodbatlas_cloud_provider_access_authorization.auth_role.role_id } +} - azure_key_vault_config { - enabled = true - client_id = "g54f9e2-89e3-40fd-8188-EXAMPLEID" - azure_environment = "AZURE" - subscription_id = "0ec944e3-g725-44f9-a147-EXAMPLEID" - resource_group_name = "ExampleRGName" - key_vault_name = "EXAMPLEKeyVault" - key_identifier = "https://EXAMPLEKeyVault.vault.azure.net/keys/EXAMPLEKey/d891821e3d364e9eb88fbd3d11807b86" - secret = "EXAMPLESECRET" - tenant_id = "e8e4b6ba-ff32-4c88-a9af-EXAMPLEID" - } +resource "mongodbatlas_advanced_cluster" "cluster" { + project_id = mongodbatlas_encryption_at_rest.test.project_id + name = "MyCluster" + cluster_type = "REPLICASET" + backup_enabled = true + encryption_at_rest_provider = "AWS" - google_cloud_kms_config { - enabled = true - service_account_key = "{\"type\": \"service_account\",\"project_id\": \"my-project-common-0\",\"private_key_id\": \"e120598ea4f88249469fcdd75a9a785c1bb3\",\"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEuwIBA(truncated)SfecnS0mT94D9\\n-----END PRIVATE KEY-----\\n\",\"client_email\": \"my-email-kms-0@my-project-common-0.iam.gserviceaccount.com\",\"client_id\": \"10180967717292066\",\"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\"token_uri\": \"https://accounts.google.com/o/oauth2/token\",\"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/my-email-kms-0%40my-project-common-0.iam.gserviceaccount.com\"}" - key_version_resource_id = "projects/my-project-common-0/locations/us-east4/keyRings/my-key-ring-0/cryptoKeys/my-key-0/cryptoKeyVersions/1" + replication_specs { + region_configs { + priority = 7 + provider_name = "AWS" + region_name = "US_EAST_1" + electable_specs { + instance_size = "M10" + node_count = 3 + } + } } } + +data "mongodbatlas_encryption_at_rest" "test" { + project_id = mongodbatlas_encryption_at_rest.test.project_id +} + +output "is_aws_kms_encryption_at_rest_valid" { + value = data.mongodbatlas_encryption_at_rest.test.aws_kms_config.valid +} ``` -**NOTE** if using the two resources path for cloud provider access, `cloud_provider_access_setup` and `cloud_provider_access_authorization`, you may need to define a `depends_on` statement for these two resources, because terraform is not able to infer the dependency. +**NOTE** If using the two resources path for cloud provider access, `cloud_provider_access_setup` and `cloud_provider_access_authorization`, you may need to define a `depends_on` statement for these two resources, because terraform is not able to infer the dependency. ```terraform resource "mongodbatlas_encryption_at_rest" "default" { @@ -65,78 +96,123 @@ resource "mongodbatlas_encryption_at_rest" "default" { } ``` -## Example: Configuring encryption at rest using customer key management in Azure and then creating a cluster - -The configuration of encryption at rest with customer key management, `mongodbatlas_encryption_at_rest`, needs to be completed before a cluster is created in the project. Force this wait by using an implicit dependency via `project_id` as shown in the example below. - +### Configuring encryption at rest using customer key management in Azure ```terraform -resource "mongodbatlas_encryption_at_rest" "example" { - project_id = "" +resource "mongodbatlas_encryption_at_rest" "test" { + project_id = var.atlas_project_id azure_key_vault_config { - enabled = true - client_id = "g54f9e2-89e3-40fd-8188-EXAMPLEID" - azure_environment = "AZURE" - subscription_id = "0ec944e3-g725-44f9-a147-EXAMPLEID" - resource_group_name = "ExampleRGName" - key_vault_name = "EXAMPLEKeyVault" - key_identifier = "https://EXAMPLEKeyVault.vault.azure.net/keys/EXAMPLEKey/d891821e3d364e9eb88fbd3d11807b86" - secret = "EXAMPLESECRET" - tenant_id = "e8e4b6ba-ff32-4c88-a9af-EXAMPLEID" + enabled = true + azure_environment = "AZURE" + + tenant_id = var.azure_tenant_id + subscription_id = var.azure_subscription_id + client_id = var.azure_client_id + secret = var.azure_client_secret + + resource_group_name = var.azure_resource_group_name + key_vault_name = var.azure_key_vault_name + key_identifier = var.azure_key_identifier } } -resource "mongodbatlas_advanced_cluster" "example_cluster" { - project_id = mongodbatlas_encryption_at_rest.example.project_id - name = "CLUSTER NAME" - cluster_type = "REPLICASET" - backup_enabled = true - encryption_at_rest_provider = "AZURE" +data "mongodbatlas_encryption_at_rest" "test" { + project_id = mongodbatlas_encryption_at_rest.test.project_id +} - replication_specs { - region_configs { - priority = 7 - provider_name = "AZURE" - region_name = "REGION" - electable_specs { - instance_size = "M10" - node_count = 3 - } - } - } +output "is_azure_encryption_at_rest_valid" { + value = data.mongodbatlas_encryption_at_rest.test.azure_key_vault_config.valid } +``` + +#### Manage Customer Keys with Azure Key Vault Over Private Endpoints +It is possible to configure Atlas Encryption at Rest to communicate with Azure Key Vault using Azure Private Link, ensuring that all traffic between Atlas and Key Vault takes place over Azure’s private network interfaces. This requires enabling `azure_key_vault_config.require_private_networking` attribute, together with the configuration of `mongodbatlas_encryption_at_rest_private_endpoint` resource. + +Please review [`mongodbatlas_encryption_at_rest_private_endpoint` resource documentation](encryption_at_rest_private_endpoint) and [complete example](https://github.com/mongodb/terraform-provider-mongodbatlas/tree/master/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure) for details on this functionality. + + +### Configuring encryption at rest using customer key management in GCP +```terraform +resource "mongodbatlas_encryption_at_rest" "test" { + project_id = var.atlas_project_id + google_cloud_kms_config { + enabled = true + service_account_key = "{\"type\": \"service_account\",\"project_id\": \"my-project-common-0\",\"private_key_id\": \"e120598ea4f88249469fcdd75a9a785c1bb3\",\"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEuwIBA(truncated)SfecnS0mT94D9\\n-----END PRIVATE KEY-----\\n\",\"client_email\": \"my-email-kms-0@my-project-common-0.iam.gserviceaccount.com\",\"client_id\": \"10180967717292066\",\"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\"token_uri\": \"https://accounts.google.com/o/oauth2/token\",\"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/my-email-kms-0%40my-project-common-0.iam.gserviceaccount.com\"}" + key_version_resource_id = "projects/my-project-common-0/locations/us-east4/keyRings/my-key-ring-0/cryptoKeys/my-key-0/cryptoKeyVersions/1" + } +} ``` -## Argument Reference + +## Schema + +### Required + +- `project_id` (String) Unique 24-hexadecimal digit string that identifies your project. + +### Optional + +- `aws_kms_config` (Block List) Amazon Web Services (AWS) KMS configuration details and encryption at rest configuration set for the specified project. (see [below for nested schema](#nestedblock--aws_kms_config)) +- `azure_key_vault_config` (Block List) Details that define the configuration of Encryption at Rest using Azure Key Vault (AKV). (see [below for nested schema](#nestedblock--azure_key_vault_config)) +- `google_cloud_kms_config` (Block List) Details that define the configuration of Encryption at Rest using Google Cloud Key Management Service (KMS). (see [below for nested schema](#nestedblock--google_cloud_kms_config)) + +### Read-Only + +- `id` (String) The ID of this resource. + + +### Nested Schema for `aws_kms_config` + +Optional: + +- `access_key_id` (String, Sensitive) Unique alphanumeric string that identifies an Identity and Access Management (IAM) access key with permissions required to access your Amazon Web Services (AWS) Customer Master Key (CMK). +- `customer_master_key_id` (String, Sensitive) Unique alphanumeric string that identifies the Amazon Web Services (AWS) Customer Master Key (CMK) you used to encrypt and decrypt the MongoDB master keys. +- `enabled` (Boolean) Flag that indicates whether someone enabled encryption at rest for the specified project through Amazon Web Services (AWS) Key Management Service (KMS). To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`. +- `region` (String) Physical location where MongoDB Atlas deploys your AWS-hosted MongoDB cluster nodes. The region you choose can affect network latency for clients accessing your databases. When MongoDB Cloud deploys a dedicated cluster, it checks if a VPC or VPC connection exists for that provider and region. If not, MongoDB Atlas creates them as part of the deployment. MongoDB Atlas assigns the VPC a CIDR block. To limit a new VPC peering connection to one CIDR block and region, create the connection first. Deploy the cluster after the connection starts. +- `role_id` (String) Unique 24-hexadecimal digit string that identifies an Amazon Web Services (AWS) Identity and Access Management (IAM) role. This IAM role has the permissions required to manage your AWS customer master key. +- `secret_access_key` (String, Sensitive) Human-readable label of the Identity and Access Management (IAM) secret access key with permissions required to access your Amazon Web Services (AWS) customer master key. + +Read-Only: + +- `valid` (Boolean) Flag that indicates whether the Amazon Web Services (AWS) Key Management Service (KMS) encryption key can encrypt and decrypt data. + + + +### Nested Schema for `azure_key_vault_config` + +Optional: + +- `azure_environment` (String) Azure environment in which your account credentials reside. +- `client_id` (String, Sensitive) Unique 36-hexadecimal character string that identifies an Azure application associated with your Azure Active Directory tenant. +- `enabled` (Boolean) Flag that indicates whether someone enabled encryption at rest for the specified project. To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`. +- `key_identifier` (String, Sensitive) Web address with a unique key that identifies for your Azure Key Vault. +- `key_vault_name` (String) Unique string that identifies the Azure Key Vault that contains your key. +- `require_private_networking` (Boolean) Enable connection to your Azure Key Vault over private networking. +- `resource_group_name` (String) Name of the Azure resource group that contains your Azure Key Vault. +- `secret` (String, Sensitive) Private data that you need secured and that belongs to the specified Azure Key Vault (AKV) tenant (**azureKeyVault.tenantID**). This data can include any type of sensitive data such as passwords, database connection strings, API keys, and the like. AKV stores this information as encrypted binary data. +- `subscription_id` (String, Sensitive) Unique 36-hexadecimal character string that identifies your Azure subscription. +- `tenant_id` (String, Sensitive) Unique 36-hexadecimal character string that identifies the Azure Active Directory tenant within your Azure subscription. + +Read-Only: + +- `valid` (Boolean) Flag that indicates whether the Azure encryption key can encrypt and decrypt data. + -* `project_id` - (Required) The unique identifier for the project. + +### Nested Schema for `google_cloud_kms_config` -### aws_kms_config -Refer to the example in the [official github repository](https://github.com/mongodb/terraform-provider-mongodbatlas/tree/master/examples) to implement Encryption at Rest -* `enabled` - Specifies whether Encryption at Rest is enabled for an Atlas project, To disable Encryption at Rest, pass only this parameter with a value of false, When you disable Encryption at Rest, Atlas also removes the configuration details. -* `customer_master_key_id` - The AWS customer master key used to encrypt and decrypt the MongoDB master keys. -* `region` - The AWS region in which the AWS customer master key exists: CA_CENTRAL_1, US_EAST_1, US_EAST_2, US_WEST_1, US_WEST_2, SA_EAST_1 -* `role_id` - ID of an AWS IAM role authorized to manage an AWS customer master key. To find the ID for an existing IAM role check the `role_id` attribute of the `mongodbatlas_cloud_provider_access` resource. +Optional: -### azure_key_vault_config -* `enabled` - Specifies whether Encryption at Rest is enabled for an Atlas project. To disable Encryption at Rest, pass only this parameter with a value of false. When you disable Encryption at Rest, Atlas also removes the configuration details. -* `client_id` - The client ID, also known as the application ID, for an Azure application associated with the Azure AD tenant. -* `azure_environment` - The Azure environment where the Azure account credentials reside. Valid values are the following: AZURE, AZURE_CHINA, AZURE_GERMANY -* `subscription_id` - The unique identifier associated with an Azure subscription. -* `resource_group_name` - The name of the Azure Resource group that contains an Azure Key Vault. -* `key_vault_name` - The name of an Azure Key Vault containing your key. -* `key_identifier` - The unique identifier of a key in an Azure Key Vault. -* `secret` - The secret associated with the Azure Key Vault specified by azureKeyVault.tenantID. -* `tenant_id` - The unique identifier for an Azure AD tenant within an Azure subscription. +- `enabled` (Boolean) Flag that indicates whether someone enabled encryption at rest for the specified project. To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`. +- `key_version_resource_id` (String, Sensitive) Resource path that displays the key version resource ID for your Google Cloud KMS. +- `service_account_key` (String, Sensitive) JavaScript Object Notation (JSON) object that contains the Google Cloud Key Management Service (KMS). Format the JSON as a string and not as an object. -### google_cloud_kms_config -* `enabled` - Specifies whether Encryption at Rest is enabled for an Atlas project. To disable Encryption at Rest, pass only this parameter with a value of false. When you disable Encryption at Rest, Atlas also removes the configuration details. -* `service_account_key` - String-formatted JSON object containing GCP KMS credentials from your GCP account. -* `key_version_resource_id` - The Key Version Resource ID from your GCP account. +Read-Only: -## Import +- `valid` (Boolean) Flag that indicates whether the Google Cloud Key Management Service (KMS) encryption key can encrypt and decrypt data. +# Import Encryption at Rest Settings can be imported using project ID, in the format `project_id`, e.g. ``` diff --git a/docs/resources/encryption_at_rest_private_endpoint.md b/docs/resources/encryption_at_rest_private_endpoint.md new file mode 100644 index 0000000000..3e3e068d12 --- /dev/null +++ b/docs/resources/encryption_at_rest_private_endpoint.md @@ -0,0 +1,94 @@ +# Resource: mongodbatlas_encryption_at_rest_private_endpoint + +`mongodbatlas_encryption_at_rest_private_endpoint` provides a resource for managing a private endpoint used for encryption at rest with customer-managed keys. This ensures all traffic between Atlas and customer key management systems take place over private network interfaces. + +~> **IMPORTANT** The Encryption at Rest using Azure Key Vault over Private Endpoints feature is available by request. To request this functionality for your Atlas deployments, contact your Account Manager. +Additionally, you'll need to set the environment variable `MONGODB_ATLAS_ENABLE_PREVIEW=true` to use this resource. To learn more about existing limitations, see the [Manage Customer Keys with Azure Key Vault Over Private Endpoints](https://www.mongodb.com/docs/atlas/security/azure-kms-over-private-endpoint/#manage-customer-keys-with-azure-key-vault-over-private-endpoints). + +-> **NOTE:** As a prerequisite to configuring a private endpoint for Azure Key Vault, the corresponding [`mongodbatlas_encryption_at_rest`](encryption_at_rest) resource has to be adjust by configuring [`azure_key_vault_config.require_private_networking`](encryption_at_rest#require_private_networking) to true. This attribute should be updated in place, ensuring the customer-managed keys encryption is never disabled. + +-> **NOTE:** This resource does not support update operations. To modify values of a private endpoint the existing resource must be deleted and a new one can be created with the modified values. + +## Example Usages + +-> **NOTE:** Only Azure Key Vault with Azure Private Link is supported at this time. + +### Configuring Atlas Encryption at Rest using Azure Key Vault with Azure Private Link + +Make sure to reference the [complete example section](https://github.com/mongodb/terraform-provider-mongodbatlas/tree/master/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure) for detailed steps and considerations. + +```terraform +resource "mongodbatlas_encryption_at_rest" "ear" { + project_id = var.atlas_project_id + + azure_key_vault_config { + require_private_networking = true + + enabled = true + azure_environment = "AZURE" + + tenant_id = var.azure_tenant_id + subscription_id = var.azure_subscription_id + client_id = var.azure_client_id + secret = var.azure_client_secret + + resource_group_name = var.azure_resource_group_name + key_vault_name = var.azure_key_vault_name + key_identifier = var.azure_key_identifier + } +} + +# Creates private endpoint +resource "mongodbatlas_encryption_at_rest_private_endpoint" "endpoint" { + project_id = mongodbatlas_encryption_at_rest.ear.project_id + cloud_provider = "AZURE" + region_name = var.azure_region_name +} + +locals { + key_vault_resource_id = "/subscriptions/${var.azure_subscription_id}/resourceGroups/${var.azure_resource_group_name}/providers/Microsoft.KeyVault/vaults/${var.azure_key_vault_name}" +} + +# Approves private endpoint connection from Azure Key Vault +resource "azapi_update_resource" "approval" { + type = "Microsoft.KeyVault/Vaults/PrivateEndpointConnections@2023-07-01" + name = mongodbatlas_encryption_at_rest_private_endpoint.endpoint.private_endpoint_connection_name + parent_id = local.key_vault_resource_id + + body = jsonencode({ + properties = { + privateLinkServiceConnectionState = { + description = "Approved via Terraform" + status = "Approved" + } + } + }) +} +``` + + +## Schema + +### Required + +- `cloud_provider` (String) Label that identifies the cloud provider for the Encryption At Rest private endpoint. +- `project_id` (String) Unique 24-hexadecimal digit string that identifies your project. +- `region_name` (String) Cloud provider region in which the Encryption At Rest private endpoint is located. + +### Read-Only + +- `error_message` (String) Error message for failures associated with the Encryption At Rest private endpoint. +- `id` (String) Unique 24-hexadecimal digit string that identifies the Private Endpoint Service. +- `private_endpoint_connection_name` (String) Connection name of the Azure Private Endpoint. +- `status` (String) State of the Encryption At Rest private endpoint. + +# Import +Encryption At Rest Private Endpoint resource can be imported using the project ID, cloud provider, and private endpoint ID. The format must be `{project_id}-{cloud_provider}-{private_endpoint_id}` e.g. + +``` +$ terraform import mongodbatlas_encryption_at_rest_private_endpoint.test 650972848269185c55f40ca1-AZURE-650972848269185c55f40ca2 +``` + +For more information see: +- [MongoDB Atlas API - Private Endpoint for Encryption at Rest Using Customer Key Management](https://www.mongodb.com/docs/atlas/reference/api-resources-spec/v2/#tag/Encryption-at-Rest-using-Customer-Key-Management/operation/getEncryptionAtRestPrivateEndpoint) Documentation. +- [Manage Customer Keys with Azure Key Vault Over Private Endpoints](https://www.mongodb.com/docs/atlas/security/azure-kms-over-private-endpoint/). diff --git a/examples/mongodbatlas_encryption_at_rest/aws/atlas-cluster/main.tf b/examples/mongodbatlas_encryption_at_rest/aws/atlas-cluster/main.tf index fb4b6d9826..e07e46e1e4 100644 --- a/examples/mongodbatlas_encryption_at_rest/aws/atlas-cluster/main.tf +++ b/examples/mongodbatlas_encryption_at_rest/aws/atlas-cluster/main.tf @@ -24,7 +24,7 @@ resource "mongodbatlas_encryption_at_rest" "test" { } resource "mongodbatlas_advanced_cluster" "cluster" { - project_id = var.atlas_project_id + project_id = mongodbatlas_encryption_at_rest.test.project_id name = "MyCluster" cluster_type = "REPLICASET" backup_enabled = true @@ -42,3 +42,11 @@ resource "mongodbatlas_advanced_cluster" "cluster" { } } } + +data "mongodbatlas_encryption_at_rest" "test" { + project_id = mongodbatlas_encryption_at_rest.test.project_id +} + +output "is_aws_kms_encryption_at_rest_valid" { + value = data.mongodbatlas_encryption_at_rest.test.aws_kms_config.valid +} diff --git a/examples/mongodbatlas_encryption_at_rest/azure/README.md b/examples/mongodbatlas_encryption_at_rest/azure/README.md new file mode 100644 index 0000000000..512a16d281 --- /dev/null +++ b/examples/mongodbatlas_encryption_at_rest/azure/README.md @@ -0,0 +1,57 @@ +# MongoDB Atlas Provider -- Encryption At Rest using Customer Key Management with Azure +This example shows how to configure encryption at rest with customer managed keys with Azure Key Vault. + +Note: It is possible to configure Atlas Encryption at Rest to communicate with Azure Key Vault using Azure Private Link, ensuring that all traffic between Atlas and Key Vault takes place over Azure’s private network interfaces. Please review `mongodbatlas_encryption_at_rest_private_endpoint` resource for details. + +## Dependencies + +* Terraform MongoDB Atlas Provider +* A MongoDB Atlas account +* A Microsoft Azure account + +## Usage + +**1\. Provide the appropriate values for the input variables.** + +- `atlas_public_key`: The public API key for MongoDB Atlas +- `atlas_private_key`: The private API key for MongoDB Atlas +- `atlas_project_id`: Atlas Project ID +- `azure_subscription_id`: Azure ID that identifies your Azure subscription +- `azure_client_id`: Azure ID identifies an Azure application associated with your Azure Active Directory tenant +- `azure_client_secret`: Secret associated to the Azure application +- `azure_tenant_id`: Azure ID that identifies the Azure Active Directory tenant within your Azure subscription +- `azure_resource_group_name`: Name of the Azure resource group that contains your Azure Key Vault +- `azure_key_vault_name`: Unique string that identifies the Azure Key Vault that contains your key +- `azure_key_identifier`: Web address with a unique key that identifies for your Azure Key Vault + +**NOTE**: The Azure application (associated to `azure_client_id`) must have the following permissions associated to the Azure Key Vault (`azure_key_vault_name`): +- GET (Key Management Operation), ENCRYPT (Cryptographic Operation) and DECRYPT (Cryptographic Operation) policy permissions. +- A `Key Vault Reader` role. + +**2\. Review the Terraform plan.** + +Execute the following command and ensure you are happy with the plan. + +``` bash +$ terraform plan +``` +This project currently supports the following deployments: + +- Configure encryption at rest in an existing project using a custom Azure Key. + +**3\. Execute the Terraform apply.** + +Now execute the plan to provision the resources. + +``` bash +$ terraform apply +``` + +**4\. Destroy the resources.** + +When you have finished your testing, ensure you destroy the resources to avoid unnecessary Atlas charges. + +``` bash +$ terraform destroy +``` + diff --git a/examples/mongodbatlas_encryption_at_rest/azure/main.tf b/examples/mongodbatlas_encryption_at_rest/azure/main.tf new file mode 100644 index 0000000000..2323df7241 --- /dev/null +++ b/examples/mongodbatlas_encryption_at_rest/azure/main.tf @@ -0,0 +1,25 @@ +resource "mongodbatlas_encryption_at_rest" "test" { + project_id = var.atlas_project_id + + azure_key_vault_config { + enabled = true + azure_environment = "AZURE" + + tenant_id = var.azure_tenant_id + subscription_id = var.azure_subscription_id + client_id = var.azure_client_id + secret = var.azure_client_secret + + resource_group_name = var.azure_resource_group_name + key_vault_name = var.azure_key_vault_name + key_identifier = var.azure_key_identifier + } +} + +data "mongodbatlas_encryption_at_rest" "test" { + project_id = mongodbatlas_encryption_at_rest.test.project_id +} + +output "is_azure_encryption_at_rest_valid" { + value = data.mongodbatlas_encryption_at_rest.test.azure_key_vault_config.valid +} diff --git a/examples/mongodbatlas_encryption_at_rest/azure/providers.tf b/examples/mongodbatlas_encryption_at_rest/azure/providers.tf new file mode 100644 index 0000000000..6fc0d099e0 --- /dev/null +++ b/examples/mongodbatlas_encryption_at_rest/azure/providers.tf @@ -0,0 +1,5 @@ +provider "mongodbatlas" { + public_key = var.atlas_public_key + private_key = var.atlas_private_key +} + diff --git a/examples/mongodbatlas_encryption_at_rest/azure/variables.tf b/examples/mongodbatlas_encryption_at_rest/azure/variables.tf new file mode 100644 index 0000000000..d4b94a39b5 --- /dev/null +++ b/examples/mongodbatlas_encryption_at_rest/azure/variables.tf @@ -0,0 +1,50 @@ +variable "atlas_public_key" { + description = "The public API key for MongoDB Atlas" + type = string +} +variable "atlas_private_key" { + description = "The private API key for MongoDB Atlas" + type = string + sensitive = true +} +variable "atlas_project_id" { + description = "Atlas Project ID" + type = string +} +variable "azure_subscription_id" { + type = string + description = "Azure ID that identifies your Azure subscription" +} + +variable "azure_client_id" { + type = string + description = "Azure ID identifies an Azure application associated with your Azure Active Directory tenant" +} + +variable "azure_client_secret" { + type = string + sensitive = true + description = "Secret associated to the Azure application" +} + +variable "azure_tenant_id" { + type = string + description = "Azure ID that identifies the Azure Active Directory tenant within your Azure subscription" +} + +variable "azure_resource_group_name" { + type = string + description = "Name of the Azure resource group that contains your Azure Key Vault" +} + +variable "azure_key_vault_name" { + type = string + description = "Unique string that identifies the Azure Key Vault that contains your key" +} + +variable "azure_key_identifier" { + type = string + description = "Web address with a unique key that identifies for your Azure Key Vault" +} + + diff --git a/examples/mongodbatlas_encryption_at_rest/azure/versions.tf b/examples/mongodbatlas_encryption_at_rest/azure/versions.tf new file mode 100644 index 0000000000..9b4be6c14c --- /dev/null +++ b/examples/mongodbatlas_encryption_at_rest/azure/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + mongodbatlas = { + source = "mongodb/mongodbatlas" + version = "~> 1.18" + } + } + required_version = ">= 1.0" +} diff --git a/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/README.md b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/README.md new file mode 100644 index 0000000000..727ec3b95b --- /dev/null +++ b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/README.md @@ -0,0 +1,73 @@ +# MongoDB Atlas Provider - Encryption At Rest using Customer Key Management via Private Network Interfaces (Azure) +This example shows how to configure encryption at rest using Azure with customer managed keys ensuring all communication with Azure Key Vault happens exclusively over Azure Private Link. + +## Dependencies + +* Terraform MongoDB Atlas Provider v1.19.0 minimum +* A MongoDB Atlas account +* Terraform Azure `azapi` provider +* A Microsoft Azure account + +## Usage + +**1\. Ensure that Encryption At Rest Azure Key Vault Private Endpoint feature is available for your project.** + +The Encryption at Rest using Azure Key Vault over Private Endpoints feature is available by request. To request this functionality for your Atlas deployments, contact your Account Manager. + +**2\. Enable `MONGODB_ATLAS_ENABLE_PREVIEW` flag.** + +This step is needed to make use of the `mongodbatlas_encryption_at_rest_private_endpoint` resource. + +``` +export MONGODB_ATLAS_ENABLE_PREVIEW="true" +``` + +**3\. Provide the appropriate values for the input variables.** + +- `atlas_public_key`: The public API key for MongoDB Atlas +- `atlas_private_key`: The private API key for MongoDB Atlas +- `atlas_project_id`: Atlas Project ID +- `azure_subscription_id`: Azure ID that identifies your Azure subscription +- `azure_client_id`: Azure ID identifies an Azure application associated with your Azure Active Directory tenant +- `azure_client_secret`: Secret associated to the Azure application +- `azure_tenant_id`: Azure ID that identifies the Azure Active Directory tenant within your Azure subscription +- `azure_resource_group_name`: Name of the Azure resource group that contains your Azure Key Vault +- `azure_key_vault_name`: Unique string that identifies the Azure Key Vault that contains your key +- `azure_key_identifier`: Web address with a unique key that identifies for your Azure Key Vault +- `azure_region_name`: Region in which the Encryption At Rest private endpoint is located + + +**NOTE**: The Azure application (associated to `azure_client_id`) must have the following permissions associated to the Azure Key Vault (`azure_key_vault_name`): +- GET (Key Management Operation), ENCRYPT (Cryptographic Operation) and DECRYPT (Cryptographic Operation) policy permissions. +- A `Key Vault Reader` role. + +**4\. Review the Terraform plan.** + +Execute the following command and ensure you are happy with the plan. + +``` bash +$ terraform plan +``` +This project will execute the following changes to acheive a successful Azure Private Link for customer managed keys: + +- Configure encryption at rest in an existing project using a custom Azure Key. For successful private networking configuration, the `requires_private_networking` attribute in `mongodbatlas_encryption_at_rest` is set to true. +- Create a private endpoint for the existing project under a certain Azure region using `mongodbatlas_encryption_at_rest_private_endpoint`. +- Approve the connection from the Azure Key Vault. This is being done through terraform with the `azapi_update_resource` resource. Alternatively, the private connection can be approved through the Azure UI or CLI. + - CLI example command: `az keyvault private-endpoint-connection approve --approval-description {"OPTIONAL DESCRIPTION"} --resource-group {RG} --vault-name {KEY VAULT NAME} –name {PRIVATE LINK CONNECTION NAME}` + +**3\. Execute the Terraform apply.** + +Now execute the plan to provision the resources. + +``` bash +$ terraform apply +``` + +**4\. Destroy the resources.** + +When you have finished your testing, ensure you destroy the resources to avoid unnecessary Atlas charges. + +``` bash +$ terraform destroy +``` + diff --git a/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/main.tf b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/main.tf new file mode 100644 index 0000000000..636a423013 --- /dev/null +++ b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/main.tf @@ -0,0 +1,46 @@ +resource "mongodbatlas_encryption_at_rest" "ear" { + project_id = var.atlas_project_id + + azure_key_vault_config { + require_private_networking = true + + enabled = true + azure_environment = "AZURE" + + tenant_id = var.azure_tenant_id + subscription_id = var.azure_subscription_id + client_id = var.azure_client_id + secret = var.azure_client_secret + + resource_group_name = var.azure_resource_group_name + key_vault_name = var.azure_key_vault_name + key_identifier = var.azure_key_identifier + } +} + +# Creates private endpoint +resource "mongodbatlas_encryption_at_rest_private_endpoint" "endpoint" { + project_id = mongodbatlas_encryption_at_rest.ear.project_id + cloud_provider = "AZURE" + region_name = var.azure_region_name +} + +locals { + key_vault_resource_id = "/subscriptions/${var.azure_subscription_id}/resourceGroups/${var.azure_resource_group_name}/providers/Microsoft.KeyVault/vaults/${var.azure_key_vault_name}" +} + +# Approves private endpoint connection from Azure Key Vault +resource "azapi_update_resource" "approval" { + type = "Microsoft.KeyVault/Vaults/PrivateEndpointConnections@2023-07-01" + name = mongodbatlas_encryption_at_rest_private_endpoint.endpoint.private_endpoint_connection_name + parent_id = local.key_vault_resource_id + + body = jsonencode({ + properties = { + privateLinkServiceConnectionState = { + description = "Approved via Terraform" + status = "Approved" + } + } + }) +} diff --git a/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/plural-data-source.tf b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/plural-data-source.tf new file mode 100644 index 0000000000..f2cb36d2dd --- /dev/null +++ b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/plural-data-source.tf @@ -0,0 +1,8 @@ +data "mongodbatlas_encryption_at_rest_private_endpoints" "plural" { + project_id = var.atlas_project_id + cloud_provider = "AZURE" +} + +output "number_of_endpoints" { + value = length(data.mongodbatlas_encryption_at_rest_private_endpoints.plural.results) +} diff --git a/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/providers.tf b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/providers.tf new file mode 100644 index 0000000000..432a001a39 --- /dev/null +++ b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/providers.tf @@ -0,0 +1,11 @@ +provider "mongodbatlas" { + public_key = var.atlas_public_key + private_key = var.atlas_private_key +} + +provider "azapi" { + tenant_id = var.azure_tenant_id + subscription_id = var.azure_subscription_id + client_id = var.azure_client_id + client_secret = var.azure_client_secret +} diff --git a/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/singular-data-source.tf b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/singular-data-source.tf new file mode 100644 index 0000000000..f3699a2353 --- /dev/null +++ b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/singular-data-source.tf @@ -0,0 +1,9 @@ +data "mongodbatlas_encryption_at_rest_private_endpoint" "single" { + project_id = var.atlas_project_id + cloud_provider = "AZURE" + id = mongodbatlas_encryption_at_rest_private_endpoint.endpoint.id +} + +output "endpoint_connection_name" { + value = data.mongodbatlas_encryption_at_rest_private_endpoint.single.private_endpoint_connection_name +} diff --git a/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/variables.tf b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/variables.tf new file mode 100644 index 0000000000..50a8762fc3 --- /dev/null +++ b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/variables.tf @@ -0,0 +1,54 @@ +variable "atlas_public_key" { + description = "The public API key for MongoDB Atlas" + type = string +} +variable "atlas_private_key" { + description = "The private API key for MongoDB Atlas" + type = string + sensitive = true +} +variable "atlas_project_id" { + description = "Atlas Project ID" + type = string +} +variable "azure_subscription_id" { + type = string + description = "Azure ID that identifies your Azure subscription" +} + +variable "azure_client_id" { + type = string + description = "Azure ID identifies an Azure application associated with your Azure Active Directory tenant" +} + +variable "azure_client_secret" { + type = string + sensitive = true + description = "Secret associated to the Azure application" +} + +variable "azure_tenant_id" { + type = string + description = "Azure ID that identifies the Azure Active Directory tenant within your Azure subscription" +} + +variable "azure_resource_group_name" { + type = string + description = "Name of the Azure resource group that contains your Azure Key Vault" +} + +variable "azure_key_vault_name" { + type = string + description = "Unique string that identifies the Azure Key Vault that contains your key" +} + +variable "azure_key_identifier" { + type = string + description = "Web address with a unique key that identifies for your Azure Key Vault" +} + +variable "azure_region_name" { + type = string + description = "Region in which the Encryption At Rest private endpoint is located." +} + diff --git a/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/versions.tf b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/versions.tf new file mode 100644 index 0000000000..c955a31212 --- /dev/null +++ b/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/versions.tf @@ -0,0 +1,14 @@ +terraform { + required_providers { + mongodbatlas = { + source = "mongodb/mongodbatlas" + version = "~> 1.18" + } + + azapi = { + source = "Azure/azapi" + version = "~> 1.15" + } + } + required_version = ">= 1.0" +} diff --git a/internal/common/conversion/type_conversion.go b/internal/common/conversion/type_conversion.go index 21a555db76..a05d8ecccd 100644 --- a/internal/common/conversion/type_conversion.go +++ b/internal/common/conversion/type_conversion.go @@ -62,3 +62,8 @@ func IsStringPresent(strPtr *string) bool { func MongoDBRegionToAWSRegion(region string) string { return strings.ReplaceAll(strings.ToLower(region), "_", "-") } + +// AWSRegionToMongoDBRegion converts region in us-east-1-like format to US_EAST_1-like +func AWSRegionToMongoDBRegion(region string) string { + return strings.ReplaceAll(strings.ToUpper(region), "-", "_") +} diff --git a/internal/common/conversion/type_conversion_test.go b/internal/common/conversion/type_conversion_test.go index badf82f279..028d7d163a 100644 --- a/internal/common/conversion/type_conversion_test.go +++ b/internal/common/conversion/type_conversion_test.go @@ -4,8 +4,9 @@ import ( "testing" "time" - "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" "github.com/stretchr/testify/assert" + + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" ) func TestTimeWithoutNanos(t *testing.T) { @@ -78,3 +79,19 @@ func TestMongoDBRegionToAWSRegion(t *testing.T) { } } } + +func TestAWSRegionToMongoDBRegion(t *testing.T) { + tests := []struct { + region string + expected string + }{ + {"us-east-1", "US_EAST_1"}, + {"US-EAST-1", "US_EAST_1"}, + } + + for _, test := range tests { + if resp := conversion.AWSRegionToMongoDBRegion(test.region); resp != test.expected { + t.Errorf("AWSRegionToMongoDBRegion(%v) = %v; want %v", test.region, resp, test.expected) + } + } +} diff --git a/internal/common/dsschema/page_request.go b/internal/common/dsschema/page_request.go new file mode 100644 index 0000000000..4195f46104 --- /dev/null +++ b/internal/common/dsschema/page_request.go @@ -0,0 +1,31 @@ +package dsschema + +import ( + "context" + "errors" + "net/http" +) + +type PaginateResponse[T any] interface { + GetResults() []T + GetTotalCount() int +} + +func AllPages[T any](ctx context.Context, listOnPage func(ctx context.Context, pageNum int) (PaginateResponse[T], *http.Response, error)) ([]T, error) { + var results []T + for currentPage := 1; ; currentPage++ { + resp, _, err := listOnPage(ctx, currentPage) + if err != nil { + return nil, err + } + if resp == nil { + return nil, errors.New("no response") + } + currentResults := resp.GetResults() + results = append(results, currentResults...) + if len(currentResults) == 0 || len(results) >= resp.GetTotalCount() { + break + } + } + return results, nil +} diff --git a/internal/common/retrystrategy/retry_state.go b/internal/common/retrystrategy/retry_state.go index f926cc3225..00d5f6670e 100644 --- a/internal/common/retrystrategy/retry_state.go +++ b/internal/common/retrystrategy/retry_state.go @@ -1,11 +1,18 @@ package retrystrategy const ( - RetryStrategyPendingState = "PENDING" - RetryStrategyCompletedState = "COMPLETED" - RetryStrategyErrorState = "ERROR" - RetryStrategyPausedState = "PAUSED" - RetryStrategyUpdatingState = "UPDATING" - RetryStrategyIdleState = "IDLE" - RetryStrategyDeletedState = "DELETED" + RetryStrategyPendingState = "PENDING" + RetryStrategyCompletedState = "COMPLETED" + RetryStrategyErrorState = "ERROR" + RetryStrategyPausedState = "PAUSED" + RetryStrategyUpdatingState = "UPDATING" + RetryStrategyDeletingState = "DELETING" + RetryStrategyInitiatingState = "INITIATING" + RetryStrategyIdleState = "IDLE" + RetryStrategyFailedState = "FAILED" + RetryStrategyActiveState = "ACTIVE" + RetryStrategyDeletedState = "DELETED" + + RetryStrategyPendingAcceptanceState = "PENDING_ACCEPTANCE" + RetryStrategyPendingRecreationState = "PENDING_RECREATION" ) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 17b2bbdef5..6c2341da86 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -31,6 +31,7 @@ import ( "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/controlplaneipaddresses" "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/databaseuser" "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/encryptionatrest" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/encryptionatrestprivateendpoint" "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/project" "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/projectipaccesslist" "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/projectipaddresses" @@ -435,8 +436,12 @@ func (p *MongodbtlasProvider) DataSources(context.Context) []func() datasource.D streamconnection.PluralDataSource, controlplaneipaddresses.DataSource, projectipaddresses.DataSource, + encryptionatrest.DataSource, + } + previewDataSources := []func() datasource.DataSource{ // Data sources not yet in GA + encryptionatrestprivateendpoint.DataSource, + encryptionatrestprivateendpoint.PluralDataSource, } - previewDataSources := []func() datasource.DataSource{} // Data sources not yet in GA if providerEnablePreview { dataSources = append(dataSources, previewDataSources...) } @@ -455,7 +460,9 @@ func (p *MongodbtlasProvider) Resources(context.Context) []func() resource.Resou streaminstance.Resource, streamconnection.Resource, } - previewResources := []func() resource.Resource{} // Resources not yet in GA + previewResources := []func() resource.Resource{ // Resources not yet in GA + encryptionatrestprivateendpoint.Resource, + } if providerEnablePreview { resources = append(resources, previewResources...) } diff --git a/internal/service/encryptionatrest/data_source.go b/internal/service/encryptionatrest/data_source.go new file mode 100644 index 0000000000..f0acd090cf --- /dev/null +++ b/internal/service/encryptionatrest/data_source.go @@ -0,0 +1,47 @@ +package encryptionatrest + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + + "github.com/mongodb/terraform-provider-mongodbatlas/internal/config" +) + +var _ datasource.DataSource = &encryptionAtRestDS{} +var _ datasource.DataSourceWithConfigure = &encryptionAtRestDS{} + +func DataSource() datasource.DataSource { + return &encryptionAtRestDS{ + DSCommon: config.DSCommon{ + DataSourceName: encryptionAtRestResourceName, + }, + } +} + +type encryptionAtRestDS struct { + config.DSCommon +} + +func (d *encryptionAtRestDS) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = DataSourceSchema(ctx) +} + +func (d *encryptionAtRestDS) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var earConfig TFEncryptionAtRestDSModel + resp.Diagnostics.Append(req.Config.Get(ctx, &earConfig)...) + if resp.Diagnostics.HasError() { + return + } + + connV2 := d.Client.AtlasV2 + projectID := earConfig.ProjectID.ValueString() + + encryptionResp, _, err := connV2.EncryptionAtRestUsingCustomerKeyManagementApi.GetEncryptionAtRest(context.Background(), projectID).Execute() + if err != nil { + resp.Diagnostics.AddError("error fetching resource", err.Error()) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, NewTFEncryptionAtRestDSModel(projectID, encryptionResp))...) +} diff --git a/internal/service/encryptionatrest/data_source_schema.go b/internal/service/encryptionatrest/data_source_schema.go new file mode 100644 index 0000000000..540fc59159 --- /dev/null +++ b/internal/service/encryptionatrest/data_source_schema.go @@ -0,0 +1,184 @@ +package encryptionatrest + +import ( + "context" + + "go.mongodb.org/atlas-sdk/v20240805003/admin" + + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +func DataSourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "aws_kms_config": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "access_key_id": schema.StringAttribute{ + Computed: true, + Sensitive: true, + Description: "Unique alphanumeric string that identifies an Identity and Access Management (IAM) access key with permissions required to access your Amazon Web Services (AWS) Customer Master Key (CMK).", + MarkdownDescription: "Unique alphanumeric string that identifies an Identity and Access Management (IAM) access key with permissions required to access your Amazon Web Services (AWS) Customer Master Key (CMK).", + }, + "customer_master_key_id": schema.StringAttribute{ + Computed: true, + Sensitive: true, + Description: "Unique alphanumeric string that identifies the Amazon Web Services (AWS) Customer Master Key (CMK) you used to encrypt and decrypt the MongoDB master keys.", + MarkdownDescription: "Unique alphanumeric string that identifies the Amazon Web Services (AWS) Customer Master Key (CMK) you used to encrypt and decrypt the MongoDB master keys.", + }, + "enabled": schema.BoolAttribute{ + Computed: true, + Description: "Flag that indicates whether someone enabled encryption at rest for the specified project through Amazon Web Services (AWS) Key Management Service (KMS). To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`.", + MarkdownDescription: "Flag that indicates whether someone enabled encryption at rest for the specified project through Amazon Web Services (AWS) Key Management Service (KMS). To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`.", + }, + "region": schema.StringAttribute{ + Computed: true, + Description: "Physical location where MongoDB Atlas deploys your AWS-hosted MongoDB cluster nodes. The region you choose can affect network latency for clients accessing your databases. When MongoDB Cloud deploys a dedicated cluster, it checks if a VPC or VPC connection exists for that provider and region. If not, MongoDB Atlas creates them as part of the deployment. MongoDB Atlas assigns the VPC a CIDR block. To limit a new VPC peering connection to one CIDR block and region, create the connection first. Deploy the cluster after the connection starts.", //nolint:lll // reason: auto-generated from Open API spec. + MarkdownDescription: "Physical location where MongoDB Atlas deploys your AWS-hosted MongoDB cluster nodes. The region you choose can affect network latency for clients accessing your databases. When MongoDB Atlas deploys a dedicated cluster, it checks if a VPC or VPC connection exists for that provider and region. If not, MongoDB Atlas creates them as part of the deployment. MongoDB Atlas assigns the VPC a CIDR block. To limit a new VPC peering connection to one CIDR block and region, create the connection first. Deploy the cluster after the connection starts.", //nolint:lll // reason: auto-generated from Open API spec. + }, + "role_id": schema.StringAttribute{ + Computed: true, + Description: "Unique 24-hexadecimal digit string that identifies an Amazon Web Services (AWS) Identity and Access Management (IAM) role. This IAM role has the permissions required to manage your AWS customer master key.", + MarkdownDescription: "Unique 24-hexadecimal digit string that identifies an Amazon Web Services (AWS) Identity and Access Management (IAM) role. This IAM role has the permissions required to manage your AWS customer master key.", + }, + "secret_access_key": schema.StringAttribute{ + Computed: true, + Sensitive: true, + Description: "Human-readable label of the Identity and Access Management (IAM) secret access key with permissions required to access your Amazon Web Services (AWS) customer master key.", + MarkdownDescription: "Human-readable label of the Identity and Access Management (IAM) secret access key with permissions required to access your Amazon Web Services (AWS) customer master key.", + }, + "valid": schema.BoolAttribute{ + Computed: true, + Description: "Flag that indicates whether the Amazon Web Services (AWS) Key Management Service (KMS) encryption key can encrypt and decrypt data.", + MarkdownDescription: "Flag that indicates whether the Amazon Web Services (AWS) Key Management Service (KMS) encryption key can encrypt and decrypt data.", + }, + }, + Computed: true, + Description: "Amazon Web Services (AWS) KMS configuration details and encryption at rest configuration set for the specified project.", + MarkdownDescription: "Amazon Web Services (AWS) KMS configuration details and encryption at rest configuration set for the specified project.", + }, + "azure_key_vault_config": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "azure_environment": schema.StringAttribute{ + Computed: true, + Description: "Azure environment in which your account credentials reside.", + MarkdownDescription: "Azure environment in which your account credentials reside.", + }, + "client_id": schema.StringAttribute{ + Computed: true, + Sensitive: true, + Description: "Unique 36-hexadecimal character string that identifies an Azure application associated with your Azure Active Directory tenant.", + MarkdownDescription: "Unique 36-hexadecimal character string that identifies an Azure application associated with your Azure Active Directory tenant.", + }, + "enabled": schema.BoolAttribute{ + Computed: true, + Description: "Flag that indicates whether someone enabled encryption at rest for the specified project. To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`.", + MarkdownDescription: "Flag that indicates whether someone enabled encryption at rest for the specified project. To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`.", + }, + "key_identifier": schema.StringAttribute{ + Computed: true, + Sensitive: true, + Description: "Web address with a unique key that identifies for your Azure Key Vault.", + MarkdownDescription: "Web address with a unique key that identifies for your Azure Key Vault.", + }, + "key_vault_name": schema.StringAttribute{ + Computed: true, + Description: "Unique string that identifies the Azure Key Vault that contains your key.", + MarkdownDescription: "Unique string that identifies the Azure Key Vault that contains your key.", + }, + "require_private_networking": schema.BoolAttribute{ + Computed: true, + Description: "Enable connection to your Azure Key Vault over private networking.", + MarkdownDescription: "Enable connection to your Azure Key Vault over private networking.", + }, + "resource_group_name": schema.StringAttribute{ + Computed: true, + Description: "Name of the Azure resource group that contains your Azure Key Vault.", + MarkdownDescription: "Name of the Azure resource group that contains your Azure Key Vault.", + }, + "secret": schema.StringAttribute{ + Computed: true, + Sensitive: true, + Description: "Private data that you need secured and that belongs to the specified Azure Key Vault (AKV) tenant (**azureKeyVault.tenantID**). This data can include any type of sensitive data such as passwords, database connection strings, API keys, and the like. AKV stores this information as encrypted binary data.", + MarkdownDescription: "Private data that you need secured and that belongs to the specified Azure Key Vault (AKV) tenant (**azureKeyVault.tenantID**). This data can include any type of sensitive data such as passwords, database connection strings, API keys, and the like. AKV stores this information as encrypted binary data.", + }, + "subscription_id": schema.StringAttribute{ + Computed: true, + Sensitive: true, + Description: "Unique 36-hexadecimal character string that identifies your Azure subscription.", + MarkdownDescription: "Unique 36-hexadecimal character string that identifies your Azure subscription.", + }, + "tenant_id": schema.StringAttribute{ + Computed: true, + Sensitive: true, + Description: "Unique 36-hexadecimal character string that identifies the Azure Active Directory tenant within your Azure subscription.", + MarkdownDescription: "Unique 36-hexadecimal character string that identifies the Azure Active Directory tenant within your Azure subscription.", + }, + "valid": schema.BoolAttribute{ + Computed: true, + Description: "Flag that indicates whether the Azure encryption key can encrypt and decrypt data.", + MarkdownDescription: "Flag that indicates whether the Azure encryption key can encrypt and decrypt data.", + }, + }, + Computed: true, + Description: "Details that define the configuration of Encryption at Rest using Azure Key Vault (AKV).", + MarkdownDescription: "Details that define the configuration of Encryption at Rest using Azure Key Vault (AKV).", + }, + "google_cloud_kms_config": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "enabled": schema.BoolAttribute{ + Computed: true, + Description: "Flag that indicates whether someone enabled encryption at rest for the specified project. To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`.", + MarkdownDescription: "Flag that indicates whether someone enabled encryption at rest for the specified project. To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`.", + }, + "key_version_resource_id": schema.StringAttribute{ + Computed: true, + Sensitive: true, + Description: "Resource path that displays the key version resource ID for your Google Cloud KMS.", + MarkdownDescription: "Resource path that displays the key version resource ID for your Google Cloud KMS.", + }, + "service_account_key": schema.StringAttribute{ + Computed: true, + Sensitive: true, + Description: "JavaScript Object Notation (JSON) object that contains the Google Cloud Key Management Service (KMS). Format the JSON as a string and not as an object.", + MarkdownDescription: "JavaScript Object Notation (JSON) object that contains the Google Cloud Key Management Service (KMS). Format the JSON as a string and not as an object.", + }, + "valid": schema.BoolAttribute{ + Computed: true, + Description: "Flag that indicates whether the Google Cloud Key Management Service (KMS) encryption key can encrypt and decrypt data.", + MarkdownDescription: "Flag that indicates whether the Google Cloud Key Management Service (KMS) encryption key can encrypt and decrypt data.", + }, + }, + Computed: true, + Description: "Details that define the configuration of Encryption at Rest using Google Cloud Key Management Service (KMS).", + MarkdownDescription: "Details that define the configuration of Encryption at Rest using Google Cloud Key Management Service (KMS).", + }, + "project_id": schema.StringAttribute{ + Required: true, + Description: "Unique 24-hexadecimal digit string that identifies your project.", + MarkdownDescription: "Unique 24-hexadecimal digit string that identifies your project.", + }, + "id": schema.StringAttribute{ + Computed: true, + }, + }, + } +} + +type TFEncryptionAtRestDSModel struct { + AzureKeyVaultConfig *TFAzureKeyVaultConfigModel `tfsdk:"azure_key_vault_config"` + AwsKmsConfig *TFAwsKmsConfigModel `tfsdk:"aws_kms_config"` + GoogleCloudKmsConfig *TFGcpKmsConfigModel `tfsdk:"google_cloud_kms_config"` + ID types.String `tfsdk:"id"` + ProjectID types.String `tfsdk:"project_id"` +} + +func NewTFEncryptionAtRestDSModel(projectID string, encryptionResp *admin.EncryptionAtRest) *TFEncryptionAtRestDSModel { + return &TFEncryptionAtRestDSModel{ + ID: types.StringValue(projectID), + ProjectID: types.StringValue(projectID), + AwsKmsConfig: NewTFAwsKmsConfigItem(encryptionResp.AwsKms), + AzureKeyVaultConfig: NewTFAzureKeyVaultConfigItem(encryptionResp.AzureKeyVault), + GoogleCloudKmsConfig: NewTFGcpKmsConfigItem(encryptionResp.GoogleCloudKms), + } +} diff --git a/internal/service/encryptionatrest/model.go b/internal/service/encryptionatrest/model.go new file mode 100644 index 0000000000..3a3fddbce7 --- /dev/null +++ b/internal/service/encryptionatrest/model.go @@ -0,0 +1,151 @@ +package encryptionatrest + +import ( + "context" + + "go.mongodb.org/atlas-sdk/v20240805003/admin" + + "github.com/hashicorp/terraform-plugin-framework/types" + + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" +) + +func NewTFEncryptionAtRestRSModel(ctx context.Context, projectID string, encryptionResp *admin.EncryptionAtRest) *TfEncryptionAtRestRSModel { + return &TfEncryptionAtRestRSModel{ + ID: types.StringValue(projectID), + ProjectID: types.StringValue(projectID), + AwsKmsConfig: NewTFAwsKmsConfig(ctx, encryptionResp.AwsKms), + AzureKeyVaultConfig: NewTFAzureKeyVaultConfig(ctx, encryptionResp.AzureKeyVault), + GoogleCloudKmsConfig: NewTFGcpKmsConfig(ctx, encryptionResp.GoogleCloudKms), + } +} + +func NewTFAwsKmsConfig(ctx context.Context, awsKms *admin.AWSKMSConfiguration) []TFAwsKmsConfigModel { + if awsKms == nil { + return []TFAwsKmsConfigModel{} + } + + return []TFAwsKmsConfigModel{ + *NewTFAwsKmsConfigItem(awsKms), + } +} + +func NewTFAzureKeyVaultConfig(ctx context.Context, az *admin.AzureKeyVault) []TFAzureKeyVaultConfigModel { + if az == nil { + return []TFAzureKeyVaultConfigModel{} + } + + return []TFAzureKeyVaultConfigModel{ + *NewTFAzureKeyVaultConfigItem(az), + } +} + +func NewTFGcpKmsConfig(ctx context.Context, gcpKms *admin.GoogleCloudKMS) []TFGcpKmsConfigModel { + if gcpKms == nil { + return []TFGcpKmsConfigModel{} + } + + return []TFGcpKmsConfigModel{ + *NewTFGcpKmsConfigItem(gcpKms), + } +} + +func NewTFAwsKmsConfigItem(awsKms *admin.AWSKMSConfiguration) *TFAwsKmsConfigModel { + if awsKms == nil { + return nil + } + + return &TFAwsKmsConfigModel{ + Enabled: types.BoolPointerValue(awsKms.Enabled), + CustomerMasterKeyID: types.StringValue(awsKms.GetCustomerMasterKeyID()), + Region: types.StringValue(awsKms.GetRegion()), + AccessKeyID: conversion.StringNullIfEmpty(awsKms.GetAccessKeyID()), + SecretAccessKey: conversion.StringNullIfEmpty(awsKms.GetSecretAccessKey()), + RoleID: conversion.StringNullIfEmpty(awsKms.GetRoleId()), + Valid: types.BoolPointerValue(awsKms.Valid), + } +} + +func NewTFAzureKeyVaultConfigItem(az *admin.AzureKeyVault) *TFAzureKeyVaultConfigModel { + if az == nil { + return nil + } + + return &TFAzureKeyVaultConfigModel{ + Enabled: types.BoolPointerValue(az.Enabled), + ClientID: types.StringValue(az.GetClientID()), + AzureEnvironment: types.StringValue(az.GetAzureEnvironment()), + SubscriptionID: types.StringValue(az.GetSubscriptionID()), + ResourceGroupName: types.StringValue(az.GetResourceGroupName()), + KeyVaultName: types.StringValue(az.GetKeyVaultName()), + KeyIdentifier: types.StringValue(az.GetKeyIdentifier()), + TenantID: types.StringValue(az.GetTenantID()), + Secret: conversion.StringNullIfEmpty(az.GetSecret()), + RequirePrivateNetworking: types.BoolValue(az.GetRequirePrivateNetworking()), + Valid: types.BoolPointerValue(az.Valid), + } +} + +func NewTFGcpKmsConfigItem(gcpKms *admin.GoogleCloudKMS) *TFGcpKmsConfigModel { + if gcpKms == nil { + return nil + } + + return &TFGcpKmsConfigModel{ + Enabled: types.BoolPointerValue(gcpKms.Enabled), + KeyVersionResourceID: types.StringValue(gcpKms.GetKeyVersionResourceID()), + ServiceAccountKey: conversion.StringNullIfEmpty(gcpKms.GetServiceAccountKey()), + Valid: types.BoolPointerValue(gcpKms.Valid), + } +} + +func NewAtlasAwsKms(tfAwsKmsConfigSlice []TFAwsKmsConfigModel) *admin.AWSKMSConfiguration { + if len(tfAwsKmsConfigSlice) == 0 { + return &admin.AWSKMSConfiguration{} + } + v := tfAwsKmsConfigSlice[0] + + awsRegion, _ := conversion.ValRegion(v.Region.ValueString()) + + return &admin.AWSKMSConfiguration{ + Enabled: v.Enabled.ValueBoolPointer(), + AccessKeyID: v.AccessKeyID.ValueStringPointer(), + SecretAccessKey: v.SecretAccessKey.ValueStringPointer(), + CustomerMasterKeyID: v.CustomerMasterKeyID.ValueStringPointer(), + Region: conversion.StringPtr(awsRegion), + RoleId: v.RoleID.ValueStringPointer(), + } +} + +func NewAtlasGcpKms(tfGcpKmsConfigSlice []TFGcpKmsConfigModel) *admin.GoogleCloudKMS { + if len(tfGcpKmsConfigSlice) == 0 { + return &admin.GoogleCloudKMS{} + } + v := tfGcpKmsConfigSlice[0] + + return &admin.GoogleCloudKMS{ + Enabled: v.Enabled.ValueBoolPointer(), + ServiceAccountKey: v.ServiceAccountKey.ValueStringPointer(), + KeyVersionResourceID: v.KeyVersionResourceID.ValueStringPointer(), + } +} + +func NewAtlasAzureKeyVault(tfAzKeyVaultConfigSlice []TFAzureKeyVaultConfigModel) *admin.AzureKeyVault { + if len(tfAzKeyVaultConfigSlice) == 0 { + return &admin.AzureKeyVault{} + } + v := tfAzKeyVaultConfigSlice[0] + + return &admin.AzureKeyVault{ + Enabled: v.Enabled.ValueBoolPointer(), + ClientID: v.ClientID.ValueStringPointer(), + AzureEnvironment: v.AzureEnvironment.ValueStringPointer(), + SubscriptionID: v.SubscriptionID.ValueStringPointer(), + ResourceGroupName: v.ResourceGroupName.ValueStringPointer(), + KeyVaultName: v.KeyVaultName.ValueStringPointer(), + KeyIdentifier: v.KeyIdentifier.ValueStringPointer(), + Secret: v.Secret.ValueStringPointer(), + TenantID: v.TenantID.ValueStringPointer(), + RequirePrivateNetworking: v.RequirePrivateNetworking.ValueBoolPointer(), + } +} diff --git a/internal/service/encryptionatrest/model_encryption_at_rest.go b/internal/service/encryptionatrest/model_encryption_at_rest.go deleted file mode 100644 index 3e1eed7375..0000000000 --- a/internal/service/encryptionatrest/model_encryption_at_rest.go +++ /dev/null @@ -1,120 +0,0 @@ -package encryptionatrest - -import ( - "context" - - "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" - "go.mongodb.org/atlas-sdk/v20240805003/admin" -) - -func NewTfEncryptionAtRestRSModel(ctx context.Context, projectID string, encryptionResp *admin.EncryptionAtRest) *TfEncryptionAtRestRSModel { - return &TfEncryptionAtRestRSModel{ - ID: types.StringValue(projectID), - ProjectID: types.StringValue(projectID), - AwsKmsConfig: NewTFAwsKmsConfig(ctx, encryptionResp.AwsKms), - AzureKeyVaultConfig: NewTFAzureKeyVaultConfig(ctx, encryptionResp.AzureKeyVault), - GoogleCloudKmsConfig: NewTFGcpKmsConfig(ctx, encryptionResp.GoogleCloudKms), - } -} - -func NewTFAwsKmsConfig(ctx context.Context, awsKms *admin.AWSKMSConfiguration) []TfAwsKmsConfigModel { - if awsKms == nil { - return []TfAwsKmsConfigModel{} - } - - return []TfAwsKmsConfigModel{ - { - Enabled: types.BoolPointerValue(awsKms.Enabled), - CustomerMasterKeyID: types.StringValue(awsKms.GetCustomerMasterKeyID()), - Region: types.StringValue(awsKms.GetRegion()), - AccessKeyID: conversion.StringNullIfEmpty(awsKms.GetAccessKeyID()), - SecretAccessKey: conversion.StringNullIfEmpty(awsKms.GetSecretAccessKey()), - RoleID: conversion.StringNullIfEmpty(awsKms.GetRoleId()), - }, - } -} - -func NewTFAzureKeyVaultConfig(ctx context.Context, az *admin.AzureKeyVault) []TfAzureKeyVaultConfigModel { - if az == nil { - return []TfAzureKeyVaultConfigModel{} - } - - return []TfAzureKeyVaultConfigModel{ - { - Enabled: types.BoolPointerValue(az.Enabled), - ClientID: types.StringValue(az.GetClientID()), - AzureEnvironment: types.StringValue(az.GetAzureEnvironment()), - SubscriptionID: types.StringValue(az.GetSubscriptionID()), - ResourceGroupName: types.StringValue(az.GetResourceGroupName()), - KeyVaultName: types.StringValue(az.GetKeyVaultName()), - KeyIdentifier: types.StringValue(az.GetKeyIdentifier()), - TenantID: types.StringValue(az.GetTenantID()), - Secret: conversion.StringNullIfEmpty(az.GetSecret()), - }, - } -} - -func NewTFGcpKmsConfig(ctx context.Context, gcpKms *admin.GoogleCloudKMS) []TfGcpKmsConfigModel { - if gcpKms == nil { - return []TfGcpKmsConfigModel{} - } - - return []TfGcpKmsConfigModel{ - { - Enabled: types.BoolPointerValue(gcpKms.Enabled), - KeyVersionResourceID: types.StringValue(gcpKms.GetKeyVersionResourceID()), - ServiceAccountKey: conversion.StringNullIfEmpty(gcpKms.GetServiceAccountKey()), - }, - } -} - -func NewAtlasAwsKms(tfAwsKmsConfigSlice []TfAwsKmsConfigModel) *admin.AWSKMSConfiguration { - if len(tfAwsKmsConfigSlice) == 0 { - return &admin.AWSKMSConfiguration{} - } - v := tfAwsKmsConfigSlice[0] - - awsRegion, _ := conversion.ValRegion(v.Region.ValueString()) - - return &admin.AWSKMSConfiguration{ - Enabled: v.Enabled.ValueBoolPointer(), - AccessKeyID: v.AccessKeyID.ValueStringPointer(), - SecretAccessKey: v.SecretAccessKey.ValueStringPointer(), - CustomerMasterKeyID: v.CustomerMasterKeyID.ValueStringPointer(), - Region: conversion.StringPtr(awsRegion), - RoleId: v.RoleID.ValueStringPointer(), - } -} - -func NewAtlasGcpKms(tfGcpKmsConfigSlice []TfGcpKmsConfigModel) *admin.GoogleCloudKMS { - if len(tfGcpKmsConfigSlice) == 0 { - return &admin.GoogleCloudKMS{} - } - v := tfGcpKmsConfigSlice[0] - - return &admin.GoogleCloudKMS{ - Enabled: v.Enabled.ValueBoolPointer(), - ServiceAccountKey: v.ServiceAccountKey.ValueStringPointer(), - KeyVersionResourceID: v.KeyVersionResourceID.ValueStringPointer(), - } -} - -func NewAtlasAzureKeyVault(tfAzKeyVaultConfigSlice []TfAzureKeyVaultConfigModel) *admin.AzureKeyVault { - if len(tfAzKeyVaultConfigSlice) == 0 { - return &admin.AzureKeyVault{} - } - v := tfAzKeyVaultConfigSlice[0] - - return &admin.AzureKeyVault{ - Enabled: v.Enabled.ValueBoolPointer(), - ClientID: v.ClientID.ValueStringPointer(), - AzureEnvironment: v.AzureEnvironment.ValueStringPointer(), - SubscriptionID: v.SubscriptionID.ValueStringPointer(), - ResourceGroupName: v.ResourceGroupName.ValueStringPointer(), - KeyVaultName: v.KeyVaultName.ValueStringPointer(), - KeyIdentifier: v.KeyIdentifier.ValueStringPointer(), - Secret: v.Secret.ValueStringPointer(), - TenantID: v.TenantID.ValueStringPointer(), - } -} diff --git a/internal/service/encryptionatrest/model_encryption_at_rest_test.go b/internal/service/encryptionatrest/model_test.go similarity index 63% rename from internal/service/encryptionatrest/model_encryption_at_rest_test.go rename to internal/service/encryptionatrest/model_test.go index 9786cb0fa4..808f5b9d74 100644 --- a/internal/service/encryptionatrest/model_encryption_at_rest_test.go +++ b/internal/service/encryptionatrest/model_test.go @@ -4,31 +4,34 @@ import ( "context" "testing" + "go.mongodb.org/atlas-sdk/v20240805003/admin" + "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/encryptionatrest" "github.com/stretchr/testify/assert" - "go.mongodb.org/atlas-sdk/v20240805003/admin" + + "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/encryptionatrest" ) var ( - projectID = "projectID" - enabled = true - customerMasterKeyID = "CustomerMasterKeyID" - region = "Region" - accessKeyID = "AccessKeyID" - secretAccessKey = "SecretAccessKey" - roleID = "RoleID" - clientID = "clientID" - azureEnvironment = "AzureEnvironment" - subscriptionID = "SubscriptionID" - resourceGroupName = "ResourceGroupName" - keyVaultName = "KeyVaultName" - keyIdentifier = "KeyIdentifier" - tenantID = "TenantID" - secret = "Secret" - keyVersionResourceID = "KeyVersionResourceID" - serviceAccountKey = "ServiceAccountKey" - AWSKMSConfiguration = &admin.AWSKMSConfiguration{ + projectID = "projectID" + enabled = true + requirePrivateNetworking = true + customerMasterKeyID = "CustomerMasterKeyID" + region = "Region" + accessKeyID = "AccessKeyID" + secretAccessKey = "SecretAccessKey" + roleID = "RoleID" + clientID = "clientID" + azureEnvironment = "AzureEnvironment" + subscriptionID = "SubscriptionID" + resourceGroupName = "ResourceGroupName" + keyVaultName = "KeyVaultName" + keyIdentifier = "KeyIdentifier" + tenantID = "TenantID" + secret = "Secret" + keyVersionResourceID = "KeyVersionResourceID" + serviceAccountKey = "ServiceAccountKey" + AWSKMSConfiguration = &admin.AWSKMSConfiguration{ Enabled: &enabled, CustomerMasterKeyID: &customerMasterKeyID, Region: ®ion, @@ -36,7 +39,7 @@ var ( SecretAccessKey: &secretAccessKey, RoleId: &roleID, } - TfAwsKmsConfigModel = encryptionatrest.TfAwsKmsConfigModel{ + TfAwsKmsConfigModel = encryptionatrest.TFAwsKmsConfigModel{ Enabled: types.BoolValue(enabled), CustomerMasterKeyID: types.StringValue(customerMasterKeyID), Region: types.StringValue(region), @@ -45,33 +48,35 @@ var ( RoleID: types.StringValue(roleID), } AzureKeyVault = &admin.AzureKeyVault{ - Enabled: &enabled, - ClientID: &clientID, - AzureEnvironment: &azureEnvironment, - SubscriptionID: &subscriptionID, - ResourceGroupName: &resourceGroupName, - KeyVaultName: &keyVaultName, - KeyIdentifier: &keyIdentifier, - TenantID: &tenantID, - Secret: &secret, + Enabled: &enabled, + ClientID: &clientID, + AzureEnvironment: &azureEnvironment, + SubscriptionID: &subscriptionID, + ResourceGroupName: &resourceGroupName, + KeyVaultName: &keyVaultName, + KeyIdentifier: &keyIdentifier, + TenantID: &tenantID, + Secret: &secret, + RequirePrivateNetworking: &requirePrivateNetworking, } - TfAzureKeyVaultConfigModel = encryptionatrest.TfAzureKeyVaultConfigModel{ - Enabled: types.BoolValue(enabled), - ClientID: types.StringValue(clientID), - AzureEnvironment: types.StringValue(azureEnvironment), - SubscriptionID: types.StringValue(subscriptionID), - ResourceGroupName: types.StringValue(resourceGroupName), - KeyVaultName: types.StringValue(keyVaultName), - KeyIdentifier: types.StringValue(keyIdentifier), - TenantID: types.StringValue(tenantID), - Secret: types.StringValue(secret), + TfAzureKeyVaultConfigModel = encryptionatrest.TFAzureKeyVaultConfigModel{ + Enabled: types.BoolValue(enabled), + ClientID: types.StringValue(clientID), + AzureEnvironment: types.StringValue(azureEnvironment), + SubscriptionID: types.StringValue(subscriptionID), + ResourceGroupName: types.StringValue(resourceGroupName), + KeyVaultName: types.StringValue(keyVaultName), + KeyIdentifier: types.StringValue(keyIdentifier), + TenantID: types.StringValue(tenantID), + Secret: types.StringValue(secret), + RequirePrivateNetworking: types.BoolValue(requirePrivateNetworking), } GoogleCloudKMS = &admin.GoogleCloudKMS{ Enabled: &enabled, KeyVersionResourceID: &keyVersionResourceID, ServiceAccountKey: &serviceAccountKey, } - TfGcpKmsConfigModel = encryptionatrest.TfGcpKmsConfigModel{ + TfGcpKmsConfigModel = encryptionatrest.TFGcpKmsConfigModel{ Enabled: types.BoolValue(enabled), KeyVersionResourceID: types.StringValue(keyVersionResourceID), ServiceAccountKey: types.StringValue(serviceAccountKey), @@ -95,16 +100,16 @@ func TestNewTfEncryptionAtRestRSModel(t *testing.T) { expectedResult: &encryptionatrest.TfEncryptionAtRestRSModel{ ID: types.StringValue(projectID), ProjectID: types.StringValue(projectID), - AwsKmsConfig: []encryptionatrest.TfAwsKmsConfigModel{TfAwsKmsConfigModel}, - AzureKeyVaultConfig: []encryptionatrest.TfAzureKeyVaultConfigModel{TfAzureKeyVaultConfigModel}, - GoogleCloudKmsConfig: []encryptionatrest.TfGcpKmsConfigModel{TfGcpKmsConfigModel}, + AwsKmsConfig: []encryptionatrest.TFAwsKmsConfigModel{TfAwsKmsConfigModel}, + AzureKeyVaultConfig: []encryptionatrest.TFAzureKeyVaultConfigModel{TfAzureKeyVaultConfigModel}, + GoogleCloudKmsConfig: []encryptionatrest.TFGcpKmsConfigModel{TfGcpKmsConfigModel}, }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - resultModel := encryptionatrest.NewTfEncryptionAtRestRSModel(context.Background(), projectID, tc.sdkModel) + resultModel := encryptionatrest.NewTFEncryptionAtRestRSModel(context.Background(), projectID, tc.sdkModel) assert.Equal(t, tc.expectedResult, resultModel) }) } @@ -114,19 +119,19 @@ func TestNewTFAwsKmsConfig(t *testing.T) { testCases := []struct { name string sdkModel *admin.AWSKMSConfiguration - expectedResult []encryptionatrest.TfAwsKmsConfigModel + expectedResult []encryptionatrest.TFAwsKmsConfigModel }{ { name: "Success NewTFAwsKmsConfig", sdkModel: AWSKMSConfiguration, - expectedResult: []encryptionatrest.TfAwsKmsConfigModel{ + expectedResult: []encryptionatrest.TFAwsKmsConfigModel{ TfAwsKmsConfigModel, }, }, { name: "Empty sdkModel", sdkModel: nil, - expectedResult: []encryptionatrest.TfAwsKmsConfigModel{}, + expectedResult: []encryptionatrest.TFAwsKmsConfigModel{}, }, } @@ -142,19 +147,19 @@ func TestNewTFAzureKeyVaultConfig(t *testing.T) { testCases := []struct { name string sdkModel *admin.AzureKeyVault - expectedResult []encryptionatrest.TfAzureKeyVaultConfigModel + expectedResult []encryptionatrest.TFAzureKeyVaultConfigModel }{ { name: "Success NewTFAwsKmsConfig", sdkModel: AzureKeyVault, - expectedResult: []encryptionatrest.TfAzureKeyVaultConfigModel{ + expectedResult: []encryptionatrest.TFAzureKeyVaultConfigModel{ TfAzureKeyVaultConfigModel, }, }, { name: "Empty sdkModel", sdkModel: nil, - expectedResult: []encryptionatrest.TfAzureKeyVaultConfigModel{}, + expectedResult: []encryptionatrest.TFAzureKeyVaultConfigModel{}, }, } @@ -170,19 +175,19 @@ func TestNewTFGcpKmsConfig(t *testing.T) { testCases := []struct { name string sdkModel *admin.GoogleCloudKMS - expectedResult []encryptionatrest.TfGcpKmsConfigModel + expectedResult []encryptionatrest.TFGcpKmsConfigModel }{ { name: "Success NewTFGcpKmsConfig", sdkModel: GoogleCloudKMS, - expectedResult: []encryptionatrest.TfGcpKmsConfigModel{ + expectedResult: []encryptionatrest.TFGcpKmsConfigModel{ TfGcpKmsConfigModel, }, }, { name: "Empty sdkModel", sdkModel: nil, - expectedResult: []encryptionatrest.TfGcpKmsConfigModel{}, + expectedResult: []encryptionatrest.TFGcpKmsConfigModel{}, }, } @@ -198,11 +203,11 @@ func TestNewAtlasAwsKms(t *testing.T) { testCases := []struct { name string expectedResult *admin.AWSKMSConfiguration - tfModel []encryptionatrest.TfAwsKmsConfigModel + tfModel []encryptionatrest.TFAwsKmsConfigModel }{ { name: "Success NewAtlasAwsKms", - tfModel: []encryptionatrest.TfAwsKmsConfigModel{TfAwsKmsConfigModel}, + tfModel: []encryptionatrest.TFAwsKmsConfigModel{TfAwsKmsConfigModel}, expectedResult: AWSKMSConfiguration, }, { @@ -224,11 +229,11 @@ func TestNewAtlasGcpKms(t *testing.T) { testCases := []struct { name string expectedResult *admin.GoogleCloudKMS - tfModel []encryptionatrest.TfGcpKmsConfigModel + tfModel []encryptionatrest.TFGcpKmsConfigModel }{ { name: "Success NewAtlasAwsKms", - tfModel: []encryptionatrest.TfGcpKmsConfigModel{TfGcpKmsConfigModel}, + tfModel: []encryptionatrest.TFGcpKmsConfigModel{TfGcpKmsConfigModel}, expectedResult: GoogleCloudKMS, }, { @@ -250,11 +255,11 @@ func TestNewAtlasAzureKeyVault(t *testing.T) { testCases := []struct { name string expectedResult *admin.AzureKeyVault - tfModel []encryptionatrest.TfAzureKeyVaultConfigModel + tfModel []encryptionatrest.TFAzureKeyVaultConfigModel }{ { name: "Success NewAtlasAwsKms", - tfModel: []encryptionatrest.TfAzureKeyVaultConfigModel{TfAzureKeyVaultConfigModel}, + tfModel: []encryptionatrest.TFAzureKeyVaultConfigModel{TfAzureKeyVaultConfigModel}, expectedResult: AzureKeyVault, }, { diff --git a/internal/service/encryptionatrest/resource_encryption_at_rest.go b/internal/service/encryptionatrest/resource.go similarity index 59% rename from internal/service/encryptionatrest/resource_encryption_at_rest.go rename to internal/service/encryptionatrest/resource.go index fc17c1085a..7a82d2bc69 100644 --- a/internal/service/encryptionatrest/resource_encryption_at_rest.go +++ b/internal/service/encryptionatrest/resource.go @@ -9,6 +9,8 @@ import ( "reflect" "time" + "go.mongodb.org/atlas-sdk/v20240805003/admin" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -19,12 +21,12 @@ import ( "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/retrystrategy" "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/validate" "github.com/mongodb/terraform-provider-mongodbatlas/internal/config" "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/project" - "go.mongodb.org/atlas-sdk/v20240805003/admin" ) const ( @@ -53,34 +55,38 @@ type encryptionAtRestRS struct { type TfEncryptionAtRestRSModel struct { ID types.String `tfsdk:"id"` ProjectID types.String `tfsdk:"project_id"` - AwsKmsConfig []TfAwsKmsConfigModel `tfsdk:"aws_kms_config"` - AzureKeyVaultConfig []TfAzureKeyVaultConfigModel `tfsdk:"azure_key_vault_config"` - GoogleCloudKmsConfig []TfGcpKmsConfigModel `tfsdk:"google_cloud_kms_config"` + AwsKmsConfig []TFAwsKmsConfigModel `tfsdk:"aws_kms_config"` + AzureKeyVaultConfig []TFAzureKeyVaultConfigModel `tfsdk:"azure_key_vault_config"` + GoogleCloudKmsConfig []TFGcpKmsConfigModel `tfsdk:"google_cloud_kms_config"` } -type TfAwsKmsConfigModel struct { +type TFAwsKmsConfigModel struct { AccessKeyID types.String `tfsdk:"access_key_id"` SecretAccessKey types.String `tfsdk:"secret_access_key"` CustomerMasterKeyID types.String `tfsdk:"customer_master_key_id"` Region types.String `tfsdk:"region"` RoleID types.String `tfsdk:"role_id"` Enabled types.Bool `tfsdk:"enabled"` + Valid types.Bool `tfsdk:"valid"` } -type TfAzureKeyVaultConfigModel struct { - ClientID types.String `tfsdk:"client_id"` - AzureEnvironment types.String `tfsdk:"azure_environment"` - SubscriptionID types.String `tfsdk:"subscription_id"` - ResourceGroupName types.String `tfsdk:"resource_group_name"` - KeyVaultName types.String `tfsdk:"key_vault_name"` - KeyIdentifier types.String `tfsdk:"key_identifier"` - Secret types.String `tfsdk:"secret"` - TenantID types.String `tfsdk:"tenant_id"` - Enabled types.Bool `tfsdk:"enabled"` +type TFAzureKeyVaultConfigModel struct { + ClientID types.String `tfsdk:"client_id"` + AzureEnvironment types.String `tfsdk:"azure_environment"` + SubscriptionID types.String `tfsdk:"subscription_id"` + ResourceGroupName types.String `tfsdk:"resource_group_name"` + KeyVaultName types.String `tfsdk:"key_vault_name"` + KeyIdentifier types.String `tfsdk:"key_identifier"` + Secret types.String `tfsdk:"secret"` + TenantID types.String `tfsdk:"tenant_id"` + Enabled types.Bool `tfsdk:"enabled"` + RequirePrivateNetworking types.Bool `tfsdk:"require_private_networking"` + Valid types.Bool `tfsdk:"valid"` } -type TfGcpKmsConfigModel struct { +type TFGcpKmsConfigModel struct { ServiceAccountKey types.String `tfsdk:"service_account_key"` KeyVersionResourceID types.String `tfsdk:"key_version_resource_id"` Enabled types.Bool `tfsdk:"enabled"` + Valid types.Bool `tfsdk:"valid"` } func (r *encryptionAtRestRS) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { @@ -97,11 +103,15 @@ func (r *encryptionAtRestRS) Schema(ctx context.Context, req resource.SchemaRequ PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, + Description: "Unique 24-hexadecimal digit string that identifies your project.", + MarkdownDescription: "Unique 24-hexadecimal digit string that identifies your project.", }, }, Blocks: map[string]schema.Block{ "aws_kms_config": schema.ListNestedBlock{ - Validators: []validator.List{listvalidator.SizeAtMost(1)}, + Description: "Amazon Web Services (AWS) KMS configuration details and encryption at rest configuration set for the specified project.", + MarkdownDescription: "Amazon Web Services (AWS) KMS configuration details and encryption at rest configuration set for the specified project.", + Validators: []validator.List{listvalidator.SizeAtMost(1)}, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ @@ -110,31 +120,50 @@ func (r *encryptionAtRestRS) Schema(ctx context.Context, req resource.SchemaRequ PlanModifiers: []planmodifier.Bool{ boolplanmodifier.UseStateForUnknown(), }, + Description: "Flag that indicates whether someone enabled encryption at rest for the specified project through Amazon Web Services (AWS) Key Management Service (KMS). To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`.", + MarkdownDescription: "Flag that indicates whether someone enabled encryption at rest for the specified project through Amazon Web Services (AWS) Key Management Service (KMS). To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`.", }, "access_key_id": schema.StringAttribute{ - Optional: true, - Sensitive: true, + Optional: true, + Sensitive: true, + Description: "Unique alphanumeric string that identifies an Identity and Access Management (IAM) access key with permissions required to access your Amazon Web Services (AWS) Customer Master Key (CMK).", + MarkdownDescription: "Unique alphanumeric string that identifies an Identity and Access Management (IAM) access key with permissions required to access your Amazon Web Services (AWS) Customer Master Key (CMK).", }, "secret_access_key": schema.StringAttribute{ - Optional: true, - Sensitive: true, + Optional: true, + Sensitive: true, + Description: "Human-readable label of the Identity and Access Management (IAM) secret access key with permissions required to access your Amazon Web Services (AWS) customer master key.", + MarkdownDescription: "Human-readable label of the Identity and Access Management (IAM) secret access key with permissions required to access your Amazon Web Services (AWS) customer master key.", }, "customer_master_key_id": schema.StringAttribute{ - Optional: true, - Sensitive: true, + Optional: true, + Sensitive: true, + Description: "Unique alphanumeric string that identifies the Amazon Web Services (AWS) Customer Master Key (CMK) you used to encrypt and decrypt the MongoDB master keys.", + MarkdownDescription: "Unique alphanumeric string that identifies the Amazon Web Services (AWS) Customer Master Key (CMK) you used to encrypt and decrypt the MongoDB master keys.", }, "region": schema.StringAttribute{ - Optional: true, + Optional: true, + Description: "Physical location where MongoDB Atlas deploys your AWS-hosted MongoDB cluster nodes. The region you choose can affect network latency for clients accessing your databases. When MongoDB Cloud deploys a dedicated cluster, it checks if a VPC or VPC connection exists for that provider and region. If not, MongoDB Atlas creates them as part of the deployment. MongoDB Atlas assigns the VPC a CIDR block. To limit a new VPC peering connection to one CIDR block and region, create the connection first. Deploy the cluster after the connection starts.", //nolint:lll // reason: auto-generated from Open API spec. + MarkdownDescription: "Physical location where MongoDB Atlas deploys your AWS-hosted MongoDB cluster nodes. The region you choose can affect network latency for clients accessing your databases. When MongoDB Cloud deploys a dedicated cluster, it checks if a VPC or VPC connection exists for that provider and region. If not, MongoDB Atlas creates them as part of the deployment. MongoDB Atlas assigns the VPC a CIDR block. To limit a new VPC peering connection to one CIDR block and region, create the connection first. Deploy the cluster after the connection starts.", //nolint:lll // reason: auto-generated from Open API spec. }, "role_id": schema.StringAttribute{ - Optional: true, + Optional: true, + Description: "Unique 24-hexadecimal digit string that identifies an Amazon Web Services (AWS) Identity and Access Management (IAM) role. This IAM role has the permissions required to manage your AWS customer master key.", + MarkdownDescription: "Unique 24-hexadecimal digit string that identifies an Amazon Web Services (AWS) Identity and Access Management (IAM) role. This IAM role has the permissions required to manage your AWS customer master key.", + }, + "valid": schema.BoolAttribute{ + Computed: true, + Description: "Flag that indicates whether the Amazon Web Services (AWS) Key Management Service (KMS) encryption key can encrypt and decrypt data.", + MarkdownDescription: "Flag that indicates whether the Amazon Web Services (AWS) Key Management Service (KMS) encryption key can encrypt and decrypt data.", }, }, Validators: []validator.Object{validate.AwsKmsConfig()}, }, }, "azure_key_vault_config": schema.ListNestedBlock{ - Validators: []validator.List{listvalidator.SizeAtMost(1)}, + Description: "Details that define the configuration of Encryption at Rest using Azure Key Vault (AKV).", + MarkdownDescription: "Details that define the configuration of Encryption at Rest using Azure Key Vault (AKV).", + Validators: []validator.List{listvalidator.SizeAtMost(1)}, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ @@ -143,41 +172,75 @@ func (r *encryptionAtRestRS) Schema(ctx context.Context, req resource.SchemaRequ PlanModifiers: []planmodifier.Bool{ boolplanmodifier.UseStateForUnknown(), }, + Description: "Flag that indicates whether someone enabled encryption at rest for the specified project. To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`.", + MarkdownDescription: "Flag that indicates whether someone enabled encryption at rest for the specified project. To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`.", }, "client_id": schema.StringAttribute{ - Optional: true, - Sensitive: true, + Optional: true, + Sensitive: true, + Description: "Unique 36-hexadecimal character string that identifies an Azure application associated with your Azure Active Directory tenant.", + MarkdownDescription: "Unique 36-hexadecimal character string that identifies an Azure application associated with your Azure Active Directory tenant.", }, "azure_environment": schema.StringAttribute{ - Optional: true, + Optional: true, + Description: "Azure environment in which your account credentials reside.", + MarkdownDescription: "Azure environment in which your account credentials reside.", }, "subscription_id": schema.StringAttribute{ - Optional: true, - Sensitive: true, + Optional: true, + Sensitive: true, + Description: "Unique 36-hexadecimal character string that identifies your Azure subscription.", + MarkdownDescription: "Unique 36-hexadecimal character string that identifies your Azure subscription.", }, "resource_group_name": schema.StringAttribute{ - Optional: true, + Optional: true, + Description: "Name of the Azure resource group that contains your Azure Key Vault.", + MarkdownDescription: "Name of the Azure resource group that contains your Azure Key Vault.", }, "key_vault_name": schema.StringAttribute{ - Optional: true, + Optional: true, + Description: "Unique string that identifies the Azure Key Vault that contains your key.", + MarkdownDescription: "Unique string that identifies the Azure Key Vault that contains your key.", }, "key_identifier": schema.StringAttribute{ - Optional: true, - Sensitive: true, + Optional: true, + Sensitive: true, + Description: "Web address with a unique key that identifies for your Azure Key Vault.", + MarkdownDescription: "Web address with a unique key that identifies for your Azure Key Vault.", }, "secret": schema.StringAttribute{ - Optional: true, - Sensitive: true, + Optional: true, + Sensitive: true, + Description: "Private data that you need secured and that belongs to the specified Azure Key Vault (AKV) tenant (**azureKeyVault.tenantID**). This data can include any type of sensitive data such as passwords, database connection strings, API keys, and the like. AKV stores this information as encrypted binary data.", + MarkdownDescription: "Private data that you need secured and that belongs to the specified Azure Key Vault (AKV) tenant (**azureKeyVault.tenantID**). This data can include any type of sensitive data such as passwords, database connection strings, API keys, and the like. AKV stores this information as encrypted binary data.", }, "tenant_id": schema.StringAttribute{ - Optional: true, - Sensitive: true, + Optional: true, + Sensitive: true, + Description: "Unique 36-hexadecimal character string that identifies the Azure Active Directory tenant within your Azure subscription.", + MarkdownDescription: "Unique 36-hexadecimal character string that identifies the Azure Active Directory tenant within your Azure subscription.", + }, + "require_private_networking": schema.BoolAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.UseStateForUnknown(), + }, + Description: "Enable connection to your Azure Key Vault over private networking.", + MarkdownDescription: "Enable connection to your Azure Key Vault over private networking.", + }, + "valid": schema.BoolAttribute{ + Computed: true, + Description: "Flag that indicates whether the Azure encryption key can encrypt and decrypt data.", + MarkdownDescription: "Flag that indicates whether the Azure encryption key can encrypt and decrypt data.", }, }, }, }, "google_cloud_kms_config": schema.ListNestedBlock{ - Validators: []validator.List{listvalidator.SizeAtMost(1)}, + Description: "Details that define the configuration of Encryption at Rest using Google Cloud Key Management Service (KMS).", + MarkdownDescription: "Details that define the configuration of Encryption at Rest using Google Cloud Key Management Service (KMS).", + Validators: []validator.List{listvalidator.SizeAtMost(1)}, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ @@ -186,14 +249,25 @@ func (r *encryptionAtRestRS) Schema(ctx context.Context, req resource.SchemaRequ PlanModifiers: []planmodifier.Bool{ boolplanmodifier.UseStateForUnknown(), }, + Description: "Flag that indicates whether someone enabled encryption at rest for the specified project. To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`.", + MarkdownDescription: "Flag that indicates whether someone enabled encryption at rest for the specified project. To disable encryption at rest using customer key management and remove the configuration details, pass only this parameter with a value of `false`.", }, "service_account_key": schema.StringAttribute{ - Optional: true, - Sensitive: true, + Optional: true, + Sensitive: true, + Description: "JavaScript Object Notation (JSON) object that contains the Google Cloud Key Management Service (KMS). Format the JSON as a string and not as an object.", + MarkdownDescription: "JavaScript Object Notation (JSON) object that contains the Google Cloud Key Management Service (KMS). Format the JSON as a string and not as an object.", }, "key_version_resource_id": schema.StringAttribute{ - Optional: true, - Sensitive: true, + Optional: true, + Sensitive: true, + Description: "Resource path that displays the key version resource ID for your Google Cloud KMS.", + MarkdownDescription: "Resource path that displays the key version resource ID for your Google Cloud KMS.", + }, + "valid": schema.BoolAttribute{ + Computed: true, + Description: "Flag that indicates whether the Google Cloud Key Management Service (KMS) encryption key can encrypt and decrypt data.", + MarkdownDescription: "Flag that indicates whether the Google Cloud Key Management Service (KMS) encryption key can encrypt and decrypt data.", }, }, }, @@ -241,7 +315,7 @@ func (r *encryptionAtRestRS) Create(ctx context.Context, req resource.CreateRequ return } - encryptionAtRestPlanNew := NewTfEncryptionAtRestRSModel(ctx, projectID, encryptionResp.(*admin.EncryptionAtRest)) + encryptionAtRestPlanNew := NewTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp.(*admin.EncryptionAtRest)) resetDefaultsFromConfigOrState(ctx, encryptionAtRestPlan, encryptionAtRestPlanNew, encryptionAtRestConfig) // set state to fully populated data @@ -299,7 +373,7 @@ func (r *encryptionAtRestRS) Read(ctx context.Context, req resource.ReadRequest, return } - encryptionAtRestStateNew := NewTfEncryptionAtRestRSModel(ctx, projectID, encryptionResp) + encryptionAtRestStateNew := NewTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) if isImport { setEmptyArrayForEmptyBlocksReturnedFromImport(encryptionAtRestStateNew) } else { @@ -361,7 +435,7 @@ func (r *encryptionAtRestRS) Update(ctx context.Context, req resource.UpdateRequ return } - encryptionAtRestStateNew := NewTfEncryptionAtRestRSModel(ctx, projectID, encryptionResp) + encryptionAtRestStateNew := NewTFEncryptionAtRestRSModel(ctx, projectID, encryptionResp) resetDefaultsFromConfigOrState(ctx, encryptionAtRestState, encryptionAtRestStateNew, encryptionAtRestConfig) // save updated data into Terraform state @@ -404,15 +478,15 @@ func (r *encryptionAtRestRS) ImportState(ctx context.Context, req resource.Impor resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } -func hasGcpKmsConfigChanged(gcpKmsConfigsPlan, gcpKmsConfigsState []TfGcpKmsConfigModel) bool { +func hasGcpKmsConfigChanged(gcpKmsConfigsPlan, gcpKmsConfigsState []TFGcpKmsConfigModel) bool { return !reflect.DeepEqual(gcpKmsConfigsPlan, gcpKmsConfigsState) } -func hasAzureKeyVaultConfigChanged(azureKeyVaultConfigPlan, azureKeyVaultConfigState []TfAzureKeyVaultConfigModel) bool { +func hasAzureKeyVaultConfigChanged(azureKeyVaultConfigPlan, azureKeyVaultConfigState []TFAzureKeyVaultConfigModel) bool { return !reflect.DeepEqual(azureKeyVaultConfigPlan, azureKeyVaultConfigState) } -func hasAwsKmsConfigChanged(awsKmsConfigPlan, awsKmsConfigState []TfAwsKmsConfigModel) bool { +func hasAwsKmsConfigChanged(awsKmsConfigPlan, awsKmsConfigState []TFAwsKmsConfigModel) bool { return !reflect.DeepEqual(awsKmsConfigPlan, awsKmsConfigState) } @@ -432,7 +506,7 @@ func resetDefaultsFromConfigOrState(ctx context.Context, encryptionAtRestRSCurre func HandleGcpKmsConfig(ctx context.Context, earRSCurrent, earRSNew, earRSConfig *TfEncryptionAtRestRSModel) { // this is required to avoid unnecessary change detection during plan after migration to Plugin Framework if user didn't set this block if earRSCurrent.GoogleCloudKmsConfig == nil { - earRSNew.GoogleCloudKmsConfig = []TfGcpKmsConfigModel{} + earRSNew.GoogleCloudKmsConfig = []TFGcpKmsConfigModel{} return } @@ -448,7 +522,7 @@ func HandleGcpKmsConfig(ctx context.Context, earRSCurrent, earRSNew, earRSConfig func HandleAwsKmsConfigDefaults(ctx context.Context, currentStateFile, newStateFile, earRSConfig *TfEncryptionAtRestRSModel) { // this is required to avoid unnecessary change detection during plan after migration to Plugin Framework if user didn't set this block if currentStateFile.AwsKmsConfig == nil { - newStateFile.AwsKmsConfig = []TfAwsKmsConfigModel{} + newStateFile.AwsKmsConfig = []TFAwsKmsConfigModel{} return } @@ -469,7 +543,7 @@ func HandleAwsKmsConfigDefaults(ctx context.Context, currentStateFile, newStateF func HandleAzureKeyVaultConfigDefaults(ctx context.Context, earRSCurrent, earRSNew, earRSConfig *TfEncryptionAtRestRSModel) { // this is required to avoid unnecessary change detection during plan after migration to Plugin Framework if user didn't set this block if earRSCurrent.AzureKeyVaultConfig == nil { - earRSNew.AzureKeyVaultConfig = []TfAzureKeyVaultConfigModel{} + earRSNew.AzureKeyVaultConfig = []TFAzureKeyVaultConfigModel{} return } @@ -490,14 +564,14 @@ func HandleAzureKeyVaultConfigDefaults(ctx context.Context, earRSCurrent, earRSN // - the API returns the block TfAzureKeyVaultConfigModel{enable=false} if the user does not provider AZURE KMS func setEmptyArrayForEmptyBlocksReturnedFromImport(newStateFromImport *TfEncryptionAtRestRSModel) { if len(newStateFromImport.AwsKmsConfig) == 1 && !newStateFromImport.AwsKmsConfig[0].Enabled.ValueBool() { - newStateFromImport.AwsKmsConfig = []TfAwsKmsConfigModel{} + newStateFromImport.AwsKmsConfig = []TFAwsKmsConfigModel{} } if len(newStateFromImport.GoogleCloudKmsConfig) == 1 && !newStateFromImport.GoogleCloudKmsConfig[0].Enabled.ValueBool() { - newStateFromImport.GoogleCloudKmsConfig = []TfGcpKmsConfigModel{} + newStateFromImport.GoogleCloudKmsConfig = []TFGcpKmsConfigModel{} } if len(newStateFromImport.AzureKeyVaultConfig) == 1 && !newStateFromImport.AzureKeyVaultConfig[0].Enabled.ValueBool() { - newStateFromImport.AzureKeyVaultConfig = []TfAzureKeyVaultConfigModel{} + newStateFromImport.AzureKeyVaultConfig = []TFAzureKeyVaultConfigModel{} } } diff --git a/internal/service/encryptionatrest/resource_encryption_at_rest_migration_test.go b/internal/service/encryptionatrest/resource_migration_test.go similarity index 61% rename from internal/service/encryptionatrest/resource_encryption_at_rest_migration_test.go rename to internal/service/encryptionatrest/resource_migration_test.go index cf9ed9d228..095dd099f7 100644 --- a/internal/service/encryptionatrest/resource_encryption_at_rest_migration_test.go +++ b/internal/service/encryptionatrest/resource_migration_test.go @@ -1,15 +1,19 @@ package encryptionatrest_test import ( + "fmt" "os" + "strconv" "testing" + "go.mongodb.org/atlas-sdk/v20240805003/admin" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc" "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/mig" - "go.mongodb.org/atlas-sdk/v20240805003/admin" ) func TestMigEncryptionAtRest_basicAWS(t *testing.T) { @@ -22,36 +26,28 @@ func TestMigEncryptionAtRest_basicAWS(t *testing.T) { awsKms = admin.AWSKMSConfiguration{ Enabled: conversion.Pointer(true), CustomerMasterKeyID: conversion.StringPtr(os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID")), - Region: conversion.StringPtr(os.Getenv("AWS_REGION")), + Region: conversion.StringPtr(conversion.AWSRegionToMongoDBRegion(os.Getenv("AWS_REGION"))), RoleId: conversion.StringPtr(os.Getenv("AWS_ROLE_ID")), } + useDatasource = mig.IsProviderVersionAtLeast("1.19.0") // data source introduced in this version ) resource.Test(t, resource.TestCase{ PreCheck: func() { mig.PreCheck(t); acc.PreCheckAwsEnv(t) }, - CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, + CheckDestroy: acc.EARDestroy, Steps: []resource.TestStep{ { ExternalProviders: mig.ExternalProviders(), - Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKms(projectID, &awsKms), + Config: configAwsKms(projectID, &awsKms, useDatasource), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), + acc.CheckEARExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.enabled", "true"), resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.region", awsKms.GetRegion()), resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.role_id", awsKms.GetRoleId()), ), }, - { - ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, - Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKms(projectID, &awsKms), - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - acc.DebugPlan(), - plancheck.ExpectEmptyPlan(), - }, - }, - }, + mig.TestStepCheckEmptyPlan(configAwsKms(projectID, &awsKms, useDatasource)), }, }) } @@ -62,36 +58,35 @@ func TestMigEncryptionAtRest_withRole_basicAWS(t *testing.T) { var ( resourceName = "mongodbatlas_encryption_at_rest.test" projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") - accessKeyID = os.Getenv("AWS_ACCESS_KEY_ID") - secretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") - policyName = acc.RandomName() - roleName = acc.RandomName() + + awsIAMRoleName = acc.RandomIAMRole() + awsIAMRolePolicyName = fmt.Sprintf("%s-policy", awsIAMRoleName) + awsKeyName = acc.RandomName() awsKms = admin.AWSKMSConfiguration{ Enabled: conversion.Pointer(true), + Region: conversion.StringPtr(conversion.AWSRegionToMongoDBRegion(os.Getenv("AWS_REGION"))), CustomerMasterKeyID: conversion.StringPtr(os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID")), - Region: conversion.StringPtr(os.Getenv("AWS_REGION")), } ) resource.Test(t, resource.TestCase{ PreCheck: func() { mig.PreCheck(t); acc.PreCheckAwsEnv(t) }, - CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, + CheckDestroy: acc.EARDestroy, Steps: []resource.TestStep{ { ExternalProviders: mig.ExternalProvidersWithAWS(), - Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKmsWithRole(awsKms.GetRegion(), accessKeyID, secretKey, projectID, policyName, roleName, false, &awsKms), + Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKmsWithRole(projectID, awsIAMRoleName, awsIAMRolePolicyName, awsKeyName, &awsKms), }, { ExternalProviders: acc.ExternalProvidersOnlyAWS(), ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, - Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKmsWithRole(awsKms.GetRegion(), accessKeyID, secretKey, projectID, policyName, roleName, false, &awsKms), + Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKmsWithRole(projectID, awsIAMRoleName, awsIAMRolePolicyName, awsKeyName, &awsKms), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), + acc.CheckEARExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.enabled", "true"), resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.region", awsKms.GetRegion()), - resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.role_id", awsKms.GetRoleId()), ), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ @@ -105,11 +100,9 @@ func TestMigEncryptionAtRest_withRole_basicAWS(t *testing.T) { } func TestMigEncryptionAtRest_basicAzure(t *testing.T) { - acc.SkipTestForCI(t) // needs Azure configuration - var ( resourceName = "mongodbatlas_encryption_at_rest.test" - projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID") + projectID = acc.ProjectIDExecution(t) azureKeyVault = admin.AzureKeyVault{ Enabled: conversion.Pointer(true), @@ -119,37 +112,38 @@ func TestMigEncryptionAtRest_basicAzure(t *testing.T) { ResourceGroupName: conversion.StringPtr(os.Getenv("AZURE_RESOURCE_GROUP_NAME")), KeyVaultName: conversion.StringPtr(os.Getenv("AZURE_KEY_VAULT_NAME")), KeyIdentifier: conversion.StringPtr(os.Getenv("AZURE_KEY_IDENTIFIER")), - Secret: conversion.StringPtr(os.Getenv("AZURE_SECRET")), + Secret: conversion.StringPtr(os.Getenv("AZURE_APP_SECRET")), TenantID: conversion.StringPtr(os.Getenv("AZURE_TENANT_ID")), } + + attrMap = map[string]string{ + "enabled": strconv.FormatBool(azureKeyVault.GetEnabled()), + "azure_environment": azureKeyVault.GetAzureEnvironment(), + "resource_group_name": azureKeyVault.GetResourceGroupName(), + "key_vault_name": azureKeyVault.GetKeyVaultName(), + "client_id": azureKeyVault.GetClientID(), + "key_identifier": azureKeyVault.GetKeyIdentifier(), + "subscription_id": azureKeyVault.GetSubscriptionID(), + "tenant_id": azureKeyVault.GetTenantID(), + } + + useDatasource = mig.IsProviderVersionAtLeast("1.19.0") // data source introduced in this version ) resource.Test(t, resource.TestCase{ - PreCheck: func() { mig.PreCheck(t); acc.PreCheckEncryptionAtRestEnvAzure(t) }, - CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, + PreCheck: func() { mig.PreCheckBasic(t); acc.PreCheckEncryptionAtRestEnvAzure(t) }, + CheckDestroy: acc.EARDestroy, Steps: []resource.TestStep{ { ExternalProviders: mig.ExternalProviders(), - Config: testAccMongoDBAtlasEncryptionAtRestConfigAzureKeyVault(projectID, &azureKeyVault), + Config: acc.ConfigEARAzureKeyVault(projectID, &azureKeyVault, false, useDatasource), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), + acc.CheckEARExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), - resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.enabled", "true"), - resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.azure_environment", azureKeyVault.GetAzureEnvironment()), - resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.resource_group_name", azureKeyVault.GetResourceGroupName()), - resource.TestCheckResourceAttr(resourceName, "azure_key_vault_config.0.key_vault_name", azureKeyVault.GetKeyVaultName()), + acc.EARCheckResourceAttr(resourceName, "azure_key_vault_config.0", attrMap), ), }, - { - ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, - Config: testAccMongoDBAtlasEncryptionAtRestConfigAzureKeyVault(projectID, &azureKeyVault), - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - acc.DebugPlan(), - plancheck.ExpectEmptyPlan(), - }, - }, - }, + mig.TestStepCheckEmptyPlan(acc.ConfigEARAzureKeyVault(projectID, &azureKeyVault, false, useDatasource)), }, }) } @@ -166,31 +160,24 @@ func TestMigEncryptionAtRest_basicGCP(t *testing.T) { ServiceAccountKey: conversion.StringPtr(os.Getenv("GCP_SERVICE_ACCOUNT_KEY")), KeyVersionResourceID: conversion.StringPtr(os.Getenv("GCP_KEY_VERSION_RESOURCE_ID")), } + useDatasource = mig.IsProviderVersionAtLeast("1.19.0") // data source introduced in this version ) resource.Test(t, resource.TestCase{ PreCheck: func() { mig.PreCheck(t); acc.PreCheckGPCEnv(t) }, - CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, + CheckDestroy: acc.EARDestroy, Steps: []resource.TestStep{ { ExternalProviders: mig.ExternalProviders(), - Config: testAccMongoDBAtlasEncryptionAtRestConfigGoogleCloudKms(projectID, &googleCloudKms), + Config: configGoogleCloudKms(projectID, &googleCloudKms, useDatasource), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), + acc.CheckEARExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), resource.TestCheckResourceAttr(resourceName, "google_cloud_kms_config.0.enabled", "true"), + resource.TestCheckResourceAttrSet(resourceName, "google_cloud_kms_config.0.key_version_resource_id"), ), }, - { - ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, - Config: testAccMongoDBAtlasEncryptionAtRestConfigGoogleCloudKms(projectID, &googleCloudKms), - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - acc.DebugPlan(), - plancheck.ExpectEmptyPlan(), - }, - }, - }, + mig.TestStepCheckEmptyPlan(configGoogleCloudKms(projectID, &googleCloudKms, useDatasource)), }, }) } @@ -207,36 +194,28 @@ func TestMigEncryptionAtRest_basicAWS_from_v1_11_0(t *testing.T) { AccessKeyID: conversion.StringPtr(os.Getenv("AWS_ACCESS_KEY_ID")), SecretAccessKey: conversion.StringPtr(os.Getenv("AWS_SECRET_ACCESS_KEY")), CustomerMasterKeyID: conversion.StringPtr(os.Getenv("AWS_CUSTOMER_MASTER_KEY_ID")), - Region: conversion.StringPtr(os.Getenv("AWS_REGION")), + Region: conversion.StringPtr(conversion.AWSRegionToMongoDBRegion(os.Getenv("AWS_REGION"))), RoleId: conversion.StringPtr(os.Getenv("AWS_ROLE_ID")), } + useDatasource = mig.IsProviderVersionAtLeast("1.19.0") // data source introduced in this version ) resource.Test(t, resource.TestCase{ PreCheck: func() { acc.PreCheck(t); acc.PreCheckAwsEnv(t) }, - CheckDestroy: testAccCheckMongoDBAtlasEncryptionAtRestDestroy, + CheckDestroy: acc.EARDestroy, Steps: []resource.TestStep{ { ExternalProviders: acc.ExternalProvidersWithAWS("1.11.0"), - Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKms(projectID, &awsKms), + Config: configAwsKms(projectID, &awsKms, useDatasource), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckMongoDBAtlasEncryptionAtRestExists(resourceName), + acc.CheckEARExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.enabled", "true"), resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.region", awsKms.GetRegion()), resource.TestCheckResourceAttr(resourceName, "aws_kms_config.0.role_id", awsKms.GetRoleId()), ), }, - { - ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, - Config: testAccMongoDBAtlasEncryptionAtRestConfigAwsKms(projectID, &awsKms), - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - acc.DebugPlan(), - plancheck.ExpectEmptyPlan(), - }, - }, - }, + mig.TestStepCheckEmptyPlan(configAwsKms(projectID, &awsKms, useDatasource)), }, }) } diff --git a/internal/service/encryptionatrest/resource_encryption_at_rest_test.go b/internal/service/encryptionatrest/resource_test.go similarity index 52% rename from internal/service/encryptionatrest/resource_encryption_at_rest_test.go rename to internal/service/encryptionatrest/resource_test.go index 91786ca273..4e306227e0 100644 --- a/internal/service/encryptionatrest/resource_encryption_at_rest_test.go +++ b/internal/service/encryptionatrest/resource_test.go @@ -7,157 +7,96 @@ import ( "os" "testing" + "go.mongodb.org/atlas-sdk/v20240805003/admin" + "go.mongodb.org/atlas-sdk/v20240805003/mockadmin" + "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/retrystrategy" "github.com/mongodb/terraform-provider-mongodbatlas/internal/service/encryptionatrest" "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "go.mongodb.org/atlas-sdk/v20240805003/admin" - "go.mongodb.org/atlas-sdk/v20240805003/mockadmin" ) const ( - initialConfigEncryptionRestRoleAWS = ` -provider "aws" { - region = lower(replace("%[1]s", "_", "-")) - access_key = "%[2]s" - secret_key = "%[3]s" -} - -%[7]s - -resource "mongodbatlas_cloud_provider_access" "test" { - project_id = "%[4]s" - provider_name = "AWS" - %[8]s - -} - -resource "aws_iam_role_policy" "test_policy" { - name = "%[5]s" - role = aws_iam_role.test_role.id - - policy = <<-EOF - { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Deny", - "Action": "*", - "Resource": "*" - } - ] - } - EOF -} - -resource "aws_iam_role" "test_role" { - name = "%[6]s" - - assume_role_policy = < **IMPORTANT** By default, Atlas enables encryption at rest for all cluster storage and snapshot volumes. + +~> **IMPORTANT** Atlas limits this feature to dedicated cluster tiers of M10 and greater. For more information see: https://www.mongodb.com/docs/atlas/reference/api-resources-spec/#tag/Encryption-at-Rest-using-Customer-Key-Management + +-> **NOTE:** Groups and projects are synonymous terms. You may find `groupId` in the official documentation. + + +## Example Usages + +### Configuring encryption at rest using customer key management in AWS +{{ tffile (printf "examples/%s/aws/atlas-cluster/main.tf" .Name )}} + +### Configuring encryption at rest using customer key management in Azure +{{ tffile (printf "examples/%s/azure/main.tf" .Name )}} + +-> **NOTE:** It is possible to configure Atlas Encryption at Rest to communicate with Azure Key Vault using Azure Private Link, ensuring that all traffic between Atlas and Key Vault takes place over Azure’s private network interfaces. Please review `mongodbatlas_encryption_at_rest_private_endpoint` resource for details. + +### Configuring encryption at rest using customer key management in GCP +```terraform +resource "mongodbatlas_encryption_at_rest" "test" { + project_id = var.atlas_project_id + + google_cloud_kms_config { + enabled = true + service_account_key = "{\"type\": \"service_account\",\"project_id\": \"my-project-common-0\",\"private_key_id\": \"e120598ea4f88249469fcdd75a9a785c1bb3\",\"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEuwIBA(truncated)SfecnS0mT94D9\\n-----END PRIVATE KEY-----\\n\",\"client_email\": \"my-email-kms-0@my-project-common-0.iam.gserviceaccount.com\",\"client_id\": \"10180967717292066\",\"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\"token_uri\": \"https://accounts.google.com/o/oauth2/token\",\"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/my-email-kms-0%40my-project-common-0.iam.gserviceaccount.com\"}" + key_version_resource_id = "projects/my-project-common-0/locations/us-east4/keyRings/my-key-ring-0/cryptoKeys/my-key-0/cryptoKeyVersions/1" + } +} + +data "mongodbatlas_encryption_at_rest" "test" { + project_id = mongodbatlas_encryption_at_rest.test.project_id +} + +output "is_gcp_encryption_at_rest_valid" { + value = data.mongodbatlas_encryption_at_rest.test.google_cloud_kms_config.valid +} +``` + +{{ .SchemaMarkdown | trimspace }} + +# Import +Encryption at Rest Settings can be imported using project ID, in the format `project_id`, e.g. + +``` +$ terraform import mongodbatlas_encryption_at_rest.example 1112222b3bf99403840e8934 +``` + +For more information see: [MongoDB Atlas API Reference for Encryption at Rest using Customer Key Management.](https://www.mongodb.com/docs/atlas/reference/api-resources-spec/#tag/Encryption-at-Rest-using-Customer-Key-Management) \ No newline at end of file diff --git a/templates/data-sources/encryption_at_rest_private_endpoint.md.tmpl b/templates/data-sources/encryption_at_rest_private_endpoint.md.tmpl new file mode 100644 index 0000000000..74675e1338 --- /dev/null +++ b/templates/data-sources/encryption_at_rest_private_endpoint.md.tmpl @@ -0,0 +1,18 @@ +# {{.Type}}: {{.Name}} + +`{{.Name}}` describes a private endpoint used for encryption at rest using customer-managed keys. + +~> **IMPORTANT** The Encryption at Rest using Azure Key Vault over Private Endpoints feature is available by request. To request this functionality for your Atlas deployments, contact your Account Manager. +Additionally, you'll need to set the environment variable `MONGODB_ATLAS_ENABLE_PREVIEW=true` to use this data source. To learn more about existing limitations, see the [Manage Customer Keys with Azure Key Vault Over Private Endpoints](https://www.mongodb.com/docs/atlas/security/azure-kms-over-private-endpoint/#manage-customer-keys-with-azure-key-vault-over-private-endpoints). + +## Example Usages + +-> **NOTE:** Only Azure Key Vault with Azure Private Link is supported at this time. + +{{ tffile (printf "examples/%s/azure/singular-data-source.tf" .Name )}} + +{{ .SchemaMarkdown | trimspace }} + +For more information see: +- [MongoDB Atlas API - Private Endpoint for Encryption at Rest Using Customer Key Management](https://www.mongodb.com/docs/atlas/reference/api-resources-spec/v2/#tag/Encryption-at-Rest-using-Customer-Key-Management/operation/getEncryptionAtRestPrivateEndpoint) Documentation. +- [Manage Customer Keys with Azure Key Vault Over Private Endpoints](https://www.mongodb.com/docs/atlas/security/azure-kms-over-private-endpoint/). diff --git a/templates/data-sources/encryption_at_rest_private_endpoints.md.tmpl b/templates/data-sources/encryption_at_rest_private_endpoints.md.tmpl new file mode 100644 index 0000000000..701736d56a --- /dev/null +++ b/templates/data-sources/encryption_at_rest_private_endpoints.md.tmpl @@ -0,0 +1,18 @@ +# {{.Type}}: {{.Name}} + +`{{.Name}}` describes private endpoints of a particular cloud provider used for encryption at rest using customer-managed keys. + +~> **IMPORTANT** The Encryption at Rest using Azure Key Vault over Private Endpoints feature is available by request. To request this functionality for your Atlas deployments, contact your Account Manager. +Additionally, you'll need to set the environment variable `MONGODB_ATLAS_ENABLE_PREVIEW=true` to use this data source. To learn more about existing limitations, see the [Manage Customer Keys with Azure Key Vault Over Private Endpoints](https://www.mongodb.com/docs/atlas/security/azure-kms-over-private-endpoint/#manage-customer-keys-with-azure-key-vault-over-private-endpoints). + +## Example Usages + +-> **NOTE:** Only Azure Key Vault with Azure Private Link is supported at this time. + +{{ tffile ("examples/mongodbatlas_encryption_at_rest_private_endpoint/azure/plural-data-source.tf") }} + +{{ .SchemaMarkdown | trimspace }} + +For more information see: +- [MongoDB Atlas API - Private Endpoint for Encryption at Rest Using Customer Key Management](https://www.mongodb.com/docs/atlas/reference/api-resources-spec/v2/#tag/Encryption-at-Rest-using-Customer-Key-Management/operation/getEncryptionAtRestPrivateEndpointsForCloudProvider) Documentation. +- [Manage Customer Keys with Azure Key Vault Over Private Endpoints](https://www.mongodb.com/docs/atlas/security/azure-kms-over-private-endpoint/). diff --git a/templates/resources/encryption_at_rest.md.tmpl b/templates/resources/encryption_at_rest.md.tmpl new file mode 100644 index 0000000000..4a3d08c67e --- /dev/null +++ b/templates/resources/encryption_at_rest.md.tmpl @@ -0,0 +1,77 @@ +# {{.Type}}: {{.Name}} + +`{{.Name}}` allows management of Encryption at Rest for an Atlas project using Customer Key Management configuration. The following providers are supported: +- [Amazon Web Services Key Management Service](https://docs.atlas.mongodb.com/security-aws-kms/#security-aws-kms) +- [Azure Key Vault](https://docs.atlas.mongodb.com/security-azure-kms/#security-azure-kms) +- [Google Cloud KMS](https://docs.atlas.mongodb.com/security-gcp-kms/#security-gcp-kms) + +The [encryption at rest Terraform module](https://registry.terraform.io/modules/terraform-mongodbatlas-modules/encryption-at-rest/mongodbatlas/latest) makes use of this resource and simplifies its use. It is currently limited to AWS KMS. + +Atlas does not automatically rotate user-managed encryption keys. Defer to your preferred Encryption at Rest provider’s documentation and guidance for best practices on key rotation. Atlas automatically creates a 90-day key rotation alert when you configure Encryption at Rest using your Key Management in an Atlas project. + +See [Encryption at Rest](https://docs.atlas.mongodb.com/security-kms-encryption/index.html) for more information, including prerequisites and restrictions. + +~> **IMPORTANT** By default, Atlas enables encryption at rest for all cluster storage and snapshot volumes. + +~> **IMPORTANT** Atlas limits this feature to dedicated cluster tiers of M10 and greater. For more information see: https://www.mongodb.com/docs/atlas/reference/api-resources-spec/#tag/Encryption-at-Rest-using-Customer-Key-Management + +-> **NOTE:** Groups and projects are synonymous terms. You may find `groupId` in the official documentation. + + +-> **IMPORTANT NOTE** To disable the encryption at rest with customer key management for a project all existing clusters in the project must first either have encryption at rest for the provider set to none, e.g. `encryption_at_rest_provider = "NONE"`, or be deleted. + +## Enabling Encryption at Rest for existing Atlas cluster + +After configuring at least one key management provider for an Atlas project, Project Owners can enable customer key management for each Atlas cluster for which they require encryption. For clusters defined in terraform, the [`encryption_at_rest_provider` attribute](advanced_cluster#encryption_at_rest_provider) can be used in both `mongodbatlas_advanced_cluster` and `mongodbatlas_cluster` resources. The key management provider does not have to match the cluster cloud service provider. + +Please reference [Enable Customer Key Management for an Atlas Cluster](https://www.mongodb.com/docs/atlas/security-kms-encryption/#enable-customer-key-management-for-an-service-cluster) documentation for additional considerations. + + +## Example Usages + +### Configuring encryption at rest using customer key management in AWS +The configuration of encryption at rest with customer key management, `mongodbatlas_encryption_at_rest`, needs to be completed before a cluster is created in the project. Force this wait by using an implicit dependency via `project_id` as shown in the example below. + +{{ tffile (printf "examples/%s/aws/atlas-cluster/main.tf" .Name )}} + +**NOTE** If using the two resources path for cloud provider access, `cloud_provider_access_setup` and `cloud_provider_access_authorization`, you may need to define a `depends_on` statement for these two resources, because terraform is not able to infer the dependency. + +```terraform +resource "mongodbatlas_encryption_at_rest" "default" { + (...) + depends_on = [mongodbatlas_cloud_provider_access_setup., mongodbatlas_cloud_provider_access_authorization.] +} +``` + +### Configuring encryption at rest using customer key management in Azure +{{ tffile (printf "examples/%s/azure/main.tf" .Name )}} + +#### Manage Customer Keys with Azure Key Vault Over Private Endpoints +It is possible to configure Atlas Encryption at Rest to communicate with Azure Key Vault using Azure Private Link, ensuring that all traffic between Atlas and Key Vault takes place over Azure’s private network interfaces. This requires enabling `azure_key_vault_config.require_private_networking` attribute, together with the configuration of `mongodbatlas_encryption_at_rest_private_endpoint` resource. + +Please review [`mongodbatlas_encryption_at_rest_private_endpoint` resource documentation](encryption_at_rest_private_endpoint) and [complete example](https://github.com/mongodb/terraform-provider-mongodbatlas/tree/master/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure) for details on this functionality. + + +### Configuring encryption at rest using customer key management in GCP +```terraform +resource "mongodbatlas_encryption_at_rest" "test" { + project_id = var.atlas_project_id + + google_cloud_kms_config { + enabled = true + service_account_key = "{\"type\": \"service_account\",\"project_id\": \"my-project-common-0\",\"private_key_id\": \"e120598ea4f88249469fcdd75a9a785c1bb3\",\"private_key\": \"-----BEGIN PRIVATE KEY-----\\nMIIEuwIBA(truncated)SfecnS0mT94D9\\n-----END PRIVATE KEY-----\\n\",\"client_email\": \"my-email-kms-0@my-project-common-0.iam.gserviceaccount.com\",\"client_id\": \"10180967717292066\",\"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\"token_uri\": \"https://accounts.google.com/o/oauth2/token\",\"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/my-email-kms-0%40my-project-common-0.iam.gserviceaccount.com\"}" + key_version_resource_id = "projects/my-project-common-0/locations/us-east4/keyRings/my-key-ring-0/cryptoKeys/my-key-0/cryptoKeyVersions/1" + } +} +``` + +{{ .SchemaMarkdown | trimspace }} + +# Import +Encryption at Rest Settings can be imported using project ID, in the format `project_id`, e.g. + +``` +$ terraform import mongodbatlas_encryption_at_rest.example 1112222b3bf99403840e8934 +``` + +For more information see: [MongoDB Atlas API Reference for Encryption at Rest using Customer Key Management.](https://www.mongodb.com/docs/atlas/reference/api-resources-spec/#tag/Encryption-at-Rest-using-Customer-Key-Management) diff --git a/templates/resources/encryption_at_rest_private_endpoint.md.tmpl b/templates/resources/encryption_at_rest_private_endpoint.md.tmpl new file mode 100644 index 0000000000..4867ee2014 --- /dev/null +++ b/templates/resources/encryption_at_rest_private_endpoint.md.tmpl @@ -0,0 +1,33 @@ +# {{.Type}}: {{.Name}} + +`{{.Name}}` provides a resource for managing a private endpoint used for encryption at rest with customer-managed keys. This ensures all traffic between Atlas and customer key management systems take place over private network interfaces. + +~> **IMPORTANT** The Encryption at Rest using Azure Key Vault over Private Endpoints feature is available by request. To request this functionality for your Atlas deployments, contact your Account Manager. +Additionally, you'll need to set the environment variable `MONGODB_ATLAS_ENABLE_PREVIEW=true` to use this resource. To learn more about existing limitations, see the [Manage Customer Keys with Azure Key Vault Over Private Endpoints](https://www.mongodb.com/docs/atlas/security/azure-kms-over-private-endpoint/#manage-customer-keys-with-azure-key-vault-over-private-endpoints). + +-> **NOTE:** As a prerequisite to configuring a private endpoint for Azure Key Vault, the corresponding [`mongodbatlas_encryption_at_rest`](encryption_at_rest) resource has to be adjust by configuring [`azure_key_vault_config.require_private_networking`](encryption_at_rest#require_private_networking) to true. This attribute should be updated in place, ensuring the customer-managed keys encryption is never disabled. + +-> **NOTE:** This resource does not support update operations. To modify values of a private endpoint the existing resource must be deleted and a new one can be created with the modified values. + +## Example Usages + +-> **NOTE:** Only Azure Key Vault with Azure Private Link is supported at this time. + +### Configuring Atlas Encryption at Rest using Azure Key Vault with Azure Private Link + +Make sure to reference the [complete example section](https://github.com/mongodb/terraform-provider-mongodbatlas/tree/master/examples/mongodbatlas_encryption_at_rest_private_endpoint/azure) for detailed steps and considerations. + +{{ tffile (printf "examples/%s/azure/main.tf" .Name )}} + +{{ .SchemaMarkdown | trimspace }} + +# Import +Encryption At Rest Private Endpoint resource can be imported using the project ID, cloud provider, and private endpoint ID. The format must be `{project_id}-{cloud_provider}-{private_endpoint_id}` e.g. + +``` +$ terraform import mongodbatlas_encryption_at_rest_private_endpoint.test 650972848269185c55f40ca1-AZURE-650972848269185c55f40ca2 +``` + +For more information see: +- [MongoDB Atlas API - Private Endpoint for Encryption at Rest Using Customer Key Management](https://www.mongodb.com/docs/atlas/reference/api-resources-spec/v2/#tag/Encryption-at-Rest-using-Customer-Key-Management/operation/getEncryptionAtRestPrivateEndpoint) Documentation. +- [Manage Customer Keys with Azure Key Vault Over Private Endpoints](https://www.mongodb.com/docs/atlas/security/azure-kms-over-private-endpoint/).