Initial commit

This commit is contained in:
2023-07-22 06:32:44 +00:00
commit 9bb2865a65
15 changed files with 964 additions and 0 deletions

75
cmd/deploy.go Normal file
View File

@@ -0,0 +1,75 @@
package cmd
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
_ "embed"
"encoding/base64"
"encoding/pem"
"fmt"
"math/big"
"strings"
"time"
"github.com/spf13/cobra"
"go.uber.org/zap"
)
func init() {
rootCmd.AddCommand(deoplyCmd)
}
//go:embed deploy.yaml
var template string
var deoplyCmd = &cobra.Command{
Use: "deploy",
Run: func(cmd *cobra.Command, args []string) {
// 1. create ca and key for webhook
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
zap.L().Fatal("failed to generate key", zap.Error(err))
}
cfg := &x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{CommonName: fmt.Sprintf("%s.%s.svc", app, namespace)},
NotBefore: time.Now(),
NotAfter: time.Now().Add(365 * 24 * time.Hour),
BasicConstraintsValid: true,
IsCA: true,
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
DNSNames: []string{fmt.Sprintf("%s.%s.svc", app, namespace)},
}
cert, err := x509.CreateCertificate(rand.Reader, cfg, cfg, &key.PublicKey, key)
if err != nil {
zap.L().Fatal("failed to create cert", zap.Error(err))
}
template = strings.ReplaceAll(template, "NAMESPACE", namespace)
template = strings.ReplaceAll(template, "APP", app)
template = strings.ReplaceAll(template, "CA_BUNDLE", base64.StdEncoding.EncodeToString(pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: cert,
})))
template = strings.ReplaceAll(template, "KEY", base64.StdEncoding.EncodeToString(pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
})))
fmt.Println(template)
},
}
var (
namespace string
app string
)
func init() {
rootCmd.AddCommand(deoplyCmd)
deoplyCmd.PersistentFlags().StringVar(&namespace, "namespace", "default", "namespace")
deoplyCmd.PersistentFlags().StringVar(&app, "app", "default", "app")
}

88
cmd/deploy.yaml Normal file
View File

@@ -0,0 +1,88 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: APP
namespace: NAMESPACE
labels:
app: APP
spec:
replicas: 1
selector:
matchLabels:
app: APP
template:
metadata:
labels:
app: APP
spec:
containers:
- name: APP
image: gitlab.yoshino-s.xyz/yoshino-s/cilium-envoy-hook:latest
imagePullPolicy: Always
args:
- --tls-cert-file-path=/etc/webhook/certs/cert.pem
- --tls-key-file-path=/etc/webhook/certs/key.pem
ports:
- name: http
containerPort: 8080
protocol: TCP
volumeMounts:
- name: webhook-certs
mountPath: /etc/webhook/certs
readOnly: true
volumes:
- name: webhook-certs
secret:
secretName: APP-certs
---
apiVersion: v1
kind: Service
metadata:
name: APP
namespace: NAMESPACE
labels:
app: APP
spec:
ports:
- name: http
port: 443
targetPort: 8080
- name: metrics
port: 8081
targetPort: 8081
selector:
app: APP
---
# File autogenerated by ./scripts/gen-certs.sh
apiVersion: v1
data:
cert.pem: CA_BUNDLE
key.pem: KEY_PEM
kind: Secret
metadata:
creationTimestamp: null
name: APP-certs
namespace: NAMESPACE
---
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: APP
labels:
app: APP
kind: mutator
webhooks:
- name: mutator.APP.io
admissionReviewVersions: ["v1"]
sideEffects: None
clientConfig:
service:
name: APP
namespace: NAMESPACE
path: /
caBundle: CA_BUNDLE
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: ["*"]
apiVersions: ["*"]
resources: ["CiliumEnvoyConfig"]

29
cmd/root.go Normal file
View File

@@ -0,0 +1,29 @@
package cmd
import (
"github.com/spf13/cobra"
"go.uber.org/zap"
)
var rootCmd = &cobra.Command{
Use: "hook",
}
func Execute() {
if Version == "dev" {
logger, err := zap.NewDevelopment()
if err != nil {
panic(err)
}
zap.ReplaceGlobals(logger)
} else {
logger, err := zap.NewProduction()
if err != nil {
panic(err)
}
zap.ReplaceGlobals(logger)
}
if err := rootCmd.Execute(); err != nil {
zap.L().Fatal("failed to execute root command", zap.Error(err))
}
}

151
cmd/server.go Normal file
View File

