Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion docs/mcs.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ MCS Configuration is a part of MinIOInstance yaml file. Check the sample file [a
|-----------------------|-------------|
| spec.mcs | Defines the mcs configuration. mcs is a graphical user interface for MinIO. Refer [this](https://github.com/minio/mcs) |
| spec.mcs.image | Defines the mcs image |
| spec.mcs.mcsAccessKey | Specify the access key to be used by mcs |
| spec.mcs.replicas | Number of MCS pods to be created. |
| spec.mcs.mcsSecret | Use this secret to assign mcs credentials to MinIOInstance. |
| spec.mcs.selector | Add a selector for the mcs. Which will be used by the mcs container for grouping. (Note: Should not match the labels provided in `spec.selector`) |
| spec.mcs.metadata | This allows a way to map metadata to the mcs container. Internally `metadata` is a struct type as [explained here](https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#ObjectMeta). [Note: Should match the labels in `spec.mcs.selector`] |
Expand All @@ -39,3 +39,16 @@ Alternatively, you can deploy the example like this
```
kubectl create -f https://raw.githubusercontent.com/minio/minio-operator/master/examples/minioinstance-mcs.yaml
```

Above example file uses CSR for self signed certificate generation. MinIO requires one certificates/key pair

- X.509 certificate for the MinIO server and the corresponding private key.

Accordingly, you'll need to approve the CSR request, using below approach

```
kubectl get csr
kubectl certificate approve <csr-name>
```

Once all the CSRs are approved, MinIO Operator will deploy MCS Pods and start MinIO Server with MCS integration.
2 changes: 1 addition & 1 deletion docs/operator-fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ If the MirrorInstance is named as `mirrorinstance`, resources and their names as
| spec.securityContext | Define a security context for the MinIOInstance pod. Refer [this document](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for details. |
| spec.mcs | Defines the mcs configuration. mcs is a graphical user interface for MinIO. Refer [this](https://github.com/minio/mcs) |
| spec.mcs.image | Defines the mcs image. |
| spec.mcs.mcsAccessKey | Specify the access key to be used by mcs |
| spec.mcs.replicas | Number of MCS pods to be created. |
| spec.mcs.mcsSecret | Use this secret to assign mcs credentials to MinIOInstance. |
| spec.mcs.selector | Add a selector for the mcs. Which will be used by the mcs container for grouping. (Note: Should not match the labels provided in `spec.selector`) |
| spec.mcs.metadata | This allows a way to map metadata to the mcs container. Internally `metadata` is a struct type as [explained here](https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#ObjectMeta). [Note: Should match the labels in `spec.mcs.selector`] |
Expand Down
4 changes: 2 additions & 2 deletions examples/minioinstance-kes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ spec:
storage: 10Gi
## Define configuration for MCS (Graphical user interface for MinIO)
mcs:
image: minio/mcs:v0.0.3
mcsAccessKey: "mcs"
image: minio/mcs:v0.0.4
replicas: 2
mcsSecret:
name: minio-mcs-secret
metadata:
Expand Down
17 changes: 10 additions & 7 deletions examples/minioinstance-mcs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ metadata:
name: minio-mcs-secret
type: Opaque
data:
mcshmacjwt: WU9VUkpXVFNJR05JTkdTRUNSRVQ= # base 64 encoded "YOURJWTSIGNINGSECRET" (echo -n 'YOURJWTSIGNINGSECRET' | base64)
mcspbkdfpassphrase: U0VDUkVU # base 64 encoded "SECRET" (echo -n 'SECRET' | base64)
mcspbkdfsalt: U0VDUkVU # base 64 encoded "SECRET" (echo -n 'SECRET' | base64)
mcssecretkey: WU9VUk1DU1NFQ1JFVA== # base 64 encoded "YOURMCSSECRET" (echo -n 'YOURMCSSECRET' | base64)
MCS_HMAC_JWT_SECRET: WU9VUkpXVFNJR05JTkdTRUNSRVQ= # base 64 encoded "YOURJWTSIGNINGSECRET" (echo -n 'YOURJWTSIGNINGSECRET' | base64)
MCS_PBKDF_PASSPHRASE: U0VDUkVU # base 64 encoded "SECRET" (echo -n 'SECRET' | base64)
MCS_PBKDF_SALT: U0VDUkVU # base 64 encoded "SECRET" (echo -n 'SECRET' | base64)
MCS_ACCESS_KEY: WU9VUk1DU0FDQ0VTUw== # base 64 encoded "YOURMCSACCESS" (echo -n 'YOURMCSACCESS' | base64)
MCS_SECRET_KEY: WU9VUk1DU1NFQ1JFVA== # base 64 encoded "YOURMCSSECRET" (echo -n 'YOURMCSSECRET' | base64)
---
apiVersion: v1
kind: Service
Expand Down Expand Up @@ -84,8 +85,8 @@ spec:
storage: 10Gi
## Define configuration for MCS (Graphical user interface for MinIO)
mcs:
image: minio/mcs:v0.0.3
mcsAccessKey: "mcs"
image: minio/mcs:v0.0.4
replicas: 2
mcsSecret:
name: minio-mcs-secret
metadata:
Expand All @@ -100,7 +101,7 @@ spec:
# name: tls-ssl-minio
## Enable Kubernetes based certificate generation and signing as explained in
## https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster
requestAutoCert: false
requestAutoCert: true
## PodManagement policy for pods created by StatefulSet. Can be "OrderedReady" or "Parallel"
## Refer https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/#pod-management-policy
## for details. Defaults to "Parallel"
Expand Down Expand Up @@ -136,6 +137,7 @@ spec:
## restarts the pods if liveness checks fail.
liveness:
httpGet:
scheme: HTTPS
path: /minio/health/live
port: 9000
initialDelaySeconds: 120
Expand All @@ -147,6 +149,7 @@ spec:
## Disable this check if you're setting PodManagementPolicy to "OrderedReady".
readiness:
httpGet:
scheme: HTTPS
path: /minio/health/ready
port: 9000
initialDelaySeconds: 120
Expand Down
4 changes: 2 additions & 2 deletions examples/minioinstance.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ spec:
# value: storage
## Define configuration for mcs (A graphical user interface for MinIO)
mcs:
image: minio/mcs:v0.0.3
mcsAccessKey: "mcs"
image: minio/mcs:v0.0.4
replicas: 2
mcsSecret:
name: minio-mcs-secret
selector:
Expand Down
5 changes: 4 additions & 1 deletion pkg/apis/operator.min.io/v1/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const MirrorCRDResourceKind = "MirrorInstance"
// MCS Related Constants

// DefaultMCSImage specifies the latest MCS Docker hub image
const DefaultMCSImage = "minio/mcs:v0.0.3"
const DefaultMCSImage = "minio/mcs:v0.0.4"

// MCSInstanceLabel is applied to the MCS pods of a MinIOInstance cluster
const MCSInstanceLabel = "v1.min.io/mcs"
Expand All @@ -127,6 +127,9 @@ const MCSAdminPolicyName = "mcsAdmin"
// MCSRestartPolicy defines the default restart policy for MCS Containers
const MCSRestartPolicy = corev1.RestartPolicyAlways

// DefaultMCSReplicas specifies the default number of MCS pods to be created if not specified
const DefaultMCSReplicas = 2

// KES Related Constants

// DefaultKESImage specifies the latest KES Docker hub image
Expand Down
58 changes: 50 additions & 8 deletions pkg/apis/operator.min.io/v1/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ package v1

import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
"path"
"strconv"
"time"
Expand Down Expand Up @@ -167,8 +169,13 @@ func (mi *MinIOInstance) EnsureDefaults() *MinIOInstance {
}
}

if mi.HasMCSEnabled() && mi.Spec.MCS.Image == "" {
mi.Spec.MCS.Image = DefaultMCSImage
if mi.HasMCSEnabled() {
if mi.Spec.MCS.Image == "" {
mi.Spec.MCS.Image = DefaultMCSImage
}
if mi.Spec.MCS.Replicas == 0 {
mi.Spec.MCS.Replicas = DefaultMCSReplicas
}
}

if mi.HasKESEnabled() {
Expand Down Expand Up @@ -292,7 +299,7 @@ func (mi *MinIOInstance) HasKESSelector() bool {
// CreateMCSUser function creates an admin user
func (mi *MinIOInstance) CreateMCSUser(minioSecret, mcsSecret map[string][]byte) error {

var accessKey, secretKey, mcsSecretKey []byte
var accessKey, secretKey, mcsAccessKey, mcsSecretKey []byte
var ok bool

host := net.JoinHostPort(mi.MinIOCIServiceHost(), strconv.Itoa(MinIOPort))
Expand All @@ -310,19 +317,30 @@ func (mi *MinIOInstance) CreateMCSUser(minioSecret, mcsSecret map[string][]byte)
return errors.New("secretkey not provided")
}

mcsSecretKey, ok = mcsSecret["mcssecretkey"]
mcsAccessKey, ok = mcsSecret["MCS_ACCESS_KEY"]
if !ok {
return errors.New("MCS_ACCESS_KEY not provided")
}

mcsSecretKey, ok = mcsSecret["MCS_SECRET_KEY"]
if !ok {
return errors.New("mcssecretkey not provided")
return errors.New("MCS_SECRET_KEY not provided")
}

madmClnt, err := madmin.New(host, string(accessKey), string(secretKey), Scheme == "https")
if err != nil {
return err
}
// try to add user with a 20 seconds timeout

if Scheme == "https" {
madmClnt = setUpInsecureTLS(madmClnt)
}

// add user with a 20 seconds timeout
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
defer cancel()
if err = madmClnt.AddUser(ctx, mi.Spec.MCS.MCSAccessKey, string(mcsSecretKey)); err != nil {

if err = madmClnt.AddUser(ctx, string(mcsAccessKey), string(mcsSecretKey)); err != nil {
return err
}

Expand Down Expand Up @@ -351,13 +369,37 @@ func (mi *MinIOInstance) CreateMCSUser(minioSecret, mcsSecret map[string][]byte)
return err
}

if err = madmClnt.SetPolicy(context.Background(), MCSAdminPolicyName, string(mi.Spec.MCS.MCSAccessKey), false); err != nil {
if err = madmClnt.SetPolicy(context.Background(), MCSAdminPolicyName, string(mcsAccessKey), false); err != nil {
return err
}

return nil
}

// Set up admin client to use self certificates
func setUpInsecureTLS(api *madmin.AdminClient) *madmin.AdminClient {
// Keep TLS config.
tlsConfig := &tls.Config{
// Can't use SSLv3 because of POODLE and BEAST
// Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
// Can't use TLSv1.1 because of RC4 cipher usage
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: true,
}

var transport http.RoundTripper = &http.Transport{
DialContext: (&net.Dialer{
Timeout: 10 * time.Second,
KeepAlive: 15 * time.Second,
}).DialContext,
TLSClientConfig: tlsConfig,
}

// Set custom transport.
api.SetCustomTransport(transport)
return api
}

// OwnerRef returns the OwnerReference to be added to all resources created by MinIOInstance
func (mi *MinIOInstance) OwnerRef() []metav1.OwnerReference {
return []metav1.OwnerReference{
Expand Down
16 changes: 11 additions & 5 deletions pkg/apis/operator.min.io/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,17 @@ type Zone struct {

// MCSConfig defines the credentials for mcs
type MCSConfig struct {
Image string `json:"image,omitempty"`
MCSAccessKey string `json:"mcsAccessKey"`
MCSSecret *corev1.LocalObjectReference `json:"mcsSecret,omitempty"`
Selector *metav1.LabelSelector `json:"selector,omitempty"`
Metadata *metav1.ObjectMeta `json:"metadata,omitempty"`
// Replicas defines number of pods for KES StatefulSet.
// +optional
Replicas int32 `json:"replicas,omitempty"`
// Image defines the MinIOInstance Docker image.
// +optional
Image string `json:"image,omitempty"`
// This secret provides all environment variables for KES
// This is a mandatory field
MCSSecret *corev1.LocalObjectReference `json:"mcsSecret,omitempty"`
Selector *metav1.LabelSelector `json:"selector,omitempty"`
Metadata *metav1.ObjectMeta `json:"metadata,omitempty"`
}

// KESConfig defines the specifications for KES StatefulSet
Expand Down
79 changes: 26 additions & 53 deletions pkg/resources/deployments/mcs-deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,59 +27,33 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// Returns the MCS environment variables set in configuration.
func mcsEnvironmentVars(mi *miniov1.MinIOInstance) []corev1.EnvVar {
envVars := make([]corev1.EnvVar, 0)
if mi.HasMCSSecret() {
var secretName string
secretName = mi.Spec.MCS.MCSSecret.Name
envVars = append(envVars, corev1.EnvVar{
Name: "MCS_HMAC_JWT_SECRET",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretName,
},
Key: "mcshmacjwt",
},
},
}, corev1.EnvVar{
Name: "MCS_PBKDF_PASSPHRASE",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretName,
},
Key: "mcspbkdfpassphrase",
},
},
}, corev1.EnvVar{
Name: "MCS_PBKDF_SALT",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretName,
},
Key: "mcspbkdfsalt",
},
},
}, corev1.EnvVar{
// Adds required MCS environment variables
func mcsEnvVars(mi *miniov1.MinIOInstance) []corev1.EnvVar {
envVars := []corev1.EnvVar{
{
Name: "MCS_MINIO_SERVER",
Value: miniov1.Scheme + "://" + net.JoinHostPort(mi.MinIOCIServiceHost(), strconv.Itoa(miniov1.MinIOPort)),
}, corev1.EnvVar{
Name: "MCS_SECRET_KEY",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: secretName,
},
Key: "mcssecretkey",
},
}
if miniov1.Scheme == "https" {
envVars = append(envVars, corev1.EnvVar{
Name: "MCS_MINIO_SERVER_TLS_SKIP_VERIFICATION",
Value: "on",
})
}
return envVars
}

// Returns the MCS environment variables set in configuration.
func mcsSecretEnvVars(mi *miniov1.MinIOInstance) []corev1.EnvFromSource {
envVars := []corev1.EnvFromSource{
{
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: mi.Spec.MCS.MCSSecret.Name,
},
},
}, corev1.EnvVar{
Name: "MCS_ACCESS_KEY",
Value: mi.Spec.MCS.MCSAccessKey,
})
},
}
return envVars
}
Expand Down Expand Up @@ -123,24 +97,23 @@ func mcsContainer(mi *miniov1.MinIOInstance) corev1.Container {
},
ImagePullPolicy: miniov1.DefaultImagePullPolicy,
Args: args,
Env: mcsEnvironmentVars(mi),
Env: mcsEnvVars(mi),
EnvFrom: mcsSecretEnvVars(mi),
Resources: mi.Spec.Resources,
}
}

// NewForMCS creates a new Deployment for the given MinIO instance.
func NewForMCS(mi *miniov1.MinIOInstance) *appsv1.Deployment {

var replicas int32 = 1

d := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Namespace: mi.Namespace,
Name: mi.MCSDeploymentName(),
OwnerReferences: mi.OwnerRef(),
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
Replicas: &mi.Spec.MCS.Replicas,
Selector: mi.Spec.MCS.Selector,
Template: corev1.PodTemplateSpec{
ObjectMeta: mcsMetadata(mi),
Expand Down