diff --git a/go.mod b/go.mod index 7e55112..2ceb32b 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/hashicorp/go-memdb v1.3.4 github.com/hashicorp/go-retryablehttp v0.7.5 github.com/hexops/gotextdiff v1.0.3 - github.com/kong/deck v1.32.1 + github.com/kong/deck v1.32.2-0.20240130093755-1b708da921f5 github.com/kong/go-kong v0.51.1-0.20240125175037-0c077f5b9ac7 github.com/shirou/gopsutil/v3 v3.24.1 github.com/ssgelm/cookiejarparser v1.0.1 diff --git a/go.sum b/go.sum index 38d3f35..bb1a8c2 100644 --- a/go.sum +++ b/go.sum @@ -182,8 +182,8 @@ github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuOb github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/kong/deck v1.32.1 h1:WZ7R79KQrmFn9XFmChbb2uGrVBywfk9dHfSU5QgBdPQ= -github.com/kong/deck v1.32.1/go.mod h1:MDJtBMepXGtzEpNWzub/i2zxC4d64rbmty16Q4ZkjfU= +github.com/kong/deck v1.32.2-0.20240130093755-1b708da921f5 h1:BKuzSnX0pwKPPiSsZgKHM+jAGTSV05Dt9NxnrgqCpXE= +github.com/kong/deck v1.32.2-0.20240130093755-1b708da921f5/go.mod h1:oV/8tP95DcK4/JUn0x3hoi9YSPMT63SdsAMKFBGQ2bQ= github.com/kong/go-apiops v0.1.29 h1:c+AB8MmGIr+K01Afm4GB2xaOmJnD/8KWMJQkr9qssnc= github.com/kong/go-apiops v0.1.29/go.mod h1:ZNdiTZyVrAssB4wjEYWV7BfpcV9UME9LxnDDZhMPuNU= github.com/kong/go-kong v0.51.1-0.20240125175037-0c077f5b9ac7 h1:/iV93Gwv410lIeJx8VCfCA4fpuvSuTw2LqZpDXsIE9Q= diff --git a/pkg/utils/types.go b/pkg/utils/types.go index 8bd33c9..415a4b3 100644 --- a/pkg/utils/types.go +++ b/pkg/utils/types.go @@ -95,12 +95,7 @@ type KongClientConfig struct { Address string Workspace string - TLSServerName string - - TLSCACert string - - TLSSkipVerify bool - Debug bool + Debug bool SkipWorkspaceCrud bool @@ -112,12 +107,10 @@ type KongClientConfig struct { CookieJarPath string - TLSClientCert string - - TLSClientKey string - // whether or not the client should retry on 429s Retryable bool + + TLSConfig TLSConfig } type KonnectConfig struct { @@ -131,6 +124,16 @@ type KonnectConfig struct { Headers []string ControlPlaneName string + + TLSConfig TLSConfig +} + +type TLSConfig struct { + ServerName string + CACert string + ClientCert string + ClientKey string + SkipVerify bool } // ForWorkspace returns a copy of KongClientConfig that produces a KongClient for the workspace specified by argument. @@ -209,30 +212,9 @@ func getRetryableClient(client *http.Client) *http.Client { // GetKongClient returns a Kong client func GetKongClient(opt KongClientConfig) (*kong.Client, error) { - var tlsConfig tls.Config - if opt.TLSSkipVerify { - tlsConfig.InsecureSkipVerify = true //nolint:gosec - } - if opt.TLSServerName != "" { - tlsConfig.ServerName = opt.TLSServerName - } - - if opt.TLSCACert != "" { - certPool := x509.NewCertPool() - ok := certPool.AppendCertsFromPEM([]byte(opt.TLSCACert)) - if !ok { - return nil, fmt.Errorf("failed to load TLSCACert") - } - tlsConfig.RootCAs = certPool - } - - if opt.TLSClientCert != "" && opt.TLSClientKey != "" { - // Read the key pair to create certificate - cert, err := tls.X509KeyPair([]byte(opt.TLSClientCert), []byte(opt.TLSClientKey)) - if err != nil { - return nil, fmt.Errorf("failed to load client certificate: %w", err) - } - tlsConfig.Certificates = []tls.Certificate{cert} + tlsConfig, err := getTLSConfig(opt.TLSConfig) + if err != nil { + return nil, fmt.Errorf("failed to load TLS config: %w", err) } clientTimeout = time.Duration(opt.Timeout) * time.Second @@ -241,7 +223,7 @@ func GetKongClient(opt KongClientConfig) (*kong.Client, error) { c = HTTPClient() } defaultTransport := http.DefaultTransport.(*http.Transport) - defaultTransport.TLSClientConfig = &tlsConfig + defaultTransport.TLSClientConfig = tlsConfig c.Transport = defaultTransport address := CleanAddress(opt.Address) @@ -296,13 +278,47 @@ func parseHeaders(headers []string) (http.Header, error) { return res, nil } +func getTLSConfig(opt TLSConfig) (*tls.Config, error) { + var tlsConfig tls.Config + if opt.SkipVerify { + tlsConfig.InsecureSkipVerify = true //nolint:gosec + } + if opt.ServerName != "" { + tlsConfig.ServerName = opt.ServerName + } + + if opt.CACert != "" { + certPool := x509.NewCertPool() + ok := certPool.AppendCertsFromPEM([]byte(opt.CACert)) + if !ok { + return nil, fmt.Errorf("failed to load TLSCACert") + } + tlsConfig.RootCAs = certPool + } + + if opt.ClientCert != "" && opt.ClientKey != "" { + // Read the key pair to create certificate + cert, err := tls.X509KeyPair([]byte(opt.ClientCert), []byte(opt.ClientKey)) + if err != nil { + return nil, fmt.Errorf("failed to load client certificate: %w", err) + } + tlsConfig.Certificates = []tls.Certificate{cert} + } + return &tlsConfig, nil +} + func GetKonnectClient(httpClient *http.Client, config KonnectConfig) (*konnect.Client, error, ) { address := CleanAddress(config.Address) if httpClient == nil { + tlsConfig, err := getTLSConfig(config.TLSConfig) + if err != nil { + return nil, fmt.Errorf("failed to load TLS config: %w", err) + } defaultTransport := http.DefaultTransport.(*http.Transport) + defaultTransport.TLSClientConfig = tlsConfig defaultTransport.Proxy = http.ProxyFromEnvironment httpClient = http.DefaultClient httpClient.Transport = defaultTransport @@ -345,3 +361,25 @@ func HTTPClient() *http.Client { }, } } + +func HTTPClientWithTLSConfig(opt TLSConfig) (*http.Client, error) { + httpClient := &http.Client{ + Timeout: clientTimeout, + Transport: &http.Transport{ + DialContext: (&net.Dialer{Timeout: clientTimeout}).DialContext, + TLSHandshakeTimeout: clientTimeout, + Proxy: http.ProxyFromEnvironment, + }, + } + + tlsConfig, err := getTLSConfig(opt) + if err != nil { + return nil, fmt.Errorf("failed to load TLS config: %w", err) + } + defaultTransport := http.DefaultTransport.(*http.Transport) + defaultTransport.TLSClientConfig = tlsConfig + defaultTransport.Proxy = http.ProxyFromEnvironment + httpClient = http.DefaultClient + httpClient.Transport = defaultTransport + return httpClient, nil +} diff --git a/tests/integration/sync_test.go b/tests/integration/sync_test.go index 7412bdc..cb5d713 100644 --- a/tests/integration/sync_test.go +++ b/tests/integration/sync_test.go @@ -196,6 +196,24 @@ var ( }, } + plugin36 = []*kong.Plugin{ + { + Name: kong.String("basic-auth"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "anonymous": "58076db2-28b6-423b-ba39-a797193017f7", + "hide_credentials": false, + "realm": string("service"), + }, + }, + } + plugin_on_entities = []*kong.Plugin{ //nolint:revive,stylecheck { Name: kong.String("prometheus"), @@ -1537,7 +1555,7 @@ func Test_Sync_BasicAuth_Plugin_From_2_0_5_Till_2_8_0(t *testing.T) { } // test scope: -// - 3.x +// - >=3.0 <3.6.0 func Test_Sync_BasicAuth_Plugin_From_3x(t *testing.T) { // setup stage client, err := getTestClient() @@ -1561,7 +1579,41 @@ func Test_Sync_BasicAuth_Plugin_From_3x(t *testing.T) { } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - runWhenKongOrKonnect(t, ">=3.0.0") + runWhenKongOrKonnect(t, ">=3.0.0 <3.6.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.6+ +func Test_Sync_BasicAuth_Plugin_From_36(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + initialKongFile string + expectedState utils.KongRawState + }{ + { + name: "create a plugin", + kongFile: "testdata/sync/003-create-a-plugin/kong3x.yaml", + expectedState: utils.KongRawState{ + Plugins: plugin36, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.6.0") setup(t) sync(tc.kongFile)