FlexibleEngineCloud/terraform-provider-flexibleengine

Missing kms_key_project_id option for flexibleengine_obs_bucket resource

Closed this issue · 0 comments

Hello there,

We have a specific usecase with OBS, that is currently not working with the terraform provider:

  • KMS key is provisioned with terraform in an IAM project (let's say eu-west-0_proj_name)
  • OBS bucket is provisioned with terraform
  • Bucket is encrypted with the above mentioned KMS key
  • IAM user is provisioned with terraform
  • IAM policies are configured to give the user access to the bucket and KMS

Currently this is not working, because we can't set kms_key_project_id for the bucket, which seems to be required. I have built the provider with a following patch, which have solved our issues (it is loosely based on the implementation in huaweicloud provider).

diff --git a/flexibleengine/resource_flexibleengine_obs_bucket.go b/flexibleengine/resource_flexibleengine_obs_bucket.go
index 4dda4487..a9ebc655 100644
--- a/flexibleengine/resource_flexibleengine_obs_bucket.go
+++ b/flexibleengine/resource_flexibleengine_obs_bucket.go
@@ -239,6 +239,11 @@ func resourceObsBucket() *schema.Resource {
                                Type:     schema.TypeString,
                                Optional: true,
                        },
+                       "kms_key_project_id": {
+                               Type:     schema.TypeString,
+                               Optional: true,
+                               Computed: true,
+                       },
                        "multi_az": {
                                Type:     schema.TypeBool,
                                Optional: true,
@@ -318,7 +323,7 @@ func resourceObsBucketUpdate(d *schema.ResourceData, meta interface{}) error {
                }
        }

-       if d.HasChanges("encryption", "kms_key_id") {
+       if d.HasChanges("encryption", "kms_key_id", "kms_key_project_id") {
                if err := resourceObsBucketEncryptionUpdate(obsClient, d); err != nil {
                        return err
                }
@@ -567,6 +572,7 @@ func resourceObsBucketEncryptionUpdate(obsClient *obs.ObsClient, d *schema.Resou
                input.Bucket = bucket
                input.SSEAlgorithm = obs.DEFAULT_SSE_KMS_ENCRYPTION
                input.KMSMasterKeyID = d.Get("kms_key_id").(string)
+               input.ProjectID = d.Get("kms_key_project_id").(string)

                log.Printf("[DEBUG] enable default encryption of OBS bucket %s: %#v", bucket, input)
                _, err := obsClient.SetBucketEncryption(input)
@@ -905,6 +911,7 @@ func setObsBucketEncryption(obsClient *obs.ObsClient, d *schema.ResourceData) er
                        if obsError.Code == "NoSuchEncryptionConfiguration" || obsError.Code == "FsNotSupport" {
                                d.Set("encryption", false)
                                d.Set("kms_key_id", nil)
+                               d.Set("kms_key_project_id", nil)
                                return nil
                        }
                        return fmt.Errorf("Error getting encryption configuration of OBS bucket %s: %s,\n Reason: %s",
@@ -916,9 +923,11 @@ func setObsBucketEncryption(obsClient *obs.ObsClient, d *schema.ResourceData) er
        if output.SSEAlgorithm != "" {
                d.Set("encryption", true)
                d.Set("kms_key_id", output.KMSMasterKeyID)
+               d.Set("kms_key_project_id", output.ProjectID)
        } else {
                d.Set("encryption", false)
                d.Set("kms_key_id", nil)
+               d.Set("kms_key_project_id", nil)
        }

        return nil

Terraform Version

$ terraform -version
Terraform v1.6.4-dev
on linux_amd64
+ provider registry.terraform.io/flexibleenginecloud/flexibleengine v1.45.0

Affected Resource(s)

Please list the resources as a list, for example:

  • flexibleengine_obs_bucket

Terraform Configuration Files

Resources
provider "flexibleengine" {
}

data "flexibleengine_identity_projects" "current" {
  name = "eu-west-0_proj_name"
}

data "flexibleengine_identity_projects" "obs" {
  name = "MOS" // The project for OBS Billing
}

data "flexibleengine_identity_group" "admins" {
  name = "admin"
}

resource "flexibleengine_kms_key_v1" "mm-key-test" {
  key_alias    = "mm-key-test2"
  pending_days = "7"
  realm        = "eu-west-0"
  is_enabled   = true
}

resource "flexibleengine_kms_grant" "mm-key" {
  for_each = toset(data.flexibleengine_identity_group.admins.users[*].id)

  key_id            = flexibleengine_kms_key_v1.mm-key-test.id
  type              = "user"
  grantee_principal = each.value
  operations        = ["describe-key"]
}

resource "flexibleengine_obs_bucket" "mm-test" {
  bucket             = "mm-test-tf"
  acl                = "private"
  storage_class      = "STANDARD"
  encryption         = true
  kms_key_id         = flexibleengine_kms_key_v1.mm-key-test.id
  kms_key_project_id = data.flexibleengine_identity_projects.current.projects[0].id
}

resource "flexibleengine_identity_user_v3" "bucket-user" {
  name        = "mm-test-tf"
}

resource "flexibleengine_identity_role_v3" "bucket-role" {
  name        = "mm-test-tf"
  description = "TF provisioned role"
  type        = "AX"

  policy = <<EOF
{
  "Version": "1.1",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "obs:bucket:HeadBucket",
        "obs:bucket:ListBucket",
        "obs:object:DeleteObject",
        "obs:object:ModifyObjectMetaData",
        "obs:object:GetObject",
        "obs:object:PutObject"
      ],
      "Resource": ["OBS:*:*:bucket:mm-test-tf", "OBS:*:*:object:mm-test-tf/*"]
    },
    {
      "Effect": "Allow",
      "Action": ["obs:bucket:ListAllMyBuckets"]
    }
  ]
}
EOF
}

resource "flexibleengine_identity_role_v3" "bucket-kms-role" {
  name        = "mm-test-tf-kms"
  description = "TF provisioned role"
  type        = "AX"

  policy = <<EOF
{
  "Version": "1.1",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "kms:dek:crypto",
        "kms:cmk:list",
        "kms:dek:create",
        "kms:cmkTag:listInstance",
        "kms:cmk:get",
        "kms:cmk:getRotation",
        "kms:cmk:crypto",
        "kms:cmkTag:list",
        "kms:cmk:getMaterial",
        "kms:dek:encrypt",
        "kms:cmk:encrypt",
        "kms:dek:decrypt",
        "kms:cmk:getInstance",
        "kms:cmk:decrypt",
        "kms:grant:list",
        "kms:cmk:getQuota"
      ]
    }
  ]
}
EOF
}

