Skip to content

Commit

Permalink
Set host for http health checker explicitly to avoid using the cluste…
Browse files Browse the repository at this point in the history
…r name as host header for http health checking request. (#3057)

* Set host for http health checker explictly to avoid using the cluster name as host header for http health checking request

Signed-off-by: lemonlinger <[email protected]>

* fix broken tests

Signed-off-by: lemonlinger <[email protected]>

* fix health-check test case in xds translation

Signed-off-by: lemonlinger <[email protected]>

* Simplify code and concise comments

Signed-off-by: lemonlinger <[email protected]>

---------

Signed-off-by: lemonlinger <[email protected]>
  • Loading branch information
lemonlinger authored Apr 2, 2024
1 parent 36d7141 commit 8f450a9
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 0 deletions.
5 changes: 5 additions & 0 deletions internal/gatewayapi/backendtrafficpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ func (t *Translator) translateBackendTrafficPolicyForRoute(policy *egv1a1.Backen
r.LoadBalancer = lb
r.ProxyProtocol = pp
r.HealthCheck = hc
// Update the Host field in HealthCheck, now that we have access to the Route Hostname.
r.HealthCheck.SetHTTPHostIfAbsent(r.Hostname)
r.CircuitBreaker = cb
r.FaultInjection = fi
r.TCPKeepalive = ka
Expand Down Expand Up @@ -532,7 +534,10 @@ func (t *Translator) translateBackendTrafficPolicyForGateway(policy *egv1a1.Back
}
if r.HealthCheck == nil {
r.HealthCheck = hc
// Update the Host field in HealthCheck, now that we have access to the Route Hostname.
r.HealthCheck.SetHTTPHostIfAbsent(r.Hostname)
}

if r.CircuitBreaker == nil {
r.CircuitBreaker = cb
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ xdsIR:
expectedStatuses:
- 200
- 300
host: '*'
method: GET
path: /healthz
interval: 3s
Expand Down Expand Up @@ -624,6 +625,7 @@ xdsIR:
expectedStatuses:
- 200
- 201
host: gateway.envoyproxy.io
method: GET
path: /healthz
interval: 5s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ xdsIR:
expectedStatuses:
- 200
- 300
host: ""
method: GET
path: /healthz
interval: 3s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ xdsIR:
expectedStatuses:
- 200
- 300
host: ""
method: GET
path: /healthz
interval: 3s
Expand Down
12 changes: 12 additions & 0 deletions internal/ir/xds.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ var (
ErrHealthCheckUnhealthyThresholdInvalid = errors.New("field HealthCheck.UnhealthyThreshold should be greater than 0")
ErrHealthCheckHealthyThresholdInvalid = errors.New("field HealthCheck.HealthyThreshold should be greater than 0")
ErrHealthCheckerInvalid = errors.New("health checker setting is invalid, only one health checker can be set")
ErrHCHTTPHostInvalid = errors.New("field HTTPHealthChecker.Host should be specified")
ErrHCHTTPPathInvalid = errors.New("field HTTPHealthChecker.Path should be specified")
ErrHCHTTPMethodInvalid = errors.New("only one of the GET, HEAD, POST, DELETE, OPTIONS, TRACE, PATCH of HTTPHealthChecker.Method could be set")
ErrHCHTTPExpectedStatusesInvalid = errors.New("field HTTPHealthChecker.ExpectedStatuses should be specified")
Expand Down Expand Up @@ -1551,6 +1552,12 @@ type ActiveHealthCheck struct {
TCP *TCPHealthChecker `json:"tcp,omitempty" yaml:"tcp,omitempty"`
}

func (h *HealthCheck) SetHTTPHostIfAbsent(host string) {
if h != nil && h.Active != nil && h.Active.HTTP != nil && h.Active.HTTP.Host == "" {
h.Active.HTTP.Host = host
}
}

// Validate the fields within the HealthCheck structure.
func (h *HealthCheck) Validate() error {
var errs error
Expand Down Expand Up @@ -1607,6 +1614,8 @@ func (h *HealthCheck) Validate() error {
// HTTPHealthChecker defines the settings of http health check.
// +k8s:deepcopy-gen=true
type HTTPHealthChecker struct {
// Host defines the value of the host header in the HTTP health check request.
Host string `json:"host" yaml:"host"`
// Path defines the HTTP path that will be requested during health checking.
Path string `json:"path" yaml:"path"`
// Method defines the HTTP method used for health checking.
Expand All @@ -1620,6 +1629,9 @@ type HTTPHealthChecker struct {
// Validate the fields within the HTTPHealthChecker structure.
func (c *HTTPHealthChecker) Validate() error {
var errs error
if c.Host == "" {
errs = errors.Join(errs, ErrHCHTTPHostInvalid)
}
if c.Path == "" {
errs = errors.Join(errs, ErrHCHTTPPathInvalid)
}
Expand Down
26 changes: 26 additions & 0 deletions internal/ir/xds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,7 @@ func TestValidateHealthCheck(t *testing.T) {
UnhealthyThreshold: ptr.To[uint32](3),
HealthyThreshold: ptr.To[uint32](3),
HTTP: &HTTPHealthChecker{
Host: "*",
Path: "/healthz",
ExpectedStatuses: []HTTPStatus{200, 400},
},
Expand All @@ -1273,6 +1274,7 @@ func TestValidateHealthCheck(t *testing.T) {
UnhealthyThreshold: ptr.To[uint32](3),
HealthyThreshold: ptr.To[uint32](3),
HTTP: &HTTPHealthChecker{
Host: "*",
Path: "/healthz",
Method: ptr.To(http.MethodGet),
ExpectedStatuses: []HTTPStatus{200, 400},
Expand All @@ -1290,6 +1292,7 @@ func TestValidateHealthCheck(t *testing.T) {
UnhealthyThreshold: ptr.To[uint32](0),
HealthyThreshold: ptr.To[uint32](3),
HTTP: &HTTPHealthChecker{
Host: "*",
Path: "/healthz",
Method: ptr.To(http.MethodPatch),
ExpectedStatuses: []HTTPStatus{200, 400},
Expand All @@ -1307,6 +1310,7 @@ func TestValidateHealthCheck(t *testing.T) {
UnhealthyThreshold: ptr.To[uint32](3),
HealthyThreshold: ptr.To[uint32](0),
HTTP: &HTTPHealthChecker{
Host: "*",
Path: "/healthz",
Method: ptr.To(http.MethodPost),
ExpectedStatuses: []HTTPStatus{200, 400},
Expand All @@ -1316,6 +1320,23 @@ func TestValidateHealthCheck(t *testing.T) {
},
want: ErrHealthCheckHealthyThresholdInvalid,
},
{
name: "http-health-check: invalid host",
input: HealthCheck{&ActiveHealthCheck{
Timeout: &metav1.Duration{Duration: time.Second},
Interval: &metav1.Duration{Duration: time.Second},
UnhealthyThreshold: ptr.To[uint32](3),
HealthyThreshold: ptr.To[uint32](3),
HTTP: &HTTPHealthChecker{
Path: "/healthz",
Method: ptr.To(http.MethodPut),
ExpectedStatuses: []HTTPStatus{200, 400},
},
},
&OutlierDetection{},
},
want: ErrHCHTTPHostInvalid,
},
{
name: "http-health-check: invalid path",
input: HealthCheck{&ActiveHealthCheck{
Expand All @@ -1324,6 +1345,7 @@ func TestValidateHealthCheck(t *testing.T) {
UnhealthyThreshold: ptr.To[uint32](3),
HealthyThreshold: ptr.To[uint32](3),
HTTP: &HTTPHealthChecker{
Host: "*",
Path: "",
Method: ptr.To(http.MethodPut),
ExpectedStatuses: []HTTPStatus{200, 400},
Expand All @@ -1341,6 +1363,7 @@ func TestValidateHealthCheck(t *testing.T) {
UnhealthyThreshold: ptr.To(uint32(3)),
HealthyThreshold: ptr.To(uint32(3)),
HTTP: &HTTPHealthChecker{
Host: "*",
Path: "/healthz",
Method: ptr.To(http.MethodConnect),
ExpectedStatuses: []HTTPStatus{200, 400},
Expand All @@ -1358,6 +1381,7 @@ func TestValidateHealthCheck(t *testing.T) {
UnhealthyThreshold: ptr.To(uint32(3)),
HealthyThreshold: ptr.To(uint32(3)),
HTTP: &HTTPHealthChecker{
Host: "*",
Path: "/healthz",
Method: ptr.To(http.MethodDelete),
ExpectedStatuses: []HTTPStatus{},
Expand All @@ -1375,6 +1399,7 @@ func TestValidateHealthCheck(t *testing.T) {
UnhealthyThreshold: ptr.To(uint32(3)),
HealthyThreshold: ptr.To(uint32(3)),
HTTP: &HTTPHealthChecker{
Host: "*",
Path: "/healthz",
Method: ptr.To(http.MethodHead),
ExpectedStatuses: []HTTPStatus{100, 600},
Expand All @@ -1392,6 +1417,7 @@ func TestValidateHealthCheck(t *testing.T) {
UnhealthyThreshold: ptr.To(uint32(3)),
HealthyThreshold: ptr.To(uint32(3)),
HTTP: &HTTPHealthChecker{
Host: "*",
Path: "/healthz",
Method: ptr.To(http.MethodOptions),
ExpectedStatuses: []HTTPStatus{200, 300},
Expand Down
1 change: 1 addition & 0 deletions internal/xds/translator/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ func buildXdsHealthCheck(healthcheck *ir.ActiveHealthCheck) []*corev3.HealthChec
}
if healthcheck.HTTP != nil {
httpChecker := &corev3.HealthCheck_HttpHealthCheck{
Host: healthcheck.HTTP.Host,
Path: healthcheck.HTTP.Path,
}
if healthcheck.HTTP.Method != nil {
Expand Down
2 changes: 2 additions & 0 deletions internal/xds/translator/testdata/in/xds-ir/health-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ http:
unhealthyThreshold: 3
healthyThreshold: 1
http:
host: "*"
path: "/healthz"
expectedResponse:
text: "ok"
Expand Down Expand Up @@ -46,6 +47,7 @@ http:
unhealthyThreshold: 3
healthyThreshold: 3
http:
host: "*"
path: "/healthz"
expectedResponse:
binary: "cG9uZw=="
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
start: "200"
- end: "301"
start: "300"
host: '*'
path: /healthz
receive:
- text: 6f6b
Expand Down Expand Up @@ -53,6 +54,7 @@
expectedStatuses:
- end: "202"
start: "200"
host: '*'
path: /healthz
receive:
- binary: cG9uZw==
Expand Down

0 comments on commit 8f450a9

Please sign in to comment.