Update encryption configuration screen for tenant (#1611)

This commit is contained in:
Lenin Alevski
2022-03-01 01:56:38 -06:00
committed by GitHub
parent 208afdfc3a
commit 4fa2f16e9a
30 changed files with 6216 additions and 225 deletions

View File

@@ -634,6 +634,41 @@ func init() {
}
},
"/namespaces/{namespace}/tenants/{tenant}/encryption": {
"get": {
"tags": [
"OperatorAPI"
],
"summary": "Tenant Encryption Info",
"operationId": "TenantEncryptionInfo",
"parameters": [
{
"type": "string",
"name": "namespace",
"in": "path",
"required": true
},
{
"type": "string",
"name": "tenant",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/encryptionConfigurationResponse"
}
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/error"
}
}
}
},
"put": {
"tags": [
"OperatorAPI"
@@ -673,6 +708,38 @@ func init() {
}
}
}
},
"delete": {
"tags": [
"OperatorAPI"
],
"summary": "Tenant Delete Encryption",
"operationId": "TenantDeleteEncryption",
"parameters": [
{
"type": "string",
"name": "namespace",
"in": "path",
"required": true
},
{
"type": "string",
"name": "tenant",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"description": "A successful response."
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/error"
}
}
}
}
},
"/namespaces/{namespace}/tenants/{tenant}/events": {
@@ -2013,6 +2080,12 @@ func init() {
"replicas": {
"type": "string"
},
"secretsToBeDeleted": {
"type": "array",
"items": {
"type": "string"
}
},
"securityContext": {
"type": "object",
"$ref": "#/definitions/securityContext"
@@ -2029,6 +2102,56 @@ func init() {
}
]
},
"encryptionConfigurationResponse": {
"allOf": [
{
"$ref": "#/definitions/metadataFields"
},
{
"type": "object",
"properties": {
"aws": {
"type": "object",
"$ref": "#/definitions/awsConfiguration"
},
"azure": {
"type": "object",
"$ref": "#/definitions/azureConfiguration"
},
"gcp": {
"type": "object",
"$ref": "#/definitions/gcpConfiguration"
},
"gemalto": {
"type": "object",
"$ref": "#/definitions/gemaltoConfigurationResponse"
},
"image": {
"type": "string"
},
"mtls_client": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
},
"replicas": {
"type": "string"
},
"securityContext": {
"type": "object",
"$ref": "#/definitions/securityContext"
},
"server": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
},
"vault": {
"type": "object",
"$ref": "#/definitions/vaultConfigurationResponse"
}
}
}
]
},
"error": {
"type": "object",
"required": [
@@ -2197,6 +2320,57 @@ func init() {
}
}
},
"gemaltoConfigurationResponse": {
"type": "object",
"required": [
"keysecure"
],
"properties": {
"keysecure": {
"type": "object",
"required": [
"endpoint",
"credentials"
],
"properties": {
"credentials": {
"type": "object",
"required": [
"token",
"domain"
],
"properties": {
"domain": {
"type": "string"
},
"retry": {
"type": "integer",
"format": "int64"
},
"token": {
"type": "string"
}
}
},
"endpoint": {
"type": "string"
},
"tls": {
"type": "object",
"required": [
"ca"
],
"properties": {
"ca": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
}
}
}
}
}
}
},
"getDirectCSIDriveListResponse": {
"type": "object",
"properties": {
@@ -3648,6 +3822,71 @@ func init() {
}
}
}
},
"vaultConfigurationResponse": {
"type": "object",
"required": [
"endpoint",
"approle"
],
"properties": {
"approle": {
"type": "object",
"required": [
"id",
"secret"
],
"properties": {
"engine": {
"type": "string"
},
"id": {
"type": "string"
},
"retry": {
"type": "integer",
"format": "int64"
},
"secret": {
"type": "string"
}
}
},
"endpoint": {
"type": "string"
},
"engine": {
"type": "string"
},
"namespace": {
"type": "string"
},
"prefix": {
"type": "string"
},
"status": {
"type": "object",
"properties": {
"ping": {
"type": "integer",
"format": "int64"
}
}
},
"tls": {
"type": "object",
"properties": {
"ca": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
},
"crt": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
}
}
}
}
}
},
"securityDefinitions": {
@@ -4264,6 +4503,41 @@ func init() {
}
},
"/namespaces/{namespace}/tenants/{tenant}/encryption": {
"get": {
"tags": [
"OperatorAPI"
],
"summary": "Tenant Encryption Info",
"operationId": "TenantEncryptionInfo",
"parameters": [
{
"type": "string",
"name": "namespace",
"in": "path",
"required": true
},
{
"type": "string",
"name": "tenant",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/encryptionConfigurationResponse"
}
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/error"
}
}
}
},
"put": {
"tags": [
"OperatorAPI"
@@ -4303,6 +4577,38 @@ func init() {
}
}
}
},
"delete": {
"tags": [
"OperatorAPI"
],
"summary": "Tenant Delete Encryption",
"operationId": "TenantDeleteEncryption",
"parameters": [
{
"type": "string",
"name": "namespace",
"in": "path",
"required": true
},
{
"type": "string",
"name": "tenant",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"description": "A successful response."
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/error"
}
}
}
}
},
"/namespaces/{namespace}/tenants/{tenant}/events": {
@@ -5517,6 +5823,80 @@ func init() {
}
}
},
"GemaltoConfigurationResponseKeysecure": {
"type": "object",
"required": [
"endpoint",
"credentials"
],
"properties": {
"credentials": {
"type": "object",
"required": [
"token",
"domain"
],
"properties": {
"domain": {
"type": "string"
},
"retry": {
"type": "integer",
"format": "int64"
},
"token": {
"type": "string"
}
}
},
"endpoint": {
"type": "string"
},
"tls": {
"type": "object",
"required": [
"ca"
],
"properties": {
"ca": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
}
}
}
}
},
"GemaltoConfigurationResponseKeysecureCredentials": {
"type": "object",
"required": [
"token",
"domain"
],
"properties": {
"domain": {
"type": "string"
},
"retry": {
"type": "integer",
"format": "int64"
},
"token": {
"type": "string"
}
}
},
"GemaltoConfigurationResponseKeysecureTLS": {
"type": "object",
"required": [
"ca"
],
"properties": {
"ca": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
}
}
},
"IdpConfigurationActiveDirectory": {
"type": "object",
"required": [
@@ -6003,6 +6383,50 @@ func init() {
}
}
},
"VaultConfigurationResponseApprole": {
"type": "object",
"required": [
"id",
"secret"
],
"properties": {
"engine": {
"type": "string"
},
"id": {
"type": "string"
},
"retry": {
"type": "integer",
"format": "int64"
},
"secret": {
"type": "string"
}
}
},
"VaultConfigurationResponseStatus": {
"type": "object",
"properties": {
"ping": {
"type": "integer",
"format": "int64"
}
}
},
"VaultConfigurationResponseTLS": {
"type": "object",
"properties": {
"ca": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
},
"crt": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
}
}
},
"VaultConfigurationStatus": {
"type": "object",
"properties": {
@@ -6376,6 +6800,12 @@ func init() {
"replicas": {
"type": "string"
},
"secretsToBeDeleted": {
"type": "array",
"items": {
"type": "string"
}
},
"securityContext": {
"type": "object",
"$ref": "#/definitions/securityContext"
@@ -6392,6 +6822,56 @@ func init() {
}
]
},
"encryptionConfigurationResponse": {
"allOf": [
{
"$ref": "#/definitions/metadataFields"
},
{
"type": "object",
"properties": {
"aws": {
"type": "object",
"$ref": "#/definitions/awsConfiguration"
},
"azure": {
"type": "object",
"$ref": "#/definitions/azureConfiguration"
},
"gcp": {
"type": "object",
"$ref": "#/definitions/gcpConfiguration"
},
"gemalto": {
"type": "object",
"$ref": "#/definitions/gemaltoConfigurationResponse"
},
"image": {
"type": "string"
},
"mtls_client": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
},
"replicas": {
"type": "string"
},
"securityContext": {
"type": "object",
"$ref": "#/definitions/securityContext"
},
"server": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
},
"vault": {
"type": "object",
"$ref": "#/definitions/vaultConfigurationResponse"
}
}
}
]
},
"error": {
"type": "object",
"required": [
@@ -6560,6 +7040,57 @@ func init() {
}
}
},
"gemaltoConfigurationResponse": {
"type": "object",
"required": [
"keysecure"
],
"properties": {
"keysecure": {
"type": "object",
"required": [
"endpoint",
"credentials"
],
"properties": {
"credentials": {
"type": "object",
"required": [
"token",
"domain"
],
"properties": {
"domain": {
"type": "string"
},
"retry": {
"type": "integer",
"format": "int64"
},
"token": {
"type": "string"
}
}
},
"endpoint": {
"type": "string"
},
"tls": {
"type": "object",
"required": [
"ca"
],
"properties": {
"ca": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
}
}
}
}
}
}
},
"getDirectCSIDriveListResponse": {
"type": "object",
"properties": {
@@ -7864,6 +8395,71 @@ func init() {
}
}
}
},
"vaultConfigurationResponse": {
"type": "object",
"required": [
"endpoint",
"approle"
],
"properties": {
"approle": {
"type": "object",
"required": [
"id",
"secret"
],
"properties": {
"engine": {
"type": "string"
},
"id": {
"type": "string"
},
"retry": {
"type": "integer",
"format": "int64"
},
"secret": {
"type": "string"
}
}
},
"endpoint": {
"type": "string"
},
"engine": {
"type": "string"
},
"namespace": {
"type": "string"
},
"prefix": {
"type": "string"
},
"status": {
"type": "object",
"properties": {
"ping": {
"type": "integer",
"format": "int64"
}
}
},
"tls": {
"type": "object",
"properties": {
"ca": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
},
"crt": {
"type": "object",
"$ref": "#/definitions/certificateInfo"
}
}
}
}
}
},
"securityDefinitions": {

View File

@@ -42,6 +42,8 @@ var (
errorUnableToGetTenantLogs = errors.New("unable to get tenant logs")
errorUnableToUpdateTenantCertificates = errors.New("unable to update tenant certificates")
errorUpdatingEncryptionConfig = errors.New("unable to update encryption configuration")
errorDeletingEncryptionConfig = errors.New("error disabling tenant encryption")
errorEncryptionConfigNotFound = errors.New("encryption configuration not found")
errBucketBodyNotInRequest = errors.New("error bucket body not in request")
errBucketNameNotInRequest = errors.New("error bucket name not in request")
errGroupBodyNotInRequest = errors.New("error group body not in request")

View File

@@ -177,9 +177,15 @@ func NewOperatorAPI(spec *loads.Document) *OperatorAPI {
OperatorAPITenantAddPoolHandler: operator_api.TenantAddPoolHandlerFunc(func(params operator_api.TenantAddPoolParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation operator_api.TenantAddPool has not yet been implemented")
}),
OperatorAPITenantDeleteEncryptionHandler: operator_api.TenantDeleteEncryptionHandlerFunc(func(params operator_api.TenantDeleteEncryptionParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation operator_api.TenantDeleteEncryption has not yet been implemented")
}),
OperatorAPITenantDetailsHandler: operator_api.TenantDetailsHandlerFunc(func(params operator_api.TenantDetailsParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation operator_api.TenantDetails has not yet been implemented")
}),
OperatorAPITenantEncryptionInfoHandler: operator_api.TenantEncryptionInfoHandlerFunc(func(params operator_api.TenantEncryptionInfoParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation operator_api.TenantEncryptionInfo has not yet been implemented")
}),
OperatorAPITenantSecurityHandler: operator_api.TenantSecurityHandlerFunc(func(params operator_api.TenantSecurityParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation operator_api.TenantSecurity has not yet been implemented")
}),
@@ -323,8 +329,12 @@ type OperatorAPI struct {
OperatorAPISubscriptionValidateHandler operator_api.SubscriptionValidateHandler
// OperatorAPITenantAddPoolHandler sets the operation handler for the tenant add pool operation
OperatorAPITenantAddPoolHandler operator_api.TenantAddPoolHandler
// OperatorAPITenantDeleteEncryptionHandler sets the operation handler for the tenant delete encryption operation
OperatorAPITenantDeleteEncryptionHandler operator_api.TenantDeleteEncryptionHandler
// OperatorAPITenantDetailsHandler sets the operation handler for the tenant details operation
OperatorAPITenantDetailsHandler operator_api.TenantDetailsHandler
// OperatorAPITenantEncryptionInfoHandler sets the operation handler for the tenant encryption info operation
OperatorAPITenantEncryptionInfoHandler operator_api.TenantEncryptionInfoHandler
// OperatorAPITenantSecurityHandler sets the operation handler for the tenant security operation
OperatorAPITenantSecurityHandler operator_api.TenantSecurityHandler
// OperatorAPITenantUpdateCertificateHandler sets the operation handler for the tenant update certificate operation
@@ -532,9 +542,15 @@ func (o *OperatorAPI) Validate() error {
if o.OperatorAPITenantAddPoolHandler == nil {
unregistered = append(unregistered, "operator_api.TenantAddPoolHandler")
}
if o.OperatorAPITenantDeleteEncryptionHandler == nil {
unregistered = append(unregistered, "operator_api.TenantDeleteEncryptionHandler")
}
if o.OperatorAPITenantDetailsHandler == nil {
unregistered = append(unregistered, "operator_api.TenantDetailsHandler")
}
if o.OperatorAPITenantEncryptionInfoHandler == nil {
unregistered = append(unregistered, "operator_api.TenantEncryptionInfoHandler")
}
if o.OperatorAPITenantSecurityHandler == nil {
unregistered = append(unregistered, "operator_api.TenantSecurityHandler")
}
@@ -803,6 +819,10 @@ func (o *OperatorAPI) initHandlerCache() {
o.handlers["POST"] = make(map[string]http.Handler)
}
o.handlers["POST"]["/namespaces/{namespace}/tenants/{tenant}/pools"] = operator_api.NewTenantAddPool(o.context, o.OperatorAPITenantAddPoolHandler)
if o.handlers["DELETE"] == nil {
o.handlers["DELETE"] = make(map[string]http.Handler)
}
o.handlers["DELETE"]["/namespaces/{namespace}/tenants/{tenant}/encryption"] = operator_api.NewTenantDeleteEncryption(o.context, o.OperatorAPITenantDeleteEncryptionHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
@@ -810,6 +830,10 @@ func (o *OperatorAPI) initHandlerCache() {
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/namespaces/{namespace}/tenants/{tenant}/encryption"] = operator_api.NewTenantEncryptionInfo(o.context, o.OperatorAPITenantEncryptionInfoHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/namespaces/{namespace}/tenants/{tenant}/security"] = operator_api.NewTenantSecurity(o.context, o.OperatorAPITenantSecurityHandler)
if o.handlers["PUT"] == nil {
o.handlers["PUT"] = make(map[string]http.Handler)

View File

@@ -0,0 +1,88 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 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 operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// TenantDeleteEncryptionHandlerFunc turns a function with the right signature into a tenant delete encryption handler
type TenantDeleteEncryptionHandlerFunc func(TenantDeleteEncryptionParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn TenantDeleteEncryptionHandlerFunc) Handle(params TenantDeleteEncryptionParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// TenantDeleteEncryptionHandler interface for that can handle valid tenant delete encryption params
type TenantDeleteEncryptionHandler interface {
Handle(TenantDeleteEncryptionParams, *models.Principal) middleware.Responder
}
// NewTenantDeleteEncryption creates a new http.Handler for the tenant delete encryption operation
func NewTenantDeleteEncryption(ctx *middleware.Context, handler TenantDeleteEncryptionHandler) *TenantDeleteEncryption {
return &TenantDeleteEncryption{Context: ctx, Handler: handler}
}
/* TenantDeleteEncryption swagger:route DELETE /namespaces/{namespace}/tenants/{tenant}/encryption OperatorAPI tenantDeleteEncryption
Tenant Delete Encryption
*/
type TenantDeleteEncryption struct {
Context *middleware.Context
Handler TenantDeleteEncryptionHandler
}
func (o *TenantDeleteEncryption) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewTenantDeleteEncryptionParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -0,0 +1,112 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 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 operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt"
)
// NewTenantDeleteEncryptionParams creates a new TenantDeleteEncryptionParams object
//
// There are no default values defined in the spec.
func NewTenantDeleteEncryptionParams() TenantDeleteEncryptionParams {
return TenantDeleteEncryptionParams{}
}
// TenantDeleteEncryptionParams contains all the bound params for the tenant delete encryption operation
// typically these are obtained from a http.Request
//
// swagger:parameters TenantDeleteEncryption
type TenantDeleteEncryptionParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
Required: true
In: path
*/
Namespace string
/*
Required: true
In: path
*/
Tenant string
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewTenantDeleteEncryptionParams() beforehand.
func (o *TenantDeleteEncryptionParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
rNamespace, rhkNamespace, _ := route.Params.GetOK("namespace")
if err := o.bindNamespace(rNamespace, rhkNamespace, route.Formats); err != nil {
res = append(res, err)
}
rTenant, rhkTenant, _ := route.Params.GetOK("tenant")
if err := o.bindTenant(rTenant, rhkTenant, route.Formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// bindNamespace binds and validates parameter Namespace from path.
func (o *TenantDeleteEncryptionParams) bindNamespace(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Namespace = raw
return nil
}
// bindTenant binds and validates parameter Tenant from path.
func (o *TenantDeleteEncryptionParams) bindTenant(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Tenant = raw
return nil
}

View File

@@ -0,0 +1,113 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 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 operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// TenantDeleteEncryptionNoContentCode is the HTTP code returned for type TenantDeleteEncryptionNoContent
const TenantDeleteEncryptionNoContentCode int = 204
/*TenantDeleteEncryptionNoContent A successful response.
swagger:response tenantDeleteEncryptionNoContent
*/
type TenantDeleteEncryptionNoContent struct {
}
// NewTenantDeleteEncryptionNoContent creates TenantDeleteEncryptionNoContent with default headers values
func NewTenantDeleteEncryptionNoContent() *TenantDeleteEncryptionNoContent {
return &TenantDeleteEncryptionNoContent{}
}
// WriteResponse to the client
func (o *TenantDeleteEncryptionNoContent) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses
rw.WriteHeader(204)
}
/*TenantDeleteEncryptionDefault Generic error response.
swagger:response tenantDeleteEncryptionDefault
*/
type TenantDeleteEncryptionDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
}
// NewTenantDeleteEncryptionDefault creates TenantDeleteEncryptionDefault with default headers values
func NewTenantDeleteEncryptionDefault(code int) *TenantDeleteEncryptionDefault {
if code <= 0 {
code = 500
}
return &TenantDeleteEncryptionDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the tenant delete encryption default response
func (o *TenantDeleteEncryptionDefault) WithStatusCode(code int) *TenantDeleteEncryptionDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the tenant delete encryption default response
func (o *TenantDeleteEncryptionDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the tenant delete encryption default response
func (o *TenantDeleteEncryptionDefault) WithPayload(payload *models.Error) *TenantDeleteEncryptionDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the tenant delete encryption default response
func (o *TenantDeleteEncryptionDefault) SetPayload(payload *models.Error) {
o.Payload = payload
}
// WriteResponse to the client
func (o *TenantDeleteEncryptionDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -0,0 +1,124 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 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 operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
"strings"
)
// TenantDeleteEncryptionURL generates an URL for the tenant delete encryption operation
type TenantDeleteEncryptionURL struct {
Namespace string
Tenant string
_basePath string
// avoid unkeyed usage
_ struct{}
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *TenantDeleteEncryptionURL) WithBasePath(bp string) *TenantDeleteEncryptionURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *TenantDeleteEncryptionURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *TenantDeleteEncryptionURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/namespaces/{namespace}/tenants/{tenant}/encryption"
namespace := o.Namespace
if namespace != "" {
_path = strings.Replace(_path, "{namespace}", namespace, -1)
} else {
return nil, errors.New("namespace is required on TenantDeleteEncryptionURL")
}
tenant := o.Tenant
if tenant != "" {
_path = strings.Replace(_path, "{tenant}", tenant, -1)
} else {
return nil, errors.New("tenant is required on TenantDeleteEncryptionURL")
}
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *TenantDeleteEncryptionURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *TenantDeleteEncryptionURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *TenantDeleteEncryptionURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on TenantDeleteEncryptionURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on TenantDeleteEncryptionURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *TenantDeleteEncryptionURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -0,0 +1,88 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 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 operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// TenantEncryptionInfoHandlerFunc turns a function with the right signature into a tenant encryption info handler
type TenantEncryptionInfoHandlerFunc func(TenantEncryptionInfoParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn TenantEncryptionInfoHandlerFunc) Handle(params TenantEncryptionInfoParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// TenantEncryptionInfoHandler interface for that can handle valid tenant encryption info params
type TenantEncryptionInfoHandler interface {
Handle(TenantEncryptionInfoParams, *models.Principal) middleware.Responder
}
// NewTenantEncryptionInfo creates a new http.Handler for the tenant encryption info operation
func NewTenantEncryptionInfo(ctx *middleware.Context, handler TenantEncryptionInfoHandler) *TenantEncryptionInfo {
return &TenantEncryptionInfo{Context: ctx, Handler: handler}
}
/* TenantEncryptionInfo swagger:route GET /namespaces/{namespace}/tenants/{tenant}/encryption OperatorAPI tenantEncryptionInfo
Tenant Encryption Info
*/
type TenantEncryptionInfo struct {
Context *middleware.Context
Handler TenantEncryptionInfoHandler
}
func (o *TenantEncryptionInfo) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewTenantEncryptionInfoParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -0,0 +1,112 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 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 operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt"
)
// NewTenantEncryptionInfoParams creates a new TenantEncryptionInfoParams object
//
// There are no default values defined in the spec.
func NewTenantEncryptionInfoParams() TenantEncryptionInfoParams {
return TenantEncryptionInfoParams{}
}
// TenantEncryptionInfoParams contains all the bound params for the tenant encryption info operation
// typically these are obtained from a http.Request
//
// swagger:parameters TenantEncryptionInfo
type TenantEncryptionInfoParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
Required: true
In: path
*/
Namespace string
/*
Required: true
In: path
*/
Tenant string
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewTenantEncryptionInfoParams() beforehand.
func (o *TenantEncryptionInfoParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
rNamespace, rhkNamespace, _ := route.Params.GetOK("namespace")
if err := o.bindNamespace(rNamespace, rhkNamespace, route.Formats); err != nil {
res = append(res, err)
}
rTenant, rhkTenant, _ := route.Params.GetOK("tenant")
if err := o.bindTenant(rTenant, rhkTenant, route.Formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// bindNamespace binds and validates parameter Namespace from path.
func (o *TenantEncryptionInfoParams) bindNamespace(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Namespace = raw
return nil
}
// bindTenant binds and validates parameter Tenant from path.
func (o *TenantEncryptionInfoParams) bindTenant(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Tenant = raw
return nil
}

View File

@@ -0,0 +1,133 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 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 operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// TenantEncryptionInfoOKCode is the HTTP code returned for type TenantEncryptionInfoOK
const TenantEncryptionInfoOKCode int = 200
/*TenantEncryptionInfoOK A successful response.
swagger:response tenantEncryptionInfoOK
*/
type TenantEncryptionInfoOK struct {
/*
In: Body
*/
Payload *models.EncryptionConfigurationResponse `json:"body,omitempty"`
}
// NewTenantEncryptionInfoOK creates TenantEncryptionInfoOK with default headers values
func NewTenantEncryptionInfoOK() *TenantEncryptionInfoOK {
return &TenantEncryptionInfoOK{}
}
// WithPayload adds the payload to the tenant encryption info o k response
func (o *TenantEncryptionInfoOK) WithPayload(payload *models.EncryptionConfigurationResponse) *TenantEncryptionInfoOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the tenant encryption info o k response
func (o *TenantEncryptionInfoOK) SetPayload(payload *models.EncryptionConfigurationResponse) {
o.Payload = payload
}
// WriteResponse to the client
func (o *TenantEncryptionInfoOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
/*TenantEncryptionInfoDefault Generic error response.
swagger:response tenantEncryptionInfoDefault
*/
type TenantEncryptionInfoDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
}
// NewTenantEncryptionInfoDefault creates TenantEncryptionInfoDefault with default headers values
func NewTenantEncryptionInfoDefault(code int) *TenantEncryptionInfoDefault {
if code <= 0 {
code = 500
}
return &TenantEncryptionInfoDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the tenant encryption info default response
func (o *TenantEncryptionInfoDefault) WithStatusCode(code int) *TenantEncryptionInfoDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the tenant encryption info default response
func (o *TenantEncryptionInfoDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the tenant encryption info default response
func (o *TenantEncryptionInfoDefault) WithPayload(payload *models.Error) *TenantEncryptionInfoDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the tenant encryption info default response
func (o *TenantEncryptionInfoDefault) SetPayload(payload *models.Error) {
o.Payload = payload
}
// WriteResponse to the client
func (o *TenantEncryptionInfoDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -0,0 +1,124 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2021 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 operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
"strings"
)
// TenantEncryptionInfoURL generates an URL for the tenant encryption info operation
type TenantEncryptionInfoURL struct {
Namespace string
Tenant string
_basePath string
// avoid unkeyed usage
_ struct{}
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *TenantEncryptionInfoURL) WithBasePath(bp string) *TenantEncryptionInfoURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *TenantEncryptionInfoURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *TenantEncryptionInfoURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/namespaces/{namespace}/tenants/{tenant}/encryption"
namespace := o.Namespace
if namespace != "" {
_path = strings.Replace(_path, "{namespace}", namespace, -1)
} else {
return nil, errors.New("namespace is required on TenantEncryptionInfoURL")
}
tenant := o.Tenant
if tenant != "" {
_path = strings.Replace(_path, "{tenant}", tenant, -1)
} else {
return nil, errors.New("tenant is required on TenantEncryptionInfoURL")
}
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *TenantEncryptionInfoURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *TenantEncryptionInfoURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *TenantEncryptionInfoURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on TenantEncryptionInfoURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on TenantEncryptionInfoURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *TenantEncryptionInfoURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -280,6 +280,24 @@ func registerTenantHandlers(api *operations.OperatorAPI) {
return operator_api.NewTenantUpdateEncryptionCreated()
})
// Delete tenant Encryption Configuration
api.OperatorAPITenantDeleteEncryptionHandler = operator_api.TenantDeleteEncryptionHandlerFunc(func(params operator_api.TenantDeleteEncryptionParams, session *models.Principal) middleware.Responder {
err := getTenantDeleteEncryptionResponse(session, params)
if err != nil {
return operator_api.NewTenantDeleteEncryptionDefault(int(err.Code)).WithPayload(err)
}
return operator_api.NewTenantDeleteEncryptionNoContent()
})
// Get Tenant Encryption Configuration
api.OperatorAPITenantEncryptionInfoHandler = operator_api.TenantEncryptionInfoHandlerFunc(func(params operator_api.TenantEncryptionInfoParams, session *models.Principal) middleware.Responder {
configuration, err := getTenantEncryptionInfoResponse(session, params)
if err != nil {
return operator_api.NewTenantEncryptionInfoDefault(int(err.Code)).WithPayload(err)
}
return operator_api.NewTenantEncryptionInfoOK().WithPayload(configuration)
})
// Get Tenant YAML
api.OperatorAPIGetTenantYAMLHandler = operator_api.GetTenantYAMLHandlerFunc(func(params operator_api.GetTenantYAMLParams, principal *models.Principal) middleware.Responder {
payload, err := getTenantYAML(principal, params)
@@ -635,6 +653,34 @@ func getTenantDetailsResponse(session *models.Principal, params operator_api.Ten
return info, nil
}
func parseCertificate(name string, rawCert []byte) (*models.CertificateInfo, error) {
block, _ := pem.Decode(rawCert)
if block == nil {
return nil, errors.New("certificate failed to decode")
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, err
}
domains := []string{}
// append certificate domain names
if len(cert.DNSNames) > 0 {
domains = append(domains, cert.DNSNames...)
}
// append certificate IPs
if len(cert.IPAddresses) > 0 {
for _, ip := range cert.IPAddresses {
domains = append(domains, ip.String())
}
}
return &models.CertificateInfo{
SerialNumber: cert.SerialNumber.String(),
Name: name,
Domains: domains,
Expiry: cert.NotAfter.String(),
}, nil
}
// parseTenantCertificates convert public key pem certificates stored in k8s secrets for a given Tenant into x509 certificates
func parseTenantCertificates(ctx context.Context, clientSet K8sClientI, namespace string, secrets []*miniov2.LocalCertificateReference) ([]*models.CertificateInfo, error) {
var certificates []*models.CertificateInfo
@@ -1207,7 +1253,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
minInst.Spec.KES.NodeSelector = tenantReq.Encryption.NodeSelector
if tenantReq.Encryption.SecurityContext != nil {
sc, err := parseSecurityContext(tenantReq.Encryption.SecurityContext)
sc, err := convertModelSCToK8sSC(tenantReq.Encryption.SecurityContext)
if err != nil {
return nil, prepareError(err)
}
@@ -1309,7 +1355,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
}
// if security context for logSearch is present, configure it.
if tenantReq.LogSearchConfiguration.SecurityContext != nil {
sc, err := parseSecurityContext(tenantReq.LogSearchConfiguration.SecurityContext)
sc, err := convertModelSCToK8sSC(tenantReq.LogSearchConfiguration.SecurityContext)
if err != nil {
return nil, prepareError(err)
}
@@ -1317,7 +1363,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
}
// if security context for logSearch is present, configure it.
if tenantReq.LogSearchConfiguration.PostgresSecurityContext != nil {
sc, err := parseSecurityContext(tenantReq.LogSearchConfiguration.PostgresSecurityContext)
sc, err := convertModelSCToK8sSC(tenantReq.LogSearchConfiguration.PostgresSecurityContext)
if err != nil {
return nil, prepareError(err)
}
@@ -1411,7 +1457,7 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre
}
// if security context for prometheus is present, configure it.
if tenantReq.PrometheusConfiguration != nil && tenantReq.PrometheusConfiguration.SecurityContext != nil {
sc, err := parseSecurityContext(tenantReq.PrometheusConfiguration.SecurityContext)
sc, err := convertModelSCToK8sSC(tenantReq.PrometheusConfiguration.SecurityContext)
if err != nil {
return nil, prepareError(err)
}
@@ -2550,7 +2596,7 @@ func parseTenantPoolRequest(poolParams *models.Pool) (*miniov2.Pool, error) {
}
// if security context for Tenant is present, configure it.
if poolParams.SecurityContext != nil {
sc, err := parseSecurityContext(poolParams.SecurityContext)
sc, err := convertModelSCToK8sSC(poolParams.SecurityContext)
if err != nil {
return nil, err
}

View File

@@ -22,6 +22,7 @@ import (
"crypto/tls"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"strconv"
"time"
@@ -39,8 +40,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// parseSecurityContext validate and return securityContext for pods
func parseSecurityContext(sc *models.SecurityContext) (*corev1.PodSecurityContext, error) {
// convertModelSCToK8sSC validates and converts from models.SecurityContext to corev1.PodSecurityContext
func convertModelSCToK8sSC(sc *models.SecurityContext) (*corev1.PodSecurityContext, error) {
if sc == nil {
return nil, errors.New("invalid security context")
}
@@ -64,6 +65,19 @@ func parseSecurityContext(sc *models.SecurityContext) (*corev1.PodSecurityContex
}, nil
}
// convertK8sSCToModelSC validates and converts from corev1.PodSecurityContext to models.SecurityContext
func convertK8sSCToModelSC(sc *corev1.PodSecurityContext) *models.SecurityContext {
runAsUser := strconv.FormatInt(*sc.RunAsUser, 10)
RunAsGroup := strconv.FormatInt(*sc.RunAsGroup, 10)
FsGroup := strconv.FormatInt(*sc.FSGroup, 10)
return &models.SecurityContext{
RunAsUser: &runAsUser,
RunAsGroup: &RunAsGroup,
RunAsNonRoot: sc.RunAsNonRoot,
FsGroup: &FsGroup,
}
}
// tenantUpdateCertificates receives the keyPair certificates (public and private keys) for Minio and Console and will try
// to replace the existing kubernetes secrets with the new values, then will restart the affected pods so the new volumes can be mounted
func tenantUpdateCertificates(ctx context.Context, operatorClient OperatorClientI, clientSet K8sClientI, namespace string, params operator_api.TenantUpdateCertificateParams) error {
@@ -116,6 +130,22 @@ func getTenantUpdateCertificatesResponse(session *models.Principal, params opera
return nil
}
// tenantDeleteEncryption allow user to disable tenant encryption for a particular tenant
func tenantDeleteEncryption(ctx context.Context, operatorClient OperatorClientI, namespace string, params operator_api.TenantDeleteEncryptionParams) error {
tenantName := params.Tenant
tenant, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{})
if err != nil {
return err
}
tenant.EnsureDefaults()
tenant.Spec.KES = nil
_, err = operatorClient.TenantUpdate(ctx, tenant, metav1.UpdateOptions{})
if err != nil {
return err
}
return nil
}
// tenantUpdateEncryption allow user to update KES server certificates, KES client certificates (used by MinIO for mTLS) and KES configuration (KMS configuration, credentials, etc)
func tenantUpdateEncryption(ctx context.Context, operatorClient OperatorClientI, clientSet K8sClientI, namespace string, params operator_api.TenantUpdateEncryptionParams) error {
tenantName := params.Tenant
@@ -125,47 +155,99 @@ func tenantUpdateEncryption(ctx context.Context, operatorClient OperatorClientI,
if err != nil {
return err
}
// Check if encryption is enabled for MinIO via KES
if tenant.HasKESEnabled() {
// check if KES is deployed with external certificates and user provided new server keypair
if tenant.KESExternalCert() && body.Server != nil {
kesExternalCertSecretName := fmt.Sprintf("%s-kes-external-cert", secretName)
// update certificates
certificates := []*models.KeyPairConfiguration{body.Server}
if _, err := createOrReplaceExternalCertSecrets(ctx, clientSet, namespace, certificates, kesExternalCertSecretName, tenantName); err != nil {
return err
tenant.EnsureDefaults()
// Initialize KES configuration if not present
if !tenant.HasKESEnabled() {
tenant.Spec.KES = &miniov2.KESConfig{}
}
if tenant.KESExternalCert() {
for _, certificateToBeDeleted := range params.Body.SecretsToBeDeleted {
if tenant.Spec.KES.ExternalCertSecret.Name == certificateToBeDeleted {
tenant.Spec.KES.ExternalCertSecret = nil
break
}
}
// check if Tenant is deployed with external client certificates and user provided new client keypaiir
if tenant.ExternalClientCert() && body.Client != nil {
tenantExternalClientCertSecretName := fmt.Sprintf("%s-tenant-external-client-cert", secretName)
// Update certificates
certificates := []*models.KeyPairConfiguration{body.Client}
if _, err := createOrReplaceExternalCertSecrets(ctx, clientSet, namespace, certificates, tenantExternalClientCertSecretName, tenantName); err != nil {
return err
}
// Restart MinIO pods to mount the new client secrets
err := clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=%s", miniov2.TenantLabel, tenantName),
})
if err != nil {
return err
}
if tenant.ExternalClientCert() {
for _, certificateToBeDeleted := range params.Body.SecretsToBeDeleted {
if tenant.Spec.ExternalClientCertSecret.Name == certificateToBeDeleted {
tenant.Spec.ExternalClientCertSecret = nil
break
}
}
// update KES identities in kes-configuration.yaml secret
kesConfigurationSecretName := fmt.Sprintf("%s-kes-configuration", secretName)
kesClientCertSecretName := fmt.Sprintf("%s-kes-client-cert", secretName)
_, _, err := createOrReplaceKesConfigurationSecrets(ctx, clientSet, namespace, body, kesConfigurationSecretName, kesClientCertSecretName, tenantName)
}
if body.Server != nil {
kesExternalCertSecretName := fmt.Sprintf("%s-kes-external-cert", secretName)
if tenant.KESExternalCert() {
kesExternalCertSecretName = tenant.Spec.KES.ExternalCertSecret.Name
}
// update certificates
certificates := []*models.KeyPairConfiguration{body.Server}
createdCertificates, err := createOrReplaceExternalCertSecrets(ctx, clientSet, namespace, certificates, kesExternalCertSecretName, tenantName)
if err != nil {
return err
}
// Restart KES pods to mount the new configuration
err = clientSet.deletePodCollection(ctx, namespace, metav1.DeleteOptions{}, metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=%s", miniov2.KESInstanceLabel, fmt.Sprintf("%s-kes", tenantName)),
})
if len(createdCertificates) > 0 {
tenant.Spec.KES.ExternalCertSecret = createdCertificates[0]
}
}
if body.Client != nil {
tenantExternalClientCertSecretName := fmt.Sprintf("%s-tenant-external-client-cert", secretName)
if tenant.ExternalClientCert() {
tenantExternalClientCertSecretName = tenant.Spec.ExternalClientCertSecret.Name
}
// Update certificates
certificates := []*models.KeyPairConfiguration{body.Client}
createdCertificates, err := createOrReplaceExternalCertSecrets(ctx, clientSet, namespace, certificates, tenantExternalClientCertSecretName, tenantName)
if err != nil {
return err
}
if len(createdCertificates) > 0 {
tenant.Spec.ExternalClientCertSecret = createdCertificates[0]
}
}
// update KES identities in kes-configuration.yaml secret
kesConfigurationSecretName := fmt.Sprintf("%s-kes-configuration", secretName)
kesClientCertSecretName := fmt.Sprintf("%s-kes-client-cert", secretName)
kesConfigurationSecret, kesClientCertSecret, err := createOrReplaceKesConfigurationSecrets(ctx, clientSet, namespace, body, kesConfigurationSecretName, kesClientCertSecretName, tenantName)
if err != nil {
return err
}
tenant.Spec.KES.Configuration = kesConfigurationSecret
tenant.Spec.KES.ClientCertSecret = kesClientCertSecret
image := params.Body.Image
if image == "" {
image = miniov2.DefaultKESImage
}
tenant.Spec.KES.Image = image
i, err := strconv.ParseInt(params.Body.Replicas, 10, 32)
if err != nil {
return err
}
tenant.Spec.KES.Replicas = int32(i)
tenant.Spec.KES.SecurityContext, err = convertModelSCToK8sSC(params.Body.SecurityContext)
if err != nil {
return err
}
_, err = operatorClient.TenantUpdate(ctx, tenant, metav1.UpdateOptions{})
if err != nil {
return err
}
return nil
}
// getTenantDeleteEncryptionResponse is a wrapper for tenantDeleteEncryption
func getTenantDeleteEncryptionResponse(session *models.Principal, params operator_api.TenantDeleteEncryptionParams) *models.Error {
ctx := context.Background()
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
if err != nil {
return prepareError(err, errorDeletingEncryptionConfig)
}
opClient := operatorClient{
client: opClientClientSet,
}
if err := tenantDeleteEncryption(ctx, &opClient, params.Namespace, params); err != nil {
return prepareError(err, errorDeletingEncryptionConfig)
}
return nil
}
@@ -194,6 +276,203 @@ func getTenantUpdateEncryptionResponse(session *models.Principal, params operato
return nil
}
// tenantEncryptionInfo retrieves encryption information for the current tenant
func tenantEncryptionInfo(ctx context.Context, operatorClient OperatorClientI, clientSet K8sClientI, namespace string, params operator_api.TenantEncryptionInfoParams) (*models.EncryptionConfigurationResponse, error) {
tenantName := params.Tenant
tenant, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{})
if err != nil {
return nil, err
}
// Check if encryption is enabled for MinIO via KES
if tenant.HasKESEnabled() {
encryptConfig := &models.EncryptionConfigurationResponse{
Image: tenant.Spec.KES.Image,
Replicas: fmt.Sprintf("%d", tenant.Spec.KES.Replicas),
}
if tenant.Spec.KES.Image == "" {
encryptConfig.Image = miniov2.GetTenantKesImage()
}
if tenant.Spec.KES.SecurityContext != nil {
encryptConfig.SecurityContext = convertK8sSCToModelSC(tenant.Spec.KES.SecurityContext)
}
if tenant.KESExternalCert() {
kesExternalCerts, err := parseTenantCertificates(ctx, clientSet, tenant.Namespace, []*miniov2.LocalCertificateReference{tenant.Spec.KES.ExternalCertSecret})
if err != nil {
return nil, err
}
if len(kesExternalCerts) > 0 {
encryptConfig.Server = kesExternalCerts[0]
}
}
if tenant.ExternalClientCert() {
clientCerts, err := parseTenantCertificates(ctx, clientSet, tenant.Namespace, []*miniov2.LocalCertificateReference{tenant.Spec.ExternalClientCertSecret})
if err != nil {
return nil, err
}
if len(clientCerts) > 0 {
encryptConfig.MtlsClient = clientCerts[0]
}
}
if tenant.Spec.KES.Configuration != nil {
configSecret, err := clientSet.getSecret(ctx, tenant.Namespace, tenant.Spec.KES.Configuration.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}
if rawConfiguration, ok := configSecret.Data["server-config.yaml"]; ok {
kesConfiguration := &kes.ServerConfig{}
err := yaml.Unmarshal(rawConfiguration, kesConfiguration)
if err != nil {
return nil, err
}
if kesConfiguration.Keys.Vault != nil {
vault := kesConfiguration.Keys.Vault
vaultConfig := &models.VaultConfigurationResponse{
Prefix: vault.Prefix,
Namespace: vault.Namespace,
Engine: vault.EnginePath,
Endpoint: &vault.Endpoint,
}
if vault.Status != nil {
vaultConfig.Status = &models.VaultConfigurationResponseStatus{
Ping: int64(vault.Status.Ping.Seconds()),
}
}
if vault.AppRole != nil {
vaultConfig.Approle = &models.VaultConfigurationResponseApprole{
Engine: vault.AppRole.EnginePath,
ID: &vault.AppRole.ID,
Retry: int64(vault.AppRole.Retry.Seconds()),
Secret: &vault.AppRole.Secret,
}
}
if tenant.KESClientCert() {
vaultConfig.TLS = &models.VaultConfigurationResponseTLS{}
clientSecretName := tenant.Spec.KES.ClientCertSecret.Name
keyPair, err := clientSet.getSecret(ctx, namespace, clientSecretName, metav1.GetOptions{})
if err != nil {
return nil, err
}
// Extract client public certificate
if rawCert, ok := keyPair.Data["client.crt"]; ok {
vaultConfig.TLS.Crt, err = parseCertificate(clientSecretName, rawCert)
if err != nil {
return nil, err
}
}
// Extract client ca certificate
if rawCert, ok := keyPair.Data["ca.crt"]; ok {
vaultConfig.TLS.Ca, err = parseCertificate(clientSecretName, rawCert)
if err != nil {
return nil, err
}
}
}
encryptConfig.Vault = vaultConfig
}
if kesConfiguration.Keys.Aws != nil {
awsJSON, err := json.Marshal(kesConfiguration.Keys.Aws)
if err != nil {
return nil, err
}
awsConfig := &models.AwsConfiguration{}
err = json.Unmarshal(awsJSON, awsConfig)
if err != nil {
return nil, err
}
encryptConfig.Aws = awsConfig
}
if kesConfiguration.Keys.Gcp != nil {
gcpJSON, err := json.Marshal(kesConfiguration.Keys.Gcp)
if err != nil {
return nil, err
}
gcpConfig := &models.GcpConfiguration{}
err = json.Unmarshal(gcpJSON, gcpConfig)
if err != nil {
return nil, err
}
encryptConfig.Gcp = gcpConfig
}
if kesConfiguration.Keys.Gemalto != nil {
gemalto := kesConfiguration.Keys.Gemalto
gemaltoConfig := &models.GemaltoConfigurationResponse{
Keysecure: &models.GemaltoConfigurationResponseKeysecure{},
}
if gemalto.KeySecure != nil {
gemaltoConfig.Keysecure.Endpoint = &gemalto.KeySecure.Endpoint
if gemalto.KeySecure.Credentials != nil {
gemaltoConfig.Keysecure.Credentials = &models.GemaltoConfigurationResponseKeysecureCredentials{
Domain: &gemalto.KeySecure.Credentials.Domain,
Retry: int64(gemalto.KeySecure.Credentials.Retry.Seconds()),
Token: &gemalto.KeySecure.Credentials.Token,
}
}
if gemalto.KeySecure.TLS != nil {
if tenant.KESClientCert() {
gemaltoConfig.Keysecure.TLS = &models.GemaltoConfigurationResponseKeysecureTLS{}
clientSecretName := tenant.Spec.KES.ClientCertSecret.Name
keyPair, err := clientSet.getSecret(ctx, namespace, clientSecretName, metav1.GetOptions{})
if err != nil {
return nil, err
}
// Extract client ca certificate
if rawCert, ok := keyPair.Data["ca.crt"]; ok {
gemaltoConfig.Keysecure.TLS.Ca, err = parseCertificate(clientSecretName, rawCert)
if err != nil {
return nil, err
}
}
}
}
}
encryptConfig.Gemalto = gemaltoConfig
}
if kesConfiguration.Keys.Azure != nil {
azureJSON, err := json.Marshal(kesConfiguration.Keys.Azure)
if err != nil {
return nil, err
}
azureConfig := &models.AzureConfiguration{}
err = json.Unmarshal(azureJSON, azureConfig)
if err != nil {
return nil, err
}
encryptConfig.Azure = azureConfig
}
}
}
return encryptConfig, nil
}
return nil, errors.New("encryption configuration not found")
}
// getTenantEncryptionResponse is a wrapper for tenantEncryptionInfo
func getTenantEncryptionInfoResponse(session *models.Principal, params operator_api.TenantEncryptionInfoParams) (*models.EncryptionConfigurationResponse, *models.Error) {
ctx := context.Background()
// get Kubernetes Client
clientSet, err := cluster.K8sClient(session.STSSessionToken)
if err != nil {
return nil, prepareError(err, errorEncryptionConfigNotFound)
}
k8sClient := k8sClient{
client: clientSet,
}
opClientClientSet, err := cluster.OperatorClient(session.STSSessionToken)
if err != nil {
return nil, prepareError(err, errorEncryptionConfigNotFound)
}
opClient := operatorClient{
client: opClientClientSet,
}
configuration, err := tenantEncryptionInfo(ctx, &opClient, &k8sClient, params.Namespace, params)
if err != nil {
return nil, prepareError(err, errorEncryptionConfigNotFound)
}
return configuration, nil
}
// getKESConfiguration will generate the KES server certificate secrets, the tenant client secrets for mTLS authentication between MinIO and KES and the
// kes-configuration.yaml file used by the KES service (how to connect to the external KMS, eg: Vault, AWS, Gemalto, etc)
func getKESConfiguration(ctx context.Context, clientSet K8sClientI, ns string, encryptionCfg *models.EncryptionConfiguration, secretName, tenantName string) (kesConfiguration *miniov2.KESConfig, err error) {
@@ -410,6 +689,10 @@ func createOrReplaceKesConfigurationSecrets(ctx context.Context, clientSet K8sCl
mTLSCertificates := map[string][]byte{}
// if encryption is enabled and encryption is configured to use Vault
if encryptionCfg.Vault != nil {
ping := 10 // default ping
if encryptionCfg.Vault.Status != nil {
ping = int(encryptionCfg.Vault.Status.Ping)
}
// Initialize Vault Config
kesConfig.Keys.Vault = &kes.Vault{
Endpoint: *encryptionCfg.Vault.Endpoint,
@@ -417,16 +700,17 @@ func createOrReplaceKesConfigurationSecrets(ctx context.Context, clientSet K8sCl
Namespace: encryptionCfg.Vault.Namespace,
Prefix: encryptionCfg.Vault.Prefix,
Status: &kes.VaultStatus{
Ping: 10 * time.Second,
Ping: time.Duration(ping) * time.Second,
},
}
// Vault AppRole credentials
if encryptionCfg.Vault.Approle != nil {
retry := encryptionCfg.Vault.Approle.Retry
kesConfig.Keys.Vault.AppRole = &kes.AppRole{
EnginePath: encryptionCfg.Vault.Approle.Engine,
ID: *encryptionCfg.Vault.Approle.ID,
Secret: *encryptionCfg.Vault.Approle.Secret,
Retry: 15 * time.Second,
Retry: time.Duration(retry) * time.Second,
}
} else {
return nil, nil, errors.New("approle credentials missing for kes")