Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for OCI key manager #4

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
3 changes: 2 additions & 1 deletion config/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func DefaultConfig() *Configuration {
ServerPort: viper.GetString(VaultServerPort),
ClientToken: viper.GetString(VaultClientToken),
}
} else {
} else if strings.ToLower(cfg.KeyManager) == constant.KmipKeyManager {
cfg.Kmip = KmipConfig{
Version: viper.GetString(KmipVersion),
ServerIP: viper.GetString(KmipServerIP),
Expand All @@ -72,5 +72,6 @@ func DefaultConfig() *Configuration {
RootCertificateFilePath: viper.GetString(KmipRootCertPath),
}
}
// Currently we do nothing special for OCI config.
return cfg
}
1 change: 1 addition & 0 deletions constant/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const (

// kmipmanager constants
KmipKeyManager = "kmip"
OCIKeyManager = "oci"
VaultKeyManager = "vault"
DefaultVaultPort = 8200

Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/hashicorp/vault/api v1.10.0
github.com/intel/trustauthority-client v1.1.0
github.com/onsi/gomega v1.27.10
github.com/oracle/oci-go-sdk/v65 v65.70.0
github.com/pkg/errors v0.9.1
github.com/shaj13/go-guardian/v2 v2.11.6
github.com/shaj13/libcache v1.2.1
Expand All @@ -38,6 +39,7 @@ require (
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-test/deep v1.1.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
Expand Down Expand Up @@ -67,6 +69,7 @@ require (
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/sony/gobreaker v0.5.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,8 @@ github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
Expand Down Expand Up @@ -738,6 +740,8 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/oracle/oci-go-sdk/v65 v65.70.0 h1:gLa0IX/SidTm60VbHabnImrW3hyymmNLQJy6gZGrgDA=
github.com/oracle/oci-go-sdk/v65 v65.70.0/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0=
github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
Expand Down Expand Up @@ -772,6 +776,8 @@ github.com/shaj13/libcache v1.2.1 h1:ET4FBxwUJhNVDD/EMOUIG97AQVktlkc//SPAga5JF4c
github.com/shaj13/libcache v1.2.1/go.mod h1:YCq92Zosqj4erhlLdm2Mu1cX2FDAxjfFOxTphzN7S9U=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg=
github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
Expand Down
8 changes: 8 additions & 0 deletions keymanager/key_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package keymanager

import (
"intel/kbs/v1/ociclient"
"intel/kbs/v1/vaultclient"
"strings"

Expand All @@ -27,6 +28,13 @@ func NewKeyManager(cfg *config.Configuration) (KeyManager, error) {
return nil, errors.Wrap(err, "Failed to initialize KmipManager")
}
return NewKmipManager(kmipClient), nil
} else if strings.ToLower(cfg.KeyManager) == constant.OCIKeyManager {
ociClient := ociclient.NewOCIClient()
err := ociClient.InitializeClient()
if err != nil {
return nil, errors.Wrap(err, "keymanager/key_manager:NewKeyManager() Failed to initialize OCI client")
}
return NewOCIManager(ociClient), nil
} else if strings.ToLower(cfg.KeyManager) == constant.VaultKeyManager {
vaultClient := vaultclient.NewVaultClient()
err := vaultClient.InitializeClient(cfg.Vault.ServerIP, cfg.Vault.ServerPort, cfg.Vault.ClientToken)
Expand Down
103 changes: 103 additions & 0 deletions keymanager/oci_key_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2024 Oracle Corporation
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/

package keymanager

import (
"intel/kbs/v1/model"
"intel/kbs/v1/ociclient"
"time"

"github.com/google/uuid"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)

type OCIManager struct {
client ociclient.OCIClient
}

func NewOCIManager(c ociclient.OCIClient) *OCIManager {
return &OCIManager{c}
}

func (om *OCIManager) CreateKey(keyRequest *model.KeyRequest) (*model.KeyAttributes, error) {
if keyRequest.KeyInfo.OciCompartmentId == "" || keyRequest.KeyInfo.OciKeyId == "" ||
keyRequest.KeyInfo.OciSecretName == "" || keyRequest.KeyInfo.OciVaultId == "" {
return nil, errors.New("Missing oci_compartment_id, oci_key_id, oci_secret_name, or oci_vault_id")
}

newUuid, err := uuid.NewRandom()
if err != nil {
return nil, errors.Wrap(err, "failed to create new UUID")
}
keyAttributes := &model.KeyAttributes{
ID: newUuid,
Algorithm: keyRequest.KeyInfo.Algorithm,
KeyLength: keyRequest.KeyInfo.KeyLength,
OciCompartmentId: keyRequest.KeyInfo.OciCompartmentId,
OciKeyId: keyRequest.KeyInfo.OciKeyId,
OciSecretName: keyRequest.KeyInfo.OciSecretName,
OciVaultId: keyRequest.KeyInfo.OciVaultId,
TransferPolicyId: keyRequest.TransferPolicyID,
CreatedAt: time.Now().UTC(),
}

log.Infof("OCI: Creating key: algorithm = %q; secret name = %q", keyAttributes.Algorithm, keyAttributes.OciSecretName)

if err := om.client.CreateKey(keyAttributes); err != nil {
return nil, errors.Wrap(err, "failed to create key")
}

return keyAttributes, nil
}

func (om *OCIManager) DeleteKey(keyAttributes *model.KeyAttributes) error {
err := om.client.DeleteKey(keyAttributes.OciSecretId)
if err != nil {
log.Errorf("Error while deleting key: %s", err.Error())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use errors.wrap() for consistency.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to re-consider the usage of github.com/pkg/errors since it's archived and not maintained. In general, projects are trying to move away from it and use error wrapping from the std library.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update it to errors.Wrap() for now. I was just copying the code from vault_key_manager.go:DeleteKey(). If we want to move the std library implementation, I would suggest doing that as a separate patch(set) that updates error usage everywhere.

I'm also not 100% sure what wrapping from the std library you want to do -- I don't see an errors.Wrap() function there. Do you mean using fmt.Errorf() or errors.Join()?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking%w with err

return err
}

log.Infof("OCI: Deleting key: algorithm = %q; secret id = %q", keyAttributes.Algorithm, keyAttributes.OciSecretId)

return nil
}

func (om *OCIManager) RegisterKey(keyRequest *model.KeyRequest) (*model.KeyAttributes, error) {
if keyRequest.KeyInfo.OciSecretId == "" {
return nil, errors.New("oci_secret_id cannot be empty for register operation in OCI mode")
}

newUuid, err := uuid.NewRandom()
if err != nil {
return nil, errors.Wrap(err, "failed to create new UUID")
}
keyAttributes := &model.KeyAttributes{
ID: newUuid,
Algorithm: keyRequest.KeyInfo.Algorithm,
KeyLength: keyRequest.KeyInfo.KeyLength,
OciSecretId: keyRequest.KeyInfo.OciSecretId,
TransferPolicyId: keyRequest.TransferPolicyID,
CreatedAt: time.Now().UTC(),
}

log.Infof("OCI: Registering key: algorithm = %q; secret id = %q", keyAttributes.Algorithm, keyAttributes.OciSecretId)

return keyAttributes, nil
}

func (om *OCIManager) TransferKey(keyAttributes *model.KeyAttributes) ([]byte, error) {
if keyAttributes.OciSecretId == "" {
return nil, errors.New("key is not created with OCI key manager")
}

secretVersionNumber := int64(0)

log.Infof("OCI: Transferring key: secret id = %q; secret version = %d", keyAttributes.OciSecretId, secretVersionNumber)

return om.client.GetKey(keyAttributes.OciSecretId, secretVersionNumber)
}
15 changes: 15 additions & 0 deletions model/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,21 @@ type KeyInfo struct {
// KMIP Key ID, if the key is already created in KMIP Backend
// example: 7110194b-a703-4657-9d7f-3e02b62f2ed8
KmipKeyID string `json:"kmip_key_id,omitempty"`
// The OCID of the compartment where you want to create the secret.
// example: ocid1.test.oc1..<unique_ID>EXAMPLE-compartmentId-Value
OciCompartmentId string `json:"oci_compartment_id,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to return all these fields in response? if not, then we can keep these in separate struct.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's what I was thinking too. I just did this for now since the Vault and KMIP stuff was also all mixed in there. If we want to separate them out, then I can do a patch that first pulls out the Vault and KMIP stuff into separate structs, then change this patch to also be in a separate struct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we only have KmipKeyID field for KMIP which is needed in both request and response (none specific to vault), hence kept KmipKeyID in KeyInfo struct which is shared between request and response. If the OCI fields also need to be kept in both request and response, then we can leave them in KeyInfo struct.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While separating out the OCI stuff, I was going over the other code. Both KeyData and KmipKeyID are actually both only used with KeyRequest as well. They are also in the KeyAttributes struct. Is the intent is that KeyAttributes and KeyInfo should roughly match?

If so, one option for the OCI code is to just put OciSecretId in KeyInfo and KeyAttributes, as that's the only one needed in both. Then I can put the rest of the OCI fields into their own struct and just include that in the KeyRequest struct

// The OCID of the master encryption key that is used to encrypt the secret.
// example: ocid1.test.oc1..<unique_ID>EXAMPLE-keyId-Value
OciKeyId string `json:"oci_key_id,omitempty"`
// OCI Secret ID, if the key is already created in OCI backend
// example: ocid1.test.oc1..<unique_ID>EXAMPLE-secretId-Value
OciSecretId string `json:"oci_secret_id,omitempty"`
// A user-friendly name for the secret.
// example: EXAMPLE-secretName-Value
OciSecretName string `json:"oci_secret_name,omitempty"`
// The OCID of the vault where you want to create the secret.
// example: ocid1.test.oc1..<unique_ID>EXAMPLE-vaultId-Value
OciVaultId string `json:"oci_vault_id,omitempty"`
}

type KeyFilterCriteria struct {
Expand Down
5 changes: 5 additions & 0 deletions model/key_attributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ type KeyAttributes struct {
TransferPolicyId uuid.UUID `json:"transfer_policy_id,omitempty"`
TransferLink string `json:"transfer_link,omitempty"`
CreatedAt time.Time `json:"created_at,omitempty"`
OciCompartmentId string `json:"oci_compartment_id,omitempty"`
OciKeyId string `json:"oci_key_id,omitempty"`
OciSecretName string `json:"oci_secret_name,omitempty"`
OciSecretId string `json:"oci_secret_id,omitempty"`
OciVaultId string `json:"oci_vault_id,omitempty"`
}

func (ka *KeyAttributes) ToKeyResponse() *KeyResponse {
Expand Down
47 changes: 47 additions & 0 deletions ociclient/mock_ociclient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2024 Oracle Corporation
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/

package ociclient

import (
"intel/kbs/v1/model"

"github.com/stretchr/testify/mock"
)

// MockOCIClient is a mock of OCIClient interface
type MockOCIClient struct {
mock.Mock
}

// NewMockOCIClient creates a new mock instance
func NewMockOCIClient() *MockOCIClient {
return &MockOCIClient{}
}

// InitializeClient mocks base method
func (m *MockOCIClient) InitializeClient(serverIP, serverPort, clientToken string) error {
args := m.Called(serverIP, serverPort, clientToken)
return args.Error(0)
}

// CreateKey mocks base method
func (m *MockOCIClient) CreateKey(keyAttrib *model.KeyAttributes) error {
args := m.Called(keyAttrib)
return args.Error(0)
}

// DeleteKey mocks base method
func (m *MockOCIClient) DeleteKey(id string) error {
args := m.Called(id)
return args.Error(0)
}

// GetKey mocks base method
func (m *MockOCIClient) GetKey(id string) ([]byte, error) {
args := m.Called(id)
return args.Get(0).([]byte), args.Error(1)
}
Loading
Loading