Skip to content

Commit

Permalink
No more operator tls (#1515)
Browse files Browse the repository at this point in the history
* No more operator tls
* No issue a certificate for Operator
* Remove need on `operator-tls` secret
* Remove MINIO_OPERATOR_TLS_ENABLE env variable
* remove env variable from helm
  • Loading branch information
pjuarezd committed Mar 21, 2023
1 parent c4213ec commit d1abc0d
Show file tree
Hide file tree
Showing 8 changed files with 11 additions and 249 deletions.
19 changes: 1 addition & 18 deletions docs/tls.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# MinIO Operator TLS Configuration [![Slack](https://slack.min.io/slack?type=svg)](https://slack.min.io)
# MinIO TLS Configuration [![Slack](https://slack.min.io/slack?type=svg)](https://slack.min.io)

This document explains how to enable TLS on MinIO pods.

Expand Down Expand Up @@ -88,23 +88,6 @@ Finally, configure MinIO to use the newly created TLS certificate:
type: kubernetes.io/tls
```

---

## Rotate MinIO Operator TLS certificates

In case the operator TLS certificate expired you can just delete the `operator-tls` secret in the `minio-operator` namespace and
operator will generate a new one automatically, additionally it will copy the `public.crt` portion of the certificate into
each tenant namespace

---

## Using your own certificate for MinIO Operator

If you wish to use your own certificate for `MinIO Operator` instead of using the auto generated one, just delete or replace the content of the
`operator-tls` secret in the `minio-operator` namespace, `operator-tls` must contain the `public.crt` and `private.key` keys.

---

## Using your own CA Certificate for MinIO Operator

If your `MinIO` tenants are using `custom certificates` or certificates generated by your own internal `certificate authority` (ie: `cert-manager`).
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.20
require (
github.com/blang/semver/v4 v4.0.0
github.com/docker/cli v20.10.22+incompatible
github.com/dustin/go-humanize v1.0.1
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.14.1
github.com/go-openapi/errors v0.20.3
github.com/go-openapi/loads v0.21.2
Expand Down
2 changes: 0 additions & 2 deletions helm/operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
operator:
## Setup environment variables for the Operator
# env:
# - name: MINIO_OPERATOR_TLS_ENABLE
# value: "off"
# - name: MINIO_CONSOLE_TLS_ENABLE
# value: "off"
# - name: CLUSTER_DOMAIN
Expand Down
5 changes: 2 additions & 3 deletions pkg/controller/console.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,11 @@ func (c *Controller) recreateOperatorConsoleCertsIfRequired(ctx context.Context)
return nil
}

// isOperatorConsoleTLS Internal func, reads MINIO_OPERATOR_TLS_ENABLE ENV to identify if Operator Console TLS is enabled, default "off"
// **WARNING** This will change and will be default to "on" in operator v5
// isOperatorConsoleTLS Internal func, reads MINIO_CONSOLE_TLS_ENABLE ENV to identify if Operator Console TLS is enabled, default "off"
func isOperatorConsoleTLS() bool {
value, set := os.LookupEnv(ConsoleTLSEnv)
// By default, Console TLS is NOT used.
return (set && value == "on")
return set && value == "on"
}

func getConsoleDeploymentName() string {
Expand Down
38 changes: 2 additions & 36 deletions pkg/controller/main-controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,10 @@ import (

xcerts "github.com/minio/pkg/certs"

"github.com/minio/operator/pkg/controller/certificates"

"k8s.io/klog/v2"

"github.com/minio/minio-go/v7/pkg/set"
"github.com/minio/operator/pkg/controller/certificates"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/klog/v2"

"k8s.io/client-go/tools/leaderelection"
"k8s.io/client-go/tools/leaderelection/resourcelock"
Expand Down Expand Up @@ -116,9 +114,6 @@ var ErrMinIONotReady = fmt.Errorf("MinIO is not ready")
// ErrMinIORestarting is the error returned when MinIO is restarting
var ErrMinIORestarting = fmt.Errorf("MinIO is restarting")

// ErrLogSearchNotReady is the error returned when Log Search is not Ready
var ErrLogSearchNotReady = fmt.Errorf("Log Search is not ready")

// Controller struct watches the Kubernetes API for changes to Tenant resources
type Controller struct {
// podName is the identifier of this instance
Expand Down Expand Up @@ -794,11 +789,6 @@ func (c *Controller) syncHandler(key string) error {
klog.V(2).Infof(err.Error())
}

// In case the operator certificate is removed or expired, re-create them
if err := c.recreateOperatorCertsIfRequired(ctx); err != nil {
return err
}

// validate the minio certificates
err = c.checkMinIOCertificatesStatus(ctx, tenant, nsName)
if err != nil {
Expand Down Expand Up @@ -883,12 +873,6 @@ func (c *Controller) syncHandler(key string) error {
return err
}

// check if operator-tls has to be updated or re-created in the tenant namespace
err = c.checkOperatorCertForTenant(ctx, tenant)
if err != nil {
return err
}

// check if operator-ca-tls has to be updated or re-created in the tenant namespace
operatorCATLSExists, err := c.checkOperatorCaForTenant(ctx, tenant)
if err != nil {
Expand Down Expand Up @@ -934,7 +918,6 @@ func (c *Controller) syncHandler(key string) error {

// Check if we need to create any of the pools. It's important not to update the statefulsets
// in this loop because we need all the pools "as they are" for the hot-update below
operatorTLSCertIsMounted := false
for i, pool := range tenant.Spec.Pools {
// Get the StatefulSet with the name specified in Tenant.status.pools[i].SSName

Expand Down Expand Up @@ -967,7 +950,6 @@ func (c *Controller) syncHandler(key string) error {
ServiceName: hlSvc.Name,
HostsTemplate: c.hostsTemplate,
OperatorVersion: c.operatorVersion,
OperatorTLS: isOperatorTLS(),
OperatorCATLS: operatorCATLSExists,
OperatorImage: c.operatorImage,
})
Expand All @@ -989,20 +971,6 @@ func (c *Controller) syncHandler(key string) error {
// keep track of all replicas
totalReplicas += ss.Status.Replicas
images = append(images, ss.Spec.Template.Spec.Containers[0].Image)

// check if operator-tls public.crt is mounted on MinIO pods
if !operatorTLSCertIsMounted {
for _, volume := range ss.Spec.Template.Spec.Volumes {
if volume.Projected == nil || volume.Projected.Sources == nil {
continue
}
for _, vp := range volume.Projected.Sources {
if vp.Secret.Name == OperatorTLSSecretName {
operatorTLSCertIsMounted = true
}
}
}
}
}

var initializedPool miniov2.Pool
Expand Down Expand Up @@ -1200,7 +1168,6 @@ func (c *Controller) syncHandler(key string) error {
ServiceName: hlSvc.Name,
HostsTemplate: c.hostsTemplate,
OperatorVersion: c.operatorVersion,
OperatorTLS: isOperatorTLS(),
OperatorCATLS: operatorCATLSExists,
OperatorImage: c.operatorImage,
})
Expand Down Expand Up @@ -1251,7 +1218,6 @@ func (c *Controller) syncHandler(key string) error {
ServiceName: hlSvc.Name,
HostsTemplate: c.hostsTemplate,
OperatorVersion: c.operatorVersion,
OperatorTLS: isOperatorTLS(),
OperatorCATLS: operatorCATLSExists,
OperatorImage: c.operatorImage,
})
Expand Down
77 changes: 0 additions & 77 deletions pkg/controller/minio.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,83 +192,6 @@ func (c *Controller) checkOperatorCaForTenant(ctx context.Context, tenant *minio
return true, nil
}

// checkOperatorCertForTenant checks create or updates the operator-tls secret for tenant
func (c *Controller) checkOperatorCertForTenant(ctx context.Context, tenant *miniov2.Tenant) error {
if !isOperatorTLS() {
return nil
}
// get operator-tls in minio-operator namespace
operatorCertSecret, err := c.kubeClientSet.CoreV1().Secrets(miniov2.GetNSFromFile()).Get(ctx, OperatorTLSSecretName, metav1.GetOptions{})
if err != nil {
return err
}

// default secret keys for Opaque k8s secret
publicCertKey := "public.crt"
// if secret type is k8s tls or cert-manager use the right secret keys
if operatorCertSecret.Type == "kubernetes.io/tls" || operatorCertSecret.Type == "cert-manager.io/v1alpha2" || operatorCertSecret.Type == "cert-manager.io/v1" {
publicCertKey = "tls.crt"
}

if _, ok := operatorCertSecret.Data[publicCertKey]; !ok {
return fmt.Errorf("missing '%s' in %s/%s secret", publicCertKey, miniov2.GetNSFromFile(), OperatorTLSSecretName)
}

operatorCert := operatorCertSecret.Data[publicCertKey]

tenantOperatorCertSecret, err := c.kubeClientSet.CoreV1().Secrets(tenant.Namespace).Get(ctx, OperatorTLSSecretName, metav1.GetOptions{})
if err != nil {
if k8serrors.IsNotFound(err) {
klog.Infof("'%s/%s' secret not found, creating one now", tenant.Namespace, OperatorTLSSecretName)
// create tenant operator-tls secret copying only the public.crt portion from the original operator-tls secret
opTLSSecret := &corev1.Secret{
Type: "Opaque",
ObjectMeta: metav1.ObjectMeta{
Name: OperatorTLSSecretName,
Namespace: tenant.Namespace,
Labels: tenant.MinIOPodLabels(),
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(tenant, schema.GroupVersionKind{
Group: miniov2.SchemeGroupVersion.Group,
Version: miniov2.SchemeGroupVersion.Version,
Kind: miniov2.MinIOCRDResourceKind,
}),
},
},
Data: map[string][]byte{
"public.crt": operatorCert,
},
}
_, err := c.kubeClientSet.CoreV1().Secrets(tenant.Namespace).Create(ctx, opTLSSecret, metav1.CreateOptions{})
if err != nil {
return err
}
}
return err
}

if _, ok := tenantOperatorCertSecret.Data["public.crt"]; !ok {
err = c.kubeClientSet.CoreV1().Secrets(tenant.Namespace).Delete(ctx, OperatorTLSSecretName, metav1.DeleteOptions{})
if err != nil {
return err
}
return fmt.Errorf("missing 'public.crt' in %s/%s secret, re-creating it", tenant.Namespace, OperatorTLSSecretName)
}

tenantOperatorCert := tenantOperatorCertSecret.Data["public.crt"]

if string(tenantOperatorCert) != string(operatorCert) {
tenantOperatorCertSecret.Data["public.crt"] = operatorCert
_, err = c.kubeClientSet.CoreV1().Secrets(tenant.Namespace).Update(ctx, tenantOperatorCertSecret, metav1.UpdateOptions{})
if err != nil {
return err
}
return fmt.Errorf("'%s' key in %s/%s secret changed, updating '%s/%s' secret", publicCertKey, miniov2.GetNSFromFile(), OperatorTLSSecretName, tenant.Namespace, OperatorTLSSecretName)
}

return nil
}

// checkMinIOCertificatesStatus checks for the current status of MinIO and it's service
func (c *Controller) checkMinIOCertificatesStatus(ctx context.Context, tenant *miniov2.Tenant, nsName types.NamespacedName) error {
if tenant.AutoCert() {
Expand Down
89 changes: 0 additions & 89 deletions pkg/controller/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"crypto/tls"
"net"
"net/http"
"os"
"time"

appsv1 "k8s.io/api/apps/v1"
Expand All @@ -43,12 +42,8 @@ const (
CertPasswordEnv = "OPERATOR_CERT_PASSWD"
// OperatorDeplymentNameEnv Env variable to specify a custom deployment name for Operator
OperatorDeplymentNameEnv = "MINIO_OPERATOR_DEPLOYMENT_NAME"
// OperatorTLSEnv Env variable to turn on / off Operator TLS.
OperatorTLSEnv = "MINIO_OPERATOR_TLS_ENABLE"
// OperatorCATLSSecretName is the name of the secret for the operator CA
OperatorCATLSSecretName = "operator-ca-tls"
// OperatorTLSSecretName is the name of secret created with TLS certs for Operator
OperatorTLSSecretName = "operator-tls"
// DefaultDeploymentName is the default name of the operator deployment
DefaultDeploymentName = "minio-operator"
// DefaultOperatorImage is the version fo the operator being used
Expand Down Expand Up @@ -80,62 +75,6 @@ func (c *Controller) rolloutRestartDeployment(deployName string) error {
return nil
}

// generateOperatorTLSCert Issues the Operator TLS Certificate
func (c *Controller) generateOperatorTLSCert() (*string, *string) {
return c.generateTLSCert("operator", OperatorTLSSecretName, getOperatorDeploymentName())
}

// recreateOperatorCertsIfRequired - Generate Operator TLS certs if not present or if is expired
func (c *Controller) recreateOperatorCertsIfRequired(ctx context.Context) error {
namespace := miniov2.GetNSFromFile()
operatorTLSSecret, err := c.getTLSSecret(ctx, namespace, OperatorTLSSecretName)
if err != nil {
if k8serrors.IsNotFound(err) {
klog.V(2).Info("TLS certificate not found. Generating one.")
// Generate new certificate KeyPair for Operator server
c.generateOperatorTLSCert()
// reload in memory certificate for the operator server
if serverCertsManager != nil {
serverCertsManager.ReloadCerts()
}

return nil
}
return err
}

needsRenewal, err := c.certNeedsRenewal(operatorTLSSecret)
if err != nil {
return err
}

if !needsRenewal {
return nil
}

// Expired cert. Delete the secret + CSR and re-create the cert
err = c.deleteCSR(ctx, operatorCSRName())
if err != nil {
return err
}
klog.V(2).Info("Deleting the TLS secret of expired cert on operator")
err = c.kubeClientSet.CoreV1().Secrets(namespace).Delete(ctx, OperatorTLSSecretName, metav1.DeleteOptions{})
if err != nil {
return err
}

klog.V(2).Info("Generating a fresh TLS certificate for Operator")
// Generate new certificate KeyPair for Operator server
c.generateOperatorTLSCert()

// reload in memory certificate for the operator server
if serverCertsManager != nil {
serverCertsManager.ReloadCerts()
}

return nil
}

func (c *Controller) fetchUserCredentials(ctx context.Context, tenant *miniov2.Tenant) []*v1.Secret {
var userCredentials []*v1.Secret
for _, credential := range tenant.Spec.Users {
Expand All @@ -155,22 +94,6 @@ func (c *Controller) getTransport() *http.Transport {
// Default kubernetes CA certificate
rootCAs.AppendCertsFromPEM(miniov2.GetPodCAFromFile())

// If ca.crt exists in operator-tls (ie if the cert was issued by cert-manager) load the ca certificate from there
operatorTLSCert, err := c.kubeClientSet.CoreV1().Secrets(miniov2.GetNSFromFile()).Get(context.Background(), OperatorTLSSecretName, metav1.GetOptions{})
if err == nil && operatorTLSCert != nil {
// default secret keys for Opaque k8s secret
caCertKey := "public.crt"
// if secret type is k8s tls or cert-manager use the right ca key
if operatorTLSCert.Type == "kubernetes.io/tls" {
caCertKey = "tls.crt"
} else if operatorTLSCert.Type == "cert-manager.io/v1alpha2" || operatorTLSCert.Type == "cert-manager.io/v1" {
caCertKey = "ca.crt"
}
if val, ok := operatorTLSCert.Data[caCertKey]; ok {
rootCAs.AppendCertsFromPEM(val)
}
}

// Custom ca certificate to be used by operator
operatorCATLSCert, err := c.kubeClientSet.CoreV1().Secrets(miniov2.GetNSFromFile()).Get(context.Background(), OperatorCATLSSecretName, metav1.GetOptions{})
if err == nil && operatorCATLSCert != nil {
Expand Down Expand Up @@ -313,15 +236,3 @@ func (c *Controller) createBuckets(ctx context.Context, tenant *miniov2.Tenant,
func getOperatorDeploymentName() string {
return env.Get(OperatorDeplymentNameEnv, DefaultDeploymentName)
}

// isOperatorTLS Internal func, reads MINIO_OPERATOR_TLS_ENABLE ENV to identify if Operator TLS is enabled, default "on"
func isOperatorTLS() bool {
value, set := os.LookupEnv(OperatorTLSEnv)
// By default, Operator TLS is used.
return (set && value == "on") || !set
}

// operatorCSRName Internal func returns the given operator CSR name
func operatorCSRName() string {
return getCSRName("operator")
}

0 comments on commit d1abc0d

Please sign in to comment.