Kubernetes の apiserver proxy は HTTPS バックエンドにもアクセスできる

ドキュメントには HTTP の例しか書かれていませんが、HTTPS でもアクセスできたのでメモしておきます。

- http://kubernetes.io/docs/user-guide/accessing-the-cluster/#manually-constructing-apiserver-proxy-urls

例示されていないものの、できそうなことは上記ページの最後でちょっとだけ示唆されていました。

>The apiserver proxy: - is a bastion built into the apiserver - connects a user outside of the cluster to cluster IPs which otherwise might not be reachable - runs in the apiserver processes - client to proxy uses HTTPS (or http if apiserver so configured) - proxy to target may use HTTP or HTTPS as chosen by proxy using available information - can be used to reach a Node, Pod, or Service - does load balancing when used to reach a Service

## リクエスト方法

バックエンドが HTTP なら以下のようになると書かれています。

`http://kubernetes_master_address/api/v1/proxy/namespaces/namespace_name/services/service_name[:port_name]`

最後の `service_name` の前に `scheme` を挿入するとバックエンドへのアクセスが `HTTPS` になります。

`http://kubernetes_master_address/api/v1/proxy/namespaces/namespace_name/services/https:service_name:port_name`

もちろん API Server へのアクセスが HTTPS になっていても問題ありません。

`https://kubernetes_master_address/api/v1/proxy/namespaces/namespace_name/services/https:service_name:port_name`

例えば `kube-system` namespace にある `kube-registry` service が 443 ポートで公開されているなら以下のようになります。

`http://kubernetes_master_address/api/v1/proxy/namespaces/kube-system/services/https:kube-registry:443/`
`https://kubernetes_master_address/api/v1/proxy/namespaces/kube-system/services/https:kube-registry:443/`

ここで大切なのは、https でアクセスする時はポート番号も忘れずに書く必要があるということです。

## scheme の生成場所

どうやって指定すればいいのか分からず、ソースを漁ってみた時のメモ書きです。<br>
proxy の方法だけ知りたい方はこのセクションは読む必要はありません。

確認時のバージョンは `1.4.4` でした。


```go:pkg/apiserver/proxy.go
  location, roundTripper, err := redirector.ResourceLocation(ctx, id)
  if err != nil {
    httplog.LogOf(req, w).Addf("Error getting ResourceLocation: %v", err)
    httpCode = errorNegotiated(err, r.serializer, gv, w, req)
    return
  }
  location, roundTripper, err := redirector.ResourceLocation(ctx, id)
  if err != nil {
    httplog.LogOf(req, w).Addf("Error getting ResourceLocation: %v", err)
    httpCode = errorNegotiated(err, r.serializer, gv, w, req)
    return
  }

/*** 省略 ***/

  // Default to http
  if location.Scheme == "" {
    location.Scheme = "http"
  }

/*** 省略 ***/

  proxy := httputil.NewSingleHostReverseProxy(&url.URL{Scheme: location.Scheme, Host: location.Host})
```

```go:pkg/registry/core/service/rest.go
// ResourceLocation returns a URL to which one can send traffic for the specified service.
func (rs *REST) ResourceLocation(ctx api.Context, id string) (*url.URL, http.RoundTripper, error) {
  // Allow ID as "svcname", "svcname:port", or "scheme:svcname:port".
  svcScheme, svcName, portStr, valid := utilnet.SplitSchemeNamePort(id)

/*** 省略 ***/

        return &url.URL{
          Scheme: svcScheme,
          Host:   net.JoinHostPort(ip, strconv.Itoa(port)),
        }, rs.proxyTransport, nil
```

`id` にそれらしい値が入ればいけそうなので、その先を見る

```go:pkg/util/net/port_split.go
// SplitSchemeNamePort takes a string of the following forms:
//  * "<name>",                 returns "",        "<name>","",      true
//  * "<name>:<port>",          returns "",        "<name>","<port>",true
//  * "<scheme>:<name>:<port>", returns "<scheme>","<name>","<port>",true
//
// Name must be non-empty or valid will be returned false.
// Scheme must be "http" or "https" if specified
// Port is returned as a string, and it is not required to be numeric (could be
// used for a named port, for example).
func SplitSchemeNamePort(id string) (scheme, name, port string, valid bool) {
  parts := strings.Split(id, ":")
  switch len(parts) {
  case 1:
    name = parts[0]
  case 2:
    name = parts[0]
    port = parts[1]
  case 3:
    scheme = parts[0]
    name = parts[1]
    port = parts[2]
  default:
    return "", "", "", false
  }

  if len(name) > 0 && validSchemes.Has(scheme) {
    return scheme, name, port, true
  } else {
    return "", "", "", false
  }
}
```

というわけで、`id` が `https:servicename:port` という形になっていれば良さそうだと分かりました。
先は読まずにリクエストを試して通ったので良しとします。