Support for providing Tenant client certificates (#2294)
This commit is contained in:
@@ -2651,7 +2651,7 @@ func init() {
|
||||
"logSearchConfiguration": {
|
||||
"$ref": "#/definitions/logSearchConfiguration"
|
||||
},
|
||||
"mounth_path": {
|
||||
"mount_path": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
@@ -4757,6 +4757,12 @@ func init() {
|
||||
"customCertificates": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"client": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/certificateInfo"
|
||||
}
|
||||
},
|
||||
"minio": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -4861,13 +4867,19 @@ func init() {
|
||||
"tlsConfiguration": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ca_certificates": {
|
||||
"minioCAsCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"minio": {
|
||||
"minioClientCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/keyPairConfiguration"
|
||||
}
|
||||
},
|
||||
"minioServerCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/keyPairConfiguration"
|
||||
@@ -4930,16 +4942,22 @@ func init() {
|
||||
"customCertificates": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"minio": {
|
||||
"minioCAsCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"minioClientCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/keyPairConfiguration"
|
||||
}
|
||||
},
|
||||
"minioCAs": {
|
||||
"minioServerCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
"$ref": "#/definitions/keyPairConfiguration"
|
||||
}
|
||||
},
|
||||
"secretsToBeDeleted": {
|
||||
@@ -8128,6 +8146,12 @@ func init() {
|
||||
"TenantSecurityResponseCustomCertificates": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"client": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/certificateInfo"
|
||||
}
|
||||
},
|
||||
"minio": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -8166,16 +8190,22 @@ func init() {
|
||||
"UpdateTenantSecurityRequestCustomCertificates": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"minio": {
|
||||
"minioCAsCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"minioClientCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/keyPairConfiguration"
|
||||
}
|
||||
},
|
||||
"minioCAs": {
|
||||
"minioServerCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
"$ref": "#/definitions/keyPairConfiguration"
|
||||
}
|
||||
},
|
||||
"secretsToBeDeleted": {
|
||||
@@ -8576,7 +8606,7 @@ func init() {
|
||||
"logSearchConfiguration": {
|
||||
"$ref": "#/definitions/logSearchConfiguration"
|
||||
},
|
||||
"mounth_path": {
|
||||
"mount_path": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
@@ -10535,6 +10565,12 @@ func init() {
|
||||
"customCertificates": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"client": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/certificateInfo"
|
||||
}
|
||||
},
|
||||
"minio": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -10639,13 +10675,19 @@ func init() {
|
||||
"tlsConfiguration": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ca_certificates": {
|
||||
"minioCAsCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"minio": {
|
||||
"minioClientCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/keyPairConfiguration"
|
||||
}
|
||||
},
|
||||
"minioServerCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/keyPairConfiguration"
|
||||
@@ -10708,16 +10750,22 @@ func init() {
|
||||
"customCertificates": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"minio": {
|
||||
"minioCAsCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"minioClientCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/keyPairConfiguration"
|
||||
}
|
||||
},
|
||||
"minioCAs": {
|
||||
"minioServerCertificates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
"$ref": "#/definitions/keyPairConfiguration"
|
||||
}
|
||||
},
|
||||
"secretsToBeDeleted": {
|
||||
|
||||
@@ -256,7 +256,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
}
|
||||
}
|
||||
|
||||
isEncryptionEnabled := false
|
||||
canEncryptionBeEnabled := false
|
||||
|
||||
if tenantReq.EnableTLS != nil {
|
||||
// if enableTLS is defined in the create tenant request we assign the value
|
||||
@@ -264,25 +264,35 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
minInst.Spec.RequestAutoCert = tenantReq.EnableTLS
|
||||
if *tenantReq.EnableTLS {
|
||||
// requestAutoCert is enabled, MinIO will be deployed with TLS enabled and encryption can be enabled
|
||||
isEncryptionEnabled = true
|
||||
canEncryptionBeEnabled = true
|
||||
}
|
||||
}
|
||||
// External TLS certificates for MinIO
|
||||
if tenantReq.TLS != nil && len(tenantReq.TLS.Minio) > 0 {
|
||||
isEncryptionEnabled = true
|
||||
// External server TLS certificates for MinIO
|
||||
if tenantReq.TLS != nil && len(tenantReq.TLS.MinioServerCertificates) > 0 {
|
||||
canEncryptionBeEnabled = true
|
||||
// Certificates used by the MinIO instance
|
||||
externalCertSecretName := fmt.Sprintf("%s-instance-external-certificates", secretName)
|
||||
externalCertSecret, err := createOrReplaceExternalCertSecrets(ctx, &k8sClient, ns, tenantReq.TLS.Minio, externalCertSecretName, tenantName)
|
||||
externalCertSecretName := fmt.Sprintf("%s-external-server-certificate", tenantName)
|
||||
externalCertSecret, err := createOrReplaceExternalCertSecrets(ctx, &k8sClient, ns, tenantReq.TLS.MinioServerCertificates, externalCertSecretName, tenantName)
|
||||
if err != nil {
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
minInst.Spec.ExternalCertSecret = externalCertSecret
|
||||
}
|
||||
// External client TLS certificates for MinIO
|
||||
if tenantReq.TLS != nil && len(tenantReq.TLS.MinioClientCertificates) > 0 {
|
||||
// Client certificates used by the MinIO instance
|
||||
externalClientCertSecretName := fmt.Sprintf("%s-external-client-certificate", tenantName)
|
||||
externalClientCertSecret, err := createOrReplaceExternalCertSecrets(ctx, &k8sClient, ns, tenantReq.TLS.MinioClientCertificates, externalClientCertSecretName, tenantName)
|
||||
if err != nil {
|
||||
return nil, restapi.ErrorWithContext(ctx, err)
|
||||
}
|
||||
minInst.Spec.ExternalClientCertSecrets = externalClientCertSecret
|
||||
}
|
||||
// If encryption configuration is present and TLS will be enabled (using AutoCert or External certificates)
|
||||
if tenantReq.Encryption != nil && isEncryptionEnabled {
|
||||
if tenantReq.Encryption != nil && canEncryptionBeEnabled {
|
||||
// KES client mTLSCertificates used by MinIO instance
|
||||
if tenantReq.Encryption.Client != nil {
|
||||
tenantExternalClientCertSecretName := fmt.Sprintf("%s-tenant-external-client-cert", secretName)
|
||||
tenantExternalClientCertSecretName := fmt.Sprintf("%s-external-client-certificate-kes", tenantName)
|
||||
certificates := []*models.KeyPairConfiguration{tenantReq.Encryption.Client}
|
||||
certificateSecrets, err := createOrReplaceExternalCertSecrets(ctx, &k8sClient, ns, certificates, tenantExternalClientCertSecretName, tenantName)
|
||||
if err != nil {
|
||||
@@ -312,15 +322,15 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
}
|
||||
}
|
||||
// External TLS CA certificates for MinIO
|
||||
if tenantReq.TLS != nil && len(tenantReq.TLS.CaCertificates) > 0 {
|
||||
if tenantReq.TLS != nil && len(tenantReq.TLS.MinioCAsCertificates) > 0 {
|
||||
var caCertificates []tenantSecret
|
||||
for i, caCertificate := range tenantReq.TLS.CaCertificates {
|
||||
for i, caCertificate := range tenantReq.TLS.MinioCAsCertificates {
|
||||
certificateContent, err := base64.StdEncoding.DecodeString(caCertificate)
|
||||
if err != nil {
|
||||
return nil, restapi.ErrorWithContext(ctx, restapi.ErrDefault, nil, err)
|
||||
}
|
||||
caCertificates = append(caCertificates, tenantSecret{
|
||||
Name: fmt.Sprintf("ca-certificate-%d", i),
|
||||
Name: fmt.Sprintf("%s-ca-certificate-%d", tenantName, i),
|
||||
Content: map[string][]byte{
|
||||
"public.crt": certificateContent,
|
||||
},
|
||||
@@ -353,8 +363,8 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
|
||||
}
|
||||
|
||||
// Set Mount Path if provided
|
||||
if tenantReq.MounthPath != "" {
|
||||
minInst.Spec.Mountpath = tenantReq.MounthPath
|
||||
if tenantReq.MountPath != "" {
|
||||
minInst.Spec.Mountpath = tenantReq.MountPath
|
||||
}
|
||||
|
||||
// We accept either `image_pull_secret` or the individual details of the `image_registry` but not both
|
||||
|
||||
@@ -71,7 +71,7 @@ func getTenantDetailsResponse(session *models.Principal, params operator_api.Ten
|
||||
|
||||
// detect if encryption is enabled
|
||||
info.EncryptionEnabled = minTenant.HasKESEnabled() || tenantConfiguration["MINIO_KMS_SECRET_KEY"] != ""
|
||||
info.LogEnabled = minTenant.HasLogEnabled()
|
||||
info.LogEnabled = minTenant.HasLogSearchAPIEnabled()
|
||||
info.MonitoringEnabled = minTenant.HasPrometheusEnabled()
|
||||
info.IdpAdEnabled = ldapEnabled
|
||||
info.IdpOidcEnabled = oidcEnabled
|
||||
|
||||
@@ -614,65 +614,70 @@ func parseTenantCertificates(ctx context.Context, clientSet K8sClientI, namespac
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if v, ok := secretTypePublicKeyNameMap[secret.Type]; ok {
|
||||
publicKey = v
|
||||
}
|
||||
|
||||
// Extract public key from certificate TLS secret
|
||||
if rawCert, ok := keyPair.Data[publicKey]; ok {
|
||||
var blocks []byte
|
||||
for {
|
||||
var block *pem.Block
|
||||
block, rawCert = pem.Decode(rawCert)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
if block.Type == "CERTIFICATE" {
|
||||
blocks = append(blocks, block.Bytes...)
|
||||
var rawCert []byte
|
||||
if _, ok := keyPair.Data[publicKey]; !ok {
|
||||
return nil, fmt.Errorf("public key: %v not found inside certificate secret %v", publicKey, secret.Name)
|
||||
}
|
||||
rawCert = keyPair.Data[publicKey]
|
||||
var blocks []byte
|
||||
for {
|
||||
var block *pem.Block
|
||||
block, rawCert = pem.Decode(rawCert)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
if block.Type == "CERTIFICATE" {
|
||||
blocks = append(blocks, block.Bytes...)
|
||||
}
|
||||
}
|
||||
// parse all certificates we found on this k8s secret
|
||||
certs, err := x509.ParseCertificates(blocks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cert := range certs {
|
||||
var domains []string
|
||||
if cert.Subject.CommonName != "" {
|
||||
domains = append(domains, cert.Subject.CommonName)
|
||||
}
|
||||
// append certificate domain names
|
||||
if len(cert.DNSNames) > 0 {
|
||||
domains = append(domains, cert.DNSNames...)
|
||||
}
|
||||
// append certificate IPs
|
||||
if len(cert.IPAddresses) > 0 {
|
||||
for _, ip := range cert.IPAddresses {
|
||||
domains = append(domains, ip.String())
|
||||
}
|
||||
}
|
||||
// parse all certificates we found on this k8s secret
|
||||
certs, err := x509.ParseCertificates(blocks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cert := range certs {
|
||||
var domains []string
|
||||
if cert.Subject.CommonName != "" {
|
||||
domains = append(domains, cert.Subject.CommonName)
|
||||
}
|
||||
// append certificate domain names
|
||||
if len(cert.DNSNames) > 0 {
|
||||
domains = append(domains, cert.DNSNames...)
|
||||
}
|
||||
// append certificate IPs
|
||||
if len(cert.IPAddresses) > 0 {
|
||||
for _, ip := range cert.IPAddresses {
|
||||
domains = append(domains, ip.String())
|
||||
}
|
||||
}
|
||||
certificates = append(certificates, &models.CertificateInfo{
|
||||
SerialNumber: cert.SerialNumber.String(),
|
||||
Name: secret.Name,
|
||||
Domains: domains,
|
||||
Expiry: cert.NotAfter.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
certificates = append(certificates, &models.CertificateInfo{
|
||||
SerialNumber: cert.SerialNumber.String(),
|
||||
Name: secret.Name,
|
||||
Domains: domains,
|
||||
Expiry: cert.NotAfter.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
}
|
||||
return certificates, nil
|
||||
}
|
||||
|
||||
func getTenantSecurity(ctx context.Context, clientSet K8sClientI, tenant *miniov2.Tenant) (response *models.TenantSecurityResponse, err error) {
|
||||
var minioExternalCertificates []*models.CertificateInfo
|
||||
var minioExternalServerCertificates []*models.CertificateInfo
|
||||
var minioExternalClientCertificates []*models.CertificateInfo
|
||||
var minioExternalCaCertificates []*models.CertificateInfo
|
||||
var tenantSecurityContext *models.SecurityContext
|
||||
// Certificates used by MinIO server
|
||||
if minioExternalCertificates, err = parseTenantCertificates(ctx, clientSet, tenant.Namespace, tenant.Spec.ExternalCertSecret); err != nil {
|
||||
// Server certificates used by MinIO
|
||||
if minioExternalServerCertificates, err = parseTenantCertificates(ctx, clientSet, tenant.Namespace, tenant.Spec.ExternalCertSecret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// CA Certificates used by MinIO server
|
||||
// Client certificates used by MinIO
|
||||
if minioExternalClientCertificates, err = parseTenantCertificates(ctx, clientSet, tenant.Namespace, tenant.Spec.ExternalClientCertSecrets); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// CA Certificates used by MinIO
|
||||
if minioExternalCaCertificates, err = parseTenantCertificates(ctx, clientSet, tenant.Namespace, tenant.Spec.ExternalCaCertSecret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -683,8 +688,9 @@ func getTenantSecurity(ctx context.Context, clientSet K8sClientI, tenant *miniov
|
||||
return &models.TenantSecurityResponse{
|
||||
AutoCert: tenant.AutoCert(),
|
||||
CustomCertificates: &models.TenantSecurityResponseCustomCertificates{
|
||||
Minio: minioExternalCertificates,
|
||||
Minio: minioExternalServerCertificates,
|
||||
MinioCAs: minioExternalCaCertificates,
|
||||
Client: minioExternalClientCertificates,
|
||||
},
|
||||
SecurityContext: tenantSecurityContext,
|
||||
}, nil
|
||||
@@ -857,13 +863,6 @@ func updateTenantIdentityProvider(ctx context.Context, operatorClient OperatorCl
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// restart all MinIO pods at the same time
|
||||
err = client.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
|
||||
LabelSelector: fmt.Sprintf("%s=%s", miniov2.TenantLabel, tenant.Name),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1034,47 +1033,55 @@ func updateTenantSecurity(ctx context.Context, operatorClient OperatorClientI, c
|
||||
}
|
||||
// Update AutoCert
|
||||
minInst.Spec.RequestAutoCert = ¶ms.Body.AutoCert
|
||||
var newMinIOExternalCertSecret []*miniov2.LocalCertificateReference
|
||||
var newMinIOExternalCaCertSecret []*miniov2.LocalCertificateReference
|
||||
// Remove Certificate Secrets from MinIO (Tenant.Spec.ExternalCertSecret)
|
||||
for _, certificate := range minInst.Spec.ExternalCertSecret {
|
||||
skip := false
|
||||
for _, certificateToBeDeleted := range params.Body.CustomCertificates.SecretsToBeDeleted {
|
||||
if certificate.Name == certificateToBeDeleted {
|
||||
skip = true
|
||||
break
|
||||
var newExternalCertSecret []*miniov2.LocalCertificateReference
|
||||
var newExternalClientCertSecrets []*miniov2.LocalCertificateReference
|
||||
var newExternalCaCertSecret []*miniov2.LocalCertificateReference
|
||||
secretsToBeRemoved := map[string]bool{}
|
||||
|
||||
if params.Body.CustomCertificates != nil {
|
||||
// Copy certificate secrets to be deleted into map
|
||||
for _, secret := range params.Body.CustomCertificates.SecretsToBeDeleted {
|
||||
secretsToBeRemoved[secret] = true
|
||||
}
|
||||
|
||||
// Remove certificates from Tenant.Spec.ExternalCertSecret
|
||||
for _, certificate := range minInst.Spec.ExternalCertSecret {
|
||||
if _, ok := secretsToBeRemoved[certificate.Name]; !ok {
|
||||
newExternalCertSecret = append(newExternalCertSecret, certificate)
|
||||
}
|
||||
}
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
newMinIOExternalCertSecret = append(newMinIOExternalCertSecret, certificate)
|
||||
}
|
||||
// Remove Certificate Secrets from MinIO CAs (Tenant.Spec.ExternalCaCertSecret)
|
||||
for _, certificate := range minInst.Spec.ExternalCaCertSecret {
|
||||
skip := false
|
||||
for _, certificateToBeDeleted := range params.Body.CustomCertificates.SecretsToBeDeleted {
|
||||
if certificate.Name == certificateToBeDeleted {
|
||||
skip = true
|
||||
break
|
||||
// Remove certificates from Tenant.Spec.ExternalClientCertSecrets
|
||||
for _, certificate := range minInst.Spec.ExternalClientCertSecrets {
|
||||
if _, ok := secretsToBeRemoved[certificate.Name]; !ok {
|
||||
newExternalClientCertSecrets = append(newExternalClientCertSecrets, certificate)
|
||||
}
|
||||
}
|
||||
if skip {
|
||||
continue
|
||||
// Remove certificates from Tenant.Spec.ExternalCaCertSecret
|
||||
for _, certificate := range minInst.Spec.ExternalCaCertSecret {
|
||||
if _, ok := secretsToBeRemoved[certificate.Name]; !ok {
|
||||
newExternalCaCertSecret = append(newExternalCaCertSecret, certificate)
|
||||
}
|
||||
}
|
||||
newMinIOExternalCaCertSecret = append(newMinIOExternalCaCertSecret, certificate)
|
||||
|
||||
}
|
||||
// Create new Certificate Secrets for MinIO
|
||||
secretName := fmt.Sprintf("%s-%s", minInst.Name, strings.ToLower(utils.RandomCharString(5)))
|
||||
externalCertSecretName := fmt.Sprintf("%s-external-certificates", secretName)
|
||||
externalCertSecrets, err := createOrReplaceExternalCertSecrets(ctx, client, minInst.Namespace, params.Body.CustomCertificates.Minio, externalCertSecretName, minInst.Name)
|
||||
// Create new Server Certificate Secrets for MinIO
|
||||
externalServerCertSecretName := fmt.Sprintf("%s-external-server-certificate", secretName)
|
||||
externalServerCertSecrets, err := createOrReplaceExternalCertSecrets(ctx, client, minInst.Namespace, params.Body.CustomCertificates.MinioServerCertificates, externalServerCertSecretName, minInst.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newMinIOExternalCertSecret = append(newMinIOExternalCertSecret, externalCertSecrets...)
|
||||
newExternalCertSecret = append(newExternalCertSecret, externalServerCertSecrets...)
|
||||
// Create new Client Certificate Secrets for MinIO
|
||||
externalClientCertSecretName := fmt.Sprintf("%s-external-client-certificate", secretName)
|
||||
externalClientCertSecrets, err := createOrReplaceExternalCertSecrets(ctx, client, minInst.Namespace, params.Body.CustomCertificates.MinioClientCertificates, externalClientCertSecretName, minInst.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newExternalClientCertSecrets = append(newExternalClientCertSecrets, externalClientCertSecrets...)
|
||||
// Create new CAs Certificate Secrets for MinIO
|
||||
var caCertificates []tenantSecret
|
||||
for i, caCertificate := range params.Body.CustomCertificates.MinioCAs {
|
||||
for i, caCertificate := range params.Body.CustomCertificates.MinioCAsCertificates {
|
||||
certificateContent, err := base64.StdEncoding.DecodeString(caCertificate)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1091,7 +1098,7 @@ func updateTenantSecurity(ctx context.Context, operatorClient OperatorClientI, c
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newMinIOExternalCaCertSecret = append(newMinIOExternalCaCertSecret, certificateSecrets...)
|
||||
newExternalCaCertSecret = append(newExternalCaCertSecret, certificateSecrets...)
|
||||
}
|
||||
|
||||
// set Security Context
|
||||
@@ -1105,20 +1112,13 @@ func updateTenantSecurity(ctx context.Context, operatorClient OperatorClientI, c
|
||||
}
|
||||
|
||||
// Update External Certificates
|
||||
minInst.Spec.ExternalCertSecret = newMinIOExternalCertSecret
|
||||
minInst.Spec.ExternalCaCertSecret = newMinIOExternalCaCertSecret
|
||||
minInst.Spec.ExternalCertSecret = newExternalCertSecret
|
||||
minInst.Spec.ExternalClientCertSecrets = newExternalClientCertSecrets
|
||||
minInst.Spec.ExternalCaCertSecret = newExternalCaCertSecret
|
||||
_, err = operatorClient.TenantUpdate(ctx, minInst, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// restart all MinIO pods at the same time
|
||||
err = client.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
|
||||
LabelSelector: fmt.Sprintf("%s=%s", miniov2.TenantLabel, minInst.Name),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -99,20 +99,12 @@ func tenantUpdateCertificates(ctx context.Context, operatorClient OperatorClient
|
||||
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)
|
||||
if tenant.ExternalCert() && body.MinioServerCertificates != nil {
|
||||
minioCertSecretName := fmt.Sprintf("%s-instance-external-certificates", tenantName)
|
||||
// update certificates
|
||||
if _, err := createOrReplaceExternalCertSecrets(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", miniov2.TenantLabel, tenantName),
|
||||
})
|
||||
if err != nil {
|
||||
if _, err := createOrReplaceExternalCertSecrets(ctx, clientSet, namespace, body.MinioServerCertificates, minioCertSecretName, tenantName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ func Test_tenantUpdateCertificates(t *testing.T) {
|
||||
namespace: "",
|
||||
params: operator_api.TenantUpdateCertificateParams{
|
||||
Body: &models.TLSConfiguration{
|
||||
Minio: []*models.KeyPairConfiguration{
|
||||
MinioServerCertificates: []*models.KeyPairConfiguration{
|
||||
{
|
||||
Crt: nil,
|
||||
Key: nil,
|
||||
@@ -133,7 +133,7 @@ func Test_tenantUpdateCertificates(t *testing.T) {
|
||||
namespace: "",
|
||||
params: operator_api.TenantUpdateCertificateParams{
|
||||
Body: &models.TLSConfiguration{
|
||||
Minio: []*models.KeyPairConfiguration{
|
||||
MinioServerCertificates: []*models.KeyPairConfiguration{
|
||||
{
|
||||
Crt: &badCrt,
|
||||
Key: &badKey,
|
||||
@@ -167,7 +167,7 @@ func Test_tenantUpdateCertificates(t *testing.T) {
|
||||
namespace: "",
|
||||
params: operator_api.TenantUpdateCertificateParams{
|
||||
Body: &models.TLSConfiguration{
|
||||
Minio: []*models.KeyPairConfiguration{
|
||||
MinioServerCertificates: []*models.KeyPairConfiguration{
|
||||
{
|
||||
Crt: &crt,
|
||||
Key: &key,
|
||||
@@ -195,46 +195,6 @@ func Test_tenantUpdateCertificates(t *testing.T) {
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "certificates replaced but error during deleting existing tenant pods",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
opClient: opClient,
|
||||
clientSet: k8sClient,
|
||||
namespace: "",
|
||||
params: operator_api.TenantUpdateCertificateParams{
|
||||
Body: &models.TLSConfiguration{
|
||||
Minio: []*models.KeyPairConfiguration{
|
||||
{
|
||||
Crt: &crt,
|
||||
Key: &key,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
mockTenantGet: func(ctx context.Context, namespace string, tenantName string, options metav1.GetOptions) (*miniov2.Tenant, error) {
|
||||
return &miniov2.Tenant{
|
||||
Spec: miniov2.TenantSpec{
|
||||
ExternalCertSecret: []*miniov2.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,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
opClientTenantGetMock = tt.args.mockTenantGet
|
||||
|
||||
@@ -28,6 +28,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
xhttp "github.com/minio/console/pkg/http"
|
||||
|
||||
"github.com/minio/console/operatorapi/operations/operator_api"
|
||||
@@ -41,7 +43,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
)
|
||||
|
||||
@@ -1215,3 +1217,140 @@ func Test_UpdateDomainsResponse(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseTenantCertificates(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
kClient := k8sClientMock{}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
clientSet K8sClientI
|
||||
namespace string
|
||||
secrets []*miniov2.LocalCertificateReference
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []*models.CertificateInfo
|
||||
mockGetSecret func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error)
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "empty secrets list",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
clientSet: kClient,
|
||||
secrets: nil,
|
||||
},
|
||||
mockGetSecret: func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
|
||||
return nil, nil
|
||||
},
|
||||
want: nil,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "error getting secret",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
clientSet: kClient,
|
||||
secrets: []*miniov2.LocalCertificateReference{
|
||||
{
|
||||
Name: "certificate-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
mockGetSecret: func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
|
||||
return nil, errors.New("error getting secret")
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "error getting certificate because of missing public key",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
clientSet: kClient,
|
||||
secrets: []*miniov2.LocalCertificateReference{
|
||||
{
|
||||
Name: "certificate-1",
|
||||
Type: "Opaque",
|
||||
},
|
||||
},
|
||||
},
|
||||
mockGetSecret: func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
|
||||
certificateSecret := &corev1.Secret{
|
||||
Data: map[string][]byte{
|
||||
"eaeaeae": []byte(`
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBUDCCAQKgAwIBAgIRALdFZh8hLU348ho9wYzlZbAwBQYDK2VwMBIxEDAOBgNV
|
||||
BAoTB0FjbWUgQ28wHhcNMjIwODE4MjAxMzUzWhcNMjMwODE4MjAxMzUzWjASMRAw
|
||||
DgYDVQQKEwdBY21lIENvMCowBQYDK2VwAyEAct5c3dzzbNOTi+C62w7QHoSivEWD
|
||||
MYAheDXZWHC55tGjbTBrMA4GA1UdDwEB/wQEAwIChDATBgNVHSUEDDAKBggrBgEF
|
||||
BQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs0At8sTSLCjiM24AZhxFY
|
||||
a2CswjAUBgNVHREEDTALgglsb2NhbGhvc3QwBQYDK2VwA0EABan+d16CeN8UD+QF
|
||||
a8HBhPAiOpaZeEF6+EqTlq9VfL3eSVd7CLRI+/KtY7ptwomuTeYzuV73adKdE9N2
|
||||
ZrJuAw==
|
||||
-----END CERTIFICATE-----
|
||||
`),
|
||||
},
|
||||
Type: "Opaque",
|
||||
}
|
||||
return certificateSecret, nil
|
||||
},
|
||||
want: nil,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "return certificate from existing secret",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
clientSet: kClient,
|
||||
secrets: []*miniov2.LocalCertificateReference{
|
||||
{
|
||||
Name: "certificate-1",
|
||||
Type: "Opaque",
|
||||
},
|
||||
},
|
||||
},
|
||||
mockGetSecret: func(ctx context.Context, namespace, secretName string, opts metav1.GetOptions) (*corev1.Secret, error) {
|
||||
certificateSecret := &corev1.Secret{
|
||||
Data: map[string][]byte{
|
||||
"public.crt": []byte(`
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBUDCCAQKgAwIBAgIRALdFZh8hLU348ho9wYzlZbAwBQYDK2VwMBIxEDAOBgNV
|
||||
BAoTB0FjbWUgQ28wHhcNMjIwODE4MjAxMzUzWhcNMjMwODE4MjAxMzUzWjASMRAw
|
||||
DgYDVQQKEwdBY21lIENvMCowBQYDK2VwAyEAct5c3dzzbNOTi+C62w7QHoSivEWD
|
||||
MYAheDXZWHC55tGjbTBrMA4GA1UdDwEB/wQEAwIChDATBgNVHSUEDDAKBggrBgEF
|
||||
BQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs0At8sTSLCjiM24AZhxFY
|
||||
a2CswjAUBgNVHREEDTALgglsb2NhbGhvc3QwBQYDK2VwA0EABan+d16CeN8UD+QF
|
||||
a8HBhPAiOpaZeEF6+EqTlq9VfL3eSVd7CLRI+/KtY7ptwomuTeYzuV73adKdE9N2
|
||||
ZrJuAw==
|
||||
-----END CERTIFICATE-----
|
||||
`),
|
||||
},
|
||||
Type: "Opaque",
|
||||
}
|
||||
return certificateSecret, nil
|
||||
},
|
||||
want: []*models.CertificateInfo{
|
||||
{
|
||||
SerialNumber: "243609062983998893460787085129017550256",
|
||||
Name: "certificate-1",
|
||||
Expiry: "2023-08-18T20:13:53Z",
|
||||
Domains: []string{"localhost"},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
k8sclientGetSecretMock = tt.mockGetSecret
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseTenantCertificates(tt.args.ctx, tt.args.clientSet, tt.args.namespace, tt.args.secrets)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseTenantCertificates(%v, %v, %v, %v)error = %v, wantErr %v", tt.args.ctx, tt.args.clientSet, tt.args.namespace, tt.args.secrets, err, tt.wantErr)
|
||||
}
|
||||
assert.Equalf(t, tt.want, got, "parseTenantCertificates(%v, %v, %v, %v)", tt.args.ctx, tt.args.clientSet, tt.args.namespace, tt.args.secrets)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user