mirror of
https://github.com/rancher/rke.git
synced 2025-08-08 02:14:30 +00:00
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.
166 lines
5.4 KiB
Go
166 lines
5.4 KiB
Go
package cluster
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/rancher/rke/services"
|
|
"k8s.io/apimachinery/pkg/util/validation"
|
|
)
|
|
|
|
func (c *Cluster) ValidateCluster() error {
|
|
// validate duplicate nodes
|
|
if err := validateDuplicateNodes(c); err != nil {
|
|
return err
|
|
}
|
|
|
|
// validate hosts options
|
|
if err := validateHostsOptions(c); err != nil {
|
|
return err
|
|
}
|
|
|
|
// validate Auth options
|
|
if err := validateAuthOptions(c); err != nil {
|
|
return err
|
|
}
|
|
|
|
// validate Network options
|
|
if err := validateNetworkOptions(c); err != nil {
|
|
return err
|
|
}
|
|
|
|
// validate Ingress options
|
|
if err := validateIngressOptions(c); err != nil {
|
|
return err
|
|
}
|
|
|
|
// validate services options
|
|
return validateServicesOptions(c)
|
|
}
|
|
|
|
func validateAuthOptions(c *Cluster) error {
|
|
for strategy, enabled := range c.AuthnStrategies {
|
|
if !enabled {
|
|
continue
|
|
}
|
|
strategy = strings.ToLower(strategy)
|
|
if strategy != AuthnX509Provider && strategy != AuthnWebhookProvider {
|
|
return fmt.Errorf("Authentication strategy [%s] is not supported", strategy)
|
|
}
|
|
}
|
|
if !c.AuthnStrategies[AuthnX509Provider] {
|
|
return fmt.Errorf("Authentication strategy must contain [%s]", AuthnX509Provider)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateNetworkOptions(c *Cluster) error {
|
|
if c.Network.Plugin != NoNetworkPlugin && c.Network.Plugin != FlannelNetworkPlugin && c.Network.Plugin != CalicoNetworkPlugin && c.Network.Plugin != CanalNetworkPlugin && c.Network.Plugin != WeaveNetworkPlugin {
|
|
return fmt.Errorf("Network plugin [%s] is not supported", c.Network.Plugin)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateHostsOptions(c *Cluster) error {
|
|
for i, host := range c.Nodes {
|
|
if len(host.Address) == 0 {
|
|
return fmt.Errorf("Address for host (%d) is not provided", i+1)
|
|
}
|
|
if len(host.User) == 0 {
|
|
return fmt.Errorf("User for host (%d) is not provided", i+1)
|
|
}
|
|
if len(host.Role) == 0 {
|
|
return fmt.Errorf("Role for host (%d) is not provided", i+1)
|
|
}
|
|
if errs := validation.IsDNS1123Subdomain(host.HostnameOverride); len(errs) > 0 {
|
|
return fmt.Errorf("Hostname_override [%s] for host (%d) is not valid: %v", host.HostnameOverride, i+1, errs)
|
|
}
|
|
for _, role := range host.Role {
|
|
if role != services.ETCDRole && role != services.ControlRole && role != services.WorkerRole {
|
|
return fmt.Errorf("Role [%s] for host (%d) is not recognized", role, i+1)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateServicesOptions(c *Cluster) error {
|
|
servicesOptions := map[string]string{
|
|
"etcd_image": c.Services.Etcd.Image,
|
|
"kube_api_image": c.Services.KubeAPI.Image,
|
|
"kube_api_service_cluster_ip_range": c.Services.KubeAPI.ServiceClusterIPRange,
|
|
"kube_controller_image": c.Services.KubeController.Image,
|
|
"kube_controller_service_cluster_ip_range": c.Services.KubeController.ServiceClusterIPRange,
|
|
"kube_controller_cluster_cidr": c.Services.KubeController.ClusterCIDR,
|
|
"scheduler_image": c.Services.Scheduler.Image,
|
|
"kubelet_image": c.Services.Kubelet.Image,
|
|
"kubelet_cluster_dns_service": c.Services.Kubelet.ClusterDNSServer,
|
|
"kubelet_cluster_domain": c.Services.Kubelet.ClusterDomain,
|
|
"kubelet_infra_container_image": c.Services.Kubelet.InfraContainerImage,
|
|
"kubeproxy_image": c.Services.Kubeproxy.Image,
|
|
}
|
|
for optionName, OptionValue := range servicesOptions {
|
|
if len(OptionValue) == 0 {
|
|
return fmt.Errorf("%s can't be empty", strings.Join(strings.Split(optionName, "_"), " "))
|
|
}
|
|
}
|
|
// Validate external etcd information
|
|
if len(c.Services.Etcd.ExternalURLs) > 0 {
|
|
if len(c.Services.Etcd.CACert) == 0 {
|
|
return fmt.Errorf("External CA Certificate for etcd can't be empty")
|
|
}
|
|
if len(c.Services.Etcd.Cert) == 0 {
|
|
return fmt.Errorf("External Client Certificate for etcd can't be empty")
|
|
}
|
|
if len(c.Services.Etcd.Key) == 0 {
|
|
return fmt.Errorf("External Client Key for etcd can't be empty")
|
|
}
|
|
if len(c.Services.Etcd.Path) == 0 {
|
|
return fmt.Errorf("External etcd path can't be empty")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateIngressOptions(c *Cluster) error {
|
|
// Should be changed when adding more ingress types
|
|
if c.Ingress.Provider != DefaultIngressController && c.Ingress.Provider != "none" {
|
|
return fmt.Errorf("Ingress controller %s is incorrect", c.Ingress.Provider)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ValidateHostCount(c *Cluster) error {
|
|
if len(c.EtcdHosts) == 0 && len(c.Services.Etcd.ExternalURLs) == 0 {
|
|
failedEtcdHosts := []string{}
|
|
for _, host := range c.InactiveHosts {
|
|
if host.IsEtcd {
|
|
failedEtcdHosts = append(failedEtcdHosts, host.Address)
|
|
}
|
|
return fmt.Errorf("Cluster must have at least one etcd plane host: failed to connect to the following etcd host(s) %v", failedEtcdHosts)
|
|
}
|
|
return fmt.Errorf("Cluster must have at least one etcd plane host: please specify one or more etcd in cluster config")
|
|
}
|
|
if len(c.EtcdHosts) > 0 && len(c.Services.Etcd.ExternalURLs) > 0 {
|
|
return fmt.Errorf("Cluster can't have both internal and external etcd")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateDuplicateNodes(c *Cluster) error {
|
|
for i := range c.Nodes {
|
|
for j := range c.Nodes {
|
|
if i == j {
|
|
continue
|
|
}
|
|
if c.Nodes[i].Address == c.Nodes[j].Address {
|
|
return fmt.Errorf("Cluster can't have duplicate node: %s", c.Nodes[i].Address)
|
|
}
|
|
if c.Nodes[i].HostnameOverride == c.Nodes[j].HostnameOverride {
|
|
return fmt.Errorf("Cluster can't have duplicate node: %s", c.Nodes[i].HostnameOverride)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|