From 584a226336c39d5278e6082cd4989405d3a670ed Mon Sep 17 00:00:00 2001 From: Nicolas Vinuesa Date: Wed, 23 Oct 2024 20:53:10 +0200 Subject: [PATCH] fix: create an insecure tls http client for maas when skip TLS verify Before this patch we weren't able to bootstrap on MAAS when configured for TLS with a self-signed certificate. We now add the posibility to take the `skip-tls-verify` cloud spec field into account and create an insecure TLS http client for the maas controller connection in that case. --- provider/maas/config_test.go | 2 +- provider/maas/environ.go | 35 ++++++++++++++------- provider/maas/environprovider_test.go | 15 ++++++++- provider/maas/maas_environ_whitebox_test.go | 10 +++++- provider/maas/maas_test.go | 3 +- 5 files changed, 50 insertions(+), 15 deletions(-) diff --git a/provider/maas/config_test.go b/provider/maas/config_test.go index 8f8661b242b..0b389ec1ab5 100644 --- a/provider/maas/config_test.go +++ b/provider/maas/config_test.go @@ -38,7 +38,7 @@ func newConfig(values map[string]interface{}) (*maasModelConfig, error) { func (s *configSuite) SetUpTest(c *gc.C) { s.BaseSuite.SetUpTest(c) - mockGetController := func(string, string) (gomaasapi.Controller, error) { + mockGetController := func(gomaasapi.ControllerArgs) (gomaasapi.Controller, error) { return nil, gomaasapi.NewUnsupportedVersionError("oops") } s.PatchValue(&GetMAASController, mockGetController) diff --git a/provider/maas/environ.go b/provider/maas/environ.go index be1f777295e..87cb07ca1ef 100644 --- a/provider/maas/environ.go +++ b/provider/maas/environ.go @@ -5,6 +5,7 @@ package maas import ( stdcontext "context" + "crypto/tls" "fmt" "net/http" "regexp" @@ -51,6 +52,7 @@ var defaultShortRetryStrategy = retry.CallArgs{ Delay: 200 * time.Millisecond, MaxDuration: 5 * time.Second, } + var defaultLongRetryStrategy = retry.CallArgs{ Clock: clock.WallClock, Delay: 10 * time.Second, @@ -62,11 +64,8 @@ var ( GetMAASController = getMAASController ) -func getMAASController(maasServer, apiKey string) (gomaasapi.Controller, error) { - return gomaasapi.NewController(gomaasapi.ControllerArgs{ - BaseURL: maasServer, - APIKey: apiKey, - }) +func getMAASController(args gomaasapi.ControllerArgs) (gomaasapi.Controller, error) { + return gomaasapi.NewController(args) } type maasEnviron struct { @@ -104,8 +103,10 @@ type maasEnviron struct { longRetryStrategy retry.CallArgs } -var _ environs.Environ = (*maasEnviron)(nil) -var _ environs.Networking = (*maasEnviron)(nil) +var ( + _ environs.Environ = (*maasEnviron)(nil) + _ environs.Networking = (*maasEnviron)(nil) +) // Capabilities is an alias for a function that gets // the capabilities of a MAAS installation. @@ -261,7 +262,22 @@ func (env *maasEnviron) SetCloudSpec(_ stdcontext.Context, spec environscloudspe } apiVersion := apiVersion2 - controller, err := GetMAASController(maasServer, maasOAuth) + args := gomaasapi.ControllerArgs{ + BaseURL: maasServer, + APIKey: maasOAuth, + } + // If the user has specified to skip TLS verification, we need to + // add a new http client with insecure TLS (skip verify). + if spec.SkipTLSVerify { + args.HTTPClient = &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + }, + } + } + controller, err := GetMAASController(args) if err != nil { return errors.Trace(err) } @@ -630,7 +646,6 @@ func (env *maasEnviron) acquireNode( acquireParams.SystemId = systemId } machine, constraintMatches, err := env.maasController.AllocateMachine(acquireParams) - if err != nil { common.HandleCredentialError(IsAuthorisationFailure, err, ctx) return nil, errors.Trace(err) @@ -654,7 +669,6 @@ func (env *maasEnviron) StartInstance( ctx context.ProviderCallContext, args environs.StartInstanceParams, ) (_ *environs.StartInstanceResult, err error) { - availabilityZone := args.AvailabilityZone var nodeName, systemId string if args.Placement != "" { @@ -1019,7 +1033,6 @@ func (env *maasEnviron) StopInstances(ctx context.ProviderCallContext, ids ...in return errors.Trace(err) } return common.RemoveStateInstances(env.Storage(), ids...) - } // Instances returns the instances.Instance objects corresponding to the given diff --git a/provider/maas/environprovider_test.go b/provider/maas/environprovider_test.go index 66af0685624..4b67bcc6d04 100644 --- a/provider/maas/environprovider_test.go +++ b/provider/maas/environprovider_test.go @@ -59,6 +59,19 @@ func (s *EnvironProviderSuite) TestPrepareConfig(c *gc.C) { c.Assert(err, jc.ErrorIsNil) } +func (s *EnvironProviderSuite) TestPrepareConfigSkipTLSVerify(c *gc.C) { + attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) + config, err := config.New(config.NoDefaults, attrs) + c.Assert(err, jc.ErrorIsNil) + cloud := s.cloudSpec() + cloud.SkipTLSVerify = true + _, err = providerInstance.PrepareConfig(environs.PrepareConfigParams{ + Config: config, + Cloud: cloud, + }) + c.Assert(err, jc.ErrorIsNil) +} + func (s *EnvironProviderSuite) TestPrepareConfigInvalidOAuth(c *gc.C) { attrs := testing.FakeConfig().Merge(testing.Attrs{"type": "maas"}) config, err := config.New(config.NoDefaults, attrs) @@ -108,7 +121,7 @@ func createTempFile(c *gc.C, content []byte) string { defer file.Close() c.Assert(err, jc.ErrorIsNil) filename := file.Name() - err = os.WriteFile(filename, content, 0644) + err = os.WriteFile(filename, content, 0o644) c.Assert(err, jc.ErrorIsNil) return filename } diff --git a/provider/maas/maas_environ_whitebox_test.go b/provider/maas/maas_environ_whitebox_test.go index ea73a65a1a6..82d3a33f637 100644 --- a/provider/maas/maas_environ_whitebox_test.go +++ b/provider/maas/maas_environ_whitebox_test.go @@ -91,6 +91,12 @@ func (suite *maasEnvironSuite) TestNewEnvironWithController(c *gc.C) { c.Assert(env, gc.NotNil) } +func (suite *maasEnvironSuite) TestNewEnvironWithControllerSkipTLSVerify(c *gc.C) { + env, err := suite.getEnvWithServer(c) + c.Assert(err, jc.ErrorIsNil) + c.Assert(env, gc.NotNil) +} + func (suite *maasEnvironSuite) injectControllerWithSpacesAndCheck(c *gc.C, spaces []gomaasapi.Space, expected gomaasapi.AllocateMachineArgs) (*maasEnviron, *fakeController) { machine := newFakeMachine("Bruce Sterling", arch.HostArch(), "") return suite.injectControllerWithMachine(c, machine, spaces, expected) @@ -455,7 +461,8 @@ func (suite *maasEnvironSuite) TestAcquireNodePassedAgentName(c *gc.C) { suite.injectController(&fakeController{ allocateMachineArgsCheck: func(args gomaasapi.AllocateMachineArgs) { c.Assert(args, gc.DeepEquals, gomaasapi.AllocateMachineArgs{ - AgentName: env.Config().UUID()}) + AgentName: env.Config().UUID(), + }) }, allocateMachine: &fakeMachine{ systemID: "Bruce Sterling", @@ -1742,6 +1749,7 @@ func makeFakeSubnet(id int) fakeSubnet { cidr: fmt.Sprintf("10.20.%d.0/24", 16+id), } } + func (suite *maasEnvironSuite) TestAllocateContainerAddressesMachinesError(c *gc.C) { var env *maasEnviron subnet := makeFakeSubnet(3) diff --git a/provider/maas/maas_test.go b/provider/maas/maas_test.go index 91b282066b9..d351ab9f7a8 100644 --- a/provider/maas/maas_test.go +++ b/provider/maas/maas_test.go @@ -31,7 +31,7 @@ type maasSuite struct { } func (suite *maasSuite) injectController(controller gomaasapi.Controller) { - mockGetController := func(maasServer, apiKey string) (gomaasapi.Controller, error) { + mockGetController := func(args gomaasapi.ControllerArgs) (gomaasapi.Controller, error) { return controller, nil } suite.PatchValue(&GetMAASController, mockGetController) @@ -186,6 +186,7 @@ func (c *fakeController) StaticRoutes() ([]gomaasapi.StaticRoute, error) { } return c.staticRoutes, nil } + func (c *fakeController) Files(prefix string) ([]gomaasapi.File, error) { c.MethodCall(c, "Files", prefix) return c.files, c.NextErr()