Fix Session validation for MCS Operator Mode (#191)

* Fix Session validation for MCS Operator Mode

* Updated assets
This commit is contained in:
Daniel Valdivia
2020-07-08 13:55:08 -07:00
committed by GitHub
parent 8a74b795c8
commit 328133d3ff
41 changed files with 608 additions and 398 deletions

View File

@@ -24,7 +24,7 @@ import (
) )
func GetK8sConfig(token string) *rest.Config { func GetK8sConfig(token string) *rest.Config {
// if m3 is running inside k8s by default he will have access to the ca cert from the k8s local authority // if console is running inside k8s by default he will have access to the ca cert from the k8s local authority
const ( const (
rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
) )
@@ -33,7 +33,7 @@ func GetK8sConfig(token string) *rest.Config {
tlsClientConfig.CAFile = rootCAFile tlsClientConfig.CAFile = rootCAFile
} }
config := &rest.Config{ config := &rest.Config{
Host: getK8sAPIServer(), Host: GetK8sAPIServer(),
TLSClientConfig: tlsClientConfig, TLSClientConfig: tlsClientConfig,
APIPath: "/", APIPath: "/",
BearerToken: token, BearerToken: token,

View File

@@ -34,27 +34,27 @@ var (
errCantDetermineMCImage = errors.New("can't determine MC Image") errCantDetermineMCImage = errors.New("can't determine MC Image")
) )
func getK8sAPIServer() string { func GetK8sAPIServer() string {
// if m3 is running inside a k8s pod KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT will contain the k8s api server apiServerAddress // if console is running inside a k8s pod KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT will contain the k8s api server apiServerAddress
// if m3 is not running inside k8s by default will look for the k8s api server on localhost:8001 (kubectl proxy) // if console is not running inside k8s by default will look for the k8s api server on localhost:8001 (kubectl proxy)
// NOTE: using kubectl proxy is for local development only, since every request send to localhost:8001 will bypass service account authentication // NOTE: using kubectl proxy is for local development only, since every request send to localhost:8001 will bypass service account authentication
// more info here: https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#directly-accessing-the-rest-api // more info here: https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#directly-accessing-the-rest-api
// you can override this using M3_K8S_API_SERVER, ie use the k8s cluster from `kubectl config view` // you can override this using MCS_K8S_API_SERVER, ie use the k8s cluster from `kubectl config view`
host, port := env.Get("KUBERNETES_SERVICE_HOST", ""), env.Get("KUBERNETES_SERVICE_PORT", "") host, port := env.Get("KUBERNETES_SERVICE_HOST", ""), env.Get("KUBERNETES_SERVICE_PORT", "")
apiServerAddress := "http://localhost:8001" apiServerAddress := "http://localhost:8001"
if host != "" && port != "" { if host != "" && port != "" {
apiServerAddress = "https://" + net.JoinHostPort(host, port) apiServerAddress = "https://" + net.JoinHostPort(host, port)
} }
return env.Get(M3K8sAPIServer, apiServerAddress) return env.Get(McsK8sAPIServer, apiServerAddress)
} }
// getK8sAPIServerInsecure allow to tell the k8s client to skip TLS certificate verification, ie: when connecting to a k8s cluster // getK8sAPIServerInsecure allow to tell the k8s client to skip TLS certificate verification, ie: when connecting to a k8s cluster
// that uses certificate not trusted by your machine // that uses certificate not trusted by your machine
func getK8sAPIServerInsecure() bool { func getK8sAPIServerInsecure() bool {
return strings.ToLower(env.Get(m3k8SAPIServerInsecure, "off")) == "on" return strings.ToLower(env.Get(McsK8SAPIServerInsecure, "off")) == "on"
} }
// GetNsFromFile assumes mkube is running inside a k8s pod and extract the current namespace from the // GetNsFromFile assumes console is running inside a k8s pod and extract the current namespace from the
// /var/run/secrets/kubernetes.io/serviceaccount/namespace file // /var/run/secrets/kubernetes.io/serviceaccount/namespace file
func GetNsFromFile() string { func GetNsFromFile() string {
dat, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace") dat, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
@@ -64,12 +64,12 @@ func GetNsFromFile() string {
return string(dat) return string(dat)
} }
// This operation will run only once at mkube startup // This operation will run only once at console startup
var namespace = GetNsFromFile() var namespace = GetNsFromFile()
// Returns the namespace in which the controller is installed // Returns the namespace in which the controller is installed
func GetNs() string { func GetNs() string {
return env.Get(M3Namespace, namespace) return env.Get(McsNamespace, namespace)
} }
// getLatestMinIOImage returns the latest docker image for MinIO if found on the internet // getLatestMinIOImage returns the latest docker image for MinIO if found on the internet
@@ -106,7 +106,7 @@ var latestMinIOImage, errLatestMinIOImage = getLatestMinIOImage(
// a preferred image to be used (configured via ENVIRONMENT VARIABLES) GetMinioImage will return that // a preferred image to be used (configured via ENVIRONMENT VARIABLES) GetMinioImage will return that
// if not, GetMinioImage will try to obtain the image URL for the latest version of MinIO and return that // if not, GetMinioImage will try to obtain the image URL for the latest version of MinIO and return that
func GetMinioImage() (*string, error) { func GetMinioImage() (*string, error) {
image := strings.TrimSpace(env.Get(M3MinioImage, "")) image := strings.TrimSpace(env.Get(McsMinioImage, ""))
// if there is a preferred image configured by the user we'll always return that // if there is a preferred image configured by the user we'll always return that
if image != "" { if image != "" {
return &image, nil return &image, nil
@@ -156,7 +156,7 @@ func getLatestMCImage() (*string, error) {
var latestMCImage, errLatestMCImage = getLatestMCImage() var latestMCImage, errLatestMCImage = getLatestMCImage()
func GetMCImage() (*string, error) { func GetMCImage() (*string, error) {
image := strings.TrimSpace(env.Get(M3MCImage, "")) image := strings.TrimSpace(env.Get(McsMCImage, ""))
// if there is a preferred image configured by the user we'll always return that // if there is a preferred image configured by the user we'll always return that
if image != "" { if image != "" {
return &image, nil return &image, nil

View File

@@ -17,9 +17,9 @@
package cluster package cluster
const ( const (
M3K8sAPIServer = "M3_K8S_API_SERVER" McsK8sAPIServer = "MCS_K8S_API_SERVER"
m3k8SAPIServerInsecure = "M3_K8S_API_SERVER_INSECURE" McsK8SAPIServerInsecure = "MCS_K8S_API_SERVER_INSECURE"
M3MinioImage = "M3_MINIO_IMAGE" McsMinioImage = "MCS_MINIO_IMAGE"
M3MCImage = "M3_MC_IMAGE" McsMCImage = "MCS_MC_IMAGE"
M3Namespace = "M3_NAMESPACE" McsNamespace = "MCS_NAMESPACE"
) )

View File

@@ -0,0 +1,27 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcs
spec:
replicas: 1
selector:
matchLabels:
app: mcs
template:
metadata:
labels:
app: mcs
spec:
serviceAccountName: m3-sa
containers:
- name: mcs
image: minio/mcs:latest
imagePullPolicy: "IfNotPresent"
args:
- /mcs
- server
ports:
- containerPort: 9090
name: http
- containerPort: 9433
name: https

View File

@@ -0,0 +1,11 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# beginning of customizations
resources:
- mcs-service-account.yaml
- mcs-cluster-role.yaml
- mcs-cluster-role-binding.yaml
- mcs-configmap.yaml
- mcs-service.yaml
- mcs-deployment.yaml
- minio-operator.yaml

View File

@@ -0,0 +1,12 @@
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: mcs-sa-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: mcs-sa-role
subjects:
- kind: ServiceAccount
name: mcs-sa
namespace: default

View File

@@ -0,0 +1,77 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: mcs-sa-role
rules:
- apiGroups:
- ""
resources:
- namespaces
- secrets
- pods
- services
- events
- resourcequotas
verbs:
- get
- watch
- create
- list
- patch
- apiGroups:
- "storage.k8s.io"
resources:
- storageclasses
verbs:
- get
- watch
- create
- list
- patch
- apiGroups:
- apps
resources:
- statefulsets
- deployments
verbs:
- get
- create
- list
- patch
- watch
- update
- delete
- apiGroups:
- batch
resources:
- jobs
verbs:
- get
- create
- list
- patch
- watch
- update
- delete
- apiGroups:
- "certificates.k8s.io"
resources:
- "certificatesigningrequests"
- "certificatesigningrequests/approval"
- "certificatesigningrequests/status"
verbs:
- update
- create
- get
- apiGroups:
- operator.min.io
resources:
- "*"
verbs:
- "*"
- apiGroups:
- min.io
resources:
- "*"
verbs:
- "*"

View File

@@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: mcs-env
data:
MCS_PORT: "9090"
MCS_TLS_PORT: "9443"

View File

@@ -18,7 +18,7 @@ spec:
image: minio/mcs:latest image: minio/mcs:latest
imagePullPolicy: "IfNotPresent" imagePullPolicy: "IfNotPresent"
env: env:
- name: MCS_MKUBE_ADMIN_ONLY - name: MCS_OPERATOR_MODE
value: "on" value: "on"
args: args:
- /mcs - /mcs

View File

@@ -0,0 +1,5 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: mcs-sa
namespace: default

View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: mcs
labels:
name: mcs
spec:
ports:
- port: 9090
name: http
- port: 9443
name: https
selector:
app: mcs

View File

@@ -0,0 +1,203 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: minioinstances.operator.min.io
spec:
group: operator.min.io
scope: Namespaced
names:
kind: MinIOInstance
singular: minioinstance
plural: minioinstances
versions:
- name: v1
served: true
storage: true
schema:
# openAPIV3Schema is the schema for validating custom objects.
# Refer https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#specifying-a-structural-schema
# for more details
openAPIV3Schema:
type: object
properties:
spec:
type: object
x-kubernetes-preserve-unknown-fields: true
properties:
replicas:
type: integer
minimum: 1
maximum: 32
image:
type: string
serviceName:
type: string
volumesPerServer:
type: integer
mountPath:
type: string
podManagementPolicy:
type: string
enum: [Parallel, OrderedReady]
default: Parallel
requestAutoCert:
type: boolean
default: false
version:
type: string
mountpath:
type: string
subpath:
type: string
mcs:
type: object
x-kubernetes-preserve-unknown-fields: true
properties:
image:
type: string
replicas:
type: integer
default: 2
mcsSecret:
type: object
properties:
name:
type: string
kes:
type: object
x-kubernetes-preserve-unknown-fields: true
properties:
image:
type: string
replicas:
type: integer
default: 2
kesSecret:
type: object
properties:
name:
type: string
status:
type: object
properties:
currentState:
type: string
subresources:
# status enables the status subresource.
status: {}
additionalPrinterColumns:
- name: Current State
type: string
jsonPath: ".status.currentState"
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: minio-operator-role
rules:
- apiGroups:
- ""
resources:
- namespaces
- secrets
- pods
- services
- events
verbs:
- get
- watch
- create
- list
- delete
- apiGroups:
- apps
resources:
- statefulsets
- deployments
verbs:
- get
- create
- list
- patch
- watch
- update
- delete
- apiGroups:
- batch
resources:
- jobs
verbs:
- get
- create
- list
- patch
- watch
- update
- delete
- apiGroups:
- "certificates.k8s.io"
resources:
- "certificatesigningrequests"
- "certificatesigningrequests/approval"
- "certificatesigningrequests/status"
verbs:
- update
- create
- get
- delete
- apiGroups:
- operator.min.io
resources:
- "*"
verbs:
- "*"
- apiGroups:
- min.io
resources:
- "*"
verbs:
- "*"
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: minio-operator
namespace: default
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: minio-operator-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: minio-operator-role
subjects:
- kind: ServiceAccount
name: minio-operator
namespace: default
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: minio-operator
namespace: default
spec:
replicas: 1
selector:
matchLabels:
name: minio-operator
template:
metadata:
labels:
name: minio-operator
spec:
serviceAccountName: minio-operator
containers:
- name: minio-operator
image: minio/k8s-operator:2.0.8
imagePullPolicy: IfNotPresent
# To specify cluster domain, un comment the following:
# env:
# - name: CLUSTER_DOMAIN
# value: mycluster.mydomain

View File

@@ -29,18 +29,18 @@ import (
"github.com/go-openapi/validate" "github.com/go-openapi/validate"
) )
// LoginMkubeRequest login mkube request // LoginOperatorRequest login operator request
// //
// swagger:model loginMkubeRequest // swagger:model loginOperatorRequest
type LoginMkubeRequest struct { type LoginOperatorRequest struct {
// jwt // jwt
// Required: true // Required: true
Jwt *string `json:"jwt"` Jwt *string `json:"jwt"`
} }
// Validate validates this login mkube request // Validate validates this login operator request
func (m *LoginMkubeRequest) Validate(formats strfmt.Registry) error { func (m *LoginOperatorRequest) Validate(formats strfmt.Registry) error {
var res []error var res []error
if err := m.validateJwt(formats); err != nil { if err := m.validateJwt(formats); err != nil {
@@ -53,7 +53,7 @@ func (m *LoginMkubeRequest) Validate(formats strfmt.Registry) error {
return nil return nil
} }
func (m *LoginMkubeRequest) validateJwt(formats strfmt.Registry) error { func (m *LoginOperatorRequest) validateJwt(formats strfmt.Registry) error {
if err := validate.Required("jwt", "body", m.Jwt); err != nil { if err := validate.Required("jwt", "body", m.Jwt); err != nil {
return err return err
@@ -63,7 +63,7 @@ func (m *LoginMkubeRequest) validateJwt(formats strfmt.Registry) error {
} }
// MarshalBinary interface implementation // MarshalBinary interface implementation
func (m *LoginMkubeRequest) MarshalBinary() ([]byte, error) { func (m *LoginOperatorRequest) MarshalBinary() ([]byte, error) {
if m == nil { if m == nil {
return nil, nil return nil, nil
} }
@@ -71,8 +71,8 @@ func (m *LoginMkubeRequest) MarshalBinary() ([]byte, error) {
} }
// UnmarshalBinary interface implementation // UnmarshalBinary interface implementation
func (m *LoginMkubeRequest) UnmarshalBinary(b []byte) error { func (m *LoginOperatorRequest) UnmarshalBinary(b []byte) error {
var res LoginMkubeRequest var res LoginOperatorRequest
if err := swag.ReadJSON(b, &res); err != nil { if err := swag.ReadJSON(b, &res); err != nil {
return err return err
} }

View File

@@ -22,8 +22,7 @@ import (
"github.com/minio/minio/pkg/env" "github.com/minio/minio/pkg/env"
) )
// GetOperatorOnly gets MCS mkube admin mode status set on env variable // GetOperatorMode gets MCS Operator mode status set on env variable or default one
// or default one func GetOperatorMode() bool {
func GetOperatorOnly() bool { return strings.ToLower(env.Get(mcsOperatorMode, "off")) == "on"
return strings.ToLower(env.Get(McsmKubeAdminOnly, "off")) == "on"
} }

View File

@@ -17,5 +17,5 @@
package acl package acl
const ( const (
McsmKubeAdminOnly = "MCS_MKUBE_ADMIN_ONLY" mcsOperatorMode = "MCS_OPERATOR_MODE"
) )

View File

@@ -233,7 +233,7 @@ var operatorRules = map[string]ConfigurationActionSet{
} }
// operatorOnly ENV variable // operatorOnly ENV variable
var operatorOnly = GetOperatorOnly() var operatorOnly = GetOperatorMode()
// GetActionsStringFromPolicy extract the admin/s3 actions from a given policy and return them in []string format // GetActionsStringFromPolicy extract the admin/s3 actions from a given policy and return them in []string format
// //

View File

@@ -21,17 +21,17 @@ import (
"log" "log"
"net/http" "net/http"
"github.com/minio/mcs/pkg/auth/mkube" "github.com/minio/mcs/cluster"
"github.com/minio/minio-go/v6/pkg/credentials" "github.com/minio/minio-go/v6/pkg/credentials"
) )
// mkubeCredentialsProvider is an struct to hold the JWT (service account token) // operatorCredentialsProvider is an struct to hold the JWT (service account token)
type mkubeCredentialsProvider struct { type operatorCredentialsProvider struct {
serviceAccountJWT string serviceAccountJWT string
} }
// Implementing the interfaces of the minio Provider, we use this to leverage on the existing mcs Authentication flow // Implementing the interfaces of the minio Provider, we use this to leverage on the existing mcs Authentication flow
func (s mkubeCredentialsProvider) Retrieve() (credentials.Value, error) { func (s operatorCredentialsProvider) Retrieve() (credentials.Value, error) {
return credentials.Value{ return credentials.Value{
AccessKeyID: "", AccessKeyID: "",
SecretAccessKey: "", SecretAccessKey: "",
@@ -40,38 +40,32 @@ func (s mkubeCredentialsProvider) Retrieve() (credentials.Value, error) {
} }
// IsExpired dummy function, must be implemented in order to work with the minio provider authentication // IsExpired dummy function, must be implemented in order to work with the minio provider authentication
func (s mkubeCredentialsProvider) IsExpired() bool { func (s operatorCredentialsProvider) IsExpired() bool {
return false return false
} }
// isServiceAccountTokenValid will make an authenticated request (using bearer token) against Mkube hostname, if the // isServiceAccountTokenValid will make an authenticated request (using bearer token) against kubernetes api, if the
// request success means the provided jwt its a valid service account token and the MCS user can use it for future requests // request success means the provided jwt its a valid service account token and the MCS user can use it for future
// until it fails // requests until it fails
func isServiceAccountTokenValid(client *http.Client, jwt string) bool { func isServiceAccountTokenValid(client *http.Client, jwt string) bool {
url := fmt.Sprintf("%s/api/v1/tenants", mkube.GetMkubeEndpoint()) //# Explore the API with TOKEN
m3Req, err := http.NewRequest("GET", url, nil) //curl -X GET $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
apiURL := fmt.Sprintf("%s/api", cluster.GetK8sAPIServer())
req, _ := http.NewRequest("GET", apiURL, nil)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", jwt))
_, err := client.Do(req)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return false return false
} }
token := fmt.Sprintf("Bearer %s", jwt) return true
m3Req.Header.Add("Authorization", token)
resp, err := client.Do(m3Req)
if err != nil {
log.Println(err)
return false
}
defer resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
return true
}
return false
} }
// GetMcsCredentialsFromMkube will validate the provided JWT (service account token) and return it in the form of credentials.Credentials // GetMcsCredentialsForOperator will validate the provided JWT (service account token) and return it in the form of credentials.Credentials
func GetMcsCredentialsFromMkube(jwt string) (*credentials.Credentials, error) { func GetMcsCredentialsForOperator(jwt string) (*credentials.Credentials, error) {
if isServiceAccountTokenValid(mkube.HTTPClient, jwt) { client := http.Client{}
return credentials.New(mkubeCredentialsProvider{serviceAccountJWT: jwt}), nil if isServiceAccountTokenValid(&client, jwt) {
return credentials.New(operatorCredentialsProvider{serviceAccountJWT: jwt}), nil
} }
return nil, errInvalidCredentials return nil, errInvalidCredentials
} }

View File

@@ -1,117 +0,0 @@
// 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 mkube
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"github.com/minio/minio/pkg/env"
)
var (
certDontExists = "File certificate doesn't exists: %s"
)
// getMkubeEndpoint returns the hostname of mkube
func GetMkubeEndpoint() string {
return env.Get(McsMkubeHost, "http://m3:8787")
}
// getMkubeEndpointIsSecure returns true or false depending on the protocol in Mkube URL
func getMkubeEndpointIsSecure() bool {
server := GetMkubeEndpoint()
if strings.Contains(server, "://") {
parts := strings.Split(server, "://")
if len(parts) > 1 {
if parts[0] == "https" {
return true
}
}
}
return false
}
// If MCS_M3_SERVER_TLS_CA_CERTIFICATE is true mcs will load a list of certificates into the
// http.client rootCAs store, this is useful for testing or when working with self-signed certificates
func getMkubeServerTLSRootCAs() []string {
caCertFileNames := strings.TrimSpace(env.Get(McsMkubeTLSCACertificate, ""))
if caCertFileNames == "" {
return []string{}
}
return strings.Split(caCertFileNames, ",")
}
// FileExists verifies if a file exist on the desired location and its not a folder
func FileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
// GetMkubeHTTPClient returns an http.Client with custom configurations used by MCS to talk to Mkube
// custom configurations include the use of CA certificates
func getMkubeHTTPClient() *http.Client {
httpTransport := &http.Transport{}
// If Mkube server is running with TLS enabled and it's using a self-signed certificate
// or a certificate issued by a custom certificate authority we prepare a new custom *http.Transport
if getMkubeEndpointIsSecure() {
caCertFileNames := getMkubeServerTLSRootCAs()
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,
}
// If CAs certificates are configured we save them to the http.Client RootCAs store
if len(caCertFileNames) > 0 {
certs := x509.NewCertPool()
for _, caCert := range caCertFileNames {
// Validate certificate exists
if FileExists(caCert) {
pemData, err := ioutil.ReadFile(caCert)
if err != nil {
// if there was an error reading pem file stop mcs
panic(err)
}
certs.AppendCertsFromPEM(pemData)
} else {
// if provided cert filename doesn't exists stop mcs
panic(fmt.Sprintf(certDontExists, caCert))
}
}
tlsConfig.RootCAs = certs
}
httpTransport.TLSClientConfig = tlsConfig
}
// Return http client with default configuration
return &http.Client{
Transport: httpTransport,
}
}
// HTTPClient it's a public variable that contains the HTTP configuration to be used by MCS to talk to Mkube
// This function will run only once
var HTTPClient = getMkubeHTTPClient()

View File

@@ -1,22 +0,0 @@
// 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 mkube
const (
McsMkubeHost = "MCS_M3_HOSTNAME"
McsMkubeTLSCACertificate = "MCS_M3_SERVER_TLS_CA_CERTIFICATE"
)

File diff suppressed because one or more lines are too long

View File

@@ -122,7 +122,7 @@ const Login = ({ classes, userLoggedIn }: ILoginProps) => {
const loginStrategyEndpoints: LoginStrategyRoutes = { const loginStrategyEndpoints: LoginStrategyRoutes = {
form: "/api/v1/login", form: "/api/v1/login",
"service-account": "/api/v1/login/mkube", "service-account": "/api/v1/login/operator",
}; };
const loginStrategyPayload: LoginStrategyPayload = { const loginStrategyPayload: LoginStrategyPayload = {
form: { accessKey, secretKey }, form: { accessKey, secretKey },

View File

@@ -29,7 +29,6 @@ import (
"github.com/minio/mcs/pkg/auth" "github.com/minio/mcs/pkg/auth"
xjwt "github.com/minio/mcs/pkg/auth/jwt" xjwt "github.com/minio/mcs/pkg/auth/jwt"
"github.com/minio/mcs/pkg/auth/ldap" "github.com/minio/mcs/pkg/auth/ldap"
"github.com/minio/mcs/pkg/auth/mkube"
"github.com/minio/minio-go/v6" "github.com/minio/minio-go/v6"
"github.com/minio/minio-go/v6/pkg/credentials" "github.com/minio/minio-go/v6/pkg/credentials"
) )
@@ -162,18 +161,14 @@ func (s mcsSTSAssumeRole) IsExpired() bool {
// STSClient contains http.client configuration need it by STSAssumeRole // STSClient contains http.client configuration need it by STSAssumeRole
var STSClient = PrepareSTSClient() var STSClient = PrepareSTSClient()
var MinioEndpoint = getMinIOServer() var MinioEndpoint = getMinIOServer()
var MkubeEndpoint = mkube.GetMkubeEndpoint()
func newMcsCredentials(accessKey, secretKey, location string) (*credentials.Credentials, error) { func newMcsCredentials(accessKey, secretKey, location string) (*credentials.Credentials, error) {
// Future authentication methods can be added under this switch statement // Future authentication methods can be added under this switch statement
switch { switch {
// MKUBE authentication for MCS // authentication for Operator Console
case acl.GetOperatorOnly(): case acl.GetOperatorMode():
{ {
if MkubeEndpoint == "" { creds, err := auth.GetMcsCredentialsForOperator(secretKey)
return nil, errors.New("endpoint cannot be empty for Mkube")
}
creds, err := auth.GetMcsCredentialsFromMkube(secretKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -236,5 +236,5 @@ func getSecureExpectCTHeader() string {
// getTenantMemorySize Memory size value to be used when generating the // getTenantMemorySize Memory size value to be used when generating the
// MinioInstance request // MinioInstance request
func getTenantMemorySize() string { func getTenantMemorySize() string {
return env.Get(M3TenantMemorySize, defaultTenantMemorySize) return env.Get(McsTenantMemorySize, defaultTenantMemorySize)
} }

View File

@@ -24,6 +24,8 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/minio/mcs/pkg/acl"
"github.com/minio/mcs/models" "github.com/minio/mcs/models"
"github.com/minio/mcs/pkg" "github.com/minio/mcs/pkg"
"github.com/minio/mcs/pkg/auth" "github.com/minio/mcs/pkg/auth"
@@ -60,9 +62,18 @@ func configureAPI(api *operations.McsAPI) http.Handler {
// Applies when the "x-token" header is set // Applies when the "x-token" header is set
api.KeyAuth = func(token string, scopes []string) (*models.Principal, error) { api.KeyAuth = func(token string, scopes []string) (*models.Principal, error) {
if auth.IsJWTValid(token) { if acl.GetOperatorMode() {
prin := models.Principal(token) // here we just check the token is present on the request, authentication will be done
return &prin, nil // by kubernetes api server
if token != "" {
prin := models.Principal(token)
return &prin, nil
}
} else {
if auth.IsJWTValid(token) {
prin := models.Principal(token)
return &prin, nil
}
} }
log.Printf("Access attempt with incorrect api key auth: %s", token) log.Printf("Access attempt with incorrect api key auth: %s", token)
return nil, errors.New(401, "incorrect api key auth") return nil, errors.New(401, "incorrect api key auth")
@@ -99,7 +110,7 @@ func configureAPI(api *operations.McsAPI) http.Handler {
// Register admin Service Account Handlers // Register admin Service Account Handlers
registerServiceAccountsHandlers(api) registerServiceAccountsHandlers(api)
//m3 // Operator Console
// Register tenant handlers // Register tenant handlers
registerTenantHandlers(api) registerTenantHandlers(api)
// Register ResourceQuota handlers // Register ResourceQuota handlers

View File

@@ -17,12 +17,6 @@
package restapi package restapi
const ( const (
// consts for common configuration // McsTenantMemorySize Memory size to be used when creating MinioInstance request
M3Version = `0.1.0` McsTenantMemorySize = "MCS_TENANT_MEMORY_SIZE"
M3Hostname = "M3_HOSTNAME"
M3Port = "M3_PORT"
M3TLSHostname = "M3_TLS_HOSTNAME"
M3TLSPort = "M3_TLS_PORT"
// M3TenantMemorySize Memory size to be used when creating MinioInstance request
M3TenantMemorySize = "M3_TENANT_MEMORY_SIZE"
) )

View File

@@ -754,21 +754,21 @@ func init() {
} }
} }
}, },
"/login/mkube": { "/login/oauth2/auth": {
"post": { "post": {
"security": [], "security": [],
"tags": [ "tags": [
"UserAPI" "UserAPI"
], ],
"summary": "Login to Mkube.", "summary": "Identity Provider oauth2 callback endpoint.",
"operationId": "LoginMkube", "operationId": "LoginOauth2Auth",
"parameters": [ "parameters": [
{ {
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/loginMkubeRequest" "$ref": "#/definitions/loginOauth2AuthRequest"
} }
} }
], ],
@@ -788,21 +788,21 @@ func init() {
} }
} }
}, },
"/login/oauth2/auth": { "/login/operator": {
"post": { "post": {
"security": [], "security": [],
"tags": [ "tags": [
"UserAPI" "UserAPI"
], ],
"summary": "Identity Provider oauth2 callback endpoint.", "summary": "Login to Operator Console.",
"operationId": "LoginOauth2Auth", "operationId": "LoginOperator",
"parameters": [ "parameters": [
{ {
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/loginOauth2AuthRequest" "$ref": "#/definitions/loginOperatorRequest"
} }
} }
], ],
@@ -2126,17 +2126,6 @@ func init() {
} }
} }
}, },
"loginMkubeRequest": {
"type": "object",
"required": [
"jwt"
],
"properties": {
"jwt": {
"type": "string"
}
}
},
"loginOauth2AuthRequest": { "loginOauth2AuthRequest": {
"type": "object", "type": "object",
"required": [ "required": [
@@ -2152,6 +2141,17 @@ func init() {
} }
} }
}, },
"loginOperatorRequest": {
"type": "object",
"required": [
"jwt"
],
"properties": {
"jwt": {
"type": "string"
}
}
},
"loginRequest": { "loginRequest": {
"type": "object", "type": "object",
"required": [ "required": [
@@ -3396,21 +3396,21 @@ func init() {
} }
} }
}, },
"/login/mkube": { "/login/oauth2/auth": {
"post": { "post": {
"security": [], "security": [],
"tags": [ "tags": [
"UserAPI" "UserAPI"
], ],
"summary": "Login to Mkube.", "summary": "Identity Provider oauth2 callback endpoint.",
"operationId": "LoginMkube", "operationId": "LoginOauth2Auth",
"parameters": [ "parameters": [
{ {
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/loginMkubeRequest" "$ref": "#/definitions/loginOauth2AuthRequest"
} }
} }
], ],
@@ -3430,21 +3430,21 @@ func init() {
} }
} }
}, },
"/login/oauth2/auth": { "/login/operator": {
"post": { "post": {
"security": [], "security": [],
"tags": [ "tags": [
"UserAPI" "UserAPI"
], ],
"summary": "Identity Provider oauth2 callback endpoint.", "summary": "Login to Operator Console.",
"operationId": "LoginOauth2Auth", "operationId": "LoginOperator",
"parameters": [ "parameters": [
{ {
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/loginOauth2AuthRequest" "$ref": "#/definitions/loginOperatorRequest"
} }
} }
], ],
@@ -4782,17 +4782,6 @@ func init() {
} }
} }
}, },
"loginMkubeRequest": {
"type": "object",
"required": [
"jwt"
],
"properties": {
"jwt": {
"type": "string"
}
}
},
"loginOauth2AuthRequest": { "loginOauth2AuthRequest": {
"type": "object", "type": "object",
"required": [ "required": [
@@ -4808,6 +4797,17 @@ func init() {
} }
} }
}, },
"loginOperatorRequest": {
"type": "object",
"required": [
"jwt"
],
"properties": {
"jwt": {
"type": "string"
}
}
},
"loginRequest": { "loginRequest": {
"type": "object", "type": "object",
"required": [ "required": [

View File

@@ -170,15 +170,15 @@ func gkeIntegration(clientset *kubernetes.Clientset, tenantName string, namespac
return err return err
} }
// udpate ingress with this new service // udpate ingress with this new service
m3Ingress, err := clientset.ExtensionsV1beta1().Ingresses(namespace).Get(context.Background(), "mkube-ingress", metav1.GetOptions{}) consoleIngress, err := clientset.ExtensionsV1beta1().Ingresses(namespace).Get(context.Background(), "console-ingress", metav1.GetOptions{})
if err != nil { if err != nil {
return err return err
} }
certsInIngress := m3Ingress.ObjectMeta.Annotations["networking.gke.io/managed-certificates"] certsInIngress := consoleIngress.ObjectMeta.Annotations["networking.gke.io/managed-certificates"]
allCerts := strings.Split(certsInIngress, ",") allCerts := strings.Split(certsInIngress, ",")
allCerts = append(allCerts, manCertName) allCerts = append(allCerts, manCertName)
m3Ingress.ObjectMeta.Annotations["networking.gke.io/managed-certificates"] = strings.Join(allCerts, ",") consoleIngress.ObjectMeta.Annotations["networking.gke.io/managed-certificates"] = strings.Join(allCerts, ",")
tenantNodePortIoS := intstr.IntOrString{ tenantNodePortIoS := intstr.IntOrString{
Type: intstr.Int, Type: intstr.Int,
@@ -190,7 +190,7 @@ func gkeIntegration(clientset *kubernetes.Clientset, tenantName string, namespac
IntVal: int32(tenantMcsNodePort), IntVal: int32(tenantMcsNodePort),
} }
m3Ingress.Spec.Rules = append(m3Ingress.Spec.Rules, extensionsBeta1.IngressRule{ consoleIngress.Spec.Rules = append(consoleIngress.Spec.Rules, extensionsBeta1.IngressRule{
Host: tenantDomain, Host: tenantDomain,
IngressRuleValue: extensionsBeta1.IngressRuleValue{ IngressRuleValue: extensionsBeta1.IngressRuleValue{
HTTP: &extensionsBeta1.HTTPIngressRuleValue{ HTTP: &extensionsBeta1.HTTPIngressRuleValue{
@@ -205,7 +205,7 @@ func gkeIntegration(clientset *kubernetes.Clientset, tenantName string, namespac
}, },
}, },
}) })
m3Ingress.Spec.Rules = append(m3Ingress.Spec.Rules, extensionsBeta1.IngressRule{ consoleIngress.Spec.Rules = append(consoleIngress.Spec.Rules, extensionsBeta1.IngressRule{
Host: tenantMcsDomain, Host: tenantMcsDomain,
IngressRuleValue: extensionsBeta1.IngressRuleValue{ IngressRuleValue: extensionsBeta1.IngressRuleValue{
HTTP: &extensionsBeta1.HTTPIngressRuleValue{ HTTP: &extensionsBeta1.HTTPIngressRuleValue{
@@ -221,7 +221,7 @@ func gkeIntegration(clientset *kubernetes.Clientset, tenantName string, namespac
}, },
}) })
_, err = clientset.ExtensionsV1beta1().Ingresses(namespace).Update(context.Background(), m3Ingress, metav1.UpdateOptions{}) _, err = clientset.ExtensionsV1beta1().Ingresses(namespace).Update(context.Background(), consoleIngress, metav1.UpdateOptions{})
if err != nil { if err != nil {
return err return err
} }

View File

@@ -156,12 +156,12 @@ func NewMcsAPI(spec *loads.Document) *McsAPI {
UserAPILoginDetailHandler: user_api.LoginDetailHandlerFunc(func(params user_api.LoginDetailParams) middleware.Responder { UserAPILoginDetailHandler: user_api.LoginDetailHandlerFunc(func(params user_api.LoginDetailParams) middleware.Responder {
return middleware.NotImplemented("operation user_api.LoginDetail has not yet been implemented") return middleware.NotImplemented("operation user_api.LoginDetail has not yet been implemented")
}), }),
UserAPILoginMkubeHandler: user_api.LoginMkubeHandlerFunc(func(params user_api.LoginMkubeParams) middleware.Responder {
return middleware.NotImplemented("operation user_api.LoginMkube has not yet been implemented")
}),
UserAPILoginOauth2AuthHandler: user_api.LoginOauth2AuthHandlerFunc(func(params user_api.LoginOauth2AuthParams) middleware.Responder { UserAPILoginOauth2AuthHandler: user_api.LoginOauth2AuthHandlerFunc(func(params user_api.LoginOauth2AuthParams) middleware.Responder {
return middleware.NotImplemented("operation user_api.LoginOauth2Auth has not yet been implemented") return middleware.NotImplemented("operation user_api.LoginOauth2Auth has not yet been implemented")
}), }),
UserAPILoginOperatorHandler: user_api.LoginOperatorHandlerFunc(func(params user_api.LoginOperatorParams) middleware.Responder {
return middleware.NotImplemented("operation user_api.LoginOperator has not yet been implemented")
}),
UserAPILogoutHandler: user_api.LogoutHandlerFunc(func(params user_api.LogoutParams, principal *models.Principal) middleware.Responder { UserAPILogoutHandler: user_api.LogoutHandlerFunc(func(params user_api.LogoutParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation user_api.Logout has not yet been implemented") return middleware.NotImplemented("operation user_api.Logout has not yet been implemented")
}), }),
@@ -327,10 +327,10 @@ type McsAPI struct {
UserAPILoginHandler user_api.LoginHandler UserAPILoginHandler user_api.LoginHandler
// UserAPILoginDetailHandler sets the operation handler for the login detail operation // UserAPILoginDetailHandler sets the operation handler for the login detail operation
UserAPILoginDetailHandler user_api.LoginDetailHandler UserAPILoginDetailHandler user_api.LoginDetailHandler
// UserAPILoginMkubeHandler sets the operation handler for the login mkube operation
UserAPILoginMkubeHandler user_api.LoginMkubeHandler
// UserAPILoginOauth2AuthHandler sets the operation handler for the login oauth2 auth operation // UserAPILoginOauth2AuthHandler sets the operation handler for the login oauth2 auth operation
UserAPILoginOauth2AuthHandler user_api.LoginOauth2AuthHandler UserAPILoginOauth2AuthHandler user_api.LoginOauth2AuthHandler
// UserAPILoginOperatorHandler sets the operation handler for the login operator operation
UserAPILoginOperatorHandler user_api.LoginOperatorHandler
// UserAPILogoutHandler sets the operation handler for the logout operation // UserAPILogoutHandler sets the operation handler for the logout operation
UserAPILogoutHandler user_api.LogoutHandler UserAPILogoutHandler user_api.LogoutHandler
// UserAPIMakeBucketHandler sets the operation handler for the make bucket operation // UserAPIMakeBucketHandler sets the operation handler for the make bucket operation
@@ -533,12 +533,12 @@ func (o *McsAPI) Validate() error {
if o.UserAPILoginDetailHandler == nil { if o.UserAPILoginDetailHandler == nil {
unregistered = append(unregistered, "user_api.LoginDetailHandler") unregistered = append(unregistered, "user_api.LoginDetailHandler")
} }
if o.UserAPILoginMkubeHandler == nil {
unregistered = append(unregistered, "user_api.LoginMkubeHandler")
}
if o.UserAPILoginOauth2AuthHandler == nil { if o.UserAPILoginOauth2AuthHandler == nil {
unregistered = append(unregistered, "user_api.LoginOauth2AuthHandler") unregistered = append(unregistered, "user_api.LoginOauth2AuthHandler")
} }
if o.UserAPILoginOperatorHandler == nil {
unregistered = append(unregistered, "user_api.LoginOperatorHandler")
}
if o.UserAPILogoutHandler == nil { if o.UserAPILogoutHandler == nil {
unregistered = append(unregistered, "user_api.LogoutHandler") unregistered = append(unregistered, "user_api.LogoutHandler")
} }
@@ -820,11 +820,11 @@ func (o *McsAPI) initHandlerCache() {
if o.handlers["POST"] == nil { if o.handlers["POST"] == nil {
o.handlers["POST"] = make(map[string]http.Handler) o.handlers["POST"] = make(map[string]http.Handler)
} }
o.handlers["POST"]["/login/mkube"] = user_api.NewLoginMkube(o.context, o.UserAPILoginMkubeHandler) o.handlers["POST"]["/login/oauth2/auth"] = user_api.NewLoginOauth2Auth(o.context, o.UserAPILoginOauth2AuthHandler)
if o.handlers["POST"] == nil { if o.handlers["POST"] == nil {
o.handlers["POST"] = make(map[string]http.Handler) o.handlers["POST"] = make(map[string]http.Handler)
} }
o.handlers["POST"]["/login/oauth2/auth"] = user_api.NewLoginOauth2Auth(o.context, o.UserAPILoginOauth2AuthHandler) o.handlers["POST"]["/login/operator"] = user_api.NewLoginOperator(o.context, o.UserAPILoginOperatorHandler)
if o.handlers["POST"] == nil { if o.handlers["POST"] == nil {
o.handlers["POST"] = make(map[string]http.Handler) o.handlers["POST"] = make(map[string]http.Handler)
} }

View File

@@ -28,40 +28,40 @@ import (
"github.com/go-openapi/runtime/middleware" "github.com/go-openapi/runtime/middleware"
) )
// LoginMkubeHandlerFunc turns a function with the right signature into a login mkube handler // LoginOperatorHandlerFunc turns a function with the right signature into a login operator handler
type LoginMkubeHandlerFunc func(LoginMkubeParams) middleware.Responder type LoginOperatorHandlerFunc func(LoginOperatorParams) middleware.Responder
// Handle executing the request and returning a response // Handle executing the request and returning a response
func (fn LoginMkubeHandlerFunc) Handle(params LoginMkubeParams) middleware.Responder { func (fn LoginOperatorHandlerFunc) Handle(params LoginOperatorParams) middleware.Responder {
return fn(params) return fn(params)
} }
// LoginMkubeHandler interface for that can handle valid login mkube params // LoginOperatorHandler interface for that can handle valid login operator params
type LoginMkubeHandler interface { type LoginOperatorHandler interface {
Handle(LoginMkubeParams) middleware.Responder Handle(LoginOperatorParams) middleware.Responder
} }
// NewLoginMkube creates a new http.Handler for the login mkube operation // NewLoginOperator creates a new http.Handler for the login operator operation
func NewLoginMkube(ctx *middleware.Context, handler LoginMkubeHandler) *LoginMkube { func NewLoginOperator(ctx *middleware.Context, handler LoginOperatorHandler) *LoginOperator {
return &LoginMkube{Context: ctx, Handler: handler} return &LoginOperator{Context: ctx, Handler: handler}
} }
/*LoginMkube swagger:route POST /login/mkube UserAPI loginMkube /*LoginOperator swagger:route POST /login/operator UserAPI loginOperator
Login to Mkube. Login to Operator Console.
*/ */
type LoginMkube struct { type LoginOperator struct {
Context *middleware.Context Context *middleware.Context
Handler LoginMkubeHandler Handler LoginOperatorHandler
} }
func (o *LoginMkube) ServeHTTP(rw http.ResponseWriter, r *http.Request) { func (o *LoginOperator) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r) route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil { if rCtx != nil {
r = rCtx r = rCtx
} }
var Params = NewLoginMkubeParams() var Params = NewLoginOperatorParams()
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err) o.Context.Respond(rw, r, route.Produces, route, err)

View File

@@ -33,18 +33,18 @@ import (
"github.com/minio/mcs/models" "github.com/minio/mcs/models"
) )
// NewLoginMkubeParams creates a new LoginMkubeParams object // NewLoginOperatorParams creates a new LoginOperatorParams object
// no default values defined in spec. // no default values defined in spec.
func NewLoginMkubeParams() LoginMkubeParams { func NewLoginOperatorParams() LoginOperatorParams {
return LoginMkubeParams{} return LoginOperatorParams{}
} }
// LoginMkubeParams contains all the bound params for the login mkube operation // LoginOperatorParams contains all the bound params for the login operator operation
// typically these are obtained from a http.Request // typically these are obtained from a http.Request
// //
// swagger:parameters LoginMkube // swagger:parameters LoginOperator
type LoginMkubeParams struct { type LoginOperatorParams struct {
// HTTP Request Object // HTTP Request Object
HTTPRequest *http.Request `json:"-"` HTTPRequest *http.Request `json:"-"`
@@ -53,21 +53,21 @@ type LoginMkubeParams struct {
Required: true Required: true
In: body In: body
*/ */
Body *models.LoginMkubeRequest Body *models.LoginOperatorRequest
} }
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface // 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. // for simple values it will use straight method calls.
// //
// To ensure default values, the struct must have been initialized with NewLoginMkubeParams() beforehand. // To ensure default values, the struct must have been initialized with NewLoginOperatorParams() beforehand.
func (o *LoginMkubeParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { func (o *LoginOperatorParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error var res []error
o.HTTPRequest = r o.HTTPRequest = r
if runtime.HasBody(r) { if runtime.HasBody(r) {
defer r.Body.Close() defer r.Body.Close()
var body models.LoginMkubeRequest var body models.LoginOperatorRequest
if err := route.Consumer.Consume(r.Body, &body); err != nil { if err := route.Consumer.Consume(r.Body, &body); err != nil {
if err == io.EOF { if err == io.EOF {
res = append(res, errors.Required("body", "body", "")) res = append(res, errors.Required("body", "body", ""))

View File

@@ -30,14 +30,14 @@ import (
"github.com/minio/mcs/models" "github.com/minio/mcs/models"
) )
// LoginMkubeCreatedCode is the HTTP code returned for type LoginMkubeCreated // LoginOperatorCreatedCode is the HTTP code returned for type LoginOperatorCreated
const LoginMkubeCreatedCode int = 201 const LoginOperatorCreatedCode int = 201
/*LoginMkubeCreated A successful login. /*LoginOperatorCreated A successful login.
swagger:response loginMkubeCreated swagger:response loginOperatorCreated
*/ */
type LoginMkubeCreated struct { type LoginOperatorCreated struct {
/* /*
In: Body In: Body
@@ -45,25 +45,25 @@ type LoginMkubeCreated struct {
Payload *models.LoginResponse `json:"body,omitempty"` Payload *models.LoginResponse `json:"body,omitempty"`
} }
// NewLoginMkubeCreated creates LoginMkubeCreated with default headers values // NewLoginOperatorCreated creates LoginOperatorCreated with default headers values
func NewLoginMkubeCreated() *LoginMkubeCreated { func NewLoginOperatorCreated() *LoginOperatorCreated {
return &LoginMkubeCreated{} return &LoginOperatorCreated{}
} }
// WithPayload adds the payload to the login mkube created response // WithPayload adds the payload to the login operator created response
func (o *LoginMkubeCreated) WithPayload(payload *models.LoginResponse) *LoginMkubeCreated { func (o *LoginOperatorCreated) WithPayload(payload *models.LoginResponse) *LoginOperatorCreated {
o.Payload = payload o.Payload = payload
return o return o
} }
// SetPayload sets the payload to the login mkube created response // SetPayload sets the payload to the login operator created response
func (o *LoginMkubeCreated) SetPayload(payload *models.LoginResponse) { func (o *LoginOperatorCreated) SetPayload(payload *models.LoginResponse) {
o.Payload = payload o.Payload = payload
} }
// WriteResponse to the client // WriteResponse to the client
func (o *LoginMkubeCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { func (o *LoginOperatorCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(201) rw.WriteHeader(201)
if o.Payload != nil { if o.Payload != nil {
@@ -74,11 +74,11 @@ func (o *LoginMkubeCreated) WriteResponse(rw http.ResponseWriter, producer runti
} }
} }
/*LoginMkubeDefault Generic error response. /*LoginOperatorDefault Generic error response.
swagger:response loginMkubeDefault swagger:response loginOperatorDefault
*/ */
type LoginMkubeDefault struct { type LoginOperatorDefault struct {
_statusCode int _statusCode int
/* /*
@@ -87,41 +87,41 @@ type LoginMkubeDefault struct {
Payload *models.Error `json:"body,omitempty"` Payload *models.Error `json:"body,omitempty"`
} }
// NewLoginMkubeDefault creates LoginMkubeDefault with default headers values // NewLoginOperatorDefault creates LoginOperatorDefault with default headers values
func NewLoginMkubeDefault(code int) *LoginMkubeDefault { func NewLoginOperatorDefault(code int) *LoginOperatorDefault {
if code <= 0 { if code <= 0 {
code = 500 code = 500
} }
return &LoginMkubeDefault{ return &LoginOperatorDefault{
_statusCode: code, _statusCode: code,
} }
} }
// WithStatusCode adds the status to the login mkube default response // WithStatusCode adds the status to the login operator default response
func (o *LoginMkubeDefault) WithStatusCode(code int) *LoginMkubeDefault { func (o *LoginOperatorDefault) WithStatusCode(code int) *LoginOperatorDefault {
o._statusCode = code o._statusCode = code
return o return o
} }
// SetStatusCode sets the status to the login mkube default response // SetStatusCode sets the status to the login operator default response
func (o *LoginMkubeDefault) SetStatusCode(code int) { func (o *LoginOperatorDefault) SetStatusCode(code int) {
o._statusCode = code o._statusCode = code
} }
// WithPayload adds the payload to the login mkube default response // WithPayload adds the payload to the login operator default response
func (o *LoginMkubeDefault) WithPayload(payload *models.Error) *LoginMkubeDefault { func (o *LoginOperatorDefault) WithPayload(payload *models.Error) *LoginOperatorDefault {
o.Payload = payload o.Payload = payload
return o return o
} }
// SetPayload sets the payload to the login mkube default response // SetPayload sets the payload to the login operator default response
func (o *LoginMkubeDefault) SetPayload(payload *models.Error) { func (o *LoginOperatorDefault) SetPayload(payload *models.Error) {
o.Payload = payload o.Payload = payload
} }
// WriteResponse to the client // WriteResponse to the client
func (o *LoginMkubeDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { func (o *LoginOperatorDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode) rw.WriteHeader(o._statusCode)
if o.Payload != nil { if o.Payload != nil {

View File

@@ -28,15 +28,15 @@ import (
golangswaggerpaths "path" golangswaggerpaths "path"
) )
// LoginMkubeURL generates an URL for the login mkube operation // LoginOperatorURL generates an URL for the login operator operation
type LoginMkubeURL struct { type LoginOperatorURL struct {
_basePath string _basePath string
} }
// WithBasePath sets the base path for this url builder, only required when it's different from the // WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec. // base path specified in the swagger spec.
// When the value of the base path is an empty string // When the value of the base path is an empty string
func (o *LoginMkubeURL) WithBasePath(bp string) *LoginMkubeURL { func (o *LoginOperatorURL) WithBasePath(bp string) *LoginOperatorURL {
o.SetBasePath(bp) o.SetBasePath(bp)
return o return o
} }
@@ -44,15 +44,15 @@ func (o *LoginMkubeURL) WithBasePath(bp string) *LoginMkubeURL {
// SetBasePath sets the base path for this url builder, only required when it's different from the // SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec. // base path specified in the swagger spec.
// When the value of the base path is an empty string // When the value of the base path is an empty string
func (o *LoginMkubeURL) SetBasePath(bp string) { func (o *LoginOperatorURL) SetBasePath(bp string) {
o._basePath = bp o._basePath = bp
} }
// Build a url path and query string // Build a url path and query string
func (o *LoginMkubeURL) Build() (*url.URL, error) { func (o *LoginOperatorURL) Build() (*url.URL, error) {
var _result url.URL var _result url.URL
var _path = "/login/mkube" var _path = "/login/operator"
_basePath := o._basePath _basePath := o._basePath
if _basePath == "" { if _basePath == "" {
@@ -64,7 +64,7 @@ func (o *LoginMkubeURL) Build() (*url.URL, error) {
} }
// Must is a helper function to panic when the url builder returns an error // Must is a helper function to panic when the url builder returns an error
func (o *LoginMkubeURL) Must(u *url.URL, err error) *url.URL { func (o *LoginOperatorURL) Must(u *url.URL, err error) *url.URL {
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -75,17 +75,17 @@ func (o *LoginMkubeURL) Must(u *url.URL, err error) *url.URL {
} }
// String returns the string representation of the path with query string // String returns the string representation of the path with query string
func (o *LoginMkubeURL) String() string { func (o *LoginOperatorURL) String() string {
return o.Must(o.Build()).String() return o.Must(o.Build()).String()
} }
// BuildFull builds a full url with scheme, host, path and query string // BuildFull builds a full url with scheme, host, path and query string
func (o *LoginMkubeURL) BuildFull(scheme, host string) (*url.URL, error) { func (o *LoginOperatorURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" { if scheme == "" {
return nil, errors.New("scheme is required for a full url on LoginMkubeURL") return nil, errors.New("scheme is required for a full url on LoginOperatorURL")
} }
if host == "" { if host == "" {
return nil, errors.New("host is required for a full url on LoginMkubeURL") return nil, errors.New("host is required for a full url on LoginOperatorURL")
} }
base, err := o.Build() base, err := o.Build()
@@ -99,6 +99,6 @@ func (o *LoginMkubeURL) BuildFull(scheme, host string) (*url.URL, error) {
} }
// StringFull returns the string representation of a complete url // StringFull returns the string representation of a complete url
func (o *LoginMkubeURL) StringFull(scheme, host string) string { func (o *LoginOperatorURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String() return o.Must(o.BuildFull(scheme, host)).String()
} }

View File

@@ -61,12 +61,12 @@ func registerLoginHandlers(api *operations.McsAPI) {
} }
return user_api.NewLoginOauth2AuthCreated().WithPayload(loginResponse) return user_api.NewLoginOauth2AuthCreated().WithPayload(loginResponse)
}) })
api.UserAPILoginMkubeHandler = user_api.LoginMkubeHandlerFunc(func(params user_api.LoginMkubeParams) middleware.Responder { api.UserAPILoginOperatorHandler = user_api.LoginOperatorHandlerFunc(func(params user_api.LoginOperatorParams) middleware.Responder {
loginResponse, err := getLoginMkubeResponse(params.Body) loginResponse, err := getLoginOperatorResponse(params.Body)
if err != nil { if err != nil {
return user_api.NewLoginMkubeDefault(401).WithPayload(&models.Error{Code: 401, Message: swag.String(err.Error())}) return user_api.NewLoginOperatorDefault(401).WithPayload(&models.Error{Code: 401, Message: swag.String(err.Error())})
} }
return user_api.NewLoginMkubeCreated().WithPayload(loginResponse) return user_api.NewLoginOperatorCreated().WithPayload(loginResponse)
}) })
} }
@@ -155,7 +155,7 @@ func getLoginDetailsResponse() (*models.LoginDetails, error) {
ctx := context.Background() ctx := context.Background()
loginStrategy := models.LoginDetailsLoginStrategyForm loginStrategy := models.LoginDetailsLoginStrategyForm
redirectURL := "" redirectURL := ""
if acl.GetOperatorOnly() { if acl.GetOperatorMode() {
loginStrategy = models.LoginDetailsLoginStrategyServiceAccount loginStrategy = models.LoginDetailsLoginStrategyServiceAccount
} else if oauth2.IsIdpEnabled() { } else if oauth2.IsIdpEnabled() {
loginStrategy = models.LoginDetailsLoginStrategyRedirect loginStrategy = models.LoginDetailsLoginStrategyRedirect
@@ -261,8 +261,8 @@ func getLoginOauth2AuthResponse(lr *models.LoginOauth2AuthRequest) (*models.Logi
return nil, errorGeneric return nil, errorGeneric
} }
// getLoginMkubeResponse validate the provided service account token against mkube // getLoginOperatorResponse validate the provided service account token against k8s api
func getLoginMkubeResponse(lmr *models.LoginMkubeRequest) (*models.LoginResponse, error) { func getLoginOperatorResponse(lmr *models.LoginOperatorRequest) (*models.LoginResponse, error) {
creds, err := newMcsCredentials("", *lmr.Jwt, "") creds, err := newMcsCredentials("", *lmr.Jwt, "")
if err != nil { if err != nil {
log.Println("error login:", err) log.Println("error login:", err)

View File

@@ -60,16 +60,16 @@ paths:
security: [] security: []
tags: tags:
- UserAPI - UserAPI
/login/mkube: /login/operator:
post: post:
summary: Login to Mkube. summary: Login to Operator Console.
operationId: LoginMkube operationId: LoginOperator
parameters: parameters:
- name: body - name: body
in: body in: body
required: true required: true
schema: schema:
$ref: '#/definitions/loginMkubeRequest' $ref: '#/definitions/loginOperatorRequest'
responses: responses:
201: 201:
description: A successful login. description: A successful login.
@@ -1462,7 +1462,7 @@ definitions:
type: string type: string
code: code:
type: string type: string
loginMkubeRequest: loginOperatorRequest:
type: object type: object
required: required:
- jwt - jwt