knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/webhook/README.md (about) 1 ## Knative Webhooks 2 3 Knative provides infrastructure for authoring webhooks under 4 `knative.dev/pkg/webhook` and has a few built-in helpers for certain common 5 admission control scenarios. The built-in admission controllers are: 6 7 1. Resource validation and defaulting (builds around `apis.Validatable` and 8 `apis.Defaultable` under `knative.dev/pkg/apis`). 9 2. ConfigMap validation, which builds around similar patterns from 10 `knative.dev/pkg/configmap` (in particular the `store` concept) 11 12 To illustrate standing up the webhook, let's start with one of these built-in 13 admission controllers and then talk about how you can write your own admission 14 controller. 15 16 ## Standing up a Webhook from an Admission Controller 17 18 We provide facilities in `knative.dev/pkg/injection/sharedmain` to try and 19 eliminate much of the boilerplate involved in standing up a webhook. For this 20 example we will show how to stand up the webhook using the built-in admission 21 controller for validating and defaulting resources. 22 23 The code to stand up such a webhook looks roughly like this: 24 25 ```go 26 // Create a function matching this signature to pass into sharedmain. 27 func NewResourceAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { 28 return validation.NewAdmissionController(ctx, 29 // Name of the resource webhook (created via yaml) 30 fmt.Sprintf("resources.webhook.%s.knative.dev", system.Namespace()), 31 32 // The path on which to serve the webhook. 33 "/resource-validation", 34 35 // The resources to validate and default. 36 map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ 37 // List the types to validate, this from knative.dev/sample-controller 38 v1alpha1.SchemeGroupVersion.WithKind("AddressableService"): &v1alpha1.AddressableService{}, 39 }, 40 41 // A function that infuses the context passed to Validate/SetDefaults with custom metadata. 42 func(ctx context.Context) context.Context { 43 // Here is where you would infuse the context with state 44 // (e.g. attach a store with configmap data, like knative.dev/serving attaches config-defaults) 45 return ctx 46 }, 47 48 // Whether to disallow unknown fields when parsing the resources' JSON. 49 true, 50 ) 51 } 52 53 func main() { 54 // Set up a signal context with our webhook options. 55 ctx := webhook.WithOptions(signals.NewContext(), webhook.Options{ 56 // The name of the Kubernetes service selecting over this deployment's pods. 57 ServiceName: "webhook", 58 59 // The port on which to serve. 60 Port: 8443, 61 62 // The name of the secret containing certificate data. 63 SecretName: "webhook-certs", 64 }) 65 66 sharedmain.MainWithContext(ctx, "webhook", 67 // The certificate controller will ensure that the named secret (above) has 68 // the appropriate shape for our webhook's admission controllers. 69 certificates.NewController, 70 71 // This invokes the method defined above to instantiate the resource admission 72 // controller. 73 NewResourceAdmissionController, 74 ) 75 } 76 ``` 77 78 There is also a config map validation admission controller built in under 79 `knative.dev/pkg/webhook/configmaps`. 80 81 ## TLS Configuration 82 83 The webhook server supports configuring TLS parameters through the `webhook.Options` struct. This allows you to control the TLS version, cipher suites, and elliptic curve preferences for enhanced security. 84 85 ### Available TLS Options 86 87 ```go 88 type Options struct { 89 // ... other fields ... 90 91 // TLSMinVersion contains the minimum TLS version that is acceptable. 92 // Default is TLS 1.3 if not specified. 93 // Supported values: tls.VersionTLS12, tls.VersionTLS13 94 TLSMinVersion uint16 95 96 // TLSMaxVersion contains the maximum TLS version that is acceptable. 97 // If not set (0), the maximum version supported by the implementation will be used. 98 // Useful for enforcing Modern profile (TLS 1.3 only) by setting both 99 // TLSMinVersion and TLSMaxVersion to tls.VersionTLS13. 100 TLSMaxVersion uint16 101 102 // TLSCipherSuites specifies the list of enabled cipher suites. 103 // If empty, a default list of secure cipher suites will be used. 104 // Note: Cipher suites are not configurable in TLS 1.3; they are 105 // determined by the implementation. 106 TLSCipherSuites []uint16 107 108 // TLSCurvePreferences specifies the elliptic curves that will be used 109 // in an ECDHE handshake. If empty, the default curves will be used. 110 TLSCurvePreferences []tls.CurveID 111 } 112 ``` 113 114 ### Environment Variable Configuration 115 116 You can also configure the minimum TLS version via the `WEBHOOK_TLS_MIN_VERSION` environment variable: 117 118 ```yaml 119 env: 120 - name: WEBHOOK_TLS_MIN_VERSION 121 value: "1.3" # or "1.2" 122 ``` 123 124 ### Usage Examples 125 126 #### Example 1: Default Configuration (Recommended) 127 128 By default, the webhook uses TLS 1.3 as the minimum version with secure defaults: 129 130 ```go 131 ctx := webhook.WithOptions(signals.NewContext(), webhook.Options{ 132 ServiceName: "webhook", 133 Port: 8443, 134 SecretName: "webhook-certs", 135 // TLS defaults: MinVersion=1.3, secure cipher suites and curves 136 }) 137 ``` 138 139 #### Example 2: Modern Profile (TLS 1.3 Only) 140 141 To enforce TLS 1.3 only (highest security profile): 142 143 ```go 144 ctx := webhook.WithOptions(signals.NewContext(), webhook.Options{ 145 ServiceName: "webhook", 146 Port: 8443, 147 SecretName: "webhook-certs", 148 TLSMinVersion: tls.VersionTLS13, 149 TLSMaxVersion: tls.VersionTLS13, // Enforce TLS 1.3 only 150 }) 151 ``` 152 153 #### Example 3: Intermediate Profile (TLS 1.2+) 154 155 For broader compatibility while maintaining security: 156 157 ```go 158 ctx := webhook.WithOptions(signals.NewContext(), webhook.Options{ 159 ServiceName: "webhook", 160 Port: 8443, 161 SecretName: "webhook-certs", 162 TLSMinVersion: tls.VersionTLS12, 163 }) 164 ``` 165 166 #### Example 4: Custom Cipher Suites 167 168 To specify custom cipher suites (for TLS 1.2): 169 170 ```go 171 ctx := webhook.WithOptions(signals.NewContext(), webhook.Options{ 172 ServiceName: "webhook", 173 Port: 8443, 174 SecretName: "webhook-certs", 175 TLSMinVersion: tls.VersionTLS12, 176 TLSCipherSuites: []uint16{ 177 tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 178 tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 179 tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 180 tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 181 }, 182 }) 183 ``` 184 185 #### Example 5: Custom Elliptic Curves 186 187 To specify elliptic curve preferences: 188 189 ```go 190 ctx := webhook.WithOptions(signals.NewContext(), webhook.Options{ 191 ServiceName: "webhook", 192 Port: 8443, 193 SecretName: "webhook-certs", 194 TLSCurvePreferences: []tls.CurveID{ 195 tls.X25519, // Preferred 196 tls.CurveP256, 197 tls.CurveP384, 198 }, 199 }) 200 ``` 201 202 #### Example 6: Complete Custom Configuration 203 204 For full control over TLS parameters: 205 206 ```go 207 ctx := webhook.WithOptions(signals.NewContext(), webhook.Options{ 208 ServiceName: "webhook", 209 Port: 8443, 210 SecretName: "webhook-certs", 211 TLSMinVersion: tls.VersionTLS12, 212 TLSMaxVersion: tls.VersionTLS13, 213 TLSCipherSuites: []uint16{ 214 tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 215 tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 216 }, 217 TLSCurvePreferences: []tls.CurveID{ 218 tls.X25519, 219 tls.CurveP256, 220 }, 221 }) 222 ``` 223 224 ## Writing new Admission Controllers 225 226 To implement your own admission controller akin to the resource defaulting and 227 validation controller above, you implement a 228 `knative.dev/pkg/controller.Reconciler` as with any you would with any other 229 type of controller, but the `Reconciler` that gets embedded in the 230 `*controller.Impl` should _also_ implement: 231 232 ```go 233 // AdmissionController provides the interface for different admission controllers 234 type AdmissionController interface { 235 // Path returns the path that this particular admission controller serves on. 236 Path() string 237 238 // Admit is the callback which is invoked when an HTTPS request comes in on Path(). 239 Admit(context.Context, *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse 240 } 241 ``` 242 243 The `Reconciler` part is responsible for the mutating or validating webhook 244 configuration. The `AdmissionController` part is responsible for guiding request 245 dispatch (`Path()`) and handling admission requests (`Admit()`).