diff --git a/cmd/nginx/flags.go b/cmd/nginx/flags.go index 5ef2b19b3..73aaeecc3 100644 --- a/cmd/nginx/flags.go +++ b/cmd/nginx/flags.go @@ -44,6 +44,10 @@ func parseFlags() (bool, *controller.Configuration, error) { Takes the form "protocol://address:port". If not specified, it is assumed the program runs inside a Kubernetes cluster and local discovery is attempted.`) + rootCAFile = flags.String("certificate-authority", "", + `Path to a cert file for the certificate authority. This certificate is used +only when the flag --apiserver-host is specified.`) + kubeConfigFile = flags.String("kubeconfig", "", `Path to a kubeconfig file containing authorization and API server information.`) @@ -289,5 +293,9 @@ Takes the form ":port". If not provided, no admission controller is starte ValidationWebhookKeyPath: *validationWebhookKey, } + if *apiserverHost != "" { + config.RootCAFile = *rootCAFile + } + return false, config, nil } diff --git a/cmd/nginx/main.go b/cmd/nginx/main.go index b8d40c11c..2fa1c85a4 100644 --- a/cmd/nginx/main.go +++ b/cmd/nginx/main.go @@ -36,7 +36,9 @@ import ( discovery "k8s.io/apimachinery/pkg/version" "k8s.io/apiserver/pkg/server/healthz" "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + certutil "k8s.io/client-go/util/cert" "k8s.io/klog" "k8s.io/ingress-nginx/internal/file" @@ -69,7 +71,7 @@ func main() { klog.Fatal(err) } - kubeClient, err := createApiserverClient(conf.APIServerHost, conf.KubeConfigFile) + kubeClient, err := createApiserverClient(conf.APIServerHost, conf.RootCAFile, conf.KubeConfigFile) if err != nil { handleFatalInitError(err) } @@ -173,12 +175,24 @@ func handleSigterm(ngx *controller.NGINXController, exit exiter) { // If neither apiserverHost nor kubeConfig is passed in, we assume the // controller runs inside Kubernetes and fallback to the in-cluster config. If // the in-cluster config is missing or fails, we fallback to the default config. -func createApiserverClient(apiserverHost, kubeConfig string) (*kubernetes.Clientset, error) { +func createApiserverClient(apiserverHost, rootCAFile, kubeConfig string) (*kubernetes.Clientset, error) { cfg, err := clientcmd.BuildConfigFromFlags(apiserverHost, kubeConfig) if err != nil { return nil, err } + if apiserverHost != "" && rootCAFile != "" { + tlsClientConfig := rest.TLSClientConfig{} + + if _, err := certutil.NewPool(rootCAFile); err != nil { + klog.Errorf("Expected to load root CA config from %s, but got err: %v", rootCAFile, err) + } else { + tlsClientConfig.CAFile = rootCAFile + } + + cfg.TLSClientConfig = tlsClientConfig + } + klog.Infof("Creating API client for %s", cfg.Host) client, err := kubernetes.NewForConfig(cfg) diff --git a/cmd/nginx/main_test.go b/cmd/nginx/main_test.go index ef674d27f..a3b6a6b20 100644 --- a/cmd/nginx/main_test.go +++ b/cmd/nginx/main_test.go @@ -34,7 +34,7 @@ import ( ) func TestCreateApiserverClient(t *testing.T) { - _, err := createApiserverClient("", "") + _, err := createApiserverClient("", "", "") if err == nil { t.Fatal("Expected an error creating REST client without an API server URL or kubeconfig file.") } diff --git a/internal/ingress/controller/controller.go b/internal/ingress/controller/controller.go index 05e9ac581..13d484d96 100644 --- a/internal/ingress/controller/controller.go +++ b/internal/ingress/controller/controller.go @@ -49,9 +49,12 @@ const ( // Configuration contains all the settings required by an Ingress controller type Configuration struct { - APIServerHost string + APIServerHost string + RootCAFile string + KubeConfigFile string - Client clientset.Interface + + Client clientset.Interface ResyncPeriod time.Duration