add insecurebackendproxy

This commit is contained in:
David Eads 2019-10-11 14:21:49 -04:00
parent a886247fe4
commit 867ee1d5ff
14 changed files with 448 additions and 38 deletions

View File

@ -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

View File

@ -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() {
@ -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:

View File

@ -65,10 +65,11 @@ 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
@ -76,9 +77,28 @@ 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
}
@ -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
}
@ -163,6 +185,10 @@ 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 {
@ -170,10 +196,11 @@ func NewNodeConnectionInfoGetter(nodes NodeGetter, config KubeletClientConfig) (
}
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
@ -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
}

View File

@ -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"
@ -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))
}
}

View File

@ -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",
@ -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",
],
)

View File

@ -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",

View File

@ -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"
)
@ -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)
}

View File

@ -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"
)
@ -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
}

View File

@ -18,6 +18,7 @@ package pod
import (
"context"
"net/http"
"net/url"
"reflect"
"testing"
@ -320,31 +321,56 @@ func (g mockPodGetter) Get(context.Context, string, *metav1.GetOptions) (runtime
func TestCheckLogLocation(t *testing.T) {
ctx := genericapirequest.NewDefaultContext()
tcs := []struct {
in *api.Pod
opts *api.PodLogOptions
expectedErr error
name string
in *api.Pod
opts *api.PodLogOptions
expectedErr error
expectedTransport http.RoundTripper
}{
{
in: &api.Pod{
Spec: api.PodSpec{},
Status: api.PodStatus{},
},
opts: &api.PodLogOptions{},
expectedErr: errors.NewBadRequest("a container name must be specified for pod test"),
},
{
name: "simple",
in: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{Name: "mycontainer"},
},
NodeName: "foo",
},
Status: api.PodStatus{},
},
opts: &api.PodLogOptions{},
expectedErr: nil,
opts: &api.PodLogOptions{},
expectedErr: nil,
expectedTransport: fakeSecureRoundTripper,
},
{
name: "insecure",
in: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{Name: "mycontainer"},
},
NodeName: "foo",
},
Status: api.PodStatus{},
},
opts: &api.PodLogOptions{
InsecureSkipTLSVerifyBackend: true,
},
expectedErr: nil,
expectedTransport: fakeInsecureRoundTripper,
},
{
name: "missing container",
in: &api.Pod{
Spec: api.PodSpec{},
Status: api.PodStatus{},
},
opts: &api.PodLogOptions{},
expectedErr: errors.NewBadRequest("a container name must be specified for pod test"),
expectedTransport: nil,
},
{
name: "choice of two containers",
in: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
@ -354,10 +380,12 @@ func TestCheckLogLocation(t *testing.T) {
},
Status: api.PodStatus{},
},
opts: &api.PodLogOptions{},
expectedErr: errors.NewBadRequest("a container name must be specified for pod test, choose one of: [container1 container2]"),
opts: &api.PodLogOptions{},
expectedErr: errors.NewBadRequest("a container name must be specified for pod test, choose one of: [container1 container2]"),
expectedTransport: nil,
},
{
name: "initcontainers",
in: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
@ -370,10 +398,12 @@ func TestCheckLogLocation(t *testing.T) {
},
Status: api.PodStatus{},
},
opts: &api.PodLogOptions{},
expectedErr: errors.NewBadRequest("a container name must be specified for pod test, choose one of: [container1 container2] or one of the init containers: [initcontainer1]"),
opts: &api.PodLogOptions{},
expectedErr: errors.NewBadRequest("a container name must be specified for pod test, choose one of: [container1 container2] or one of the init containers: [initcontainer1]"),
expectedTransport: nil,
},
{
name: "bad container",
in: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
@ -386,30 +416,44 @@ func TestCheckLogLocation(t *testing.T) {
opts: &api.PodLogOptions{
Container: "unknown",
},
expectedErr: errors.NewBadRequest("container unknown is not valid for pod test"),
expectedErr: errors.NewBadRequest("container unknown is not valid for pod test"),
expectedTransport: nil,
},
{
name: "good with two containers",
in: &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{Name: "container1"},
{Name: "container2"},
},
NodeName: "foo",
},
Status: api.PodStatus{},
},
opts: &api.PodLogOptions{
Container: "container2",
},
expectedErr: nil,
expectedErr: nil,
expectedTransport: fakeSecureRoundTripper,
},
}
for _, tc := range tcs {
getter := &mockPodGetter{tc.in}
_, _, err := LogLocation(getter, nil, ctx, "test", tc.opts)
if !reflect.DeepEqual(err, tc.expectedErr) {
t.Errorf("expected %v, got %v", tc.expectedErr, err)
}
t.Run(tc.name, func(t *testing.T) {
getter := &mockPodGetter{tc.in}
connectionGetter := &mockConnectionInfoGetter{&client.ConnectionInfo{
Transport: fakeSecureRoundTripper,
InsecureSkipTLSVerifyTransport: fakeInsecureRoundTripper,
}}
_, actualTransport, err := LogLocation(getter, connectionGetter, ctx, "test", tc.opts)
if !reflect.DeepEqual(err, tc.expectedErr) {
t.Errorf("expected %v, got %v", tc.expectedErr, err)
}
if actualTransport != tc.expectedTransport {
t.Errorf("expected %v, got %v", tc.expectedTransport, actualTransport)
}
})
}
}
@ -564,3 +608,16 @@ func TestGetPodIP(t *testing.T) {
})
}
}
type fakeTransport struct {
val string
}
func (f fakeTransport) RoundTrip(*http.Request) (*http.Response, error) {
return nil, nil
}
var (
fakeSecureRoundTripper = fakeTransport{val: "secure"}
fakeInsecureRoundTripper = fakeTransport{val: "insecure"}
)

