diff --git a/api/docker/client.go b/api/docker/client.go index dace4800d..2fdb21842 100644 --- a/api/docker/client.go +++ b/api/docker/client.go @@ -42,7 +42,7 @@ func (factory *ClientFactory) CreateClient(endpoint *portainer.Endpoint, nodeNam } else if endpoint.Type == portainer.AgentOnDockerEnvironment { return createAgentClient(endpoint, factory.signatureService, nodeName) } else if endpoint.Type == portainer.EdgeAgentOnDockerEnvironment { - return createEdgeClient(endpoint, factory.reverseTunnelService, nodeName) + return createEdgeClient(endpoint, factory.signatureService, factory.reverseTunnelService, nodeName) } if strings.HasPrefix(endpoint.URL, "unix://") || strings.HasPrefix(endpoint.URL, "npipe://") { @@ -71,13 +71,22 @@ func createTCPClient(endpoint *portainer.Endpoint) (*client.Client, error) { ) } -func createEdgeClient(endpoint *portainer.Endpoint, reverseTunnelService portainer.ReverseTunnelService, nodeName string) (*client.Client, error) { +func createEdgeClient(endpoint *portainer.Endpoint, signatureService portainer.DigitalSignatureService, reverseTunnelService portainer.ReverseTunnelService, nodeName string) (*client.Client, error) { httpCli, err := httpClient(endpoint) if err != nil { return nil, err } - headers := map[string]string{} + signature, err := signatureService.CreateSignature(portainer.PortainerAgentSignatureMessage) + if err != nil { + return nil, err + } + + headers := map[string]string{ + portainer.PortainerAgentPublicKeyHeader: signatureService.EncodedPublicKey(), + portainer.PortainerAgentSignatureHeader: signature, + } + if nodeName != "" { headers[portainer.PortainerAgentTargetHeader] = nodeName } diff --git a/api/http/handler/websocket/proxy.go b/api/http/handler/websocket/proxy.go index 14072d315..a03cb6637 100644 --- a/api/http/handler/websocket/proxy.go +++ b/api/http/handler/websocket/proxy.go @@ -22,7 +22,14 @@ func (handler *Handler) proxyEdgeAgentWebsocketRequest(w http.ResponseWriter, r endpointURL.Scheme = "ws" proxy := websocketproxy.NewProxy(endpointURL) + signature, err := handler.SignatureService.CreateSignature(portainer.PortainerAgentSignatureMessage) + if err != nil { + return err + } + proxy.Director = func(incoming *http.Request, out http.Header) { + out.Set(portainer.PortainerAgentPublicKeyHeader, handler.SignatureService.EncodedPublicKey()) + out.Set(portainer.PortainerAgentSignatureHeader, signature) out.Set(portainer.PortainerAgentTargetHeader, params.nodeName) out.Set(portainer.PortainerAgentKubernetesSATokenHeader, params.token) } diff --git a/api/http/proxy/factory/docker/transport.go b/api/http/proxy/factory/docker/transport.go index 98c755d37..6c043d246 100644 --- a/api/http/proxy/factory/docker/transport.go +++ b/api/http/proxy/factory/docker/transport.go @@ -92,7 +92,7 @@ func (transport *Transport) ProxyDockerRequest(request *http.Request) (*http.Res requestPath := apiVersionRe.ReplaceAllString(request.URL.Path, "") request.URL.Path = requestPath - if transport.endpoint.Type == portainer.AgentOnDockerEnvironment { + if transport.endpoint.Type == portainer.AgentOnDockerEnvironment || transport.endpoint.Type == portainer.EdgeAgentOnDockerEnvironment { signature, err := transport.signatureService.CreateSignature(portainer.PortainerAgentSignatureMessage) if err != nil { return nil, err diff --git a/api/http/proxy/factory/kubernetes.go b/api/http/proxy/factory/kubernetes.go index d4aba1769..1d96d3fd5 100644 --- a/api/http/proxy/factory/kubernetes.go +++ b/api/http/proxy/factory/kubernetes.go @@ -72,7 +72,7 @@ func (factory *ProxyFactory) newKubernetesEdgeHTTPProxy(endpoint *portainer.Endp endpointURL.Scheme = "http" proxy := newSingleHostReverseProxyWithHostHeader(endpointURL) - proxy.Transport = kubernetes.NewEdgeTransport(factory.reverseTunnelService, endpoint, tokenManager, factory.kubernetesClientFactory, factory.dataStore) + proxy.Transport = kubernetes.NewEdgeTransport(factory.dataStore, factory.signatureService, factory.reverseTunnelService, endpoint, tokenManager, factory.kubernetesClientFactory) return proxy, nil } diff --git a/api/http/proxy/factory/kubernetes/edge_transport.go b/api/http/proxy/factory/kubernetes/edge_transport.go index 042982a4d..5d7cc62e6 100644 --- a/api/http/proxy/factory/kubernetes/edge_transport.go +++ b/api/http/proxy/factory/kubernetes/edge_transport.go @@ -10,11 +10,12 @@ import ( type edgeTransport struct { *baseTransport + signatureService portainer.DigitalSignatureService reverseTunnelService portainer.ReverseTunnelService } // NewAgentTransport returns a new transport that can be used to send signed requests to a Portainer Edge agent -func NewEdgeTransport(reverseTunnelService portainer.ReverseTunnelService, endpoint *portainer.Endpoint, tokenManager *tokenManager, k8sClientFactory *cli.ClientFactory, dataStore portainer.DataStore) *edgeTransport { +func NewEdgeTransport(dataStore portainer.DataStore, signatureService portainer.DigitalSignatureService, reverseTunnelService portainer.ReverseTunnelService, endpoint *portainer.Endpoint, tokenManager *tokenManager, k8sClientFactory *cli.ClientFactory) *edgeTransport { transport := &edgeTransport{ baseTransport: newBaseTransport( &http.Transport{}, @@ -24,6 +25,7 @@ func NewEdgeTransport(reverseTunnelService portainer.ReverseTunnelService, endpo dataStore, ), reverseTunnelService: reverseTunnelService, + signatureService: signatureService, } return transport @@ -45,6 +47,14 @@ func (transport *edgeTransport) RoundTrip(request *http.Request) (*http.Response } } + signature, err := transport.signatureService.CreateSignature(portainer.PortainerAgentSignatureMessage) + if err != nil { + return nil, err + } + + request.Header.Set(portainer.PortainerAgentPublicKeyHeader, transport.signatureService.EncodedPublicKey()) + request.Header.Set(portainer.PortainerAgentSignatureHeader, signature) + response, err := transport.baseTransport.RoundTrip(request) if err == nil { diff --git a/api/kubernetes/cli/client.go b/api/kubernetes/cli/client.go index 9e2794bb1..0fc40d384 100644 --- a/api/kubernetes/cli/client.go +++ b/api/kubernetes/cli/client.go @@ -115,26 +115,8 @@ func (rt *agentHeaderRoundTripper) RoundTrip(req *http.Request) (*http.Response, func (factory *ClientFactory) buildAgentClient(endpoint *portainer.Endpoint) (*kubernetes.Clientset, error) { endpointURL := fmt.Sprintf("https://%s/kubernetes", endpoint.URL) - signature, err := factory.signatureService.CreateSignature(portainer.PortainerAgentSignatureMessage) - if err != nil { - return nil, err - } - config, err := clientcmd.BuildConfigFromFlags(endpointURL, "") - if err != nil { - return nil, err - } - config.Insecure = true - - config.Wrap(func(rt http.RoundTripper) http.RoundTripper { - return &agentHeaderRoundTripper{ - signatureHeader: signature, - publicKeyHeader: factory.signatureService.EncodedPublicKey(), - roundTripper: rt, - } - }) - - return kubernetes.NewForConfig(config) + return factory.createRemoteClient(endpointURL); } func (factory *ClientFactory) buildEdgeClient(endpoint *portainer.Endpoint) (*kubernetes.Clientset, error) { @@ -163,12 +145,29 @@ func (factory *ClientFactory) buildEdgeClient(endpoint *portainer.Endpoint) (*ku endpointURL := fmt.Sprintf("http://127.0.0.1:%d/kubernetes", tunnel.Port) + return factory.createRemoteClient(endpointURL); +} + +func (factory *ClientFactory) createRemoteClient(endpointURL string) (*kubernetes.Clientset, error) { + signature, err := factory.signatureService.CreateSignature(portainer.PortainerAgentSignatureMessage) + if err != nil { + return nil, err + } + config, err := clientcmd.BuildConfigFromFlags(endpointURL, "") if err != nil { return nil, err } config.Insecure = true + config.Wrap(func(rt http.RoundTripper) http.RoundTripper { + return &agentHeaderRoundTripper{ + signatureHeader: signature, + publicKeyHeader: factory.signatureService.EncodedPublicKey(), + roundTripper: rt, + } + }) + return kubernetes.NewForConfig(config) }