summaryrefslogtreecommitdiff
path: root/path_config.go
diff options
context:
space:
mode:
Diffstat (limited to 'path_config.go')
-rw-r--r--path_config.go253
1 files changed, 253 insertions, 0 deletions
diff --git a/path_config.go b/path_config.go
new file mode 100644
index 0000000..a89488b
--- /dev/null
+++ b/path_config.go
@@ -0,0 +1,253 @@
+package secretsengine
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "time"
+
+ "git.tardisproject.uk/tcmal/vault-plugin-kerberos-secrets/config"
+ "github.com/hashicorp/vault/sdk/framework"
+ "github.com/hashicorp/vault/sdk/logical"
+)
+
+const (
+ configStoragePath = "config"
+ defaultCtxTimeout = 1 * time.Minute
+)
+
+// ConfigPaths extends the Vault API with a `/config` endpoint for the backend.
+func pathConfig(b *krbBackend) []*framework.Path {
+ return []*framework.Path{&framework.Path{
+ Pattern: "config",
+ Fields: configSchema(),
+ Operations: map[logical.Operation]framework.OperationHandler{
+ logical.ReadOperation: &framework.PathOperation{
+ Callback: b.pathConfigRead,
+ },
+ logical.CreateOperation: &framework.PathOperation{
+ Callback: b.pathConfigWrite,
+ },
+ logical.UpdateOperation: &framework.PathOperation{
+ Callback: b.pathConfigWrite,
+ },
+ logical.DeleteOperation: &framework.PathOperation{
+ Callback: b.pathConfigDelete,
+ },
+ },
+ ExistenceCheck: b.pathConfigExistenceCheck,
+ HelpSynopsis: pathConfigHelpSynopsis,
+ HelpDescription: pathConfigHelpDescription,
+ },
+ }
+}
+
+func configSchema() map[string]*framework.FieldSchema {
+ return map[string]*framework.FieldSchema{
+ "realm": {
+ Type: framework.TypeString,
+ Description: "The realm to authenticate against",
+ Required: true,
+ DisplayAttrs: &framework.DisplayAttributes{
+ Name: "Realm",
+ Sensitive: false,
+ },
+ },
+ "username": {
+ Type: framework.TypeString,
+ Description: "The username to access kadmin with",
+ Required: true,
+ DisplayAttrs: &framework.DisplayAttributes{
+ Name: "Username",
+ Sensitive: false,
+ },
+ },
+ "password": {
+ Type: framework.TypeString,
+ Description: "The user's password to access kadmin with",
+ Required: true,
+ DisplayAttrs: &framework.DisplayAttributes{
+ Name: "Password",
+ Sensitive: true,
+ },
+ },
+ "kdc": {
+ Type: framework.TypeCommaStringSlice,
+ Description: "Available KDCs for the realm",
+ Required: true,
+ DisplayAttrs: &framework.DisplayAttributes{
+ Name: "KDCs",
+ Sensitive: false,
+ },
+ },
+ "admin_server": {
+ Type: framework.TypeCommaStringSlice,
+ Description: "Available admin servers for the realm",
+ Required: true,
+ DisplayAttrs: &framework.DisplayAttributes{
+ Name: "Admin Servers",
+ Sensitive: false,
+ },
+ },
+ "kpasswd_server": {
+ Type: framework.TypeCommaStringSlice,
+ Description: "KPasswd servers for the realm",
+ Required: true,
+ DisplayAttrs: &framework.DisplayAttributes{
+ Name: "KPasswd Servers",
+ Sensitive: false,
+ },
+ },
+ }
+
+}
+
+// pathConfigExistenceCheck verifies if the configuration exists.
+func (b *krbBackend) pathConfigExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) {
+ out, err := req.Storage.Get(ctx, req.Path)
+ if err != nil {
+ return false, fmt.Errorf("existence check failed: %w", err)
+ }
+
+ return out != nil, nil
+}
+
+// pathConfigRead reads the configuration and outputs non-sensitive information.
+func (b *krbBackend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
+ config, err := getConfig(ctx, req.Storage)
+ if err != nil {
+ return nil, err
+ }
+
+ if config == nil {
+ return nil, fmt.Errorf("config not yet created")
+ }
+
+ return &logical.Response{
+ Data: map[string]interface{}{
+ "realm": config.Realm,
+ "kdc": config.KDC,
+ "admin_server": config.AdminServer,
+ "kpasswd_server": config.KPasswdServer,
+ "username": config.Username,
+ },
+ }, nil
+}
+
+// pathConfigWrite updates the configuration for the backend
+func (b *krbBackend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
+ c, err := getConfig(ctx, req.Storage)
+ if err != nil {
+ return nil, err
+ }
+
+ createOperation := (req.Operation == logical.CreateOperation)
+
+ if c == nil {
+ if !createOperation {
+ return nil, errors.New("config not found during update operation")
+ }
+ c = new(config.Config)
+ }
+
+ if realm, ok := data.GetOk("realm"); ok {
+ c.Realm = realm.(string)
+ } else if !ok && createOperation {
+ return nil, fmt.Errorf("missing realm in configuration")
+ }
+
+ // TODO: Also validate these aren't empty
+ if kdc, ok := data.GetOk("kdc"); ok {
+ c.KDC = kdc.([]string)
+ } else if !ok && createOperation {
+ return nil, fmt.Errorf("missing KDCs in configuration")
+ }
+ if len(c.KDC) == 0 {
+ return nil, fmt.Errorf("no KDCs specified")
+ }
+
+ if admin_server, ok := data.GetOk("admin_server"); ok {
+ c.AdminServer = admin_server.([]string)
+ } else if !ok && createOperation {
+ return nil, fmt.Errorf("missing admin servers in configuration")
+ }
+ if len(c.AdminServer) == 0 {
+ return nil, fmt.Errorf("no admin servers specified")
+ }
+
+ if kpasswd_server, ok := data.GetOk("kpasswd_server"); ok {
+ c.KPasswdServer = kpasswd_server.([]string)
+ } else if !ok && createOperation {
+ return nil, fmt.Errorf("missing kpasswd servers in configuration")
+ }
+ if len(c.KPasswdServer) == 0 {
+ return nil, fmt.Errorf("no kpasswd servers specified")
+ }
+
+ if username, ok := data.GetOk("username"); ok {
+ c.Username = username.(string)
+ } else if !ok && createOperation {
+ return nil, fmt.Errorf("missing username in configuration")
+ }
+
+ if password, ok := data.GetOk("password"); ok {
+ c.Password = password.(string)
+ } else if !ok && createOperation {
+ return nil, fmt.Errorf("missing password in configuration")
+ }
+
+ entry, err := logical.StorageEntryJSON(configStoragePath, c)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := req.Storage.Put(ctx, entry); err != nil {
+ return nil, err
+ }
+
+ b.reset()
+
+ return nil, nil
+}
+
+// pathConfigDelete removes the configuration for the backend
+func (b *krbBackend) pathConfigDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
+ err := req.Storage.Delete(ctx, configStoragePath)
+
+ if err == nil {
+ b.reset()
+ }
+
+ return nil, err
+}
+
+func getConfig(ctx context.Context, s logical.Storage) (*config.Config, error) {
+ entry, err := s.Get(ctx, configStoragePath)
+ if err != nil {
+ return nil, err
+ }
+
+ if entry == nil {
+ return nil, nil
+ }
+
+ c := new(config.Config)
+ if err := entry.DecodeJSON(&c); err != nil {
+ return nil, fmt.Errorf("error reading root configuration: %w", err)
+ }
+
+ // return the config, we are done
+ return c, nil
+}
+
+// pathConfigHelpSynopsis summarizes the help text for the configuration
+const pathConfigHelpSynopsis = `Configure the Kerberos backend.`
+
+// pathConfigHelpDescription describes the help text for the configuration
+const pathConfigHelpDescription = `
+The Kerberos secret backend requires credentials and
+connection details for the Kerberos servers.
+
+The user provided must be able to create & modify principals
+in order for this backend to work correctly.
+`