1
0
mirror of https://github.com/rancher/rke.git synced 2025-08-27 10:58:32 +00:00
rke/cluster/defaults.go
Erik Wilson e04b7d4413 Add support for Kubernetes API Authn Webhook
Allow multiple authn strategies to be defined, including new 'webhook'
strategy. Webhook strategy configuration contains the contents of the
authentication webhook file as well as the cache timeout period.

This change allows a Kubernetes API Auth service to authenticate
user requests without proxying through the Rancher server.
2019-01-03 17:15:23 -07:00

331 lines
11 KiB
Go

package cluster
import (
"context"
"fmt"
"strings"
"github.com/rancher/rke/cloudprovider"
"github.com/rancher/rke/docker"
"github.com/rancher/rke/k8s"
"github.com/rancher/rke/log"
"github.com/rancher/rke/services"
"github.com/rancher/rke/templates"
"github.com/rancher/types/apis/management.cattle.io/v3"
)
const (
DefaultServiceClusterIPRange = "10.43.0.0/16"
DefaultNodePortRange = "30000-32767"
DefaultClusterCIDR = "10.42.0.0/16"
DefaultClusterDNSService = "10.43.0.10"
DefaultClusterDomain = "cluster.local"
DefaultClusterName = "local"
DefaultClusterSSHKeyPath = "~/.ssh/id_rsa"
DefaultK8sVersion = v3.DefaultK8s
DefaultSSHPort = "22"
DefaultDockerSockPath = "/var/run/docker.sock"
DefaultAuthStrategy = "x509"
DefaultAuthorizationMode = "rbac"
DefaultAuthnWebhookFile = templates.AuthnWebhook
DefaultAuthnCacheTimeout = "5s"
DefaultNetworkPlugin = "canal"
DefaultNetworkCloudProvider = "none"
DefaultIngressController = "nginx"
DefaultEtcdBackupCreationPeriod = "12h"
DefaultEtcdBackupRetentionPeriod = "72h"
DefaultEtcdSnapshot = true
DefaultMonitoringProvider = "metrics-server"
DefaultEtcdHeartbeatIntervalName = "heartbeat-interval"
DefaultEtcdHeartbeatIntervalValue = "500"
DefaultEtcdElectionTimeoutName = "election-timeout"
DefaultEtcdElectionTimeoutValue = "5000"
)
type ExternalFlags struct {
ConfigDir string
ClusterFilePath string
DisablePortCheck bool
Local bool
UpdateOnly bool
}
func setDefaultIfEmptyMapValue(configMap map[string]string, key string, value string) {
if _, ok := configMap[key]; !ok {
configMap[key] = value
}
}
func setDefaultIfEmpty(varName *string, defaultValue string) {
if len(*varName) == 0 {
*varName = defaultValue
}
}
func (c *Cluster) setClusterDefaults(ctx context.Context) {
if len(c.SSHKeyPath) == 0 {
c.SSHKeyPath = DefaultClusterSSHKeyPath
}
// Default Path prefix
if len(c.PrefixPath) == 0 {
c.PrefixPath = "/"
}
// Set bastion/jump host defaults
if len(c.BastionHost.Address) > 0 {
if len(c.BastionHost.Port) == 0 {
c.BastionHost.Port = DefaultSSHPort
}
if len(c.BastionHost.SSHKeyPath) == 0 {
c.BastionHost.SSHKeyPath = c.SSHKeyPath
}
c.BastionHost.SSHAgentAuth = c.SSHAgentAuth
}
for i, host := range c.Nodes {
if len(host.InternalAddress) == 0 {
c.Nodes[i].InternalAddress = c.Nodes[i].Address
}
if len(host.HostnameOverride) == 0 {
// This is a temporary modification
c.Nodes[i].HostnameOverride = c.Nodes[i].Address
}
if len(host.SSHKeyPath) == 0 {
c.Nodes[i].SSHKeyPath = c.SSHKeyPath
}
if len(host.Port) == 0 {
c.Nodes[i].Port = DefaultSSHPort
}
c.Nodes[i].HostnameOverride = strings.ToLower(c.Nodes[i].HostnameOverride)
// For now, you can set at the global level only.
c.Nodes[i].SSHAgentAuth = c.SSHAgentAuth
}
if len(c.Authorization.Mode) == 0 {
c.Authorization.Mode = DefaultAuthorizationMode
}
if c.Services.KubeAPI.PodSecurityPolicy && c.Authorization.Mode != services.RBACAuthorizationMode {
log.Warnf(ctx, "PodSecurityPolicy can't be enabled with RBAC support disabled")
c.Services.KubeAPI.PodSecurityPolicy = false
}
if len(c.Ingress.Provider) == 0 {
c.Ingress.Provider = DefaultIngressController
}
if len(c.ClusterName) == 0 {
c.ClusterName = DefaultClusterName
}
if len(c.Version) == 0 {
c.Version = DefaultK8sVersion
}
if c.AddonJobTimeout == 0 {
c.AddonJobTimeout = k8s.DefaultTimeout
}
if len(c.Monitoring.Provider) == 0 {
c.Monitoring.Provider = DefaultMonitoringProvider
}
//set docker private registry URL
for _, pr := range c.PrivateRegistries {
if pr.URL == "" {
pr.URL = docker.DockerRegistryURL
}
c.PrivateRegistriesMap[pr.URL] = pr
}
c.setClusterImageDefaults()
c.setClusterServicesDefaults()
c.setClusterNetworkDefaults()
c.setClusterAuthnDefaults()
}
func (c *Cluster) setClusterServicesDefaults() {
// We don't accept per service images anymore.
c.Services.KubeAPI.Image = c.SystemImages.Kubernetes
c.Services.Scheduler.Image = c.SystemImages.Kubernetes
c.Services.KubeController.Image = c.SystemImages.Kubernetes
c.Services.Kubelet.Image = c.SystemImages.Kubernetes
c.Services.Kubeproxy.Image = c.SystemImages.Kubernetes
c.Services.Etcd.Image = c.SystemImages.Etcd
// enable etcd snapshots by default
if c.Services.Etcd.Snapshot == nil {
defaultSnapshot := DefaultEtcdSnapshot
c.Services.Etcd.Snapshot = &defaultSnapshot
}
serviceConfigDefaultsMap := map[*string]string{
&c.Services.KubeAPI.ServiceClusterIPRange: DefaultServiceClusterIPRange,
&c.Services.KubeAPI.ServiceNodePortRange: DefaultNodePortRange,
&c.Services.KubeController.ServiceClusterIPRange: DefaultServiceClusterIPRange,
&c.Services.KubeController.ClusterCIDR: DefaultClusterCIDR,
&c.Services.Kubelet.ClusterDNSServer: DefaultClusterDNSService,
&c.Services.Kubelet.ClusterDomain: DefaultClusterDomain,
&c.Services.Kubelet.InfraContainerImage: c.SystemImages.PodInfraContainer,
&c.Services.Etcd.Creation: DefaultEtcdBackupCreationPeriod,
&c.Services.Etcd.Retention: DefaultEtcdBackupRetentionPeriod,
}
for k, v := range serviceConfigDefaultsMap {
setDefaultIfEmpty(k, v)
}
// Add etcd timeouts
if c.Services.Etcd.ExtraArgs == nil {
c.Services.Etcd.ExtraArgs = make(map[string]string)
}
if _, ok := c.Services.Etcd.ExtraArgs[DefaultEtcdElectionTimeoutName]; !ok {
c.Services.Etcd.ExtraArgs[DefaultEtcdElectionTimeoutName] = DefaultEtcdElectionTimeoutValue
}
if _, ok := c.Services.Etcd.ExtraArgs[DefaultEtcdHeartbeatIntervalName]; !ok {
c.Services.Etcd.ExtraArgs[DefaultEtcdHeartbeatIntervalName] = DefaultEtcdHeartbeatIntervalValue
}
}
func (c *Cluster) setClusterImageDefaults() {
var privRegURL string
imageDefaults, ok := v3.K8sVersionToRKESystemImages[c.Version]
if !ok {
imageDefaults = v3.K8sVersionToRKESystemImages[DefaultK8sVersion]
}
for _, privReg := range c.PrivateRegistries {
if privReg.IsDefault {
privRegURL = privReg.URL
break
}
}
systemImagesDefaultsMap := map[*string]string{
&c.SystemImages.Alpine: d(imageDefaults.Alpine, privRegURL),
&c.SystemImages.NginxProxy: d(imageDefaults.NginxProxy, privRegURL),
&c.SystemImages.CertDownloader: d(imageDefaults.CertDownloader, privRegURL),
&c.SystemImages.KubeDNS: d(imageDefaults.KubeDNS, privRegURL),
&c.SystemImages.KubeDNSSidecar: d(imageDefaults.KubeDNSSidecar, privRegURL),
&c.SystemImages.DNSmasq: d(imageDefaults.DNSmasq, privRegURL),
&c.SystemImages.KubeDNSAutoscaler: d(imageDefaults.KubeDNSAutoscaler, privRegURL),
&c.SystemImages.KubernetesServicesSidecar: d(imageDefaults.KubernetesServicesSidecar, privRegURL),
&c.SystemImages.Etcd: d(imageDefaults.Etcd, privRegURL),
&c.SystemImages.Kubernetes: d(imageDefaults.Kubernetes, privRegURL),
&c.SystemImages.PodInfraContainer: d(imageDefaults.PodInfraContainer, privRegURL),
&c.SystemImages.Flannel: d(imageDefaults.Flannel, privRegURL),
&c.SystemImages.FlannelCNI: d(imageDefaults.FlannelCNI, privRegURL),
&c.SystemImages.CalicoNode: d(imageDefaults.CalicoNode, privRegURL),
&c.SystemImages.CalicoCNI: d(imageDefaults.CalicoCNI, privRegURL),
&c.SystemImages.CalicoCtl: d(imageDefaults.CalicoCtl, privRegURL),
&c.SystemImages.CanalNode: d(imageDefaults.CanalNode, privRegURL),
&c.SystemImages.CanalCNI: d(imageDefaults.CanalCNI, privRegURL),
&c.SystemImages.CanalFlannel: d(imageDefaults.CanalFlannel, privRegURL),
&c.SystemImages.WeaveNode: d(imageDefaults.WeaveNode, privRegURL),
&c.SystemImages.WeaveCNI: d(imageDefaults.WeaveCNI, privRegURL),
&c.SystemImages.Ingress: d(imageDefaults.Ingress, privRegURL),
&c.SystemImages.IngressBackend: d(imageDefaults.IngressBackend, privRegURL),
&c.SystemImages.MetricsServer: d(imageDefaults.MetricsServer, privRegURL),
}
for k, v := range systemImagesDefaultsMap {
setDefaultIfEmpty(k, v)
}
}
func (c *Cluster) setClusterNetworkDefaults() {
setDefaultIfEmpty(&c.Network.Plugin, DefaultNetworkPlugin)
if c.Network.Options == nil {
// don't break if the user didn't define options
c.Network.Options = make(map[string]string)
}
networkPluginConfigDefaultsMap := make(map[string]string)
// This is still needed because RKE doesn't use c.Network.*NetworkProvider, that's a rancher type
switch c.Network.Plugin {
case CalicoNetworkPlugin:
networkPluginConfigDefaultsMap = map[string]string{
CalicoCloudProvider: DefaultNetworkCloudProvider,
}
case FlannelNetworkPlugin:
networkPluginConfigDefaultsMap = map[string]string{
FlannelBackendType: "vxlan",
}
case CanalNetworkPlugin:
networkPluginConfigDefaultsMap = map[string]string{
CanalFlannelBackendType: "vxlan",
}
}
if c.Network.CalicoNetworkProvider != nil {
setDefaultIfEmpty(&c.Network.CalicoNetworkProvider.CloudProvider, DefaultNetworkCloudProvider)
networkPluginConfigDefaultsMap[CalicoCloudProvider] = c.Network.CalicoNetworkProvider.CloudProvider
}
if c.Network.FlannelNetworkProvider != nil {
networkPluginConfigDefaultsMap[FlannelIface] = c.Network.FlannelNetworkProvider.Iface
}
if c.Network.CanalNetworkProvider != nil {
networkPluginConfigDefaultsMap[CanalIface] = c.Network.CanalNetworkProvider.Iface
}
if c.Network.WeaveNetworkProvider != nil {
networkPluginConfigDefaultsMap[WeavePassword] = c.Network.WeaveNetworkProvider.Password
}
for k, v := range networkPluginConfigDefaultsMap {
setDefaultIfEmptyMapValue(c.Network.Options, k, v)
}
}
func (c *Cluster) setClusterAuthnDefaults() {
setDefaultIfEmpty(&c.Authentication.Strategy, DefaultAuthStrategy)
for _, strategy := range strings.Split(c.Authentication.Strategy, "|") {
strategy = strings.ToLower(strings.TrimSpace(strategy))
c.AuthnStrategies[strategy] = true
}
if c.AuthnStrategies[AuthnWebhookProvider] && c.Authentication.Webhook == nil {
c.Authentication.Webhook = &v3.AuthWebhookConfig{}
}
if c.Authentication.Webhook != nil {
webhookConfigDefaultsMap := map[*string]string{
&c.Authentication.Webhook.ConfigFile: DefaultAuthnWebhookFile,
&c.Authentication.Webhook.CacheTimeout: DefaultAuthnCacheTimeout,
}
for k, v := range webhookConfigDefaultsMap {
setDefaultIfEmpty(k, v)
}
}
}
func d(image, defaultRegistryURL string) string {
if len(defaultRegistryURL) == 0 {
return image
}
return fmt.Sprintf("%s/%s", defaultRegistryURL, image)
}
func (c *Cluster) setCloudProvider() error {
p, err := cloudprovider.InitCloudProvider(c.CloudProvider)
if err != nil {
return fmt.Errorf("Failed to initialize cloud provider: %v", err)
}
if p != nil {
c.CloudConfigFile, err = p.GenerateCloudConfigFile()
if err != nil {
return fmt.Errorf("Failed to parse cloud config file: %v", err)
}
c.CloudProvider.Name = p.GetName()
if c.CloudProvider.Name == "" {
return fmt.Errorf("Name of the cloud provider is not defined for custom provider")
}
}
return nil
}
func GetExternalFlags(local, updateOnly, disablePortCheck bool, configDir, clusterFilePath string) ExternalFlags {
return ExternalFlags{
Local: local,
UpdateOnly: updateOnly,
DisablePortCheck: disablePortCheck,
ConfigDir: configDir,
ClusterFilePath: clusterFilePath,
}
}