Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add helper for setting up MicroCloud proxy #287

Merged
merged 3 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions client/proxy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package client

import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
"strings"

"github.com/canonical/lxd/shared"
"github.com/canonical/microcluster/client"

"github.com/canonical/microcloud/microcloud/api/types"
)

// UseAuthProxy takes the given microcluster client and secret and proxies requests to other services through the MicroCloud API.
// The secret will be set in the authentication header in lieu of TLS authentication, if present.
func UseAuthProxy(c *client.Client, secret string, serviceType types.ServiceType) (*client.Client, error) {
tp, ok := c.Transport.(*http.Transport)
if !ok {
return nil, fmt.Errorf("Invalid client transport type")
}

// If the client is a unix client, it may not have any TLS config.
if tp.TLSClientConfig == nil {
tp.TLSClientConfig = &tls.Config{}
}

// Only set InsecureSkipVerify if the secret is non-empty, so we will fallback to regular TLS authentication.
if secret != "" {
tp.TLSClientConfig.InsecureSkipVerify = true
Dismissed Show dismissed Hide dismissed
}

tp.Proxy = AuthProxy(secret, serviceType)

c.Transport = tp

return c, nil
}

// AuthProxy takes a request to a service and sends it to MicroCloud instead,
// to be then forwarded to the unix socket of the corresponding service.
// The secret is set in the request header to use in lieu of TLS authentication.
func AuthProxy(secret string, serviceType types.ServiceType) func(r *http.Request) (*url.URL, error) {
return func(r *http.Request) (*url.URL, error) {
r.Header.Set("X-MicroCloud-Auth", secret)

// MicroCloud itself doesn't need to use the proxy other than to set the auth secret.
if serviceType != types.MicroCloud {
path := fmt.Sprintf("/1.0/services/%s", strings.ToLower(string(serviceType)))
if !strings.HasPrefix(r.URL.Path, path) {
r.URL.Path = path + r.URL.Path
}
}

return shared.ProxyFromEnvironment(r)
}
}
21 changes: 3 additions & 18 deletions service/lxd.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"context"
"fmt"
"net"
"net/http"
"net/url"
"os"
"strings"
"time"
Expand All @@ -20,6 +18,7 @@ import (
"golang.org/x/mod/semver"

"github.com/canonical/microcloud/microcloud/api/types"
cloudClient "github.com/canonical/microcloud/microcloud/client"
"github.com/canonical/microcloud/microcloud/mdns"
)

Expand Down Expand Up @@ -60,14 +59,7 @@ func (s LXDService) Client(ctx context.Context, secret string) (lxd.InstanceServ
return lxd.ConnectLXDUnixWithContext(ctx, s.m.FileSystem.ControlSocket().URL.Host, &lxd.ConnectionArgs{
HTTPClient: c.Client.Client,
SkipGetServer: true,
Proxy: func(r *http.Request) (*url.URL, error) {
r.Header.Set("X-MicroCloud-Auth", secret)
if !strings.HasPrefix(r.URL.Path, "/1.0/services/lxd") {
r.URL.Path = "/1.0/services/lxd" + r.URL.Path
}

return shared.ProxyFromEnvironment(r)
},
Proxy: cloudClient.AuthProxy(secret, types.LXD),
})
}

