Repository: kubernetes-sigs/gateway-api

Issue:
Conformance tests for BackendTLSPolicy
<!-- Please only use this template for submitting conformance test requests -->

**What would you like to be added**:
Conformance tests for BackendTLSPolicy. Comment below if you're interested in working on covering any of these areas.

Core Capabilities:
- [x]  Valid BackendTLSPolicy with 1 targetRef/service using CACertificateRef and matching hostname
- [x] Invalid: hostname doesn't match the hostname in the certificate served by the backend
- [ ] Invalid BackendTLSPolicy performs no default forwarding
- [ ] ~Valid BackendTLSPolicy with 1 targetRef/service using WellKnownCACertificates and matching hostname~
- [ ] ~Invalid: targetRef in different namespace~
- [ ] ~Invalid: both CACertificateRef and WellKnownCACertificates is specified~
- [ ] ~Invalid: SNI hostname invalid - not RFC1123 (should be caught by validation)~
- [ ] ~Invalid: Namespace (of targetRef) not set~

**Why this is needed**:
This is needed in order for BackendTLSPolicy to graduate from v1alpha3 to v1.


Hints from issue comments:
@candita: cc @whitneygriffith @mlavacca @whitneygriffith: #1897@mlavacca: > Invalid: both CACertificateRef and WellKnownCACertificates is specified

I think this test cannot be implemented, as this rule is directly enforced by CEL:

https://github.com/kubernetes-sigs/gateway-api/blob/d49ae960279b7022c8f7e041221df306ef64094d/apis/v1alpha3/backendtlspolicy_types.go#L81@mlavacca: > Valid BackendTLSPolicy with 1 targetRef/service using WellKnownCACertificates and matching hostname

`WellKnownCACertificates` is an implementation-specific feature, therefore I think we should either:
- leave it out of conformance tests, or
- accept that the implementation set the `Accepted` condition to false, as stated in https://github.com/kubernetes-sigs/gateway-api/blob/d49ae960279b7022c8f7e041221df306ef64094d/apis/v1alpha3/backendtlspolicy_types.go#L115-L118

If we go the second way, though, in my opinion, this is beyond the bare minimum set of conformance tests needed for graduation.@mlavacca: > Invalid: targetRef in different namespace

The TargetRef is a `LocalPolicyTargetReference`, there is no namespace field in it. I think that a `TargetRef` in a different namespace is impossible, given the current API state.

https://github.com/kubernetes-sigs/gateway-api/blob/86c06a0b62587a627a9929d5943c5894a608ad62/apis/v1alpha2/policy_types.go#L39-L48@keithmattix: /assign @candita @whitneygriffith @whitneygriffith: > > Invalid: targetRef in different namespace
> The TargetRef is a `LocalPolicyTargetReference`, there is no namespace field in it. I think that a `TargetRef` in a different namespace is impossible, given the current API state.

I agree, we don't need a conformance test for this case. The same applies for Invalid: Namespace (of targetRef) not set. @whitneygriffith: Updated test cases: 

- [ ] Valid BackendTLSPolicy with 1 targetRef/service using CACertificateRef and matching hostname
- [ ]  Invalid: hostname doesn't match the hostname in the certificate served by the backend
- [ ] Invalid: if an implementation doesn't claim support for BackendTLSPolicy, it rejects forwarding to Services with a BackendTLSPolicy attached.

Removed test cases:

