Skip to content

Commit

Permalink
feat: Auto-generate static credentials and auth secret if non-existent
Browse files Browse the repository at this point in the history
  • Loading branch information
codablock committed Sep 5, 2023
1 parent b1741a8 commit e2db6af
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 10 deletions.
32 changes: 32 additions & 0 deletions install/webui/webui/webui-rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ rules:
verbs: ["impersonate"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: kluctl-webui-role
namespace: kluctl-system
rules:
# allow to read/write credentials
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch", "create", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
Expand All @@ -52,3 +63,24 @@ subjects:
- kind: ServiceAccount
name: kluctl-webui
namespace: kluctl-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/component: rbac
app.kubernetes.io/created-by: controller
app.kubernetes.io/instance: kluctl-webui-rolebinding
app.kubernetes.io/managed-by: kluctl
app.kubernetes.io/name: rolebinding
app.kubernetes.io/part-of: controller
name: kluctl-webui-rolebinding
namespace: kluctl-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kluctl-webui-role
subjects:
- kind: ServiceAccount
name: kluctl-webui
namespace: kluctl-system
42 changes: 38 additions & 4 deletions pkg/k8s/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import (
"github.com/kluctl/kluctl/v2/pkg/types/k8s"
"github.com/kluctl/kluctl/v2/pkg/utils/uo"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/rand"
"sigs.k8s.io/controller-runtime/pkg/client"
)

Expand Down Expand Up @@ -68,16 +70,48 @@ func GetClusterId(ctx context.Context, c client.Client) (string, error) {
}

func GetSingleSecret(ctx context.Context, c client.Client, name string, namespace string, key string) (string, error) {
return doGetOrGenerateSingleSecret(ctx, c, name, namespace, key, false, "")
}

func GetOrGenerateSingleSecret(ctx context.Context, c client.Client, name string, namespace string, key string, manager string) (string, error) {
return doGetOrGenerateSingleSecret(ctx, c, name, namespace, key, true, manager)
}

func doGetOrGenerateSingleSecret(ctx context.Context, c client.Client, name string, namespace string, key string, allowGenerate bool, manager string) (string, error) {
var secret corev1.Secret
err := c.Get(ctx, client.ObjectKey{Name: name, Namespace: namespace}, &secret)
if err != nil {
return "", err
if !allowGenerate || !errors.IsNotFound(err) {
return "", err
}
secret.Name = name
secret.Namespace = namespace
err = c.Create(ctx, &secret, client.FieldOwner(manager))
if err != nil && !errors.IsAlreadyExists(err) {
return "", err
}
}

if secret.Data == nil {
secret.Data = map[string][]byte{}
}

x, ok := secret.Data[key]
if !ok {
return "", fmt.Errorf("secret %s has no '%s' key", name, key)
if ok {
return string(x), nil
}
if !allowGenerate {
return "", fmt.Errorf("secrets %s has no key %s", name, key)
}

generated := rand.String(32)
patch := client.MergeFrom(secret.DeepCopy())
secret.Data[key] = []byte(generated)

err = c.Patch(ctx, &secret, patch, client.FieldOwner(manager))
if err != nil {
return "", err
}

return string(x), nil
return generated, nil
}
14 changes: 9 additions & 5 deletions pkg/webui/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,20 @@ func newAuthHandler(ctx context.Context, serverClient client.Client, authConfig
return ret, nil
}

x, err := ret.getSecret(authConfig.AuthSecretName, authConfig.AuthSecretKey)
x, err := ret.getSecret(authConfig.AuthSecretName, authConfig.AuthSecretKey, true)
if err != nil {
return nil, err
}
ret.authSecret = []byte(x)

if authConfig.StaticLoginEnabled {
x, err = ret.getSecret(authConfig.StaticLoginSecretName, authConfig.StaticAdminSecretKey)
x, err = ret.getSecret(authConfig.StaticLoginSecretName, authConfig.StaticAdminSecretKey, true)
if err != nil {
return nil, err
}
ret.adminPassword = x

x, err = ret.getSecret(authConfig.StaticLoginSecretName, authConfig.StaticViewerSecretKey)
x, err = ret.getSecret(authConfig.StaticLoginSecretName, authConfig.StaticViewerSecretKey, true)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -251,9 +251,13 @@ func (s *authHandler) userHandler(c *gin.Context) {
c.JSON(http.StatusOK, user)
}

func (s *authHandler) getSecret(secretName string, secretKey string) (string, error) {
func (s *authHandler) getSecret(secretName string, secretKey string, allowGenerate bool) (string, error) {
if s.serverClient == nil {
return "", fmt.Errorf("no serverClient set")
}
return k8s.GetSingleSecret(s.ctx, s.serverClient, secretName, "kluctl-system", secretKey)
if allowGenerate {
return k8s.GetOrGenerateSingleSecret(s.ctx, s.serverClient, secretName, "kluctl-system", secretKey, "kluctl-webui")
} else {
return k8s.GetSingleSecret(s.ctx, s.serverClient, secretName, "kluctl-system", secretKey)
}
}
2 changes: 1 addition & 1 deletion pkg/webui/auth_oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (s *authHandler) setupOidcProvider(ctx context.Context, authConfig AuthConf
return nil
}

clientSecret, err := s.getSecret(authConfig.OidcClientSecretName, authConfig.OidcClientSecretKey)
clientSecret, err := s.getSecret(authConfig.OidcClientSecretName, authConfig.OidcClientSecretKey, false)
if err != nil {
return err
}
Expand Down

0 comments on commit e2db6af

Please sign in to comment.