Skip to content

Commit

Permalink
cmk import (#751)
Browse files Browse the repository at this point in the history
  • Loading branch information
artem-lifshits authored Nov 13, 2024
1 parent 960efd8 commit d0db3ff
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 0 deletions.
66 changes: 66 additions & 0 deletions acceptance/openstack/kms/v1/keys_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package v1

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"regexp"
"testing"

"github.com/opentelekomcloud/gophertelekomcloud/acceptance/clients"
Expand Down Expand Up @@ -84,3 +89,64 @@ func TestKmsEncryptDataLifecycle(t *testing.T) {

tools.PrintResource(t, kmsDecrypt)
}

// Test requries an external kms key in `pending import` state
// and can't be run more than once for the key or an error will occur:
// `The plain key value must be same with imported before when try to re-import a deleted key material`
func TestKmsCMKImportLifecycle(t *testing.T) {
kmsID := clients.EnvOS.GetEnv("KMS_ID")
if kmsID == "" {
t.Skip("OS_KMS_ID env var is missing but KMSv1 grant test requires")
}

client, err := clients.NewKMSV1Client()
th.AssertNoErr(t, err)

getOpts := keys.GetCMKImportOpts{
KeyId: kmsID,
WrappingAlgorithm: "RSAES_PKCS1_V1_5",
}

getResp, err := keys.GetCMKImport(client, getOpts)
th.AssertNoErr(t, err)

publicKeyBytes, err := base64.StdEncoding.DecodeString(getResp.PublicKey)
th.AssertNoErr(t, err)

pubKey, err := x509.ParsePKIXPublicKey(publicKeyBytes)
th.AssertNoErr(t, err)

rsaPublicKey, ok := pubKey.(*rsa.PublicKey)
th.AssertEquals(t, ok, true)

keyMaterial := make([]byte, 32)
_, err = rand.Read(keyMaterial)
th.AssertNoErr(t, err)

encryptedKeyMaterial, err := rsa.EncryptPKCS1v15(
rand.Reader,
rsaPublicKey,
keyMaterial,
)
th.AssertNoErr(t, err)

publicMaterial := base64.StdEncoding.EncodeToString(encryptedKeyMaterial)

matched, err := regexp.MatchString("^[0-9a-zA-Z+/=]{344,360}$", publicMaterial)
th.AssertNoErr(t, err)
th.AssertEquals(t, matched, true)

kmsOpts := keys.ImportCMKOpts{
KeyId: kmsID,
ImportToken: getResp.ImportToken,
EncryptedKeyMaterial: publicMaterial,
}

err = keys.ImportCMKMaterial(client, kmsOpts)
th.AssertNoErr(t, err)

err = keys.DeleteCMKImport(client, keys.DeleteCMKImportOpts{
KeyId: kmsID,
})
th.AssertNoErr(t, err)
}
2 changes: 2 additions & 0 deletions openstack/kms/v1/keys/Create.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ type CreateOpts struct {
Realm string `json:"realm,omitempty"`
// Purpose of a CMK (The default value is Encrypt_Decrypt)
KeyUsage string `json:"key_usage,omitempty"`
// Origin of a CMK. The default value is kms. Possible values: `kms` / `external`
Origin string `json:"origin,omitempty"`
}

func Create(client *golangsdk.ServiceClient, opts CreateOpts) (*Key, error) {
Expand Down
23 changes: 23 additions & 0 deletions openstack/kms/v1/keys/DeleteCMKImport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package keys

import (
golangsdk "github.com/opentelekomcloud/gophertelekomcloud"
"github.com/opentelekomcloud/gophertelekomcloud/internal/build"
)

type DeleteCMKImportOpts struct {
KeyId string `json:"key_id" required:"true"`
Sequence string `json:"sequence,omitempty"`
}

func DeleteCMKImport(client *golangsdk.ServiceClient, opts DeleteCMKImportOpts) error {
b, err := build.RequestBody(opts, "")
if err != nil {
return err
}

_, err = client.Post(client.ServiceURL("kms", "delete-imported-key-material"), b, nil, &golangsdk.RequestOpts{
OkCodes: []int{200},
})
return err
}
39 changes: 39 additions & 0 deletions openstack/kms/v1/keys/GetCMKImport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package keys

import (
golangsdk "github.com/opentelekomcloud/gophertelekomcloud"
"github.com/opentelekomcloud/gophertelekomcloud/internal/build"
"github.com/opentelekomcloud/gophertelekomcloud/internal/extract"
)

type GetCMKImportOpts struct {
KeyId string `json:"key_id" required:"true"`
WrappingAlgorithm string `json:"wrapping_algorithm" required:"true"`
Sequence string `json:"sequence,omitempty"`
}

func GetCMKImport(client *golangsdk.ServiceClient, opts GetCMKImportOpts) (*CMKImport, error) {
b, err := build.RequestBody(opts, "")
if err != nil {
return nil, err
}

raw, err := client.Post(client.ServiceURL("kms", "get-parameters-for-import"), &b, nil, &golangsdk.RequestOpts{
OkCodes: []int{200},
})
if err != nil {
return nil, err
}

var res CMKImport

err = extract.Into(raw.Body, &res)
return &res, err
}

type CMKImport struct {
KeyId string `json:"key_id"`
ImportToken string `json:"import_token"`
ExpirationTime int `json:"expiration_time"`
PublicKey string `json:"public_key"`
}
27 changes: 27 additions & 0 deletions openstack/kms/v1/keys/ImportCMKMaterial.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package keys

import (
golangsdk "github.com/opentelekomcloud/gophertelekomcloud"
"github.com/opentelekomcloud/gophertelekomcloud/internal/build"
)

type ImportCMKOpts struct {
KeyId string `json:"key_id" required:"true"`
ImportToken string `json:"import_token" required:"true"`
EncryptedKeyMaterial string `json:"encrypted_key_material" required:"true"`
ExpirationTime string `json:"expiration_time,omitempty"`
Sequence string `json:"sequence,omitempty"`
}

func ImportCMKMaterial(client *golangsdk.ServiceClient, opts ImportCMKOpts) error {
b, err := build.RequestBody(opts, "")
if err != nil {
return err
}

_, err = client.Post(client.ServiceURL("kms", "import-key-material"), b, nil, &golangsdk.RequestOpts{
OkCodes: []int{200},
})

return err
}

0 comments on commit d0db3ff

Please sign in to comment.