- Valid BackendTLSPolicy with 1 targetRef/service using WellKnownCACertificates and matching hostname (`WellKnownCACertificates` is an implementation-specific feature and is beyond the minimum set of tests needed for graduation)
- Invalid: targetRef in different namespace (targetRef is of type [LocalPolicyTargetReference](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io%2fv1alpha2.LocalPolicyTargetReference) which does not have a namespace field)
- Invalid: both CACertificateRef and WellKnownCACertificates is specified (enforced by CEL)
- Invalid: SNI hostname invalid - not RFC1123 (should be caught by validation)
- Invalid BackendTLSPolicy performs no default forwarding as all the required fields are set (enforced by validation)
- Invalid: Namespace (of targetRef) not set (targetRef is of type [LocalPolicyTargetReference](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io%2fv1alpha2.LocalPolicyTargetReference) which does not have a namespace field)@k8s-triage-robot: The Kubernetes project currently lacks enough contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:
- After 90d of inactivity, `lifecycle/stale` is applied
- After 30d of inactivity since `lifecycle/stale` was applied, `lifecycle/rotten` is applied
- After 30d of inactivity since `lifecycle/rotten` was applied, the issue is closed

You can:
- Mark this issue as fresh with `/remove-lifecycle stale`
- Close this issue with `/close`
- Offer to help out with [Issue Triage][1]

