openshift-online/ocm-sdk-go

Wrong `Host` header sent to TLS server

Closed this issue · 2 comments

Version 0.1.164 of the SDK sends an incorrect Host header to the API server, containing the name of the SSO server instead of the name of the API server:

2021/03/22 12:40:47 OpenID token URL wasn't provided, will use 'https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token'
2021/03/22 12:40:47 OpenID client identifier wasn't provided, will use 'cloud-services'
2021/03/22 12:40:47 OpenID client secret wasn't provided, will use ''
2021/03/22 12:40:47 Added URL with prefix '', regular expression '^(/.*)?$' and URL 'https://api.openshift.com'
2021/03/22 12:40:47 Resolved URL is 'https://api.openshift.com/api/clusters_mgmt/v1/clusters?page=1&search=name+like+%27my%25%27&size=10'
2021/03/22 12:40:47 OCM auth: Bearer token isn't available
2021/03/22 12:40:47 OCM auth: trying to get new tokens (attempt 1)
2021/03/22 12:40:47 OCM auth: requesting new token using the refresh token grant
2021/03/22 12:40:47 Client for key 'tcp' doesn't exist, will create it
2021/03/22 12:40:47 Request method is POST
2021/03/22 12:40:47 Request URL is 'https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token'
2021/03/22 12:40:47 Request header 'Host' is 'sso.redhat.com'
2021/03/22 12:40:47 Request header 'Accept' is 'application/json'
2021/03/22 12:40:47 Request header 'Content-Type' is 'application/x-www-form-urlencoded'
2021/03/22 12:40:47 Request header 'User-Agent' is 'OCM-SDK/0.1.164'
2021/03/22 12:40:47 Request body follows
2021/03/22 12:40:47 client_id=cloud-services&client_secret=***&grant_type=refresh_token&refresh_token=***
2021/03/22 12:40:48 Response protocol is 'HTTP/1.1'
2021/03/22 12:40:48 Response status is '200 OK'
2021/03/22 12:40:48 Response header 'Cache-Control' is 'no-store'
2021/03/22 12:40:48 Response header 'Content-Type' is 'application/json'
2021/03/22 12:40:48 Response header 'Date' is 'Mon, 22 Mar 2021 11:40:48 GMT'
2021/03/22 12:40:48 Response header 'Pragma' is 'no-cache'
2021/03/22 12:40:48 Response header 'Set-Cookie' is 'BIGipServer~prod~keycloak-webssl-https=862389514.64288.0000; path=/; Httponly; Secure'
2021/03/22 12:40:48 Response header 'Strict-Transport-Security' is 'max-age=31536000; includeSubDomains'
2021/03/22 12:40:48 Response header 'Vary' is 'Accept-Encoding'
2021/03/22 12:40:48 Response header 'X-Content-Type-Options' is 'nosniff'
2021/03/22 12:40:48 Response header 'X-Frame-Options' is 'SAMEORIGIN'
2021/03/22 12:40:48 Response header 'X-Site' is 'phx2'
2021/03/22 12:40:48 Response header 'X-Xss-Protection' is '1; mode=block'
2021/03/22 12:40:48 Response body follows
2021/03/22 12:40:48 {
  "access_token": "***",
  "expires_in": 900,
  "refresh_expires_in": 0,
  "refresh_token": "***",
  "token_type": "bearer",
  "id_token": "***",
  "not-before-policy": 0,
  "session_state": "3df8402d-8476-41a5-a128-f7bbc7d03d4b",
  "scope": "openid offline_access"
}
2021/03/22 12:40:48 OCM auth: got tokens on attempt 1.
2021/03/22 12:40:48 Request method is GET
2021/03/22 12:40:48 Request URL is 'https://api.openshift.com/api/clusters_mgmt/v1/clusters?page=1&search=name+like+%27my%25%27&size=10'
2021/03/22 12:40:48 Request header 'Host' is 'api.openshift.com'
2021/03/22 12:40:48 Request header 'Accept' is 'application/json'
2021/03/22 12:40:48 Request header 'Authorization' is omitted
2021/03/22 12:40:48 Request header 'User-Agent' is 'OCM-SDK/0.1.164'
Can't retrieve page 1: can't send request: Get "https://api.openshift.com/api/clusters_mgmt/v1/clusters?page=1&search=name+like+%27my%25%27&size=10": x509: certificate is valid for *.apps.app-sre-prod-04.i5h0.p1.openshiftapps.com, api.app-sre-prod-04.i5h0.p1.openshiftapps.com, rh-api.app-sre-prod-04.i5h0.p1.openshiftapps.com, not sso.redhat.com

That results in a rejected request because the verification of the host name in the TLS certificate fails.

This happens because when support for Unix sockets was introduced it was necessary to also explicitly set the ServerName in the TLS configuration to the host name of the target host, otherwise the Go library would send the Unix socket name as the host, something like Host: /tmp/my.socket. But the TCP client is shared for all hosts, for example for api.openshift.com and sso.redhat.com. So if the first request happens to be a request to sso.redhat.com (it will usually be) the HTTP client will use sso.redhat.com as the TLS server name also for API requests, not only for SSO requests. In this case the API server happens to be behind an OpenShift router that uses SNI to select the target service and certificates. As there is no sso.redhat.com target behind that OpenShift router it returns the default, which fails validation against the sso.redhat.com name.

Fixed in #357 and included in release 0.1.165.