diff --git a/server/config.go b/server/config.go
index 6400138acc53043138a9d178ac906f761f56cf1c..415c8e18985a20ddbbd958d55711fbc71920c122 100644
--- a/server/config.go
+++ b/server/config.go
@@ -38,6 +38,7 @@ type Config struct {
 	URLPrefix                  string                    `yaml:"url_path_prefix"`
 	DeviceManager              *device.Config            `yaml:"device_manager"`
 	KeyStore                   *clientutil.BackendConfig `yaml:"keystore"`
+	KeyStoreEnableGroups       []string                  `yaml:"keystore_enable_groups"`
 
 	allowedServicesRx []*regexp.Regexp
 }
diff --git a/server/http.go b/server/http.go
index 208067ba900f910c9a48def255d403d0aef2444f..be96d516eefc0cc6e632d083df18a6ffeeab7d6e 100644
--- a/server/http.go
+++ b/server/http.go
@@ -4,6 +4,7 @@ package server
 //go:generate go-bindata --nocompress --pkg server static/... templates/...
 
 import (
+	"context"
 	"encoding/gob"
 	"encoding/json"
 	"fmt"
@@ -88,6 +89,7 @@ type Server struct {
 	loginHandler        *loginHandler
 	loginService        *LoginService
 	keystore            ksclient.Client
+	keystoreGroups      []string
 	csrfSecret          []byte
 	tpl                 *template.Template
 	urlPrefix           string
@@ -134,6 +136,7 @@ func New(loginService *LoginService, authClient authclient.Client, config *Confi
 		}
 		log.Printf("keystore client enabled")
 		s.keystore = ks
+		s.keystoreGroups = config.KeyStoreEnableGroups
 	}
 
 	devMgr, err := device.New(config.DeviceManager)
@@ -145,25 +148,51 @@ func New(loginService *LoginService, authClient authclient.Client, config *Confi
 	return s, nil
 }
 
+func inAnyGroups(groups, ref []string) bool {
+	for _, rr := range ref {
+		for _, gg := range groups {
+			if gg == rr {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+// We unlock the keystore if the following conditions are met:
+// keystore_enable_groups is set, userinfo is not nil, and the groups match.
+func (h *Server) maybeUnlockKeystore(ctx context.Context, username, password string, userinfo *auth.UserInfo) (bool, error) {
+	if h.keystore == nil {
+		return false, nil
+	}
+
+	var shard string
+	if len(h.keystoreGroups) > 0 {
+		if userinfo == nil {
+			return false, nil
+		}
+		if !inAnyGroups(userinfo.Groups, h.keystoreGroups) {
+			return false, nil
+		}
+		shard = userinfo.Shard
+	}
+	return true, h.keystore.Open(ctx, shard, username, password, int(h.authSessionLifetime.Seconds()))
+}
+
 func (h *Server) loginCallback(w http.ResponseWriter, req *http.Request, username, password string, userinfo *auth.UserInfo) error {
 	// Open the keystore for this user with the password used to
 	// authenticate. Set the TTL to the duration of the
 	// authenticated session.
-	var kmsg string
-	if h.keystore != nil {
-		var shard string
-		if userinfo != nil {
-			shard = userinfo.Shard
-			kmsg = fmt.Sprintf(" (unlocked key on shard %s)", shard)
-		} else {
-			kmsg = " (unlocked key)"
-		}
-		if err := h.keystore.Open(req.Context(), shard, username, password, int(h.authSessionLifetime.Seconds())); err != nil {
-			log.Printf("failed to unlock keystore for user %s: %v", username, err)
-			return err
-		}
+	decrypted, err := h.maybeUnlockKeystore(req.Context(), username, password, userinfo)
+	if err != nil {
+		log.Printf("failed to unlock keystore for user %s: %v", username, err)
+		return err
 	}
 
+	var kmsg string
+	if decrypted {
+		kmsg = " (key unlocked)"
+	}
 	log.Printf("successful login for user %s%s", username, kmsg)
 
 	// Create cookie-based session for the authenticated user.