mirror of
https://github.com/portainer/portainer.git
synced 2025-08-04 21:35:23 +02:00
fix(tls): centralize the TLS configuration to ensure FIPS compliance BE-11979 (#960)
This commit is contained in:
parent
3eab294908
commit
163aa57e5c
25 changed files with 454 additions and 112 deletions
|
@ -14,8 +14,13 @@ linters:
|
||||||
- perfsprint
|
- perfsprint
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- bodyclose
|
- bodyclose
|
||||||
|
- forbidigo
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
|
forbidigo:
|
||||||
|
forbid:
|
||||||
|
- p: ^tls\.Config$
|
||||||
|
msg: 'Use crypto.CreateTLSConfiguration() instead'
|
||||||
depguard:
|
depguard:
|
||||||
rules:
|
rules:
|
||||||
main:
|
main:
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
// GetAgentVersionAndPlatform returns the agent version and platform
|
// GetAgentVersionAndPlatform returns the agent version and platform
|
||||||
//
|
//
|
||||||
// it sends a ping to the agent and parses the version and platform from the headers
|
// it sends a ping to the agent and parses the version and platform from the headers
|
||||||
func GetAgentVersionAndPlatform(endpointUrl string, tlsConfig *tls.Config) (portainer.AgentPlatform, string, error) {
|
func GetAgentVersionAndPlatform(endpointUrl string, tlsConfig *tls.Config) (portainer.AgentPlatform, string, error) { //nolint:forbidigo
|
||||||
httpCli := &http.Client{
|
httpCli := &http.Client{
|
||||||
Timeout: 3 * time.Second,
|
Timeout: 3 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,36 @@
|
||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/fips140"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateTLSConfiguration creates a basic tls.Config with recommended TLS settings
|
// CreateTLSConfiguration creates a basic tls.Config with recommended TLS settings
|
||||||
func CreateTLSConfiguration() *tls.Config {
|
func CreateTLSConfiguration() *tls.Config { //nolint:forbidigo
|
||||||
return &tls.Config{
|
// TODO: use fips.FIPSMode() instead
|
||||||
|
return createTLSConfiguration(fips140.Enabled())
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTLSConfiguration(fipsEnabled bool) *tls.Config { //nolint:forbidigo
|
||||||
|
if fipsEnabled {
|
||||||
|
return &tls.Config{ //nolint:forbidigo
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
MaxVersion: tls.VersionTLS13,
|
||||||
|
CipherSuites: []uint16{
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
},
|
||||||
|
CurvePreferences: []tls.CurveID{tls.CurveP256, tls.CurveP384, tls.CurveP521},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tls.Config{ //nolint:forbidigo
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
CipherSuites: []uint16{
|
CipherSuites: []uint16{
|
||||||
tls.TLS_AES_128_GCM_SHA256,
|
tls.TLS_AES_128_GCM_SHA256,
|
||||||
|
@ -34,19 +56,29 @@ func CreateTLSConfiguration() *tls.Config {
|
||||||
|
|
||||||
// CreateTLSConfigurationFromBytes initializes a tls.Config using a CA certificate, a certificate and a key
|
// CreateTLSConfigurationFromBytes initializes a tls.Config using a CA certificate, a certificate and a key
|
||||||
// loaded from memory.
|
// loaded from memory.
|
||||||
func CreateTLSConfigurationFromBytes(caCert, cert, key []byte, skipClientVerification, skipServerVerification bool) (*tls.Config, error) {
|
func CreateTLSConfigurationFromBytes(useTLS bool, caCert, cert, key []byte, skipClientVerification, skipServerVerification bool) (*tls.Config, error) { //nolint:forbidigo
|
||||||
config := CreateTLSConfiguration()
|
// TODO: use fips.FIPSMode() instead
|
||||||
config.InsecureSkipVerify = skipServerVerification
|
return createTLSConfigurationFromBytes(fips140.Enabled(), useTLS, caCert, cert, key, skipClientVerification, skipServerVerification)
|
||||||
|
}
|
||||||
|
|
||||||
if !skipClientVerification {
|
func createTLSConfigurationFromBytes(fipsEnabled, useTLS bool, caCert, cert, key []byte, skipClientVerification, skipServerVerification bool) (*tls.Config, error) { //nolint:forbidigo
|
||||||
|
if !useTLS {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
config := CreateTLSConfiguration()
|
||||||
|
config.InsecureSkipVerify = skipServerVerification && !fipsEnabled
|
||||||
|
|
||||||
|
if !skipClientVerification || fipsEnabled {
|
||||||
certificate, err := tls.X509KeyPair(cert, key)
|
certificate, err := tls.X509KeyPair(cert, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Certificates = []tls.Certificate{certificate}
|
config.Certificates = []tls.Certificate{certificate}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !skipServerVerification {
|
if !skipServerVerification || fipsEnabled {
|
||||||
caCertPool := x509.NewCertPool()
|
caCertPool := x509.NewCertPool()
|
||||||
caCertPool.AppendCertsFromPEM(caCert)
|
caCertPool.AppendCertsFromPEM(caCert)
|
||||||
config.RootCAs = caCertPool
|
config.RootCAs = caCertPool
|
||||||
|
@ -57,29 +89,38 @@ func CreateTLSConfigurationFromBytes(caCert, cert, key []byte, skipClientVerific
|
||||||
|
|
||||||
// CreateTLSConfigurationFromDisk initializes a tls.Config using a CA certificate, a certificate and a key
|
// CreateTLSConfigurationFromDisk initializes a tls.Config using a CA certificate, a certificate and a key
|
||||||
// loaded from disk.
|
// loaded from disk.
|
||||||
func CreateTLSConfigurationFromDisk(caCertPath, certPath, keyPath string, skipServerVerification bool) (*tls.Config, error) {
|
func CreateTLSConfigurationFromDisk(config portainer.TLSConfiguration) (*tls.Config, error) { //nolint:forbidigo
|
||||||
config := CreateTLSConfiguration()
|
// TODO: use fips.FIPSMode() instead
|
||||||
config.InsecureSkipVerify = skipServerVerification
|
return createTLSConfigurationFromDisk(fips140.Enabled(), config)
|
||||||
|
}
|
||||||
|
|
||||||
if certPath != "" && keyPath != "" {
|
func createTLSConfigurationFromDisk(fipsEnabled bool, config portainer.TLSConfiguration) (*tls.Config, error) { //nolint:forbidigo
|
||||||
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
if !config.TLS {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfig := CreateTLSConfiguration()
|
||||||
|
tlsConfig.InsecureSkipVerify = config.TLSSkipVerify && !fipsEnabled
|
||||||
|
|
||||||
|
if config.TLSCertPath != "" && config.TLSKeyPath != "" {
|
||||||
|
cert, err := tls.LoadX509KeyPair(config.TLSCertPath, config.TLSKeyPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Certificates = []tls.Certificate{cert}
|
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !skipServerVerification && caCertPath != "" {
|
if !tlsConfig.InsecureSkipVerify && config.TLSCACertPath != "" {
|
||||||
caCert, err := os.ReadFile(caCertPath)
|
caCert, err := os.ReadFile(config.TLSCACertPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
caCertPool := x509.NewCertPool()
|
caCertPool := x509.NewCertPool()
|
||||||
caCertPool.AppendCertsFromPEM(caCert)
|
caCertPool.AppendCertsFromPEM(caCert)
|
||||||
config.RootCAs = caCertPool
|
tlsConfig.RootCAs = caCertPool
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return tlsConfig, nil
|
||||||
}
|
}
|
||||||
|
|
79
api/crypto/tls_test.go
Normal file
79
api/crypto/tls_test.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateTLSConfiguration(t *testing.T) {
|
||||||
|
config := CreateTLSConfiguration()
|
||||||
|
require.Equal(t, config.MinVersion, uint16(tls.VersionTLS12))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateTLSConfigurationFIPS(t *testing.T) {
|
||||||
|
fips := true
|
||||||
|
|
||||||
|
fipsCipherSuites := []uint16{
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
}
|
||||||
|
|
||||||
|
fipsCurvePreferences := []tls.CurveID{tls.CurveP256, tls.CurveP384, tls.CurveP521}
|
||||||
|
|
||||||
|
config := createTLSConfiguration(fips)
|
||||||
|
require.Equal(t, config.MinVersion, uint16(tls.VersionTLS12))
|
||||||
|
require.Equal(t, config.MaxVersion, uint16(tls.VersionTLS13))
|
||||||
|
require.Equal(t, config.CipherSuites, fipsCipherSuites)
|
||||||
|
require.Equal(t, config.CurvePreferences, fipsCurvePreferences)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateTLSConfigurationFromBytes(t *testing.T) {
|
||||||
|
// No TLS
|
||||||
|
config, err := CreateTLSConfigurationFromBytes(false, nil, nil, nil, false, false)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Nil(t, config)
|
||||||
|
|
||||||
|
// Skip TLS client/server verifications
|
||||||
|
config, err = CreateTLSConfigurationFromBytes(true, nil, nil, nil, true, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, config)
|
||||||
|
|
||||||
|
// Empty TLS
|
||||||
|
config, err = CreateTLSConfigurationFromBytes(true, nil, nil, nil, false, false)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Nil(t, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateTLSConfigurationFromDisk(t *testing.T) {
|
||||||
|
// No TLS
|
||||||
|
config, err := CreateTLSConfigurationFromDisk(portainer.TLSConfiguration{})
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Nil(t, config)
|
||||||
|
|
||||||
|
// Skip TLS verifications
|
||||||
|
config, err = CreateTLSConfigurationFromDisk(portainer.TLSConfiguration{
|
||||||
|
TLS: true,
|
||||||
|
TLSSkipVerify: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateTLSConfigurationFromDiskFIPS(t *testing.T) {
|
||||||
|
fips := true
|
||||||
|
|
||||||
|
// Skipping TLS verifications cannot be done in FIPS mode
|
||||||
|
config, err := createTLSConfigurationFromDisk(fips, portainer.TLSConfiguration{
|
||||||
|
TLS: true,
|
||||||
|
TLSSkipVerify: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, config)
|
||||||
|
require.False(t, config.InsecureSkipVerify)
|
||||||
|
}
|
|
@ -181,10 +181,11 @@ func httpClient(endpoint *portainer.Endpoint, timeout *time.Duration) (*http.Cli
|
||||||
}
|
}
|
||||||
|
|
||||||
if endpoint.TLSConfig.TLS {
|
if endpoint.TLSConfig.TLS {
|
||||||
tlsConfig, err := crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig.TLSCACertPath, endpoint.TLSConfig.TLSCertPath, endpoint.TLSConfig.TLSKeyPath, endpoint.TLSConfig.TLSSkipVerify)
|
tlsConfig, err := crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
transport.TLSClientConfig = tlsConfig
|
transport.TLSClientConfig = tlsConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
api/docker/client/client_test.go
Normal file
26
api/docker/client/client_test.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHttpClient(t *testing.T) {
|
||||||
|
// Valid TLS configuration
|
||||||
|
endpoint := &portainer.Endpoint{}
|
||||||
|
endpoint.TLSConfig = portainer.TLSConfiguration{TLS: true}
|
||||||
|
|
||||||
|
cli, err := httpClient(endpoint, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, cli)
|
||||||
|
|
||||||
|
// Invalid TLS configuration
|
||||||
|
endpoint.TLSConfig.TLSCertPath = "/invalid/path/client.crt"
|
||||||
|
endpoint.TLSConfig.TLSKeyPath = "/invalid/path/client.key"
|
||||||
|
|
||||||
|
cli, err = httpClient(endpoint, nil)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Nil(t, cli)
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -11,6 +10,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
"github.com/portainer/portainer/api/crypto"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/segmentio/encoding/json"
|
"github.com/segmentio/encoding/json"
|
||||||
|
@ -105,21 +105,28 @@ func Get(url string, timeout int) ([]byte, error) {
|
||||||
// ExecutePingOperation will send a SystemPing operation HTTP request to a Docker environment(endpoint)
|
// ExecutePingOperation will send a SystemPing operation HTTP request to a Docker environment(endpoint)
|
||||||
// using the specified host and optional TLS configuration.
|
// using the specified host and optional TLS configuration.
|
||||||
// It uses a new Http.Client for each operation.
|
// It uses a new Http.Client for each operation.
|
||||||
func ExecutePingOperation(host string, tlsConfig *tls.Config) (bool, error) {
|
func ExecutePingOperation(host string, tlsConfiguration portainer.TLSConfiguration) (bool, error) {
|
||||||
transport := &http.Transport{}
|
transport := &http.Transport{}
|
||||||
|
|
||||||
scheme := "http"
|
scheme := "http"
|
||||||
if tlsConfig != nil {
|
|
||||||
|
if tlsConfiguration.TLS {
|
||||||
|
tlsConfig, err := crypto.CreateTLSConfigurationFromDisk(tlsConfiguration)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
transport.TLSClientConfig = tlsConfig
|
transport.TLSClientConfig = tlsConfig
|
||||||
scheme = "https"
|
scheme = "https"
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Timeout: time.Second * 3,
|
Timeout: 3 * time.Second,
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
}
|
}
|
||||||
|
|
||||||
target := strings.Replace(host, "tcp://", scheme+"://", 1)
|
target := strings.Replace(host, "tcp://", scheme+"://", 1)
|
||||||
|
|
||||||
return pingOperation(client, target)
|
return pingOperation(client, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
api/http/client/client_test.go
Normal file
31
api/http/client/client_test.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExecutePingOperationFailure(t *testing.T) {
|
||||||
|
host := "http://localhost:1"
|
||||||
|
config := portainer.TLSConfiguration{
|
||||||
|
TLS: true,
|
||||||
|
TLSSkipVerify: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid host
|
||||||
|
ok, err := ExecutePingOperation(host, config)
|
||||||
|
require.False(t, ok)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
// Invalid TLS configuration
|
||||||
|
config.TLSCertPath = "/invalid/path/to/cert"
|
||||||
|
config.TLSKeyPath = "/invalid/path/to/key"
|
||||||
|
|
||||||
|
ok, err = ExecutePingOperation(host, config)
|
||||||
|
require.False(t, ok)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package endpoints
|
package endpoints
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -285,8 +284,6 @@ func (handler *Handler) endpointCreate(w http.ResponseWriter, r *http.Request) *
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler *Handler) createEndpoint(tx dataservices.DataStoreTx, payload *endpointCreatePayload) (*portainer.Endpoint, *httperror.HandlerError) {
|
func (handler *Handler) createEndpoint(tx dataservices.DataStoreTx, payload *endpointCreatePayload) (*portainer.Endpoint, *httperror.HandlerError) {
|
||||||
var err error
|
|
||||||
|
|
||||||
switch payload.EndpointCreationType {
|
switch payload.EndpointCreationType {
|
||||||
case azureEnvironment:
|
case azureEnvironment:
|
||||||
return handler.createAzureEndpoint(tx, payload)
|
return handler.createAzureEndpoint(tx, payload)
|
||||||
|
@ -301,12 +298,9 @@ func (handler *Handler) createEndpoint(tx dataservices.DataStoreTx, payload *end
|
||||||
endpointType := portainer.DockerEnvironment
|
endpointType := portainer.DockerEnvironment
|
||||||
var agentVersion string
|
var agentVersion string
|
||||||
if payload.EndpointCreationType == agentEnvironment {
|
if payload.EndpointCreationType == agentEnvironment {
|
||||||
var tlsConfig *tls.Config
|
tlsConfig, err := crypto.CreateTLSConfigurationFromBytes(payload.TLS, payload.TLSCACertFile, payload.TLSCertFile, payload.TLSKeyFile, payload.TLSSkipVerify, payload.TLSSkipClientVerify)
|
||||||
if payload.TLS {
|
if err != nil {
|
||||||
tlsConfig, err = crypto.CreateTLSConfigurationFromBytes(payload.TLSCACertFile, payload.TLSCertFile, payload.TLSKeyFile, payload.TLSSkipVerify, payload.TLSSkipClientVerify)
|
return nil, httperror.InternalServerError("Unable to create TLS configuration", err)
|
||||||
if err != nil {
|
|
||||||
return nil, httperror.InternalServerError("Unable to create TLS configuration", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
agentPlatform, version, err := agent.GetAgentVersionAndPlatform(payload.URL, tlsConfig)
|
agentPlatform, version, err := agent.GetAgentVersionAndPlatform(payload.URL, tlsConfig)
|
||||||
|
|
|
@ -21,16 +21,14 @@ func initDial(endpoint *portainer.Endpoint) (net.Conn, error) {
|
||||||
host = url.Path
|
host = url.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
if endpoint.TLSConfig.TLS {
|
if !endpoint.TLSConfig.TLS {
|
||||||
tlsConfig, err := crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig.TLSCACertPath, endpoint.TLSConfig.TLSCertPath, endpoint.TLSConfig.TLSKeyPath, endpoint.TLSConfig.TLSSkipVerify)
|
return createDial(url.Scheme, host)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return tls.Dial(url.Scheme, host, tlsConfig)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
con, err := createDial(url.Scheme, host)
|
tlsConfig, err := crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return con, err
|
return tls.Dial(url.Scheme, host, tlsConfig)
|
||||||
}
|
}
|
||||||
|
|
64
api/http/handler/websocket/initdial_test.go
Normal file
64
api/http/handler/websocket/initdial_test.go
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package websocket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInitDial(t *testing.T) {
|
||||||
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}))
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
tlsSrv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}))
|
||||||
|
defer tlsSrv.Close()
|
||||||
|
|
||||||
|
f := func(srvURL string) {
|
||||||
|
u, err := url.Parse(srvURL)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
isTLS := u.Scheme == "https"
|
||||||
|
|
||||||
|
u.Scheme = "tcp"
|
||||||
|
|
||||||
|
endpoint := &portainer.Endpoint{
|
||||||
|
URL: u.String(),
|
||||||
|
TLSConfig: portainer.TLSConfiguration{
|
||||||
|
TLS: isTLS,
|
||||||
|
TLSSkipVerify: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid configuration
|
||||||
|
conn, err := initDial(endpoint)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, conn)
|
||||||
|
|
||||||
|
err = conn.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
if !isTLS {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid TLS configuration
|
||||||
|
endpoint.TLSConfig.TLSCertPath = "/invalid/path/client.crt"
|
||||||
|
endpoint.TLSConfig.TLSKeyPath = "/invalid/path/client.key"
|
||||||
|
|
||||||
|
conn, err = initDial(endpoint)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Nil(t, conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
f(srv.URL)
|
||||||
|
f(tlsSrv.URL)
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ func (factory *ProxyFactory) NewAgentProxy(endpoint *portainer.Endpoint) (*Proxy
|
||||||
httpTransport := &http.Transport{}
|
httpTransport := &http.Transport{}
|
||||||
|
|
||||||
if endpoint.TLSConfig.TLS || endpoint.TLSConfig.TLSSkipVerify {
|
if endpoint.TLSConfig.TLS || endpoint.TLSConfig.TLSSkipVerify {
|
||||||
config, err := crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig.TLSCACertPath, endpoint.TLSConfig.TLSCertPath, endpoint.TLSConfig.TLSKeyPath, endpoint.TLSConfig.TLSSkipVerify)
|
config, err := crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithMessage(err, "failed generating tls configuration")
|
return nil, errors.WithMessage(err, "failed generating tls configuration")
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ func (factory *ProxyFactory) newDockerHTTPProxy(endpoint *portainer.Endpoint) (h
|
||||||
httpTransport := &http.Transport{}
|
httpTransport := &http.Transport{}
|
||||||
|
|
||||||
if endpoint.TLSConfig.TLS || endpoint.TLSConfig.TLSSkipVerify {
|
if endpoint.TLSConfig.TLS || endpoint.TLSConfig.TLSSkipVerify {
|
||||||
config, err := crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig.TLSCACertPath, endpoint.TLSConfig.TLSCertPath, endpoint.TLSConfig.TLSKeyPath, endpoint.TLSConfig.TLSSkipVerify)
|
config, err := crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"github.com/portainer/portainer/api/http/proxy/factory/kubernetes"
|
"github.com/portainer/portainer/api/http/proxy/factory/kubernetes"
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
"github.com/portainer/portainer/api/crypto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (factory *ProxyFactory) newKubernetesProxy(endpoint *portainer.Endpoint) (http.Handler, error) {
|
func (factory *ProxyFactory) newKubernetesProxy(endpoint *portainer.Endpoint) (http.Handler, error) {
|
||||||
|
@ -93,19 +92,19 @@ func (factory *ProxyFactory) newKubernetesAgentHTTPSProxy(endpoint *portainer.En
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConfig, err := crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig.TLSCACertPath, endpoint.TLSConfig.TLSCertPath, endpoint.TLSConfig.TLSKeyPath, endpoint.TLSConfig.TLSSkipVerify)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenCache := factory.kubernetesTokenCacheManager.GetOrCreateTokenCache(endpoint.ID)
|
tokenCache := factory.kubernetesTokenCacheManager.GetOrCreateTokenCache(endpoint.ID)
|
||||||
tokenManager, err := kubernetes.NewTokenManager(kubecli, factory.dataStore, tokenCache, false)
|
tokenManager, err := kubernetes.NewTokenManager(kubecli, factory.dataStore, tokenCache, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transport, err := kubernetes.NewAgentTransport(factory.signatureService, tokenManager, endpoint, factory.kubernetesClientFactory, factory.dataStore, factory.jwtService)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
proxy := NewSingleHostReverseProxyWithHostHeader(remoteURL)
|
proxy := NewSingleHostReverseProxyWithHostHeader(remoteURL)
|
||||||
proxy.Transport = kubernetes.NewAgentTransport(factory.signatureService, tlsConfig, tokenManager, endpoint, factory.kubernetesClientFactory, factory.dataStore, factory.jwtService)
|
proxy.Transport = transport
|
||||||
|
|
||||||
return proxy, nil
|
return proxy, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package kubernetes
|
package kubernetes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
"github.com/portainer/portainer/api/crypto"
|
||||||
"github.com/portainer/portainer/api/dataservices"
|
"github.com/portainer/portainer/api/dataservices"
|
||||||
"github.com/portainer/portainer/api/kubernetes/cli"
|
"github.com/portainer/portainer/api/kubernetes/cli"
|
||||||
)
|
)
|
||||||
|
@ -16,7 +16,12 @@ type agentTransport struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAgentTransport returns a new transport that can be used to send signed requests to a Portainer agent
|
// NewAgentTransport returns a new transport that can be used to send signed requests to a Portainer agent
|
||||||
func NewAgentTransport(signatureService portainer.DigitalSignatureService, tlsConfig *tls.Config, tokenManager *tokenManager, endpoint *portainer.Endpoint, k8sClientFactory *cli.ClientFactory, dataStore dataservices.DataStore, jwtService portainer.JWTService) *agentTransport {
|
func NewAgentTransport(signatureService portainer.DigitalSignatureService, tokenManager *tokenManager, endpoint *portainer.Endpoint, k8sClientFactory *cli.ClientFactory, dataStore dataservices.DataStore, jwtService portainer.JWTService) (*agentTransport, error) {
|
||||||
|
tlsConfig, err := crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
transport := &agentTransport{
|
transport := &agentTransport{
|
||||||
baseTransport: newBaseTransport(
|
baseTransport: newBaseTransport(
|
||||||
&http.Transport{
|
&http.Transport{
|
||||||
|
@ -31,7 +36,7 @@ func NewAgentTransport(signatureService portainer.DigitalSignatureService, tlsCo
|
||||||
signatureService: signatureService,
|
signatureService: signatureService,
|
||||||
}
|
}
|
||||||
|
|
||||||
return transport
|
return transport, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoundTrip is the implementation of the the http.RoundTripper interface
|
// RoundTrip is the implementation of the the http.RoundTripper interface
|
||||||
|
|
|
@ -15,7 +15,7 @@ type localTransport struct {
|
||||||
|
|
||||||
// NewLocalTransport returns a new transport that can be used to send requests to the local Kubernetes API
|
// NewLocalTransport returns a new transport that can be used to send requests to the local Kubernetes API
|
||||||
func NewLocalTransport(tokenManager *tokenManager, endpoint *portainer.Endpoint, k8sClientFactory *cli.ClientFactory, dataStore dataservices.DataStore, jwtService portainer.JWTService) (*localTransport, error) {
|
func NewLocalTransport(tokenManager *tokenManager, endpoint *portainer.Endpoint, k8sClientFactory *cli.ClientFactory, dataStore dataservices.DataStore, jwtService portainer.JWTService) (*localTransport, error) {
|
||||||
config, err := crypto.CreateTLSConfigurationFromBytes(nil, nil, nil, true, true)
|
config, err := crypto.CreateTLSConfigurationFromBytes(true, nil, nil, nil, true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
13
api/http/proxy/factory/kubernetes/local_transport_test.go
Normal file
13
api/http/proxy/factory/kubernetes/local_transport_test.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package kubernetes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewLocalTransport(t *testing.T) {
|
||||||
|
transport, err := NewLocalTransport(nil, nil, nil, nil, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, transport.baseTransport.httpTransport.TLSClientConfig.InsecureSkipVerify)
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
"github.com/portainer/portainer/api/crypto"
|
|
||||||
"github.com/portainer/portainer/api/dataservices"
|
"github.com/portainer/portainer/api/dataservices"
|
||||||
"github.com/portainer/portainer/api/http/client"
|
"github.com/portainer/portainer/api/http/client"
|
||||||
|
|
||||||
|
@ -108,12 +107,7 @@ func createTLSSecuredEndpoint(flags *portainer.CLIFlags, dataStore dataservices.
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(endpoint.URL, "tcp://") {
|
if strings.HasPrefix(endpoint.URL, "tcp://") {
|
||||||
tlsConfig, err := crypto.CreateTLSConfigurationFromDisk(tlsConfiguration.TLSCACertPath, tlsConfiguration.TLSCertPath, tlsConfiguration.TLSKeyPath, tlsConfiguration.TLSSkipVerify)
|
agentOnDockerEnvironment, err := client.ExecutePingOperation(endpoint.URL, tlsConfiguration)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
agentOnDockerEnvironment, err := client.ExecutePingOperation(endpoint.URL, tlsConfig)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -136,7 +130,7 @@ func createTLSSecuredEndpoint(flags *portainer.CLIFlags, dataStore dataservices.
|
||||||
|
|
||||||
func createUnsecuredEndpoint(endpointURL string, dataStore dataservices.DataStore, snapshotService portainer.SnapshotService) error {
|
func createUnsecuredEndpoint(endpointURL string, dataStore dataservices.DataStore, snapshotService portainer.SnapshotService) error {
|
||||||
if strings.HasPrefix(endpointURL, "tcp://") {
|
if strings.HasPrefix(endpointURL, "tcp://") {
|
||||||
if _, err := client.ExecutePingOperation(endpointURL, nil); err != nil {
|
if _, err := client.ExecutePingOperation(endpointURL, portainer.TLSConfiguration{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
api/internal/endpointutils/endpoint_setup_test.go
Normal file
12
api/internal/endpointutils/endpoint_setup_test.go
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package endpointutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateOfflineUnsecuredEndpoint(t *testing.T) {
|
||||||
|
err := createUnsecuredEndpoint("tcp://localhost:1", nil, nil)
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package snapshot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -138,14 +137,9 @@ func SupportDirectSnapshot(endpoint *portainer.Endpoint) bool {
|
||||||
// If the snapshot is a success, it will be associated to the environment(endpoint).
|
// If the snapshot is a success, it will be associated to the environment(endpoint).
|
||||||
func (service *Service) SnapshotEndpoint(endpoint *portainer.Endpoint) error {
|
func (service *Service) SnapshotEndpoint(endpoint *portainer.Endpoint) error {
|
||||||
if endpoint.Type == portainer.AgentOnDockerEnvironment || endpoint.Type == portainer.AgentOnKubernetesEnvironment {
|
if endpoint.Type == portainer.AgentOnDockerEnvironment || endpoint.Type == portainer.AgentOnKubernetesEnvironment {
|
||||||
var err error
|
tlsConfig, err := crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig)
|
||||||
var tlsConfig *tls.Config
|
if err != nil {
|
||||||
|
return err
|
||||||
if endpoint.TLSConfig.TLS {
|
|
||||||
tlsConfig, err = crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig.TLSCACertPath, endpoint.TLSConfig.TLSCertPath, endpoint.TLSConfig.TLSKeyPath, endpoint.TLSConfig.TLSSkipVerify)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, version, err := agent.GetAgentVersionAndPlatform(endpoint.URL, tlsConfig)
|
_, version, err := agent.GetAgentVersionAndPlatform(endpoint.URL, tlsConfig)
|
||||||
|
|
|
@ -4,11 +4,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
ldap "github.com/go-ldap/ldap/v3"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
"github.com/portainer/portainer/api/crypto"
|
"github.com/portainer/portainer/api/crypto"
|
||||||
httperrors "github.com/portainer/portainer/api/http/errors"
|
httperrors "github.com/portainer/portainer/api/http/errors"
|
||||||
|
|
||||||
|
ldap "github.com/go-ldap/ldap/v3"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -30,36 +31,44 @@ func createConnection(settings *portainer.LDAPSettings) (*ldap.Conn, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func createConnectionForURL(url string, settings *portainer.LDAPSettings) (*ldap.Conn, error) {
|
func createConnectionForURL(url string, settings *portainer.LDAPSettings) (*ldap.Conn, error) {
|
||||||
if settings.TLSConfig.TLS || settings.StartTLS {
|
if !settings.TLSConfig.TLS && !settings.StartTLS {
|
||||||
config, err := crypto.CreateTLSConfigurationFromDisk(settings.TLSConfig.TLSCACertPath, settings.TLSConfig.TLSCertPath, settings.TLSConfig.TLSKeyPath, settings.TLSConfig.TLSSkipVerify)
|
return ldap.Dial("tcp", url)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
config.ServerName = strings.Split(url, ":")[0]
|
|
||||||
|
|
||||||
if settings.TLSConfig.TLS {
|
|
||||||
return ldap.DialTLS("tcp", url, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, err := ldap.Dial("tcp", url)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = conn.StartTLS(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return conn, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ldap.Dial("tcp", url)
|
// Store the original value to ensure the TLSConfig is created
|
||||||
|
t := settings.TLSConfig.TLS
|
||||||
|
settings.TLSConfig.TLS = settings.TLSConfig.TLS || settings.StartTLS
|
||||||
|
|
||||||
|
config, err := crypto.CreateTLSConfigurationFromDisk(settings.TLSConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the original value
|
||||||
|
settings.TLSConfig.TLS = t
|
||||||
|
|
||||||
|
if settings.TLSConfig.TLS || settings.StartTLS {
|
||||||
|
config.ServerName = strings.Split(url, ":")[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.TLSConfig.TLS {
|
||||||
|
return ldap.DialTLS("tcp", url, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := ldap.Dial("tcp", url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := conn.StartTLS(config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthenticateUser is used to authenticate a user against a LDAP/AD.
|
// AuthenticateUser is used to authenticate a user against a LDAP/AD.
|
||||||
func (*Service) AuthenticateUser(username, password string, settings *portainer.LDAPSettings) error {
|
func (*Service) AuthenticateUser(username, password string, settings *portainer.LDAPSettings) error {
|
||||||
|
|
||||||
connection, err := createConnection(settings)
|
connection, err := createConnection(settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
72
api/ldap/ldap_test.go
Normal file
72
api/ldap/ldap_test.go
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCreateConnectionForURL(t *testing.T) {
|
||||||
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}))
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
tlsSrv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}))
|
||||||
|
defer tlsSrv.Close()
|
||||||
|
|
||||||
|
srvURL, err := url.Parse(tlsSrv.URL)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// TCP
|
||||||
|
|
||||||
|
settings := &portainer.LDAPSettings{
|
||||||
|
URL: srvURL.Host,
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := createConnectionForURL(settings.URL, settings)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, conn)
|
||||||
|
conn.Close()
|
||||||
|
|
||||||
|
// TLS
|
||||||
|
|
||||||
|
settings.TLSConfig = portainer.TLSConfiguration{
|
||||||
|
TLS: true,
|
||||||
|
TLSSkipVerify: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err = createConnectionForURL(settings.URL, settings)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, conn)
|
||||||
|
conn.Close()
|
||||||
|
|
||||||
|
// Invalid TLS
|
||||||
|
|
||||||
|
settings.TLSConfig = portainer.TLSConfiguration{
|
||||||
|
TLS: true,
|
||||||
|
TLSSkipVerify: true,
|
||||||
|
TLSCertPath: "/invalid/path/cert",
|
||||||
|
TLSKeyPath: "/invalid/path/key",
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err = createConnectionForURL(settings.URL, settings)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Nil(t, conn)
|
||||||
|
|
||||||
|
// StartTLS
|
||||||
|
|
||||||
|
settings.TLSConfig.TLS = false
|
||||||
|
settings.StartTLS = true
|
||||||
|
|
||||||
|
conn, err = createConnectionForURL(settings.URL, settings)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Nil(t, conn)
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package deployments
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
@ -215,13 +214,9 @@ func isEnvironmentOnline(endpoint *portainer.Endpoint) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
tlsConfig, err := crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig)
|
||||||
var tlsConfig *tls.Config
|
if err != nil {
|
||||||
if endpoint.TLSConfig.TLS {
|
return false
|
||||||
tlsConfig, err = crypto.CreateTLSConfigurationFromDisk(endpoint.TLSConfig.TLSCACertPath, endpoint.TLSConfig.TLSCertPath, endpoint.TLSConfig.TLSKeyPath, endpoint.TLSConfig.TLSSkipVerify)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = agent.GetAgentVersionAndPlatform(endpoint.URL, tlsConfig)
|
_, _, err = agent.GetAgentVersionAndPlatform(endpoint.URL, tlsConfig)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
"github.com/portainer/portainer/api/crypto"
|
||||||
"github.com/portainer/portainer/api/datastore"
|
"github.com/portainer/portainer/api/datastore"
|
||||||
gittypes "github.com/portainer/portainer/api/git/types"
|
gittypes "github.com/portainer/portainer/api/git/types"
|
||||||
"github.com/portainer/portainer/api/internal/testhelpers"
|
"github.com/portainer/portainer/api/internal/testhelpers"
|
||||||
|
@ -127,9 +128,8 @@ func agentServer(t *testing.T) string {
|
||||||
cert, err := tls.X509KeyPair([]byte(localhostCert), []byte(localhostKey))
|
cert, err := tls.X509KeyPair([]byte(localhostCert), []byte(localhostKey))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tlsConfig := &tls.Config{
|
tlsConfig := crypto.CreateTLSConfiguration()
|
||||||
Certificates: []tls.Certificate{cert},
|
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||||
}
|
|
||||||
|
|
||||||
l, err := tls.Listen("tcp", "127.0.0.1:0", tlsConfig)
|
l, err := tls.Listen("tcp", "127.0.0.1:0", tlsConfig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package networking
|
package networking
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/fips140"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -9,6 +9,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/portainer/portainer/api/crypto"
|
||||||
|
|
||||||
"github.com/segmentio/encoding/json"
|
"github.com/segmentio/encoding/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -71,13 +73,14 @@ func ProbeTelnetConnection(url string) string {
|
||||||
func DetectProxy(url string) string {
|
func DetectProxy(url string) string {
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{
|
TLSClientConfig: crypto.CreateTLSConfiguration(),
|
||||||
InsecureSkipVerify: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Timeout: 10 * time.Second,
|
Timeout: 10 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use fips.CanTLSSkipVerify() instead
|
||||||
|
client.Transport.(*http.Transport).TLSClientConfig.InsecureSkipVerify = !fips140.Enabled()
|
||||||
|
|
||||||
result := map[string]string{
|
result := map[string]string{
|
||||||
"operation": "proxy detection",
|
"operation": "proxy detection",
|
||||||
"local_address": "unknown",
|
"local_address": "unknown",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue