mirror of https://github.com/portainer/portainer
feat(edge) EE-743 enable signature checking for edge agent (#5355)
Co-authored-by: Simon Meng <simon.meng@portainer.io>pull/5315/head
parent
31fe65eade
commit
9af291b67d
|
@ -42,7 +42,7 @@ func (factory *ClientFactory) CreateClient(endpoint *portainer.Endpoint, nodeNam
|
||||||
} else if endpoint.Type == portainer.AgentOnDockerEnvironment {
|
} else if endpoint.Type == portainer.AgentOnDockerEnvironment {
|
||||||
return createAgentClient(endpoint, factory.signatureService, nodeName)
|
return createAgentClient(endpoint, factory.signatureService, nodeName)
|
||||||
} else if endpoint.Type == portainer.EdgeAgentOnDockerEnvironment {
|
} 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://") {
|
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)
|
httpCli, err := httpClient(endpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 != "" {
|
if nodeName != "" {
|
||||||
headers[portainer.PortainerAgentTargetHeader] = nodeName
|
headers[portainer.PortainerAgentTargetHeader] = nodeName
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,14 @@ func (handler *Handler) proxyEdgeAgentWebsocketRequest(w http.ResponseWriter, r
|
||||||
endpointURL.Scheme = "ws"
|
endpointURL.Scheme = "ws"
|
||||||
proxy := websocketproxy.NewProxy(endpointURL)
|
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) {
|
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.PortainerAgentTargetHeader, params.nodeName)
|
||||||
out.Set(portainer.PortainerAgentKubernetesSATokenHeader, params.token)
|
out.Set(portainer.PortainerAgentKubernetesSATokenHeader, params.token)
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ func (transport *Transport) ProxyDockerRequest(request *http.Request) (*http.Res
|
||||||
requestPath := apiVersionRe.ReplaceAllString(request.URL.Path, "")
|
requestPath := apiVersionRe.ReplaceAllString(request.URL.Path, "")
|
||||||
request.URL.Path = requestPath
|
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)
|
signature, err := transport.signatureService.CreateSignature(portainer.PortainerAgentSignatureMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -72,7 +72,7 @@ func (factory *ProxyFactory) newKubernetesEdgeHTTPProxy(endpoint *portainer.Endp
|
||||||
|
|
||||||
endpointURL.Scheme = "http"
|
endpointURL.Scheme = "http"
|
||||||
proxy := newSingleHostReverseProxyWithHostHeader(endpointURL)
|
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
|
return proxy, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,12 @@ import (
|
||||||
|
|
||||||
type edgeTransport struct {
|
type edgeTransport struct {
|
||||||
*baseTransport
|
*baseTransport
|
||||||
|
signatureService portainer.DigitalSignatureService
|
||||||
reverseTunnelService portainer.ReverseTunnelService
|
reverseTunnelService portainer.ReverseTunnelService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAgentTransport returns a new transport that can be used to send signed requests to a Portainer Edge agent
|
// 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{
|
transport := &edgeTransport{
|
||||||
baseTransport: newBaseTransport(
|
baseTransport: newBaseTransport(
|
||||||
&http.Transport{},
|
&http.Transport{},
|
||||||
|
@ -24,6 +25,7 @@ func NewEdgeTransport(reverseTunnelService portainer.ReverseTunnelService, endpo
|
||||||
dataStore,
|
dataStore,
|
||||||
),
|
),
|
||||||
reverseTunnelService: reverseTunnelService,
|
reverseTunnelService: reverseTunnelService,
|
||||||
|
signatureService: signatureService,
|
||||||
}
|
}
|
||||||
|
|
||||||
return transport
|
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)
|
response, err := transport.baseTransport.RoundTrip(request)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -115,26 +115,8 @@ func (rt *agentHeaderRoundTripper) RoundTrip(req *http.Request) (*http.Response,
|
||||||
|
|
||||||
func (factory *ClientFactory) buildAgentClient(endpoint *portainer.Endpoint) (*kubernetes.Clientset, error) {
|
func (factory *ClientFactory) buildAgentClient(endpoint *portainer.Endpoint) (*kubernetes.Clientset, error) {
|
||||||
endpointURL := fmt.Sprintf("https://%s/kubernetes", endpoint.URL)
|
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, "")
|
return factory.createRemoteClient(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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (factory *ClientFactory) buildEdgeClient(endpoint *portainer.Endpoint) (*kubernetes.Clientset, error) {
|
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)
|
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, "")
|
config, err := clientcmd.BuildConfigFromFlags(endpointURL, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
config.Insecure = true
|
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 kubernetes.NewForConfig(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue