From 8c82124a5739757816f73bf0fa6245c697361104 Mon Sep 17 00:00:00 2001 From: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com> Date: Mon, 23 Aug 2021 21:06:32 -0700 Subject: [PATCH] Prometheus Security Context (#973) * Prometheus Security Context Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com> * Missing files Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com> --- models/prometheus_configuration.go | 55 +++++++++++- models/security_context.go | 139 +++++++++++++++++++++++++++++ operatorapi/embedded_spec.go | 60 +++++++++++++ operatorapi/operator_tenants.go | 14 ++- swagger-operator.yml | 23 +++++ 5 files changed, 288 insertions(+), 3 deletions(-) create mode 100644 models/security_context.go diff --git a/models/prometheus_configuration.go b/models/prometheus_configuration.go index ad2c0b859..53f780642 100644 --- a/models/prometheus_configuration.go +++ b/models/prometheus_configuration.go @@ -25,6 +25,7 @@ package models import ( "context" + "github.com/go-openapi/errors" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" ) @@ -37,6 +38,9 @@ type PrometheusConfiguration struct { // image Image string `json:"image,omitempty"` + // security context + SecurityContext *SecurityContext `json:"securityContext,omitempty"` + // storage class StorageClass string `json:"storageClass,omitempty"` @@ -46,11 +50,60 @@ type PrometheusConfiguration struct { // Validate validates this prometheus configuration func (m *PrometheusConfiguration) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecurityContext(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } return nil } -// ContextValidate validates this prometheus configuration based on context it is used +func (m *PrometheusConfiguration) validateSecurityContext(formats strfmt.Registry) error { + if swag.IsZero(m.SecurityContext) { // not required + return nil + } + + if m.SecurityContext != nil { + if err := m.SecurityContext.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("securityContext") + } + return err + } + } + + return nil +} + +// ContextValidate validate this prometheus configuration based on the context it is used func (m *PrometheusConfiguration) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecurityContext(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PrometheusConfiguration) contextValidateSecurityContext(ctx context.Context, formats strfmt.Registry) error { + + if m.SecurityContext != nil { + if err := m.SecurityContext.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("securityContext") + } + return err + } + } + return nil } diff --git a/models/security_context.go b/models/security_context.go new file mode 100644 index 000000000..08d670110 --- /dev/null +++ b/models/security_context.go @@ -0,0 +1,139 @@ +// 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 . +// + +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 ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// SecurityContext security context +// +// swagger:model securityContext +type SecurityContext struct { + + // fs group + // Required: true + FsGroup *int64 `json:"fsGroup"` + + // run as group + // Required: true + RunAsGroup *int64 `json:"runAsGroup"` + + // run as non root + // Required: true + RunAsNonRoot *bool `json:"runAsNonRoot"` + + // run as user + // Required: true + RunAsUser *int64 `json:"runAsUser"` +} + +// Validate validates this security context +func (m *SecurityContext) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateFsGroup(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRunAsGroup(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRunAsNonRoot(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRunAsUser(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *SecurityContext) validateFsGroup(formats strfmt.Registry) error { + + if err := validate.Required("fsGroup", "body", m.FsGroup); err != nil { + return err + } + + return nil +} + +func (m *SecurityContext) validateRunAsGroup(formats strfmt.Registry) error { + + if err := validate.Required("runAsGroup", "body", m.RunAsGroup); err != nil { + return err + } + + return nil +} + +func (m *SecurityContext) validateRunAsNonRoot(formats strfmt.Registry) error { + + if err := validate.Required("runAsNonRoot", "body", m.RunAsNonRoot); err != nil { + return err + } + + return nil +} + +func (m *SecurityContext) validateRunAsUser(formats strfmt.Registry) error { + + if err := validate.Required("runAsUser", "body", m.RunAsUser); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this security context based on context it is used +func (m *SecurityContext) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *SecurityContext) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *SecurityContext) UnmarshalBinary(b []byte) error { + var res SecurityContext + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/operatorapi/embedded_spec.go b/operatorapi/embedded_spec.go index 7a1c4bf7b..63c790f95 100644 --- a/operatorapi/embedded_spec.go +++ b/operatorapi/embedded_spec.go @@ -2611,6 +2611,10 @@ func init() { "image": { "type": "string" }, + "securityContext": { + "type": "object", + "$ref": "#/definitions/securityContext" + }, "storageClass": { "type": "string", "default": "" @@ -2680,6 +2684,32 @@ func init() { } } }, + "securityContext": { + "type": "object", + "required": [ + "runAsUser", + "runAsGroup", + "runAsNonRoot", + "fsGroup" + ], + "properties": { + "fsGroup": { + "type": "integer", + "format": "int64" + }, + "runAsGroup": { + "type": "integer", + "format": "int64" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer", + "format": "int64" + } + } + }, "subscriptionValidateRequest": { "type": "object", "properties": { @@ -6143,6 +6173,10 @@ func init() { "image": { "type": "string" }, + "securityContext": { + "type": "object", + "$ref": "#/definitions/securityContext" + }, "storageClass": { "type": "string", "default": "" @@ -6212,6 +6246,32 @@ func init() { } } }, + "securityContext": { + "type": "object", + "required": [ + "runAsUser", + "runAsGroup", + "runAsNonRoot", + "fsGroup" + ], + "properties": { + "fsGroup": { + "type": "integer", + "format": "int64" + }, + "runAsGroup": { + "type": "integer", + "format": "int64" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer", + "format": "int64" + } + } + }, "subscriptionValidateRequest": { "type": "object", "properties": { diff --git a/operatorapi/operator_tenants.go b/operatorapi/operator_tenants.go index e20c57a4b..a1a1eec0d 100644 --- a/operatorapi/operator_tenants.go +++ b/operatorapi/operator_tenants.go @@ -395,11 +395,11 @@ func getTenantCreds(ctx context.Context, client K8sClientI, tenant *miniov2.Tena } func getTenant(ctx context.Context, operatorClient OperatorClientI, namespace, tenantName string) (*miniov2.Tenant, error) { - minInst, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{}) + tenant, err := operatorClient.TenantGet(ctx, namespace, tenantName, metav1.GetOptions{}) if err != nil { return nil, err } - return minInst, nil + return tenant, nil } func isPrometheusEnabled(annotations map[string]string) bool { @@ -1309,6 +1309,16 @@ func getTenantCreatedResponse(session *models.Principal, params operator_api.Cre if prometheusImage != "" { minInst.Spec.Prometheus.Image = prometheusImage } + // if security context for prometheus is present, configure it. + if tenantReq.PrometheusConfiguration != nil && tenantReq.PrometheusConfiguration.SecurityContext != nil { + sc := tenantReq.PrometheusConfiguration.SecurityContext + minInst.Spec.Prometheus.SecurityContext = &corev1.PodSecurityContext{ + RunAsUser: sc.RunAsUser, + RunAsGroup: sc.RunAsGroup, + RunAsNonRoot: sc.RunAsNonRoot, + FSGroup: sc.FsGroup, + } + } // expose services minInst.Spec.ExposeServices = &miniov2.ExposeServices{ diff --git a/swagger-operator.yml b/swagger-operator.yml index 194a55221..96f51acc8 100644 --- a/swagger-operator.yml +++ b/swagger-operator.yml @@ -1317,6 +1317,9 @@ definitions: default: 5 image: type: string + securityContext: + type: object + $ref: '#/definitions/securityContext' idpConfiguration: type: object properties: @@ -2263,3 +2266,23 @@ definitions: type: string force: type: boolean + securityContext: + type: object + required: + - runAsUser + - runAsGroup + - runAsNonRoot + - fsGroup + properties: + runAsUser: + type: integer + format: int64 + runAsGroup: + type: integer + format: int64 + runAsNonRoot: + type: boolean + fsGroup: + type: integer + format: int64 +