View File

@ -4808,6 +4808,15 @@ type PodLogOptions struct {
// slightly more or slightly less than the specified limit.
// +optional
LimitBytes *int64 `json:"limitBytes,omitempty" protobuf:"varint,8,opt,name=limitBytes"`
// 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 `json:"insecureSkipTLSVerifyBackend,omitempty" protobuf:"varint,9,opt,name=insecureSkipTLSVerifyBackend"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

View File

@ -89,6 +89,7 @@ filegroup(
":package-srcs",
"//test/integration/apiserver/admissionwebhook:all-srcs",
"//test/integration/apiserver/apply:all-srcs",
"//test/integration/apiserver/podlogs:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -0,0 +1,30 @@
load("@io_bazel_rules_go//go:def.bzl", "go_test")
go_test(
name = "go_default_test",
srcs = [
"main_test.go",
"podlogs_test.go",
],
tags = ["integration"],
deps = [
"//cmd/kube-apiserver/app/options:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//test/integration/framework:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,27 @@
/*
Copyright 2017 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.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package podlogs
import (
"testing"
"k8s.io/kubernetes/test/integration/framework"
)
func TestMain(m *testing.M) {
framework.EtcdMain(m.Run)
}

View File

@ -0,0 +1,165 @@
/*
Copyright 2018 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.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package podlogs
import (
"net"
"net/http"
"net/http/httptest"
"net/url"
"strconv"
"strings"
"testing"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
"k8s.io/kubernetes/test/integration/framework"
)
func TestInsecurePodLogs(t *testing.T) {
stopCh := make(chan struct{})
defer close(stopCh)
clientSet, _ := framework.StartTestServer(t, stopCh, framework.TestServerSetup{
ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
opts.GenericServerRunOptions.MaxRequestBodyBytes = 1024 * 1024
// I have no idea what this cert is, but it doesn't matter, we just want something that always fails validation
opts.KubeletConfig.CAData = []byte(` -----BEGIN CERTIFICATE-----
MIIDMDCCAhigAwIBAgIIHNPD7sig7YIwDQYJKoZIhvcNAQELBQAwNjESMBAGA1UE
CxMJb3BlbnNoaWZ0MSAwHgYDVQQDExdhZG1pbi1rdWJlY29uZmlnLXNpZ25lcjAe
Fw0xOTA1MzAxNTA3MzlaFw0yOTA1MjcxNTA3MzlaMDYxEjAQBgNVBAsTCW9wZW5z
aGlmdDEgMB4GA1UEAxMXYWRtaW4ta3ViZWNvbmZpZy1zaWduZXIwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQD0dHk23lHRcuq06FzYDOl9J9+s8pnGxqA3
IPcARI6ag/98aYe3ENwAB5e1i7AU2F2WiDZgj444w374XLdVgIK8zgQEm9yoqrlc
+/ayO7ceKklrKHOMwh63LvGLEOqzhol2nFmBhXAZt+HyIoZHXN0IqlA92196+Dml
0WOn1F4ce6JbAtEceFHPgLeI7KFmVaPz2796pBXh23ii6r7WvV1Rn9MKlMSBJQR4
0LZzu9/j+GdnFXewdLAAMfgPzwEqv6h3PzvtUCjgdraHEm8Rs7s15S3PUmLK4RQS
PsThx5BhJEGd/W6EzQ3BKoQfochhu3mnAQtW1J07CullySQ5Gg9fAgMBAAGjQjBA
MA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQkTaaw
YJSZ5k2Wd+OsM4GFMTGdqzANBgkqhkiG9w0BAQsFAAOCAQEAHK7+zBZPLqK+f9DT
UEnpwRmZ0aeGS4YgbGIkqpjxJymVOwkRd5A1wslvVfGZ6yOQthF6KlCmqnPyJJMR
I7FHw8j0h2ci90fEQ6IS90Y/ZJXkcgiK9Ncwa35GFGs8QrBxN4leGhtm84BnnBHN
cTWpa4zcBwru0CRG7iHc66VX16X8jHB1iFeZ5W/FgY4MsE+G1Vze4mCXSPVI4BZ2
/qlAgogjBivvSwQ9SFuCszg7IPjvT2ksm+Cf+8eT4YBqW41F85vBGR+FYK14yIla
Bgqc+dJN9xS9Ah5gLiGQJ6C4niUA11piCpvMsy+j/LQ1Erx47KMar5fuMXYk7iPq
1vqIwg==
-----END CERTIFICATE-----
`)
},
})
fakeKubeletServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("fake-log"))
w.WriteHeader(http.StatusOK)
}))
defer fakeKubeletServer.Close()
fakeKubeletURL, err := url.Parse(fakeKubeletServer.URL)
if err != nil {
t.Fatal(err)
}
fakeKubeletHost, fakeKubeletPortStr, err := net.SplitHostPort(fakeKubeletURL.Host)
if err != nil {
t.Fatal(err)
}
fakeKubeletPort, err := strconv.ParseUint(fakeKubeletPortStr, 10, 32)
if err != nil {
t.Fatal(err)
}
node, err := clientSet.CoreV1().Nodes().Create(&corev1.Node{
ObjectMeta: metav1.ObjectMeta{Name: "fake"},
})
if err != nil {
t.Fatal(err)
}
node.Status = corev1.NodeStatus{
Addresses: []corev1.NodeAddress{
{
Type: corev1.NodeExternalIP,
Address: fakeKubeletHost,
},
},
DaemonEndpoints: corev1.NodeDaemonEndpoints{
KubeletEndpoint: corev1.DaemonEndpoint{
Port: int32(fakeKubeletPort),
},
},
}
node, err = clientSet.CoreV1().Nodes().UpdateStatus(node)
if err != nil {
t.Fatal(err)
}
_, err = clientSet.CoreV1().Namespaces().Create(&corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{Name: "ns"},
})
if err != nil {
t.Fatal(err)
}
_, err = clientSet.CoreV1().ServiceAccounts("ns").Create(&corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "ns"},
})
if err != nil {
t.Fatal(err)
}
falseRef := false
pod, err := clientSet.CoreV1().Pods("ns").Create(&corev1.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "test-pod", Namespace: "ns"},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "foo",
Image: "some/image:latest",
},
},
NodeName: node.Name,
AutomountServiceAccountToken: &falseRef,
},
})
if err != nil {
t.Fatal(err)
}
insecureResult := clientSet.CoreV1().Pods("ns").GetLogs(pod.Name, &corev1.PodLogOptions{InsecureSkipTLSVerifyBackend: true}).Do()
if err := insecureResult.Error(); err != nil {
t.Fatal(err)
}
insecureStatusCode := 0
insecureResult.StatusCode(&insecureStatusCode)
if insecureStatusCode != http.StatusOK {
t.Fatal(insecureStatusCode)
}
secureResult := clientSet.CoreV1().Pods("ns").GetLogs(pod.Name, &corev1.PodLogOptions{}).Do()
if err := secureResult.Error(); err == nil || !strings.Contains(err.Error(), "x509: certificate signed by unknown authority") {
t.Fatal(err)
}
secureStatusCode := 0
secureResult.StatusCode(&secureStatusCode)
if secureStatusCode == http.StatusOK {
raw, rawErr := secureResult.Raw()
if rawErr != nil {
t.Log(rawErr)
}
t.Log(string(raw))
t.Fatal(secureStatusCode)
}
}