Skip to content

Commit

Permalink
add insecurebackendproxy
Browse files Browse the repository at this point in the history
  • Loading branch information
deads2k committed Oct 16, 2019
1 parent a886247 commit 867ee1d
Show file tree
Hide file tree
Showing 14 changed files with 443 additions and 33 deletions.
9 changes: 9 additions & 0 deletions pkg/apis/core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4203,6 +4203,15 @@ type PodLogOptions struct {
// log output. This may not display a complete final line of logging, and may return
// slightly more or slightly less than the specified limit.
LimitBytes *int64

// insecureSkipTLSVerifyBackend indicates that the apiserver should not confirm the validity of the
// serving certificate of the backend it is connecting to. This will make the HTTPS connection between the apiserver
// and the backend insecure. This means the apiserver cannot verify the log data it is receiving came from the real
// kubelet. If the kubelet is configured to verify the apiserver's TLS credentials, it does not mean the
// connection to the real kubelet is vulnerable to a man in the middle attack (e.g. an attacker could not intercept
// the actual log data coming from the real kubelet).
// +optional
InsecureSkipTLSVerifyBackend bool
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
Expand Down
7 changes: 7 additions & 0 deletions pkg/features/kube_features.go
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,12 @@ const (
//
// Enables the startupProbe in kubelet worker.
StartupProbe featuregate.Feature = "StartupProbe"

// owner: @deads2k
// beta: v1.17
//
// Enables the users to skip TLS verification of kubelets on pod logs requests
AllowInsecureBackendProxy featuregate.Feature = "AllowInsecureBackendProxy"
)

func init() {
Expand Down Expand Up @@ -563,6 +569,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
EndpointSlice: {Default: false, PreRelease: featuregate.Alpha},
EvenPodsSpread: {Default: false, PreRelease: featuregate.Alpha},
StartupProbe: {Default: false, PreRelease: featuregate.Alpha},
AllowInsecureBackendProxy: {Default: true, PreRelease: featuregate.Beta},

// inherited features from generic apiserver, relisted here to get a conflict if it is changed
// unintentionally on either side:
Expand Down
56 changes: 42 additions & 14 deletions pkg/kubelet/client/kubelet_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,40 @@ type KubeletClientConfig struct {

// ConnectionInfo provides the information needed to connect to a kubelet
type ConnectionInfo struct {
Scheme string
Hostname string
Port string
Transport http.RoundTripper
Scheme string
Hostname string
Port string
Transport http.RoundTripper
InsecureSkipTLSVerifyTransport http.RoundTripper
}

// ConnectionInfoGetter provides ConnectionInfo for the kubelet running on a named node
type ConnectionInfoGetter interface {
GetConnectionInfo(ctx context.Context, nodeName types.NodeName) (*ConnectionInfo, error)
}

// MakeTransport creates a RoundTripper for HTTP Transport.
// MakeTransport creates a secure RoundTripper for HTTP Transport.
func MakeTransport(config *KubeletClientConfig) (http.RoundTripper, error) {
tlsConfig, err := transport.TLSConfigFor(config.transportConfig())
return makeTransport(config, false)
}

// MakeInsecureTransport creates an insecure RoundTripper for HTTP Transport.
func MakeInsecureTransport(config *KubeletClientConfig) (http.RoundTripper, error) {
return makeTransport(config, true)
}

// makeTransport creates a RoundTripper for HTTP Transport.
func makeTransport(config *KubeletClientConfig, insecureSkipTLSVerify bool) (http.RoundTripper, error) {
// do the insecureSkipTLSVerify on the pre-transport *before* we go get a potentially cached connection.
// transportConfig always produces a new struct pointer.
preTLSConfig := config.transportConfig()
if insecureSkipTLSVerify && preTLSConfig != nil {
preTLSConfig.TLS.Insecure = true
preTLSConfig.TLS.CAData = nil
preTLSConfig.TLS.CAFile = ""
}

tlsConfig, err := transport.TLSConfigFor(preTLSConfig)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -148,6 +168,8 @@ type NodeConnectionInfoGetter struct {
defaultPort int
// transport is the transport to use to send a request to all kubelets
transport http.RoundTripper
// insecureSkipTLSVerifyTransport is the transport to use if the kube-apiserver wants to skip verifying the TLS certificate of the kubelet
insecureSkipTLSVerifyTransport http.RoundTripper
// preferredAddressTypes specifies the preferred order to use to find a node address
preferredAddressTypes []v1.NodeAddressType
}
Expand All @@ -163,17 +185,22 @@ func NewNodeConnectionInfoGetter(nodes NodeGetter, config KubeletClientConfig) (
if err != nil {
return nil, err
}
insecureSkipTLSVerifyTransport, err := MakeInsecureTransport(&config)
if err != nil {
return nil, err
}

types := []v1.NodeAddressType{}
for _, t := range config.PreferredAddressTypes {
types = append(types, v1.NodeAddressType(t))
}

return &NodeConnectionInfoGetter{
nodes: nodes,
scheme: scheme,
defaultPort: int(config.Port),
transport: transport,
nodes: nodes,
scheme: scheme,
defaultPort: int(config.Port),
transport: transport,
insecureSkipTLSVerifyTransport: insecureSkipTLSVerifyTransport,

preferredAddressTypes: types,
}, nil
Expand All @@ -199,9 +226,10 @@ func (k *NodeConnectionInfoGetter) GetConnectionInfo(ctx context.Context, nodeNa
}

return &ConnectionInfo{
Scheme: k.scheme,
Hostname: host,
Port: strconv.Itoa(port),
Transport: k.transport,
Scheme: k.scheme,
Hostname: host,
Port: strconv.Itoa(port),
Transport: k.transport,
InsecureSkipTLSVerifyTransport: k.insecureSkipTLSVerifyTransport,
}, nil
}
62 changes: 62 additions & 0 deletions pkg/kubelet/client/kubelet_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ limitations under the License.
package client

import (
"net"
"net/http"
"net/http/httptest"
"net/http/httputil"
"net/url"
"strconv"
"testing"

restclient "k8s.io/client-go/rest"
Expand Down Expand Up @@ -63,3 +69,59 @@ func TestMakeTransportValid(t *testing.T) {
t.Error("rt should not be nil")
}
}

func TestMakeInsecureTransport(t *testing.T) {
testServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
}))
defer testServer.Close()

testURL, err := url.Parse(testServer.URL)
if err != nil {
t.Fatal(err)
}
_, portStr, err := net.SplitHostPort(testURL.Host)
if err != nil {
t.Fatal(err)
}
port, err := strconv.ParseUint(portStr, 10, 32)
if err != nil {
t.Fatal(err)
}

config := &KubeletClientConfig{
Port: uint(port),
EnableHTTPS: true,
TLSClientConfig: restclient.TLSClientConfig{
CertFile: "../../client/testdata/mycertvalid.cer",
// TLS Configuration, only applies if EnableHTTPS is true.
KeyFile: "../../client/testdata/mycertvalid.key",
// TLS Configuration, only applies if EnableHTTPS is true.
CAFile: "../../client/testdata/myCA.cer",
},
}

rt, err := MakeInsecureTransport(config)
if err != nil {
t.Errorf("Not expecting an error #%v", err)
}
if rt == nil {
t.Error("rt should not be nil")
}

req, err := http.NewRequest(http.MethodGet, testServer.URL, nil)
if err != nil {
t.Fatal(err)
}
response, err := rt.RoundTrip(req)
if err != nil {
t.Fatal(err)
}
if response.StatusCode != http.StatusOK {
dump, err := httputil.DumpResponse(response, true)
if err != nil {
t.Fatal(err)
}
t.Fatal(string(dump))
}
}
2 changes: 2 additions & 0 deletions pkg/registry/core/pod/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ go_library(
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/helper/qos:go_default_library",
"//pkg/apis/core/validation:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubelet/client:go_default_library",
"//pkg/proxy/util:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
Expand All @@ -32,6 +33,7 @@ go_library(
"//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/storage:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
],
)

Expand Down
1 change: 1 addition & 0 deletions pkg/registry/core/pod/rest/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ go_library(
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/validation:go_default_library",
"//pkg/capabilities:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubelet/client:go_default_library",
"//pkg/registry/core/pod:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
Expand Down
6 changes: 6 additions & 0 deletions pkg/registry/core/pod/rest/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ import (
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
genericrest "k8s.io/apiserver/pkg/registry/generic/rest"
"k8s.io/apiserver/pkg/registry/rest"
utilfeature "k8s.io/apiserver/pkg/util/feature"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/validation"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/kubelet/client"
"k8s.io/kubernetes/pkg/registry/core/pod"
)
Expand Down Expand Up @@ -67,6 +69,10 @@ func (r *LogREST) Get(ctx context.Context, name string, opts runtime.Object) (ru
if !ok {
return nil, fmt.Errorf("invalid options object: %#v", opts)
}
if !utilfeature.DefaultFeatureGate.Enabled(features.AllowInsecureBackendProxy) {
logOpts.InsecureSkipTLSVerifyBackend = false
}

if errs := validation.ValidatePodLogOptions(logOpts); len(errs) > 0 {
return nil, errors.NewInvalid(api.Kind("PodLogOptions"), name, errs)
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/registry/core/pod/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ import (
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/storage"
"k8s.io/apiserver/pkg/storage/names"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/api/legacyscheme"
podutil "k8s.io/kubernetes/pkg/api/pod"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/helper/qos"
"k8s.io/kubernetes/pkg/apis/core/validation"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/kubelet/client"
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
)
Expand Down Expand Up @@ -382,6 +384,10 @@ func LogLocation(
Path: fmt.Sprintf("/containerLogs/%s/%s/%s", pod.Namespace, pod.Name, container),
RawQuery: params.Encode(),
}

if opts.InsecureSkipTLSVerifyBackend && utilfeature.DefaultFeatureGate.Enabled(features.AllowInsecureBackendProxy) {
return loc, nodeInfo.InsecureSkipTLSVerifyTransport, nil
}
return loc, nodeInfo.Transport, nil
}

Expand Down
Loading

0 comments on commit 867ee1d

Please sign in to comment.