Please send feedback to sig-contributor-experience at [kubernetes/community](https://github.com/kubernetes/community).

/lifecycle stale

[1]: https://www.kubernetes.dev/docs/guide/issue-triage/@k8s-triage-robot: The Kubernetes project currently lacks enough active contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:
- After 90d of inactivity, `lifecycle/stale` is applied
- After 30d of inactivity since `lifecycle/stale` was applied, `lifecycle/rotten` is applied
- After 30d of inactivity since `lifecycle/rotten` was applied, the issue is closed

You can:
- Mark this issue as fresh with `/remove-lifecycle rotten`
- Close this issue with `/close`
- Offer to help out with [Issue Triage][1]

Please send feedback to sig-contributor-experience at [kubernetes/community](https://github.com/kubernetes/community).

/lifecycle rotten

[1]: https://www.kubernetes.dev/docs/guide/issue-triage/@candita: /remove-lifecycle rotten@k8s-triage-robot: The Kubernetes project currently lacks enough contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:
- After 90d of inactivity, `lifecycle/stale` is applied
- After 30d of inactivity since `lifecycle/stale` was applied, `lifecycle/rotten` is applied
- After 30d of inactivity since `lifecycle/rotten` was applied, the issue is closed

You can:
- Mark this issue as fresh with `/remove-lifecycle stale`
- Close this issue with `/close`
- Offer to help out with [Issue Triage][1]

Please send feedback to sig-contributor-experience at [kubernetes/community](https://github.com/kubernetes/community).

/lifecycle stale

[1]: https://www.kubernetes.dev/docs/guide/issue-triage/@candita: /remove-lifecycle stale

Solution patch:
diff --git a/conformance/utils/http/http.go b/conformance/utils/http/http.go
index e1aca27d..91ebf225 100644
--- a/conformance/utils/http/http.go
+++ b/conformance/utils/http/http.go
@@ -117,6 +117,17 @@ func MakeRequestAndExpectEventuallyConsistentResponse(t *testing.T, r roundtripp
 	WaitForConsistentResponse(t, r, req, expected, timeoutConfig.RequiredConsecutiveSuccesses, timeoutConfig.MaxTimeToConsistency)
 }
 
+// MakeRequestAndExpectFailure makes a request with the given parameters.
+// This function needs to ensure that after the system is stable the Request is
+// not returning http 200 StatusCode.
+func MakeRequestAndExpectFailure(t *testing.T, r roundtripper.RoundTripper, timeoutConfig config.TimeoutConfig, gwAddr string, expected ExpectedResponse) {
+	t.Helper()
+
+	req := MakeRequest(t, &expected, gwAddr, "HTTP", "http")
+
+	WaitForConsistentFailureResponse(t, r, req, 5, timeoutConfig.MaxTimeToConsistency)
+}
+
 func MakeRequest(t *testing.T, expected *ExpectedResponse, gwAddr, protocol, scheme string) roundtripper.Request {
 	t.Helper()
 
@@ -261,6 +272,29 @@ func WaitForConsistentResponse(t *testing.T, r roundtripper.RoundTripper, req ro
 	tlog.Logf(t, "Request passed")
 }
 
+// WaitForConsistentFailureResponse repeats the provided request for the given
+// period of time and ensures an error is returned each time. This function fails
+// when HTTP Status OK (200) is returned.
+func WaitForConsistentFailureResponse(t *testing.T, r roundtripper.RoundTripper, req roundtripper.Request, threshold int, maxTimeToConsistency time.Duration) {
+	AwaitConvergence(t, threshold, maxTimeToConsistency, func(elapsed time.Duration) bool {
+		_, cRes, err := r.CaptureRoundTrip(req)
+		if err != nil {
+			tlog.Logf(t, "Request failed, not ready yet: %v (after %v)", err.Error(), elapsed)
+			return false
+		}
+		if roundtripper.IsTimeoutError(cRes.StatusCode) {
+			tlog.Logf(t, "Response expectation failed for request: %+v  not ready yet: %v (after %v)", req, cRes.StatusCode, elapsed)
+			return false
+		}
+		if cRes.StatusCode == 200 { // http:StatusCode OK
+			t.Fatalf("Request %+v should failed, returned HTTP Status OK (200) instead", req)
+			return false
+		}
+		return true
+	})
+	tlog.Logf(t, "Expectation for failing Request are met")
+}
+
 func CompareRoundTrip(t *testing.T, req *roundtripper.Request, cReq *roundtripper.CapturedRequest, cRes *roundtripper.CapturedResponse, expected ExpectedResponse) error {
 	if roundtripper.IsTimeoutError(cRes.StatusCode) {
 		if roundtripper.IsTimeoutError(expected.Response.StatusCode) {
diff --git a/conformance/utils/kubernetes/helpers.go b/conformance/utils/kubernetes/helpers.go
index 9e385b4c..8075132d 100644
--- a/conformance/utils/kubernetes/helpers.go
+++ b/conformance/utils/kubernetes/helpers.go
@@ -37,6 +37,7 @@ import (
 
 	gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
 	"sigs.k8s.io/gateway-api/apis/v1alpha2"
+	"sigs.k8s.io/gateway-api/apis/v1alpha3"
 	"sigs.k8s.io/gateway-api/conformance/utils/config"
 	"sigs.k8s.io/gateway-api/conformance/utils/tlog"
 )
@@ -993,3 +994,35 @@ func findPodConditionInList(t *testing.T, conditions []v1.PodCondition, condName
 	tlog.Logf(t, "%s was not in conditions list", condName)
 	return false
 }
+
+// BackendTLSPolicyMustHaveCondition checks that the created BackentTLSPolicy has the Condition,
+// halting after the specified timeout is exceeded.
+func BackendTLSPolicyMustHaveCondition(t *testing.T, client client.Client, timeoutConfig config.TimeoutConfig, policyNN, gwNN types.NamespacedName, condition metav1.Condition) {
+	t.Helper()
+	waitErr := wait.PollUntilContextTimeout(context.Background(), 1*time.Second, timeoutConfig.HTTPRouteMustHaveCondition, true, func(ctx context.Context) (bool, error) {
+		policy := &v1alpha3.BackendTLSPolicy{}
+		err := client.Get(ctx, policyNN, policy)
+		if err != nil {
+			return false, fmt.Errorf("error fetching BackendTLSPolicy: %w", err)
+		}
+
+		for _, parent := range policy.Status.Ancestors {
+			if err := ConditionsHaveLatestObservedGeneration(policy, parent.Conditions); err != nil {
+				tlog.Logf(t, "BackendTLSPolicy %s (parentRef=%v) %v",
+					policyNN, parentRefToString(parent.AncestorRef), err,
+				)
+				return false, nil
+			}
+
+			if parent.AncestorRef.Name == gatewayv1.ObjectName(gwNN.Name) && (parent.AncestorRef.Namespace == nil || string(*parent.AncestorRef.Namespace) == gwNN.Namespace) {
+				if findConditionInList(t, parent.Conditions, condition.Type, string(condition.Status), condition.Reason) {
+					return true, nil
+				}
+			}
+		}
+
+		return false, nil
+	})
+
+	require.NoErrorf(t, waitErr, "error waiting for BackendTLSPolicy status to have a Condition %v", condition)
+}
diff --git a/conformance/utils/suite/suite.go b/conformance/utils/suite/suite.go
index b34a1ea3..858fea2e 100644
--- a/conformance/utils/suite/suite.go
+++ b/conformance/utils/suite/suite.go
@@ -383,6 +383,8 @@ func (suite *ConformanceTestSuite) Setup(t *testing.T, tests []ConformanceTest)
 		suite.Applier.MustApplyObjectsWithCleanup(t, suite.Client, suite.TimeoutConfig, []client.Object{secret}, suite.Cleanup)
 		secret = kubernetes.MustCreateSelfSignedCertSecret(t, "gateway-conformance-app-backend", "tls-passthrough-checks-certificate", []string{"abc.example.com"})
 		suite.Applier.MustApplyObjectsWithCleanup(t, suite.Client, suite.TimeoutConfig, []client.Object{secret}, suite.Cleanup)
+		caConfigMapBST, _, _ := kubernetes.MustCreateCACertConfigMap(t, "gateway-conformance-infra", "backend-tls-mismatch-certificate", []string{"nex.example.com"})
+		suite.Applier.MustApplyObjectsWithCleanup(t, suite.Client, suite.TimeoutConfig, []client.Object{caConfigMapBST}, suite.Cleanup)
 		caConfigMap, ca, caPrivKey := kubernetes.MustCreateCACertConfigMap(t, "gateway-conformance-infra", "backend-tls-checks-certificate", []string{"abc.example.com"})
 		suite.Applier.MustApplyObjectsWithCleanup(t, suite.Client, suite.TimeoutConfig, []client.Object{caConfigMap}, suite.Cleanup)
 		secret = kubernetes.MustCreateCASignedCertSecret(t, "gateway-conformance-infra", "tls-checks-certificate", []string{"abc.example.com"}, ca, caPrivKey)
diff --git a/pkg/features/backendtlspolicy.go b/pkg/features/backendtlspolicy.go
index 8763b32d..95d50171 100644
--- a/pkg/features/backendtlspolicy.go
+++ b/pkg/features/backendtlspolicy.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2024 The Kubernetes Authors.
+Copyright 2025 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.



Test patch:
diff --git a/conformance/tests/backendtlspolicy.go b/conformance/tests/backendtlspolicy.go
index 1d556278..fc6c6576 100644
--- a/conformance/tests/backendtlspolicy.go
+++ b/conformance/tests/backendtlspolicy.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2024 The Kubernetes Authors.
+Copyright 2025 The Kubernetes Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -19,9 +19,12 @@ package tests
 import (
 	"testing"
 
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
 	"k8s.io/apimachinery/pkg/types"
 
 	gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
+	"sigs.k8s.io/gateway-api/apis/v1alpha2"
 	h "sigs.k8s.io/gateway-api/conformance/utils/http"
 	"sigs.k8s.io/gateway-api/conformance/utils/kubernetes"
 	"sigs.k8s.io/gateway-api/conformance/utils/suite"
@@ -35,7 +38,7 @@ func init() {
 
 var BackendTLSPolicy = suite.ConformanceTest{
 	ShortName:   "BackendTLSPolicy",
-	Description: "A single service that is targeted by a BackendTLSPolicy must successfully complete TLS termination",
+	Description: "BackendTLSPolicy must be used to configure TLS connection between gateway and backend",
 	Features: []features.FeatureName{
 		features.SupportGateway,
 		features.SupportHTTPRoute,
@@ -51,10 +54,25 @@ var BackendTLSPolicy = suite.ConformanceTest{
 		gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &gatewayv1.HTTPRoute{}, false, routeNN)
 		kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)
 
+		policyCond := metav1.Condition{
+			Type:   string(v1alpha2.PolicyConditionAccepted),
+			Status: metav1.ConditionTrue,
+			Reason: string(v1alpha2.PolicyReasonAccepted),
+		}
+
+		validPolicyNN := types.NamespacedName{Name: "normative-test-backendtlspolicy", Namespace: ns}
+		kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, validPolicyNN, gwNN, policyCond)
+
+		invalidPolicyNN := types.NamespacedName{Name: "backendtlspolicy-host-mismatch", Namespace: ns}
+		kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidPolicyNN, gwNN, policyCond)
+
+		invalidCertPolicyNN := types.NamespacedName{Name: "backendtlspolicy-cert-mismatch", Namespace: ns}
+		kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidCertPolicyNN, gwNN, policyCond)
+
 		serverStr := "abc.example.com"
 
-		// Verify that the response to a backend-tls-only call to /backendTLS will return the matching SNI.
-		t.Run("Simple HTTP request targeting BackendTLSPolicy should reach infra-backend", func(t *testing.T) {
+		// Verify that the request sent to Service with valid BackendTLSPolicy should succeed.
+		t.Run("HTTP request sent to Service with valid BackendTLSPolicy should succeed", func(t *testing.T) {
 			h.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr,
 				h.ExpectedResponse{
 					Namespace: ns,
@@ -73,8 +91,8 @@ var BackendTLSPolicy = suite.ConformanceTest{
 		if err != nil {
 			t.Fatalf("unexpected error finding TLS secret: %v", err)
 		}
-		// Verify that the response to a re-encrypted call to /backendTLS will return the matching SNI.
-		t.Run("Re-encrypt HTTPS request targeting BackendTLSPolicy should reach infra-backend", func(t *testing.T) {
+		// Verify that the request to a re-encrypted call to /backendTLS should succeed.
+		t.Run("Re-encrypt HTTPS request sent to Service with valid BackendTLSPolicy should succeed", func(t *testing.T) {
 			tls.MakeTLSRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, cPem, keyPem, serverStr,
 				h.ExpectedResponse{
 					Namespace: ns,
@@ -86,5 +104,31 @@ var BackendTLSPolicy = suite.ConformanceTest{
 					Response: h.Response{StatusCode: 200},
 				})
 		})
+
+		// Verify that the request sent to a Service targeted by a BackendTLSPolicy with mismatched host will fail.
+		t.Run("HTTP request sent to Service targeted by BackendTLSPolicy with mismatched hostname should return an HTTP error", func(t *testing.T) {
+			h.MakeRequestAndExpectFailure(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr,
+				h.ExpectedResponse{
+					Namespace: ns,
+					Request: h.Request{
+						Host: serverStr,
+						Path: "/backendTLSHostMismatch",
+						SNI:  serverStr,
+					},
+				})
+		})
+
+		// Verify that request sent to Service targeted by BackendTLSPolicy with mismatched cert should failed.
+		t.Run("HTTP request send to Service targeted by BackendTLSPolicy with mismatched cert should return HTTP error", func(t *testing.T) {
+			h.MakeRequestAndExpectFailure(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr,
+				h.ExpectedResponse{
+					Namespace: ns,
+					Request: h.Request{
+						Host: serverStr,
+						Path: "/backendTLSCertMismatch",
+						SNI:  serverStr,
+					},
+				})
+		})
 	},
 }
diff --git a/conformance/tests/backendtlspolicy.yaml b/conformance/tests/backendtlspolicy.yaml
index 91f6a590..e048cc2e 100644
--- a/conformance/tests/backendtlspolicy.yaml
+++ b/conformance/tests/backendtlspolicy.yaml
@@ -31,25 +31,6 @@ spec:
       kinds:
       - kind: HTTPRoute
 ---
-apiVersion: gateway.networking.k8s.io/v1alpha3
-kind: BackendTLSPolicy
-metadata:
-  name: normative-test-backendtlspolicy
-  namespace: gateway-conformance-infra
-spec:
-  targetRefs:
-  - group: ""
-    kind: Service
-    name: "backendtlspolicy-test"
-    sectionName: "btls"
-  validation:
-    caCertificateRefs:
-    - group: ""
-      kind: ConfigMap
-      # This secret is generated dynamically by the test suite.
-      name: "backend-tls-checks-certificate"
-    hostname: "abc.example.com"
----
 apiVersion: gateway.networking.k8s.io/v1
 kind: HTTPRoute
 metadata:
@@ -71,6 +52,24 @@ spec:
     - path:
         type: Exact
         value: /backendTLS
+  - backendRefs:
+    - group: ""
+      kind: Service
+      name: backendtlspolicy-host-mismatch-test
+      port: 443
+    matches:
+    - path:
+        type: Exact
+        value: /backendTLSHostMismatch
+  - backendRefs:
+    - group: ""
+      kind: Service
+      name: backendtlspolicy-cert-mismatch-test
+      port: 443
+    matches:
+    - path:
+        type: Exact
+        value: /backendTLSCertMismatch
 ---
 apiVersion: v1
 kind: Service
@@ -86,6 +85,36 @@ spec:
     port: 443
     targetPort: 8443
 ---
+apiVersion: v1
+kind: Service
+metadata:
+  name: backendtlspolicy-host-mismatch-test
+  namespace: gateway-conformance-infra
+spec:
+  selector:
+    app: backendtlspolicy-test
+  ports:
+  - name: "btls"
+    protocol: TCP
+    appProtocol: HTTPS
+    port: 443
+    targetPort: 8443
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: backendtlspolicy-cert-mismatch-test
+  namespace: gateway-conformance-infra
+spec:
+  selector:
+    app: backendtlspolicy-test
+  ports:
+  - name: "btls"
+    protocol: TCP
+    appProtocol: HTTPS
+    port: 443
+    targetPort: 8443
+---
 # Deployment must not be applied until after the secret is generated.
 apiVersion: apps/v1
 kind: Deployment
@@ -151,3 +180,60 @@ spec:
             path: crt
           - key: tls.key
             path: key
+---
+apiVersion: gateway.networking.k8s.io/v1alpha3
+kind: BackendTLSPolicy
+metadata:
+  name: normative-test-backendtlspolicy
+  namespace: gateway-conformance-infra
+spec:
+  targetRefs:
+  - group: ""
+    kind: Service
+    name: "backendtlspolicy-test"
+    sectionName: "btls"
+  validation:
+    caCertificateRefs:
+    - group: ""
+      kind: ConfigMap
+      # This secret is generated dynamically by the test suite.
+      name: "backend-tls-checks-certificate"
+    hostname: "abc.example.com"
+---
+apiVersion: gateway.networking.k8s.io/v1alpha3
+kind: BackendTLSPolicy
+metadata:
+  name: backendtlspolicy-host-mismatch
+  namespace: gateway-conformance-infra
+spec:
+  targetRefs:
+  - group: ""
+    kind: Service
+    name: "backendtlspolicy-host-mismatch-test"
+    sectionName: "btls"
+  validation:
+    caCertificateRefs:
+    - group: ""
+      kind: ConfigMap
+      # This secret is generated dynamically by the test suite.
+      name: "backend-tls-checks-certificate"
+    hostname: "mismatch.example.com"
+---
+apiVersion: gateway.networking.k8s.io/v1alpha3
+kind: BackendTLSPolicy
+metadata:
+  name: backendtlspolicy-cert-mismatch
+  namespace: gateway-conformance-infra
+spec:
+  targetRefs:
+  - group: ""
+    kind: Service
+    name: "backendtlspolicy-cert-mismatch-test"
+    sectionName: "btls"
+  validation:
+    caCertificateRefs:
+    - group: ""
+      kind: ConfigMap
+      # This secret is generated dynamically by the test suite.
+      name: "backend-tls-mismatch-certificate"
+    hostname: "abc.example.com"