@@ -0,0 +1,151 @@
package cmd
import (
"context"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/oklog/run"
"github.com/spf13/cobra"
"go.uber.org/zap"
kwhhttp "github.com/slok/kubewebhook/v2/pkg/http"
"github.com/slok/kubewebhook/v2/pkg/log"
kwhmutating "github.com/slok/kubewebhook/v2/pkg/webhook/mutating"
kwhmodel "github.com/slok/kubewebhook/v2/pkg/model"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type wrapLogger struct {
*zap.SugaredLogger
}
func (n *wrapLogger) WithValues(map[string]interface{}) log.Logger { return n }
func (n *wrapLogger) WithCtxValues(context.Context) log.Logger { return n }
func (n *wrapLogger) SetValuesOnCtx(parent context.Context, values map[string]interface{}) context.Context {
return parent
}
func (n *wrapLogger) Warningf(template string, args ...interface{}) {
n.Warnf(template, args...)
}
type CmdConfig struct {
WebhookListenAddr string
TLSCertFilePath string
TLSKeyFilePath string
EnableIngressSingleHost bool
IngressHostRegexes []string
MinSMScrapeInterval time.Duration
LabelMarks map[string]string
}
var (
cmdConfig = &CmdConfig{
LabelMarks: map[string]string{},
}
serverCmd = &cobra.Command{
Use: "server",
Run: func(cmd *cobra.Command, args []string) {
var err error
logger := zap.L()
var g run.Group
// OS signals.
{
sigC := make(chan os.Signal, 1)
exitC := make(chan struct{})
signal.Notify(sigC, syscall.SIGTERM, syscall.SIGINT)
g.Add(
func() error {
select {
case s := <-sigC:
logger.Sugar().Info("signal %s received", s)
return nil
case <-exitC:
return nil
}
},
func(_ error) {
close(exitC)
},
)
}
// Webhook HTTP server.
{
logger := logger.With(zap.String("addr", cmdConfig.WebhookListenAddr), zap.String("http-server", "webhooks"))
mt := kwhmutating.MutatorFunc(func(_ context.Context, _ *kwhmodel.AdmissionReview, obj metav1.Object) (*kwhmutating.MutatorResult, error) {
logger.Info("mutating webhook called", zap.Any("object", obj))
return &kwhmutating.MutatorResult{MutatedObject: obj}, nil
})
// Create webhook.
wh, err := kwhmutating.NewWebhook(kwhmutating.WebhookConfig{
ID: "mutator.cilium-envoy-hook.io",
Mutator: mt,
Logger: &wrapLogger{logger.Sugar()},
})
if err != nil {
logger.Fatal("error creating webhook", zap.Error(err))
}
// Get HTTP handler from webhook.
whHandler, err := kwhhttp.HandlerFor(kwhhttp.HandlerConfig{Webhook: wh, Logger: &wrapLogger{logger.Sugar()}})
if err != nil {
logger.Fatal("error creating webhook handler", zap.Error(err))
}
server := &http.Server{
Addr: cmdConfig.WebhookListenAddr,
Handler: whHandler,
}
g.Add(
func() error {
if cmdConfig.TLSCertFilePath == "" || cmdConfig.TLSKeyFilePath == "" {
logger.Warn("webhook running without TLS")
logger.Info("http server listening...")
return server.ListenAndServe()
}
logger.Info("https server listening...")
return server.ListenAndServeTLS(cmdConfig.TLSCertFilePath, cmdConfig.TLSKeyFilePath)
},
func(_ error) {
logger.Info("start draining connections")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
err := server.Shutdown(ctx)
if err != nil {
logger.Error("error while shutting down the server", zap.Error(err))
} else {
logger.Info("server stopped")
}
},
)
}
err = g.Run()
if err != nil {
logger.Fatal("error while running the application", zap.Error(err))
}
},
}
)
func init() {
rootCmd.AddCommand(serverCmd)
serverCmd.PersistentFlags().StringVar(&cmdConfig.WebhookListenAddr, "webhook-listen-address", ":8080", "The address where the HTTPS server will be listening to serve the webhooks.")
serverCmd.PersistentFlags().StringVar(&cmdConfig.TLSCertFilePath, "tls-cert-file-path", "", "The path for the webhook HTTPS server TLS cert file.")
serverCmd.PersistentFlags().StringVar(&cmdConfig.TLSKeyFilePath, "tls-key-file-path", "", "The path for the webhook HTTPS server TLS key file.")
}

24
cmd/version.go Normal file
View File

@@ -0,0 +1,24 @@
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
var (
// Version is set at compile time.
Version = "dev"
)
func init() {
rootCmd.AddCommand(versionCmd)
}
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(Version)
},
}