Skip to content

Commit

Permalink
feat(build): Add KMIP Management APIs to Go SDK (#122)
Browse files Browse the repository at this point in the history
* rename keyring path for conflicts

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* initial implementation of adapters and certs

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* add kmip objects, fix some stuff

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* fix structs

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* unit tests, and some fixes

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* remove import cycle

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* redo mocks

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* add mockauth

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* fix mobk paths

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* fix marshalling

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* fix delete tests

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* remove old kmip profile data

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* address PR comments

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* finish address comments

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* hardcode mock responses, refactor kmip collection metadata

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* fix tests?

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* fix typo

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* add object filter, overhaul list options

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* enhance tests

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* unexport path variables, add comments

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* sdk fixes

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* remove crk from adapter list

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* remove commented code

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

* fix tests from changes

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>

---------

Signed-off-by: Michael Darmawan <michael.darmawan@ibm.com>
  • Loading branch information
MDarmawan authored Apr 16, 2024
1 parent 866c8c2 commit d81a8cc
Show file tree
Hide file tree
Showing 6 changed files with 815 additions and 6 deletions.
8 changes: 4 additions & 4 deletions key_rings.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

const (
path = "key_rings"
keyRingPath = "key_rings"
)

type KeyRing struct {
Expand All @@ -28,7 +28,7 @@ type KeyRings struct {
// https://cloud.ibm.com/docs/key-protect?topic=key-protect-managing-key-rings#create-key-ring-api
func (c *Client) CreateKeyRing(ctx context.Context, id string) error {

req, err := c.newRequest("POST", fmt.Sprintf(path+"/%s", id), nil)
req, err := c.newRequest("POST", fmt.Sprintf(keyRingPath+"/%s", id), nil)
if err != nil {
return err
}
Expand All @@ -46,7 +46,7 @@ func (c *Client) CreateKeyRing(ctx context.Context, id string) error {
// https://cloud.ibm.com/docs/key-protect?topic=key-protect-managing-key-rings#list-key-ring-api
func (c *Client) GetKeyRings(ctx context.Context) (*KeyRings, error) {
rings := KeyRings{}
req, err := c.newRequest("GET", path, nil)
req, err := c.newRequest("GET", keyRingPath, nil)
if err != nil {
return nil, err
}
Expand All @@ -73,7 +73,7 @@ func WithForce(force bool) DeleteKeyRingQueryOption {
// For information please refer to the link below:
// https://cloud.ibm.com/docs/key-protect?topic=key-protect-managing-key-rings#delete-key-ring-api
func (c *Client) DeleteKeyRing(ctx context.Context, id string, opts ...DeleteKeyRingQueryOption) error {
req, err := c.newRequest("DELETE", fmt.Sprintf(path+"/%s", id), nil)
req, err := c.newRequest("DELETE", fmt.Sprintf(keyRingPath+"/%s", id), nil)
for _, opt := range opts {
opt(req)
}
Expand Down
160 changes: 160 additions & 0 deletions kmip_mgmt_adapters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package kp

import (
"context"
"fmt"
"time"
)

const (
kmipAdapterPath = "kmip_adapters"
kmipAdapterType = "application/vnd.ibm.kms.kmip_adapter+json"
)

type KMIPAdapter struct {
ID string `json:"id,omitempty"`
Profile string `json:"profile,omitempty"`
ProfileData map[string]string `json:"profile_data,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description"`
CreatedBy string `json:"created_by,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
UpdatedBy string `json:"updated_by,omitempty"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
}

type KMIPAdapters struct {
Metadata CollectionMetadata `json:"metadata"`
Adapters []KMIPAdapter `json:"resources"`
}

const (
KMIP_Profile_Native = "native_1.0"
)

// CreateKMIPAdapter method creates a KMIP Adapter with the specified profile.
func (c *Client) CreateKMIPAdapter(ctx context.Context, profileOpt CreateKMIPAdapterProfile, options ...CreateKMIPAdapterOption) (*KMIPAdapter, error) {
newAdapter := &KMIPAdapter{}
profileOpt(newAdapter)
for _, opt := range options {
opt(newAdapter)
}
req, err := c.newRequest("POST", kmipAdapterPath, wrapKMIPAdapter(*newAdapter))
if err != nil {
return nil, err
}

create_resp := &KMIPAdapters{}
_, err = c.do(ctx, req, create_resp)
if err != nil {
return nil, err
}
return unwrapKMIPAdapterResp(create_resp), nil
}

// Functions to be passed into the CreateKMIPAdapter() method to specify specific fields.
type CreateKMIPAdapterOption func(*KMIPAdapter)
type CreateKMIPAdapterProfile func(*KMIPAdapter)

func WithKMIPAdapterName(name string) CreateKMIPAdapterOption {
return func(adapter *KMIPAdapter) {
adapter.Name = name
}
}

func WithKMIPAdapterDescription(description string) CreateKMIPAdapterOption {
return func(adapter *KMIPAdapter) {
adapter.Description = description
}
}

func WithNativeProfile(crkID string) CreateKMIPAdapterProfile {
return func(adapter *KMIPAdapter) {
adapter.Profile = KMIP_Profile_Native

adapter.ProfileData = map[string]string{
"crk_id": crkID,
}
}
}

type ListKmipAdaptersOptions struct {
Limit *uint32
Offset *uint32
TotalCount *bool
}

// GetKMIPAdapters method lists KMIP Adapters associated with a specific KP instance.
func (c *Client) GetKMIPAdapters(ctx context.Context, listOpts *ListKmipAdaptersOptions) (*KMIPAdapters, error) {
adapters := KMIPAdapters{}
req, err := c.newRequest("GET", kmipAdapterPath, nil)
if err != nil {
return nil, err
}

if listOpts != nil {
values := req.URL.Query()
if listOpts.Limit != nil {
values.Set("limit", fmt.Sprint(*listOpts.Limit))
}
if listOpts.Offset != nil {
values.Set("offset", fmt.Sprint(*listOpts.Offset))
}
if listOpts.TotalCount != nil {
values.Set("totalCount", fmt.Sprint(*listOpts.TotalCount))
}
req.URL.RawQuery = values.Encode()
}

_, err = c.do(ctx, req, &adapters)
if err != nil {
return nil, err
}

return &adapters, nil
}

// GetKMIPAdapter method retrieves a single KMIP Adapter by name or ID.
func (c *Client) GetKMIPAdapter(ctx context.Context, nameOrID string) (*KMIPAdapter, error) {
adapters := KMIPAdapters{}
req, err := c.newRequest("GET", fmt.Sprintf("%s/%s", kmipAdapterPath, nameOrID), nil)
if err != nil {
return nil, err
}

_, err = c.do(ctx, req, &adapters)
if err != nil {
return nil, err
}

return unwrapKMIPAdapterResp(&adapters), nil
}

// DeletesKMIPAdapter method deletes a single KMIP Adapter by name or ID.
func (c *Client) DeleteKMIPAdapter(ctx context.Context, nameOrID string) error {
req, err := c.newRequest("DELETE", fmt.Sprintf("%s/%s", kmipAdapterPath, nameOrID), nil)
if err != nil {
return err
}

_, err = c.do(ctx, req, nil)
if err != nil {
return err
}

return nil
}

func wrapKMIPAdapter(adapter KMIPAdapter) KMIPAdapters {
return KMIPAdapters{
Metadata: CollectionMetadata{
CollectionType: kmipAdapterType,
CollectionTotal: 1,
},
Adapters: []KMIPAdapter{adapter},
}
}

func unwrapKMIPAdapterResp(resp *KMIPAdapters) *KMIPAdapter {
return &resp.Adapters[0]
}
136 changes: 136 additions & 0 deletions kmip_mgmt_certs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package kp

import (
"context"
"fmt"
"time"
)

const (
kmipClientCertSubPath = "certificates"
kmipClientCertType = "application/vnd.ibm.kms.kmip_client_certificate+json"
)

type KMIPClientCertificate struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Certificate string `json:"certificate,omitempty"`
CreatedBy string `json:"created_by,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
}

type KMIPClientCertificates struct {
Metadata CollectionMetadata `json:"metadata"`
Certificates []KMIPClientCertificate `json:"resources"`
}

// CreateKMIPClientCertificate registers/creates a KMIP PEM format certificate
// for use with a specific KMIP adapter.
// cert_payload is the string representation of
// the certificate to be associated with the KMIP Adapter in PEM format.
// It should explicitly have the BEGIN CERTIFICATE and END CERTIFICATE tags.
// Regex: ^\s*-----BEGIN CERTIFICATE-----[A-Za-z0-9+\/\=\r\n]+-----END CERTIFICATE-----\s*$
func (c *Client) CreateKMIPClientCertificate(ctx context.Context, adapter_nameOrID, cert_payload string, opts ...CreateKMIPClientCertOption) (*KMIPClientCertificate, error) {
newCert := &KMIPClientCertificate{
Certificate: cert_payload,
}
for _, opt := range opts {
opt(newCert)
}
req, err := c.newRequest("POST", fmt.Sprintf("%s/%s/%s", kmipAdapterPath, adapter_nameOrID, kmipClientCertSubPath), wrapKMIPClientCert(*newCert))
if err != nil {
return nil, err
}
certResp := &KMIPClientCertificates{}
_, err = c.do(ctx, req, certResp)
if err != nil {
return nil, err
}

return unwrapKMIPClientCert(certResp), nil
}

type CreateKMIPClientCertOption func(*KMIPClientCertificate)

func WithKMIPClientCertName(name string) CreateKMIPClientCertOption {
return func(cert *KMIPClientCertificate) {
cert.Name = name
}
}

// GetKMIPClientCertificates lists all certificates associated with a KMIP adapter
func (c *Client) GetKMIPClientCertificates(ctx context.Context, adapter_nameOrID string, listOpts *ListOptions) (*KMIPClientCertificates, error) {
certs := KMIPClientCertificates{}
req, err := c.newRequest("GET", fmt.Sprintf("%s/%s/%s", kmipAdapterPath, adapter_nameOrID, kmipClientCertSubPath), nil)
if err != nil {
return nil, err
}

if listOpts != nil {
values := req.URL.Query()
if listOpts.Limit != nil {
values.Set("limit", fmt.Sprint(*listOpts.Limit))
}
if listOpts.Offset != nil {
values.Set("offset", fmt.Sprint(*listOpts.Offset))
}
if listOpts.TotalCount != nil {
values.Set("totalCount", fmt.Sprint(*listOpts.TotalCount))
}
req.URL.RawQuery = values.Encode()
}

_, err = c.do(ctx, req, &certs)
if err != nil {
return nil, err
}

return &certs, nil
}

// GetKMIPClientCertificate gets a single certificate associated with a KMIP adapter
func (c *Client) GetKMIPClientCertificate(ctx context.Context, adapter_nameOrID, cert_nameOrID string) (*KMIPClientCertificate, error) {
certs := &KMIPClientCertificates{}
req, err := c.newRequest("GET", fmt.Sprintf("%s/%s/%s/%s",
kmipAdapterPath, adapter_nameOrID, kmipClientCertSubPath, cert_nameOrID), nil)
if err != nil {
return nil, err
}

_, err = c.do(ctx, req, certs)
if err != nil {
return nil, err
}

return unwrapKMIPClientCert(certs), nil
}

// DeleteKMIPClientCertificate deletes a single certificate
func (c *Client) DeleteKMIPClientCertificate(ctx context.Context, adapter_nameOrID, cert_nameOrID string) error {
req, err := c.newRequest("DELETE", fmt.Sprintf("%s/%s/%s/%s",
kmipAdapterPath, adapter_nameOrID, kmipClientCertSubPath, cert_nameOrID), nil)
if err != nil {
return err
}

_, err = c.do(ctx, req, nil)
if err != nil {
return err
}

return nil
}

func wrapKMIPClientCert(cert KMIPClientCertificate) KMIPClientCertificates {
return KMIPClientCertificates{
Metadata: CollectionMetadata{
CollectionType: kmipClientCertType,
CollectionTotal: 1,
},
Certificates: []KMIPClientCertificate{cert},
}
}

func unwrapKMIPClientCert(certs *KMIPClientCertificates) *KMIPClientCertificate {
return &certs.Certificates[0]
}
Loading

0 comments on commit d81a8cc

Please sign in to comment.