diff --git a/internal/pkg/skuba/addons/dex.go b/internal/pkg/skuba/addons/dex.go index dc383cc45c..0a6fe46b42 100644 --- a/internal/pkg/skuba/addons/dex.go +++ b/internal/pkg/skuba/addons/dex.go @@ -18,12 +18,14 @@ package addons import ( + "github.com/pkg/errors" + "k8s.io/kubernetes/cmd/kubeadm/app/images" + "github.com/SUSE/skuba/internal/pkg/skuba/dex" + "github.com/SUSE/skuba/internal/pkg/skuba/gangway" "github.com/SUSE/skuba/internal/pkg/skuba/kubernetes" "github.com/SUSE/skuba/internal/pkg/skuba/skuba" skubaconstants "github.com/SUSE/skuba/pkg/skuba" - "github.com/pkg/errors" - "k8s.io/kubernetes/cmd/kubeadm/app/images" ) var gangwayClientSecret string @@ -54,10 +56,20 @@ func renderDexTemplate(addonConfiguration AddonConfiguration) string { type dexCallbacks struct{} func (dexCallbacks) beforeApply(addonConfiguration AddonConfiguration, skubaConfiguration *skuba.SkubaConfiguration) error { + var err error + client, err := kubernetes.GetAdminClientSet() if err != nil { return errors.Wrap(err, "could not get admin client set") } + + // Read gangway client secret from secret resource if present + // in order to update global variable gangwayClientSecret. + gangwayClientSecret, err = gangway.GetClientSecret(client) + if err != nil { + return errors.Wrap(err, "unable to determine if gangway client secret exists") + } + dexCertExists, err := dex.DexCertExists(client) if err != nil { return errors.Wrap(err, "unable to determine if dex certificate exists") diff --git a/internal/pkg/skuba/addons/gangway.go b/internal/pkg/skuba/addons/gangway.go index 7d67fe9a0f..672628a4bd 100644 --- a/internal/pkg/skuba/addons/gangway.go +++ b/internal/pkg/skuba/addons/gangway.go @@ -18,12 +18,13 @@ package addons import ( + "github.com/pkg/errors" + "k8s.io/kubernetes/cmd/kubeadm/app/images" + "github.com/SUSE/skuba/internal/pkg/skuba/gangway" "github.com/SUSE/skuba/internal/pkg/skuba/kubernetes" "github.com/SUSE/skuba/internal/pkg/skuba/skuba" skubaconstants "github.com/SUSE/skuba/pkg/skuba" - "github.com/pkg/errors" - "k8s.io/kubernetes/cmd/kubeadm/app/images" ) func init() { @@ -49,6 +50,14 @@ func (gangwayCallbacks) beforeApply(addonConfiguration AddonConfiguration, skuba if err != nil { return errors.Wrap(err, "could not get admin client set") } + + // Read gangway client secret from secret resource if present + // in order to update global variable gangwayClientSecret. + gangwayClientSecret, err = gangway.GetClientSecret(client) + if err != nil { + return errors.Wrap(err, "unable to determine if gangway client secret exists") + } + gangwaySecretExists, err := gangway.GangwaySecretExists(client) if err != nil { return errors.Wrap(err, "unable to determine if gangway secret exists") diff --git a/internal/pkg/skuba/gangway/gangway.go b/internal/pkg/skuba/gangway/gangway.go index 06ca053682..3936aeadbc 100644 --- a/internal/pkg/skuba/gangway/gangway.go +++ b/internal/pkg/skuba/gangway/gangway.go @@ -24,11 +24,13 @@ import ( "github.com/pkg/errors" v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clientset "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" "k8s.io/kubernetes/cmd/kubeadm/app/util/pkiutil" + "sigs.k8s.io/yaml" "github.com/SUSE/skuba/internal/pkg/skuba/kubernetes" "github.com/SUSE/skuba/internal/pkg/skuba/node" @@ -41,6 +43,8 @@ const ( sessionKey = "session-key" secretKeyName = "oidc-gangway-secret" + + configmapName = "oidc-gangway-config" ) // GenerateSessionKey generates session key @@ -73,6 +77,32 @@ func CreateOrUpdateSessionKeyToSecret(client clientset.Interface, key []byte) er return nil } +// GetClientSecret returns the client secret from configmap +func GetClientSecret(client clientset.Interface) (string, error) { + type config struct { + ClientSecret string `yaml:"clientSecret"` + } + + cm, err := client.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(configmapName, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return "", nil + } + return "", err + } + + data, ok := cm.Data["gangway.yaml"] + if !ok { + return "", nil + } + + c := config{} + if err := yaml.Unmarshal([]byte(data), &c); err != nil { + return "", err + } + return c.ClientSecret, nil +} + // CreateCert creates a signed certificate for gangway // with kubernetes CA certificate and key func CreateCert(client clientset.Interface, pkiPath, kubeadmInitConfPath string) error { diff --git a/internal/pkg/skuba/gangway/gangway_test.go b/internal/pkg/skuba/gangway/gangway_test.go index ec63f86b35..1916351418 100644 --- a/internal/pkg/skuba/gangway/gangway_test.go +++ b/internal/pkg/skuba/gangway/gangway_test.go @@ -27,7 +27,7 @@ import ( "k8s.io/client-go/kubernetes/fake" ) -func Test_GenerateSessionKey(t *testing.T) { +func TestGenerateSessionKey(t *testing.T) { tests := []struct { name string inputLen int @@ -61,7 +61,7 @@ func Test_GenerateSessionKey(t *testing.T) { } } -func Test_CreateOrUpdateSessionKeyToSecret(t *testing.T) { +func TestCreateOrUpdateSessionKeyToSecret(t *testing.T) { tests := []struct { name string key []byte @@ -83,7 +83,95 @@ func Test_CreateOrUpdateSessionKeyToSecret(t *testing.T) { } } -func Test_CreateCert(t *testing.T) { +func TestGetClientSecret(t *testing.T) { + manifest := ` +clusterName: example +redirectURL: "https://example.com/callback" +scopes: ["openid", "email", "groups", "profile", "offline_access"] +serveTLS: true +authorizeURL: "https://example.com:32000/auth" +tokenURL: "https://example.com:32000/token" +keyFile: /etc/gangway/pki/tls.key +certFile: /etc/gangway/pki/tls.crt +clientID: "oidc" +clientSecret: "someClientSecret" +usernameClaim: "email" +apiServerURL: "https://example.com:6443" +cluster_ca_path: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" +trustedCAPath: /etc/gangway/pki/ca.crt +customHTMLTemplatesDir: /usr/share/caasp-gangway/web/templates/caasp +` + + tests := []struct { + name string + client clientset.Interface + expectedError bool + expectClientSecret string + }{ + { + name: "get client secret success", + client: fake.NewSimpleClientset(&corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configmapName, + Namespace: metav1.NamespaceSystem, + }, + Data: map[string]string{ + "gangway.yaml": manifest, + }, + }), + expectClientSecret: "someClientSecret", + }, + { + name: "client secret not exist", + client: fake.NewSimpleClientset(&corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configmapName, + Namespace: metav1.NamespaceDefault, + }, + Data: map[string]string{ + "gangway.yaml": manifest, + }, + }), + expectClientSecret: "", + }, + { + name: "client secret key not exist", + client: fake.NewSimpleClientset(&corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configmapName, + Namespace: metav1.NamespaceSystem, + }, + Data: map[string]string{ + "ooxx.yaml": manifest, + }, + }), + expectClientSecret: "", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + gotClientSecret, err := GetClientSecret(tt.client) + if tt.expectedError { + if err == nil { + t.Errorf("error expected on %s, but no error reported", tt.name) + } + return + } else if err != nil { + t.Errorf("error not expected on %s, but an error was reported (%v)", tt.name, err) + return + } + + if gotClientSecret != tt.expectClientSecret { + t.Errorf("got %s, want %s", gotClientSecret, tt.expectClientSecret) + return + } + }) + } +} + +func TestCreateCert(t *testing.T) { tests := []struct { name string pkiPath string @@ -124,7 +212,7 @@ func Test_CreateCert(t *testing.T) { } } -func Test_GangwaySecretExists(t *testing.T) { +func TestGangwaySecretExists(t *testing.T) { tests := []struct { name string client clientset.Interface @@ -171,7 +259,7 @@ func Test_GangwaySecretExists(t *testing.T) { } } -func Test_GangwayCertExists(t *testing.T) { +func TestGangwayCertExists(t *testing.T) { tests := []struct { name string client clientset.Interface @@ -218,7 +306,7 @@ func Test_GangwayCertExists(t *testing.T) { } } -func Test_RestartPods(t *testing.T) { +func TestRestartPods(t *testing.T) { tests := []struct { name string client clientset.Interface diff --git a/vendor/modules.txt b/vendor/modules.txt index a5144a78a6..ae76899480 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -216,8 +216,8 @@ k8s.io/apiextensions-apiserver/pkg/features k8s.io/apimachinery/pkg/util/version k8s.io/apimachinery/pkg/apis/meta/v1 k8s.io/apimachinery/pkg/types -k8s.io/apimachinery/pkg/runtime k8s.io/apimachinery/pkg/api/errors +k8s.io/apimachinery/pkg/runtime k8s.io/apimachinery/pkg/util/wait k8s.io/apimachinery/pkg/runtime/schema k8s.io/apimachinery/pkg/runtime/serializer @@ -234,11 +234,11 @@ k8s.io/apimachinery/pkg/selection k8s.io/apimachinery/pkg/util/runtime k8s.io/apimachinery/pkg/watch k8s.io/apimachinery/pkg/util/strategicpatch +k8s.io/apimachinery/pkg/util/validation/field k8s.io/apimachinery/pkg/conversion/queryparams k8s.io/apimachinery/pkg/util/json k8s.io/apimachinery/pkg/util/naming k8s.io/apimachinery/pkg/util/sets -k8s.io/apimachinery/pkg/util/validation/field k8s.io/apimachinery/pkg/runtime/serializer/json k8s.io/apimachinery/pkg/runtime/serializer/versioning k8s.io/apimachinery/pkg/api/meta