resource "flexibleengine_identity_group_v3" "bucket-group" {
  name = "mm-test-tf"
}

resource "flexibleengine_identity_role_assignment_v3" "assignment-bucket" {
  group_id   = flexibleengine_identity_group_v3.bucket-group.id
  role_id    = flexibleengine_identity_role_v3.bucket-role.id
  project_id = data.flexibleengine_identity_projects.obs.projects[0].id
}

resource "flexibleengine_identity_role_assignment_v3" "assignment-kms" {
  group_id   = flexibleengine_identity_group_v3.bucket-group.id
  role_id    = flexibleengine_identity_role_v3.bucket-kms-role.id
  project_id = data.flexibleengine_identity_projects.current.projects[0].id
}

resource "flexibleengine_identity_group_membership_v3" "bucket-membership" {
  group = flexibleengine_identity_group_v3.bucket-group.id
  users = [
    flexibleengine_identity_user_v3.bucket-user.id
  ]
}

Expected Behavior

IAM user should be able to download/upload files to a bucket with SSE enabled.

Actual Behavior

IAM user is getting No privilege to this kms operation error upon object upload/download.

Steps to Reproduce

Please list the steps required to reproduce the issue, for example:

  • Apply resources defined in previous section
  • Create AK/SK credentials for the user provisioned by terraform
  • Configure your favourite s3 client (I have used mc aka minio client)
  • Upload a file to the bucket