mirror of
https://github.com/rancher/rke.git
synced 2025-09-01 23:16:22 +00:00
add the support for PodSecurity on cluster at least v1.23
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -31,6 +30,7 @@ import (
|
|||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
apiserverv1 "k8s.io/apiserver/pkg/apis/apiserver/v1"
|
apiserverv1 "k8s.io/apiserver/pkg/apis/apiserver/v1"
|
||||||
|
@@ -5,7 +5,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
eventratelimitapi "k8s.io/kubernetes/plugin/pkg/admission/eventratelimit/apis/eventratelimit"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/blang/semver"
|
"github.com/blang/semver"
|
||||||
@@ -25,6 +24,9 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
apiserverv1 "k8s.io/apiserver/pkg/apis/apiserver/v1"
|
apiserverv1 "k8s.io/apiserver/pkg/apis/apiserver/v1"
|
||||||
auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
|
auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
|
||||||
|
eventratelimitapi "k8s.io/kubernetes/plugin/pkg/admission/eventratelimit/apis/eventratelimit"
|
||||||
|
admissionapiv1 "k8s.io/pod-security-admission/admission/api/v1"
|
||||||
|
admissionapiv1beta1 "k8s.io/pod-security-admission/admission/api/v1beta1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -118,6 +120,9 @@ const (
|
|||||||
DefaultKubeAPIArgAdmissionControlConfigFileValue = "/etc/kubernetes/admission.yaml"
|
DefaultKubeAPIArgAdmissionControlConfigFileValue = "/etc/kubernetes/admission.yaml"
|
||||||
|
|
||||||
EventRateLimitPluginName = "EventRateLimit"
|
EventRateLimitPluginName = "EventRateLimit"
|
||||||
|
PodSecurityPluginName = "PodSecurity"
|
||||||
|
PodSecurityPrivileged = "privileged"
|
||||||
|
PodSecurityRestricted = "restricted"
|
||||||
|
|
||||||
KubeAPIArgAuditLogPath = "audit-log-path"
|
KubeAPIArgAuditLogPath = "audit-log-path"
|
||||||
KubeAPIArgAuditLogMaxAge = "audit-log-maxage"
|
KubeAPIArgAuditLogMaxAge = "audit-log-maxage"
|
||||||
@@ -382,6 +387,9 @@ func (c *Cluster) setClusterServicesDefaults() {
|
|||||||
c.Services.KubeAPI.EventRateLimit.Configuration == nil {
|
c.Services.KubeAPI.EventRateLimit.Configuration == nil {
|
||||||
c.Services.KubeAPI.EventRateLimit.Configuration = newDefaultEventRateLimitConfig()
|
c.Services.KubeAPI.EventRateLimit.Configuration = newDefaultEventRateLimitConfig()
|
||||||
}
|
}
|
||||||
|
if len(c.Services.KubeAPI.PodSecurityConfiguration) == 0 {
|
||||||
|
c.Services.KubeAPI.PodSecurityConfiguration = PodSecurityPrivileged
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enableKubeAPIAuditLog, err := checkVersionNeedsKubeAPIAuditLog(c.Version)
|
enableKubeAPIAuditLog, err := checkVersionNeedsKubeAPIAuditLog(c.Version)
|
||||||
@@ -500,6 +508,120 @@ func newDefaultAdmissionConfiguration() (*apiserverv1.AdmissionConfiguration, er
|
|||||||
return admissionConfiguration, nil
|
return admissionConfiguration, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newDefaultPodSecurityPluginConfigurationRestricted(Version string) (apiserverv1.AdmissionPluginConfiguration, error) {
|
||||||
|
plugin := apiserverv1.AdmissionPluginConfiguration{
|
||||||
|
Name: PodSecurityPluginName,
|
||||||
|
Configuration: &runtime.Unknown{
|
||||||
|
ContentType: "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
parsedVersion, err := getClusterVersion(Version)
|
||||||
|
if err != nil {
|
||||||
|
return plugin, err
|
||||||
|
}
|
||||||
|
var cBytes []byte
|
||||||
|
if parsedRangeAtLeast125(parsedVersion) {
|
||||||
|
configuration := admissionapiv1.PodSecurityConfiguration{
|
||||||
|
TypeMeta: v1.TypeMeta{
|
||||||
|
Kind: "PodSecurityConfiguration",
|
||||||
|
APIVersion: admissionapiv1.SchemeGroupVersion.String(),
|
||||||
|
},
|
||||||
|
Defaults: admissionapiv1.PodSecurityDefaults{
|
||||||
|
Enforce: "restricted",
|
||||||
|
EnforceVersion: "latest",
|
||||||
|
Audit: "restricted",
|
||||||
|
AuditVersion: "latest",
|
||||||
|
Warn: "restricted",
|
||||||
|
WarnVersion: "latest",
|
||||||
|
},
|
||||||
|
Exemptions: admissionapiv1.PodSecurityExemptions{
|
||||||
|
Usernames: nil,
|
||||||
|
Namespaces: []string{"ingress-nginx", "kube-system"},
|
||||||
|
RuntimeClasses: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cBytes, err = json.Marshal(configuration)
|
||||||
|
if err != nil {
|
||||||
|
return plugin, fmt.Errorf("error marshalling podSecurity config: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if parsedRange123(parsedVersion) || parsedRange124(parsedVersion) {
|
||||||
|
configuration := admissionapiv1beta1.PodSecurityConfiguration{
|
||||||
|
TypeMeta: v1.TypeMeta{
|
||||||
|
Kind: "PodSecurityConfiguration",
|
||||||
|
APIVersion: admissionapiv1beta1.SchemeGroupVersion.String(),
|
||||||
|
},
|
||||||
|
Defaults: admissionapiv1beta1.PodSecurityDefaults{
|
||||||
|
Enforce: "restricted",
|
||||||
|
EnforceVersion: "latest",
|
||||||
|
Audit: "restricted",
|
||||||
|
AuditVersion: "latest",
|
||||||
|
Warn: "restricted",
|
||||||
|
WarnVersion: "latest",
|
||||||
|
},
|
||||||
|
Exemptions: admissionapiv1beta1.PodSecurityExemptions{
|
||||||
|
Usernames: nil,
|
||||||
|
Namespaces: []string{"ingress-nginx", "kube-system"},
|
||||||
|
RuntimeClasses: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cBytes, err = json.Marshal(configuration)
|
||||||
|
if err != nil {
|
||||||
|
return plugin, fmt.Errorf("error marshalling podSecurity config: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plugin.Configuration.Raw = cBytes
|
||||||
|
return plugin, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDefaultPodSecurityPluginConfigurationPrivileged(Version string) (apiserverv1.AdmissionPluginConfiguration, error) {
|
||||||
|
plugin := apiserverv1.AdmissionPluginConfiguration{
|
||||||
|
Name: PodSecurityPluginName,
|
||||||
|
Configuration: &runtime.Unknown{
|
||||||
|
ContentType: "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
parsedVersion, err := getClusterVersion(Version)
|
||||||
|
if err != nil {
|
||||||
|
return plugin, err
|
||||||
|
}
|
||||||
|
var cBytes []byte
|
||||||
|
if parsedRangeAtLeast125(parsedVersion) {
|
||||||
|
configuration := admissionapiv1.PodSecurityConfiguration{
|
||||||
|
TypeMeta: v1.TypeMeta{
|
||||||
|
Kind: "PodSecurityConfiguration",
|
||||||
|
APIVersion: admissionapiv1.SchemeGroupVersion.String(),
|
||||||
|
},
|
||||||
|
Defaults: admissionapiv1.PodSecurityDefaults{
|
||||||
|
Enforce: "privileged",
|
||||||
|
EnforceVersion: "latest",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cBytes, err = json.Marshal(configuration)
|
||||||
|
if err != nil {
|
||||||
|
return plugin, fmt.Errorf("error marshalling podSecurity config: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if parsedRange123(parsedVersion) || parsedRange124(parsedVersion) {
|
||||||
|
configuration := admissionapiv1beta1.PodSecurityConfiguration{
|
||||||
|
TypeMeta: v1.TypeMeta{
|
||||||
|
Kind: "PodSecurityConfiguration",
|
||||||
|
APIVersion: admissionapiv1beta1.SchemeGroupVersion.String(),
|
||||||
|
},
|
||||||
|
Defaults: admissionapiv1beta1.PodSecurityDefaults{
|
||||||
|
Enforce: "privileged",
|
||||||
|
EnforceVersion: "latest",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cBytes, err = json.Marshal(configuration)
|
||||||
|
if err != nil {
|
||||||
|
return plugin, fmt.Errorf("error marshalling podSecurity config: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plugin.Configuration.Raw = cBytes
|
||||||
|
return plugin, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Cluster) setClusterImageDefaults() error {
|
func (c *Cluster) setClusterImageDefaults() error {
|
||||||
var privRegURL string
|
var privRegURL string
|
||||||
|
|
||||||
|
144
cluster/hosts.go
144
cluster/hosts.go
@@ -148,67 +148,78 @@ func (c *Cluster) CalculateMaxUnavailable() (int, int, error) {
|
|||||||
return maxUnavailableWorker, maxUnavailableControl, nil
|
return maxUnavailableWorker, maxUnavailableControl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getConsolidatedAdmissionConfiguration returns a consolidated admission configuration;
|
||||||
|
// for individual plugin configuration, the one under KubeAPI.AdmissionConfiguration takes precedence over the one under KubeAPI.<PLUGIN-NAME>
|
||||||
func (c *Cluster) getConsolidatedAdmissionConfiguration() (*apiserverv1.AdmissionConfiguration, error) {
|
func (c *Cluster) getConsolidatedAdmissionConfiguration() (*apiserverv1.AdmissionConfiguration, error) {
|
||||||
var err error
|
admissionConfig, err := newDefaultAdmissionConfiguration()
|
||||||
var admissionConfig *apiserverv1.AdmissionConfiguration
|
if err != nil {
|
||||||
|
logrus.Errorf("error getting default admission configuration: %v", err)
|
||||||
if c.Services.KubeAPI.EventRateLimit == nil ||
|
return nil, err
|
||||||
!c.Services.KubeAPI.EventRateLimit.Enabled {
|
|
||||||
return c.Services.KubeAPI.AdmissionConfiguration, nil
|
|
||||||
}
|
}
|
||||||
|
if c.Services.KubeAPI.AdmissionConfiguration != nil {
|
||||||
|
copy(admissionConfig.Plugins, c.Services.KubeAPI.AdmissionConfiguration.Plugins)
|
||||||
|
}
|
||||||
|
// EventRateLimit
|
||||||
|
ertConfig, err := c.getEventRateLimitPluginConfiguration()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_ = setPluginConfiguration(admissionConfig, ertConfig)
|
||||||
|
|
||||||
logrus.Debugf("EventRateLimit is enabled")
|
// PodSecurity
|
||||||
found := false
|
psConfig, err := c.getPodSecurityAdmissionPluginConfiguration()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_ = setPluginConfiguration(admissionConfig, psConfig)
|
||||||
|
|
||||||
|
return admissionConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cluster) getEventRateLimitPluginConfiguration() (apiserverv1.AdmissionPluginConfiguration, error) {
|
||||||
|
// the configuration under KubeAPI.AdmissionConfiguration takes precedence over the one under KubeAPI.EventRateLimit
|
||||||
if c.Services.KubeAPI.AdmissionConfiguration != nil {
|
if c.Services.KubeAPI.AdmissionConfiguration != nil {
|
||||||
plugins := c.Services.KubeAPI.AdmissionConfiguration.Plugins
|
plugins := c.Services.KubeAPI.AdmissionConfiguration.Plugins
|
||||||
for _, plugin := range plugins {
|
for _, plugin := range plugins {
|
||||||
if plugin.Name == EventRateLimitPluginName {
|
if plugin.Name == EventRateLimitPluginName {
|
||||||
found = true
|
logrus.Debug("using the EventRateLimit configuration under the admission configuration")
|
||||||
break
|
return plugin, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if found {
|
if c.Services.KubeAPI.EventRateLimit != nil &&
|
||||||
logrus.Debugf("EventRateLimit Plugin configuration found in admission config")
|
c.Services.KubeAPI.EventRateLimit.Enabled &&
|
||||||
if c.Services.KubeAPI.EventRateLimit.Configuration != nil {
|
c.Services.KubeAPI.EventRateLimit.Configuration != nil {
|
||||||
logrus.Warnf("conflicting EventRateLimit configuration found, using the one from Admission Configuration")
|
logrus.Debug("using the user-specified EventRateLimit configuration")
|
||||||
return c.Services.KubeAPI.AdmissionConfiguration, nil
|
return getEventRateLimitPluginFromConfig(c.Services.KubeAPI.EventRateLimit.Configuration)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
logrus.Debug("using the default EventRateLimit configuration")
|
||||||
|
return newDefaultEventRateLimitPlugin()
|
||||||
|
}
|
||||||
|
|
||||||
logrus.Debugf("EventRateLimit Plugin configuration not found in admission config")
|
func (c *Cluster) getPodSecurityAdmissionPluginConfiguration() (apiserverv1.AdmissionPluginConfiguration, error) {
|
||||||
if c.Services.KubeAPI.AdmissionConfiguration == nil {
|
// the configuration under KubeAPI.AdmissionConfiguration takes precedence over
|
||||||
logrus.Debugf("no user specified admission configuration found")
|
// the one under KubeAPI.PodSecurityConfiguration
|
||||||
admissionConfig, err = newDefaultAdmissionConfiguration()
|
if c.Services.KubeAPI.AdmissionConfiguration != nil {
|
||||||
if err != nil {
|
plugins := c.Services.KubeAPI.AdmissionConfiguration.Plugins
|
||||||
logrus.Errorf("error getting default admission configuration: %v", err)
|
for _, plugin := range plugins {
|
||||||
return nil, err
|
logrus.Debug("using the PodSecurity configuration under the admission configuration")
|
||||||
|
if plugin.Name == PodSecurityPluginName {
|
||||||
|
return plugin, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
admissionConfig, err = newDefaultAdmissionConfiguration()
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("error getting default admission configuration: %v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
copy(admissionConfig.Plugins, c.Services.KubeAPI.AdmissionConfiguration.Plugins)
|
|
||||||
}
|
}
|
||||||
if c.Services.KubeAPI.EventRateLimit.Configuration != nil {
|
level := c.Services.KubeAPI.PodSecurityConfiguration
|
||||||
logrus.Debugf("user specified EventRateLimit configuration found")
|
logrus.Debugf("using the PodSecurity configuration [%s]", level)
|
||||||
p, err := getEventRateLimitPluginFromConfig(c.Services.KubeAPI.EventRateLimit.Configuration)
|
switch level {
|
||||||
if err != nil {
|
case PodSecurityPrivileged:
|
||||||
logrus.Errorf("error getting eventratelimit plugin from config: %v", err)
|
return newDefaultPodSecurityPluginConfigurationPrivileged(c.Version)
|
||||||
}
|
case PodSecurityRestricted:
|
||||||
admissionConfig.Plugins = append(admissionConfig.Plugins, p)
|
return newDefaultPodSecurityPluginConfigurationRestricted(c.Version)
|
||||||
} else {
|
default:
|
||||||
logrus.Debugf("using default EventRateLimit configuration")
|
logrus.Debugf("invalid PodSecurity configuration [%s], using the default [privileged] configuration", level)
|
||||||
p, err := newDefaultEventRateLimitPlugin()
|
return newDefaultPodSecurityPluginConfigurationPrivileged(c.Version)
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("error getting default eventratelimit plugin: %v", err)
|
|
||||||
}
|
|
||||||
admissionConfig.Plugins = append(admissionConfig.Plugins, p)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return admissionConfig, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cluster) SetUpHosts(ctx context.Context, flags ExternalFlags) error {
|
func (c *Cluster) SetUpHosts(ctx context.Context, flags ExternalFlags) error {
|
||||||
@@ -270,21 +281,19 @@ func (c *Cluster) SetUpHosts(ctx context.Context, flags ExternalFlags) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := c.Services.KubeAPI.ExtraArgs[KubeAPIArgAdmissionControlConfigFile]; !ok {
|
if _, ok := c.Services.KubeAPI.ExtraArgs[KubeAPIArgAdmissionControlConfigFile]; !ok {
|
||||||
if c.Services.KubeAPI.EventRateLimit != nil && c.Services.KubeAPI.EventRateLimit.Enabled {
|
controlPlaneHosts := hosts.GetUniqueHostList(nil, c.ControlPlaneHosts, nil)
|
||||||
controlPlaneHosts := hosts.GetUniqueHostList(nil, c.ControlPlaneHosts, nil)
|
ac, err := c.getConsolidatedAdmissionConfiguration()
|
||||||
ac, err := c.getConsolidatedAdmissionConfiguration()
|
if err != nil {
|
||||||
if err != nil {
|
return fmt.Errorf("error getting consolidated admission configuration: %v", err)
|
||||||
return fmt.Errorf("error getting consolidated admission configuration: %v", err)
|
|
||||||
}
|
|
||||||
bytes, err := yaml.Marshal(ac)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := deployFile(ctx, controlPlaneHosts, c.SystemImages.Alpine, c.PrivateRegistriesMap, DefaultKubeAPIArgAdmissionControlConfigFileValue, string(bytes), c.Version); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Infof(ctx, "[%s] Successfully deployed admission control config to Cluster control nodes", DefaultKubeAPIArgAdmissionControlConfigFileValue)
|
|
||||||
}
|
}
|
||||||
|
bytes, err := yaml.Marshal(ac)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := deployFile(ctx, controlPlaneHosts, c.SystemImages.Alpine, c.PrivateRegistriesMap, DefaultKubeAPIArgAdmissionControlConfigFileValue, string(bytes), c.Version); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Infof(ctx, "[%s] Successfully deployed admission control config to Cluster control nodes", DefaultKubeAPIArgAdmissionControlConfigFileValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := c.Services.KubeAPI.ExtraArgs[KubeAPIArgAuditPolicyFile]; !ok {
|
if _, ok := c.Services.KubeAPI.ExtraArgs[KubeAPIArgAuditPolicyFile]; !ok {
|
||||||
@@ -332,3 +341,18 @@ func removeFromRKENodes(nodeToRemove v3.RKEConfigNode, nodeList []v3.RKEConfigNo
|
|||||||
}
|
}
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setPluginConfiguration either adds the plugin configuration or replaces the existing one in the admission configuration
|
||||||
|
func setPluginConfiguration(admissionConfig *apiserverv1.AdmissionConfiguration, pluginConfig apiserverv1.AdmissionPluginConfiguration) error {
|
||||||
|
if admissionConfig == nil {
|
||||||
|
return fmt.Errorf("admission configuarion does not exist")
|
||||||
|
}
|
||||||
|
for i, plugin := range admissionConfig.Plugins {
|
||||||
|
if plugin.Name == pluginConfig.Name {
|
||||||
|
admissionConfig.Plugins[i] = pluginConfig
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
admissionConfig.Plugins = append(admissionConfig.Plugins, pluginConfig)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@@ -66,8 +66,11 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
admissionControlOptionNames = []string{"enable-admission-plugins", "admission-control"}
|
admissionControlOptionNames = []string{"enable-admission-plugins", "admission-control"}
|
||||||
|
parsedRangeAtLeast123 = semver.MustParseRange(">= 1.23.0-rancher0")
|
||||||
parsedRangeAtLeast124 = semver.MustParseRange(">= 1.24.0-rancher0")
|
parsedRangeAtLeast124 = semver.MustParseRange(">= 1.24.0-rancher0")
|
||||||
parsedRangeAtLeast125 = semver.MustParseRange(">= 1.25.0-rancher0")
|
parsedRangeAtLeast125 = semver.MustParseRange(">= 1.25.0-rancher0")
|
||||||
|
parsedRange123 = semver.MustParseRange(">=1.23.0-rancher0 <=1.23.99-rancher-0")
|
||||||
|
parsedRange124 = semver.MustParseRange(">=1.24.0-rancher0 <=1.24.99-rancher-0")
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetServiceOptionData(data map[string]interface{}) map[string]*v3.KubernetesServicesOptions {
|
func GetServiceOptionData(data map[string]interface{}) map[string]*v3.KubernetesServicesOptions {
|
||||||
@@ -174,24 +177,25 @@ func (c *Cluster) BuildKubeAPIProcess(host *hosts.Host, serviceOptions v3.Kubern
|
|||||||
|
|
||||||
Command := c.getRKEToolsEntryPoint(host.OS(), "kube-apiserver")
|
Command := c.getRKEToolsEntryPoint(host.OS(), "kube-apiserver")
|
||||||
CommandArgs := map[string]string{
|
CommandArgs := map[string]string{
|
||||||
"client-ca-file": pki.GetCertPath(pki.CACertName),
|
"admission-control-config-file": DefaultKubeAPIArgAdmissionControlConfigFileValue,
|
||||||
"cloud-provider": c.CloudProvider.Name,
|
"client-ca-file": pki.GetCertPath(pki.CACertName),
|
||||||
"etcd-cafile": etcdCAClientCert,
|
"cloud-provider": c.CloudProvider.Name,
|
||||||
"etcd-certfile": etcdClientCert,
|
"etcd-cafile": etcdCAClientCert,
|
||||||
"etcd-keyfile": etcdClientKey,
|
"etcd-certfile": etcdClientCert,
|
||||||
"etcd-prefix": etcdPathPrefix,
|
"etcd-keyfile": etcdClientKey,
|
||||||
"etcd-servers": etcdConnectionString,
|
"etcd-prefix": etcdPathPrefix,
|
||||||
"kubelet-client-certificate": pki.GetCertPath(pki.KubeAPICertName),
|
"etcd-servers": etcdConnectionString,
|
||||||
"kubelet-client-key": pki.GetKeyPath(pki.KubeAPICertName),
|
"kubelet-client-certificate": pki.GetCertPath(pki.KubeAPICertName),
|
||||||
"proxy-client-cert-file": pki.GetCertPath(pki.APIProxyClientCertName),
|
"kubelet-client-key": pki.GetKeyPath(pki.KubeAPICertName),
|
||||||
"proxy-client-key-file": pki.GetKeyPath(pki.APIProxyClientCertName),
|
"proxy-client-cert-file": pki.GetCertPath(pki.APIProxyClientCertName),
|
||||||
"requestheader-allowed-names": pki.APIProxyClientCertName,
|
"proxy-client-key-file": pki.GetKeyPath(pki.APIProxyClientCertName),
|
||||||
"requestheader-client-ca-file": pki.GetCertPath(pki.RequestHeaderCACertName),
|
"requestheader-allowed-names": pki.APIProxyClientCertName,
|
||||||
"service-account-key-file": pki.GetKeyPath(pki.ServiceAccountTokenKeyName),
|
"requestheader-client-ca-file": pki.GetCertPath(pki.RequestHeaderCACertName),
|
||||||
"service-cluster-ip-range": c.Services.KubeAPI.ServiceClusterIPRange,
|
"service-account-key-file": pki.GetKeyPath(pki.ServiceAccountTokenKeyName),
|
||||||
"service-node-port-range": c.Services.KubeAPI.ServiceNodePortRange,
|
"service-cluster-ip-range": c.Services.KubeAPI.ServiceClusterIPRange,
|
||||||
"tls-cert-file": pki.GetCertPath(pki.KubeAPICertName),
|
"service-node-port-range": c.Services.KubeAPI.ServiceNodePortRange,
|
||||||
"tls-private-key-file": pki.GetKeyPath(pki.KubeAPICertName),
|
"tls-cert-file": pki.GetCertPath(pki.KubeAPICertName),
|
||||||
|
"tls-private-key-file": pki.GetKeyPath(pki.KubeAPICertName),
|
||||||
}
|
}
|
||||||
CommandArrayArgs := make(map[string][]string, len(c.Services.KubeAPI.ExtraArgsArray))
|
CommandArrayArgs := make(map[string][]string, len(c.Services.KubeAPI.ExtraArgsArray))
|
||||||
|
|
||||||
@@ -256,7 +260,6 @@ func (c *Cluster) BuildKubeAPIProcess(host *hosts.Host, serviceOptions v3.Kubern
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.Services.KubeAPI.EventRateLimit != nil && c.Services.KubeAPI.EventRateLimit.Enabled {
|
if c.Services.KubeAPI.EventRateLimit != nil && c.Services.KubeAPI.EventRateLimit.Enabled {
|
||||||
CommandArgs[KubeAPIArgAdmissionControlConfigFile] = DefaultKubeAPIArgAdmissionControlConfigFileValue
|
|
||||||
CommandArgs[admissionControlOptionName] = CommandArgs[admissionControlOptionName] + ",EventRateLimit"
|
CommandArgs[admissionControlOptionName] = CommandArgs[admissionControlOptionName] + ",EventRateLimit"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,7 +708,7 @@ func (c *Cluster) BuildKubeProxyProcess(host *hosts.Host, serviceOptions v3.Kube
|
|||||||
services.SidekickContainerName,
|
services.SidekickContainerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: we should reevaluate if any of the bind mounts here should be using read-only mode
|
// TODO: we should reevaluate if any of the bind mounts here should be using read-only mode
|
||||||
var Binds []string
|
var Binds []string
|
||||||
if host.IsWindows() { // compatible with Windows
|
if host.IsWindows() { // compatible with Windows
|
||||||
Binds = []string{
|
Binds = []string{
|
||||||
|
@@ -3,6 +3,7 @@ package cluster
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rancher/rke/docker"
|
"github.com/rancher/rke/docker"
|
||||||
@@ -455,7 +456,7 @@ func syncTaints(ctx context.Context, currentCluster, kubeCluster *Cluster) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//getHostsTaintsMap return the taint set with unique key & effect for each host
|
// getHostsTaintsMap return the taint set with unique key & effect for each host
|
||||||
func getHostsTaintsMap(list []*hosts.Host) map[string]map[string]string {
|
func getHostsTaintsMap(list []*hosts.Host) map[string]map[string]string {
|
||||||
rtn := make(map[string]map[string]string)
|
rtn := make(map[string]map[string]string)
|
||||||
for _, item := range list {
|
for _, item := range list {
|
||||||
@@ -488,3 +489,18 @@ func getTaintKey(taint v3.RKETaint) string {
|
|||||||
func getTaintValue(taint v3.RKETaint) string {
|
func getTaintValue(taint v3.RKETaint) string {
|
||||||
return fmt.Sprintf("%s=%s:%s", taint.Key, taint.Value, taint.Effect)
|
return fmt.Sprintf("%s=%s:%s", taint.Key, taint.Value, taint.Effect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RestartKubeAPIServerWhenConfigChanges restarts the kube-apiserver container on the control plan nodes
|
||||||
|
// when changes are detected on the to-be-applied kube-api configuration. This is needed to handle the case
|
||||||
|
// where changes happen on the generated admission-control-config-file but not on the kube-apiserver container
|
||||||
|
func RestartKubeAPIServerWhenConfigChanges(ctx context.Context, kubeCluster, currentCluster *Cluster) error {
|
||||||
|
if currentCluster == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(currentCluster.Services.KubeAPI, kubeCluster.Services.KubeAPI) {
|
||||||
|
for _, host := range kubeCluster.ControlPlaneHosts {
|
||||||
|
return services.RestartKubeAPI(ctx, host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@@ -210,7 +210,7 @@ func (s *FullState) WriteStateFile(ctx context.Context, statePath string) error
|
|||||||
return fmt.Errorf("Failed to Marshal state object: %v", err)
|
return fmt.Errorf("Failed to Marshal state object: %v", err)
|
||||||
}
|
}
|
||||||
logrus.Tracef("Writing state file: %s", stateFile)
|
logrus.Tracef("Writing state file: %s", stateFile)
|
||||||
if err := ioutil.WriteFile(statePath, stateFile, 0600); err != nil {
|
if err := os.WriteFile(statePath, stateFile, 0600); err != nil {
|
||||||
return fmt.Errorf("Failed to write state file: %v", err)
|
return fmt.Errorf("Failed to write state file: %v", err)
|
||||||
}
|
}
|
||||||
log.Infof(ctx, "Successfully Deployed state file at [%s]", statePath)
|
log.Infof(ctx, "Successfully Deployed state file at [%s]", statePath)
|
||||||
|
@@ -55,7 +55,11 @@ func (c *Cluster) ValidateCluster(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// validate enabling Pod Security Policy
|
// validate enabling Pod Security Policy
|
||||||
if err := validatePSP(c); err != nil {
|
if err := validatePodSecurityPolicy(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// validate enabling Pod Security
|
||||||
|
if err := validatePodSecurity(c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,12 +659,13 @@ func validateCRIDockerdOption(c *Cluster) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validatePSP(c *Cluster) error {
|
func validatePodSecurityPolicy(c *Cluster) error {
|
||||||
parsedVersion, err := getClusterVersion(c.Version)
|
parsedVersion, err := getClusterVersion(c.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnf("Failed to parse semver range for validating Pod Security Policy")
|
logrus.Warnf("Failed to parse semver range for validating Pod Security Policy")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
logrus.Debugf("Checking PodSecurityPolicy for cluster version [%s]", c.Version)
|
||||||
if c.Services.KubeAPI.PodSecurityPolicy {
|
if c.Services.KubeAPI.PodSecurityPolicy {
|
||||||
if c.Authorization.Mode != services.RBACAuthorizationMode {
|
if c.Authorization.Mode != services.RBACAuthorizationMode {
|
||||||
return errors.New("PodSecurityPolicy can't be enabled with RBAC support disabled")
|
return errors.New("PodSecurityPolicy can't be enabled with RBAC support disabled")
|
||||||
@@ -672,6 +677,29 @@ func validatePSP(c *Cluster) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validatePodSecurity(c *Cluster) error {
|
||||||
|
parsedVersion, err := getClusterVersion(c.Version)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("Failed to parse semver range for validating Pod Security")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logrus.Debugf("Checking PodSecurity for cluster version [%s]", c.Version)
|
||||||
|
level := c.Services.KubeAPI.PodSecurityConfiguration
|
||||||
|
if len(level) != 0 {
|
||||||
|
if c.Authorization.Mode != services.RBACAuthorizationMode {
|
||||||
|
return errors.New("PodSecurity can't be enabled with RBAC support disabled")
|
||||||
|
}
|
||||||
|
if !parsedRangeAtLeast123(parsedVersion) {
|
||||||
|
return errors.New("cluster version must be at least v1.23 to use PodSecurity in RKE")
|
||||||
|
}
|
||||||
|
if level != PodSecurityPrivileged && level != PodSecurityRestricted {
|
||||||
|
return fmt.Errorf("invalid pod_security_configuration [%s]. Supported values: [%s, %s]",
|
||||||
|
level, PodSecurityPrivileged, PodSecurityRestricted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func getClusterVersion(version string) (semver.Version, error) {
|
func getClusterVersion(version string) (semver.Version, error) {
|
||||||
var parsedVersion semver.Version
|
var parsedVersion semver.Version
|
||||||
if len(version) <= 1 || !strings.HasPrefix(version, "v") {
|
if len(version) <= 1 || !strings.HasPrefix(version, "v") {
|
||||||
|
@@ -200,6 +200,10 @@ func ClusterUp(ctx context.Context, dialersOptions hosts.DialersOptions, flags c
|
|||||||
return APIURL, caCrt, clientCert, clientKey, nil, err
|
return APIURL, caCrt, clientCert, clientKey, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := cluster.RestartKubeAPIServerWhenConfigChanges(ctx, kubeCluster, currentCluster); err != nil {
|
||||||
|
return APIURL, caCrt, clientCert, clientKey, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if err := kubeCluster.PrePullK8sImages(ctx); err != nil {
|
if err := kubeCluster.PrePullK8sImages(ctx); err != nil {
|
||||||
return APIURL, caCrt, clientCert, clientKey, nil, err
|
return APIURL, caCrt, clientCert, clientKey, nil, err
|
||||||
}
|
}
|
||||||
|
1
go.mod
1
go.mod
@@ -40,6 +40,7 @@ require (
|
|||||||
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185
|
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185
|
||||||
k8s.io/kubectl v0.25.3
|
k8s.io/kubectl v0.25.3
|
||||||
k8s.io/kubernetes v1.13.0
|
k8s.io/kubernetes v1.13.0
|
||||||
|
k8s.io/pod-security-admission v0.25.3
|
||||||
sigs.k8s.io/yaml v1.2.0
|
sigs.k8s.io/yaml v1.2.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
2
go.sum
2
go.sum
@@ -1806,6 +1806,8 @@ k8s.io/kubectl v0.25.3/go.mod h1:glU7PiVj/R6Ud4A9FJdTcJjyzOtCJyc0eO7Mrbh3jlI=
|
|||||||
k8s.io/kubernetes v1.13.0 h1:qTfB+u5M92k2fCCCVP2iuhgwwSOv1EkAkvQY1tQODD8=
|
k8s.io/kubernetes v1.13.0 h1:qTfB+u5M92k2fCCCVP2iuhgwwSOv1EkAkvQY1tQODD8=
|
||||||
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
||||||
k8s.io/metrics v0.0.0-20191214191643-6b1944c9f765/go.mod h1:5V7rewilItwK0cz4nomU0b3XCcees2Ka5EBYWS1HBeM=
|
k8s.io/metrics v0.0.0-20191214191643-6b1944c9f765/go.mod h1:5V7rewilItwK0cz4nomU0b3XCcees2Ka5EBYWS1HBeM=
|
||||||
|
k8s.io/pod-security-admission v0.25.3 h1:2HnXWKUIDSez2sWtvxeGgGVUFvYnJJHutL4AI1MIuwk=
|
||||||
|
k8s.io/pod-security-admission v0.25.3/go.mod h1:xSaLkcMPD6cGKrZ//ZUrCNs0BewZzQdOEcC9LuXBGR4=
|
||||||
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||||
|
@@ -295,6 +295,8 @@ type KubeAPIService struct {
|
|||||||
ServiceNodePortRange string `yaml:"service_node_port_range" json:"serviceNodePortRange,omitempty" norman:"default=30000-32767"`
|
ServiceNodePortRange string `yaml:"service_node_port_range" json:"serviceNodePortRange,omitempty" norman:"default=30000-32767"`
|
||||||
// Enabled/Disable PodSecurityPolicy
|
// Enabled/Disable PodSecurityPolicy
|
||||||
PodSecurityPolicy bool `yaml:"pod_security_policy" json:"podSecurityPolicy,omitempty"`
|
PodSecurityPolicy bool `yaml:"pod_security_policy" json:"podSecurityPolicy,omitempty"`
|
||||||
|
// setting the default configuration for PodSecurityAdmission
|
||||||
|
PodSecurityConfiguration string `yaml:"pod_security_configuration" json:"podSecurityConfiguration,omitempty" norman:"default=privileged"`
|
||||||
// Enable/Disable AlwaysPullImages admissions plugin
|
// Enable/Disable AlwaysPullImages admissions plugin
|
||||||
AlwaysPullImages bool `yaml:"always_pull_images" json:"alwaysPullImages,omitempty"`
|
AlwaysPullImages bool `yaml:"always_pull_images" json:"alwaysPullImages,omitempty"`
|
||||||
// Secrets encryption provider config
|
// Secrets encryption provider config
|
||||||
@@ -920,14 +922,14 @@ type GlobalAwsOpts struct {
|
|||||||
// Security group for each ELB this security group will be used instead.
|
// Security group for each ELB this security group will be used instead.
|
||||||
ElbSecurityGroup string `json:"elb-security-group" yaml:"elb-security-group" ini:"ElbSecurityGroup,omitempty"`
|
ElbSecurityGroup string `json:"elb-security-group" yaml:"elb-security-group" ini:"ElbSecurityGroup,omitempty"`
|
||||||
|
|
||||||
// During the instantiation of an new AWS cloud provider, the detected region
|
// During the instantiation of a new AWS cloud provider, the detected region
|
||||||
// is validated against a known set of regions.
|
// is validated against a known set of regions.
|
||||||
//
|
//
|
||||||
// In a non-standard, AWS like environment (e.g. Eucalyptus), this check may
|
// In a non-standard, AWS like environment (e.g. Eucalyptus), this check may
|
||||||
// be undesirable. Setting this to true will disable the check and provide
|
// be undesirable. Setting this to true will disable the check and provide
|
||||||
// a warning that the check was skipped. Please note that this is an
|
// a warning that the check was skipped. Please note that this is an
|
||||||
// experimental feature and work-in-progress for the moment. If you find
|
// experimental feature and work-in-progress for the moment. If you find
|
||||||
// yourself in an non-AWS cloud and open an issue, please indicate that in the
|
// yourself in a non-AWS cloud and open an issue, please indicate that in the
|
||||||
// issue body.
|
// issue body.
|
||||||
DisableStrictZoneCheck bool `json:"disable-strict-zone-check" yaml:"disable-strict-zone-check" ini:"DisableStrictZoneCheck,omitempty"`
|
DisableStrictZoneCheck bool `json:"disable-strict-zone-check" yaml:"disable-strict-zone-check" ini:"DisableStrictZoneCheck,omitempty"`
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user