diff --git a/docs/resources/csms_secret_version_state.md b/docs/resources/csms_secret_version_state.md
new file mode 100644
index 0000000000..d4fa06dc3a
--- /dev/null
+++ b/docs/resources/csms_secret_version_state.md
@@ -0,0 +1,64 @@
+---
+subcategory: "Data Encryption Workshop (DEW)"
+layout: "huaweicloud"
+page_title: "HuaweiCloud: huaweicloud_csms_secret_version_state"
+description: |
+ Manages a CSMS secret version state resource within HuaweiCloud.
+---
+
+# huaweicloud_csms_secret_version_state
+
+Manages a CSMS secret version state resource within HuaweiCloud.
+
+-> A secret supports a maximum of `12` secret version states, each secret version state can identify only one
+ secret version.
+
If you add a secret version state in use to a new secret version, the secret version state will be
+ automatically removed from the old secret version.
+
**SYSCURRENT** and **SYSPREVIOUS** are built-in states, not support deletion.
+
+## Example Usage
+
+```hcl
+variable "secret_name" {}
+variable "name" {}
+variable "version_id" {}
+
+resource "huaweicloud_csms_secret_version_state" "test" {
+ secret_name = var.secret_name
+ name = var.name
+ version_id = var.version_id
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `region` - (Optional, String, ForceNew) Specifies the region in which to create the CSMS secret version state.
+ If omitted, the provider-level region will be used. Changing this parameter will create a new resource.
+
+* `secret_name` - (Required, String, ForceNew) Specifies the name of the secret to which the secret version state
+ belongs. Changing this parameter will create a new resource.
+
+* `name` - (Required, String, ForceNew) Specifies the name of the secret version state.
+ Changing this parameter will create a new secret version.
+ Only letters, digits, underscores(_) and hyphens(-) are allowed.
+ The valid length is limited from `1` to `64` characters.
+
+* `version_id` - (Required, String) Specifies the ID of the secret version.
+
+## Attribute Reference
+
+In addition to all arguments above, the following attributes are exported:
+
+* `id` - The resource ID, same as `name`.
+
+* `updated_at` - The last update time of the secret version state, in RFC3339 format.
+
+## Import
+
+The secret version state can be imported using the related `secret_name` and their `id`, separated by a slash (/), e.g.
+
+```bash
+terraform import huaweicloud_csms_secret_version_state.test /
+```
diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go
index 1b3b8c6f99..3bfbc36eb5 100644
--- a/huaweicloud/provider.go
+++ b/huaweicloud/provider.go
@@ -1288,8 +1288,9 @@ func Provider() *schema.Provider {
"huaweicloud_cse_microservice_engine": cse.ResourceMicroserviceEngine(),
"huaweicloud_cse_microservice_instance": cse.ResourceMicroserviceInstance(),
- "huaweicloud_csms_event": dew.ResourceCsmsEvent(),
- "huaweicloud_csms_secret": dew.ResourceSecret(),
+ "huaweicloud_csms_event": dew.ResourceCsmsEvent(),
+ "huaweicloud_csms_secret": dew.ResourceSecret(),
+ "huaweicloud_csms_secret_version_state": dew.ResourceSecretVersionState(),
"huaweicloud_css_cluster": css.ResourceCssCluster(),
"huaweicloud_css_cluster_restart": css.ResourceCssClusterRestart(),
diff --git a/huaweicloud/services/acceptance/dew/resource_huaweicloud_csms_secret_version_state_test.go b/huaweicloud/services/acceptance/dew/resource_huaweicloud_csms_secret_version_state_test.go
new file mode 100644
index 0000000000..d665b0fd34
--- /dev/null
+++ b/huaweicloud/services/acceptance/dew/resource_huaweicloud_csms_secret_version_state_test.go
@@ -0,0 +1,143 @@
+package dew
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
+
+ "github.com/chnsz/golangsdk"
+
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config"
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance"
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils"
+)
+
+func getSecretVersionStateResourceFunc(cfg *config.Config, state *terraform.ResourceState) (interface{}, error) {
+ var (
+ region = acceptance.HW_REGION_NAME
+ getVersionStatehttpUrl = "v1/{project_id}/secrets/{secret_name}/stages/{stage_name}"
+ product = "kms"
+ )
+ client, err := cfg.NewServiceClient(product, region)
+ if err != nil {
+ return nil, fmt.Errorf("error creating KMS client: %s", err)
+ }
+
+ getVersionStatePath := client.Endpoint + getVersionStatehttpUrl
+ getVersionStatePath = strings.ReplaceAll(getVersionStatePath, "{project_id}", client.ProjectID)
+ getVersionStatePath = strings.ReplaceAll(getVersionStatePath, "{secret_name}", state.Primary.Attributes["secret_name"])
+ getVersionStatePath = strings.ReplaceAll(getVersionStatePath, "{stage_name}", state.Primary.ID)
+ getVersionStateOpt := golangsdk.RequestOpts{
+ KeepResponseBody: true,
+ }
+
+ getResp, err := client.Request("GET", getVersionStatePath, &getVersionStateOpt)
+ if err != nil {
+ return nil, fmt.Errorf("error retrieving secret version state: %s", err)
+ }
+ return utils.FlattenResponse(getResp)
+}
+
+func TestAccSecretVersionState_basic(t *testing.T) {
+ var obj interface{}
+
+ name := acceptance.RandomAccResourceName()
+ rName := "huaweicloud_csms_secret_version_state.test"
+
+ rc := acceptance.InitResourceCheck(
+ rName,
+ &obj,
+ getSecretVersionStateResourceFunc,
+ )
+
+ resource.ParallelTest(t, resource.TestCase{
+ PreCheck: func() {
+ acceptance.TestAccPreCheck(t)
+ },
+ ProviderFactories: acceptance.TestAccProviderFactories,
+ CheckDestroy: rc.CheckResourceDestroy(),
+ Steps: []resource.TestStep{
+ {
+ Config: testAccSecretVersionState_basic(name),
+ Check: resource.ComposeTestCheckFunc(
+ rc.CheckResourceExists(),
+ resource.TestCheckResourceAttrPair(rName, "secret_name", "huaweicloud_csms_secret.test", "name"),
+ resource.TestCheckResourceAttr(rName, "name", name),
+ resource.TestCheckResourceAttrPair(rName, "version_id", "huaweicloud_csms_secret.test", "latest_version"),
+ resource.TestMatchResourceAttr(rName, "updated_at",
+ regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}?(Z|([+-]\d{2}:\d{2}))$`)),
+ ),
+ },
+ {
+ Config: testAccSecretVersionState_update(name),
+ Check: resource.ComposeTestCheckFunc(
+ rc.CheckResourceExists(),
+ resource.TestCheckResourceAttr(rName, "version_id", "v2"),
+ resource.TestCheckResourceAttr(rName, "name", name),
+ resource.TestMatchResourceAttr(rName, "updated_at",
+ regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}?(Z|([+-]\d{2}:\d{2}))$`)),
+ ),
+ },
+ {
+ ResourceName: rName,
+ ImportState: true,
+ ImportStateVerify: true,
+ ImportStateIdFunc: testAccSecretVersionStateImportStateFunc(rName),
+ },
+ },
+ })
+}
+
+func testAccSecretVersionStateImportStateFunc(name string) resource.ImportStateIdFunc {
+ return func(s *terraform.State) (string, error) {
+ var secretName, stateId string
+ rs, ok := s.RootModule().Resources[name]
+ if !ok {
+ return "", fmt.Errorf("the resource (%s) not found", name)
+ }
+
+ secretName = rs.Primary.Attributes["secret_name"]
+ stateId = rs.Primary.ID
+ if secretName == "" || stateId == "" {
+ return "", fmt.Errorf("invalid format specified for import ID, want '/', but got '%s/%s'",
+ secretName, stateId)
+ }
+ return fmt.Sprintf("%s/%s", secretName, stateId), nil
+ }
+}
+
+func testAccSecretVersionState_basic(name string) string {
+ return fmt.Sprintf(`
+resource "huaweicloud_csms_secret" "test" {
+ name = "%[1]s"
+ secret_text = "secret version"
+ description = "acc test"
+}
+
+resource "huaweicloud_csms_secret_version_state" "test" {
+ secret_name = huaweicloud_csms_secret.test.name
+ name = "%[1]s"
+ version_id = huaweicloud_csms_secret.test.latest_version
+}
+`, name)
+}
+
+func testAccSecretVersionState_update(name string) string {
+ return fmt.Sprintf(`
+resource "huaweicloud_csms_secret" "test" {
+ name = "%[1]s"
+ secret_text = "version state"
+ description = "acc test"
+}
+
+resource "huaweicloud_csms_secret_version_state" "test" {
+ secret_name = huaweicloud_csms_secret.test.name
+ name = "%[1]s"
+ version_id = "v2"
+}
+`, name)
+}
diff --git a/huaweicloud/services/dew/resource_huaweicloud_csms_secret_version_state.go b/huaweicloud/services/dew/resource_huaweicloud_csms_secret_version_state.go
new file mode 100644
index 0000000000..777e51505d
--- /dev/null
+++ b/huaweicloud/services/dew/resource_huaweicloud_csms_secret_version_state.go
@@ -0,0 +1,241 @@
+package dew
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/hashicorp/go-multierror"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+
+ "github.com/chnsz/golangsdk"
+
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/common"
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config"
+ "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils"
+)
+
+// @API DEW PUT /v1/{project_id}/secrets/{secret_name}/stages/{stage_name}
+// @API DEW GET /v1/{project_id}/secrets/{secret_name}/stages/{stage_name}
+// @API DEW DELETE /v1/{project_id}/secrets/{secret_name}/stages/{stage_name}
+func ResourceSecretVersionState() *schema.Resource {
+ return &schema.Resource{
+ CreateContext: resourceSecretVersionStateCreate,
+ ReadContext: resourceSecretVersionStateRead,
+ UpdateContext: resourceSecretVersionStateUpdate,
+ DeleteContext: resourceSecretVersionStateDelete,
+
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceSecretVersionStateImportState,
+ },
+
+ Schema: map[string]*schema.Schema{
+ "region": {
+ Type: schema.TypeString,
+ Optional: true,
+ ForceNew: true,
+ },
+ "secret_name": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ },
+ "name": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ },
+ "version_id": {
+ Type: schema.TypeString,
+ Required: true,
+ },
+ "updated_at": {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ },
+ }
+}
+
+func resourceSecretVersionStateCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ var (
+ cfg = meta.(*config.Config)
+ region = cfg.GetRegion(d)
+ createVersionStateHttpUrl = "v1/{project_id}/secrets/{secret_name}/stages/{stage_name}"
+ product = "kms"
+ )
+ client, err := cfg.NewServiceClient(product, region)
+ if err != nil {
+ return diag.Errorf("error creating KMS client: %s", err)
+ }
+
+ createVersionStatePath := client.Endpoint + createVersionStateHttpUrl
+ createVersionStatePath = strings.ReplaceAll(createVersionStatePath, "{project_id}", client.ProjectID)
+ createVersionStatePath = strings.ReplaceAll(createVersionStatePath, "{secret_name}", d.Get("secret_name").(string))
+ createVersionStatePath = strings.ReplaceAll(createVersionStatePath, "{stage_name}", d.Get("name").(string))
+
+ createVersionStateOpt := golangsdk.RequestOpts{
+ KeepResponseBody: true,
+ JSONBody: buildSecretVersionStateBodyParams(d),
+ }
+
+ creatVersionStateResp, err := client.Request("PUT", createVersionStatePath, &createVersionStateOpt)
+ if err != nil {
+ return diag.Errorf("error creating secret version state: %s", err)
+ }
+
+ createVersionStateRespBody, err := utils.FlattenResponse(creatVersionStateResp)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ stateName := utils.PathSearch("stage.name", createVersionStateRespBody, "").(string)
+ if stateName == "" {
+ return diag.Errorf("error creating secret version state: the name is not found in API response")
+ }
+ d.SetId(stateName)
+
+ return resourceSecretVersionStateRead(ctx, d, meta)
+}
+
+func buildSecretVersionStateBodyParams(d *schema.ResourceData) map[string]interface{} {
+ bodyParams := map[string]interface{}{
+ "version_id": d.Get("version_id"),
+ }
+ return bodyParams
+}
+
+func getVersionStateInfo(client *golangsdk.ServiceClient, d *schema.ResourceData) (*http.Response, error) {
+ getVersionStatehttpUrl := "v1/{project_id}/secrets/{secret_name}/stages/{stage_name}"
+ getVersionStatePath := client.Endpoint + getVersionStatehttpUrl
+ getVersionStatePath = strings.ReplaceAll(getVersionStatePath, "{project_id}", client.ProjectID)
+ getVersionStatePath = strings.ReplaceAll(getVersionStatePath, "{secret_name}", d.Get("secret_name").(string))
+ getVersionStatePath = strings.ReplaceAll(getVersionStatePath, "{stage_name}", d.Id())
+ getVersionStateOpt := golangsdk.RequestOpts{
+ KeepResponseBody: true,
+ }
+
+ return client.Request("GET", getVersionStatePath, &getVersionStateOpt)
+}
+
+func resourceSecretVersionStateRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ var (
+ cfg = meta.(*config.Config)
+ region = cfg.GetRegion(d)
+ mErr *multierror.Error
+ product = "kms"
+ )
+ client, err := cfg.NewServiceClient(product, region)
+ if err != nil {
+ return diag.Errorf("error creating KMS client: %s", err)
+ }
+
+ getVersionStateResp, err := getVersionStateInfo(client, d)
+ if err != nil {
+ return common.CheckDeletedDiag(d, err, "error retrieving secret version state")
+ }
+
+ getVersionStateRespBody, err := utils.FlattenResponse(getVersionStateResp)
+ if err != nil {
+ return diag.FromErr(err)
+ }
+
+ mErr = multierror.Append(
+ mErr,
+ d.Set("name", utils.PathSearch("stage.name", getVersionStateRespBody, nil)),
+ d.Set("secret_name", utils.PathSearch("stage.secret_name", getVersionStateRespBody, nil)),
+ d.Set("version_id", utils.PathSearch("stage.version_id", getVersionStateRespBody, nil)),
+ d.Set("updated_at", utils.FormatTimeStampRFC3339(
+ int64(utils.PathSearch("stage.update_time", getVersionStateRespBody, float64(0)).(float64))/1000, false)),
+ )
+
+ return diag.FromErr(mErr.ErrorOrNil())
+}
+
+func resourceSecretVersionStateUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ var (
+ cfg = meta.(*config.Config)
+ region = cfg.GetRegion(d)
+ updateVersionStateHttpUrl = "v1/{project_id}/secrets/{secret_name}/stages/{stage_name}"
+ product = "kms"
+ )
+ client, err := cfg.NewServiceClient(product, region)
+ if err != nil {
+ return diag.Errorf("error creating KMS client: %s", err)
+ }
+
+ updateVersionStatePath := client.Endpoint + updateVersionStateHttpUrl
+ updateVersionStatePath = strings.ReplaceAll(updateVersionStatePath, "{project_id}", client.ProjectID)
+ updateVersionStatePath = strings.ReplaceAll(updateVersionStatePath, "{secret_name}", d.Get("secret_name").(string))
+ updateVersionStatePath = strings.ReplaceAll(updateVersionStatePath, "{stage_name}", d.Id())
+ updateVersionStateOpt := golangsdk.RequestOpts{
+ KeepResponseBody: true,
+ JSONBody: buildSecretVersionStateBodyParams(d),
+ }
+
+ _, err = client.Request("PUT", updateVersionStatePath, &updateVersionStateOpt)
+ if err != nil {
+ return diag.Errorf("error updating secret version state: %s", err)
+ }
+
+ return resourceSecretVersionStateRead(ctx, d, meta)
+}
+
+func resourceSecretVersionStateDelete(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+ var (
+ cfg = meta.(*config.Config)
+ region = cfg.GetRegion(d)
+ deleteVersionStateHttpUrl = "v1/{project_id}/secrets/{secret_name}/stages/{stage_name}"
+ product = "kms"
+ )
+ client, err := cfg.NewServiceClient(product, region)
+ if err != nil {
+ return diag.Errorf("error creating KMS client: %s", err)
+ }
+
+ deleteVersionStatePath := client.Endpoint + deleteVersionStateHttpUrl
+ deleteVersionStatePath = strings.ReplaceAll(deleteVersionStatePath, "{project_id}", client.ProjectID)
+ deleteVersionStatePath = strings.ReplaceAll(deleteVersionStatePath, "{secret_name}", d.Get("secret_name").(string))
+ deleteVersionStatePath = strings.ReplaceAll(deleteVersionStatePath, "{stage_name}", d.Id())
+ deleteVersionStateOpt := golangsdk.RequestOpts{
+ KeepResponseBody: true,
+ OkCodes: []int{
+ 204,
+ },
+ }
+
+ // Before deleting, call the query details API, if query no result , then process `CheckDeleted` logic.
+ _, err = getVersionStateInfo(client, d)
+ if err != nil {
+ return common.CheckDeletedDiag(d, err, "error retrieving secret version state")
+ }
+
+ _, err = client.Request("DELETE", deleteVersionStatePath, &deleteVersionStateOpt)
+ if err != nil {
+ return diag.Errorf("error deleting secret version state: %s", err)
+ }
+
+ // Successful deletion API call does not guarantee that the resource is successfully deleted.
+ // Call the details API to confirm that the resource has been successfully deleted.
+ _, err = getVersionStateInfo(client, d)
+ if err == nil {
+ return diag.Errorf("error deleting secret version state: the version state still exists")
+ }
+
+ return nil
+}
+
+func resourceSecretVersionStateImportState(_ context.Context, d *schema.ResourceData, _ interface{}) ([]*schema.ResourceData, error) {
+ parts := strings.Split(d.Id(), "/")
+ if len(parts) != 2 {
+ return nil, fmt.Errorf("invalid format for import ID, want '/', but got '%s'", d.Id())
+ }
+
+ d.SetId(parts[1])
+ mErr := multierror.Append(nil,
+ d.Set("secret_name", parts[0]),
+ )
+ return []*schema.ResourceData{d}, mErr.ErrorOrNil()
+}