167 lines
5.4 KiB
Go
167 lines
5.4 KiB
Go
/*
|
|
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 (
|
|
"context"
|
|
"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(context.TODO(), &corev1.Node{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "fake"},
|
|
}, metav1.CreateOptions{})
|
|
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(context.TODO(), node, metav1.UpdateOptions{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err = clientSet.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "ns"},
|
|
}, metav1.CreateOptions{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err = clientSet.CoreV1().ServiceAccounts("ns").Create(context.TODO(), &corev1.ServiceAccount{
|
|
ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "ns"},
|
|
}, metav1.CreateOptions{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
falseRef := false
|
|
pod, err := clientSet.CoreV1().Pods("ns").Create(context.TODO(), &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,
|
|
},
|
|
}, metav1.CreateOptions{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
insecureResult := clientSet.CoreV1().Pods("ns").GetLogs(pod.Name, &corev1.PodLogOptions{InsecureSkipTLSVerifyBackend: true}).Do(context.TODO())
|
|
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(context.TODO())
|
|
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)
|
|
}
|
|
|
|
}
|