summaryrefslogtreecommitdiffhomepage
path: root/webhook/pkg/cli
diff options
context:
space:
mode:
authorKevin Krakauer <krakauer@google.com>2020-10-30 12:00:11 -0700
committergVisor bot <gvisor-bot@google.com>2020-10-30 12:02:09 -0700
commitd66aebb15a5804f84240dccac55cd56b1dde15e5 (patch)
tree02bcd8f1b070a773093b93eafbd8e0bb59d17e09 /webhook/pkg/cli
parent3a6f046ae8d852210ae2b82ba35e9a8c2e6757b9 (diff)
Add the gVisor admission webhook
PiperOrigin-RevId: 339913577
Diffstat (limited to 'webhook/pkg/cli')
-rw-r--r--webhook/pkg/cli/BUILD17
-rw-r--r--webhook/pkg/cli/cli.go115
2 files changed, 132 insertions, 0 deletions
diff --git a/webhook/pkg/cli/BUILD b/webhook/pkg/cli/BUILD
new file mode 100644
index 000000000..ac093c556
--- /dev/null
+++ b/webhook/pkg/cli/BUILD
@@ -0,0 +1,17 @@
+load("//tools:defs.bzl", "go_library")
+
+package(licenses = ["notice"])
+
+go_library(
+ name = "cli",
+ srcs = ["cli.go"],
+ visibility = ["//:sandbox"],
+ deps = [
+ "//pkg/log",
+ "//webhook/pkg/injector",
+ "@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
+ "@io_k8s_apimachinery//pkg/util/net:go_default_library",
+ "@io_k8s_client_go//kubernetes:go_default_library",
+ "@io_k8s_client_go//rest:go_default_library",
+ ],
+)
diff --git a/webhook/pkg/cli/cli.go b/webhook/pkg/cli/cli.go
new file mode 100644
index 000000000..a07d341a2
--- /dev/null
+++ b/webhook/pkg/cli/cli.go
@@ -0,0 +1,115 @@
+// Copyright 2020 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package cli provides a CLI interface for a mutating Kubernetes webhook.
+package cli
+
+import (
+ "flag"
+ "fmt"
+ "net"
+ "net/http"
+ "os"
+ "strconv"
+ "strings"
+
+ "gvisor.dev/gvisor/pkg/log"
+ "gvisor.dev/gvisor/webhook/pkg/injector"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ k8snet "k8s.io/apimachinery/pkg/util/net"
+ "k8s.io/client-go/kubernetes"
+ "k8s.io/client-go/rest"
+)
+
+var (
+ address = flag.String("address", "", "The ip address the admission webhook serves on. If unspecified, a public address is selected automatically.")
+ port = flag.Int("port", 0, "The port the admission webhook serves on.")
+ podLabels = flag.String("pod-namespace-labels", "", "A comma-separated namespace label selector, the admission webhook will only take effect on pods in selected namespaces, e.g. `label1,label2`.")
+)
+
+// Main runs the webhook.
+func Main() {
+ flag.Parse()
+
+ if err := run(); err != nil {
+ log.Warningf("%v", err)
+ os.Exit(1)
+ }
+}
+
+func run() error {
+ log.Infof("Starting %s\n", injector.Name)
+
+ // Create client config.
+ cfg, err := rest.InClusterConfig()
+ if err != nil {
+ return fmt.Errorf("create in cluster config: %w", err)
+ }
+
+ // Create clientset.
+ clientset, err := kubernetes.NewForConfig(cfg)
+ if err != nil {
+ return fmt.Errorf("create kubernetes client: %w", err)
+ }
+
+ if err := injector.CreateConfiguration(clientset, parsePodLabels()); err != nil {
+ return fmt.Errorf("create webhook configuration: %w", err)
+ }
+
+ if err := startWebhookHTTPS(clientset); err != nil {
+ return fmt.Errorf("start webhook https server: %w", err)
+ }
+
+ return nil
+}
+
+func parsePodLabels() *metav1.LabelSelector {
+ rv := &metav1.LabelSelector{}
+ for _, s := range strings.Split(*podLabels, ",") {
+ req := metav1.LabelSelectorRequirement{
+ Key: strings.TrimSpace(s),
+ Operator: "Exists",
+ }
+ rv.MatchExpressions = append(rv.MatchExpressions, req)
+ }
+ return rv
+}
+
+func startWebhookHTTPS(clientset kubernetes.Interface) error {
+ log.Infof("Starting HTTPS handler")
+ defer log.Infof("Stopping HTTPS handler")
+
+ if *address == "" {
+ ip, err := k8snet.ChooseHostInterface()
+ if err != nil {
+ return fmt.Errorf("select ip address: %w", err)
+ }
+ *address = ip.String()
+ }
+ mux := http.NewServeMux()
+ mux.Handle("/", http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ injector.Admit(w, r)
+ }))
+ server := &http.Server{
+ // Listen on all addresses.
+ Addr: net.JoinHostPort(*address, strconv.Itoa(*port)),
+ TLSConfig: injector.GetTLSConfig(),
+ Handler: mux,
+ }
+ if err := server.ListenAndServeTLS("", ""); err != http.ErrServerClosed {
+ return fmt.Errorf("start HTTPS handler: %w", err)
+ }
+ return nil
+}