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

feat(build): Add KMIP Management APIs to Go SDK #122

Merged
merged 24 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Comment on lines +81 to +85
Copy link
Contributor

Choose a reason for hiding this comment

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

Were we not able to reuse ListOptions? Noticed this was a change from last review

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Using its own struct type in order to allow for extensibility, adding new options to list kmip adapters


// 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