Added endpoint for update tenant certificates (minio/console) (#258)
This commit is contained in:
113
models/update_certificates_request.go
Normal file
113
models/update_certificates_request.go
Normal file
@@ -0,0 +1,113 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package models
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// UpdateCertificatesRequest update certificates request
|
||||
//
|
||||
// swagger:model updateCertificatesRequest
|
||||
type UpdateCertificatesRequest struct {
|
||||
|
||||
// console
|
||||
Console *KeyPairConfiguration `json:"console,omitempty"`
|
||||
|
||||
// minio
|
||||
Minio *KeyPairConfiguration `json:"minio,omitempty"`
|
||||
}
|
||||
|
||||
// Validate validates this update certificates request
|
||||
func (m *UpdateCertificatesRequest) Validate(formats strfmt.Registry) error {
|
||||
var res []error
|
||||
|
||||
if err := m.validateConsole(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if err := m.validateMinio(formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *UpdateCertificatesRequest) validateConsole(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.Console) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.Console != nil {
|
||||
if err := m.Console.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("console")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *UpdateCertificatesRequest) validateMinio(formats strfmt.Registry) error {
|
||||
|
||||
if swag.IsZero(m.Minio) { // not required
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.Minio != nil {
|
||||
if err := m.Minio.Validate(formats); err != nil {
|
||||
if ve, ok := err.(*errors.Validation); ok {
|
||||
return ve.ValidateName("minio")
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary interface implementation
|
||||
func (m *UpdateCertificatesRequest) MarshalBinary() ([]byte, error) {
|
||||
if m == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return swag.WriteJSON(m)
|
||||
}
|
||||
|
||||
// UnmarshalBinary interface implementation
|
||||
func (m *UpdateCertificatesRequest) UnmarshalBinary(b []byte) error {
|
||||
var res UpdateCertificatesRequest
|
||||
if err := swag.ReadJSON(b, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
*m = res
|
||||
return nil
|
||||
}
|
||||
@@ -18,9 +18,7 @@ package restapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -32,11 +30,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/minio/console/pkg/kes"
|
||||
"gopkg.in/yaml.v2"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
||||
@@ -126,6 +121,7 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
|
||||
return admin_api.NewUpdateTenantCreated()
|
||||
})
|
||||
|
||||
// Add Tenant Zones
|
||||
api.AdminAPITenantAddZoneHandler = admin_api.TenantAddZoneHandlerFunc(func(params admin_api.TenantAddZoneParams, session *models.Principal) middleware.Responder {
|
||||
err := getTenantAddZoneResponse(session, params)
|
||||
if err != nil {
|
||||
@@ -135,6 +131,7 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
|
||||
return admin_api.NewTenantAddZoneCreated()
|
||||
})
|
||||
|
||||
// Get Tenant Usage
|
||||
api.AdminAPIGetTenantUsageHandler = admin_api.GetTenantUsageHandlerFunc(func(params admin_api.GetTenantUsageParams, session *models.Principal) middleware.Responder {
|
||||
payload, err := getTenantUsageResponse(session, params)
|
||||
if err != nil {
|
||||
@@ -144,6 +141,7 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
|
||||
return admin_api.NewGetTenantUsageOK().WithPayload(payload)
|
||||
})
|
||||
|
||||
// Update Tenant Zones
|
||||
api.AdminAPITenantUpdateZonesHandler = admin_api.TenantUpdateZonesHandlerFunc(func(params admin_api.TenantUpdateZonesParams, session *models.Principal) middleware.Responder {
|
||||
resp, err := getTenantUpdateZoneResponse(session, params)
|
||||
if err != nil {
|
||||
@@ -152,6 +150,26 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
|
||||
}
|
||||
return admin_api.NewTenantUpdateZonesOK().WithPayload(resp)
|
||||
})
|
||||
|
||||
// Update Tenant Certificates
|
||||
api.AdminAPITenantUpdateCertificateHandler = admin_api.TenantUpdateCertificateHandlerFunc(func(params admin_api.TenantUpdateCertificateParams, session *models.Principal) middleware.Responder {
|
||||
err := getTenantUpdateCertificatesResponse(session, params)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return admin_api.NewGetTenantUsageDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String("Unable to update tenant certificates")})
|
||||
}
|
||||
return admin_api.NewTenantUpdateCertificateCreated()
|
||||
})
|
||||
|
||||
// Update Tenant Encryption Configuration
|
||||
api.AdminAPITenantUpdateEncryptionHandler = admin_api.TenantUpdateEncryptionHandlerFunc(func(params admin_api.TenantUpdateEncryptionParams, session *models.Principal) middleware.Responder {
|
||||
err := getTenantUpdateEncryptionResponse(session, params)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return admin_api.NewGetTenantUsageDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String("Unable to update encryption configuration")})
|
||||
}
|
||||
return admin_api.NewTenantUpdateCertificateCreated()
|
||||
})
|
||||
}
|
||||
|
||||
// getDeleteTenantResponse gets the output of deleting a minio instance
|
||||
@@ -180,7 +198,7 @@ func getDeleteTenantResponse(session *models.Principal, params admin_api.DeleteT
|
||||
// It also adds the option of deleting the tenant's underlying pvcs if deletePvcs set
|
||||
func deleteTenantAction(
|
||||
ctx context.Context,
|
||||
operatorClient OperatorClient,
|
||||
operatorClient OperatorClientI,
|
||||
clientset v1.CoreV1Interface,
|
||||
namespace, tenantName string,
|
||||
deletePvcs bool) error {
|
||||
@@ -216,7 +234,7 @@ func getTenantScheme(mi *operator.Tenant) string {
|
||||
return scheme
|
||||
}
|
||||
|
||||
func getTenantAdminClient(ctx context.Context, client K8sClient, namespace, tenantName, serviceName, scheme string, insecure bool) (*madmin.AdminClient, error) {
|
||||
func getTenantAdminClient(ctx context.Context, client K8sClientI, namespace, tenantName, serviceName, scheme string, insecure bool) (*madmin.AdminClient, error) {
|
||||
// get admin credentials from secret
|
||||
creds, err := client.getSecret(ctx, namespace, fmt.Sprintf("%s-secret", tenantName), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
@@ -239,7 +257,7 @@ func getTenantAdminClient(ctx context.Context, client K8sClient, namespace, tena
|
||||
return mAdmin, nil
|
||||
}
|
||||
|
||||
func getTenant(ctx context.Context, operatorClient OperatorClient, namespace, tenantName string) (*operator.Tenant, error) {
|
||||
func getTenant(ctx context.Context, operatorClient OperatorClientI, namespace, tenantName string) (*operator.Tenant, error) {
|
||||
minInst, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -292,7 +310,7 @@ func getTenantInfoResponse(session *models.Principal, params admin_api.TenantInf
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func listTenants(ctx context.Context, operatorClient OperatorClient, namespace string, limit *int32) (*models.ListTenantsResponse, error) {
|
||||
func listTenants(ctx context.Context, operatorClient OperatorClientI, namespace string, limit *int32) (*models.ListTenantsResponse, error) {
|
||||
listOpts := metav1.ListOptions{
|
||||
Limit: 10,
|
||||
}
|
||||
@@ -389,7 +407,10 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
}
|
||||
}
|
||||
// get Kubernetes Client
|
||||
clientset, err := cluster.K8sClient(session.SessionToken)
|
||||
clientSet, err := cluster.K8sClient(session.SessionToken)
|
||||
k8sClient := k8sClient{
|
||||
client: clientSet,
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -425,7 +446,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
},
|
||||
}
|
||||
|
||||
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -518,43 +539,15 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
if !minInst.Spec.RequestAutoCert && tenantReq.TLS != nil && tenantReq.TLS.Minio != nil {
|
||||
// User provided TLS certificates for MinIO
|
||||
isEncryptionAvailable = true
|
||||
externalTLSCertificateSecretName := fmt.Sprintf("%s-instance-external-certificates", secretName)
|
||||
// disable autoCert
|
||||
minInst.Spec.RequestAutoCert = false
|
||||
|
||||
tlsCrt, err := base64.StdEncoding.DecodeString(*tenantReq.TLS.Minio.Crt)
|
||||
// Certificates used by the MinIO instance
|
||||
externalCertSecretName := fmt.Sprintf("%s-instance-external-certificates", secretName)
|
||||
externalCertSecret, err := createOrReplaceExternalCertSecret(ctx, &k8sClient, ns, tenantReq.TLS.Minio, externalCertSecretName, tenantName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsKey, err := base64.StdEncoding.DecodeString(*tenantReq.TLS.Minio.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
externalTLSCertificateSecret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: externalTLSCertificateSecretName,
|
||||
Labels: map[string]string{
|
||||
operator.TenantLabel: tenantName,
|
||||
},
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
Immutable: &imm,
|
||||
Data: map[string][]byte{
|
||||
"tls.crt": tlsCrt,
|
||||
"tls.key": tlsKey,
|
||||
},
|
||||
}
|
||||
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &externalTLSCertificateSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Certificates used by the minio instance
|
||||
minInst.Spec.ExternalCertSecret = &operator.LocalCertificateReference{
|
||||
Name: externalTLSCertificateSecretName,
|
||||
Type: "kubernetes.io/tls",
|
||||
}
|
||||
minInst.Spec.ExternalCertSecret = externalCertSecret
|
||||
}
|
||||
|
||||
if tenantReq.Encryption != nil && isEncryptionAvailable {
|
||||
@@ -565,13 +558,14 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
})
|
||||
// KES client mTLSCertificates used by MinIO instance, only if autoCert is not enabled
|
||||
if !minInst.Spec.RequestAutoCert {
|
||||
minInst.Spec.ExternalClientCertSecret, err = getTenantExternalClientCertificates(ctx, clientset, ns, tenantReq.Encryption, secretName, tenantName)
|
||||
tenantExternalClientCertSecretName := fmt.Sprintf("%s-tenant-external-client-cert", secretName)
|
||||
minInst.Spec.ExternalClientCertSecret, err = createOrReplaceExternalCertSecret(ctx, &k8sClient, ns, tenantReq.Encryption.Client, tenantExternalClientCertSecretName, tenantName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// KES configuration for Tenant instance
|
||||
minInst.Spec.KES, err = getKESConfiguration(ctx, clientset, ns, tenantReq.Encryption, secretName, tenantName, minInst.Spec.RequestAutoCert)
|
||||
minInst.Spec.KES, err = getKESConfiguration(ctx, &k8sClient, ns, tenantReq.Encryption, secretName, tenantName, minInst.Spec.RequestAutoCert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -630,7 +624,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
}
|
||||
}
|
||||
|
||||
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -646,42 +640,15 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if !minInst.Spec.RequestAutoCert && tenantReq.TLS != nil && tenantReq.TLS.Console != nil {
|
||||
consoleExternalTLSCertificateSecretName := fmt.Sprintf("%s-console-external-certificates", secretName)
|
||||
tlsCrt, err := base64.StdEncoding.DecodeString(*tenantReq.TLS.Console.Crt)
|
||||
// Certificates used by the console instance
|
||||
externalCertSecretName := fmt.Sprintf("%s-console-external-certificates", secretName)
|
||||
externalCertSecret, err := createOrReplaceExternalCertSecret(ctx, &k8sClient, ns, tenantReq.TLS.Console, externalCertSecretName, tenantName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsKey, err := base64.StdEncoding.DecodeString(*tenantReq.TLS.Console.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
consoleExternalTLSCertificateSecret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: consoleExternalTLSCertificateSecretName,
|
||||
Labels: map[string]string{
|
||||
operator.TenantLabel: tenantName,
|
||||
},
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
Immutable: &imm,
|
||||
Data: map[string][]byte{
|
||||
"tls.crt": tlsCrt,
|
||||
"tls.key": tlsKey,
|
||||
},
|
||||
}
|
||||
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &consoleExternalTLSCertificateSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Certificates used by the minio instance
|
||||
minInst.Spec.Console.ExternalCertSecret = &operator.LocalCertificateReference{
|
||||
Name: consoleExternalTLSCertificateSecretName,
|
||||
Type: "kubernetes.io/tls",
|
||||
}
|
||||
minInst.Spec.Console.ExternalCertSecret = externalCertSecret
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// set the service name if provided
|
||||
@@ -718,7 +685,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
|
||||
if tenantReq.ImagePullSecret != "" {
|
||||
imagePullSecret = tenantReq.ImagePullSecret
|
||||
} else if imagePullSecret, err = setImageRegistry(ctx, tenantName, tenantReq.ImageRegistry, clientset.CoreV1(), ns); err != nil {
|
||||
} else if imagePullSecret, err = setImageRegistry(ctx, tenantName, tenantReq.ImageRegistry, clientSet.CoreV1(), ns); err != nil {
|
||||
log.Println("error setting image registry secret:", err)
|
||||
return nil, err
|
||||
}
|
||||
@@ -753,7 +720,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
|
||||
|
||||
// Integratrions
|
||||
if os.Getenv("GKE_INTEGRATION") != "" {
|
||||
err := gkeIntegration(clientset, tenantName, ns, session.SessionToken)
|
||||
err := gkeIntegration(clientSet, tenantName, ns, session.SessionToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -832,7 +799,7 @@ func setImageRegistry(ctx context.Context, tenantName string, req *models.ImageR
|
||||
}
|
||||
|
||||
// updateTenantAction does an update on the minioTenant by patching the desired changes
|
||||
func updateTenantAction(ctx context.Context, operatorClient OperatorClient, clientset v1.CoreV1Interface, httpCl cluster.HTTPClientI, namespace string, params admin_api.UpdateTenantParams) error {
|
||||
func updateTenantAction(ctx context.Context, operatorClient OperatorClientI, clientset v1.CoreV1Interface, httpCl cluster.HTTPClientI, namespace string, params admin_api.UpdateTenantParams) error {
|
||||
imageToUpdate := params.Body.Image
|
||||
imageRegistryReq := params.Body.ImageRegistry
|
||||
|
||||
@@ -908,7 +875,7 @@ func getUpdateTenantResponse(session *models.Principal, params admin_api.UpdateT
|
||||
}
|
||||
|
||||
// addTenantZone creates a zone to a defined tenant
|
||||
func addTenantZone(ctx context.Context, operatorClient OperatorClient, params admin_api.TenantAddZoneParams) error {
|
||||
func addTenantZone(ctx context.Context, operatorClient OperatorClientI, params admin_api.TenantAddZoneParams) error {
|
||||
tenant, err := operatorClient.TenantGet(ctx, params.Namespace, params.Tenant, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1423,344 +1390,6 @@ func parseNodeSelectorTerm(term *corev1.NodeSelectorTerm) *models.NodeSelectorTe
|
||||
return &t
|
||||
}
|
||||
|
||||
func getTenantExternalClientCertificates(ctx context.Context, clientSet *kubernetes.Clientset, ns string, encryptionCfg *models.EncryptionConfiguration, secretName, tenantName string) (clientCertificates *operator.LocalCertificateReference, err error) {
|
||||
instanceExternalClientCertificateSecretName := fmt.Sprintf("%s-instance-external-client-mtls-certificates", secretName)
|
||||
// If there's an error during this process we delete all KES configuration secrets
|
||||
defer func() {
|
||||
if err != nil {
|
||||
errDelete := clientSet.CoreV1().Secrets(ns).Delete(ctx, instanceExternalClientCertificateSecretName, metav1.DeleteOptions{})
|
||||
if errDelete != nil {
|
||||
log.Print(errDelete)
|
||||
}
|
||||
return
|
||||
}
|
||||
}()
|
||||
imm := true
|
||||
// Secret to store KES clients TLS mTLSCertificates (mTLS authentication)
|
||||
clientTLSCrt, err := base64.StdEncoding.DecodeString(*encryptionCfg.Client.Crt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clientTLSKey, err := base64.StdEncoding.DecodeString(*encryptionCfg.Client.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instanceExternalClientCertificateSecret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: instanceExternalClientCertificateSecretName,
|
||||
Labels: map[string]string{
|
||||
operator.TenantLabel: tenantName,
|
||||
},
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
Immutable: &imm,
|
||||
Data: map[string][]byte{
|
||||
"tls.crt": clientTLSCrt,
|
||||
"tls.key": clientTLSKey,
|
||||
},
|
||||
}
|
||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &instanceExternalClientCertificateSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// KES client mTLSCertificates used by MinIO instance
|
||||
clientCertificates = &operator.LocalCertificateReference{
|
||||
Name: instanceExternalClientCertificateSecretName,
|
||||
Type: "kubernetes.io/tls",
|
||||
}
|
||||
return clientCertificates, nil
|
||||
}
|
||||
|
||||
func getKESConfiguration(ctx context.Context, clientSet *kubernetes.Clientset, ns string, encryptionCfg *models.EncryptionConfiguration, secretName, tenantName string, autoCert bool) (kesConfiguration *operator.KESConfig, err error) {
|
||||
// secrets used by the KES configuration
|
||||
instanceExternalClientCertificateSecretName := fmt.Sprintf("%s-instance-external-client-mtls-certificates", secretName)
|
||||
kesExternalCertificateSecretName := fmt.Sprintf("%s-kes-external-mtls-certificates", secretName)
|
||||
kesClientCertSecretName := fmt.Sprintf("%s-kes-mtls-certificates", secretName)
|
||||
kesConfigurationSecretName := fmt.Sprintf("%s-kes-configuration", secretName)
|
||||
// If there's an error during this process we delete all KES configuration secrets
|
||||
defer func() {
|
||||
if err != nil {
|
||||
errDelete := clientSet.CoreV1().Secrets(ns).Delete(ctx, instanceExternalClientCertificateSecretName, metav1.DeleteOptions{})
|
||||
if errDelete != nil {
|
||||
log.Print(errDelete)
|
||||
}
|
||||
errDelete = clientSet.CoreV1().Secrets(ns).Delete(ctx, kesExternalCertificateSecretName, metav1.DeleteOptions{})
|
||||
if errDelete != nil {
|
||||
log.Print(errDelete)
|
||||
}
|
||||
errDelete = clientSet.CoreV1().Secrets(ns).Delete(ctx, kesClientCertSecretName, metav1.DeleteOptions{})
|
||||
if errDelete != nil {
|
||||
log.Print(errDelete)
|
||||
}
|
||||
errDelete = clientSet.CoreV1().Secrets(ns).Delete(ctx, kesConfigurationSecretName, metav1.DeleteOptions{})
|
||||
if errDelete != nil {
|
||||
log.Print(errDelete)
|
||||
}
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
imm := true
|
||||
kesConfiguration = &operator.KESConfig{
|
||||
Image: "minio/kes:v0.11.0",
|
||||
Replicas: 1,
|
||||
Metadata: nil,
|
||||
}
|
||||
// Using custom image for KES
|
||||
if encryptionCfg.Image != "" {
|
||||
kesConfiguration.Image = encryptionCfg.Image
|
||||
}
|
||||
// if autoCert is enabled then Operator will generate the client certificates, calculate the client cert identity
|
||||
// and pass it to KES via the $MINIO_KES_IDENTITY variable
|
||||
clientCrtIdentity := "$MINIO_KES_IDENTITY"
|
||||
// Generate server certificates for KES only if autoCert is disabled
|
||||
if !autoCert {
|
||||
serverTLSCrt, err := base64.StdEncoding.DecodeString(*encryptionCfg.Server.Crt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
serverTLSKey, err := base64.StdEncoding.DecodeString(*encryptionCfg.Server.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Secret to store KES server TLS mTLSCertificates
|
||||
kesExternalCertificateSecret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kesExternalCertificateSecretName,
|
||||
Labels: map[string]string{
|
||||
operator.TenantLabel: tenantName,
|
||||
},
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
Immutable: &imm,
|
||||
Data: map[string][]byte{
|
||||
"tls.crt": serverTLSCrt,
|
||||
"tls.key": serverTLSKey,
|
||||
},
|
||||
}
|
||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &kesExternalCertificateSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// External mTLSCertificates used by KES
|
||||
kesConfiguration.ExternalCertSecret = &operator.LocalCertificateReference{
|
||||
Name: kesExternalCertificateSecretName,
|
||||
Type: "kubernetes.io/tls",
|
||||
}
|
||||
|
||||
// Client certificate for KES used by Minio to mTLS
|
||||
clientTLSCrt, err := base64.StdEncoding.DecodeString(*encryptionCfg.Client.Crt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Calculate the client cert identity based on the clientTLSCrt
|
||||
h := crypto.SHA256.New()
|
||||
certificate, err := kes.ParseCertificate(clientTLSCrt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.Write(certificate.RawSubjectPublicKeyInfo)
|
||||
clientCrtIdentity = hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// Default kesConfiguration for KES
|
||||
kesConfig := kes.ServerConfig{
|
||||
Addr: "0.0.0.0:7373",
|
||||
Root: "disabled",
|
||||
TLS: kes.TLS{
|
||||
KeyPath: "/tmp/kes/server.key",
|
||||
CertPath: "/tmp/kes/server.crt",
|
||||
},
|
||||
Policies: map[string]kes.Policy{
|
||||
"default-policy": {
|
||||
Paths: []string{
|
||||
"/v1/key/create/my-minio-key",
|
||||
"/v1/key/generate/my-minio-key",
|
||||
"/v1/key/decrypt/my-minio-key",
|
||||
},
|
||||
Identities: []kes.Identity{
|
||||
kes.Identity(clientCrtIdentity),
|
||||
},
|
||||
},
|
||||
},
|
||||
Cache: kes.Cache{
|
||||
Expiry: &kes.Expiry{
|
||||
Any: 5 * time.Minute,
|
||||
Unused: 20 * time.Second,
|
||||
},
|
||||
},
|
||||
Log: kes.Log{
|
||||
Error: "on",
|
||||
Audit: "off",
|
||||
},
|
||||
Keys: kes.Keys{},
|
||||
}
|
||||
|
||||
// operator will mount the mTLSCertificates in the following paths
|
||||
// therefore we set these values in the KES yaml kesConfiguration
|
||||
var mTLSClientCrtPath = "/tmp/kes/client.crt"
|
||||
var mTLSClientKeyPath = "/tmp/kes/client.key"
|
||||
var mTLSClientCaPath = "/tmp/kes/ca.crt"
|
||||
// map to hold mTLSCertificates for KES mTLS against Vault
|
||||
mTLSCertificates := map[string][]byte{}
|
||||
|
||||
// if encryption is enabled and encryption is configured to use Vault
|
||||
if encryptionCfg.Vault != nil {
|
||||
// Initialize Vault Config
|
||||
|
||||
kesConfig.Keys.Vault = &kes.Vault{
|
||||
Endpoint: *encryptionCfg.Vault.Endpoint,
|
||||
EnginePath: encryptionCfg.Vault.Engine,
|
||||
Namespace: encryptionCfg.Vault.Namespace,
|
||||
Prefix: encryptionCfg.Vault.Prefix,
|
||||
Status: &kes.VaultStatus{
|
||||
Ping: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
// Vault AppRole credentials
|
||||
if encryptionCfg.Vault.Approle != nil {
|
||||
kesConfig.Keys.Vault.AppRole = &kes.AppRole{
|
||||
EnginePath: encryptionCfg.Vault.Approle.Engine,
|
||||
ID: *encryptionCfg.Vault.Approle.ID,
|
||||
Secret: *encryptionCfg.Vault.Approle.Secret,
|
||||
Retry: 15 * time.Second,
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New("approle credentials missing for kes")
|
||||
}
|
||||
|
||||
// Vault mTLS kesConfiguration
|
||||
if encryptionCfg.Vault.TLS != nil {
|
||||
vaultTLSConfig := encryptionCfg.Vault.TLS
|
||||
kesConfig.Keys.Vault.TLS = &kes.VaultTLS{}
|
||||
if vaultTLSConfig.Crt != "" {
|
||||
clientCrt, err := base64.StdEncoding.DecodeString(vaultTLSConfig.Crt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mTLSCertificates["client.crt"] = clientCrt
|
||||
kesConfig.Keys.Vault.TLS.CertPath = mTLSClientCrtPath
|
||||
}
|
||||
if vaultTLSConfig.Key != "" {
|
||||
clientKey, err := base64.StdEncoding.DecodeString(vaultTLSConfig.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mTLSCertificates["client.key"] = clientKey
|
||||
kesConfig.Keys.Vault.TLS.KeyPath = mTLSClientKeyPath
|
||||
}
|
||||
if vaultTLSConfig.Ca != "" {
|
||||
caCrt, err := base64.StdEncoding.DecodeString(vaultTLSConfig.Ca)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mTLSCertificates["ca.crt"] = caCrt
|
||||
kesConfig.Keys.Vault.TLS.CAPath = mTLSClientCaPath
|
||||
}
|
||||
}
|
||||
} else if encryptionCfg.Aws != nil {
|
||||
// Initialize AWS
|
||||
kesConfig.Keys.Aws = &kes.Aws{
|
||||
SecretsManager: &kes.AwsSecretManager{},
|
||||
}
|
||||
// AWS basic kesConfiguration
|
||||
if encryptionCfg.Aws.Secretsmanager != nil {
|
||||
kesConfig.Keys.Aws.SecretsManager.Endpoint = *encryptionCfg.Aws.Secretsmanager.Endpoint
|
||||
kesConfig.Keys.Aws.SecretsManager.Region = *encryptionCfg.Aws.Secretsmanager.Region
|
||||
kesConfig.Keys.Aws.SecretsManager.KmsKey = encryptionCfg.Aws.Secretsmanager.Kmskey
|
||||
// AWS credentials
|
||||
if encryptionCfg.Aws.Secretsmanager.Credentials != nil {
|
||||
kesConfig.Keys.Aws.SecretsManager.Login = &kes.AwsSecretManagerLogin{
|
||||
AccessKey: *encryptionCfg.Aws.Secretsmanager.Credentials.Accesskey,
|
||||
SecretKey: *encryptionCfg.Aws.Secretsmanager.Credentials.Secretkey,
|
||||
SessionToken: encryptionCfg.Aws.Secretsmanager.Credentials.Token,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if encryptionCfg.Gemalto != nil {
|
||||
// Initialize Gemalto
|
||||
kesConfig.Keys.Gemalto = &kes.Gemalto{
|
||||
KeySecure: &kes.GemaltoKeySecure{},
|
||||
}
|
||||
// Gemalto Configuration
|
||||
if encryptionCfg.Gemalto.Keysecure != nil {
|
||||
kesConfig.Keys.Gemalto.KeySecure.Endpoint = *encryptionCfg.Gemalto.Keysecure.Endpoint
|
||||
// Gemalto TLS kesConfiguration
|
||||
if encryptionCfg.Gemalto.Keysecure.TLS != nil {
|
||||
if encryptionCfg.Gemalto.Keysecure.TLS.Ca != nil {
|
||||
caCrt, err := base64.StdEncoding.DecodeString(*encryptionCfg.Gemalto.Keysecure.TLS.Ca)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mTLSCertificates["ca.crt"] = caCrt
|
||||
kesConfig.Keys.Gemalto.KeySecure.TLS = &kes.GemaltoTLS{
|
||||
CAPath: mTLSClientCaPath,
|
||||
}
|
||||
}
|
||||
}
|
||||
// Gemalto Login
|
||||
if encryptionCfg.Gemalto.Keysecure.Credentials != nil {
|
||||
kesConfig.Keys.Gemalto.KeySecure.Credentials = &kes.GemaltoCredentials{
|
||||
Token: *encryptionCfg.Gemalto.Keysecure.Credentials.Token,
|
||||
Domain: *encryptionCfg.Gemalto.Keysecure.Credentials.Domain,
|
||||
Retry: 15 * time.Second,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if mTLSCertificates contains elements we create the kubernetes secret
|
||||
if len(mTLSCertificates) > 0 {
|
||||
// Secret to store KES mTLS kesConfiguration
|
||||
kesClientCertSecret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kesClientCertSecretName,
|
||||
Labels: map[string]string{
|
||||
operator.TenantLabel: tenantName,
|
||||
},
|
||||
},
|
||||
Immutable: &imm,
|
||||
Data: mTLSCertificates,
|
||||
}
|
||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &kesClientCertSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// kubernetes generic secret
|
||||
kesConfiguration.ClientCertSecret = &operator.LocalCertificateReference{
|
||||
Name: kesClientCertSecretName,
|
||||
}
|
||||
}
|
||||
|
||||
// Generate Yaml kesConfiguration for KES
|
||||
serverConfigYaml, err := yaml.Marshal(kesConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Secret to store KES server kesConfiguration
|
||||
kesConfigurationSecret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kesConfigurationSecretName,
|
||||
Labels: map[string]string{
|
||||
operator.TenantLabel: tenantName,
|
||||
},
|
||||
},
|
||||
Immutable: &imm,
|
||||
Data: map[string][]byte{
|
||||
"server-config.yaml": serverConfigYaml,
|
||||
},
|
||||
}
|
||||
_, err = clientSet.CoreV1().Secrets(ns).Create(ctx, &kesConfigurationSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Configuration used by KES
|
||||
kesConfiguration.Configuration = &corev1.LocalObjectReference{
|
||||
Name: kesConfigurationSecretName,
|
||||
}
|
||||
return kesConfiguration, nil
|
||||
}
|
||||
|
||||
func getTenantUpdateZoneResponse(session *models.Principal, params admin_api.TenantUpdateZonesParams) (*models.Tenant, error) {
|
||||
ctx := context.Background()
|
||||
opClientClientSet, err := cluster.OperatorClient(session.SessionToken)
|
||||
@@ -1789,7 +1418,7 @@ func getTenantUpdateZoneResponse(session *models.Principal, params admin_api.Ten
|
||||
// It does the equivalent to a PUT request on Tenant's zones
|
||||
func updateTenantZones(
|
||||
ctx context.Context,
|
||||
operatorClient OperatorClient,
|
||||
operatorClient OperatorClientI,
|
||||
namespace string,
|
||||
tenantName string,
|
||||
zonesReq []*models.Zone) (*operator.Tenant, error) {
|
||||
|
||||
516
restapi/admin_tenants_helper.go
Normal file
516
restapi/admin_tenants_helper.go
Normal file
@@ -0,0 +1,516 @@
|
||||
// This file is part of MinIO Kubernetes Cloud
|
||||
// Copyright (c) 2020 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package restapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"errors"
|
||||
|
||||
"github.com/minio/console/cluster"
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/pkg/kes"
|
||||
"github.com/minio/console/restapi/operations/admin_api"
|
||||
operator "github.com/minio/operator/pkg/apis/minio.min.io/v1"
|
||||
"gopkg.in/yaml.v2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// tenantUpdateCertificates receives the keyPair certificates (public and private keys) for Minio and Console and will try
|
||||
// to replace the existing kubernetes secrets with the new values, then will restart the affected pods so the new volumes can be mounted
|
||||
func tenantUpdateCertificates(ctx context.Context, operatorClient OperatorClientI, clientSet K8sClientI, namespace string, params admin_api.TenantUpdateCertificateParams) error {
|
||||
tenantName := params.Tenant
|
||||
tenant, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
secretName := fmt.Sprintf("%s-secret", tenantName)
|
||||
body := params.Body
|
||||
// check if MinIO is deployed with external certs and user provided new MinIO keypair
|
||||
if tenant.ExternalCert() && body.Minio != nil {
|
||||
minioCertSecretName := fmt.Sprintf("%s-instance-external-certificates", secretName)
|
||||
// update certificates
|
||||
if _, err := createOrReplaceExternalCertSecret(ctx, clientSet, namespace, body.Minio, minioCertSecretName, tenantName); err != nil {
|
||||
return err
|
||||
}
|
||||
// restart MinIO pods
|
||||
err := clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
|
||||
LabelSelector: fmt.Sprintf("%s=%s", operator.TenantLabel, tenantName),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// check if Console is deployed with external certs and user provided new Console keypair
|
||||
if tenant.ConsoleExternalCert() && tenant.HasConsoleEnabled() && body.Console != nil {
|
||||
consoleCertSecretName := fmt.Sprintf("%s-console-external-certificates", secretName)
|
||||
// update certificates
|
||||
if _, err := createOrReplaceExternalCertSecret(ctx, clientSet, namespace, body.Console, consoleCertSecretName, tenantName); err != nil {
|
||||
return err
|
||||
}
|
||||
// restart Console pods
|
||||
err := clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
|
||||
LabelSelector: fmt.Sprintf("%s=%s", operator.ConsoleTenantLabel, fmt.Sprintf("%s-console", tenantName)),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getTenantUpdateCertificatesResponse wrapper of tenantUpdateCertificates
|
||||
func getTenantUpdateCertificatesResponse(session *models.Principal, params admin_api.TenantUpdateCertificateParams) error {
|
||||
ctx := context.Background()
|
||||
// get Kubernetes Client
|
||||
clientSet, err := cluster.K8sClient(session.SessionToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k8sClient := k8sClient{
|
||||
client: clientSet,
|
||||
}
|
||||
opClientClientSet, err := cluster.OperatorClient(session.SessionToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opClient := operatorClient{
|
||||
client: opClientClientSet,
|
||||
}
|
||||
if err := tenantUpdateCertificates(ctx, &opClient, &k8sClient, params.Namespace, params); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// tenantUpdateEncryption allow user to update KES server certificates, KES client certificates (used by MinIO for mTLS) and KES configuration (KMS configuration, credentials, etc)
|
||||
func tenantUpdateEncryption(ctx context.Context, operatorClient OperatorClientI, clientSet K8sClientI, namespace string, params admin_api.TenantUpdateEncryptionParams) error {
|
||||
tenantName := params.Tenant
|
||||
secretName := fmt.Sprintf("%s-secret", tenantName)
|
||||
tenant, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{})
|
||||
body := params.Body
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Check if encryption is enabled for MinIO via KES
|
||||
if tenant.HasKESEnabled() {
|
||||
// check if KES is deployed with external certificates and user provided new server keypair
|
||||
if tenant.KESExternalCert() && body.Server != nil {
|
||||
kesExternalCertSecretName := fmt.Sprintf("%s-kes-external-cert", secretName)
|
||||
// update certificates
|
||||
if _, err := createOrReplaceExternalCertSecret(ctx, clientSet, namespace, body.Server, kesExternalCertSecretName, tenantName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// check if Tenant is deployed with external client certificates and user provided new client keypaiir
|
||||
if tenant.ExternalClientCert() && body.Client != nil {
|
||||
tenantExternalClientCertSecretName := fmt.Sprintf("%s-tenant-external-client-cert", secretName)
|
||||
// Update certificates
|
||||
if _, err := createOrReplaceExternalCertSecret(ctx, clientSet, namespace, body.Client, tenantExternalClientCertSecretName, tenantName); err != nil {
|
||||
return err
|
||||
}
|
||||
// Restart MinIO pods to mount the new client secrets
|
||||
err := clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
|
||||
LabelSelector: fmt.Sprintf("%s=%s", operator.TenantLabel, tenantName),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// update KES identities in kes-configuration.yaml secret
|
||||
kesConfigurationSecretName := fmt.Sprintf("%s-kes-configuration", secretName)
|
||||
kesClientCertSecretName := fmt.Sprintf("%s-kes-client-cert", secretName)
|
||||
_, _, err := createOrReplaceKesConfigurationSecrets(ctx, clientSet, namespace, body, kesConfigurationSecretName, kesClientCertSecretName, tenantName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Restart KES pods to mount the new configuration
|
||||
err = clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
|
||||
LabelSelector: fmt.Sprintf("%s=%s", operator.KESInstanceLabel, fmt.Sprintf("%s-kes", tenantName)),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getTenantUpdateEncryptionResponse is a wrapper for tenantUpdateEncryption
|
||||
func getTenantUpdateEncryptionResponse(session *models.Principal, params admin_api.TenantUpdateEncryptionParams) error {
|
||||
ctx := context.Background()
|
||||
// get Kubernetes Client
|
||||
clientSet, err := cluster.K8sClient(session.SessionToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k8sClient := k8sClient{
|
||||
client: clientSet,
|
||||
}
|
||||
opClientClientSet, err := cluster.OperatorClient(session.SessionToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opClient := operatorClient{
|
||||
client: opClientClientSet,
|
||||
}
|
||||
if err := tenantUpdateEncryption(ctx, &opClient, &k8sClient, params.Namespace, params); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getKESConfiguration will generate the KES server certificate secrets, the tenant client secrets for mTLS authentication between MinIO and KES and the
|
||||
// kes-configuration.yaml file used by the KES service (how to connect to the external KMS, eg: Vault, AWS, Gemalto, etc)
|
||||
func getKESConfiguration(ctx context.Context, clientSet K8sClientI, ns string, encryptionCfg *models.EncryptionConfiguration, secretName, tenantName string, autoCert bool) (kesConfiguration *operator.KESConfig, err error) {
|
||||
// Secrets used by the MiniO tenant service
|
||||
//
|
||||
// tenantExternalClientCertSecretName is the name of the secret that will store the certificates for mTLS between MinIO and the KES, eg: app.key and app.crt
|
||||
tenantExternalClientCertSecretName := fmt.Sprintf("%s-tenant-external-client-cert", secretName)
|
||||
// Secrets used by the KES service
|
||||
//
|
||||
// kesExternalCertSecretName is the name of the secret that will store the certificates for TLS in the KES server, eg: server.key and server.crt
|
||||
kesExternalCertSecretName := fmt.Sprintf("%s-kes-external-cert", secretName)
|
||||
// kesClientCertSecretName is the name of the secret that will store the certificates for mTLS between KES and the KMS, eg: mTLS with Vault or Gemalto KMS
|
||||
kesClientCertSecretName := fmt.Sprintf("%s-kes-client-cert", secretName)
|
||||
// kesConfigurationSecretName is the name of the secret that will store the configuration file, eg: kes-configuration.yaml
|
||||
kesConfigurationSecretName := fmt.Sprintf("%s-kes-configuration", secretName)
|
||||
// if there's an error during this process we delete all KES configuration secrets
|
||||
defer func() {
|
||||
if err != nil {
|
||||
errDelete := clientSet.deleteSecret(ctx, ns, tenantExternalClientCertSecretName, metav1.DeleteOptions{})
|
||||
if errDelete != nil {
|
||||
log.Print(errDelete)
|
||||
}
|
||||
errDelete = clientSet.deleteSecret(ctx, ns, kesExternalCertSecretName, metav1.DeleteOptions{})
|
||||
if errDelete != nil {
|
||||
log.Print(errDelete)
|
||||
}
|
||||
errDelete = clientSet.deleteSecret(ctx, ns, kesClientCertSecretName, metav1.DeleteOptions{})
|
||||
if errDelete != nil {
|
||||
log.Print(errDelete)
|
||||
}
|
||||
errDelete = clientSet.deleteSecret(ctx, ns, kesConfigurationSecretName, metav1.DeleteOptions{})
|
||||
if errDelete != nil {
|
||||
log.Print(errDelete)
|
||||
}
|
||||
return
|
||||
}
|
||||
}()
|
||||
kesConfiguration = &operator.KESConfig{
|
||||
Image: "minio/kes:v0.11.0",
|
||||
Replicas: 1,
|
||||
Metadata: nil,
|
||||
}
|
||||
// Using custom image for KES
|
||||
if encryptionCfg.Image != "" {
|
||||
kesConfiguration.Image = encryptionCfg.Image
|
||||
}
|
||||
// Generate server certificates for KES only if autoCert is disabled
|
||||
if !autoCert {
|
||||
kesExternalCertSecret, err := createOrReplaceExternalCertSecret(ctx, clientSet, ns, encryptionCfg.Server, kesExternalCertSecretName, tenantName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// External TLS certificates used by KES
|
||||
kesConfiguration.ExternalCertSecret = kesExternalCertSecret
|
||||
}
|
||||
// Prepare kesConfiguration for KES
|
||||
serverConfigSecret, clientCertSecret, err := createOrReplaceKesConfigurationSecrets(ctx, clientSet, ns, encryptionCfg, kesConfigurationSecretName, kesClientCertSecretName, tenantName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Configuration used by KES
|
||||
kesConfiguration.Configuration = serverConfigSecret
|
||||
kesConfiguration.ClientCertSecret = clientCertSecret
|
||||
|
||||
return kesConfiguration, nil
|
||||
}
|
||||
|
||||
// createOrReplaceExternalCertSecret receives a keypair, public and private key, encoded in base64, decode it and generate a new kubernetes secret
|
||||
// to be used by the operator for TLS encryption
|
||||
func createOrReplaceExternalCertSecret(ctx context.Context, clientSet K8sClientI, ns string, keyPair *models.KeyPairConfiguration, secretName, tenantName string) (*operator.LocalCertificateReference, error) {
|
||||
if keyPair == nil || keyPair.Crt == nil || keyPair.Key == nil || *keyPair.Crt == "" || *keyPair.Key == "" {
|
||||
return nil, errors.New("certificate files must not be empty")
|
||||
}
|
||||
// delete secret with same name if exists
|
||||
err := clientSet.deleteSecret(ctx, ns, secretName, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
// log the error if any and continue
|
||||
log.Println(err)
|
||||
}
|
||||
imm := true
|
||||
tlsCrt, err := base64.StdEncoding.DecodeString(*keyPair.Crt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsKey, err := base64.StdEncoding.DecodeString(*keyPair.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
externalTLSCertificateSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretName,
|
||||
Labels: map[string]string{
|
||||
operator.TenantLabel: tenantName,
|
||||
},
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
Immutable: &imm,
|
||||
Data: map[string][]byte{
|
||||
"tls.crt": tlsCrt,
|
||||
"tls.key": tlsKey,
|
||||
},
|
||||
}
|
||||
_, err = clientSet.createSecret(ctx, ns, externalTLSCertificateSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Certificates used by the minio instance
|
||||
return &operator.LocalCertificateReference{
|
||||
Name: secretName,
|
||||
Type: "kubernetes.io/tls",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createOrReplaceKesConfigurationSecrets(ctx context.Context, clientSet K8sClientI, ns string, encryptionCfg *models.EncryptionConfiguration, kesConfigurationSecretName, kesClientCertSecretName, tenantName string) (*corev1.LocalObjectReference, *operator.LocalCertificateReference, error) {
|
||||
// delete KES configuration secret if exists
|
||||
if err := clientSet.deleteSecret(ctx, ns, kesConfigurationSecretName, metav1.DeleteOptions{}); err != nil {
|
||||
// log the error if any and continue
|
||||
log.Println(err)
|
||||
}
|
||||
// delete KES client cert secret if exists
|
||||
if err := clientSet.deleteSecret(ctx, ns, kesClientCertSecretName, metav1.DeleteOptions{}); err != nil {
|
||||
// log the error if any and continue
|
||||
log.Println(err)
|
||||
}
|
||||
// if autoCert is enabled then Operator will generate the client certificates, calculate the client cert identity
|
||||
// and pass it to KES via the $MINIO_KES_IDENTITY variable
|
||||
clientCrtIdentity := "$MINIO_KES_IDENTITY"
|
||||
// If a client certificate is provided proceed to calculate the identity
|
||||
if encryptionCfg.Client != nil {
|
||||
// Client certificate for KES used by Minio to mTLS
|
||||
clientTLSCrt, err := base64.StdEncoding.DecodeString(*encryptionCfg.Client.Crt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Calculate the client cert identity based on the clientTLSCrt
|
||||
h := crypto.SHA256.New()
|
||||
certificate, err := kes.ParseCertificate(clientTLSCrt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
h.Write(certificate.RawSubjectPublicKeyInfo)
|
||||
clientCrtIdentity = hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
// Default kesConfiguration for KES
|
||||
kesConfig := &kes.ServerConfig{
|
||||
Addr: "0.0.0.0:7373",
|
||||
Root: "disabled",
|
||||
TLS: kes.TLS{
|
||||
KeyPath: "/tmp/kes/server.key",
|
||||
CertPath: "/tmp/kes/server.crt",
|
||||
},
|
||||
Policies: map[string]kes.Policy{
|
||||
"default-policy": {
|
||||
Paths: []string{
|
||||
"/v1/key/create/my-minio-key",
|
||||
"/v1/key/generate/my-minio-key",
|
||||
"/v1/key/decrypt/my-minio-key",
|
||||
},
|
||||
Identities: []kes.Identity{
|
||||
kes.Identity(clientCrtIdentity),
|
||||
},
|
||||
},
|
||||
},
|
||||
Cache: kes.Cache{
|
||||
Expiry: &kes.Expiry{
|
||||
Any: 5 * time.Minute,
|
||||
Unused: 20 * time.Second,
|
||||
},
|
||||
},
|
||||
Log: kes.Log{
|
||||
Error: "on",
|
||||
Audit: "off",
|
||||
},
|
||||
Keys: kes.Keys{},
|
||||
}
|
||||
// operator will mount the mTLSCertificates in the following paths
|
||||
// therefore we set these values in the KES yaml kesConfiguration
|
||||
var mTLSClientCrtPath = "/tmp/kes/client.crt"
|
||||
var mTLSClientKeyPath = "/tmp/kes/client.key"
|
||||
var mTLSClientCaPath = "/tmp/kes/ca.crt"
|
||||
// map to hold mTLSCertificates for KES mTLS against Vault
|
||||
mTLSCertificates := map[string][]byte{}
|
||||
// if encryption is enabled and encryption is configured to use Vault
|
||||
if encryptionCfg.Vault != nil {
|
||||
// Initialize Vault Config
|
||||
kesConfig.Keys.Vault = &kes.Vault{
|
||||
Endpoint: *encryptionCfg.Vault.Endpoint,
|
||||
EnginePath: encryptionCfg.Vault.Engine,
|
||||
Namespace: encryptionCfg.Vault.Namespace,
|
||||
Prefix: encryptionCfg.Vault.Prefix,
|
||||
Status: &kes.VaultStatus{
|
||||
Ping: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
// Vault AppRole credentials
|
||||
if encryptionCfg.Vault.Approle != nil {
|
||||
kesConfig.Keys.Vault.AppRole = &kes.AppRole{
|
||||
EnginePath: encryptionCfg.Vault.Approle.Engine,
|
||||
ID: *encryptionCfg.Vault.Approle.ID,
|
||||
Secret: *encryptionCfg.Vault.Approle.Secret,
|
||||
Retry: 15 * time.Second,
|
||||
}
|
||||
} else {
|
||||
return nil, nil, errors.New("approle credentials missing for kes")
|
||||
}
|
||||
// Vault mTLS kesConfiguration
|
||||
if encryptionCfg.Vault.TLS != nil {
|
||||
vaultTLSConfig := encryptionCfg.Vault.TLS
|
||||
kesConfig.Keys.Vault.TLS = &kes.VaultTLS{}
|
||||
if vaultTLSConfig.Crt != "" {
|
||||
clientCrt, err := base64.StdEncoding.DecodeString(vaultTLSConfig.Crt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
mTLSCertificates["client.crt"] = clientCrt
|
||||
kesConfig.Keys.Vault.TLS.CertPath = mTLSClientCrtPath
|
||||
}
|
||||
if vaultTLSConfig.Key != "" {
|
||||
clientKey, err := base64.StdEncoding.DecodeString(vaultTLSConfig.Key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
mTLSCertificates["client.key"] = clientKey
|
||||
kesConfig.Keys.Vault.TLS.KeyPath = mTLSClientKeyPath
|
||||
}
|
||||
if vaultTLSConfig.Ca != "" {
|
||||
caCrt, err := base64.StdEncoding.DecodeString(vaultTLSConfig.Ca)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
mTLSCertificates["ca.crt"] = caCrt
|
||||
kesConfig.Keys.Vault.TLS.CAPath = mTLSClientCaPath
|
||||
}
|
||||
}
|
||||
} else if encryptionCfg.Aws != nil {
|
||||
// Initialize AWS
|
||||
kesConfig.Keys.Aws = &kes.Aws{
|
||||
SecretsManager: &kes.AwsSecretManager{},
|
||||
}
|
||||
// AWS basic kesConfiguration
|
||||
if encryptionCfg.Aws.Secretsmanager != nil {
|
||||
kesConfig.Keys.Aws.SecretsManager.Endpoint = *encryptionCfg.Aws.Secretsmanager.Endpoint
|
||||
kesConfig.Keys.Aws.SecretsManager.Region = *encryptionCfg.Aws.Secretsmanager.Region
|
||||
kesConfig.Keys.Aws.SecretsManager.KmsKey = encryptionCfg.Aws.Secretsmanager.Kmskey
|
||||
// AWS credentials
|
||||
if encryptionCfg.Aws.Secretsmanager.Credentials != nil {
|
||||
kesConfig.Keys.Aws.SecretsManager.Login = &kes.AwsSecretManagerLogin{
|
||||
AccessKey: *encryptionCfg.Aws.Secretsmanager.Credentials.Accesskey,
|
||||
SecretKey: *encryptionCfg.Aws.Secretsmanager.Credentials.Secretkey,
|
||||
SessionToken: encryptionCfg.Aws.Secretsmanager.Credentials.Token,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if encryptionCfg.Gemalto != nil {
|
||||
// Initialize Gemalto
|
||||
kesConfig.Keys.Gemalto = &kes.Gemalto{
|
||||
KeySecure: &kes.GemaltoKeySecure{},
|
||||
}
|
||||
// Gemalto Configuration
|
||||
if encryptionCfg.Gemalto.Keysecure != nil {
|
||||
kesConfig.Keys.Gemalto.KeySecure.Endpoint = *encryptionCfg.Gemalto.Keysecure.Endpoint
|
||||
// Gemalto TLS kesConfiguration
|
||||
if encryptionCfg.Gemalto.Keysecure.TLS != nil {
|
||||
if encryptionCfg.Gemalto.Keysecure.TLS.Ca != nil {
|
||||
caCrt, err := base64.StdEncoding.DecodeString(*encryptionCfg.Gemalto.Keysecure.TLS.Ca)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
mTLSCertificates["ca.crt"] = caCrt
|
||||
kesConfig.Keys.Gemalto.KeySecure.TLS = &kes.GemaltoTLS{
|
||||
CAPath: mTLSClientCaPath,
|
||||
}
|
||||
}
|
||||
}
|
||||
// Gemalto Login
|
||||
if encryptionCfg.Gemalto.Keysecure.Credentials != nil {
|
||||
kesConfig.Keys.Gemalto.KeySecure.Credentials = &kes.GemaltoCredentials{
|
||||
Token: *encryptionCfg.Gemalto.Keysecure.Credentials.Token,
|
||||
Domain: *encryptionCfg.Gemalto.Keysecure.Credentials.Domain,
|
||||
Retry: 15 * time.Second,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
imm := true
|
||||
// if mTLSCertificates contains elements we create the kubernetes secret
|
||||
var clientCertSecretReference *operator.LocalCertificateReference
|
||||
if len(mTLSCertificates) > 0 {
|
||||
// Secret to store KES mTLS kesConfiguration to authenticate against a KMS
|
||||
kesClientCertSecret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kesClientCertSecretName,
|
||||
Labels: map[string]string{
|
||||
operator.TenantLabel: tenantName,
|
||||
},
|
||||
},
|
||||
Immutable: &imm,
|
||||
Data: mTLSCertificates,
|
||||
}
|
||||
_, err := clientSet.createSecret(ctx, ns, &kesClientCertSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// kubernetes generic secret
|
||||
clientCertSecretReference = &operator.LocalCertificateReference{
|
||||
Name: kesClientCertSecretName,
|
||||
}
|
||||
}
|
||||
// Generate Yaml kesConfiguration for KES
|
||||
serverConfigYaml, err := yaml.Marshal(kesConfig)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Secret to store KES server kesConfiguration
|
||||
kesConfigurationSecret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: kesConfigurationSecretName,
|
||||
Labels: map[string]string{
|
||||
operator.TenantLabel: tenantName,
|
||||
},
|
||||
},
|
||||
Immutable: &imm,
|
||||
Data: map[string][]byte{
|
||||
"server-config.yaml": serverConfigYaml,
|
||||
},
|
||||
}
|
||||
_, err = clientSet.createSecret(ctx, ns, &kesConfigurationSecret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &corev1.LocalObjectReference{
|
||||
Name: kesConfigurationSecretName,
|
||||
}, clientCertSecretReference, nil
|
||||
}
|
||||
456
restapi/admin_tenants_helper_test.go
Normal file
456
restapi/admin_tenants_helper_test.go
Normal file
@@ -0,0 +1,456 @@
|
||||
package restapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
"github.com/minio/console/restapi/operations/admin_api"
|
||||
operator "github.com/minio/operator/pkg/apis/minio.min.io/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
var DeletePodCollectionMock func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||
var DeleteSecretMock func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error
|
||||
var CreateSecretMock func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error)
|
||||
|
||||
func (c k8sClientMock) deletePodCollection(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||
return DeletePodCollectionMock(ctx, namespace, opts, listOpts)
|
||||
}
|
||||
|
||||
func (c k8sClientMock) deleteSecret(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||
return DeleteSecretMock(ctx, namespace, name, opts)
|
||||
}
|
||||
|
||||
func (c k8sClientMock) createSecret(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||
return CreateSecretMock(ctx, namespace, secret, opts)
|
||||
}
|
||||
|
||||
func Test_tenantUpdateCertificates(t *testing.T) {
|
||||
k8sClient := k8sClientMock{}
|
||||
opClient := opClientMock{}
|
||||
crt := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUUzRENDQTBTZ0F3SUJBZ0lRS0pDalNyK0xaMnJrYVo5ODAvZnV5akFOQmdrcWhraUc5dzBCQVFzRkFEQ0IKdFRFZU1Cd0dBMVVFQ2hNVmJXdGpaWEowSUdSbGRtVnNiM0J0Wlc1MElFTkJNVVV3UXdZRFZRUUxERHhoYkdWMgpjMnRBVEdWdWFXNXpMVTFoWTBKdmIyc3RVSEp2TG14dlkyRnNJQ2hNWlc1cGJpQkJiR1YyYzJ0cElFaDFaWEowCllTQkJjbWxoY3lreFREQktCZ05WQkFNTVEyMXJZMlZ5ZENCaGJHVjJjMnRBVEdWdWFXNXpMVTFoWTBKdmIyc3QKVUhKdkxteHZZMkZzSUNoTVpXNXBiaUJCYkdWMmMydHBJRWgxWlhKMFlTQkJjbWxoY3lrd0hoY05NVGt3TmpBeApNREF3TURBd1doY05NekF3T0RBeU1ERTFNekEzV2pCaU1TY3dKUVlEVlFRS0V4NXRhMk5sY25RZ1pHVjJaV3h2CmNHMWxiblFnWTJWeWRHbG1hV05oZEdVeE56QTFCZ05WQkFzTUxtRnNaWFp6YTBCMGFXWmhMbXh2WTJGc0lDaE0KWlc1cGJpQkJiR1YyYzJ0cElFaDFaWEowWVNCQmNtbGhjeWt3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQgpEd0F3Z2dFS0FvSUJBUUM2dlhLVyswWmhJQUNycmpxTU9QZ3VSdGpSemk1L0VxK2JvZTJkQ1BpT3djdXo0WFlhCm1rVlcxSkhBS3VTc0I1UHE0QnFSRXFueUhYT0ZROWQ1bEFjRGNDYmhlTFRVb2h2ZkhOWW9SdWRrYkZ3RzAyOFQKdVMxTFNtcHU5VjhFU2Q0Q3BiOGRvUkcvUW8vRTF4RGk5STFhNVhoeUdHTTNsUFlYQU1HU1ZkWUNNNzh0M2ZLTwp0NFVlcEt6d2dFQ2NKRVg4MVFoem1ZT25ELysyazNxSVppZU9nOGFkbDNFUWV2eFBISXlXQ1JkaDJZTkZsRi9rCmEwTzQyRVl2NVNUT1N0dzI2TzMwTVRrcEg0dzRRZm9VV3BnZU93MDZyYTluRHdzV3VhMUZIaHlKZmxOanR1USsKU0NlaDdqTVlVUThYV1JkbXVHbzFRT0g5cjdDKy82L1JhMlZIQWdNQkFBR2pnYmt3Z2JZd0RnWURWUjBQQVFILwpCQVFEQWdXZ01CTUdBMVVkSlFRTU1Bb0dDQ3NHQVFVRkJ3TUJNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqCkJCZ3dGb0FVNHg4NUIyeGVlQzg0UEdvM1dZVWwxRGVvZlFNd1lBWURWUjBSQkZrd1Y0SWpLaTV0YVc1cGJ5MWgKYkdWMmMyc3Ribk11YzNaakxtTnNkWE4wWlhJdWJHOWpZV3lDTUNvdWFHOXVaWGwzWld4c0xXaHNMbTFwYm1sdgpMV0ZzWlhaemF5MXVjeTV6ZG1NdVkyeDFjM1JsY2k1c2IyTmhiREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBWUVBCnZnMFlIVGtzd3Z4NEE5ZXl0b1V3eTBOSFVjQXpuNy9BVCt3WEt6d3Fqa0RiS3hVYlFTMFNQVVI4SkVDMkpuUUgKU3pTNGFCNXRURVRYZUcrbHJZVU02b0RNcXlIalpUN1NJaW83OUNxOFloWWxORU9qMkhvaXdxalczZm10UU9kVApoVG1tS01lRnZleHo2cnRxbHp0cVdKa3kvOGd1MkMrMWw5UDFFUmhFNDZZY0puVmJ5REFTSGNvV2tiZVhFUGErCjNpNFd4bU1yMDlNZXFTNkFUb2NKanFBeEtYcURYWmlFZjRUVEp1ZTRBQ2s4WmhqaEtUUEV6RnQ3WllVaHY3dVoKdlZCOXhla2FqRzdMRU5kSHZncXVMRUxUV3czWkpBaXpSTU5KUUpzZU11LzdQN1NIeXRKTVJYdlVwd2R2dWhDOApKNm54aGRmUS91QVlQY1lHdlU5NUZPZ1NjWVZqNW1WQktXM0ZHbkl2YzZuamQ1OFhBSTE3dlk0K0ZZTnY4M2UxCm9mOGlxRFdWNTFyT1FlbG9FZFdmdHkvZTI2bXVWUUQzQlVjY2Z5SWpGYy9SeGNHdm5maUEwUm1uRDNkWFcyZ0oKUHFTd01ZZ3hxQndqMm1Qck5jdkFWY3BOeWRjTWJKOTFIOHRWY0ttRHMrY1NiV0tnblpmKzUvZm5yaTdmU3FLUQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
|
||||
key := "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRQzZ2WEtXKzBaaElBQ3IKcmpxTU9QZ3VSdGpSemk1L0VxK2JvZTJkQ1BpT3djdXo0WFlhbWtWVzFKSEFLdVNzQjVQcTRCcVJFcW55SFhPRgpROWQ1bEFjRGNDYmhlTFRVb2h2ZkhOWW9SdWRrYkZ3RzAyOFR1UzFMU21wdTlWOEVTZDRDcGI4ZG9SRy9Rby9FCjF4RGk5STFhNVhoeUdHTTNsUFlYQU1HU1ZkWUNNNzh0M2ZLT3Q0VWVwS3p3Z0VDY0pFWDgxUWh6bVlPbkQvKzIKazNxSVppZU9nOGFkbDNFUWV2eFBISXlXQ1JkaDJZTkZsRi9rYTBPNDJFWXY1U1RPU3R3MjZPMzBNVGtwSDR3NApRZm9VV3BnZU93MDZyYTluRHdzV3VhMUZIaHlKZmxOanR1UStTQ2VoN2pNWVVROFhXUmRtdUdvMVFPSDlyN0MrCi82L1JhMlZIQWdNQkFBRUNnZ0VCQUlyTlVFUnJSM2ZmK3IraGhJRS93ekZhbGNUMUZWaDh3aXpUWXJQcnZCMFkKYlZvcVJzZ2xUVTdxTjkvM3dmc2dzdEROZk5IQ1pySEJOR0drK0orMDZMV2tnakhycjdXeFBUaE16ZDRvUGN4RwpRdTBMOGE5ZVlBMXJwY3NOOVc5Um5JU3BRSEk4aTkxM0V6Z0RoOWk2WCt0bFQyNjNNK0JYaDhlM1Z5cDNSTmhpCjZZUTQwcWJsNlQ0TUlyLzRSMGJmcFExZWVMNVNnbHB6Z1d6ZGs4WGtmc0E5YnRiU1RoMjZKRlBPUU1tMm5adkcKbjBlZm85TDZtaktwRW9rRWpTY1hWYTRZNHJaREZFYTVIbkpUSDBHblByQzU1cDhBb3BFN1c1M2RDT3lxd29CcQo4SWtZb2grcm1qTUZrOGc5VlRVYlcwVE9YVTFSY1E1Z0gxWS9jam5uVTRrQ2dZRUE4amw5ZEQyN2JaQ2ZaTW9jCjJYRThiYkJTaFVXTjRvaklKc1lHY2xyTjJDUEtUNmExaVhvS3BrTXdGNUdsODEzQURGR1pTbWtUSUFVQXRXQU8KNzZCcEpGUlVCZ1hmUXhSU0gyS1RaRldxbE5yekZPQjNsT3h2bFJ1amw5eE9ueStyWUhJWC9BOWNqQlp3a2orSAo3MDZRTExvS1ZFL2lMYy9DMlI5VzRLRVI3R3NDZ1lFQXhWd3FyM1JnUXhHUmpueG1zbDZtUW5DQ3k2MXFoUzUxCkJicDJzWldraFNTV0w0YzFDY0NDMnZ2ektPSmJkZ2NZQU43L05sTHgzWjlCZUFjTVZMUEVoc2NPalB6YUlneEMKczJ2UkdwQUFtYnRjWi9MVlpKaERWTjIrSHowRHhnRUtCa1JzQU5XTG51cGRoUWJBdlZuTkVsY29YVlo1cC9qcwp3U1BCelFoSklaVUNnWUJqTUlHY0dTOW9SWUhRRHlmVEx4aVV2bEI4ZktnR2JRYXhRZ1FmemVsZktnRE5yekhGCnN6RXJOblk2SUkxNVpCbWhzY1I1QVNBd3kzdW55a2N6ZjFldTVjMW1qZjhJQkFsQkN1ZmFmVzRWK0xiMEJKdFQKWTZLcHg2Q3RMaTBQNk1CZ0JUaW5JazgrbW0zTXBiRnZvSmRQaVh0elhTYjhwWWhmeXdLVGg4SEVNd0tCZ1FDUwpvR0VPTFpYKy9pUjRDYkI2d0pzaExWbmZYSjJSQ096a0xwNVVYV3IzaURFVWFvMWJDMjJzcUJjRnZ2WllmL2l6ClhQbWJNSkNGS1BhSTZDT2ZJbGZXRWptYlFaZ0dSN21lZDNISkhFZDE3NTg5azBvN0RHeXB0bnl6MUs3akFvNmkKRFY5NFZ5NytCLzBuQWRkY1ZrVm5aTjJXU3RMam1xcTY2NGZtZmt0bTZRS0JnQzBsMk5OVlFWK2N0OFFRRFpINQpBRFIrSGM3Qk0wNDhURGhNTmhoR3JHc2tWNngwMCtMZTdISGdpT3h2NXJudkNlTlY2M001YUZHdFVWbllTN1VoCkE1NndaNVlZeFFnQ0xzNi9PRmZhK3NiTngrSjdnSjRjNXdMZVlJMXVPMTlzZHBHa2VHZ25vK3dXVmxDSzFCbW0KRGM0TXA2STRiUTVtdy93YVpLQnpjRTJLCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"
|
||||
badCrt := "ASD"
|
||||
badKey := "ASD"
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
opClient OperatorClientI
|
||||
clientSet K8sClientI
|
||||
namespace string
|
||||
params admin_api.TenantUpdateCertificateParams
|
||||
mockTenantGet func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error)
|
||||
mockDeleteSecret func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error
|
||||
mockCreateSecret func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error)
|
||||
mockDeletePodCollection func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "error getting tenant information",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
opClient: opClient,
|
||||
clientSet: k8sClient,
|
||||
namespace: "",
|
||||
params: admin_api.TenantUpdateCertificateParams{},
|
||||
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||
return nil, errors.New("invalid tenant")
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "error replacing external certs for tenant because of missing keypair",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
opClient: opClient,
|
||||
clientSet: k8sClient,
|
||||
namespace: "",
|
||||
params: admin_api.TenantUpdateCertificateParams{
|
||||
Body: &models.TLSConfiguration{
|
||||
Minio: &models.KeyPairConfiguration{},
|
||||
},
|
||||
},
|
||||
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||
return &operator.Tenant{
|
||||
Spec: operator.TenantSpec{
|
||||
ExternalCertSecret: &operator.LocalCertificateReference{
|
||||
Name: "secret",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "error replacing external certs for tenant because of malformed encoded certs",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
opClient: opClient,
|
||||
clientSet: k8sClient,
|
||||
namespace: "",
|
||||
params: admin_api.TenantUpdateCertificateParams{
|
||||
Body: &models.TLSConfiguration{
|
||||
Minio: &models.KeyPairConfiguration{
|
||||
Crt: &badCrt,
|
||||
Key: &badKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||
return &operator.Tenant{
|
||||
Spec: operator.TenantSpec{
|
||||
ExternalCertSecret: &operator.LocalCertificateReference{
|
||||
Name: "secret",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "error replacing external certs for tenant because of error during secret creation",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
opClient: opClient,
|
||||
clientSet: k8sClient,
|
||||
namespace: "",
|
||||
params: admin_api.TenantUpdateCertificateParams{
|
||||
Body: &models.TLSConfiguration{
|
||||
Minio: &models.KeyPairConfiguration{
|
||||
Crt: &crt,
|
||||
Key: &key,
|
||||
},
|
||||
},
|
||||
},
|
||||
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||
return &operator.Tenant{
|
||||
Spec: operator.TenantSpec{
|
||||
ExternalCertSecret: &operator.LocalCertificateReference{
|
||||
Name: "secret",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
},
|
||||
mockCreateSecret: func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||
return nil, errors.New("error creating secret")
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "certificates replaced but error during deleting existing tenant pods",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
opClient: opClient,
|
||||
clientSet: k8sClient,
|
||||
namespace: "",
|
||||
params: admin_api.TenantUpdateCertificateParams{
|
||||
Body: &models.TLSConfiguration{
|
||||
Minio: &models.KeyPairConfiguration{
|
||||
Crt: &crt,
|
||||
Key: &key,
|
||||
},
|
||||
},
|
||||
},
|
||||
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||
return &operator.Tenant{
|
||||
Spec: operator.TenantSpec{
|
||||
ExternalCertSecret: &operator.LocalCertificateReference{
|
||||
Name: "secret",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
},
|
||||
mockCreateSecret: func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||
return &v1.Secret{}, nil
|
||||
},
|
||||
mockDeletePodCollection: func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||
return errors.New("error deleting minio pods")
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "error replacing external certs for console because of missing keypair",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
opClient: opClient,
|
||||
clientSet: k8sClient,
|
||||
namespace: "",
|
||||
params: admin_api.TenantUpdateCertificateParams{
|
||||
Body: &models.TLSConfiguration{
|
||||
Console: &models.KeyPairConfiguration{},
|
||||
},
|
||||
},
|
||||
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||
return &operator.Tenant{
|
||||
Spec: operator.TenantSpec{
|
||||
Console: &operator.ConsoleConfiguration{
|
||||
ExternalCertSecret: &operator.LocalCertificateReference{
|
||||
Name: "secret",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "certificates replaced but error during deleting existing tenant pods",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
opClient: opClient,
|
||||
clientSet: k8sClient,
|
||||
namespace: "",
|
||||
params: admin_api.TenantUpdateCertificateParams{
|
||||
Body: &models.TLSConfiguration{
|
||||
Console: &models.KeyPairConfiguration{
|
||||
Crt: &crt,
|
||||
Key: &key,
|
||||
},
|
||||
},
|
||||
},
|
||||
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||
return &operator.Tenant{
|
||||
Spec: operator.TenantSpec{
|
||||
Console: &operator.ConsoleConfiguration{
|
||||
ExternalCertSecret: &operator.LocalCertificateReference{
|
||||
Name: "secret",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
},
|
||||
mockCreateSecret: func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||
return &v1.Secret{}, nil
|
||||
},
|
||||
mockDeletePodCollection: func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||
return errors.New("error deleting console pods")
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
opClientTenantGetMock = tt.args.mockTenantGet
|
||||
DeleteSecretMock = tt.args.mockDeleteSecret
|
||||
CreateSecretMock = tt.args.mockCreateSecret
|
||||
DeletePodCollectionMock = tt.args.mockDeletePodCollection
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := tenantUpdateCertificates(tt.args.ctx, tt.args.opClient, tt.args.clientSet, tt.args.namespace, tt.args.params); (err != nil) != tt.wantErr {
|
||||
t.Errorf("tenantUpdateCertificates() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_tenantUpdateEncryption(t *testing.T) {
|
||||
k8sClient := k8sClientMock{}
|
||||
opClient := opClientMock{}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
opClient OperatorClientI
|
||||
clientSet K8sClientI
|
||||
namespace string
|
||||
params admin_api.TenantUpdateEncryptionParams
|
||||
mockTenantGet func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error)
|
||||
mockDeleteSecret func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error
|
||||
mockCreateSecret func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error)
|
||||
mockDeletePodCollection func(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "error updating encryption configuration because of error getting tenant",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
opClient: opClient,
|
||||
clientSet: k8sClient,
|
||||
namespace: "",
|
||||
params: admin_api.TenantUpdateEncryptionParams{},
|
||||
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*operator.Tenant, error) {
|
||||
return nil, errors.New("invalid tenant")
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
opClientTenantGetMock = tt.args.mockTenantGet
|
||||
DeleteSecretMock = tt.args.mockDeleteSecret
|
||||
CreateSecretMock = tt.args.mockCreateSecret
|
||||
DeletePodCollectionMock = tt.args.mockDeletePodCollection
|
||||
if err := tenantUpdateEncryption(tt.args.ctx, tt.args.opClient, tt.args.clientSet, tt.args.namespace, tt.args.params); (err != nil) != tt.wantErr {
|
||||
t.Errorf("tenantUpdateEncryption() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_createOrReplaceKesConfigurationSecrets(t *testing.T) {
|
||||
k8sClient := k8sClientMock{}
|
||||
crt := "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUUzRENDQTBTZ0F3SUJBZ0lRS0pDalNyK0xaMnJrYVo5ODAvZnV5akFOQmdrcWhraUc5dzBCQVFzRkFEQ0IKdFRFZU1Cd0dBMVVFQ2hNVmJXdGpaWEowSUdSbGRtVnNiM0J0Wlc1MElFTkJNVVV3UXdZRFZRUUxERHhoYkdWMgpjMnRBVEdWdWFXNXpMVTFoWTBKdmIyc3RVSEp2TG14dlkyRnNJQ2hNWlc1cGJpQkJiR1YyYzJ0cElFaDFaWEowCllTQkJjbWxoY3lreFREQktCZ05WQkFNTVEyMXJZMlZ5ZENCaGJHVjJjMnRBVEdWdWFXNXpMVTFoWTBKdmIyc3QKVUhKdkxteHZZMkZzSUNoTVpXNXBiaUJCYkdWMmMydHBJRWgxWlhKMFlTQkJjbWxoY3lrd0hoY05NVGt3TmpBeApNREF3TURBd1doY05NekF3T0RBeU1ERTFNekEzV2pCaU1TY3dKUVlEVlFRS0V4NXRhMk5sY25RZ1pHVjJaV3h2CmNHMWxiblFnWTJWeWRHbG1hV05oZEdVeE56QTFCZ05WQkFzTUxtRnNaWFp6YTBCMGFXWmhMbXh2WTJGc0lDaE0KWlc1cGJpQkJiR1YyYzJ0cElFaDFaWEowWVNCQmNtbGhjeWt3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQgpEd0F3Z2dFS0FvSUJBUUM2dlhLVyswWmhJQUNycmpxTU9QZ3VSdGpSemk1L0VxK2JvZTJkQ1BpT3djdXo0WFlhCm1rVlcxSkhBS3VTc0I1UHE0QnFSRXFueUhYT0ZROWQ1bEFjRGNDYmhlTFRVb2h2ZkhOWW9SdWRrYkZ3RzAyOFQKdVMxTFNtcHU5VjhFU2Q0Q3BiOGRvUkcvUW8vRTF4RGk5STFhNVhoeUdHTTNsUFlYQU1HU1ZkWUNNNzh0M2ZLTwp0NFVlcEt6d2dFQ2NKRVg4MVFoem1ZT25ELysyazNxSVppZU9nOGFkbDNFUWV2eFBISXlXQ1JkaDJZTkZsRi9rCmEwTzQyRVl2NVNUT1N0dzI2TzMwTVRrcEg0dzRRZm9VV3BnZU93MDZyYTluRHdzV3VhMUZIaHlKZmxOanR1USsKU0NlaDdqTVlVUThYV1JkbXVHbzFRT0g5cjdDKy82L1JhMlZIQWdNQkFBR2pnYmt3Z2JZd0RnWURWUjBQQVFILwpCQVFEQWdXZ01CTUdBMVVkSlFRTU1Bb0dDQ3NHQVFVRkJ3TUJNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqCkJCZ3dGb0FVNHg4NUIyeGVlQzg0UEdvM1dZVWwxRGVvZlFNd1lBWURWUjBSQkZrd1Y0SWpLaTV0YVc1cGJ5MWgKYkdWMmMyc3Ribk11YzNaakxtTnNkWE4wWlhJdWJHOWpZV3lDTUNvdWFHOXVaWGwzWld4c0xXaHNMbTFwYm1sdgpMV0ZzWlhaemF5MXVjeTV6ZG1NdVkyeDFjM1JsY2k1c2IyTmhiREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBWUVBCnZnMFlIVGtzd3Z4NEE5ZXl0b1V3eTBOSFVjQXpuNy9BVCt3WEt6d3Fqa0RiS3hVYlFTMFNQVVI4SkVDMkpuUUgKU3pTNGFCNXRURVRYZUcrbHJZVU02b0RNcXlIalpUN1NJaW83OUNxOFloWWxORU9qMkhvaXdxalczZm10UU9kVApoVG1tS01lRnZleHo2cnRxbHp0cVdKa3kvOGd1MkMrMWw5UDFFUmhFNDZZY0puVmJ5REFTSGNvV2tiZVhFUGErCjNpNFd4bU1yMDlNZXFTNkFUb2NKanFBeEtYcURYWmlFZjRUVEp1ZTRBQ2s4WmhqaEtUUEV6RnQ3WllVaHY3dVoKdlZCOXhla2FqRzdMRU5kSHZncXVMRUxUV3czWkpBaXpSTU5KUUpzZU11LzdQN1NIeXRKTVJYdlVwd2R2dWhDOApKNm54aGRmUS91QVlQY1lHdlU5NUZPZ1NjWVZqNW1WQktXM0ZHbkl2YzZuamQ1OFhBSTE3dlk0K0ZZTnY4M2UxCm9mOGlxRFdWNTFyT1FlbG9FZFdmdHkvZTI2bXVWUUQzQlVjY2Z5SWpGYy9SeGNHdm5maUEwUm1uRDNkWFcyZ0oKUHFTd01ZZ3hxQndqMm1Qck5jdkFWY3BOeWRjTWJKOTFIOHRWY0ttRHMrY1NiV0tnblpmKzUvZm5yaTdmU3FLUQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
|
||||
key := "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRQzZ2WEtXKzBaaElBQ3IKcmpxTU9QZ3VSdGpSemk1L0VxK2JvZTJkQ1BpT3djdXo0WFlhbWtWVzFKSEFLdVNzQjVQcTRCcVJFcW55SFhPRgpROWQ1bEFjRGNDYmhlTFRVb2h2ZkhOWW9SdWRrYkZ3RzAyOFR1UzFMU21wdTlWOEVTZDRDcGI4ZG9SRy9Rby9FCjF4RGk5STFhNVhoeUdHTTNsUFlYQU1HU1ZkWUNNNzh0M2ZLT3Q0VWVwS3p3Z0VDY0pFWDgxUWh6bVlPbkQvKzIKazNxSVppZU9nOGFkbDNFUWV2eFBISXlXQ1JkaDJZTkZsRi9rYTBPNDJFWXY1U1RPU3R3MjZPMzBNVGtwSDR3NApRZm9VV3BnZU93MDZyYTluRHdzV3VhMUZIaHlKZmxOanR1UStTQ2VoN2pNWVVROFhXUmRtdUdvMVFPSDlyN0MrCi82L1JhMlZIQWdNQkFBRUNnZ0VCQUlyTlVFUnJSM2ZmK3IraGhJRS93ekZhbGNUMUZWaDh3aXpUWXJQcnZCMFkKYlZvcVJzZ2xUVTdxTjkvM3dmc2dzdEROZk5IQ1pySEJOR0drK0orMDZMV2tnakhycjdXeFBUaE16ZDRvUGN4RwpRdTBMOGE5ZVlBMXJwY3NOOVc5Um5JU3BRSEk4aTkxM0V6Z0RoOWk2WCt0bFQyNjNNK0JYaDhlM1Z5cDNSTmhpCjZZUTQwcWJsNlQ0TUlyLzRSMGJmcFExZWVMNVNnbHB6Z1d6ZGs4WGtmc0E5YnRiU1RoMjZKRlBPUU1tMm5adkcKbjBlZm85TDZtaktwRW9rRWpTY1hWYTRZNHJaREZFYTVIbkpUSDBHblByQzU1cDhBb3BFN1c1M2RDT3lxd29CcQo4SWtZb2grcm1qTUZrOGc5VlRVYlcwVE9YVTFSY1E1Z0gxWS9jam5uVTRrQ2dZRUE4amw5ZEQyN2JaQ2ZaTW9jCjJYRThiYkJTaFVXTjRvaklKc1lHY2xyTjJDUEtUNmExaVhvS3BrTXdGNUdsODEzQURGR1pTbWtUSUFVQXRXQU8KNzZCcEpGUlVCZ1hmUXhSU0gyS1RaRldxbE5yekZPQjNsT3h2bFJ1amw5eE9ueStyWUhJWC9BOWNqQlp3a2orSAo3MDZRTExvS1ZFL2lMYy9DMlI5VzRLRVI3R3NDZ1lFQXhWd3FyM1JnUXhHUmpueG1zbDZtUW5DQ3k2MXFoUzUxCkJicDJzWldraFNTV0w0YzFDY0NDMnZ2ektPSmJkZ2NZQU43L05sTHgzWjlCZUFjTVZMUEVoc2NPalB6YUlneEMKczJ2UkdwQUFtYnRjWi9MVlpKaERWTjIrSHowRHhnRUtCa1JzQU5XTG51cGRoUWJBdlZuTkVsY29YVlo1cC9qcwp3U1BCelFoSklaVUNnWUJqTUlHY0dTOW9SWUhRRHlmVEx4aVV2bEI4ZktnR2JRYXhRZ1FmemVsZktnRE5yekhGCnN6RXJOblk2SUkxNVpCbWhzY1I1QVNBd3kzdW55a2N6ZjFldTVjMW1qZjhJQkFsQkN1ZmFmVzRWK0xiMEJKdFQKWTZLcHg2Q3RMaTBQNk1CZ0JUaW5JazgrbW0zTXBiRnZvSmRQaVh0elhTYjhwWWhmeXdLVGg4SEVNd0tCZ1FDUwpvR0VPTFpYKy9pUjRDYkI2d0pzaExWbmZYSjJSQ096a0xwNVVYV3IzaURFVWFvMWJDMjJzcUJjRnZ2WllmL2l6ClhQbWJNSkNGS1BhSTZDT2ZJbGZXRWptYlFaZ0dSN21lZDNISkhFZDE3NTg5azBvN0RHeXB0bnl6MUs3akFvNmkKRFY5NFZ5NytCLzBuQWRkY1ZrVm5aTjJXU3RMam1xcTY2NGZtZmt0bTZRS0JnQzBsMk5OVlFWK2N0OFFRRFpINQpBRFIrSGM3Qk0wNDhURGhNTmhoR3JHc2tWNngwMCtMZTdISGdpT3h2NXJudkNlTlY2M001YUZHdFVWbllTN1VoCkE1NndaNVlZeFFnQ0xzNi9PRmZhK3NiTngrSjdnSjRjNXdMZVlJMXVPMTlzZHBHa2VHZ25vK3dXVmxDSzFCbW0KRGM0TXA2STRiUTVtdy93YVpLQnpjRTJLCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"
|
||||
badCrt := "ASD"
|
||||
badKey := "ASD"
|
||||
appRole := "ASD"
|
||||
appSecret := "ASD"
|
||||
endpoint := "ASD"
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
clientSet K8sClientI
|
||||
ns string
|
||||
encryptionCfg *models.EncryptionConfiguration
|
||||
kesConfigurationSecretName string
|
||||
kesClientCertSecretName string
|
||||
tenantName string
|
||||
mockDeleteSecret func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error
|
||||
mockCreateSecret func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error)
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *v1.LocalObjectReference
|
||||
want1 *operator.LocalCertificateReference
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "error decoding the client certificate",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
clientSet: k8sClient,
|
||||
encryptionCfg: &models.EncryptionConfiguration{
|
||||
Client: &models.KeyPairConfiguration{
|
||||
Crt: &badCrt,
|
||||
Key: &badKey,
|
||||
},
|
||||
},
|
||||
ns: "default",
|
||||
kesConfigurationSecretName: "test-secret",
|
||||
kesClientCertSecretName: "test-client-secret",
|
||||
tenantName: "test",
|
||||
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: nil,
|
||||
want1: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "error because of malformed decoded certificate",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
clientSet: k8sClient,
|
||||
encryptionCfg: &models.EncryptionConfiguration{
|
||||
Client: &models.KeyPairConfiguration{
|
||||
Crt: &key, // will cause an error because we are passing a private key as the public key
|
||||
Key: &key,
|
||||
},
|
||||
},
|
||||
ns: "default",
|
||||
kesConfigurationSecretName: "test-secret",
|
||||
kesClientCertSecretName: "test-client-secret",
|
||||
tenantName: "test",
|
||||
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
want: nil,
|
||||
want1: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "error because of malformed decoded certificate",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
clientSet: k8sClient,
|
||||
encryptionCfg: &models.EncryptionConfiguration{
|
||||
Client: &models.KeyPairConfiguration{
|
||||
Crt: &crt,
|
||||
Key: &key,
|
||||
},
|
||||
Vault: &models.VaultConfiguration{
|
||||
Approle: &models.VaultConfigurationApprole{
|
||||
Engine: "",
|
||||
ID: &appRole,
|
||||
Retry: 0,
|
||||
Secret: &appSecret,
|
||||
},
|
||||
Endpoint: &endpoint,
|
||||
Engine: "",
|
||||
Namespace: "",
|
||||
Prefix: "",
|
||||
Status: nil,
|
||||
TLS: &models.VaultConfigurationTLS{
|
||||
Ca: crt,
|
||||
Crt: crt,
|
||||
Key: key,
|
||||
},
|
||||
},
|
||||
},
|
||||
ns: "default",
|
||||
kesConfigurationSecretName: "test-secret",
|
||||
kesClientCertSecretName: "test-client-secret",
|
||||
tenantName: "test",
|
||||
mockDeleteSecret: func(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||
return nil
|
||||
},
|
||||
mockCreateSecret: func(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||
return &v1.Secret{}, nil
|
||||
},
|
||||
},
|
||||
want: &v1.LocalObjectReference{
|
||||
Name: "test-secret",
|
||||
},
|
||||
want1: &operator.LocalCertificateReference{
|
||||
Name: "test-client-secret",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
DeleteSecretMock = tt.args.mockDeleteSecret
|
||||
CreateSecretMock = tt.args.mockCreateSecret
|
||||
got, got1, err := createOrReplaceKesConfigurationSecrets(tt.args.ctx, tt.args.clientSet, tt.args.ns, tt.args.encryptionCfg, tt.args.kesConfigurationSecretName, tt.args.kesClientCertSecretName, tt.args.tenantName)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("createOrReplaceKesConfigurationSecrets() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("createOrReplaceKesConfigurationSecrets() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
if !reflect.DeepEqual(got1, tt.want1) {
|
||||
t.Errorf("createOrReplaceKesConfigurationSecrets() got1 = %v, want %v", got1, tt.want1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -88,7 +88,7 @@ func Test_TenantInfoTenantAdminClient(t *testing.T) {
|
||||
kClient := k8sClientMock{}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
client K8sClient
|
||||
client K8sClientI
|
||||
namespace string
|
||||
tenantName string
|
||||
serviceName string
|
||||
@@ -339,7 +339,7 @@ func Test_deleteTenantAction(t *testing.T) {
|
||||
opClient := opClientMock{}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
operatorClient OperatorClient
|
||||
operatorClient OperatorClientI
|
||||
nameSpace string
|
||||
tenantName string
|
||||
deletePvcs bool
|
||||
@@ -532,7 +532,7 @@ func Test_TenantAddZone(t *testing.T) {
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
operatorClient OperatorClient
|
||||
operatorClient OperatorClientI
|
||||
nameSpace string
|
||||
mockTenantPatch func(ctx context.Context, namespace string, tenantName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*v1.Tenant, error)
|
||||
mockTenantGet func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*v1.Tenant, error)
|
||||
@@ -706,7 +706,7 @@ func Test_UpdateTenantAction(t *testing.T) {
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
operatorClient OperatorClient
|
||||
operatorClient OperatorClientI
|
||||
httpCl cluster.HTTPClientI
|
||||
nameSpace string
|
||||
tenantName string
|
||||
|
||||
@@ -1076,6 +1076,90 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"/namespaces/{namespace}/tenants/{tenant}/certificates": {
|
||||
"put": {
|
||||
"tags": [
|
||||
"AdminAPI"
|
||||
],
|
||||
"summary": "Tenant Update Certificates",
|
||||
"operationId": "TenantUpdateCertificate",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "namespace",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "tenant",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/tlsConfiguration"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "A successful response."
|
||||
},
|
||||
"default": {
|
||||
"description": "Generic error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/namespaces/{namespace}/tenants/{tenant}/encryption": {
|
||||
"put": {
|
||||
"tags": [
|
||||
"AdminAPI"
|
||||
],
|
||||
"summary": "Tenant Update Encryption",
|
||||
"operationId": "TenantUpdateEncryption",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "namespace",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "tenant",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/encryptionConfiguration"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "A successful response."
|
||||
},
|
||||
"default": {
|
||||
"description": "Generic error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/namespaces/{namespace}/tenants/{tenant}/usage": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -4616,6 +4700,90 @@ func init() {
|
||||
}
|
||||
}
|
||||
},
|
||||
"/namespaces/{namespace}/tenants/{tenant}/certificates": {
|
||||
"put": {
|
||||
"tags": [
|
||||
"AdminAPI"
|
||||
],
|
||||
"summary": "Tenant Update Certificates",
|
||||
"operationId": "TenantUpdateCertificate",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "namespace",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "tenant",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/tlsConfiguration"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "A successful response."
|
||||
},
|
||||
"default": {
|
||||
"description": "Generic error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/namespaces/{namespace}/tenants/{tenant}/encryption": {
|
||||
"put": {
|
||||
"tags": [
|
||||
"AdminAPI"
|
||||
],
|
||||
"summary": "Tenant Update Encryption",
|
||||
"operationId": "TenantUpdateEncryption",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "namespace",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "tenant",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/encryptionConfiguration"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "A successful response."
|
||||
},
|
||||
"default": {
|
||||
"description": "Generic error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/namespaces/{namespace}/tenants/{tenant}/usage": {
|
||||
"get": {
|
||||
"tags": [
|
||||
|
||||
@@ -24,13 +24,16 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
// K8sClient interface with all functions to be implemented
|
||||
// by mock when testing, it should include all K8sClient respective api calls
|
||||
// K8sClientI interface with all functions to be implemented
|
||||
// by mock when testing, it should include all K8sClientI respective api calls
|
||||
// that are used within this project.
|
||||
type K8sClient interface {
|
||||
type K8sClientI interface {
|
||||
getResourceQuota(ctx context.Context, namespace, resource string, opts metav1.GetOptions) (*v1.ResourceQuota, error)
|
||||
getSecret(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*v1.Secret, error)
|
||||
getService(ctx context.Context, namespace, serviceName string, opts metav1.GetOptions) (*v1.Service, error)
|
||||
deletePodCollection(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||
deleteSecret(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error
|
||||
createSecret(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error)
|
||||
}
|
||||
|
||||
// Interface implementation
|
||||
@@ -51,3 +54,15 @@ func (c *k8sClient) getSecret(ctx context.Context, namespace, secretName string,
|
||||
func (c *k8sClient) getService(ctx context.Context, namespace, serviceName string, opts metav1.GetOptions) (*v1.Service, error) {
|
||||
return c.client.CoreV1().Services(namespace).Get(ctx, serviceName, opts)
|
||||
}
|
||||
|
||||
func (c *k8sClient) deletePodCollection(ctx context.Context, namespace string, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error {
|
||||
return c.client.CoreV1().Pods(namespace).DeleteCollection(ctx, opts, listOpts)
|
||||
}
|
||||
|
||||
func (c *k8sClient) deleteSecret(ctx context.Context, namespace string, name string, opts metav1.DeleteOptions) error {
|
||||
return c.client.CoreV1().Secrets(namespace).Delete(ctx, name, opts)
|
||||
}
|
||||
|
||||
func (c *k8sClient) createSecret(ctx context.Context, namespace string, secret *v1.Secret, opts metav1.CreateOptions) (*v1.Secret, error) {
|
||||
return c.client.CoreV1().Secrets(namespace).Create(ctx, secret, opts)
|
||||
}
|
||||
|
||||
90
restapi/operations/admin_api/tenant_update_certificate.go
Normal file
90
restapi/operations/admin_api/tenant_update_certificate.go
Normal file
@@ -0,0 +1,90 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package admin_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// TenantUpdateCertificateHandlerFunc turns a function with the right signature into a tenant update certificate handler
|
||||
type TenantUpdateCertificateHandlerFunc func(TenantUpdateCertificateParams, *models.Principal) middleware.Responder
|
||||
|
||||
// Handle executing the request and returning a response
|
||||
func (fn TenantUpdateCertificateHandlerFunc) Handle(params TenantUpdateCertificateParams, principal *models.Principal) middleware.Responder {
|
||||
return fn(params, principal)
|
||||
}
|
||||
|
||||
// TenantUpdateCertificateHandler interface for that can handle valid tenant update certificate params
|
||||
type TenantUpdateCertificateHandler interface {
|
||||
Handle(TenantUpdateCertificateParams, *models.Principal) middleware.Responder
|
||||
}
|
||||
|
||||
// NewTenantUpdateCertificate creates a new http.Handler for the tenant update certificate operation
|
||||
func NewTenantUpdateCertificate(ctx *middleware.Context, handler TenantUpdateCertificateHandler) *TenantUpdateCertificate {
|
||||
return &TenantUpdateCertificate{Context: ctx, Handler: handler}
|
||||
}
|
||||
|
||||
/*TenantUpdateCertificate swagger:route PUT /namespaces/{namespace}/tenants/{tenant}/certificates AdminAPI tenantUpdateCertificate
|
||||
|
||||
Tenant Update Certificates
|
||||
|
||||
*/
|
||||
type TenantUpdateCertificate struct {
|
||||
Context *middleware.Context
|
||||
Handler TenantUpdateCertificateHandler
|
||||
}
|
||||
|
||||
func (o *TenantUpdateCertificate) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||
if rCtx != nil {
|
||||
r = rCtx
|
||||
}
|
||||
var Params = NewTenantUpdateCertificateParams()
|
||||
|
||||
uprinc, aCtx, err := o.Context.Authorize(r, route)
|
||||
if err != nil {
|
||||
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
if aCtx != nil {
|
||||
r = aCtx
|
||||
}
|
||||
var principal *models.Principal
|
||||
if uprinc != nil {
|
||||
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
|
||||
}
|
||||
|
||||
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
|
||||
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
|
||||
res := o.Handler.Handle(Params, principal) // actually handle the request
|
||||
|
||||
o.Context.Respond(rw, r, route.Produces, route, res)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package admin_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// NewTenantUpdateCertificateParams creates a new TenantUpdateCertificateParams object
|
||||
// no default values defined in spec.
|
||||
func NewTenantUpdateCertificateParams() TenantUpdateCertificateParams {
|
||||
|
||||
return TenantUpdateCertificateParams{}
|
||||
}
|
||||
|
||||
// TenantUpdateCertificateParams contains all the bound params for the tenant update certificate operation
|
||||
// typically these are obtained from a http.Request
|
||||
//
|
||||
// swagger:parameters TenantUpdateCertificate
|
||||
type TenantUpdateCertificateParams struct {
|
||||
|
||||
// HTTP Request Object
|
||||
HTTPRequest *http.Request `json:"-"`
|
||||
|
||||
/*
|
||||
Required: true
|
||||
In: body
|
||||
*/
|
||||
Body *models.TLSConfiguration
|
||||
/*
|
||||
Required: true
|
||||
In: path
|
||||
*/
|
||||
Namespace string
|
||||
/*
|
||||
Required: true
|
||||
In: path
|
||||
*/
|
||||
Tenant string
|
||||
}
|
||||
|
||||
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||
// for simple values it will use straight method calls.
|
||||
//
|
||||
// To ensure default values, the struct must have been initialized with NewTenantUpdateCertificateParams() beforehand.
|
||||
func (o *TenantUpdateCertificateParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||
var res []error
|
||||
|
||||
o.HTTPRequest = r
|
||||
|
||||
if runtime.HasBody(r) {
|
||||
defer r.Body.Close()
|
||||
var body models.TLSConfiguration
|
||||
if err := route.Consumer.Consume(r.Body, &body); err != nil {
|
||||
if err == io.EOF {
|
||||
res = append(res, errors.Required("body", "body", ""))
|
||||
} else {
|
||||
res = append(res, errors.NewParseError("body", "body", "", err))
|
||||
}
|
||||
} else {
|
||||
// validate body object
|
||||
if err := body.Validate(route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) == 0 {
|
||||
o.Body = &body
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = append(res, errors.Required("body", "body", ""))
|
||||
}
|
||||
rNamespace, rhkNamespace, _ := route.Params.GetOK("namespace")
|
||||
if err := o.bindNamespace(rNamespace, rhkNamespace, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
rTenant, rhkTenant, _ := route.Params.GetOK("tenant")
|
||||
if err := o.bindTenant(rTenant, rhkTenant, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindNamespace binds and validates parameter Namespace from path.
|
||||
func (o *TenantUpdateCertificateParams) bindNamespace(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: true
|
||||
// Parameter is provided by construction from the route
|
||||
|
||||
o.Namespace = raw
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindTenant binds and validates parameter Tenant from path.
|
||||
func (o *TenantUpdateCertificateParams) bindTenant(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: true
|
||||
// Parameter is provided by construction from the route
|
||||
|
||||
o.Tenant = raw
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package admin_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// TenantUpdateCertificateCreatedCode is the HTTP code returned for type TenantUpdateCertificateCreated
|
||||
const TenantUpdateCertificateCreatedCode int = 201
|
||||
|
||||
/*TenantUpdateCertificateCreated A successful response.
|
||||
|
||||
swagger:response tenantUpdateCertificateCreated
|
||||
*/
|
||||
type TenantUpdateCertificateCreated struct {
|
||||
}
|
||||
|
||||
// NewTenantUpdateCertificateCreated creates TenantUpdateCertificateCreated with default headers values
|
||||
func NewTenantUpdateCertificateCreated() *TenantUpdateCertificateCreated {
|
||||
|
||||
return &TenantUpdateCertificateCreated{}
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *TenantUpdateCertificateCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
|
||||
|
||||
rw.WriteHeader(201)
|
||||
}
|
||||
|
||||
/*TenantUpdateCertificateDefault Generic error response.
|
||||
|
||||
swagger:response tenantUpdateCertificateDefault
|
||||
*/
|
||||
type TenantUpdateCertificateDefault struct {
|
||||
_statusCode int
|
||||
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewTenantUpdateCertificateDefault creates TenantUpdateCertificateDefault with default headers values
|
||||
func NewTenantUpdateCertificateDefault(code int) *TenantUpdateCertificateDefault {
|
||||
if code <= 0 {
|
||||
code = 500
|
||||
}
|
||||
|
||||
return &TenantUpdateCertificateDefault{
|
||||
_statusCode: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WithStatusCode adds the status to the tenant update certificate default response
|
||||
func (o *TenantUpdateCertificateDefault) WithStatusCode(code int) *TenantUpdateCertificateDefault {
|
||||
o._statusCode = code
|
||||
return o
|
||||
}
|
||||
|
||||
// SetStatusCode sets the status to the tenant update certificate default response
|
||||
func (o *TenantUpdateCertificateDefault) SetStatusCode(code int) {
|
||||
o._statusCode = code
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the tenant update certificate default response
|
||||
func (o *TenantUpdateCertificateDefault) WithPayload(payload *models.Error) *TenantUpdateCertificateDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the tenant update certificate default response
|
||||
func (o *TenantUpdateCertificateDefault) SetPayload(payload *models.Error) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *TenantUpdateCertificateDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.WriteHeader(o._statusCode)
|
||||
if o.Payload != nil {
|
||||
payload := o.Payload
|
||||
if err := producer.Produce(rw, payload); err != nil {
|
||||
panic(err) // let the recovery middleware deal with this
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package admin_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
golangswaggerpaths "path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TenantUpdateCertificateURL generates an URL for the tenant update certificate operation
|
||||
type TenantUpdateCertificateURL struct {
|
||||
Namespace string
|
||||
Tenant string
|
||||
|
||||
_basePath string
|
||||
// avoid unkeyed usage
|
||||
_ struct{}
|
||||
}
|
||||
|
||||
// WithBasePath sets the base path for this url builder, only required when it's different from the
|
||||
// base path specified in the swagger spec.
|
||||
// When the value of the base path is an empty string
|
||||
func (o *TenantUpdateCertificateURL) WithBasePath(bp string) *TenantUpdateCertificateURL {
|
||||
o.SetBasePath(bp)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetBasePath sets the base path for this url builder, only required when it's different from the
|
||||
// base path specified in the swagger spec.
|
||||
// When the value of the base path is an empty string
|
||||
func (o *TenantUpdateCertificateURL) SetBasePath(bp string) {
|
||||
o._basePath = bp
|
||||
}
|
||||
|
||||
// Build a url path and query string
|
||||
func (o *TenantUpdateCertificateURL) Build() (*url.URL, error) {
|
||||
var _result url.URL
|
||||
|
||||
var _path = "/namespaces/{namespace}/tenants/{tenant}/certificates"
|
||||
|
||||
namespace := o.Namespace
|
||||
if namespace != "" {
|
||||
_path = strings.Replace(_path, "{namespace}", namespace, -1)
|
||||
} else {
|
||||
return nil, errors.New("namespace is required on TenantUpdateCertificateURL")
|
||||
}
|
||||
|
||||
tenant := o.Tenant
|
||||
if tenant != "" {
|
||||
_path = strings.Replace(_path, "{tenant}", tenant, -1)
|
||||
} else {
|
||||
return nil, errors.New("tenant is required on TenantUpdateCertificateURL")
|
||||
}
|
||||
|
||||
_basePath := o._basePath
|
||||
if _basePath == "" {
|
||||
_basePath = "/api/v1"
|
||||
}
|
||||
_result.Path = golangswaggerpaths.Join(_basePath, _path)
|
||||
|
||||
return &_result, nil
|
||||
}
|
||||
|
||||
// Must is a helper function to panic when the url builder returns an error
|
||||
func (o *TenantUpdateCertificateURL) Must(u *url.URL, err error) *url.URL {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if u == nil {
|
||||
panic("url can't be nil")
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// String returns the string representation of the path with query string
|
||||
func (o *TenantUpdateCertificateURL) String() string {
|
||||
return o.Must(o.Build()).String()
|
||||
}
|
||||
|
||||
// BuildFull builds a full url with scheme, host, path and query string
|
||||
func (o *TenantUpdateCertificateURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||
if scheme == "" {
|
||||
return nil, errors.New("scheme is required for a full url on TenantUpdateCertificateURL")
|
||||
}
|
||||
if host == "" {
|
||||
return nil, errors.New("host is required for a full url on TenantUpdateCertificateURL")
|
||||
}
|
||||
|
||||
base, err := o.Build()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
base.Scheme = scheme
|
||||
base.Host = host
|
||||
return base, nil
|
||||
}
|
||||
|
||||
// StringFull returns the string representation of a complete url
|
||||
func (o *TenantUpdateCertificateURL) StringFull(scheme, host string) string {
|
||||
return o.Must(o.BuildFull(scheme, host)).String()
|
||||
}
|
||||
90
restapi/operations/admin_api/tenant_update_encryption.go
Normal file
90
restapi/operations/admin_api/tenant_update_encryption.go
Normal file
@@ -0,0 +1,90 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package admin_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// TenantUpdateEncryptionHandlerFunc turns a function with the right signature into a tenant update encryption handler
|
||||
type TenantUpdateEncryptionHandlerFunc func(TenantUpdateEncryptionParams, *models.Principal) middleware.Responder
|
||||
|
||||
// Handle executing the request and returning a response
|
||||
func (fn TenantUpdateEncryptionHandlerFunc) Handle(params TenantUpdateEncryptionParams, principal *models.Principal) middleware.Responder {
|
||||
return fn(params, principal)
|
||||
}
|
||||
|
||||
// TenantUpdateEncryptionHandler interface for that can handle valid tenant update encryption params
|
||||
type TenantUpdateEncryptionHandler interface {
|
||||
Handle(TenantUpdateEncryptionParams, *models.Principal) middleware.Responder
|
||||
}
|
||||
|
||||
// NewTenantUpdateEncryption creates a new http.Handler for the tenant update encryption operation
|
||||
func NewTenantUpdateEncryption(ctx *middleware.Context, handler TenantUpdateEncryptionHandler) *TenantUpdateEncryption {
|
||||
return &TenantUpdateEncryption{Context: ctx, Handler: handler}
|
||||
}
|
||||
|
||||
/*TenantUpdateEncryption swagger:route PUT /namespaces/{namespace}/tenants/{tenant}/encryption AdminAPI tenantUpdateEncryption
|
||||
|
||||
Tenant Update Encryption
|
||||
|
||||
*/
|
||||
type TenantUpdateEncryption struct {
|
||||
Context *middleware.Context
|
||||
Handler TenantUpdateEncryptionHandler
|
||||
}
|
||||
|
||||
func (o *TenantUpdateEncryption) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
route, rCtx, _ := o.Context.RouteInfo(r)
|
||||
if rCtx != nil {
|
||||
r = rCtx
|
||||
}
|
||||
var Params = NewTenantUpdateEncryptionParams()
|
||||
|
||||
uprinc, aCtx, err := o.Context.Authorize(r, route)
|
||||
if err != nil {
|
||||
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
if aCtx != nil {
|
||||
r = aCtx
|
||||
}
|
||||
var principal *models.Principal
|
||||
if uprinc != nil {
|
||||
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
|
||||
}
|
||||
|
||||
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
|
||||
o.Context.Respond(rw, r, route.Produces, route, err)
|
||||
return
|
||||
}
|
||||
|
||||
res := o.Handler.Handle(Params, principal) // actually handle the request
|
||||
|
||||
o.Context.Respond(rw, r, route.Produces, route, res)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package admin_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/errors"
|
||||
"github.com/go-openapi/runtime"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/go-openapi/strfmt"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// NewTenantUpdateEncryptionParams creates a new TenantUpdateEncryptionParams object
|
||||
// no default values defined in spec.
|
||||
func NewTenantUpdateEncryptionParams() TenantUpdateEncryptionParams {
|
||||
|
||||
return TenantUpdateEncryptionParams{}
|
||||
}
|
||||
|
||||
// TenantUpdateEncryptionParams contains all the bound params for the tenant update encryption operation
|
||||
// typically these are obtained from a http.Request
|
||||
//
|
||||
// swagger:parameters TenantUpdateEncryption
|
||||
type TenantUpdateEncryptionParams struct {
|
||||
|
||||
// HTTP Request Object
|
||||
HTTPRequest *http.Request `json:"-"`
|
||||
|
||||
/*
|
||||
Required: true
|
||||
In: body
|
||||
*/
|
||||
Body *models.EncryptionConfiguration
|
||||
/*
|
||||
Required: true
|
||||
In: path
|
||||
*/
|
||||
Namespace string
|
||||
/*
|
||||
Required: true
|
||||
In: path
|
||||
*/
|
||||
Tenant string
|
||||
}
|
||||
|
||||
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
|
||||
// for simple values it will use straight method calls.
|
||||
//
|
||||
// To ensure default values, the struct must have been initialized with NewTenantUpdateEncryptionParams() beforehand.
|
||||
func (o *TenantUpdateEncryptionParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
|
||||
var res []error
|
||||
|
||||
o.HTTPRequest = r
|
||||
|
||||
if runtime.HasBody(r) {
|
||||
defer r.Body.Close()
|
||||
var body models.EncryptionConfiguration
|
||||
if err := route.Consumer.Consume(r.Body, &body); err != nil {
|
||||
if err == io.EOF {
|
||||
res = append(res, errors.Required("body", "body", ""))
|
||||
} else {
|
||||
res = append(res, errors.NewParseError("body", "body", "", err))
|
||||
}
|
||||
} else {
|
||||
// validate body object
|
||||
if err := body.Validate(route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) == 0 {
|
||||
o.Body = &body
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = append(res, errors.Required("body", "body", ""))
|
||||
}
|
||||
rNamespace, rhkNamespace, _ := route.Params.GetOK("namespace")
|
||||
if err := o.bindNamespace(rNamespace, rhkNamespace, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
rTenant, rhkTenant, _ := route.Params.GetOK("tenant")
|
||||
if err := o.bindTenant(rTenant, rhkTenant, route.Formats); err != nil {
|
||||
res = append(res, err)
|
||||
}
|
||||
|
||||
if len(res) > 0 {
|
||||
return errors.CompositeValidationError(res...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindNamespace binds and validates parameter Namespace from path.
|
||||
func (o *TenantUpdateEncryptionParams) bindNamespace(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: true
|
||||
// Parameter is provided by construction from the route
|
||||
|
||||
o.Namespace = raw
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// bindTenant binds and validates parameter Tenant from path.
|
||||
func (o *TenantUpdateEncryptionParams) bindTenant(rawData []string, hasKey bool, formats strfmt.Registry) error {
|
||||
var raw string
|
||||
if len(rawData) > 0 {
|
||||
raw = rawData[len(rawData)-1]
|
||||
}
|
||||
|
||||
// Required: true
|
||||
// Parameter is provided by construction from the route
|
||||
|
||||
o.Tenant = raw
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package admin_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the swagger generate command
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-openapi/runtime"
|
||||
|
||||
"github.com/minio/console/models"
|
||||
)
|
||||
|
||||
// TenantUpdateEncryptionCreatedCode is the HTTP code returned for type TenantUpdateEncryptionCreated
|
||||
const TenantUpdateEncryptionCreatedCode int = 201
|
||||
|
||||
/*TenantUpdateEncryptionCreated A successful response.
|
||||
|
||||
swagger:response tenantUpdateEncryptionCreated
|
||||
*/
|
||||
type TenantUpdateEncryptionCreated struct {
|
||||
}
|
||||
|
||||
// NewTenantUpdateEncryptionCreated creates TenantUpdateEncryptionCreated with default headers values
|
||||
func NewTenantUpdateEncryptionCreated() *TenantUpdateEncryptionCreated {
|
||||
|
||||
return &TenantUpdateEncryptionCreated{}
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *TenantUpdateEncryptionCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
|
||||
|
||||
rw.WriteHeader(201)
|
||||
}
|
||||
|
||||
/*TenantUpdateEncryptionDefault Generic error response.
|
||||
|
||||
swagger:response tenantUpdateEncryptionDefault
|
||||
*/
|
||||
type TenantUpdateEncryptionDefault struct {
|
||||
_statusCode int
|
||||
|
||||
/*
|
||||
In: Body
|
||||
*/
|
||||
Payload *models.Error `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
// NewTenantUpdateEncryptionDefault creates TenantUpdateEncryptionDefault with default headers values
|
||||
func NewTenantUpdateEncryptionDefault(code int) *TenantUpdateEncryptionDefault {
|
||||
if code <= 0 {
|
||||
code = 500
|
||||
}
|
||||
|
||||
return &TenantUpdateEncryptionDefault{
|
||||
_statusCode: code,
|
||||
}
|
||||
}
|
||||
|
||||
// WithStatusCode adds the status to the tenant update encryption default response
|
||||
func (o *TenantUpdateEncryptionDefault) WithStatusCode(code int) *TenantUpdateEncryptionDefault {
|
||||
o._statusCode = code
|
||||
return o
|
||||
}
|
||||
|
||||
// SetStatusCode sets the status to the tenant update encryption default response
|
||||
func (o *TenantUpdateEncryptionDefault) SetStatusCode(code int) {
|
||||
o._statusCode = code
|
||||
}
|
||||
|
||||
// WithPayload adds the payload to the tenant update encryption default response
|
||||
func (o *TenantUpdateEncryptionDefault) WithPayload(payload *models.Error) *TenantUpdateEncryptionDefault {
|
||||
o.Payload = payload
|
||||
return o
|
||||
}
|
||||
|
||||
// SetPayload sets the payload to the tenant update encryption default response
|
||||
func (o *TenantUpdateEncryptionDefault) SetPayload(payload *models.Error) {
|
||||
o.Payload = payload
|
||||
}
|
||||
|
||||
// WriteResponse to the client
|
||||
func (o *TenantUpdateEncryptionDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
|
||||
|
||||
rw.WriteHeader(o._statusCode)
|
||||
if o.Payload != nil {
|
||||
payload := o.Payload
|
||||
if err := producer.Produce(rw, payload); err != nil {
|
||||
panic(err) // let the recovery middleware deal with this
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
// Code generated by go-swagger; DO NOT EDIT.
|
||||
|
||||
// This file is part of MinIO Console Server
|
||||
// Copyright (c) 2020 MinIO, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
package admin_api
|
||||
|
||||
// This file was generated by the swagger tool.
|
||||
// Editing this file might prove futile when you re-run the generate command
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
golangswaggerpaths "path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TenantUpdateEncryptionURL generates an URL for the tenant update encryption operation
|
||||
type TenantUpdateEncryptionURL struct {
|
||||
Namespace string
|
||||
Tenant string
|
||||
|
||||
_basePath string
|
||||
// avoid unkeyed usage
|
||||
_ struct{}
|
||||
}
|
||||
|
||||
// WithBasePath sets the base path for this url builder, only required when it's different from the
|
||||
// base path specified in the swagger spec.
|
||||
// When the value of the base path is an empty string
|
||||
func (o *TenantUpdateEncryptionURL) WithBasePath(bp string) *TenantUpdateEncryptionURL {
|
||||
o.SetBasePath(bp)
|
||||
return o
|
||||
}
|
||||
|
||||
// SetBasePath sets the base path for this url builder, only required when it's different from the
|
||||
// base path specified in the swagger spec.
|
||||
// When the value of the base path is an empty string
|
||||
func (o *TenantUpdateEncryptionURL) SetBasePath(bp string) {
|
||||
o._basePath = bp
|
||||
}
|
||||
|
||||
// Build a url path and query string
|
||||
func (o *TenantUpdateEncryptionURL) Build() (*url.URL, error) {
|
||||
var _result url.URL
|
||||
|
||||
var _path = "/namespaces/{namespace}/tenants/{tenant}/encryption"
|
||||
|
||||
namespace := o.Namespace
|
||||
if namespace != "" {
|
||||
_path = strings.Replace(_path, "{namespace}", namespace, -1)
|
||||
} else {
|
||||
return nil, errors.New("namespace is required on TenantUpdateEncryptionURL")
|
||||
}
|
||||
|
||||
tenant := o.Tenant
|
||||
if tenant != "" {
|
||||
_path = strings.Replace(_path, "{tenant}", tenant, -1)
|
||||
} else {
|
||||
return nil, errors.New("tenant is required on TenantUpdateEncryptionURL")
|
||||
}
|
||||
|
||||
_basePath := o._basePath
|
||||
if _basePath == "" {
|
||||
_basePath = "/api/v1"
|
||||
}
|
||||
_result.Path = golangswaggerpaths.Join(_basePath, _path)
|
||||
|
||||
return &_result, nil
|
||||
}
|
||||
|
||||
// Must is a helper function to panic when the url builder returns an error
|
||||
func (o *TenantUpdateEncryptionURL) Must(u *url.URL, err error) *url.URL {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if u == nil {
|
||||
panic("url can't be nil")
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// String returns the string representation of the path with query string
|
||||
func (o *TenantUpdateEncryptionURL) String() string {
|
||||
return o.Must(o.Build()).String()
|
||||
}
|
||||
|
||||
// BuildFull builds a full url with scheme, host, path and query string
|
||||
func (o *TenantUpdateEncryptionURL) BuildFull(scheme, host string) (*url.URL, error) {
|
||||
if scheme == "" {
|
||||
return nil, errors.New("scheme is required for a full url on TenantUpdateEncryptionURL")
|
||||
}
|
||||
if host == "" {
|
||||
return nil, errors.New("host is required for a full url on TenantUpdateEncryptionURL")
|
||||
}
|
||||
|
||||
base, err := o.Build()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
base.Scheme = scheme
|
||||
base.Host = host
|
||||
return base, nil
|
||||
}
|
||||
|
||||
// StringFull returns the string representation of a complete url
|
||||
func (o *TenantUpdateEncryptionURL) StringFull(scheme, host string) string {
|
||||
return o.Must(o.BuildFull(scheme, host)).String()
|
||||
}
|
||||
@@ -213,6 +213,12 @@ func NewConsoleAPI(spec *loads.Document) *ConsoleAPI {
|
||||
AdminAPITenantInfoHandler: admin_api.TenantInfoHandlerFunc(func(params admin_api.TenantInfoParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation admin_api.TenantInfo has not yet been implemented")
|
||||
}),
|
||||
AdminAPITenantUpdateCertificateHandler: admin_api.TenantUpdateCertificateHandlerFunc(func(params admin_api.TenantUpdateCertificateParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation admin_api.TenantUpdateCertificate has not yet been implemented")
|
||||
}),
|
||||
AdminAPITenantUpdateEncryptionHandler: admin_api.TenantUpdateEncryptionHandlerFunc(func(params admin_api.TenantUpdateEncryptionParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation admin_api.TenantUpdateEncryption has not yet been implemented")
|
||||
}),
|
||||
AdminAPITenantUpdateZonesHandler: admin_api.TenantUpdateZonesHandlerFunc(func(params admin_api.TenantUpdateZonesParams, principal *models.Principal) middleware.Responder {
|
||||
return middleware.NotImplemented("operation admin_api.TenantUpdateZones has not yet been implemented")
|
||||
}),
|
||||
@@ -377,6 +383,10 @@ type ConsoleAPI struct {
|
||||
AdminAPITenantAddZoneHandler admin_api.TenantAddZoneHandler
|
||||
// AdminAPITenantInfoHandler sets the operation handler for the tenant info operation
|
||||
AdminAPITenantInfoHandler admin_api.TenantInfoHandler
|
||||
// AdminAPITenantUpdateCertificateHandler sets the operation handler for the tenant update certificate operation
|
||||
AdminAPITenantUpdateCertificateHandler admin_api.TenantUpdateCertificateHandler
|
||||
// AdminAPITenantUpdateEncryptionHandler sets the operation handler for the tenant update encryption operation
|
||||
AdminAPITenantUpdateEncryptionHandler admin_api.TenantUpdateEncryptionHandler
|
||||
// AdminAPITenantUpdateZonesHandler sets the operation handler for the tenant update zones operation
|
||||
AdminAPITenantUpdateZonesHandler admin_api.TenantUpdateZonesHandler
|
||||
// AdminAPIUpdateGroupHandler sets the operation handler for the update group operation
|
||||
@@ -610,6 +620,12 @@ func (o *ConsoleAPI) Validate() error {
|
||||
if o.AdminAPITenantInfoHandler == nil {
|
||||
unregistered = append(unregistered, "admin_api.TenantInfoHandler")
|
||||
}
|
||||
if o.AdminAPITenantUpdateCertificateHandler == nil {
|
||||
unregistered = append(unregistered, "admin_api.TenantUpdateCertificateHandler")
|
||||
}
|
||||
if o.AdminAPITenantUpdateEncryptionHandler == nil {
|
||||
unregistered = append(unregistered, "admin_api.TenantUpdateEncryptionHandler")
|
||||
}
|
||||
if o.AdminAPITenantUpdateZonesHandler == nil {
|
||||
unregistered = append(unregistered, "admin_api.TenantUpdateZonesHandler")
|
||||
}
|
||||
@@ -928,6 +944,14 @@ func (o *ConsoleAPI) initHandlerCache() {
|
||||
if o.handlers["PUT"] == nil {
|
||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["PUT"]["/namespaces/{namespace}/tenants/{tenant}/certificates"] = admin_api.NewTenantUpdateCertificate(o.context, o.AdminAPITenantUpdateCertificateHandler)
|
||||
if o.handlers["PUT"] == nil {
|
||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["PUT"]["/namespaces/{namespace}/tenants/{tenant}/encryption"] = admin_api.NewTenantUpdateEncryption(o.context, o.AdminAPITenantUpdateEncryptionHandler)
|
||||
if o.handlers["PUT"] == nil {
|
||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||
}
|
||||
o.handlers["PUT"]["/namespaces/{namespace}/tenants/{tenant}/zones"] = admin_api.NewTenantUpdateZones(o.context, o.AdminAPITenantUpdateZonesHandler)
|
||||
if o.handlers["PUT"] == nil {
|
||||
o.handlers["PUT"] = make(map[string]http.Handler)
|
||||
|
||||
@@ -25,10 +25,10 @@ import (
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
// OperatorClient interface with all functions to be implemented
|
||||
// by mock when testing, it should include all OperatorClient respective api calls
|
||||
// OperatorClientI interface with all functions to be implemented
|
||||
// by mock when testing, it should include all OperatorClientI respective api calls
|
||||
// that are used within this project.
|
||||
type OperatorClient interface {
|
||||
type OperatorClientI interface {
|
||||
TenantDelete(ctx context.Context, namespace string, instanceName string, options metav1.DeleteOptions) error
|
||||
TenantGet(ctx context.Context, namespace string, instanceName string, options metav1.GetOptions) (*v1.Tenant, error)
|
||||
TenantPatch(ctx context.Context, namespace string, instanceName string, pt types.PatchType, data []byte, options metav1.PatchOptions) (*v1.Tenant, error)
|
||||
|
||||
@@ -42,7 +42,7 @@ func registerResourceQuotaHandlers(api *operations.ConsoleAPI) {
|
||||
})
|
||||
}
|
||||
|
||||
func getResourceQuota(ctx context.Context, client K8sClient, namespace, resourcequota string) (*models.ResourceQuota, error) {
|
||||
func getResourceQuota(ctx context.Context, client K8sClientI, namespace, resourcequota string) (*models.ResourceQuota, error) {
|
||||
resourceQuota, err := client.getResourceQuota(ctx, namespace, resourcequota, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -48,7 +48,7 @@ func Test_ResourceQuota(t *testing.T) {
|
||||
kClient := k8sClientMock{}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
client K8sClient
|
||||
client K8sClientI
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
56
swagger.yml
56
swagger.yml
@@ -1202,6 +1202,62 @@ paths:
|
||||
tags:
|
||||
- AdminAPI
|
||||
|
||||
/namespaces/{namespace}/tenants/{tenant}/certificates:
|
||||
put:
|
||||
summary: Tenant Update Certificates
|
||||
operationId: TenantUpdateCertificate
|
||||
parameters:
|
||||
- name: namespace
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
- name: tenant
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
- name: body
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/tlsConfiguration"
|
||||
responses:
|
||||
201:
|
||||
description: A successful response.
|
||||
default:
|
||||
description: Generic error response.
|
||||
schema:
|
||||
$ref: "#/definitions/error"
|
||||
tags:
|
||||
- AdminAPI
|
||||
|
||||
/namespaces/{namespace}/tenants/{tenant}/encryption:
|
||||
put:
|
||||
summary: Tenant Update Encryption
|
||||
operationId: TenantUpdateEncryption
|
||||
parameters:
|
||||
- name: namespace
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
- name: tenant
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
- name: body
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/encryptionConfiguration"
|
||||
responses:
|
||||
201:
|
||||
description: A successful response.
|
||||
default:
|
||||
description: Generic error response.
|
||||
schema:
|
||||
$ref: "#/definitions/error"
|
||||
tags:
|
||||
- AdminAPI
|
||||
|
||||
/namespaces/{namespace}/resourcequotas/{resource-quota-name}:
|
||||
get:
|
||||
summary: Get Resource Quota
|
||||
|
||||
Reference in New Issue
Block a user