summaryrefslogtreecommitdiff
path: root/path_static_roles.go
diff options
context:
space:
mode:
Diffstat (limited to 'path_static_roles.go')
-rw-r--r--path_static_roles.go202
1 files changed, 202 insertions, 0 deletions
diff --git a/path_static_roles.go b/path_static_roles.go
new file mode 100644
index 0000000..a9b3ee9
--- /dev/null
+++ b/path_static_roles.go
@@ -0,0 +1,202 @@
+package secretsengine
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/hashicorp/vault/sdk/framework"
+ "github.com/hashicorp/vault/sdk/logical"
+)
+
+const staticRolePath = "static-role"
+
+// staticRoleEntry defines the data required
+// for a static role, using a set principal
+type staticRoleEntry struct {
+ Principal string `json:"principal"`
+ Password string `json:"password"`
+ LastVaultRotation time.Time `json:"last_vault_rotation"`
+}
+
+// toResponseData returns response data for a role
+func (r *staticRoleEntry) toResponseData() map[string]interface{} {
+ respData := map[string]interface{}{
+ "principal": r.Principal,
+ "last_vault_rotation": r.LastVaultRotation,
+ }
+ return respData
+}
+
+// pathStaticRole extends the Vault API with a `/static-role`
+// endpoint for the backend.
+func pathStaticRole(b *krbBackend) []*framework.Path {
+ return []*framework.Path{
+ {
+ Pattern: staticRolePath + "/" + framework.GenericNameRegex("name"),
+ Fields: map[string]*framework.FieldSchema{
+ "name": {
+ Type: framework.TypeLowerCaseString,
+ Description: "Name of the role",
+ Required: true,
+ },
+ "principal": {
+ Type: framework.TypeString,
+ Description: "The principal credentials should be generated for.",
+ Required: true,
+ },
+ "last_vault_rotation": {
+ Type: framework.TypeDurationSecond,
+ Description: "Last time the credentials were rotated.",
+ },
+ },
+ Operations: map[logical.Operation]framework.OperationHandler{
+ logical.ReadOperation: &framework.PathOperation{
+ Callback: b.pathRolesRead,
+ },
+ logical.CreateOperation: &framework.PathOperation{
+ Callback: b.pathRolesWrite,
+ },
+ logical.UpdateOperation: &framework.PathOperation{
+ Callback: b.pathRolesWrite,
+ },
+ logical.DeleteOperation: &framework.PathOperation{
+ Callback: b.pathRolesDelete,
+ },
+ },
+ HelpSynopsis: pathRoleHelpSynopsis,
+ HelpDescription: pathRoleHelpDescription,
+ },
+ {
+ Pattern: staticRolePath + "/?$",
+ Operations: map[logical.Operation]framework.OperationHandler{
+ logical.ListOperation: &framework.PathOperation{
+ Callback: b.pathRolesList,
+ },
+ },
+ HelpSynopsis: pathRoleListHelpSynopsis,
+ HelpDescription: pathRoleListHelpDescription,
+ },
+ }
+}
+
+// pathRolesList makes a request to Vault storage to retrieve a list of roles for the backend
+func (b *krbBackend) pathRolesList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
+ entries, err := req.Storage.List(ctx, staticRolePath)
+ if err != nil {
+ return nil, err
+ }
+
+ return logical.ListResponse(entries), nil
+}
+
+// pathRolesRead makes a request to Vault storage to read a role and return response data
+func (b *krbBackend) pathRolesRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
+ entry, err := b.getRole(ctx, req.Storage, d.Get("name").(string))
+ if err != nil {
+ return nil, err
+ }
+
+ if entry == nil {
+ return nil, nil
+ }
+
+ return &logical.Response{
+ Data: entry.toResponseData(),
+ }, nil
+}
+
+// pathRolesWrite makes a request to Vault storage to update a role based on the attributes passed to the role configuration
+func (b *krbBackend) pathRolesWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
+ name, ok := d.GetOk("name")
+ if !ok {
+ return logical.ErrorResponse("missing role name"), nil
+ }
+
+ roleEntry, err := b.getRole(ctx, req.Storage, name.(string))
+ if err != nil {
+ return nil, err
+ }
+
+ if roleEntry == nil {
+ roleEntry = &staticRoleEntry{}
+ }
+
+ createOperation := (req.Operation == logical.CreateOperation)
+
+ if principal, ok := d.GetOk("principal"); ok {
+ roleEntry.Principal = principal.(string)
+ } else if !ok && createOperation {
+ return nil, fmt.Errorf("missing principal in role")
+ }
+
+ roleEntry.LastVaultRotation = time.Unix(0, 0)
+
+ if err := setRole(ctx, req.Storage, name.(string), roleEntry); err != nil {
+ return nil, err
+ }
+
+ return nil, nil
+}
+
+// pathRolesDelete makes a request to Vault storage to delete a role
+func (b *krbBackend) pathRolesDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
+ err := req.Storage.Delete(ctx, staticRolePath+"/"+d.Get("name").(string))
+ if err != nil {
+ return nil, fmt.Errorf("error deleting krb role: %w", err)
+ }
+
+ return nil, nil
+}
+
+// setRole adds the role to the Vault storage API
+func setRole(ctx context.Context, s logical.Storage, name string, roleEntry *staticRoleEntry) error {
+ entry, err := logical.StorageEntryJSON(staticRolePath+"/"+name, roleEntry)
+ if err != nil {
+ return err
+ }
+
+ if entry == nil {
+ return fmt.Errorf("failed to create storage entry for role")
+ }
+
+ if err := s.Put(ctx, entry); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// getRole gets the role from the Vault storage API
+func (b *krbBackend) getRole(ctx context.Context, s logical.Storage, name string) (*staticRoleEntry, error) {
+ if name == "" {
+ return nil, fmt.Errorf("missing role name")
+ }
+
+ entry, err := s.Get(ctx, staticRolePath+"/"+name)
+ if err != nil {
+ return nil, err
+ }
+
+ if entry == nil {
+ return nil, nil
+ }
+
+ var role staticRoleEntry
+
+ if err := entry.DecodeJSON(&role); err != nil {
+ return nil, err
+ }
+ return &role, nil
+}
+
+const (
+ pathRoleHelpSynopsis = `Manages the Vault roles for credentials for individual Kerberos principals.`
+ pathRoleHelpDescription = `
+This path allows you to read and write roles used to generate credentials for individual Kerberos principals.
+You can configure a role to manage a principal's password by setting the principal field.
+`
+
+ pathRoleListHelpSynopsis = `List the existing roles in HashiCups backend`
+ pathRoleListHelpDescription = `Roles will be listed by the role name.`
+)