Skip to content

Commit

Permalink
Add KES v2 config and toolbox helps (#1602)
Browse files Browse the repository at this point in the history
* add KES config v2 and tooltips
* self document how we identiy the `arch` from KES image tag
* Verify expected KES cofig Model on tests
* add assertions to verify the expected error result
  • Loading branch information
pjuarezd authored May 23, 2023
1 parent c276b93 commit 5f0bbde
Show file tree
Hide file tree
Showing 14 changed files with 1,636 additions and 644 deletions.
797 changes: 614 additions & 183 deletions api/encryption-handlers.go

Large diffs are not rendered by default.

277 changes: 267 additions & 10 deletions api/encryption-handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package api
import (
"context"
"errors"
"fmt"
"net/http"
"time"

Expand Down Expand Up @@ -293,7 +294,7 @@ func (suite *TenantTestSuite) TestTenantEncryptionInfoWithClientCertError() {
suite.assert.NotNil(err)
}

func (suite *TenantTestSuite) TestTenantEncryptionInfoWithKesClientCertError() {
func (suite *TenantTestSuite) TestTenantEncryptionInfoWithKesClientCertErrorV2() {
opClientTenantGetMock = func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) {
return &miniov2.Tenant{
Spec: miniov2.TenantSpec{
Expand All @@ -312,7 +313,7 @@ func (suite *TenantTestSuite) TestTenantEncryptionInfoWithKesClientCertError() {
if secretName == "mock-kes-config" {
return &corev1.Secret{
Data: map[string][]byte{
"server-config.yaml": suite.getKesYamlMock(false),
"server-config.yaml": suite.getKesV2YamlMock(false),
},
}, nil
}
Expand All @@ -329,9 +330,10 @@ func (suite *TenantTestSuite) TestTenantEncryptionInfoWithKesClientCertError() {
res, err := tenantEncryptionInfo(context.Background(), suite.opClient, suite.k8sclient, params.Namespace, params)
suite.assert.Nil(res)
suite.assert.NotNil(err)
suite.assert.Equal(err, errors.New("certificate failed to decode"))
}

func (suite *TenantTestSuite) TestTenantEncryptionInfoWithKesClientCACertError() {
func (suite *TenantTestSuite) TestTenantEncryptionInfoWithKesClientCertErrorV1() {
opClientTenantGetMock = func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) {
return &miniov2.Tenant{
Spec: miniov2.TenantSpec{
Expand All @@ -342,6 +344,7 @@ func (suite *TenantTestSuite) TestTenantEncryptionInfoWithKesClientCACertError()
Configuration: &corev1.LocalObjectReference{
Name: "mock-kes-config",
},
Image: "minio/kes:v0.21.1",
},
},
}, nil
Expand All @@ -350,7 +353,86 @@ func (suite *TenantTestSuite) TestTenantEncryptionInfoWithKesClientCACertError()
if secretName == "mock-kes-config" {
return &corev1.Secret{
Data: map[string][]byte{
"server-config.yaml": suite.getKesYamlMock(false),
"server-config.yaml": suite.getKesV1YamlMock(false),
},
}, nil
}
if secretName == "mock-kes-crt" {
return &corev1.Secret{
Data: map[string][]byte{
"client.crt": []byte("mock-client-crt"),
},
}, nil
}
return nil, errors.New("mock-get-error")
}
params, _ := suite.initTenantEncryptionInfoRequest()
res, err := tenantEncryptionInfo(context.Background(), suite.opClient, suite.k8sclient, params.Namespace, params)
suite.assert.Nil(res)
suite.assert.NotNil(err)
suite.assert.Equal(err, errors.New("certificate failed to decode"))
}

func (suite *TenantTestSuite) TestTenantEncryptionInfoWithKesClientCACertErrorV2() {
opClientTenantGetMock = func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) {
return &miniov2.Tenant{
Spec: miniov2.TenantSpec{
KES: &miniov2.KESConfig{
ClientCertSecret: &miniov2.LocalCertificateReference{
Name: "mock-kes-crt",
},
Configuration: &corev1.LocalObjectReference{
Name: "mock-kes-config",
},
},
},
}, nil
}
k8sclientGetSecretMock = func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
if secretName == "mock-kes-config" {
return &corev1.Secret{
Data: map[string][]byte{
"server-config.yaml": suite.getKesV2YamlMock(false),
},
}, nil
}
if secretName == "mock-kes-crt" {
return &corev1.Secret{
Data: map[string][]byte{
"ca.crt": []byte("mock-client-crt"),
},
}, nil
}
return nil, errors.New("mock-get-error")
}
params, _ := suite.initTenantEncryptionInfoRequest()
res, err := tenantEncryptionInfo(context.Background(), suite.opClient, suite.k8sclient, params.Namespace, params)
suite.assert.Nil(res)
suite.assert.NotNil(err)
suite.assert.Equal(err, errors.New("certificate failed to decode"))
}

func (suite *TenantTestSuite) TestTenantEncryptionInfoWithKesClientCACertErrorV1() {
opClientTenantGetMock = func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) {
return &miniov2.Tenant{
Spec: miniov2.TenantSpec{
KES: &miniov2.KESConfig{
ClientCertSecret: &miniov2.LocalCertificateReference{
Name: "mock-kes-crt",
},
Configuration: &corev1.LocalObjectReference{
Name: "mock-kes-config",
},
Image: "minio/kes:v0.21.1",
},
},
}, nil
}
k8sclientGetSecretMock = func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
if secretName == "mock-kes-config" {
return &corev1.Secret{
Data: map[string][]byte{
"server-config.yaml": suite.getKesV1YamlMock(false),
},
}, nil
}
Expand All @@ -367,9 +449,10 @@ func (suite *TenantTestSuite) TestTenantEncryptionInfoWithKesClientCACertError()
res, err := tenantEncryptionInfo(context.Background(), suite.opClient, suite.k8sclient, params.Namespace, params)
suite.assert.Nil(res)
suite.assert.NotNil(err)
suite.assert.Equal(err, errors.New("certificate failed to decode"))
}

func (suite *TenantTestSuite) TestTenantEncryptionInfoWithGemaltoError() {
func (suite *TenantTestSuite) TestTenantEncryptionInfoWithGemaltoErrorV2() {
opClientTenantGetMock = func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) {
return &miniov2.Tenant{
Spec: miniov2.TenantSpec{
Expand All @@ -388,7 +471,7 @@ func (suite *TenantTestSuite) TestTenantEncryptionInfoWithGemaltoError() {
if secretName == "mock-kes-config" {
return &corev1.Secret{
Data: map[string][]byte{
"server-config.yaml": suite.getKesYamlMock(true),
"server-config.yaml": suite.getKesV2YamlMock(true),
},
}, nil
}
Expand All @@ -405,16 +488,21 @@ func (suite *TenantTestSuite) TestTenantEncryptionInfoWithGemaltoError() {
res, err := tenantEncryptionInfo(context.Background(), suite.opClient, suite.k8sclient, params.Namespace, params)
suite.assert.Nil(res)
suite.assert.NotNil(err)
suite.assert.Equal(err, errors.New("certificate failed to decode"))
}

func (suite *TenantTestSuite) TestTenantEncryptionInfoWithoutError() {
func (suite *TenantTestSuite) TestTenantEncryptionInfoWithGemaltoErrorV1() {
opClientTenantGetMock = func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) {
return &miniov2.Tenant{
Spec: miniov2.TenantSpec{
KES: &miniov2.KESConfig{
ClientCertSecret: &miniov2.LocalCertificateReference{
Name: "mock-kes-crt",
},
Configuration: &corev1.LocalObjectReference{
Name: "mock-kes-config",
},
Image: "minio/kes:v0.21.1",
},
},
}, nil
Expand All @@ -423,20 +511,148 @@ func (suite *TenantTestSuite) TestTenantEncryptionInfoWithoutError() {
if secretName == "mock-kes-config" {
return &corev1.Secret{
Data: map[string][]byte{
"server-config.yaml": suite.getKesYamlMock(false),
"server-config.yaml": suite.getKesV1YamlMock(true),
},
}, nil
}
if secretName == "mock-kes-crt" {
return &corev1.Secret{
Data: map[string][]byte{
"ca.crt": []byte("mock-client-crt"),
},
}, nil
}
return nil, errors.New("mock-get-error")
}
params, _ := suite.initTenantEncryptionInfoRequest()
res, err := tenantEncryptionInfo(context.Background(), suite.opClient, suite.k8sclient, params.Namespace, params)
suite.assert.Nil(res)
suite.assert.NotNil(err)
suite.assert.Equal(err, errors.New("certificate failed to decode"))
}

func (suite *TenantTestSuite) TestTenantEncryptionInfoWithoutErrorv2() {
rawConfig := suite.getKesV2YamlMock(true)
kesImage := miniov2.GetTenantKesImage()

opClientTenantGetMock = func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) {
return &miniov2.Tenant{
Spec: miniov2.TenantSpec{
KES: &miniov2.KESConfig{
Configuration: &corev1.LocalObjectReference{
Name: "mock-kes-config",
},
},
},
}, nil
}
k8sclientGetSecretMock = func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
if secretName == "mock-kes-config" {
return &corev1.Secret{
Data: map[string][]byte{
"server-config.yaml": rawConfig,
},
}, nil
}
return nil, errors.New("mock-get-error")
}
params, _ := suite.initTenantEncryptionInfoRequest()
expectedConfig, err := suite.getExpectedEncriptionConfiguration(context.Background(), rawConfig, true, suite.opClient, params.Tenant, params.Namespace, kesImage)
suite.assert.Nil(err)
res, err := tenantEncryptionInfo(context.Background(), suite.opClient, suite.k8sclient, params.Namespace, params)
suite.assert.Equal(expectedConfig, res)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}

func (suite *TenantTestSuite) TestTenantEncryptionInfoWithoutErrorv1() {
rawConfig := suite.getKesV1YamlMock(false)
kesImage := "minio/kes:v0.21.1"

opClientTenantGetMock = func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) {
return &miniov2.Tenant{
Spec: miniov2.TenantSpec{
KES: &miniov2.KESConfig{
Configuration: &corev1.LocalObjectReference{
Name: "mock-kes-config",
},
Image: kesImage,
},
},
}, nil
}
k8sclientGetSecretMock = func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
if secretName == "mock-kes-config" {
return &corev1.Secret{
Data: map[string][]byte{
"server-config.yaml": rawConfig,
},
}, nil
}
return nil, errors.New("mock-get-error")
}
params, _ := suite.initTenantEncryptionInfoRequest()
expectedConfig, err := suite.getExpectedEncriptionConfiguration(context.Background(), rawConfig, false, suite.opClient, params.Tenant, params.Namespace, kesImage)
suite.assert.Nil(err)
res, err := tenantEncryptionInfo(context.Background(), suite.opClient, suite.k8sclient, params.Namespace, params)
suite.assert.Equal(expectedConfig, res)
suite.assert.NotNil(res)
suite.assert.Nil(err)
}

func (suite *TenantTestSuite) getKesYamlMock(noVault bool) []byte {
kesConfig := &kes.ServerConfig{
func (suite *TenantTestSuite) getExpectedEncriptionConfiguration(ctx context.Context, rawConfig []byte, noVault bool, operatorClient OperatorClientI, tenantName string, namespace string, kesImage string) (*models.EncryptionConfigurationResponse, error) {
tenant, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{})
endpoint := "mock-endpoint"
mockid := "mock-id"
mocksecret := "mock-secret"
mockdomain := "mock-domain"
mocktoken := "mock-token"

if err != nil {
return nil, err
}
response := &models.EncryptionConfigurationResponse{
Raw: string(rawConfig),
Image: kesImage,
Replicas: fmt.Sprintf("%d", tenant.Spec.KES.Replicas),
Aws: &models.AwsConfiguration{},
Gcp: &models.GcpConfiguration{},
Azure: &models.AzureConfiguration{},
Vault: &models.VaultConfigurationResponse{
Prefix: "mock-prefix",
Namespace: "mock-namespace",
Engine: "mock-engine-path",
Endpoint: &endpoint,
Status: &models.VaultConfigurationResponseStatus{
Ping: 5,
},
Approle: &models.VaultConfigurationResponseApprole{
Engine: "mock-engine-path",
ID: &mockid,
Retry: 5,
Secret: &mocksecret,
},
},
Gemalto: &models.GemaltoConfigurationResponse{
Keysecure: &models.GemaltoConfigurationResponseKeysecure{
Endpoint: &endpoint,
Credentials: &models.GemaltoConfigurationResponseKeysecureCredentials{
Domain: &mockdomain,
Retry: 5,
Token: &mocktoken,
},
},
},
}
if noVault {
response.Vault = nil
}

return response, nil
}

func (suite *TenantTestSuite) getKesV1YamlMock(noVault bool) []byte {
kesConfig := &kes.ServerConfigV1{
Keys: kes.Keys{
Vault: &kes.Vault{
Prefix: "mock-prefix",
Expand Down Expand Up @@ -476,6 +692,47 @@ func (suite *TenantTestSuite) getKesYamlMock(noVault bool) []byte {
return kesConfigBytes
}

func (suite *TenantTestSuite) getKesV2YamlMock(noVault bool) []byte {
kesConfig := &kes.ServerConfigV2{
Keystore: kes.Keys{
Vault: &kes.Vault{
Prefix: "mock-prefix",
Namespace: "mock-namespace",
EnginePath: "mock-engine-path",
Endpoint: "mock-endpoint",
Status: &kes.VaultStatus{
Ping: 5 * time.Second,
},
AppRole: &kes.AppRole{
EnginePath: "mock-engine-path",
ID: "mock-id",
Retry: 5 * time.Second,
Secret: "mock-secret",
},
},
Aws: &kes.Aws{},
Gcp: &kes.Gcp{},
Gemalto: &kes.Gemalto{
KeySecure: &kes.GemaltoKeySecure{
Endpoint: "mock-endpoint",
Credentials: &kes.GemaltoCredentials{
Domain: "mock-domain",
Retry: 5 * time.Second,
Token: "mock-token",
},
TLS: &kes.GemaltoTLS{},
},
},
Azure: &kes.Azure{},
},
}
if noVault {
kesConfig.Keystore.Vault = nil
}
kesConfigBytes, _ := yaml.Marshal(kesConfig)
return kesConfigBytes
}

func (suite *TenantTestSuite) initTenantEncryptionInfoRequest() (params operator_api.TenantEncryptionInfoParams, api operations.OperatorAPI) {
registerEncryptionHandlers(&api)
params.HTTPRequest = &http.Request{}
Expand Down
Loading

0 comments on commit 5f0bbde

Please sign in to comment.