mirror of https://github.com/portainer/portainer
Co-authored-by: Simon Meng <simon.meng@portainer.io>pull/4689/head
parent
7848bcf2f4
commit
c9f68a4d8f
|
@ -3,6 +3,7 @@ package kubernetes
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/portainer/portainer/api/http/security"
|
"github.com/portainer/portainer/api/http/security"
|
||||||
|
@ -13,14 +14,16 @@ import (
|
||||||
|
|
||||||
type (
|
type (
|
||||||
localTransport struct {
|
localTransport struct {
|
||||||
httpTransport *http.Transport
|
httpTransport *http.Transport
|
||||||
tokenManager *tokenManager
|
tokenManager *tokenManager
|
||||||
|
endpointIdentifier portainer.EndpointID
|
||||||
}
|
}
|
||||||
|
|
||||||
agentTransport struct {
|
agentTransport struct {
|
||||||
httpTransport *http.Transport
|
httpTransport *http.Transport
|
||||||
tokenManager *tokenManager
|
tokenManager *tokenManager
|
||||||
signatureService portainer.DigitalSignatureService
|
signatureService portainer.DigitalSignatureService
|
||||||
|
endpointIdentifier portainer.EndpointID
|
||||||
}
|
}
|
||||||
|
|
||||||
edgeTransport struct {
|
edgeTransport struct {
|
||||||
|
@ -50,21 +53,11 @@ func NewLocalTransport(tokenManager *tokenManager) (*localTransport, error) {
|
||||||
|
|
||||||
// RoundTrip is the implementation of the the http.RoundTripper interface
|
// RoundTrip is the implementation of the the http.RoundTripper interface
|
||||||
func (transport *localTransport) RoundTrip(request *http.Request) (*http.Response, error) {
|
func (transport *localTransport) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||||
tokenData, err := security.RetrieveTokenData(request)
|
token, err := getRoundTripToken(request, transport.tokenManager, transport.endpointIdentifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var token string
|
|
||||||
if tokenData.Role == portainer.AdministratorRole {
|
|
||||||
token = transport.tokenManager.getAdminServiceAccountToken()
|
|
||||||
} else {
|
|
||||||
token, err = transport.tokenManager.getUserServiceAccountToken(int(tokenData.ID))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
|
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
|
||||||
|
|
||||||
return transport.httpTransport.RoundTrip(request)
|
return transport.httpTransport.RoundTrip(request)
|
||||||
|
@ -85,21 +78,11 @@ func NewAgentTransport(signatureService portainer.DigitalSignatureService, tlsCo
|
||||||
|
|
||||||
// RoundTrip is the implementation of the the http.RoundTripper interface
|
// RoundTrip is the implementation of the the http.RoundTripper interface
|
||||||
func (transport *agentTransport) RoundTrip(request *http.Request) (*http.Response, error) {
|
func (transport *agentTransport) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||||
tokenData, err := security.RetrieveTokenData(request)
|
token, err := getRoundTripToken(request, transport.tokenManager, transport.endpointIdentifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var token string
|
|
||||||
if tokenData.Role == portainer.AdministratorRole {
|
|
||||||
token = transport.tokenManager.getAdminServiceAccountToken()
|
|
||||||
} else {
|
|
||||||
token, err = transport.tokenManager.getUserServiceAccountToken(int(tokenData.ID))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
request.Header.Set(portainer.PortainerAgentKubernetesSATokenHeader, token)
|
request.Header.Set(portainer.PortainerAgentKubernetesSATokenHeader, token)
|
||||||
|
|
||||||
signature, err := transport.signatureService.CreateSignature(portainer.PortainerAgentSignatureMessage)
|
signature, err := transport.signatureService.CreateSignature(portainer.PortainerAgentSignatureMessage)
|
||||||
|
@ -127,21 +110,11 @@ func NewEdgeTransport(reverseTunnelService portainer.ReverseTunnelService, endpo
|
||||||
|
|
||||||
// RoundTrip is the implementation of the the http.RoundTripper interface
|
// RoundTrip is the implementation of the the http.RoundTripper interface
|
||||||
func (transport *edgeTransport) RoundTrip(request *http.Request) (*http.Response, error) {
|
func (transport *edgeTransport) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||||
tokenData, err := security.RetrieveTokenData(request)
|
token, err := getRoundTripToken(request, transport.tokenManager, transport.endpointIdentifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var token string
|
|
||||||
if tokenData.Role == portainer.AdministratorRole {
|
|
||||||
token = transport.tokenManager.getAdminServiceAccountToken()
|
|
||||||
} else {
|
|
||||||
token, err = transport.tokenManager.getUserServiceAccountToken(int(tokenData.ID))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
request.Header.Set(portainer.PortainerAgentKubernetesSATokenHeader, token)
|
request.Header.Set(portainer.PortainerAgentKubernetesSATokenHeader, token)
|
||||||
|
|
||||||
response, err := transport.httpTransport.RoundTrip(request)
|
response, err := transport.httpTransport.RoundTrip(request)
|
||||||
|
@ -154,3 +127,27 @@ func (transport *edgeTransport) RoundTrip(request *http.Request) (*http.Response
|
||||||
|
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRoundTripToken(
|
||||||
|
request *http.Request,
|
||||||
|
tokenManager *tokenManager,
|
||||||
|
endpointIdentifier portainer.EndpointID,
|
||||||
|
) (string, error) {
|
||||||
|
tokenData, err := security.RetrieveTokenData(request)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var token string
|
||||||
|
if tokenData.Role == portainer.AdministratorRole {
|
||||||
|
token = tokenManager.getAdminServiceAccountToken()
|
||||||
|
} else {
|
||||||
|
token, err = tokenManager.getUserServiceAccountToken(int(tokenData.ID))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed retrieving service account token: %v", err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ type (
|
||||||
proxyFactory *factory.ProxyFactory
|
proxyFactory *factory.ProxyFactory
|
||||||
endpointProxies cmap.ConcurrentMap
|
endpointProxies cmap.ConcurrentMap
|
||||||
legacyExtensionProxies cmap.ConcurrentMap
|
legacyExtensionProxies cmap.ConcurrentMap
|
||||||
|
k8sClientFactory *cli.ClientFactory
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ func NewManager(dataStore portainer.DataStore, signatureService portainer.Digita
|
||||||
return &Manager{
|
return &Manager{
|
||||||
endpointProxies: cmap.New(),
|
endpointProxies: cmap.New(),
|
||||||
legacyExtensionProxies: cmap.New(),
|
legacyExtensionProxies: cmap.New(),
|
||||||
|
k8sClientFactory: kubernetesClientFactory,
|
||||||
proxyFactory: factory.NewProxyFactory(dataStore, signatureService, tunnelService, clientFactory, kubernetesClientFactory, kubernetesTokenCacheManager),
|
proxyFactory: factory.NewProxyFactory(dataStore, signatureService, tunnelService, clientFactory, kubernetesClientFactory, kubernetesTokenCacheManager),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,8 +58,11 @@ func (manager *Manager) GetEndpointProxy(endpoint *portainer.Endpoint) http.Hand
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteEndpointProxy deletes the proxy associated to a key
|
// DeleteEndpointProxy deletes the proxy associated to a key
|
||||||
|
// and cleans the k8s endpoint client cache. DeleteEndpointProxy
|
||||||
|
// is currently only called for edge connection clean up.
|
||||||
func (manager *Manager) DeleteEndpointProxy(endpoint *portainer.Endpoint) {
|
func (manager *Manager) DeleteEndpointProxy(endpoint *portainer.Endpoint) {
|
||||||
manager.endpointProxies.Remove(string(endpoint.ID))
|
manager.endpointProxies.Remove(string(endpoint.ID))
|
||||||
|
manager.k8sClientFactory.RemoveKubeClient(endpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateLegacyExtensionProxy creates a new HTTP reverse proxy for a legacy extension and adds it to the registered proxies
|
// CreateLegacyExtensionProxy creates a new HTTP reverse proxy for a legacy extension and adds it to the registered proxies
|
||||||
|
|
|
@ -40,6 +40,11 @@ func NewClientFactory(signatureService portainer.DigitalSignatureService, revers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the cached kube client so a new one can be created
|
||||||
|
func (factory *ClientFactory) RemoveKubeClient(endpoint *portainer.Endpoint) {
|
||||||
|
factory.endpointClients.Remove(strconv.Itoa(int(endpoint.ID)))
|
||||||
|
}
|
||||||
|
|
||||||
// GetKubeClient checks if an existing client is already registered for the endpoint and returns it if one is found.
|
// GetKubeClient checks if an existing client is already registered for the endpoint and returns it if one is found.
|
||||||
// If no client is registered, it will create a new client, register it, and returns it.
|
// If no client is registered, it will create a new client, register it, and returns it.
|
||||||
func (factory *ClientFactory) GetKubeClient(endpoint *portainer.Endpoint) (portainer.KubeClient, error) {
|
func (factory *ClientFactory) GetKubeClient(endpoint *portainer.Endpoint) (portainer.KubeClient, error) {
|
||||||
|
|
Loading…
Reference in New Issue