1
0
mirror of https://github.com/rancher/steve.git synced 2025-06-30 08:42:06 +00:00
steve/pkg/resources/clusters/shell.go

119 lines
2.9 KiB
Go
Raw Normal View History

2020-06-01 22:59:38 +00:00
package clusters
import (
"context"
"net/http"
"net/http/httputil"
"time"
2020-07-19 20:55:34 +00:00
"github.com/rancher/steve/pkg/podimpersonation"
"github.com/rancher/steve/pkg/stores/proxy"
2020-06-01 22:59:38 +00:00
"github.com/rancher/wrangler/pkg/schemas/validation"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
2020-06-02 15:51:42 +00:00
)
2020-06-01 22:59:38 +00:00
type shell struct {
2020-07-19 20:55:34 +00:00
namespace string
impersonator *podimpersonation.PodImpersonation
cg proxy.ClientGetter
2020-06-02 15:51:42 +00:00
}
2020-06-01 22:59:38 +00:00
func (s *shell) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
ctx, user, client, err := s.contextAndClient(req)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
2020-07-19 20:55:34 +00:00
pod, err := s.impersonator.CreatePod(ctx, user, s.createPod(), &podimpersonation.PodOptions{
Wait: true,
})
2020-06-01 22:59:38 +00:00
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
s.proxyRequest(rw, req, pod, client)
}
func (s *shell) proxyRequest(rw http.ResponseWriter, req *http.Request, pod *v1.Pod, client kubernetes.Interface) {
attachURL := client.CoreV1().RESTClient().
Get().
Namespace(pod.Namespace).
Resource("pods").
Name(pod.Name).
SubResource("attach").
VersionedParams(&v1.PodAttachOptions{
2020-06-22 16:41:48 +00:00
Stdin: true,
Stdout: true,
Stderr: true,
TTY: true,
2020-06-02 15:51:42 +00:00
Container: "shell",
2020-06-01 22:59:38 +00:00
}, scheme.ParameterCodec).URL()
httpClient := client.CoreV1().RESTClient().(*rest.RESTClient).Client
p := httputil.ReverseProxy{
Director: func(req *http.Request) {
req.URL = attachURL
req.Host = attachURL.Host
delete(req.Header, "Authorization")
delete(req.Header, "Cookie")
},
Transport: httpClient.Transport,
FlushInterval: time.Millisecond * 100,
}
p.ServeHTTP(rw, req)
}
func (s *shell) contextAndClient(req *http.Request) (context.Context, user.Info, kubernetes.Interface, error) {
ctx := req.Context()
2020-06-02 15:51:42 +00:00
client, err := s.cg.AdminK8sInterface()
2020-06-01 22:59:38 +00:00
if err != nil {
return ctx, nil, nil, err
}
user, ok := request.UserFrom(ctx)
if !ok {
return ctx, nil, nil, validation.Unauthorized
}
return ctx, user, client, nil
}
2020-07-19 20:55:34 +00:00
func (s *shell) createPod() *v1.Pod {
return &v1.Pod{
2020-06-01 22:59:38 +00:00
ObjectMeta: metav1.ObjectMeta{
GenerateName: "dashboard-shell-",
2020-07-19 20:55:34 +00:00
Namespace: s.namespace,
2020-06-01 22:59:38 +00:00
},
Spec: v1.PodSpec{
2020-07-19 20:55:34 +00:00
TerminationGracePeriodSeconds: new(int64),
RestartPolicy: v1.RestartPolicyNever,
2020-06-01 22:59:38 +00:00
Containers: []v1.Container{
{
2020-07-19 20:55:34 +00:00
Name: "shell",
TTY: true,
Stdin: true,
StdinOnce: true,
2020-06-02 15:51:42 +00:00
Env: []v1.EnvVar{
{
Name: "KUBECONFIG",
2020-07-19 20:55:34 +00:00
Value: "/home/shell/.kube/config",
2020-06-01 22:59:38 +00:00
},
},
2020-06-02 15:51:42 +00:00
Image: "ibuildthecloud/shell:v0.0.1",
ImagePullPolicy: v1.PullIfNotPresent,
Command: []string{"bash"},
},
2020-06-01 22:59:38 +00:00
},
},
}
}