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

Integrate OpenStack Barbican Secret Manager #373

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8c49666
Initial commit
mrhamburg Jun 23, 2023
64ba616
Added debug info
mrhamburg Jun 23, 2023
33fd458
fix: barbican: don't decode secret payload
artashesbalabekyan Jun 24, 2023
695d35a
fix: barbican: use query parameters when get secrets by name
artashesbalabekyan Jun 24, 2023
66d52d3
refactor: barbican: diverse the functions logic
artashesbalabekyan Jun 24, 2023
bdefa89
fix: Content-Type header
artashesbalabekyan Jun 24, 2023
32d959a
refactor: barbican: diversify the code
artashesbalabekyan Jun 25, 2023
aec0a78
fix: error messages barbican
mrhamburg Jun 25, 2023
744ec83
fix: test: throw error if test should not fail
artashesbalabekyan Jun 25, 2023
2f7b039
refactor: openstack: use barbican-sdk-go package
artashesbalabekyan Jun 29, 2023
f7dcad5
remove launch.json
artashesbalabekyan Jun 29, 2023
accae2f
mod: update barbican sdk package
artashesbalabekyan Jul 1, 2023
35e1150
mod: update barbican sdk package
artashesbalabekyan Jul 2, 2023
40fada2
Merge branch 'master' of github.com:minio/kes into integrate_openstac…
artashesbalabekyan Jul 7, 2023
005a125
fix: openstack tests
artashesbalabekyan Jul 7, 2023
1878d8b
integrate barbican using gophercloud package
artashesbalabekyan Jul 9, 2023
6393557
fix: edge_test shouldfiail case
artashesbalabekyan Jul 9, 2023
d30ed6f
fix: openstack: don't use service type and name for endpoint options
artashesbalabekyan Jul 9, 2023
63f7949
openstack: remove unused prints
artashesbalabekyan Jul 9, 2023
3390828
fix: openstack: throw key already exists error when trying to create …
artashesbalabekyan Jul 9, 2023
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
3 changes: 3 additions & 0 deletions cmd/kes/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ func description(config *edge.ServerConfig) (kind string, endpoint []string, err
case *edge.AzureKeyVaultKeyStore:
kind = "Azure KeyVault"
endpoint = []string{kms.Endpoint}
case *edge.OpenStackBarbicanKeyStore:
kind = "OpenStack Barbican"
endpoint = []string{kms.BarbicanUrl}
default:
return "", nil, fmt.Errorf("unknown KMS backend %T", kms)
}
Expand Down
14 changes: 10 additions & 4 deletions edge/edge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var createTests = []struct {
{ // 1
Args: map[string][]byte{"edge-test": []byte("edge-test-value")},
Setup: func(ctx context.Context, s kv.Store[string, []byte], suffix string) error {
return s.Create(ctx, "edge-test-"+suffix, []byte("t"))
return s.Create(ctx, "edge-test-"+suffix, []byte(""))
},
ShouldFail: true,
},
Expand All @@ -45,7 +45,10 @@ func testCreate(ctx context.Context, store kv.Store[string, []byte], t *testing.
for i, test := range createTests {
if test.Setup != nil {
if err := test.Setup(ctx, store, fmt.Sprintf("%s-%d", seed, i)); err != nil {
t.Fatalf("Test %d: failed to setup: %v", i, err)
if !test.ShouldFail {
t.Fatalf("Test %d: failed to setup: %v", i, err)
}
continue
}
}

Expand Down Expand Up @@ -73,7 +76,7 @@ var setTests = []struct {
{ // 1
Args: map[string][]byte{"edge-test": []byte("edge-test-value")},
Setup: func(ctx context.Context, s kv.Store[string, []byte], sufffix string) error {
return s.Create(ctx, "edge-test-"+sufffix, []byte("t"))
return s.Create(ctx, "edge-test-"+sufffix, []byte(""))
},
ShouldFail: true,
},
Expand All @@ -84,7 +87,10 @@ func testSet(ctx context.Context, store kv.Store[string, []byte], t *testing.T,
for i, test := range setTests {
if test.Setup != nil {
if err := test.Setup(ctx, store, fmt.Sprintf("%s-%d", seed, i)); err != nil {
t.Fatalf("Test %d: failed to setup: %v", i, err)
if !test.ShouldFail {
t.Fatalf("Test %d: failed to setup: %v", i, err)
}
continue
}
}

Expand Down
48 changes: 48 additions & 0 deletions edge/openstack_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2023 - MinIO, Inc. All rights reserved.
// Use of this source code is governed by the AGPLv3
// license that can be found in the LICENSE file.

package edge_test

import (
"flag"
"os"
"testing"

"github.com/minio/kes/edge"
)

var openstackConfigFile = flag.String("openstack.config", "", "Path to a KES config file with OpenStack SDKMS config")

func TestOpenStack(t *testing.T) {
if *openstackConfigFile == "" {
t.Skip("OpenStack tests disabled. Use -openstack.config=<FILE> to enable them")
}
file, err := os.Open(*openstackConfigFile)
if err != nil {
t.Fatal(err)
}
defer file.Close()

config, err := edge.ReadServerConfigYAML(file)
if err != nil {
t.Fatal(err)
}

if _, ok := config.KeyStore.(*edge.OpenStackBarbicanKeyStore); !ok {
t.Fatalf("Invalid Keystore: want %T - got %T", config.KeyStore, &edge.OpenStackBarbicanKeyStore{})
}

ctx, cancel := testingContext(t)
defer cancel()

store, err := config.KeyStore.Connect(ctx)
if err != nil {
t.Fatal(err)
}

t.Run("Create", func(t *testing.T) { testCreate(ctx, store, t, RandString(ranStringLength)) })
t.Run("Set", func(t *testing.T) { testSet(ctx, store, t, RandString(ranStringLength)) })
t.Run("Get", func(t *testing.T) { testGet(ctx, store, t, RandString(ranStringLength)) })
t.Run("Status", func(t *testing.T) { testStatus(ctx, store, t) })
}
55 changes: 55 additions & 0 deletions edge/server-config-yml.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,21 @@ type yml struct {
} `yaml:"managed_identity"`
} `yaml:"keyvault"`
} `yaml:"azure"`

OpenStack *struct {
Barbican *struct {
AuthUrl env[string] `yaml:"auth_url"`
Credentials *struct {
UserDomain env[string] `yaml:"user_domain"`
Username env[string] `yaml:"username"`
Password env[string] `yaml:"password"`
ProjectDomain env[string] `yaml:"project_domain"`
ProjectName env[string] `yaml:"project_name"`
ServiceName env[string] `yaml:"service_name"`
Region env[string] `yaml:"region"`
} `yaml:"credentials"`
} `yaml:"barbican"`
} `yaml:"openstack"`
} `yaml:"keystore"`
}

Expand Down Expand Up @@ -597,6 +612,46 @@ func ymlToKeyStore(y *yml) (KeyStore, error) {
keystore = s
}

// OpenStack Barbican
if y.KeyStore.OpenStack != nil && y.KeyStore.OpenStack.Barbican != nil {
if keystore != nil {
return nil, errors.New("edge: invalid keystore config: more than once keystore specified")
}
if y.KeyStore.OpenStack.Barbican.AuthUrl.Value == "" {
return nil, errors.New("edge: invalid OpenStack Barbican keystore: no Auth Url specified")
}
if y.KeyStore.OpenStack.Barbican.Credentials.UserDomain.Value == "" {
return nil, errors.New("edge: invalid OpenStack Barbican keystore: no User Domain specified")
}
if y.KeyStore.OpenStack.Barbican.Credentials.Username.Value == "" {
return nil, errors.New("edge: invalid OpenStack Barbican keystore: no Username specified")
}
if y.KeyStore.OpenStack.Barbican.Credentials.Password.Value == "" {
return nil, errors.New("edge: invalid OpenStack Barbican keystore: no Password specified")
}
if y.KeyStore.OpenStack.Barbican.Credentials.ProjectName.Value == "" {
return nil, errors.New("edge: invalid OpenStack Barbican keystore: no ProjectName specified")
}
if y.KeyStore.OpenStack.Barbican.Credentials.Region.Value == "" {
return nil, errors.New("edge: invalid OpenStack Barbican keystore: no Region specified")
}

s := &OpenStackBarbicanKeyStore{
AuthUrl: y.KeyStore.OpenStack.Barbican.AuthUrl.Value,
UserDomain: y.KeyStore.OpenStack.Barbican.Credentials.UserDomain.Value,
Username: y.KeyStore.OpenStack.Barbican.Credentials.Username.Value,
Password: y.KeyStore.OpenStack.Barbican.Credentials.Password.Value,
ProjectName: y.KeyStore.OpenStack.Barbican.Credentials.ProjectName.Value,
ServiceName: y.KeyStore.OpenStack.Barbican.Credentials.ServiceName.Value,
Region: y.KeyStore.OpenStack.Barbican.Credentials.Region.Value,
}

if s.ServiceName == "" {
s.ServiceName = "barbican"
}
keystore = s
}

if keystore == nil {
return nil, errors.New("edge: no keystore specified")
}
Expand Down
55 changes: 55 additions & 0 deletions edge/server-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"time"

"github.com/gophercloud/gophercloud"
"github.com/minio/kes-go"
"github.com/minio/kes/internal/keystore/aws"
"github.com/minio/kes/internal/keystore/azure"
Expand All @@ -17,6 +18,7 @@ import (
"github.com/minio/kes/internal/keystore/gcp"
"github.com/minio/kes/internal/keystore/gemalto"
kesstore "github.com/minio/kes/internal/keystore/kes"
"github.com/minio/kes/internal/keystore/openstack"
"github.com/minio/kes/internal/keystore/vault"
"github.com/minio/kes/kv"
)
Expand Down Expand Up @@ -637,3 +639,56 @@ func (s *AzureKeyVaultKeyStore) Connect(ctx context.Context) (kv.Store[string, [
return nil, errors.New("edge: failed to connect to Azure KeyVault: no authentication method specified")
}
}

// OpenStackBarbicanKeyStore is a structure containing the
// configuration for OpenStack Barbican
type OpenStackBarbicanKeyStore struct {
// OpenStack Auth Url
AuthUrl string

// The Domain of the user.
UserDomain string

// The user name. If you do not provide a user name and password, you must provide a token.
Username string

// The password for the user.
Password string

// The project name. Both the Project ID and Project Name are optional.
ProjectName string

// URL of the Barbican instance to connect to
BarbicanUrl string

// ServiceName [optional] is the service name for the client (e.g., "nova") as it
// appears in the service catalog. Services can have the same Type but a
// different Name, which is why both Type and Name are sometimes needed.
ServiceName string

// Region [required] is the geographic region in which the endpoint resides,
// generally specifying which datacenter should house your resources.
// Required only for services that span multiple regions.
Region string

_ [0]int
}

// Connect returns a kv.Store that stores key-value pairs on OpenStack Barbican.
func (s *OpenStackBarbicanKeyStore) Connect(ctx context.Context) (kv.Store[string, []byte], error) {
creds := gophercloud.AuthOptions{
IdentityEndpoint: s.AuthUrl,
Username: s.Username,
Password: s.Password,
DomainID: s.UserDomain,
TenantName: s.ProjectName,
}

endpointOpts := gophercloud.EndpointOpts{
Type: "key-manager",
Name: s.ServiceName,
Region: s.Region,
}

return openstack.Connect(ctx, creds, endpointOpts)
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/aws/aws-sdk-go v1.34.0
github.com/charmbracelet/lipgloss v0.6.0
github.com/fatih/color v1.13.0
github.com/gophercloud/gophercloud v1.5.0
github.com/hashicorp/vault/api v1.5.0
github.com/minio/kes-go v0.1.0
github.com/minio/selfupdate v0.4.0
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbez
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ=
github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
github.com/gophercloud/gophercloud v1.5.0 h1:cDN6XFCLKiiqvYpjQLq9AiM7RDRbIC9450WpPH+yvXo=
github.com/gophercloud/gophercloud v1.5.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
Expand Down Expand Up @@ -334,6 +336,7 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
Expand Down Expand Up @@ -475,6 +478,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
2 changes: 1 addition & 1 deletion internal/api/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ func edgeDescribeKey(config *EdgeRouterConfig) API {
return err
}

w.Header().Set("Content-Length", "application/json")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(Response{
Name: name,
Expand Down
Loading