Expand All @@ -83,14 +75,7 @@ func (s LXDService) remoteClient(secret string, address string, port int64) (lxd
HTTPClient: c.Client.Client,
InsecureSkipVerify: true,
SkipGetServer: true,
Proxy: func(r *http.Request) (*url.URL, error) {
r.Header.Set("X-MicroCloud-Auth", secret)
if !strings.HasPrefix(r.URL.Path, "/1.0/services/lxd") {
r.URL.Path = "/1.0/services/lxd" + r.URL.Path
}

return shared.ProxyFromEnvironment(r)
},
Proxy: cloudClient.AuthProxy(secret, types.LXD),
})
if err != nil {
return nil, err
Expand Down
42 changes: 10 additions & 32 deletions service/microceph.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package service

import (
"context"
"crypto/tls"
"fmt"
"net/http"
"net/url"
Expand All @@ -17,6 +16,7 @@ import (
"github.com/canonical/microcluster/microcluster"

"github.com/canonical/microcloud/microcloud/api/types"
cloudClient "github.com/canonical/microcloud/microcloud/client"
)

// CephService is a MicroCeph service.
Expand Down Expand Up @@ -65,15 +65,9 @@ func (s CephService) Client(target string, secret string) (*client.Client, error
c = c.UseTarget(target)
}

if secret != "" {
c.Client.Client.Transport.(*http.Transport).Proxy = func(r *http.Request) (*url.URL, error) {
r.Header.Set("X-MicroCloud-Auth", secret)
if !strings.HasPrefix(r.URL.Path, "/1.0/services/microceph") {
r.URL.Path = "/1.0/services/microceph" + r.URL.Path
}

return shared.ProxyFromEnvironment(r)
}
c, err = cloudClient.UseAuthProxy(c, secret, types.MicroCeph)
if err != nil {
return nil, err
}

return c, nil
Expand Down Expand Up @@ -141,17 +135,9 @@ func (s CephService) RemoteClusterMembers(ctx context.Context, secret string, ad
return nil, err
}

client.Client.Client.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives: true,
Proxy: func(r *http.Request) (*url.URL, error) {
r.Header.Set("X-MicroCloud-Auth", secret)
if !strings.HasPrefix(r.URL.Path, "/1.0/services/microceph") {
r.URL.Path = "/1.0/services/microceph" + r.URL.Path
}

return shared.ProxyFromEnvironment(r)
},
client, err = cloudClient.UseAuthProxy(client, secret, types.MicroCeph)
if err != nil {
return nil, err
}

return clusterMembers(ctx, client)
Expand Down Expand Up @@ -182,17 +168,9 @@ func (s CephService) ClusterConfig(ctx context.Context, targetAddress string, ta
return nil, err
}

c.Client.Client.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives: true,
Proxy: func(r *http.Request) (*url.URL, error) {
r.Header.Set("X-MicroCloud-Auth", targetSecret)
if !strings.HasPrefix(r.URL.Path, "/1.0/services/microceph") {
r.URL.Path = "/1.0/services/microceph" + r.URL.Path
}

return shared.ProxyFromEnvironment(r)
},
c, err = cloudClient.UseAuthProxy(c, targetSecret, types.MicroCeph)
if err != nil {
return nil, err
}
}

Expand Down
38 changes: 10 additions & 28 deletions service/microcloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@ package service

import (
"context"
"crypto/tls"
"fmt"
"net/http"
"net/url"
"strconv"
"time"

"github.com/canonical/lxd/lxd/util"
"github.com/canonical/lxd/shared"
"github.com/canonical/lxd/shared/api"
cephTypes "github.com/canonical/microceph/microceph/api/types"
microClient "github.com/canonical/microcluster/client"
Expand All @@ -21,6 +17,7 @@ import (

"github.com/canonical/microcloud/microcloud/api/types"
"github.com/canonical/microcloud/microcloud/client"
cloudClient "github.com/canonical/microcloud/microcloud/client"
)

// CloudService is a MicroCloud service.
Expand Down Expand Up @@ -105,14 +102,9 @@ func (s CloudService) RemoteIssueToken(ctx context.Context, clusterAddress strin
return "", err
}

c.Client.Client.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives: true,
Proxy: func(r *http.Request) (*url.URL, error) {
r.Header.Set("X-MicroCloud-Auth", secret)

return shared.ProxyFromEnvironment(r)
},
c, err = cloudClient.UseAuthProxy(c, secret, types.MicroCloud)
if err != nil {
return "", err
}

return client.RemoteIssueToken(ctx, c, serviceType, types.ServiceTokensPost{ClusterAddress: c.URL().URL.Host, JoinerName: peer})
Expand Down Expand Up @@ -141,14 +133,9 @@ func (s CloudService) RequestJoin(ctx context.Context, secret string, name strin
return err
}

c.Client.Client.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives: true,
Proxy: func(r *http.Request) (*url.URL, error) {
r.Header.Set("X-MicroCloud-Auth", secret)

return shared.ProxyFromEnvironment(r)
},
c, err = cloudClient.UseAuthProxy(c, secret, types.MicroCloud)
if err != nil {
return err
}
}

Expand All @@ -162,14 +149,9 @@ func (s CloudService) RemoteClusterMembers(ctx context.Context, secret string, a
return nil, err
}

client.Client.Client.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives: true,
Proxy: func(r *http.Request) (*url.URL, error) {
r.Header.Set("X-MicroCloud-Auth", secret)

return shared.ProxyFromEnvironment(r)
},
client, err = cloudClient.UseAuthProxy(client, secret, types.MicroCloud)
if err != nil {
return nil, err
}

return clusterMembers(ctx, client)
Expand Down
16 changes: 4 additions & 12 deletions service/microovn.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package service

import (
"context"
"crypto/tls"
"fmt"
"net/http"
"net/url"
Expand All @@ -15,6 +14,7 @@ import (
"github.com/canonical/microcluster/microcluster"

"github.com/canonical/microcloud/microcloud/api/types"
cloudClient "github.com/canonical/microcloud/microcloud/client"
)

// OVNService is a MicroOVN service.
Expand Down Expand Up @@ -101,17 +101,9 @@ func (s OVNService) RemoteClusterMembers(ctx context.Context, secret string, add
return nil, err
}

client.Client.Client.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
DisableKeepAlives: true,
Proxy: func(r *http.Request) (*url.URL, error) {
r.Header.Set("X-MicroCloud-Auth", secret)
if !strings.HasPrefix(r.URL.Path, "/1.0/services/microovn") {
r.URL.Path = "/1.0/services/microovn" + r.URL.Path
}

return shared.ProxyFromEnvironment(r)
},
client, err = cloudClient.UseAuthProxy(client, secret, types.MicroOVN)
if err != nil {
return nil, err
}

return clusterMembers(ctx, client)
Expand Down
Loading