Unverified Commit c7b94fe5 authored by Oren Shomron's avatar Oren Shomron Committed by GitHub
Browse files

Merge pull request #831 from shomron/issue-726-tls-skip-verify

Add --tls-skip-verify global option affecting outgoing HTTP requests
parents 746561a9 de033c2c
...@@ -16,7 +16,11 @@ ...@@ -16,7 +16,11 @@
package actions package actions
import ( import (
"crypto/tls"
"fmt" "fmt"
"net"
"net/http"
"time"
"github.com/ksonnet/ksonnet/pkg/app" "github.com/ksonnet/ksonnet/pkg/app"
"github.com/ksonnet/ksonnet/pkg/client" "github.com/ksonnet/ksonnet/pkg/client"
...@@ -110,6 +114,8 @@ const ( ...@@ -110,6 +114,8 @@ const (
OptionTlaVarFiles = "tla-var-files" OptionTlaVarFiles = "tla-var-files"
// OptionTlaVars is jsonnet tla vars. // OptionTlaVars is jsonnet tla vars.
OptionTlaVars = "tla-vars" OptionTlaVars = "tla-vars"
// OptionTLSSkipVerify specifies that tls server certifactes should not be verified.
OptionTLSSkipVerify = "tls-skip-verify"
// OptionUnset is unset option. // OptionUnset is unset option.
OptionUnset = "unset" OptionUnset = "unset"
// OptionURI is uri option. Used for setting registry URI. // OptionURI is uri option. Used for setting registry URI.
...@@ -342,6 +348,38 @@ func (o *optionLoader) LoadApp() app.App { ...@@ -342,6 +348,38 @@ func (o *optionLoader) LoadApp() app.App {
return a return a
} }
// LoadHTTPClient loads an HTTP client based on common configuration for certificates, tls verification, timeouts, etc.
func (o *optionLoader) LoadHTTPClient() *http.Client {
tlsSkipVerify := o.LoadOptionalBool(OptionTLSSkipVerify)
tlsConfig := &tls.Config{
InsecureSkipVerify: tlsSkipVerify,
}
timeoutSeconds := 10
var defaultTransport http.RoundTripper = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSClientConfig: tlsConfig,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
c := &http.Client{
Timeout: time.Duration(timeoutSeconds) * time.Second,
Transport: defaultTransport,
}
return c
}
func (o *optionLoader) load(key string) interface{} { func (o *optionLoader) load(key string) interface{} {
if o.err != nil { if o.err != nil {
return nil return nil
......
...@@ -48,6 +48,8 @@ type PkgDescribe struct { ...@@ -48,6 +48,8 @@ type PkgDescribe struct {
func NewPkgDescribe(m map[string]interface{}) (*PkgDescribe, error) { func NewPkgDescribe(m map[string]interface{}) (*PkgDescribe, error) {
ol := newOptionLoader(m) ol := newOptionLoader(m)
httpClientOpt := registry.HTTPClientOpt(ol.LoadHTTPClient())
app := ol.LoadApp() app := ol.LoadApp()
pd := &PkgDescribe{ pd := &PkgDescribe{
app: app, app: app,
...@@ -55,7 +57,7 @@ func NewPkgDescribe(m map[string]interface{}) (*PkgDescribe, error) { ...@@ -55,7 +57,7 @@ func NewPkgDescribe(m map[string]interface{}) (*PkgDescribe, error) {
templateSrc: pkgDescribeTemplate, templateSrc: pkgDescribeTemplate,
out: os.Stdout, out: os.Stdout,
packageManager: registry.NewPackageManager(app), packageManager: registry.NewPackageManager(app, httpClientOpt),
} }
if ol.err != nil { if ol.err != nil {
......
...@@ -153,8 +153,9 @@ func TestPkgDescribe(t *testing.T) { ...@@ -153,8 +153,9 @@ func TestPkgDescribe(t *testing.T) {
a.On("Libraries").Return(libraries, nil) a.On("Libraries").Return(libraries, nil)
in := map[string]interface{}{ in := map[string]interface{}{
OptionApp: a, OptionApp: a,
OptionPackageName: "apache", OptionPackageName: "apache",
OptionTLSSkipVerify: false,
} }
pd, err := NewPkgDescribe(in) pd, err := NewPkgDescribe(in)
......
...@@ -55,6 +55,8 @@ func NewPkgInstall(m map[string]interface{}) (*PkgInstall, error) { ...@@ -55,6 +55,8 @@ func NewPkgInstall(m map[string]interface{}) (*PkgInstall, error) {
if ol.err != nil { if ol.err != nil {
return nil, ol.err return nil, ol.err
} }
httpClient := ol.LoadHTTPClient()
httpClientOpt := registry.HTTPClientOpt(httpClient)
nl := &PkgInstall{ nl := &PkgInstall{
app: a, app: a,
...@@ -62,9 +64,11 @@ func NewPkgInstall(m map[string]interface{}) (*PkgInstall, error) { ...@@ -62,9 +64,11 @@ func NewPkgInstall(m map[string]interface{}) (*PkgInstall, error) {
customName: ol.LoadString(OptionName), customName: ol.LoadString(OptionName),
force: ol.LoadBool(OptionForce), force: ol.LoadBool(OptionForce),
envName: ol.LoadOptionalString(OptionEnvName), envName: ol.LoadOptionalString(OptionEnvName),
checker: registry.NewPackageManager(a), checker: registry.NewPackageManager(a, httpClientOpt),
libCacherFn: registry.CacheDependency, libCacherFn: func(a app.App, checker registry.InstalledChecker, d pkg.Descriptor, customName string, force bool) (*app.LibraryConfig, error) {
return registry.CacheDependency(a, checker, d, customName, force, httpClient)
},
libUpdateFn: a.UpdateLib, libUpdateFn: a.UpdateLib,
} }
......
...@@ -32,10 +32,11 @@ func TestPkgInstall(t *testing.T) { ...@@ -32,10 +32,11 @@ func TestPkgInstall(t *testing.T) {
customName := "customName" customName := "customName"
in := map[string]interface{}{ in := map[string]interface{}{
OptionApp: appMock, OptionApp: appMock,
OptionLibName: libName, OptionLibName: libName,
OptionName: customName, OptionName: customName,
OptionForce: false, OptionForce: false,
OptionTLSSkipVerify: false,
} }
a, err := NewPkgInstall(in) a, err := NewPkgInstall(in)
......
...@@ -58,15 +58,20 @@ type PkgList struct { ...@@ -58,15 +58,20 @@ type PkgList struct {
func NewPkgList(m map[string]interface{}) (*PkgList, error) { func NewPkgList(m map[string]interface{}) (*PkgList, error) {
ol := newOptionLoader(m) ol := newOptionLoader(m)
app := ol.LoadApp() a := ol.LoadApp()
httpClient := ol.LoadHTTPClient()
httpClientOpt := registry.HTTPClientOpt(httpClient)
rl := &PkgList{ rl := &PkgList{
app: app, app: a,
pm: registry.NewPackageManager(app), pm: registry.NewPackageManager(a, httpClientOpt),
onlyInstalled: ol.LoadBool(OptionInstalled), onlyInstalled: ol.LoadBool(OptionInstalled),
outputType: ol.LoadOptionalString(OptionOutput), outputType: ol.LoadOptionalString(OptionOutput),
registryListFn: registry.List, registryListFn: func(ksApp app.App) ([]registry.Registry, error) {
out: os.Stdout, return registry.List(ksApp, httpClient)
},
out: os.Stdout,
} }
if ol.err != nil { if ol.err != nil {
......
...@@ -152,9 +152,10 @@ func TestPkgList(t *testing.T) { ...@@ -152,9 +152,10 @@ func TestPkgList(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
in := map[string]interface{}{ in := map[string]interface{}{
OptionApp: appMock, OptionApp: appMock,
OptionInstalled: tc.onlyInstalled, OptionInstalled: tc.onlyInstalled,
OptionOutput: tc.outputType, OptionOutput: tc.outputType,
OptionTLSSkipVerify: false,
} }
a, err := NewPkgList(in) a, err := NewPkgList(in)
......
...@@ -51,12 +51,14 @@ func NewPrototypeDescribe(m map[string]interface{}) (*PrototypeDescribe, error) ...@@ -51,12 +51,14 @@ func NewPrototypeDescribe(m map[string]interface{}) (*PrototypeDescribe, error)
ol := newOptionLoader(m) ol := newOptionLoader(m)
app := ol.LoadApp() app := ol.LoadApp()
httpClientOpt := registry.HTTPClientOpt(ol.LoadHTTPClient())
pd := &PrototypeDescribe{ pd := &PrototypeDescribe{
app: app, app: app,
query: ol.LoadString(OptionQuery), query: ol.LoadString(OptionQuery),
out: os.Stdout, out: os.Stdout,
packageManager: registry.NewPackageManager(app), packageManager: registry.NewPackageManager(app, httpClientOpt),
} }
if ol.err != nil { if ol.err != nil {
......
...@@ -33,8 +33,9 @@ func TestPrototypeDescribe(t *testing.T) { ...@@ -33,8 +33,9 @@ func TestPrototypeDescribe(t *testing.T) {
manager.On("Prototypes").Return(prototypes, nil) manager.On("Prototypes").Return(prototypes, nil)
in := map[string]interface{}{ in := map[string]interface{}{
OptionApp: appMock, OptionApp: appMock,
OptionQuery: "namespace", OptionQuery: "namespace",
OptionTLSSkipVerify: false,
} }
a, err := NewPrototypeDescribe(in) a, err := NewPrototypeDescribe(in)
......
...@@ -51,12 +51,14 @@ func NewPrototypeList(m map[string]interface{}) (*PrototypeList, error) { ...@@ -51,12 +51,14 @@ func NewPrototypeList(m map[string]interface{}) (*PrototypeList, error) {
ol := newOptionLoader(m) ol := newOptionLoader(m)
app := ol.LoadApp() app := ol.LoadApp()
httpClientOpt := registry.HTTPClientOpt(ol.LoadHTTPClient())
pl := &PrototypeList{ pl := &PrototypeList{
app: app, app: app,
out: os.Stdout, out: os.Stdout,
outputType: ol.LoadOptionalString(OptionOutput), outputType: ol.LoadOptionalString(OptionOutput),
packageManager: registry.NewPackageManager(app), packageManager: registry.NewPackageManager(app, httpClientOpt),
} }
if ol.err != nil { if ol.err != nil {
......
...@@ -58,8 +58,9 @@ func TestPrototypeList(t *testing.T) { ...@@ -58,8 +58,9 @@ func TestPrototypeList(t *testing.T) {
manager.On("Prototypes").Return(prototypes, nil) manager.On("Prototypes").Return(prototypes, nil)
in := map[string]interface{}{ in := map[string]interface{}{
OptionApp: appMock, OptionApp: appMock,
OptionOutput: tc.outputType, OptionOutput: tc.outputType,
OptionTLSSkipVerify: false,
} }
a, err := NewPrototypeList(in) a, err := NewPrototypeList(in)
......
...@@ -62,13 +62,15 @@ func NewPrototypePreview(m map[string]interface{}) (*PrototypePreview, error) { ...@@ -62,13 +62,15 @@ func NewPrototypePreview(m map[string]interface{}) (*PrototypePreview, error) {
ol := newOptionLoader(m) ol := newOptionLoader(m)
app := ol.LoadApp() app := ol.LoadApp()
httpClientOpt := registry.HTTPClientOpt(ol.LoadHTTPClient())
pp := &PrototypePreview{ pp := &PrototypePreview{
app: app, app: app,
query: ol.LoadString(OptionQuery), query: ol.LoadString(OptionQuery),
args: ol.LoadStringSlice(OptionArguments), args: ol.LoadStringSlice(OptionArguments),
out: os.Stdout, out: os.Stdout,
packageManager: registry.NewPackageManager(app), packageManager: registry.NewPackageManager(app, httpClientOpt),
bindFlagsFn: prototype.BindFlags, bindFlagsFn: prototype.BindFlags,
extractParametersFn: prototype.ExtractParameters, extractParametersFn: prototype.ExtractParameters,
} }
......
...@@ -41,9 +41,10 @@ func TestPrototypePreview(t *testing.T) { ...@@ -41,9 +41,10 @@ func TestPrototypePreview(t *testing.T) {
} }
in := map[string]interface{}{ in := map[string]interface{}{
OptionApp: appMock, OptionApp: appMock,
OptionQuery: "single-port-deployment", OptionQuery: "single-port-deployment",
OptionArguments: args, OptionArguments: args,
OptionTLSSkipVerify: false,
} }
a, err := NewPrototypePreview(in) a, err := NewPrototypePreview(in)
...@@ -74,9 +75,10 @@ func TestPrototypePreview_bind_flags_failed(t *testing.T) { ...@@ -74,9 +75,10 @@ func TestPrototypePreview_bind_flags_failed(t *testing.T) {
} }
in := map[string]interface{}{ in := map[string]interface{}{
OptionApp: appMock, OptionApp: appMock,
OptionQuery: "single-port-deployment", OptionQuery: "single-port-deployment",
OptionArguments: args, OptionArguments: args,
OptionTLSSkipVerify: false,
} }
a, err := NewPrototypePreview(in) a, err := NewPrototypePreview(in)
......
...@@ -54,13 +54,15 @@ func NewPrototypeSearch(m map[string]interface{}) (*PrototypeSearch, error) { ...@@ -54,13 +54,15 @@ func NewPrototypeSearch(m map[string]interface{}) (*PrototypeSearch, error) {
ol := newOptionLoader(m) ol := newOptionLoader(m)
app := ol.LoadApp() app := ol.LoadApp()
httpClientOpt := registry.HTTPClientOpt(ol.LoadHTTPClient())
ps := &PrototypeSearch{ ps := &PrototypeSearch{
app: app, app: app,
query: ol.LoadString(OptionQuery), query: ol.LoadString(OptionQuery),
outputType: ol.LoadOptionalString(OptionOutput), outputType: ol.LoadOptionalString(OptionOutput),
out: os.Stdout, out: os.Stdout,
packageManager: registry.NewPackageManager(app), packageManager: registry.NewPackageManager(app, httpClientOpt),
protoSearchFn: protoSearch, protoSearchFn: protoSearch,
} }
......
...@@ -58,9 +58,10 @@ func TestPrototypeSearch(t *testing.T) { ...@@ -58,9 +58,10 @@ func TestPrototypeSearch(t *testing.T) {
manager.On("Prototypes").Return(prototypes, nil) manager.On("Prototypes").Return(prototypes, nil)
in := map[string]interface{}{ in := map[string]interface{}{
OptionApp: appMock, OptionApp: appMock,
OptionQuery: "search", OptionQuery: "search",
OptionOutput: tc.outputType, OptionOutput: tc.outputType,
OptionTLSSkipVerify: false,
} }
a, err := NewPrototypeSearch(in) a, err := NewPrototypeSearch(in)
......
...@@ -57,12 +57,14 @@ func NewPrototypeUse(m map[string]interface{}) (*PrototypeUse, error) { ...@@ -57,12 +57,14 @@ func NewPrototypeUse(m map[string]interface{}) (*PrototypeUse, error) {
ol := newOptionLoader(m) ol := newOptionLoader(m)
app := ol.LoadApp() app := ol.LoadApp()
httpClientOpt := registry.HTTPClientOpt(ol.LoadHTTPClient())
pl := &PrototypeUse{ pl := &PrototypeUse{
app: app, app: app,
args: ol.LoadStringSlice(OptionArguments), args: ol.LoadStringSlice(OptionArguments),
out: os.Stdout, out: os.Stdout,
packageManager: registry.NewPackageManager(app), packageManager: registry.NewPackageManager(app, httpClientOpt),
createComponentFn: component.Create, createComponentFn: component.Create,
bindFlagsFn: prototype.BindFlags, bindFlagsFn: prototype.BindFlags,
extractParametersFn: prototype.ExtractParameters, extractParametersFn: prototype.ExtractParameters,
......
...@@ -45,8 +45,9 @@ func TestPrototypeUse(t *testing.T) { ...@@ -45,8 +45,9 @@ func TestPrototypeUse(t *testing.T) {
} }
in := map[string]interface{}{ in := map[string]interface{}{
OptionApp: appMock, OptionApp: appMock,
OptionArguments: args, OptionArguments: args,
OptionTLSSkipVerify: false,
} }
a, err := NewPrototypeUse(in) a, err := NewPrototypeUse(in)
...@@ -92,8 +93,9 @@ func TestPrototypeUse_bind_flags_failed(t *testing.T) { ...@@ -92,8 +93,9 @@ func TestPrototypeUse_bind_flags_failed(t *testing.T) {
} }
in := map[string]interface{}{ in := map[string]interface{}{
OptionApp: appMock, OptionApp: appMock,
OptionArguments: args, OptionArguments: args,
OptionTLSSkipVerify: false,
} }
a, err := NewPrototypeUse(in) a, err := NewPrototypeUse(in)
...@@ -143,8 +145,9 @@ func TestPrototypeUse_with_module_in_name(t *testing.T) { ...@@ -143,8 +145,9 @@ func TestPrototypeUse_with_module_in_name(t *testing.T) {
} }
in := map[string]interface{}{ in := map[string]interface{}{
OptionApp: appMock, OptionApp: appMock,
OptionArguments: args, OptionArguments: args,
OptionTLSSkipVerify: false,
} }
a, err := NewPrototypeUse(in) a, err := NewPrototypeUse(in)
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package actions package actions
import ( import (
"net/http"
"net/url" "net/url"
"strings" "strings"
...@@ -36,11 +37,13 @@ func RunRegistryAdd(m map[string]interface{}) error { ...@@ -36,11 +37,13 @@ func RunRegistryAdd(m map[string]interface{}) error {
// RegistryAdd adds a registry. // RegistryAdd adds a registry.
type RegistryAdd struct { type RegistryAdd struct {
app app.App app app.App
name string name string
uri string uri string
isOverride bool isOverride bool
registryAddFn func(a app.App, protocol registry.Protocol, name string, uri string, isOverride bool) (*registry.Spec, error) httpClient *http.Client
registryAddFn func(a app.App, protocol registry.Protocol, name string, uri string, isOverride bool, httpClient *http.Client) (*registry.Spec, error)
} }
// NewRegistryAdd creates an instance of RegistryAdd. // NewRegistryAdd creates an instance of RegistryAdd.
...@@ -52,6 +55,7 @@ func NewRegistryAdd(m map[string]interface{}) (*RegistryAdd, error) { ...@@ -52,6 +55,7 @@ func NewRegistryAdd(m map[string]interface{}) (*RegistryAdd, error) {
name: ol.LoadString(OptionName), name: ol.LoadString(OptionName),
uri: ol.LoadString(OptionURI), uri: ol.LoadString(OptionURI),
isOverride: ol.LoadBool(OptionOverride), isOverride: ol.LoadBool(OptionOverride),
httpClient: ol.LoadHTTPClient(),
registryAddFn: registry.Add, registryAddFn: registry.Add,
} }
...@@ -70,7 +74,7 @@ func (ra *RegistryAdd) Run() error { ...@@ -70,7 +74,7 @@ func (ra *RegistryAdd) Run() error {
return errors.Wrap(err, "detect registry protocol") return errors.Wrap(err, "detect registry protocol")
} }
_, err = ra.registryAddFn(ra.app, rd.Protocol, ra.name, rd.URI, ra.isOverride) _, err = ra.registryAddFn(ra.app, rd.Protocol, ra.name, rd.URI, ra.isOverride, ra.httpClient)
return err return err
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package actions package actions
import ( import (
"net/http"
"testing" "testing"
"github.com/ksonnet/ksonnet/pkg/app" "github.com/ksonnet/ksonnet/pkg/app"
...@@ -85,17 +86,18 @@ func TestRegistryAdd(t *testing.T) { ...@@ -85,17 +86,18 @@ func TestRegistryAdd(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
in := map[string]interface{}{ in := map[string]interface{}{
OptionApp: appMock, OptionApp: appMock,
OptionName: name, OptionName: name,
OptionURI: tc.uri, OptionURI: tc.uri,
OptionVersion: tc.version, OptionVersion: tc.version,
OptionOverride: tc.isOverride, OptionOverride: tc.isOverride,
OptionTLSSkipVerify: false,
} }
a, err := NewRegistryAdd(in) a, err := NewRegistryAdd(in)
require.NoError(t, err) require.NoError(t, err)
a.registryAddFn = func(a app.App, protocol registry.Protocol, name string, uri string, isOverride bool) (*registry.Spec, error) { a.registryAddFn = func(a app.App, protocol registry.Protocol, name string, uri string, isOverride bool, httpClient *http.Client) (*registry.Spec, error) {
assert.Equal(t, "new", name) assert.Equal(t, "new", name)
assert.Equal(t, tc.protocol, protocol)