-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support for proxying Juju client through k8s
When Juju clients want to talk with Juju controllers inside of k8s they require the controller to be publicly accessible. This commit introduces a change allowing clients to port-forward to the controller when a route able connection is not possible. Main features of the PR: - k8s tunnel and proxier for the k8s api - Start of a wider proxying framework for developing other types of proxy's for Juju controller connections - Changes to the users controller.yaml file describing the proxy to use when making connections.
- Loading branch information
Showing
34 changed files
with
1,372 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Copyright 2021 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package provider | ||
|
||
import ( | ||
k8sproxy "github.com/juju/juju/caas/kubernetes/provider/proxy" | ||
"github.com/juju/juju/proxy" | ||
) | ||
|
||
func (k *kubernetesClient) ConnectionProxyInfo() (proxy.Proxier, error) { | ||
return k8sproxy.GetControllerProxy( | ||
getBootstrapResourceName(JujuControllerStackName, proxyResourceName), | ||
k.k8sCfgUnlocked.Host, | ||
k.client().CoreV1().ConfigMaps(k.GetCurrentNamespace()), | ||
k.client().CoreV1().ServiceAccounts(k.GetCurrentNamespace()), | ||
k.client().CoreV1().Secrets(k.GetCurrentNamespace()), | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Copyright 2020 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package provider | ||
|
||
import ( | ||
"github.com/go-logr/logr" | ||
"github.com/juju/loggo" | ||
) | ||
|
||
// klogAdapter is an adapter for Kubernetes logger onto juju loggo. We use this | ||
// to suppress logging from client-go and force it through juju logging methods | ||
type klogAdapter struct { | ||
loggo.Logger | ||
} | ||
|
||
// newKlogAdapter creates a new klog adapter to juju loggo | ||
func newKlogAdapter() *klogAdapter { | ||
return &klogAdapter{ | ||
Logger: loggo.GetLogger("juju.kubernetes.klog"), | ||
} | ||
} | ||
|
||
// Enabled see https://pkg.go.dev/github.com/go-logr/logr#Logger | ||
func (k *klogAdapter) Enabled() bool { | ||
return true | ||
} | ||
|
||
// Error see https://pkg.go.dev/github.com/go-logr/logr#Logger | ||
func (k *klogAdapter) Error(err error, msg string, keysAndValues ...interface{}) { | ||
if err != nil { | ||
k.Logger.Debugf(msg+": "+err.Error(), keysAndValues...) | ||
} else { | ||
k.Logger.Debugf(msg, keysAndValues...) | ||
} | ||
} | ||
|
||
// Info see https://pkg.go.dev/github.com/go-logr/logr#Logger | ||
func (k *klogAdapter) Info(msg string, keysAndValues ...interface{}) { | ||
k.Logger.Infof(msg, keysAndValues...) | ||
} | ||
|
||
// V see https://pkg.go.dev/github.com/go-logr/logr#Logger | ||
func (k *klogAdapter) V(level int) logr.Logger { | ||
return k | ||
} | ||
|
||
// WithValues see https://pkg.go.dev/github.com/go-logr/logr#Logger | ||
func (k *klogAdapter) WithValues(keysAndValues ...interface{}) logr.Logger { | ||
return k | ||
} | ||
|
||
// WithName see https://pkg.go.dev/github.com/go-logr/logr#Logger | ||
func (k *klogAdapter) WithName(name string) logr.Logger { | ||
return k | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// Copyright 2021 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package proxy | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
|
||
"github.com/juju/errors" | ||
k8serrors "k8s.io/apimachinery/pkg/api/errors" | ||
meta "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
core "k8s.io/client-go/kubernetes/typed/core/v1" | ||
) | ||
|
||
const ( | ||
serviceAccountSecretCADataKey = "ca.crt" | ||
serviceAccountSecretNamespaceKey = "namespace" | ||
serviceAccountSecretTokenKey = "token" | ||
) | ||
|
||
func GetControllerProxy( | ||
name, | ||
apiHost string, | ||
configI core.ConfigMapInterface, | ||
saI core.ServiceAccountInterface, | ||
secretI core.SecretInterface, | ||
) (*Proxier, error) { | ||
cm, err := configI.Get(context.TODO(), name, meta.GetOptions{}) | ||
if k8serrors.IsNotFound(err) { | ||
return nil, errors.NotFoundf("controller proxy config %s", name) | ||
} else if err != nil { | ||
return nil, errors.Trace(err) | ||
} | ||
|
||
config := ControllerProxyConfig{} | ||
if err := json.Unmarshal([]byte(cm.Data[ProxyConfigMapKey]), &config); err != nil { | ||
return nil, errors.Trace(err) | ||
} | ||
|
||
sa, err := saI.Get(context.TODO(), config.Name, meta.GetOptions{}) | ||
if k8serrors.IsNotFound(err) { | ||
return nil, errors.NotFoundf("controller proxy service account for %s", name) | ||
} else if err != nil { | ||
return nil, errors.Trace(err) | ||
} | ||
|
||
if secLen := len(sa.Secrets); secLen < 1 || secLen > 1 { | ||
return nil, fmt.Errorf("unsupported number of service account secrets: %d", secLen) | ||
} | ||
|
||
sec, err := secretI.Get(context.TODO(), sa.Secrets[0].Name, meta.GetOptions{}) | ||
if k8serrors.IsNotFound(err) { | ||
return nil, fmt.Errorf("could not get proxy service account secret: %s", sa.Secrets[0].Name) | ||
} else if err != nil { | ||
return nil, errors.Trace(err) | ||
} | ||
|
||
proxierConfig := ProxierConfig{ | ||
APIHost: apiHost, | ||
CAData: string(sec.Data[serviceAccountSecretCADataKey]), | ||
Namespace: config.Namespace, | ||
RemotePort: config.RemotePort, | ||
Service: config.TargetService, | ||
ServiceAccountToken: string(sec.Data[serviceAccountSecretTokenKey]), | ||
} | ||
|
||
return NewProxier(proxierConfig), nil | ||
} | ||
|
||
func HasControllerProxy( | ||
name string, | ||
configI core.ConfigMapInterface, | ||
) (bool, error) { | ||
_, err := configI.Get(context.TODO(), name, meta.GetOptions{}) | ||
if k8serrors.IsNotFound(err) { | ||
return false, nil | ||
} else if err != nil { | ||
return false, errors.Trace(err) | ||
} | ||
return true, nil | ||
} |
Oops, something went wrong.