Compare commits

...

17 Commits

Author SHA1 Message Date
Minio Trusted
c0bf9c5da8 update version to v0.3.8 2020-08-05 12:38:13 -07:00
Daniel Valdivia
16a6524b11 Pass Annotations to PVC (#233) 2020-08-05 12:35:41 -07:00
Minio Trusted
c1963c6122 update to v0.3.7 2020-08-05 11:06:25 -07:00
Cesar N
73154e8dd7 Add missing field on Tenant Creation (#232) 2020-08-05 01:21:35 -07:00
Daniel Valdivia
e2e8cbe46c Erasure Coding Parity (#231) 2020-08-04 22:32:41 -07:00
Cesar N
b9b776c278 Add ImageRegistry field to Tenant Create and Tenant Update (#230) 2020-08-04 20:54:59 -07:00
Cesar N
7710df62ee Add imagePullSecretsName field on Add Tenant request (#227) 2020-08-04 16:04:04 -07:00
Minio Trusted
63e1c554b7 update to v0.3.6 2020-08-03 12:14:15 -07:00
Daniel Valdivia
a9d8f3fc41 Return Disk Usage (#226)
* Return Disk Usage

* Address comments
2020-08-03 12:11:48 -07:00
Minio Trusted
59bf546b4a upgrade to v0.3.5 2020-08-03 09:24:57 -07:00
Lenin Alevski
c3e34dc220 Support for deploying minio/console with IDP integration (#221) 2020-08-02 23:45:54 -07:00
Daniel Valdivia
cd547e9425 Limit Console RAM to 64Mi. Increase Logging for Tenant APIs. (#225) 2020-08-02 23:04:51 -07:00
Harshavardhana
d98b70f0ca update CREDITS with new deps (#222)
Co-authored-by: Daniel Valdivia <hola@danielvaldivia.com>
2020-08-02 12:29:58 -07:00
Daniel Valdivia
7ff009ec43 Add Insecure parameter to NewAdminClient function (#224)
When using the madmin client, for some operations such as health checks against a MinIO instnace with TLS we need a client with insecure turned on.
2020-08-02 12:21:21 -07:00
dependabot[bot]
3760c783d0 Bump elliptic from 6.5.2 to 6.5.3 in /portal-ui (#223)
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.2 to 6.5.3.
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.2...v6.5.3)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-08-02 09:36:01 -07:00
Daniel Valdivia
a8be3c72aa Release v0.3.4 (#220) 2020-07-30 21:06:58 -07:00
Lenin Alevski
ee8242d72a TLS with user provided certificates and KES support for MinIO (#213)
This PR adds the following features:

- Allow user to provide its own keypair certificates for enable TLS in
  MinIO
- Allow user to configure data encryption at rest in MinIO with KES
- Removes JWT schema for login and instead Console authentication will use
  encrypted session tokens

Enable TLS between client and MinIO with user provided certificates

Instead of using AutoCert feature now the user can provide `cert` and
`key` via `tls` object, values must be valid `x509.Certificate`
formatted files encoded in `base64`

Enable encryption at rest configuring KES

User can deploy KES via Console/Operator by defining the encryption
object, AutoCert must be enabled or custom certificates for KES must be
provided, KES support 3 KMS backends: `Vault`, `AWS KMS` and `Gemalto`,
previous configuration of the KMS is necessary.

eg of body request for create-tenant

```
{
    "name": "honeywell",
    "access_key": "minio",
    "secret_key": "minio123",
    "enable_mcs": false,
    "enable_ssl": false,
    "service_name": "honeywell",
    "zones": [
        {
            "name": "honeywell-zone-1",
            "servers": 1,
            "volumes_per_server": 4,
            "volume_configuration": {
                "size": 256000000,
                "storage_class": "vsan-default-storage-policy"
            }
        }
    ],
    "namespace": "default",
    "tls": {
      "tls.crt": "",
      "tls.key": ""
    },
    "encryption": {
        "server": {
          "tls.crt": "",
          "tls.key": ""
        },
        "client": {
          "tls.crt": "",
          "tls.key": ""
        },
      "vault": {
        "endpoint": "http://vault:8200",
        "prefix": "",
        "approle": {
          "id": "",
          "secret": ""
        }
      }
    }
}
```
2020-07-30 17:49:56 -07:00
45 changed files with 8368 additions and 2346 deletions

View File

@@ -21,7 +21,7 @@ linters:
- structcheck
service:
golangci-lint-version: 1.21.0 # use the fixed version to not introduce new linters unexpectedly
golangci-lint-version: 1.27.0 # use the fixed version to not introduce new linters unexpectedly
run:
skip-dirs:

View File

@@ -23,6 +23,33 @@ builds:
goarch:
- amd64
- arm64
ignore:
- goos: darwin
goarch: arm64
- goos: darwin
goarch: arm
- goos: darwin
goarch: ppc64le
- goos: darwin
goarch: s390x
- goos: windows
goarch: arm64
- goos: windows
goarch: arm
- goos: windows
goarch: ppc64le
- goos: windows
goarch: s390x
- goos: freebsd
goarch: arm
- goos: freebsd
goarch: arm64
- goos: freebsd
goarch: ppc64le
- goos: freebsd
goarch: s390x
env:
- CGO_ENABLED=0
main: ./cmd/console/

6507
CREDITS

File diff suppressed because it is too large Load Diff

View File

@@ -25,8 +25,10 @@ verifiers: getdeps fmt lint
fmt:
@echo "Running $@ check"
@GO111MODULE=on gofmt -d cmd/
@GO111MODULE=on gofmt -d restapi/
@GO111MODULE=on gofmt -d pkg/
@GO111MODULE=on gofmt -d cmd/
@GO111MODULE=on gofmt -d cluster/
lint:
@echo "Running $@ check"

View File

@@ -98,7 +98,7 @@ func getLatestMinIOImage(client HTTPClientI) (*string, error) {
var latestMinIOImage, errLatestMinIOImage = getLatestMinIOImage(
&HTTPClient{
Client: &http.Client{
Timeout: 4 * time.Second,
Timeout: 15 * time.Second,
},
})

5
go.mod
View File

@@ -4,7 +4,6 @@ go 1.13
require (
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/elazarl/go-bindata-assetfs v1.0.0
github.com/go-openapi/errors v0.19.6
github.com/go-openapi/loads v0.19.5
@@ -15,19 +14,19 @@ require (
github.com/go-openapi/validate v0.19.10
github.com/gorilla/websocket v1.4.2
github.com/jessevdk/go-flags v1.4.0
github.com/json-iterator/go v1.1.10
github.com/minio/cli v1.22.0
github.com/minio/kes v0.10.1
github.com/minio/mc v0.0.0-20200725183142-90d22b271f60
github.com/minio/minio v0.0.0-20200725154241-abbf6ce6ccf8
github.com/minio/minio-go/v7 v7.0.2-0.20200722162308-e0105ca08252
github.com/minio/operator v0.0.0-20200730044813-c2895a5065a1
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/satori/go.uuid v1.2.0
github.com/stretchr/testify v1.6.1
github.com/unrolled/secure v1.0.7
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
golang.org/x/net v0.0.0-20200707034311-ab3426394381
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
gopkg.in/yaml.v2 v2.3.0
k8s.io/api v0.18.0
k8s.io/apimachinery v0.18.0
k8s.io/client-go v0.18.0

7
go.sum
View File

@@ -55,6 +55,7 @@ github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:o
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/aws/aws-sdk-go v1.20.21/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.26.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/bcicen/jstream v0.0.0-20190220045926-16c1f8af81c2 h1:M+TYzBcNIRyzPRg66ndEqUMd7oWDmhvdQmaPC6EZNwM=
github.com/bcicen/jstream v0.0.0-20190220045926-16c1f8af81c2/go.mod h1:RDu/qcrnpEdJC/p8tx34+YBFqqX71lB7dOX9QE+ZC4M=
github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=
@@ -134,6 +135,7 @@ github.com/frankban/quicktest v1.4.1/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
@@ -453,6 +455,8 @@ github.com/minio/cli v1.22.0 h1:VTQm7lmXm3quxO917X3p+el1l0Ca5X3S4PM2ruUYO68=
github.com/minio/cli v1.22.0/go.mod h1:bYxnK0uS629N3Bq+AOZZ+6lwF77Sodk4+UL9vNuXhOY=
github.com/minio/highwayhash v1.0.0 h1:iMSDhgUILCr0TNm8LWlSjF8N0ZIj2qbO8WHp6Q/J2BA=
github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc=
github.com/minio/kes v0.10.1 h1:f+WDJdNHNMf1xE6BbjtCLUyh671weSCQ30uynoCPl78=
github.com/minio/kes v0.10.1/go.mod h1:mTF1Bv8YVEtQqF/B7Felp4tLee44Pp+dgI0rhCvgNg8=
github.com/minio/mc v0.0.0-20200725183142-90d22b271f60 h1:LevaZ33nx+rUzRsuU7rVvqXUP7VCu2BQanhITw4Z9rA=
github.com/minio/mc v0.0.0-20200725183142-90d22b271f60/go.mod h1:Hvnyrb/NMM+pJ53JO/J3jxGtwPDYJh7K6c1D+RR2h2g=
github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
@@ -588,8 +592,6 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/secure-io/sio-go v0.3.0 h1:QKGb6rGJeiExac9wSWxnWPYo8O8OFN7lxXQvHshX6vo=
github.com/secure-io/sio-go v0.3.0/go.mod h1:D3KmXgKETffyYxBdFRN+Hpd2WzhzqS0EQwT3XWsAcBU=
github.com/shirou/gopsutil v2.20.3-0.20200314133625-53cec6b37e6a+incompatible h1:YiKUe2ZOmfpDBH4OSyxwkx/mjNqHHnNhOtZ2mPyRme8=
@@ -695,6 +697,7 @@ golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=

View File

@@ -15,7 +15,7 @@ spec:
serviceAccountName: console-sa
containers:
- name: console
image: minio/console:latest
image: minio/console:v0.3.8
imagePullPolicy: "IfNotPresent"
args:
- server

View File

@@ -6,8 +6,18 @@ rules:
- apiGroups:
- ""
resources:
- namespaces
- secrets
verbs:
- get
- watch
- create
- list
- patch
- update
- apiGroups:
- ""
resources:
- namespaces
- pods
- services
- events

View File

@@ -15,7 +15,7 @@ spec:
serviceAccountName: console-sa
containers:
- name: console
image: minio/console:latest
image: minio/console:v0.3.8
imagePullPolicy: "IfNotPresent"
env:
- name: CONSOLE_OPERATOR_MODE

258
models/aws_configuration.go Normal file
View File

@@ -0,0 +1,258 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// AwsConfiguration aws configuration
//
// swagger:model awsConfiguration
type AwsConfiguration struct {
// secretsmanager
// Required: true
Secretsmanager *AwsConfigurationSecretsmanager `json:"secretsmanager"`
}
// Validate validates this aws configuration
func (m *AwsConfiguration) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateSecretsmanager(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AwsConfiguration) validateSecretsmanager(formats strfmt.Registry) error {
if err := validate.Required("secretsmanager", "body", m.Secretsmanager); err != nil {
return err
}
if m.Secretsmanager != nil {
if err := m.Secretsmanager.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("secretsmanager")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *AwsConfiguration) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AwsConfiguration) UnmarshalBinary(b []byte) error {
var res AwsConfiguration
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// AwsConfigurationSecretsmanager aws configuration secretsmanager
//
// swagger:model AwsConfigurationSecretsmanager
type AwsConfigurationSecretsmanager struct {
// credentials
// Required: true
Credentials *AwsConfigurationSecretsmanagerCredentials `json:"credentials"`
// endpoint
// Required: true
Endpoint *string `json:"endpoint"`
// kmskey
Kmskey string `json:"kmskey,omitempty"`
// region
// Required: true
Region *string `json:"region"`
}
// Validate validates this aws configuration secretsmanager
func (m *AwsConfigurationSecretsmanager) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateCredentials(formats); err != nil {
res = append(res, err)
}
if err := m.validateEndpoint(formats); err != nil {
res = append(res, err)
}
if err := m.validateRegion(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AwsConfigurationSecretsmanager) validateCredentials(formats strfmt.Registry) error {
if err := validate.Required("secretsmanager"+"."+"credentials", "body", m.Credentials); err != nil {
return err
}
if m.Credentials != nil {
if err := m.Credentials.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("secretsmanager" + "." + "credentials")
}
return err
}
}
return nil
}
func (m *AwsConfigurationSecretsmanager) validateEndpoint(formats strfmt.Registry) error {
if err := validate.Required("secretsmanager"+"."+"endpoint", "body", m.Endpoint); err != nil {
return err
}
return nil
}
func (m *AwsConfigurationSecretsmanager) validateRegion(formats strfmt.Registry) error {
if err := validate.Required("secretsmanager"+"."+"region", "body", m.Region); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *AwsConfigurationSecretsmanager) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AwsConfigurationSecretsmanager) UnmarshalBinary(b []byte) error {
var res AwsConfigurationSecretsmanager
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// AwsConfigurationSecretsmanagerCredentials aws configuration secretsmanager credentials
//
// swagger:model AwsConfigurationSecretsmanagerCredentials
type AwsConfigurationSecretsmanagerCredentials struct {
// accesskey
// Required: true
Accesskey *string `json:"accesskey"`
// secretkey
// Required: true
Secretkey *string `json:"secretkey"`
// token
Token string `json:"token,omitempty"`
}
// Validate validates this aws configuration secretsmanager credentials
func (m *AwsConfigurationSecretsmanagerCredentials) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateAccesskey(formats); err != nil {
res = append(res, err)
}
if err := m.validateSecretkey(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *AwsConfigurationSecretsmanagerCredentials) validateAccesskey(formats strfmt.Registry) error {
if err := validate.Required("secretsmanager"+"."+"credentials"+"."+"accesskey", "body", m.Accesskey); err != nil {
return err
}
return nil
}
func (m *AwsConfigurationSecretsmanagerCredentials) validateSecretkey(formats strfmt.Registry) error {
if err := validate.Required("secretsmanager"+"."+"credentials"+"."+"secretkey", "body", m.Secretkey); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *AwsConfigurationSecretsmanagerCredentials) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *AwsConfigurationSecretsmanagerCredentials) UnmarshalBinary(b []byte) error {
var res AwsConfigurationSecretsmanagerCredentials
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -48,9 +48,21 @@ type CreateTenantRequest struct {
// enable ssl
EnableSsl *bool `json:"enable_ssl,omitempty"`
// encryption
Encryption *EncryptionConfiguration `json:"encryption,omitempty"`
// erasure coding parity
ErasureCodingParity int64 `json:"erasureCodingParity,omitempty"`
// idp
Idp *IdpConfiguration `json:"idp,omitempty"`
// image
Image string `json:"image,omitempty"`
// image registry
ImageRegistry *ImageRegistry `json:"image_registry,omitempty"`
// mounth path
MounthPath string `json:"mounth_path,omitempty"`
@@ -69,6 +81,9 @@ type CreateTenantRequest struct {
// service name
ServiceName string `json:"service_name,omitempty"`
// tls
TLS *TLSConfiguration `json:"tls,omitempty"`
// zones
// Required: true
Zones []*Zone `json:"zones"`
@@ -78,6 +93,18 @@ type CreateTenantRequest struct {
func (m *CreateTenantRequest) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateEncryption(formats); err != nil {
res = append(res, err)
}
if err := m.validateIdp(formats); err != nil {
res = append(res, err)
}
if err := m.validateImageRegistry(formats); err != nil {
res = append(res, err)
}
if err := m.validateName(formats); err != nil {
res = append(res, err)
}
@@ -86,6 +113,10 @@ func (m *CreateTenantRequest) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateTLS(formats); err != nil {
res = append(res, err)
}
if err := m.validateZones(formats); err != nil {
res = append(res, err)
}
@@ -96,6 +127,60 @@ func (m *CreateTenantRequest) Validate(formats strfmt.Registry) error {
return nil
}
func (m *CreateTenantRequest) validateEncryption(formats strfmt.Registry) error {
if swag.IsZero(m.Encryption) { // not required
return nil
}
if m.Encryption != nil {
if err := m.Encryption.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("encryption")
}
return err
}
}
return nil
}
func (m *CreateTenantRequest) validateIdp(formats strfmt.Registry) error {
if swag.IsZero(m.Idp) { // not required
return nil
}
if m.Idp != nil {
if err := m.Idp.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("idp")
}
return err
}
}
return nil
}
func (m *CreateTenantRequest) validateImageRegistry(formats strfmt.Registry) error {
if swag.IsZero(m.ImageRegistry) { // not required
return nil
}
if m.ImageRegistry != nil {
if err := m.ImageRegistry.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("image_registry")
}
return err
}
}
return nil
}
func (m *CreateTenantRequest) validateName(formats strfmt.Registry) error {
if err := validate.Required("name", "body", m.Name); err != nil {
@@ -118,6 +203,24 @@ func (m *CreateTenantRequest) validateNamespace(formats strfmt.Registry) error {
return nil
}
func (m *CreateTenantRequest) validateTLS(formats strfmt.Registry) error {
if swag.IsZero(m.TLS) { // not required
return nil
}
if m.TLS != nil {
if err := m.TLS.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("tls")
}
return err
}
}
return nil
}
func (m *CreateTenantRequest) validateZones(formats strfmt.Registry) error {
if err := validate.Required("zones", "body", m.Zones); err != nil {

View File

@@ -0,0 +1,331 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// EncryptionConfiguration encryption configuration
//
// swagger:model encryptionConfiguration
type EncryptionConfiguration struct {
// aws
Aws *AwsConfiguration `json:"aws,omitempty"`
// client
Client *EncryptionConfigurationClient `json:"client,omitempty"`
// gemalto
Gemalto *GemaltoConfiguration `json:"gemalto,omitempty"`
// image
Image string `json:"image,omitempty"`
// master key
MasterKey string `json:"master_key,omitempty"`
// server
Server *EncryptionConfigurationServer `json:"server,omitempty"`
// vault
Vault *VaultConfiguration `json:"vault,omitempty"`
}
// Validate validates this encryption configuration
func (m *EncryptionConfiguration) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateAws(formats); err != nil {
res = append(res, err)
}
if err := m.validateClient(formats); err != nil {
res = append(res, err)
}
if err := m.validateGemalto(formats); err != nil {
res = append(res, err)
}
if err := m.validateServer(formats); err != nil {
res = append(res, err)
}
if err := m.validateVault(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *EncryptionConfiguration) validateAws(formats strfmt.Registry) error {
if swag.IsZero(m.Aws) { // not required
return nil
}
if m.Aws != nil {
if err := m.Aws.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("aws")
}
return err
}
}
return nil
}
func (m *EncryptionConfiguration) validateClient(formats strfmt.Registry) error {
if swag.IsZero(m.Client) { // not required
return nil
}
if m.Client != nil {
if err := m.Client.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("client")
}
return err
}
}
return nil
}
func (m *EncryptionConfiguration) validateGemalto(formats strfmt.Registry) error {
if swag.IsZero(m.Gemalto) { // not required
return nil
}
if m.Gemalto != nil {
if err := m.Gemalto.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("gemalto")
}
return err
}
}
return nil
}
func (m *EncryptionConfiguration) validateServer(formats strfmt.Registry) error {
if swag.IsZero(m.Server) { // not required
return nil
}
if m.Server != nil {
if err := m.Server.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("server")
}
return err
}
}
return nil
}
func (m *EncryptionConfiguration) validateVault(formats strfmt.Registry) error {
if swag.IsZero(m.Vault) { // not required
return nil
}
if m.Vault != nil {
if err := m.Vault.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("vault")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *EncryptionConfiguration) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *EncryptionConfiguration) UnmarshalBinary(b []byte) error {
var res EncryptionConfiguration
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// EncryptionConfigurationClient encryption configuration client
//
// swagger:model EncryptionConfigurationClient
type EncryptionConfigurationClient struct {
// crt
// Required: true
Crt *string `json:"crt"`
// key
// Required: true
Key *string `json:"key"`
}
// Validate validates this encryption configuration client
func (m *EncryptionConfigurationClient) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateCrt(formats); err != nil {
res = append(res, err)
}
if err := m.validateKey(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *EncryptionConfigurationClient) validateCrt(formats strfmt.Registry) error {
if err := validate.Required("client"+"."+"crt", "body", m.Crt); err != nil {
return err
}
return nil
}
func (m *EncryptionConfigurationClient) validateKey(formats strfmt.Registry) error {
if err := validate.Required("client"+"."+"key", "body", m.Key); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *EncryptionConfigurationClient) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *EncryptionConfigurationClient) UnmarshalBinary(b []byte) error {
var res EncryptionConfigurationClient
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// EncryptionConfigurationServer encryption configuration server
//
// swagger:model EncryptionConfigurationServer
type EncryptionConfigurationServer struct {
// crt
// Required: true
Crt *string `json:"crt"`
// key
// Required: true
Key *string `json:"key"`
}
// Validate validates this encryption configuration server
func (m *EncryptionConfigurationServer) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateCrt(formats); err != nil {
res = append(res, err)
}
if err := m.validateKey(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *EncryptionConfigurationServer) validateCrt(formats strfmt.Registry) error {
if err := validate.Required("server"+"."+"crt", "body", m.Crt); err != nil {
return err
}
return nil
}
func (m *EncryptionConfigurationServer) validateKey(formats strfmt.Registry) error {
if err := validate.Required("server"+"."+"key", "body", m.Key); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *EncryptionConfigurationServer) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *EncryptionConfigurationServer) UnmarshalBinary(b []byte) error {
var res EncryptionConfigurationServer
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -0,0 +1,314 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// GemaltoConfiguration gemalto configuration
//
// swagger:model gemaltoConfiguration
type GemaltoConfiguration struct {
// keysecure
// Required: true
Keysecure *GemaltoConfigurationKeysecure `json:"keysecure"`
}
// Validate validates this gemalto configuration
func (m *GemaltoConfiguration) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateKeysecure(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *GemaltoConfiguration) validateKeysecure(formats strfmt.Registry) error {
if err := validate.Required("keysecure", "body", m.Keysecure); err != nil {
return err
}
if m.Keysecure != nil {
if err := m.Keysecure.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("keysecure")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *GemaltoConfiguration) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *GemaltoConfiguration) UnmarshalBinary(b []byte) error {
var res GemaltoConfiguration
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// GemaltoConfigurationKeysecure gemalto configuration keysecure
//
// swagger:model GemaltoConfigurationKeysecure
type GemaltoConfigurationKeysecure struct {
// credentials
// Required: true
Credentials *GemaltoConfigurationKeysecureCredentials `json:"credentials"`
// endpoint
// Required: true
Endpoint *string `json:"endpoint"`
// tls
TLS *GemaltoConfigurationKeysecureTLS `json:"tls,omitempty"`
}
// Validate validates this gemalto configuration keysecure
func (m *GemaltoConfigurationKeysecure) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateCredentials(formats); err != nil {
res = append(res, err)
}
if err := m.validateEndpoint(formats); err != nil {
res = append(res, err)
}
if err := m.validateTLS(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *GemaltoConfigurationKeysecure) validateCredentials(formats strfmt.Registry) error {
if err := validate.Required("keysecure"+"."+"credentials", "body", m.Credentials); err != nil {
return err
}
if m.Credentials != nil {
if err := m.Credentials.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("keysecure" + "." + "credentials")
}
return err
}
}
return nil
}
func (m *GemaltoConfigurationKeysecure) validateEndpoint(formats strfmt.Registry) error {
if err := validate.Required("keysecure"+"."+"endpoint", "body", m.Endpoint); err != nil {
return err
}
return nil
}
func (m *GemaltoConfigurationKeysecure) validateTLS(formats strfmt.Registry) error {
if swag.IsZero(m.TLS) { // not required
return nil
}
if m.TLS != nil {
if err := m.TLS.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("keysecure" + "." + "tls")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *GemaltoConfigurationKeysecure) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *GemaltoConfigurationKeysecure) UnmarshalBinary(b []byte) error {
var res GemaltoConfigurationKeysecure
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// GemaltoConfigurationKeysecureCredentials gemalto configuration keysecure credentials
//
// swagger:model GemaltoConfigurationKeysecureCredentials
type GemaltoConfigurationKeysecureCredentials struct {
// domain
// Required: true
Domain *string `json:"domain"`
// retry
Retry int64 `json:"retry,omitempty"`
// token
// Required: true
Token *string `json:"token"`
}
// Validate validates this gemalto configuration keysecure credentials
func (m *GemaltoConfigurationKeysecureCredentials) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateDomain(formats); err != nil {
res = append(res, err)
}
if err := m.validateToken(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *GemaltoConfigurationKeysecureCredentials) validateDomain(formats strfmt.Registry) error {
if err := validate.Required("keysecure"+"."+"credentials"+"."+"domain", "body", m.Domain); err != nil {
return err
}
return nil
}
func (m *GemaltoConfigurationKeysecureCredentials) validateToken(formats strfmt.Registry) error {
if err := validate.Required("keysecure"+"."+"credentials"+"."+"token", "body", m.Token); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *GemaltoConfigurationKeysecureCredentials) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *GemaltoConfigurationKeysecureCredentials) UnmarshalBinary(b []byte) error {
var res GemaltoConfigurationKeysecureCredentials
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// GemaltoConfigurationKeysecureTLS gemalto configuration keysecure TLS
//
// swagger:model GemaltoConfigurationKeysecureTLS
type GemaltoConfigurationKeysecureTLS struct {
// ca
// Required: true
Ca *string `json:"ca"`
}
// Validate validates this gemalto configuration keysecure TLS
func (m *GemaltoConfigurationKeysecureTLS) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateCa(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *GemaltoConfigurationKeysecureTLS) validateCa(formats strfmt.Registry) error {
if err := validate.Required("keysecure"+"."+"tls"+"."+"ca", "body", m.Ca); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *GemaltoConfigurationKeysecureTLS) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *GemaltoConfigurationKeysecureTLS) UnmarshalBinary(b []byte) error {
var res GemaltoConfigurationKeysecureTLS
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

299
models/idp_configuration.go Normal file
View File

@@ -0,0 +1,299 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// IdpConfiguration idp configuration
//
// swagger:model idpConfiguration
type IdpConfiguration struct {
// active directory
ActiveDirectory *IdpConfigurationActiveDirectory `json:"active_directory,omitempty"`
// oidc
Oidc *IdpConfigurationOidc `json:"oidc,omitempty"`
}
// Validate validates this idp configuration
func (m *IdpConfiguration) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateActiveDirectory(formats); err != nil {
res = append(res, err)
}
if err := m.validateOidc(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *IdpConfiguration) validateActiveDirectory(formats strfmt.Registry) error {
if swag.IsZero(m.ActiveDirectory) { // not required
return nil
}
if m.ActiveDirectory != nil {
if err := m.ActiveDirectory.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("active_directory")
}
return err
}
}
return nil
}
func (m *IdpConfiguration) validateOidc(formats strfmt.Registry) error {
if swag.IsZero(m.Oidc) { // not required
return nil
}
if m.Oidc != nil {
if err := m.Oidc.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("oidc")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *IdpConfiguration) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *IdpConfiguration) UnmarshalBinary(b []byte) error {
var res IdpConfiguration
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// IdpConfigurationActiveDirectory idp configuration active directory
//
// swagger:model IdpConfigurationActiveDirectory
type IdpConfigurationActiveDirectory struct {
// group name attribute
GroupNameAttribute string `json:"group_name_attribute,omitempty"`
// group search base dn
GroupSearchBaseDn string `json:"group_search_base_dn,omitempty"`
// group search filter
GroupSearchFilter string `json:"group_search_filter,omitempty"`
// server insecure
ServerInsecure bool `json:"server_insecure,omitempty"`
// skip ssl verification
SkipSslVerification bool `json:"skip_ssl_verification,omitempty"`
// url
// Required: true
URL *string `json:"url"`
// user search filter
// Required: true
UserSearchFilter *string `json:"user_search_filter"`
// username format
// Required: true
UsernameFormat *string `json:"username_format"`
}
// Validate validates this idp configuration active directory
func (m *IdpConfigurationActiveDirectory) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateURL(formats); err != nil {
res = append(res, err)
}
if err := m.validateUserSearchFilter(formats); err != nil {
res = append(res, err)
}
if err := m.validateUsernameFormat(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *IdpConfigurationActiveDirectory) validateURL(formats strfmt.Registry) error {
if err := validate.Required("active_directory"+"."+"url", "body", m.URL); err != nil {
return err
}
return nil
}
func (m *IdpConfigurationActiveDirectory) validateUserSearchFilter(formats strfmt.Registry) error {
if err := validate.Required("active_directory"+"."+"user_search_filter", "body", m.UserSearchFilter); err != nil {
return err
}
return nil
}
func (m *IdpConfigurationActiveDirectory) validateUsernameFormat(formats strfmt.Registry) error {
if err := validate.Required("active_directory"+"."+"username_format", "body", m.UsernameFormat); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *IdpConfigurationActiveDirectory) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *IdpConfigurationActiveDirectory) UnmarshalBinary(b []byte) error {
var res IdpConfigurationActiveDirectory
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// IdpConfigurationOidc idp configuration oidc
//
// swagger:model IdpConfigurationOidc
type IdpConfigurationOidc struct {
// client id
// Required: true
ClientID *string `json:"client_id"`
// secret id
// Required: true
SecretID *string `json:"secret_id"`
// url
// Required: true
URL *string `json:"url"`
}
// Validate validates this idp configuration oidc
func (m *IdpConfigurationOidc) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateClientID(formats); err != nil {
res = append(res, err)
}
if err := m.validateSecretID(formats); err != nil {
res = append(res, err)
}
if err := m.validateURL(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *IdpConfigurationOidc) validateClientID(formats strfmt.Registry) error {
if err := validate.Required("oidc"+"."+"client_id", "body", m.ClientID); err != nil {
return err
}
return nil
}
func (m *IdpConfigurationOidc) validateSecretID(formats strfmt.Registry) error {
if err := validate.Required("oidc"+"."+"secret_id", "body", m.SecretID); err != nil {
return err
}
return nil
}
func (m *IdpConfigurationOidc) validateURL(formats strfmt.Registry) error {
if err := validate.Required("oidc"+"."+"url", "body", m.URL); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *IdpConfigurationOidc) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *IdpConfigurationOidc) UnmarshalBinary(b []byte) error {
var res IdpConfigurationOidc
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

115
models/image_registry.go Normal file
View File

@@ -0,0 +1,115 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// ImageRegistry image registry
//
// swagger:model imageRegistry
type ImageRegistry struct {
// password
// Required: true
Password *string `json:"password"`
// registry
// Required: true
Registry *string `json:"registry"`
// username
// Required: true
Username *string `json:"username"`
}
// Validate validates this image registry
func (m *ImageRegistry) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validatePassword(formats); err != nil {
res = append(res, err)
}
if err := m.validateRegistry(formats); err != nil {
res = append(res, err)
}
if err := m.validateUsername(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *ImageRegistry) validatePassword(formats strfmt.Registry) error {
if err := validate.Required("password", "body", m.Password); err != nil {
return err
}
return nil
}
func (m *ImageRegistry) validateRegistry(formats strfmt.Registry) error {
if err := validate.Required("registry", "body", m.Registry); err != nil {
return err
}
return nil
}
func (m *ImageRegistry) validateUsername(formats strfmt.Registry) error {
if err := validate.Required("username", "body", m.Username); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *ImageRegistry) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *ImageRegistry) UnmarshalBinary(b []byte) error {
var res ImageRegistry
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -32,8 +32,11 @@ import (
// swagger:model tenantUsage
type TenantUsage struct {
// used size
UsedSize int64 `json:"used_size,omitempty"`
// disk used
DiskUsed int64 `json:"disk_used,omitempty"`
// used
Used int64 `json:"used,omitempty"`
}
// Validate validates this tenant usage

View File

@@ -0,0 +1,98 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// TLSConfiguration tls configuration
//
// swagger:model tlsConfiguration
type TLSConfiguration struct {
// crt
// Required: true
Crt *string `json:"crt"`
// key
// Required: true
Key *string `json:"key"`
}
// Validate validates this tls configuration
func (m *TLSConfiguration) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateCrt(formats); err != nil {
res = append(res, err)
}
if err := m.validateKey(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *TLSConfiguration) validateCrt(formats strfmt.Registry) error {
if err := validate.Required("crt", "body", m.Crt); err != nil {
return err
}
return nil
}
func (m *TLSConfiguration) validateKey(formats strfmt.Registry) error {
if err := validate.Required("key", "body", m.Key); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *TLSConfiguration) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *TLSConfiguration) UnmarshalBinary(b []byte) error {
var res TLSConfiguration
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -37,6 +37,9 @@ type UpdateTenantRequest struct {
// image
// Pattern: ^((.*?)/(.*?):(.+))$
Image string `json:"image,omitempty"`
// image registry
ImageRegistry *ImageRegistry `json:"image_registry,omitempty"`
}
// Validate validates this update tenant request
@@ -47,6 +50,10 @@ func (m *UpdateTenantRequest) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateImageRegistry(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
@@ -66,6 +73,24 @@ func (m *UpdateTenantRequest) validateImage(formats strfmt.Registry) error {
return nil
}
func (m *UpdateTenantRequest) validateImageRegistry(formats strfmt.Registry) error {
if swag.IsZero(m.ImageRegistry) { // not required
return nil
}
if m.ImageRegistry != nil {
if err := m.ImageRegistry.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("image_registry")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *UpdateTenantRequest) MarshalBinary() ([]byte, error) {
if m == nil {

View File

@@ -0,0 +1,247 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2020 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package models
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/go-openapi/errors"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
// VaultConfiguration vault configuration
//
// swagger:model vaultConfiguration
type VaultConfiguration struct {
// approle
// Required: true
Approle *VaultConfigurationApprole `json:"approle"`
// endpoint
// Required: true
Endpoint *string `json:"endpoint"`
// engine
Engine string `json:"engine,omitempty"`
// namespace
Namespace string `json:"namespace,omitempty"`
// prefix
Prefix string `json:"prefix,omitempty"`
// status
Status *VaultConfigurationStatus `json:"status,omitempty"`
}
// Validate validates this vault configuration
func (m *VaultConfiguration) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateApprole(formats); err != nil {
res = append(res, err)
}
if err := m.validateEndpoint(formats); err != nil {
res = append(res, err)
}
if err := m.validateStatus(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *VaultConfiguration) validateApprole(formats strfmt.Registry) error {
if err := validate.Required("approle", "body", m.Approle); err != nil {
return err
}
if m.Approle != nil {
if err := m.Approle.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("approle")
}
return err
}
}
return nil
}
func (m *VaultConfiguration) validateEndpoint(formats strfmt.Registry) error {
if err := validate.Required("endpoint", "body", m.Endpoint); err != nil {
return err
}
return nil
}
func (m *VaultConfiguration) validateStatus(formats strfmt.Registry) error {
if swag.IsZero(m.Status) { // not required
return nil
}
if m.Status != nil {
if err := m.Status.Validate(formats); err != nil {
if ve, ok := err.(*errors.Validation); ok {
return ve.ValidateName("status")
}
return err
}
}
return nil
}
// MarshalBinary interface implementation
func (m *VaultConfiguration) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *VaultConfiguration) UnmarshalBinary(b []byte) error {
var res VaultConfiguration
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// VaultConfigurationApprole vault configuration approle
//
// swagger:model VaultConfigurationApprole
type VaultConfigurationApprole struct {
// engine
Engine string `json:"engine,omitempty"`
// id
// Required: true
ID *string `json:"id"`
// retry
Retry int64 `json:"retry,omitempty"`
// secret
// Required: true
Secret *string `json:"secret"`
}
// Validate validates this vault configuration approle
func (m *VaultConfigurationApprole) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validateID(formats); err != nil {
res = append(res, err)
}
if err := m.validateSecret(formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *VaultConfigurationApprole) validateID(formats strfmt.Registry) error {
if err := validate.Required("approle"+"."+"id", "body", m.ID); err != nil {
return err
}
return nil
}
func (m *VaultConfigurationApprole) validateSecret(formats strfmt.Registry) error {
if err := validate.Required("approle"+"."+"secret", "body", m.Secret); err != nil {
return err
}
return nil
}
// MarshalBinary interface implementation
func (m *VaultConfigurationApprole) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *VaultConfigurationApprole) UnmarshalBinary(b []byte) error {
var res VaultConfigurationApprole
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}
// VaultConfigurationStatus vault configuration status
//
// swagger:model VaultConfigurationStatus
type VaultConfigurationStatus struct {
// ping
Ping int64 `json:"ping,omitempty"`
}
// Validate validates this vault configuration status
func (m *VaultConfigurationStatus) Validate(formats strfmt.Registry) error {
return nil
}
// MarshalBinary interface implementation
func (m *VaultConfigurationStatus) MarshalBinary() ([]byte, error) {
if m == nil {
return nil, nil
}
return swag.WriteJSON(m)
}
// UnmarshalBinary interface implementation
func (m *VaultConfigurationStatus) UnmarshalBinary(b []byte) error {
var res VaultConfigurationStatus
if err := swag.ReadJSON(b, &res); err != nil {
return err
}
*m = res
return nil
}

View File

@@ -1,281 +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 jwt
// This file is a re-implementation of the original code here with some
// additional allocation tweaks reproduced using GODEBUG=allocfreetrace=1
// original file https://github.com/dgrijalva/jwt-go/blob/master/parser.go
// borrowed under MIT License https://github.com/dgrijalva/jwt-go/blob/master/LICENSE
import (
"crypto"
"crypto/hmac"
"encoding/base64"
"encoding/json"
"fmt"
"strings"
"sync"
"time"
jwtgo "github.com/dgrijalva/jwt-go"
jsoniter "github.com/json-iterator/go"
)
const (
claimData = "data"
claimSub = "sub"
)
// SigningMethodHMAC - Implements the HMAC-SHA family of signing methods signing methods
// Expects key type of []byte for both signing and validation
type SigningMethodHMAC struct {
Name string
Hash crypto.Hash
}
// Specific instances for HS256, HS384, HS512
var (
SigningMethodHS256 *SigningMethodHMAC
SigningMethodHS384 *SigningMethodHMAC
SigningMethodHS512 *SigningMethodHMAC
)
var (
base64BufPool sync.Pool
hmacSigners []*SigningMethodHMAC
)
func init() {
base64BufPool = sync.Pool{
New: func() interface{} {
buf := make([]byte, 8192)
return &buf
},
}
hmacSigners = []*SigningMethodHMAC{
{"HS256", crypto.SHA256},
{"HS384", crypto.SHA384},
{"HS512", crypto.SHA512},
}
}
// StandardClaims are basically standard claims with "Data"
type StandardClaims struct {
Data string `json:"data,omitempty"`
jwtgo.StandardClaims
}
// MapClaims - implements custom unmarshaller
type MapClaims struct {
Data string `json:"data,omitempty"`
Subject string `json:"sub,omitempty"`
jwtgo.MapClaims
}
// NewStandardClaims - initializes standard claims
func NewStandardClaims() *StandardClaims {
return &StandardClaims{}
}
// SetIssuer sets issuer for these claims
func (c *StandardClaims) SetIssuer(issuer string) {
c.Issuer = issuer
}
// SetAudience sets audience for these claims
func (c *StandardClaims) SetAudience(aud string) {
c.Audience = aud
}
// SetExpiry sets expiry in unix epoch secs
func (c *StandardClaims) SetExpiry(t time.Time) {
c.ExpiresAt = t.Unix()
}
// SetSubject sets unique identifier for the jwt
func (c *StandardClaims) SetSubject(subject string) {
c.Subject = subject
}
// SetData sets the "Data" custom field.
func (c *StandardClaims) SetData(data string) {
c.Data = data
}
// Valid - implements https://godoc.org/github.com/dgrijalva/jwt-go#Claims compatible
// claims interface, additionally validates "Data" field.
func (c *StandardClaims) Valid() error {
if err := c.StandardClaims.Valid(); err != nil {
return err
}
if c.Data == "" || c.Subject == "" {
return jwtgo.NewValidationError("data/sub",
jwtgo.ValidationErrorClaimsInvalid)
}
return nil
}
// NewMapClaims - Initializes a new map claims
func NewMapClaims() *MapClaims {
return &MapClaims{MapClaims: jwtgo.MapClaims{}}
}
// Lookup returns the value and if the key is found.
func (c *MapClaims) Lookup(key string) (value string, ok bool) {
var vinterface interface{}
vinterface, ok = c.MapClaims[key]
if ok {
value, ok = vinterface.(string)
}
return
}
// SetExpiry sets expiry in unix epoch secs
func (c *MapClaims) SetExpiry(t time.Time) {
c.MapClaims["exp"] = t.Unix()
}
// SetData sets the "Data" custom field.
func (c *MapClaims) SetData(data string) {
c.MapClaims[claimData] = data
}
// Valid - implements https://godoc.org/github.com/dgrijalva/jwt-go#Claims compatible
// claims interface, additionally validates "Data" field.
func (c *MapClaims) Valid() error {
if err := c.MapClaims.Valid(); err != nil {
return err
}
if c.Data == "" || c.Subject == "" {
return jwtgo.NewValidationError("data/subject",
jwtgo.ValidationErrorClaimsInvalid)
}
return nil
}
// Map returns underlying low-level map claims.
func (c *MapClaims) Map() map[string]interface{} {
return c.MapClaims
}
// MarshalJSON marshals the MapClaims struct
func (c *MapClaims) MarshalJSON() ([]byte, error) {
return json.Marshal(c.MapClaims)
}
// https://tools.ietf.org/html/rfc7519#page-11
type jwtHeader struct {
Algorithm string `json:"alg"`
Type string `json:"typ"`
}
// ParseWithClaims - parse the token string, valid methods.
func ParseWithClaims(tokenStr string, claims *MapClaims) error {
bufp := base64BufPool.Get().(*[]byte)
defer base64BufPool.Put(bufp)
signer, err := parseUnverifiedMapClaims(tokenStr, claims, *bufp)
if err != nil {
return err
}
i := strings.LastIndex(tokenStr, ".")
if i < 0 {
return jwtgo.ErrSignatureInvalid
}
n, err := base64Decode(tokenStr[i+1:], *bufp)
if err != nil {
return err
}
var ok bool
claims.Data, ok = claims.Lookup(claimData)
if !ok {
return jwtgo.NewValidationError("data missing",
jwtgo.ValidationErrorClaimsInvalid)
}
claims.Subject, ok = claims.Lookup(claimSub)
if !ok {
return jwtgo.NewValidationError("sub missing",
jwtgo.ValidationErrorClaimsInvalid)
}
hasher := hmac.New(signer.Hash.New, []byte(GetHmacJWTSecret()))
hasher.Write([]byte(tokenStr[:i]))
if !hmac.Equal((*bufp)[:n], hasher.Sum(nil)) {
return jwtgo.ErrSignatureInvalid
}
// Signature is valid, lets validate the claims for
// other fields such as expiry etc.
return claims.Valid()
}
// base64Decode returns the bytes represented by the base64 string s.
func base64Decode(s string, buf []byte) (int, error) {
return base64.RawURLEncoding.Decode(buf, []byte(s))
}
// ParseUnverifiedMapClaims - WARNING: Don't use this method unless you know what you're doing
//
// This method parses the token but doesn't validate the signature. It's only
// ever useful in cases where you know the signature is valid (because it has
// been checked previously in the stack) and you want to extract values from
// it.
func parseUnverifiedMapClaims(tokenString string, claims *MapClaims, buf []byte) (*SigningMethodHMAC, error) {
if strings.Count(tokenString, ".") != 2 {
return nil, jwtgo.ErrSignatureInvalid
}
i := strings.Index(tokenString, ".")
j := strings.LastIndex(tokenString, ".")
n, err := base64Decode(tokenString[:i], buf)
if err != nil {
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed}
}
var header = jwtHeader{}
var json = jsoniter.ConfigCompatibleWithStandardLibrary
if err = json.Unmarshal(buf[:n], &header); err != nil {
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed}
}
n, err = base64Decode(tokenString[i+1:j], buf)
if err != nil {
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed}
}
if err = json.Unmarshal(buf[:n], &claims.MapClaims); err != nil {
return nil, &jwtgo.ValidationError{Inner: err, Errors: jwtgo.ValidationErrorMalformed}
}
for _, signer := range hmacSigners {
if header.Algorithm == signer.Name {
return signer, nil
}
}
return nil, jwtgo.NewValidationError(fmt.Sprintf("signing method (%s) is unavailable.", header.Algorithm),
jwtgo.ValidationErrorUnverifiable)
}

View File

@@ -24,11 +24,11 @@ import (
)
var (
errInvalidCredentials = errors.New("invalid Credentials")
errInvalidCredentials = errors.New("invalid Login")
)
// GetConsoleCredentialsFromLDAP authenticates the user against MinIO when the LDAP integration is enabled
// if the authentication succeed *credentials.Credentials object is returned and we continue with the normal STSAssumeRole flow
// if the authentication succeed *credentials.Login object is returned and we continue with the normal STSAssumeRole flow
func GetConsoleCredentialsFromLDAP(endpoint, ldapUser, ldapPassword string) (*credentials.Credentials, error) {
creds, err := credentials.NewLDAPIdentity(endpoint, ldapUser, ldapPassword)
if err != nil {

View File

@@ -76,7 +76,7 @@ func isServiceAccountTokenValid(ctx context.Context, operatorClient OperatorClie
return true
}
// GetConsoleCredentialsForOperator will validate the provided JWT (service account token) and return it in the form of credentials.Credentials
// GetConsoleCredentialsForOperator will validate the provided JWT (service account token) and return it in the form of credentials.Login
func GetConsoleCredentialsForOperator(jwt string) (*credentials.Credentials, error) {
ctx := context.Background()
opClientClientSet, err := cluster.OperatorClient(jwt)

View File

@@ -28,30 +28,26 @@ import (
"log"
"net/http"
"strings"
"time"
jwtgo "github.com/dgrijalva/jwt-go"
"github.com/go-openapi/swag"
"github.com/minio/console/models"
xjwt "github.com/minio/console/pkg/auth/jwt"
"github.com/minio/console/pkg/auth/token"
"github.com/minio/minio-go/v7/pkg/credentials"
uuid "github.com/satori/go.uuid"
"golang.org/x/crypto/pbkdf2"
)
var (
errAuthentication = errors.New("authentication failed, check your access credentials")
errNoAuthToken = errors.New("JWT token missing")
errReadingToken = errors.New("JWT internal data is malformed")
errClaimsFormat = errors.New("encrypted jwt claims not in the right format")
errNoAuthToken = errors.New("session token missing")
errReadingToken = errors.New("session token internal data is malformed")
errClaimsFormat = errors.New("encrypted session token claims not in the right format")
)
// derivedKey is the key used to encrypt the JWT claims, its derived using pbkdf on CONSOLE_PBKDF_PASSPHRASE with CONSOLE_PBKDF_SALT
var derivedKey = pbkdf2.Key([]byte(xjwt.GetPBKDFPassphrase()), []byte(xjwt.GetPBKDFSalt()), 4096, 32, sha1.New)
// derivedKey is the key used to encrypt the session token claims, its derived using pbkdf on CONSOLE_PBKDF_PASSPHRASE with CONSOLE_PBKDF_SALT
var derivedKey = pbkdf2.Key([]byte(token.GetPBKDFPassphrase()), []byte(token.GetPBKDFSalt()), 4096, 32, sha1.New)
// IsJWTValid returns true or false depending if the provided jwt is valid or not
func IsJWTValid(token string) bool {
_, err := JWTAuthenticate(token)
// IsSessionTokenValid returns true or false depending if the provided session token is valid or not
func IsSessionTokenValid(token string) bool {
_, err := SessionTokenAuthenticate(token)
return err == nil
}
@@ -63,8 +59,8 @@ type DecryptedClaims struct {
Actions []string
}
// JWTAuthenticate takes a jwt, decode it, extract claims and validate the signature
// if the jwt claims.Data is valid we proceed to decrypt the information inside
// SessionTokenAuthenticate takes a session token, decode it, extract claims and validate the signature
// if the session token claims are valid we proceed to decrypt the information inside
//
// returns claims after validation in the following format:
//
@@ -73,48 +69,36 @@ type DecryptedClaims struct {
// SecretAccessKey
// SessionToken
// }
func JWTAuthenticate(token string) (*DecryptedClaims, error) {
func SessionTokenAuthenticate(token string) (*DecryptedClaims, error) {
if token == "" {
return nil, errNoAuthToken
}
// initialize claims object
claims := xjwt.NewMapClaims()
// populate the claims object
if err := xjwt.ParseWithClaims(token, claims); err != nil {
return nil, errAuthentication
}
// decrypt the claims.Data field
claimTokens, err := decryptClaims(claims.Data)
// decrypt encrypted token
claimTokens, err := decryptClaims(token)
if err != nil {
// we print decryption token error information for debugging purposes
log.Println(err)
// we return a generic error that doesn't give any information to attackers
return nil, errReadingToken
}
// claimsTokens contains the decrypted STS claims
// claimsTokens contains the decrypted JWT for Console
return claimTokens, nil
}
// NewJWTWithClaimsForClient generates a new jwt with claims based on the provided STS credentials, first
// NewEncryptedTokenForClient generates a new session token with claims based on the provided STS credentials, first
// encrypts the claims and the sign them
func NewJWTWithClaimsForClient(credentials *credentials.Value, actions []string, audience string) (string, error) {
func NewEncryptedTokenForClient(credentials *credentials.Value, actions []string) (string, error) {
if credentials != nil {
encryptedClaims, err := encryptClaims(credentials.AccessKeyID, credentials.SecretAccessKey, credentials.SessionToken, actions)
if err != nil {
return "", err
}
claims := xjwt.NewStandardClaims()
claims.SetExpiry(time.Now().UTC().Add(xjwt.GetConsoleSTSAndJWTDurationTime()))
claims.SetSubject(uuid.NewV4().String())
claims.SetData(encryptedClaims)
claims.SetAudience(audience)
jwt := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, claims)
return jwt.SignedString([]byte(xjwt.GetHmacJWTSecret()))
return encryptedClaims, nil
}
return "", errors.New("provided credentials are empty")
}
// encryptClaims() receives the 3 STS claims, concatenate them and encrypt them using AES-GCM
// encryptClaims() receives the STS claims, concatenate them and encrypt them using AES-GCM
// returns a base64 encoded ciphertext
func encryptClaims(accessKeyID, secretAccessKey, sessionToken string, actions []string) (string, error) {
payload := []byte(fmt.Sprintf("%s#%s#%s#%s", accessKeyID, secretAccessKey, sessionToken, strings.Join(actions, ",")))
@@ -189,7 +173,7 @@ func decrypt(data []byte) ([]byte, error) {
// GetTokenFromRequest returns a token from a http Request
// either defined on a cookie `token` or on Authorization header.
//
// Authorization Header needs to be like "Authorization Bearer <jwt_token>"
// Authorization Header needs to be like "Authorization Bearer <token>"
func GetTokenFromRequest(r *http.Request) (*string, error) {
// Get Auth token
var reqToken string
@@ -216,9 +200,9 @@ func GetClaimsFromTokenInRequest(req *http.Request) (*models.Principal, error) {
if err != nil {
return nil, err
}
// Perform decryption of the JWT, if Console is able to decrypt the JWT that means a valid session
// Perform decryption of the session token, if Console is able to decrypt the session token that means a valid session
// was used in the first place to get it
claims, err := JWTAuthenticate(*sessionID)
claims, err := SessionTokenAuthenticate(*sessionID)
if err != nil {
return nil, err
}

View File

@@ -14,24 +14,15 @@
// 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 jwt
package token
import (
"strconv"
"time"
"github.com/minio/console/pkg/auth/utils"
"github.com/minio/minio/pkg/env"
)
// defaultHmacJWTPassphrase will be used by default if application is not configured with a custom CONSOLE_HMAC_JWT_SECRET secret
var defaultHmacJWTPassphrase = utils.RandomCharString(64)
// GetHmacJWTSecret returns the 64 bytes secret used for signing the generated JWT for the application
func GetHmacJWTSecret() string {
return env.Get(ConsoleHmacJWTSecret, defaultHmacJWTPassphrase)
}
// ConsoleSTSAndJWTDurationSeconds returns the default session duration for the STS requested tokens and the generated JWTs.
// Ideally both values should match so jwt and Minio sts sessions expires at the same time.
func GetConsoleSTSAndJWTDurationInSeconds() int {
@@ -42,12 +33,6 @@ func GetConsoleSTSAndJWTDurationInSeconds() int {
return duration
}
// GetConsoleSTSAndJWTDurationTime returns GetConsoleSTSAndJWTDurationInSeconds in duration format
func GetConsoleSTSAndJWTDurationTime() time.Duration {
duration := GetConsoleSTSAndJWTDurationInSeconds()
return time.Duration(duration) * time.Second
}
var defaultPBKDFPassphrase = utils.RandomCharString(64)
// GetPBKDFPassphrase returns passphrase for the pbkdf2 function used to encrypt JWT payload

View File

@@ -14,10 +14,9 @@
// 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 jwt
package token
const (
ConsoleHmacJWTSecret = "CONSOLE_HMAC_JWT_SECRET"
ConsoleSTSAndJWTDurationSeconds = "CONSOLE_STS_AND_JWT_DURATION_SECONDS"
ConsolePBKDFPassphrase = "CONSOLE_PBKDF_PASSPHRASE"
ConsolePBKDFSalt = "CONSOLE_PBKDF_SALT"

View File

@@ -23,7 +23,6 @@ import (
"github.com/stretchr/testify/assert"
)
var audience = ""
var creds = &credentials.Value{
AccessKeyID: "fakeAccessKeyID",
SecretAccessKey: "fakeSecretAccessKey",
@@ -35,25 +34,25 @@ var badToken = "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiRDMwYWE0ekQ1bWt
func TestNewJWTWithClaimsForClient(t *testing.T) {
funcAssert := assert.New(t)
// Test-1 : NewJWTWithClaimsForClient() is generated correctly without errors
function := "NewJWTWithClaimsForClient()"
jwt, err := NewJWTWithClaimsForClient(creds, []string{""}, audience)
// Test-1 : NewEncryptedTokenForClient() is generated correctly without errors
function := "NewEncryptedTokenForClient()"
jwt, err := NewEncryptedTokenForClient(creds, []string{""})
if err != nil || jwt == "" {
t.Errorf("Failed on %s:, error occurred: %s", function, err)
}
// saving jwt for future tests
goodToken = jwt
// Test-2 : NewJWTWithClaimsForClient() throws error because of empty credentials
if _, err = NewJWTWithClaimsForClient(nil, []string{""}, audience); err != nil {
// Test-2 : NewEncryptedTokenForClient() throws error because of empty credentials
if _, err = NewEncryptedTokenForClient(nil, []string{""}); err != nil {
funcAssert.Equal("provided credentials are empty", err.Error())
}
}
func TestJWTAuthenticate(t *testing.T) {
funcAssert := assert.New(t)
// Test-1 : JWTAuthenticate() should correctly return the claims
function := "JWTAuthenticate()"
claims, err := JWTAuthenticate(goodToken)
// Test-1 : SessionTokenAuthenticate() should correctly return the claims
function := "SessionTokenAuthenticate()"
claims, err := SessionTokenAuthenticate(goodToken)
if err != nil || claims == nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err)
} else {
@@ -61,20 +60,20 @@ func TestJWTAuthenticate(t *testing.T) {
funcAssert.Equal(claims.SecretAccessKey, creds.SecretAccessKey)
funcAssert.Equal(claims.SessionToken, creds.SessionToken)
}
// Test-2 : JWTAuthenticate() return an error because of a tampered jwt
if _, err := JWTAuthenticate(badToken); err != nil {
funcAssert.Equal("authentication failed, check your access credentials", err.Error())
// Test-2 : SessionTokenAuthenticate() return an error because of a tampered jwt
if _, err := SessionTokenAuthenticate(badToken); err != nil {
funcAssert.Equal("session token internal data is malformed", err.Error())
}
// Test-3 : JWTAuthenticate() return an error because of an empty jwt
if _, err := JWTAuthenticate(""); err != nil {
funcAssert.Equal("JWT token missing", err.Error())
// Test-3 : SessionTokenAuthenticate() return an error because of an empty jwt
if _, err := SessionTokenAuthenticate(""); err != nil {
funcAssert.Equal("session token missing", err.Error())
}
}
func TestIsJWTValid(t *testing.T) {
funcAssert := assert.New(t)
// Test-1 : JWTAuthenticate() provided token is valid
funcAssert.Equal(true, IsJWTValid(goodToken))
// Test-2 : JWTAuthenticate() provided token is invalid
funcAssert.Equal(false, IsJWTValid(badToken))
// Test-1 : SessionTokenAuthenticate() provided token is valid
funcAssert.Equal(true, IsSessionTokenValid(goodToken))
// Test-2 : SessionTokenAuthenticate() provided token is invalid
funcAssert.Equal(false, IsSessionTokenValid(badToken))
}

144
pkg/kes/kes.go Normal file
View File

@@ -0,0 +1,144 @@
package kes
import (
"crypto/x509"
"encoding/pem"
"errors"
"time"
"github.com/minio/kes"
)
type TLSProxyHeader struct {
ClientCert string `yaml:"cert,omitempty"`
}
type TLSProxy struct {
Identities *[]kes.Identity `yaml:"identities,omitempty"`
Header *TLSProxyHeader `yaml:"header,omitempty"`
}
type TLS struct {
KeyPath string `yaml:"key,omitempty"`
CertPath string `yaml:"cert,omitempty"`
Proxy *TLSProxy `yaml:"proxy,omitempty"`
}
type Policy struct {
Paths []string `yaml:"paths,omitempty"`
Identities []kes.Identity `yaml:"identities,omitempty"`
}
type Expiry struct {
Any time.Duration `yaml:"any,omitempty"`
Unused time.Duration `yaml:"unused,omitempty"`
}
type Cache struct {
Expiry *Expiry `yaml:"expiry,omitempty"`
}
type Log struct {
Error string `yaml:"error,omitempty"`
Audit string `yaml:"audit,omitempty"`
}
type Fs struct {
Path string `yaml:"path,omitempty"`
}
type AppRole struct {
EnginePath string `yaml:"engine,omitempty"`
ID string `yaml:"id,omitempty"`
Secret string `yaml:"secret,omitempty"`
Retry time.Duration `yaml:"retry,omitempty"`
}
type VaultTLS struct {
KeyPath string `yaml:"key,omitempty"`
CertPath string `yaml:"cert,omitempty"`
CAPath string `yaml:"ca,omitempty"`
}
type VaultStatus struct {
Ping time.Duration `yaml:"ping,omitempty"`
}
type Vault struct {
Endpoint string `yaml:"endpoint,omitempty"`
EnginePath string `yaml:"engine,omitempty"`
Namespace string `yaml:"namespace,omitempty"`
Prefix string `yaml:"prefix,omitempty"`
AppRole *AppRole `yaml:"approle,omitempty"`
TLS *VaultTLS `yaml:"tls,omitempty"`
Status *VaultStatus `yaml:"status,omitempty"`
}
type AwsSecretManagerLogin struct {
AccessKey string `yaml:"accesskey"`
SecretKey string `yaml:"secretkey"`
SessionToken string `yaml:"token"`
}
type AwsSecretManager struct {
Endpoint string `yaml:"endpoint,omitempty"`
Region string `yaml:"region,omitempty"`
KmsKey string ` yaml:"kmskey,omitempty"`
Login *AwsSecretManagerLogin `yaml:"credentials,omitempty"`
}
type Aws struct {
SecretsManager *AwsSecretManager `yaml:"secretsmanager,omitempty"`
}
type GemaltoCredentials struct {
Token string `yaml:"token,omitempty"`
Domain string `yaml:"domain,omitempty"`
Retry time.Duration `yaml:"retry,omitempty"`
}
type GemaltoTLS struct {
CAPath string `yaml:"ca,omitempty"`
}
type GemaltoKeySecure struct {
Endpoint string `yaml:"endpoint,omitempty"`
Credentials *GemaltoCredentials `yaml:"credentials,omitempty"`
TLS *GemaltoTLS `yaml:"tls,omitempty"`
}
type Gemalto struct {
KeySecure *GemaltoKeySecure `yaml:"keysecure,omitempty"`
}
type Keys struct {
Fs *Fs `yaml:"fs,omitempty"`
Vault *Vault `yaml:"vault,omitempty"`
Aws *Aws `yaml:"aws,omitempty"`
Gemalto *Gemalto `yaml:"gemalto,omitempty"`
}
type ServerConfig struct {
Addr string `yaml:"address,omitempty"`
Root kes.Identity `yaml:"root,omitempty"`
TLS TLS `yaml:"tls,omitempty"`
Policies map[string]Policy `yaml:"policy,omitempty"`
Cache Cache `yaml:"cache,omitempty"`
Log Log `yaml:"log,omitempty"`
Keys Keys `yaml:"keys,omitempty"`
}
func ParseCertificate(cert []byte) (*x509.Certificate, error) {
for {
var certDERBlock *pem.Block
certDERBlock, cert = pem.Decode(cert)
if certDERBlock == nil {
break
}
if certDERBlock.Type == "CERTIFICATE" {
return x509.ParseCertificate(certDERBlock.Bytes)
}
}
return nil, errors.New("found no (non-CA) certificate in any PEM block")
}

View File

@@ -4877,9 +4877,9 @@
"integrity": "sha512-WOr3SrZ55lUFYugA6sUu3H3ZoxVIH5o3zTSqYS+2DOJJP4hnHmBiD1w432a2YFW/H2G5FIxE6DB06rv+9dUL5g=="
},
"elliptic": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz",
"integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==",
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
"requires": {
"bn.js": "^4.4.0",
"brorand": "^1.0.1",

View File

@@ -250,7 +250,10 @@ const Login = ({ classes, userLoggedIn }: ILoginProps) => {
</Typography>
<Button
component={"a"}
href={loginStrategy.redirect}
href={loginStrategy.redirect.replace(
"%5BHOSTNAME%5D",
window.location.hostname
)}
type="submit"
fullWidth
variant="contained"

View File

@@ -2588,9 +2588,9 @@ bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5:
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
version "4.11.8"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
version "4.11.9"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
body-parser@1.19.0:
version "1.19.0"
@@ -4374,9 +4374,9 @@ electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.413:
integrity sha512-JTEOWiqCY4snuKuQAaFy0z6LK2Gdb8Lojkd/csQwpNHgMUF8I6QRjGVKk44IH46dHQhUFKzr4o6zxZrtDBjc2Q==
elliptic@^6.0.0:
version "6.5.2"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762"
integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==
version "6.5.3"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
dependencies:
bn.js "^4.4.0"
brorand "^1.0.1"

View File

@@ -60,11 +60,11 @@ func TestListConfig(t *testing.T) {
function := "listConfig()"
// Test-1 : listConfig() get list of two configurations and ensure is output correctly
configListMock := []madmin.HelpKV{
madmin.HelpKV{
{
Key: "region",
Description: "label the location of the server",
},
madmin.HelpKV{
{
Key: "notify_nsq",
Description: "publish bucket notifications to NSQ endpoints",
},

View File

@@ -18,6 +18,9 @@ package restapi
import (
"context"
"crypto"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
@@ -29,13 +32,16 @@ import (
"strings"
"time"
"github.com/minio/console/pkg/kes"
kes2 "github.com/minio/kes"
"gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/api/resource"
types "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/types"
corev1 "k8s.io/api/core/v1"
"github.com/minio/console/cluster"
madmin "github.com/minio/minio/pkg/madmin"
"github.com/minio/minio/pkg/madmin"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/swag"
@@ -43,14 +49,31 @@ import (
"github.com/minio/console/restapi/operations"
"github.com/minio/console/restapi/operations/admin_api"
operator "github.com/minio/operator/pkg/apis/minio.min.io/v1"
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
)
const (
minioRegCred = "minio-regcred-secret"
)
type imageRegistry struct {
Auths map[string]imageRegistryCredentials `json:"auths"`
}
type imageRegistryCredentials struct {
Username string `json:"username"`
Password string `json:"password"`
Auth string `json:"auth"`
}
func registerTenantHandlers(api *operations.ConsoleAPI) {
// Add Tenant
api.AdminAPICreateTenantHandler = admin_api.CreateTenantHandlerFunc(func(params admin_api.CreateTenantParams, session *models.Principal) middleware.Responder {
resp, err := getTenantCreatedResponse(session, params)
if err != nil {
log.Println(err)
return admin_api.NewCreateTenantDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
}
return admin_api.NewCreateTenantOK().WithPayload(resp)
@@ -59,6 +82,7 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
api.AdminAPIListAllTenantsHandler = admin_api.ListAllTenantsHandlerFunc(func(params admin_api.ListAllTenantsParams, session *models.Principal) middleware.Responder {
resp, err := getListAllTenantsResponse(session, params)
if err != nil {
log.Println(err)
return admin_api.NewListTenantsDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
}
return admin_api.NewListTenantsOK().WithPayload(resp)
@@ -68,6 +92,7 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
api.AdminAPIListTenantsHandler = admin_api.ListTenantsHandlerFunc(func(params admin_api.ListTenantsParams, session *models.Principal) middleware.Responder {
resp, err := getListTenantsResponse(session, params)
if err != nil {
log.Println(err)
return admin_api.NewListTenantsDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
}
return admin_api.NewListTenantsOK().WithPayload(resp)
@@ -77,6 +102,7 @@ func registerTenantHandlers(api *operations.ConsoleAPI) {
api.AdminAPITenantInfoHandler = admin_api.TenantInfoHandlerFunc(func(params admin_api.TenantInfoParams, session *models.Principal) middleware.Responder {
resp, err := getTenantInfoResponse(session, params)
if err != nil {
log.Println(err)
return admin_api.NewTenantInfoDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
}
return admin_api.NewTenantInfoOK().WithPayload(resp)
@@ -324,7 +350,10 @@ func getListTenantsResponse(session *models.Principal, params admin_api.ListTena
}
func getTenantCreatedResponse(session *models.Principal, params admin_api.CreateTenantParams) (*models.CreateTenantResponse, error) {
minioImage := params.Body.Image
tenantReq := params.Body
minioImage := tenantReq.Image
ctx := context.Background()
if minioImage == "" {
minImg, err := cluster.GetMinioImage()
if err != nil {
@@ -338,19 +367,22 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
return nil, err
}
ns := *params.Body.Namespace
ns := *tenantReq.Namespace
// if access/secret are provided, use them, else create a random pair
accessKey := RandomCharString(16)
secretKey := RandomCharString(32)
if params.Body.AccessKey != "" {
accessKey = params.Body.AccessKey
if tenantReq.AccessKey != "" {
accessKey = tenantReq.AccessKey
}
if params.Body.SecretKey != "" {
secretKey = params.Body.SecretKey
if tenantReq.SecretKey != "" {
secretKey = tenantReq.SecretKey
}
secretName := fmt.Sprintf("%s-secret", *params.Body.Name)
secretName := fmt.Sprintf("%s-secret", *tenantReq.Name)
imm := true
instanceSecret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
@@ -362,24 +394,27 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
},
}
_, err = clientset.CoreV1().Secrets(ns).Create(context.Background(), &instanceSecret, metav1.CreateOptions{})
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
if err != nil {
return nil, err
}
enableSSL := false
if params.Body.EnableSsl != nil {
enableSSL = *params.Body.EnableSsl
}
enableConsole := true
if params.Body.EnableConsole != nil {
enableConsole = *params.Body.EnableConsole
var envrionmentVariables []corev1.EnvVar
// Check the Erasure Coding Parity for validity and pass it to Tenant
if tenantReq.ErasureCodingParity > 0 {
if tenantReq.ErasureCodingParity < 2 && tenantReq.ErasureCodingParity > 8 {
return nil, errors.New("invalid Erasure Coding Value")
}
envrionmentVariables = append(envrionmentVariables, corev1.EnvVar{
Name: "MINIO_STORAGE_CLASS_STANDARD",
Value: fmt.Sprintf("%d", tenantReq.ErasureCodingParity),
})
}
//Construct a MinIO Instance with everything we are getting from parameters
minInst := operator.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: *params.Body.Name,
Name: *tenantReq.Name,
},
Spec: operator.TenantSpec{
Image: minioImage,
@@ -387,14 +422,338 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
CredsSecret: &corev1.LocalObjectReference{
Name: secretName,
},
RequestAutoCert: enableSSL,
Env: envrionmentVariables,
},
}
idpEnabled := false
// Enable IDP (Active Directory) for MinIO
if tenantReq.Idp != nil && tenantReq.Idp.ActiveDirectory != nil {
url := *tenantReq.Idp.ActiveDirectory.URL
userNameFormat := *tenantReq.Idp.ActiveDirectory.UsernameFormat
userSearchFilter := *tenantReq.Idp.ActiveDirectory.UserSearchFilter
tlsSkipVerify := tenantReq.Idp.ActiveDirectory.SkipSslVerification
serverInsecure := tenantReq.Idp.ActiveDirectory.ServerInsecure
groupSearchDN := tenantReq.Idp.ActiveDirectory.GroupSearchBaseDn
groupSearchFilter := tenantReq.Idp.ActiveDirectory.GroupSearchFilter
groupNameAttribute := tenantReq.Idp.ActiveDirectory.GroupNameAttribute
if url != "" && userNameFormat != "" && userSearchFilter != "" {
// CONSOLE_LDAP_ENABLED
idpEnabled = true
minInst.Spec.Env = append(minInst.Spec.Env, corev1.EnvVar{
Name: "MINIO_IDENTITY_LDAP_SERVER_ADDR",
Value: userNameFormat,
}, corev1.EnvVar{
Name: "MINIO_IDENTITY_LDAP_USERNAME_FORMAT",
Value: userNameFormat,
}, corev1.EnvVar{
Name: "MINIO_IDENTITY_LDAP_USERNAME_SEARCH_FILTER",
Value: userSearchFilter,
}, corev1.EnvVar{
Name: "MINIO_IDENTITY_LDAP_USERNAME_SEARCH_FILTER",
Value: userSearchFilter,
}, corev1.EnvVar{
Name: "MINIO_IDENTITY_LDAP_GROUP_SEARCH_BASE_DN",
Value: groupSearchDN,
}, corev1.EnvVar{
Name: "MINIO_IDENTITY_LDAP_GROUP_SEARCH_FILTER",
Value: groupSearchFilter,
}, corev1.EnvVar{
Name: "MINIO_IDENTITY_LDAP_GROUP_NAME_ATTRIBUTE",
Value: groupNameAttribute,
})
if tlsSkipVerify {
minInst.Spec.Env = append(minInst.Spec.Env, corev1.EnvVar{
Name: "MINIO_IDENTITY_LDAP_TLS_SKIP_VERIFY",
Value: "on",
})
}
if serverInsecure {
minInst.Spec.Env = append(minInst.Spec.Env, corev1.EnvVar{
Name: "MINIO_IDENTITY_LDAP_SERVER_INSECURE",
Value: "on",
})
}
}
}
// operator request AutoCert feature
encryption := false
if tenantReq.EnableSsl != nil {
encryption = true
minInst.Spec.RequestAutoCert = *tenantReq.EnableSsl
}
// User provided TLS certificates (this will take priority over autoCert)
if tenantReq.TLS != nil && tenantReq.TLS.Crt != nil && tenantReq.TLS.Key != nil {
encryption = true
externalTLSCertificateSecretName := fmt.Sprintf("%s-instance-external-certificates", secretName)
// disable autoCert
minInst.Spec.RequestAutoCert = false
tlsCrt, err := base64.StdEncoding.DecodeString(*tenantReq.TLS.Crt)
if err != nil {
return nil, err
}
tlsKey, err := base64.StdEncoding.DecodeString(*tenantReq.TLS.Key)
if err != nil {
return nil, err
}
externalTLSCertificateSecret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: externalTLSCertificateSecretName,
},
Type: corev1.SecretTypeTLS,
Immutable: &imm,
Data: map[string][]byte{
"tls.crt": tlsCrt,
"tls.key": tlsKey,
},
}
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &externalTLSCertificateSecret, metav1.CreateOptions{})
if err != nil {
return nil, err
}
// Certificates used by the minio instance
minInst.Spec.ExternalCertSecret = &operator.LocalCertificateReference{
Name: externalTLSCertificateSecretName,
Type: "kubernetes.io/tls",
}
}
if tenantReq.Encryption != nil && encryption {
// Enable auto encryption
minInst.Spec.Env = append(minInst.Spec.Env, corev1.EnvVar{
Name: "MINIO_KMS_AUTO_ENCRYPTION",
Value: "on",
})
if tenantReq.Encryption.MasterKey != "" {
// Configure MinIO to use MINIO_KMS_MASTER_KEY legacy key
// https://docs.min.io/docs/minio-vault-legacy.html
minInst.Spec.Env = append(minInst.Spec.Env, corev1.EnvVar{
Name: "MINIO_KMS_MASTER_KEY",
Value: tenantReq.Encryption.MasterKey,
})
} else {
// KES configuration for Tenant instance
minInst.Spec.KES = &operator.KESConfig{
Image: "minio/kes:latest",
Replicas: 1,
Metadata: nil,
}
// Using custom image for KES
if tenantReq.Encryption.Image != "" {
minInst.Spec.KES.Image = tenantReq.Encryption.Image
}
// Secret to store KES server TLS certificates
// TODO check if AutoCert it's already configured
serverTLSCrt, err := base64.StdEncoding.DecodeString(*tenantReq.Encryption.Server.Crt)
if err != nil {
return nil, err
}
serverTLSKey, err := base64.StdEncoding.DecodeString(*tenantReq.Encryption.Server.Key)
if err != nil {
return nil, err
}
kesExternalCertificateSecretName := fmt.Sprintf("%s-kes-external-certificates", secretName)
kesExternalCertificateSecret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: kesExternalCertificateSecretName,
},
Type: corev1.SecretTypeTLS,
Immutable: &imm,
Data: map[string][]byte{
"tls.crt": serverTLSCrt,
"tls.key": serverTLSKey,
},
}
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &kesExternalCertificateSecret, metav1.CreateOptions{})
if err != nil {
return nil, err
}
// External certificates used by KES
minInst.Spec.KES.ExternalCertSecret = &operator.LocalCertificateReference{
Name: kesExternalCertificateSecretName,
Type: "kubernetes.io/tls",
}
// Secret to store KES clients TLS certificates (mTLS authentication)
clientTLSCrt, err := base64.StdEncoding.DecodeString(*tenantReq.Encryption.Client.Crt)
if err != nil {
return nil, err
}
clientTLSKey, err := base64.StdEncoding.DecodeString(*tenantReq.Encryption.Client.Key)
if err != nil {
return nil, err
}
instanceExternalClientCertificateSecretName := fmt.Sprintf("%s-instance-external-client-certificates", secretName)
instanceExternalClientCertificateSecret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: instanceExternalClientCertificateSecretName,
},
Type: corev1.SecretTypeTLS,
Immutable: &imm,
Data: map[string][]byte{
"tls.crt": clientTLSCrt,
"tls.key": clientTLSKey,
},
}
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &instanceExternalClientCertificateSecret, metav1.CreateOptions{})
if err != nil {
return nil, err
}
// KES client certificates used by MinIO instance
minInst.Spec.ExternalClientCertSecret = &operator.LocalCertificateReference{
Name: instanceExternalClientCertificateSecretName,
Type: "kubernetes.io/tls",
}
// Calculate the client cert identity based on the clientTLSCrt
h := crypto.SHA256.New()
certificate, err := kes.ParseCertificate(clientTLSCrt)
if err != nil {
return nil, err
}
h.Write(certificate.RawSubjectPublicKeyInfo)
clientCrtIdentity := hex.EncodeToString(h.Sum(nil))
// Default configuration for KES
kesConfig := kes.ServerConfig{
Addr: "0.0.0.0:7373",
Root: "disabled",
TLS: kes.TLS{
KeyPath: "/tmp/kes/server.key",
CertPath: "/tmp/kes/server.crt",
},
Policies: map[string]kes.Policy{
"default-policy": {
Paths: []string{
"/v1/key/create/my-minio-key",
"/v1/key/generate/my-minio-key",
"/v1/key/decrypt/my-minio-key",
},
Identities: []kes2.Identity{
kes2.Identity(clientCrtIdentity),
},
},
},
Cache: kes.Cache{
Expiry: &kes.Expiry{
Any: 5 * time.Minute,
Unused: 20 * time.Second,
},
},
Log: kes.Log{
Error: "on",
Audit: "off",
},
Keys: kes.Keys{},
}
// if encryption is enabled and encryption is configured to use Vault
if tenantReq.Encryption.Vault != nil {
// Initialize Vault Config
kesConfig.Keys.Vault = &kes.Vault{
Endpoint: *tenantReq.Encryption.Vault.Endpoint,
EnginePath: tenantReq.Encryption.Vault.Engine,
Namespace: tenantReq.Encryption.Vault.Namespace,
Prefix: tenantReq.Encryption.Vault.Prefix,
Status: &kes.VaultStatus{
Ping: 10 * time.Second,
},
}
// Vault AppRole credentials
if tenantReq.Encryption.Vault.Approle != nil {
kesConfig.Keys.Vault.AppRole = &kes.AppRole{
EnginePath: tenantReq.Encryption.Vault.Approle.Engine,
ID: *tenantReq.Encryption.Vault.Approle.ID,
Secret: *tenantReq.Encryption.Vault.Approle.Secret,
Retry: 15 * time.Second,
}
} else {
return nil, errors.New("approle credentials missing for kes")
}
} else if tenantReq.Encryption.Aws != nil {
// Initialize AWS
kesConfig.Keys.Aws = &kes.Aws{
SecretsManager: &kes.AwsSecretManager{},
}
// AWS basic configuration
if tenantReq.Encryption.Aws.Secretsmanager != nil {
kesConfig.Keys.Aws.SecretsManager.Endpoint = *tenantReq.Encryption.Aws.Secretsmanager.Endpoint
kesConfig.Keys.Aws.SecretsManager.Region = *tenantReq.Encryption.Aws.Secretsmanager.Region
kesConfig.Keys.Aws.SecretsManager.KmsKey = tenantReq.Encryption.Aws.Secretsmanager.Kmskey
// AWS credentials
if tenantReq.Encryption.Aws.Secretsmanager.Credentials != nil {
kesConfig.Keys.Aws.SecretsManager.Login = &kes.AwsSecretManagerLogin{
AccessKey: *tenantReq.Encryption.Aws.Secretsmanager.Credentials.Accesskey,
SecretKey: *tenantReq.Encryption.Aws.Secretsmanager.Credentials.Secretkey,
SessionToken: tenantReq.Encryption.Aws.Secretsmanager.Credentials.Token,
}
}
}
} else if tenantReq.Encryption.Gemalto != nil {
// Initialize Gemalto
kesConfig.Keys.Gemalto = &kes.Gemalto{
KeySecure: &kes.GemaltoKeySecure{},
}
// Gemalto Configuration
if tenantReq.Encryption.Gemalto.Keysecure != nil {
kesConfig.Keys.Gemalto.KeySecure.Endpoint = *tenantReq.Encryption.Gemalto.Keysecure.Endpoint
// Gemalto TLS configuration
if tenantReq.Encryption.Gemalto.Keysecure.TLS != nil {
kesConfig.Keys.Gemalto.KeySecure.TLS = &kes.GemaltoTLS{
CAPath: *tenantReq.Encryption.Gemalto.Keysecure.TLS.Ca,
}
}
// Gemalto Login
if tenantReq.Encryption.Gemalto.Keysecure.Credentials != nil {
kesConfig.Keys.Gemalto.KeySecure.Credentials = &kes.GemaltoCredentials{
Token: *tenantReq.Encryption.Gemalto.Keysecure.Credentials.Token,
Domain: *tenantReq.Encryption.Gemalto.Keysecure.Credentials.Domain,
Retry: 15 * time.Second,
}
}
}
}
// Generate Yaml configuration for KES
serverConfigYaml, err := yaml.Marshal(kesConfig)
if err != nil {
return nil, err
}
// Secret to store KES server configuration
kesConfigurationSecretName := fmt.Sprintf("%s-kes-configuration", secretName)
kesConfigurationSecret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: kesConfigurationSecretName,
},
Immutable: &imm,
Data: map[string][]byte{
"server-config.yaml": serverConfigYaml,
},
}
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &kesConfigurationSecret, metav1.CreateOptions{})
if err != nil {
return nil, err
}
// Configuration used by KES
minInst.Spec.KES.Configuration = &corev1.LocalObjectReference{
Name: kesConfigurationSecretName,
}
}
}
// optionals are set below
var consoleAccess string
var consoleSecret string
enableConsole := true
if tenantReq.EnableConsole != nil {
enableConsole = *tenantReq.EnableConsole
}
if enableConsole {
consoleSelector := fmt.Sprintf("%s-console", *params.Body.Name)
consoleSelector := fmt.Sprintf("%s-console", *tenantReq.Name)
consoleSecretName := fmt.Sprintf("%s-secret", consoleSelector)
consoleAccess = RandomCharString(16)
consoleSecret = RandomCharString(32)
@@ -412,26 +771,62 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
"CONSOLE_SECRET_KEY": []byte(consoleSecret),
},
}
_, err = clientset.CoreV1().Secrets(ns).Create(context.Background(), &instanceSecret, metav1.CreateOptions{})
// Enable IDP (Open ID Connect) for console
if !idpEnabled && tenantReq.Idp != nil && tenantReq.Idp.Oidc != nil {
url := *tenantReq.Idp.Oidc.URL
clientID := *tenantReq.Idp.Oidc.ClientID
secretID := *tenantReq.Idp.Oidc.SecretID
if url != "" && clientID != "" && secretID != "" {
instanceSecret.Data["CONSOLE_IDP_URL"] = []byte(url)
instanceSecret.Data["CONSOLE_IDP_CLIENT_ID"] = []byte(clientID)
instanceSecret.Data["CONSOLE_IDP_SECRET"] = []byte(secretID)
consoleScheme := "http"
consolePort := 9090
if minInst.Spec.RequestAutoCert {
consoleScheme = "https"
consolePort = 9443
}
// https://[HOSTNAME]:9443 will be replaced by javascript in the browser to use the actual hostname
// assigned to Console, eg: https://localhost:9443
instanceSecret.Data["CONSOLE_IDP_CALLBACK"] = []byte(fmt.Sprintf("%s://[HOSTNAME]:%d/oauth_callback", consoleScheme, consolePort))
}
}
_, err = clientset.CoreV1().Secrets(ns).Create(ctx, &instanceSecret, metav1.CreateOptions{})
if err != nil {
return nil, err
}
const consoleVersion = "minio/console:v0.3.3"
const consoleVersion = "minio/console:v0.3.8"
minInst.Spec.Console = &operator.ConsoleConfiguration{
Replicas: 2,
Image: consoleVersion,
ConsoleSecret: &corev1.LocalObjectReference{Name: consoleSecretName},
Resources: corev1.ResourceRequirements{
Requests: map[corev1.ResourceName]resource.Quantity{
"memory": resource.MustParse("64Mi"),
},
},
}
}
// set the service name if provided
if params.Body.ServiceName != "" {
minInst.Spec.ServiceName = params.Body.ServiceName
if tenantReq.ServiceName != "" {
minInst.Spec.ServiceName = tenantReq.ServiceName
}
// add annotations
var annotations map[string]string
if len(tenantReq.Annotations) > 0 {
if minInst.Spec.Metadata == nil {
minInst.Spec.Metadata = &metav1.ObjectMeta{}
}
annotations = tenantReq.Annotations
minInst.Spec.Metadata.Annotations = annotations
}
// set the zones if they are provided
for _, zone := range params.Body.Zones {
zone, err := parseTenantZoneRequest(zone)
for _, zone := range tenantReq.Zones {
zone, err := parseTenantZoneRequest(zone, annotations)
if err != nil {
return nil, err
}
@@ -439,15 +834,17 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
}
// Set Mount Path if provided
if params.Body.MounthPath != "" {
minInst.Spec.Mountpath = params.Body.MounthPath
if tenantReq.MounthPath != "" {
minInst.Spec.Mountpath = tenantReq.MounthPath
}
// add annotations
if len(params.Body.Annotations) > 0 {
if minInst.Spec.Metadata == nil {
minInst.Spec.Metadata = &metav1.ObjectMeta{}
}
minInst.Spec.Metadata.Annotations = params.Body.Annotations
if err := setImageRegistry(ctx, tenantReq.ImageRegistry, clientset.CoreV1(), ns); err != nil {
log.Println("error setting image registry secret:", err)
return nil, err
}
minInst.Spec.ImagePullSecret = corev1.LocalObjectReference{
Name: minioRegCred,
}
opClient, err := cluster.OperatorClient(session.SessionToken)
@@ -462,7 +859,7 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
// Integratrions
if os.Getenv("GKE_INTEGRATION") != "" {
err := gkeIntegration(clientset, *params.Body.Name, ns, session.SessionToken)
err := gkeIntegration(clientset, *tenantReq.Name, ns, session.SessionToken)
if err != nil {
return nil, err
}
@@ -473,24 +870,84 @@ func getTenantCreatedResponse(session *models.Principal, params admin_api.Create
}
// Attach Console Credentials
if enableConsole {
response.Console = &models.CreateTenantResponseConsole{}
response.Console.AccessKey = consoleAccess
response.Console.SecretKey = consoleSecret
response.Console = &models.CreateTenantResponseConsole{
AccessKey: consoleAccess,
SecretKey: consoleSecret,
}
}
return response, nil
}
func setImageRegistry(ctx context.Context, req *models.ImageRegistry, clientset v1.CoreV1Interface, namespace string) error {
if req == nil || req.Registry == nil || req.Username == nil || req.Password == nil {
return nil
}
credentials := make(map[string]imageRegistryCredentials)
// username:password encoded
authData := []byte(fmt.Sprintf("%s:%s", *req.Username, *req.Password))
authStr := base64.StdEncoding.EncodeToString(authData)
credentials[*req.Registry] = imageRegistryCredentials{
Username: *req.Username,
Password: *req.Password,
Auth: authStr,
}
imRegistry := imageRegistry{
Auths: credentials,
}
imRegistryJSON, err := json.Marshal(imRegistry)
if err != nil {
return err
}
instanceSecret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: minioRegCred,
},
Data: map[string][]byte{
corev1.DockerConfigJsonKey: []byte(string(imRegistryJSON)),
},
Type: corev1.SecretTypeDockerConfigJson,
}
// Get or Create secret if it doesn't exist
_, err = clientset.Secrets(namespace).Get(ctx, minioRegCred, metav1.GetOptions{})
if err != nil {
if k8sErrors.IsNotFound(err) {
_, err = clientset.Secrets(namespace).Create(ctx, &instanceSecret, metav1.CreateOptions{})
if err != nil {
return err
}
return nil
}
return err
}
_, err = clientset.Secrets(namespace).Update(ctx, &instanceSecret, metav1.UpdateOptions{})
if err != nil {
return err
}
return nil
}
// updateTenantAction does an update on the minioTenant by patching the desired changes
func updateTenantAction(ctx context.Context, operatorClient OperatorClient, httpCl cluster.HTTPClientI, nameSpace string, params admin_api.UpdateTenantParams) error {
func updateTenantAction(ctx context.Context, operatorClient OperatorClient, clientset v1.CoreV1Interface, httpCl cluster.HTTPClientI, namespace string, params admin_api.UpdateTenantParams) error {
imageToUpdate := params.Body.Image
minInst, err := operatorClient.TenantGet(ctx, nameSpace, params.Tenant, metav1.GetOptions{})
imageRegistryReq := params.Body.ImageRegistry
if err := setImageRegistry(ctx, imageRegistryReq, clientset, namespace); err != nil {
log.Println("error setting image registry secret:", err)
return err
}
minInst, err := operatorClient.TenantGet(ctx, namespace, params.Tenant, metav1.GetOptions{})
if err != nil {
return err
}
// if image to update is empty we'll use the latest image by default
if strings.TrimSpace(imageToUpdate) != "" {
minInst.Spec.Image = params.Body.Image
minInst.Spec.Image = imageToUpdate
} else {
im, err := cluster.GetLatestMinioImage(httpCl)
if err != nil {
@@ -503,7 +960,7 @@ func updateTenantAction(ctx context.Context, operatorClient OperatorClient, http
if err != nil {
return err
}
_, err = operatorClient.TenantPatch(ctx, nameSpace, minInst.Name, types.MergePatchType, payloadBytes, metav1.PatchOptions{})
_, err = operatorClient.TenantPatch(ctx, namespace, minInst.Name, types.MergePatchType, payloadBytes, metav1.PatchOptions{})
if err != nil {
return err
}
@@ -517,6 +974,11 @@ func getUpdateTenantResponse(session *models.Principal, params admin_api.UpdateT
log.Println("error getting operator client:", err)
return err
}
// get Kubernetes Client
clientset, err := cluster.K8sClient(session.SessionToken)
if err != nil {
return err
}
opClient := &operatorClient{
client: opClientClientSet,
@@ -526,7 +988,8 @@ func getUpdateTenantResponse(session *models.Principal, params admin_api.UpdateT
Timeout: 4 * time.Second,
},
}
if err := updateTenantAction(ctx, opClient, httpC, params.Namespace, params); err != nil {
if err := updateTenantAction(ctx, opClient, clientset.CoreV1(), httpC, params.Namespace, params); err != nil {
log.Println("error patching Tenant:", err)
return err
}
@@ -541,7 +1004,7 @@ func addTenantZone(ctx context.Context, operatorClient OperatorClient, params ad
}
zoneParams := params.Body
zone, err := parseTenantZoneRequest(zoneParams)
zone, err := parseTenantZoneRequest(zoneParams, tenant.ObjectMeta.Annotations)
if err != nil {
return err
}
@@ -583,6 +1046,7 @@ func getTenantUsageResponse(session *models.Principal, params admin_api.GetTenan
opClientClientSet, err := cluster.OperatorClient(session.SessionToken)
if err != nil {
log.Println("error operator client", err)
return nil, err
}
clientset, err := cluster.K8sClient(session.SessionToken)
@@ -633,13 +1097,13 @@ func getTenantUsageResponse(session *models.Principal, params admin_api.GetTenan
log.Println("error getting admin info:", err)
return nil, err
}
info := &models.TenantUsage{UsedSize: adminInfo.Usage}
info := &models.TenantUsage{Used: adminInfo.Usage, DiskUsed: adminInfo.DisksUsage}
return info, nil
}
// parseTenantZoneRequest parse zone request and returns the equivalent
// operator.Zone object
func parseTenantZoneRequest(zoneParams *models.Zone) (*operator.Zone, error) {
func parseTenantZoneRequest(zoneParams *models.Zone, annotations map[string]string) (*operator.Zone, error) {
if zoneParams.VolumeConfiguration == nil {
return nil, errors.New("a volume configuration must be specified")
}
@@ -672,8 +1136,8 @@ func parseTenantZoneRequest(zoneParams *models.Zone) (*operator.Zone, error) {
}
// parse resources' requests
var resourcesRequests corev1.ResourceList
var resourcesLimits corev1.ResourceList
resourcesRequests := make(corev1.ResourceList)
resourcesLimits := make(corev1.ResourceList)
if zoneParams.Resources != nil {
for key, val := range zoneParams.Resources.Requests {
resourcesRequests[corev1.ResourceName(key)] = *resource.NewQuantity(val, resource.BinarySI)
@@ -779,16 +1243,22 @@ func parseTenantZoneRequest(zoneParams *models.Zone) (*operator.Zone, error) {
tolerations = append(tolerations, toleration)
}
zone := &operator.Zone{
Name: zoneParams.Name,
Servers: int32(*zoneParams.Servers),
VolumesPerServer: *zoneParams.VolumesPerServer,
VolumeClaimTemplate: &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "data",
},
Spec: volTemp,
// Pass annotations to the volume
vct := &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "data",
},
Spec: volTemp,
}
if len(annotations) > 0 {
vct.ObjectMeta.Annotations = annotations
}
zone := &operator.Zone{
Name: zoneParams.Name,
Servers: int32(*zoneParams.Servers),
VolumesPerServer: *zoneParams.VolumesPerServer,
VolumeClaimTemplate: vct,
Resources: corev1.ResourceRequirements{
Requests: resourcesRequests,
Limits: resourcesLimits,

View File

@@ -35,7 +35,9 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
types "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/fake"
)
var opClientTenantDeleteMock func(ctx context.Context, namespace string, tenantName string, options metav1.DeleteOptions) error
@@ -573,6 +575,7 @@ func Test_UpdateTenantAction(t *testing.T) {
tests := []struct {
name string
args args
objs []runtime.Object
wantErr bool
}{
{
@@ -708,8 +711,9 @@ func Test_UpdateTenantAction(t *testing.T) {
opClientTenantGetMock = tt.args.mockTenantGet
opClientTenantPatchMock = tt.args.mockTenantPatch
httpClientGetMock = tt.args.mockHTTPClientGet
cnsClient := fake.NewSimpleClientset(tt.objs...)
t.Run(tt.name, func(t *testing.T) {
if err := updateTenantAction(tt.args.ctx, tt.args.operatorClient, tt.args.httpCl, tt.args.nameSpace, tt.args.params); (err != nil) != tt.wantErr {
if err := updateTenantAction(tt.args.ctx, tt.args.operatorClient, cnsClient.CoreV1(), tt.args.httpCl, tt.args.nameSpace, tt.args.params); (err != nil) != tt.wantErr {
t.Errorf("deleteTenantAction() error = %v, wantErr %v", err, tt.wantErr)
}
})

View File

@@ -67,13 +67,13 @@ func TestListUsers(t *testing.T) {
// Test-1 : listUsers() Get response from minio client with two users and return the same number on listUsers()
// mock minIO client
mockUserMap := map[string]madmin.UserInfo{
"ABCDEFGHI": madmin.UserInfo{
"ABCDEFGHI": {
SecretKey: "",
PolicyName: "ABCDEFGHI-policy",
Status: "enabled",
MemberOf: []string{"group1", "group2"},
},
"ZBCDEFGHI": madmin.UserInfo{
"ZBCDEFGHI": {
SecretKey: "",
PolicyName: "ZBCDEFGHI-policy",
Status: "enabled",

View File

@@ -33,8 +33,13 @@ import (
const globalAppName = "console"
// NewAdminClient gives a new client interface
// NewAdminClient gives a new madmin client interface
func NewAdminClient(url, accessKey, secretKey string) (*madmin.AdminClient, *probe.Error) {
return NewAdminClientWithInsecure(url, accessKey, secretKey, false)
}
// NewAdminClientWithInsecure gives a new madmin client interface either secure or insecure based on parameter
func NewAdminClientWithInsecure(url, accessKey, secretKey string, insecure bool) (*madmin.AdminClient, *probe.Error) {
appName := filepath.Base(globalAppName)
s3Client, err := s3AdminNew(&mcCmd.Config{
@@ -44,7 +49,7 @@ func NewAdminClient(url, accessKey, secretKey string) (*madmin.AdminClient, *pro
AppName: appName,
AppVersion: ConsoleVersion,
AppComments: []string{appName, runtime.GOOS, runtime.GOARCH},
Insecure: false,
Insecure: insecure,
})
if err != nil {
return nil, err.Trace(url)

View File

@@ -26,8 +26,8 @@ import (
"github.com/minio/console/models"
"github.com/minio/console/pkg/acl"
"github.com/minio/console/pkg/auth"
xjwt "github.com/minio/console/pkg/auth/jwt"
"github.com/minio/console/pkg/auth/ldap"
xjwt "github.com/minio/console/pkg/auth/token"
mc "github.com/minio/mc/cmd"
"github.com/minio/mc/pkg/probe"
"github.com/minio/minio-go/v7"
@@ -125,7 +125,7 @@ func (c mcClient) watch(ctx context.Context, options mc.WatchOptions) (*mc.Watch
}
// ConsoleCredentials interface with all functions to be implemented
// by mock when testing, it should include all needed consoleCredentials.Credentials api calls
// by mock when testing, it should include all needed consoleCredentials.Login api calls
// that are used within this project.
type ConsoleCredentials interface {
Get() (credentials.Value, error)
@@ -137,12 +137,12 @@ type consoleCredentials struct {
consoleCredentials *credentials.Credentials
}
// implements *Credentials.Get()
// implements *Login.Get()
func (c consoleCredentials) Get() (credentials.Value, error) {
return c.consoleCredentials.Get()
}
// implements *Credentials.Expire()
// implements *Login.Expire()
func (c consoleCredentials) Expire() {
c.consoleCredentials.Expire()
}
@@ -217,14 +217,14 @@ func newConsoleCredentials(accessKey, secretKey, location string) (*credentials.
// GetClaimsFromJWT decrypt and returns the claims associated to a provided jwt
func GetClaimsFromJWT(jwt string) (*auth.DecryptedClaims, error) {
claims, err := auth.JWTAuthenticate(jwt)
claims, err := auth.SessionTokenAuthenticate(jwt)
if err != nil {
return nil, err
}
return claims, nil
}
// getConsoleCredentialsFromSession returns the *consoleCredentials.Credentials associated to the
// getConsoleCredentialsFromSession returns the *consoleCredentials.Login associated to the
// provided jwt, this is useful for running the Expire() or IsExpired() operations
func getConsoleCredentialsFromSession(claims *models.Principal) *credentials.Credentials {
return credentials.NewStaticV4(claims.AccessKeyID, claims.SecretAccessKey, claims.SessionToken)

View File

@@ -63,7 +63,7 @@ func configureAPI(api *operations.ConsoleAPI) http.Handler {
api.KeyAuth = func(token string, scopes []string) (*models.Principal, error) {
// we are validating the jwt by decrypting the claims inside, if the operation succed that means the jwt
// was generated and signed by us in the first place
claims, err := auth.JWTAuthenticate(token)
claims, err := auth.SessionTokenAuthenticate(token)
if err != nil {
log.Println(err)
return nil, errors.New(401, "incorrect api key auth")

File diff suppressed because it is too large Load Diff

View File

@@ -66,12 +66,12 @@ func Test_ResourceQuota(t *testing.T) {
want: models.ResourceQuota{
Name: mockRQResponse.Name,
Elements: []*models.ResourceQuotaElement{
&models.ResourceQuotaElement{
{
Name: "storage",
Hard: int64(1000),
Used: int64(500),
},
&models.ResourceQuotaElement{
{
Name: "cpu",
Hard: int64(2048),
Used: int64(1024),

View File

@@ -148,7 +148,7 @@ func TestListBucketEvents(t *testing.T) {
LambdaConfigs: []notification.LambdaConfig{},
TopicConfigs: []notification.TopicConfig{},
QueueConfigs: []notification.QueueConfig{
notification.QueueConfig{
{
Queue: "arn:minio:sqs::test:postgresql",
Config: notification.Config{
ID: "",
@@ -160,11 +160,11 @@ func TestListBucketEvents(t *testing.T) {
Filter: &notification.Filter{
S3Key: notification.S3Key{
FilterRules: []notification.FilterRule{
notification.FilterRule{
{
Name: "suffix",
Value: ".jpg",
},
notification.FilterRule{
{
Name: "prefix",
Value: "file/",
},
@@ -176,7 +176,7 @@ func TestListBucketEvents(t *testing.T) {
},
}
expectedOutput := []*models.NotificationConfig{
&models.NotificationConfig{
{
Arn: swag.String("arn:minio:sqs::test:postgresql"),
ID: "",
Prefix: "file/",
@@ -213,7 +213,7 @@ func TestListBucketEvents(t *testing.T) {
LambdaConfigs: []notification.LambdaConfig{},
TopicConfigs: []notification.TopicConfig{},
QueueConfigs: []notification.QueueConfig{
notification.QueueConfig{
{
Queue: "arn:minio:sqs::test:postgresql",
Config: notification.Config{
ID: "",
@@ -225,7 +225,7 @@ func TestListBucketEvents(t *testing.T) {
},
}
expectedOutput = []*models.NotificationConfig{
&models.NotificationConfig{
{
Arn: swag.String("arn:minio:sqs::test:postgresql"),
ID: "",
Prefix: "",
@@ -258,7 +258,7 @@ func TestListBucketEvents(t *testing.T) {
////// Test-3 : listBucketEvents() get list of events
mockBucketN = notification.Configuration{
LambdaConfigs: []notification.LambdaConfig{
notification.LambdaConfig{
{
Lambda: "lambda",
Config: notification.Config{
ID: "",
@@ -268,11 +268,11 @@ func TestListBucketEvents(t *testing.T) {
Filter: &notification.Filter{
S3Key: notification.S3Key{
FilterRules: []notification.FilterRule{
notification.FilterRule{
{
Name: "suffix",
Value: ".png",
},
notification.FilterRule{
{
Name: "prefix",
Value: "lambda/",
},
@@ -283,7 +283,7 @@ func TestListBucketEvents(t *testing.T) {
},
},
TopicConfigs: []notification.TopicConfig{
notification.TopicConfig{
{
Topic: "topic",
Config: notification.Config{
ID: "",
@@ -293,11 +293,11 @@ func TestListBucketEvents(t *testing.T) {
Filter: &notification.Filter{
S3Key: notification.S3Key{
FilterRules: []notification.FilterRule{
notification.FilterRule{
{
Name: "suffix",
Value: ".gif",
},
notification.FilterRule{
{
Name: "prefix",
Value: "topic/",
},
@@ -308,7 +308,7 @@ func TestListBucketEvents(t *testing.T) {
},
},
QueueConfigs: []notification.QueueConfig{
notification.QueueConfig{
{
Queue: "arn:minio:sqs::test:postgresql",
Config: notification.Config{
ID: "",
@@ -326,7 +326,7 @@ func TestListBucketEvents(t *testing.T) {
}
// order matters in output: topic,queue then lambda are given respectively
expectedOutput = []*models.NotificationConfig{
&models.NotificationConfig{
{
Arn: swag.String("topic"),
ID: "",
Prefix: "topic/",
@@ -335,7 +335,7 @@ func TestListBucketEvents(t *testing.T) {
models.NotificationEventTypeDelete,
},
},
&models.NotificationConfig{
{
Arn: swag.String("arn:minio:sqs::test:postgresql"),
ID: "",
Prefix: "",
@@ -344,7 +344,7 @@ func TestListBucketEvents(t *testing.T) {
models.NotificationEventTypeDelete,
},
},
&models.NotificationConfig{
{
Arn: swag.String("lambda"),
ID: "",
Prefix: "lambda/",

View File

@@ -82,8 +82,8 @@ func TestListBucket(t *testing.T) {
mockBucketList := madmin.AccountUsageInfo{
AccountName: "test",
Buckets: []madmin.BucketUsageInfo{
madmin.BucketUsageInfo{Name: "bucket-1", Created: time.Now(), Size: 1024},
madmin.BucketUsageInfo{Name: "bucket-2", Created: time.Now().Add(time.Hour * 1), Size: 0},
{Name: "bucket-1", Created: time.Now(), Size: 1024},
{Name: "bucket-2", Created: time.Now().Add(time.Hour * 1), Size: 0},
},
}
// mock function response from listBucketsWithContext(ctx)

View File

@@ -34,7 +34,7 @@ import (
var (
errorGeneric = errors.New("an error occurred, please try again")
errInvalidCredentials = errors.New("invalid Credentials")
errInvalidCredentials = errors.New("invalid Login")
)
func registerLoginHandlers(api *operations.ConsoleAPI) {
@@ -80,7 +80,7 @@ func login(credentials ConsoleCredentials, actions []string) (*string, error) {
return nil, errInvalidCredentials
}
// if we made it here, the consoleCredentials work, generate a jwt with claims
jwt, err := auth.NewJWTWithClaimsForClient(&tokens, actions, getMinIOServer())
jwt, err := auth.NewEncryptedTokenForClient(&tokens, actions)
if err != nil {
log.Println("error authenticating user", err)
return nil, errInvalidCredentials

View File

@@ -71,7 +71,7 @@ func TestWatch(t *testing.T) {
// mocking sending 5 lines of info
for range lines {
info := []mc.EventInfo{
mc.EventInfo{
{
UserAgent: textToReceive,
},
}
@@ -134,7 +134,7 @@ func TestWatch(t *testing.T) {
// mocking sending 5 lines of info
for range lines {
info := []mc.EventInfo{
mc.EventInfo{
{
UserAgent: textToReceive,
},
}
@@ -177,7 +177,7 @@ func TestWatch(t *testing.T) {
// mocking sending 5 lines of info
for range lines {
info := []mc.EventInfo{
mc.EventInfo{
{
UserAgent: textToReceive,
},
}

View File

@@ -1733,7 +1733,10 @@ definitions:
tenantUsage:
type: object
properties:
used_size:
used:
type: integer
format: int64
disk_used:
type: integer
format: int64
@@ -1768,12 +1771,30 @@ definitions:
type: integer
format: int64
title: number of tenants accessible to tenant user
updateTenantRequest:
type: object
properties:
image:
type: string
pattern: "^((.*?)/(.*?):(.+))$"
image_registry:
$ref: "#/definitions/imageRegistry"
imageRegistry:
type: object
required:
- registry
- username
- password
properties:
registry:
type: string
username:
type: string
password:
type: string
createTenantRequest:
type: object
required:
@@ -1806,10 +1827,213 @@ definitions:
default: true
namespace:
type: string
erasureCodingParity:
type: integer
annotations:
type: object
additionalProperties:
type: string
image_registry:
$ref: "#/definitions/imageRegistry"
idp:
type: object
$ref: "#/definitions/idpConfiguration"
tls:
type: object
$ref: "#/definitions/tlsConfiguration"
encryption:
type: object
$ref: "#/definitions/encryptionConfiguration"
tlsConfiguration:
type: object
required:
- crt
- key
properties:
crt:
type: string
key:
type: string
idpConfiguration:
type: object
properties:
oidc:
type: object
required:
- url
- client_id
- secret_id
properties:
url:
type: string
client_id:
type: string
secret_id:
type: string
active_directory:
type: object
required:
- url
- username_format
- user_search_filter
properties:
url:
type: string
username_format:
type: string
user_search_filter:
type: string
group_search_base_dn:
type: string
group_search_filter:
type: string
group_name_attribute:
type: string
skip_ssl_verification:
type: boolean
server_insecure:
type: boolean
encryptionConfiguration:
type: object
properties:
image:
type: string
server:
type: object
required:
- crt
- key
properties:
crt:
type: string
key:
type: string
client:
type: object
required:
- crt
- key
properties:
crt:
type: string
key:
type: string
master_key:
type: string
gemalto:
type: object
$ref: "#/definitions/gemaltoConfiguration"
aws:
type: object
$ref: "#/definitions/awsConfiguration"
vault:
type: object
$ref: "#/definitions/vaultConfiguration"
vaultConfiguration:
type: object
required:
- endpoint
- approle
properties:
endpoint:
type: string
engine:
type: string
namespace:
type: string
prefix:
type: string
approle:
type: object
required:
- id
- secret
properties:
engine:
type: string
id:
type: string
secret:
type: string
retry:
type: integer
format: int64
status:
type: object
properties:
ping:
type: integer
format: int64
awsConfiguration:
type: object
required:
- secretsmanager
properties:
secretsmanager:
type: object
required:
- endpoint
- region
- credentials
properties:
endpoint:
type: string
region:
type: string
kmskey:
type: string
credentials:
type: object
required:
- accesskey
- secretkey
properties:
accesskey:
type: string
secretkey:
type: string
token:
type: string
gemaltoConfiguration:
type: object
required:
- keysecure
properties:
keysecure:
type: object
required:
- endpoint
- credentials
properties:
endpoint:
type: string
credentials:
type: object
required:
- token
- domain
properties:
token:
type: string
domain:
type: string
retry:
type: integer
format: int64
tls:
type: object
required:
- ca
properties:
ca:
type: string
createTenantResponse:
type: object
properties: