2016-05-30 18:30:01 +00:00
package approle
import (
2018-01-08 18:31:38 +00:00
"context"
2016-05-30 18:30:01 +00:00
"fmt"
"strings"
"time"
"github.com/fatih/structs"
2018-04-05 15:49:21 +00:00
"github.com/hashicorp/errwrap"
2016-05-30 18:30:01 +00:00
"github.com/hashicorp/go-uuid"
2016-09-19 18:40:43 +00:00
"github.com/hashicorp/vault/helper/cidrutil"
2018-03-08 22:49:08 +00:00
"github.com/hashicorp/vault/helper/consts"
2017-03-07 16:21:32 +00:00
"github.com/hashicorp/vault/helper/locksutil"
2016-05-30 18:30:01 +00:00
"github.com/hashicorp/vault/helper/policyutil"
"github.com/hashicorp/vault/helper/strutil"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
// roleStorageEntry stores all the options that are set on an role
type roleStorageEntry struct {
// UUID that uniquely represents this role. This serves as a credential
// to perform login using this role.
RoleID string ` json:"role_id" structs:"role_id" mapstructure:"role_id" `
// UUID that serves as the HMAC key for the hashing the 'secret_id's
// of the role
HMACKey string ` json:"hmac_key" structs:"hmac_key" mapstructure:"hmac_key" `
// Policies that are to be required by the token to access this role
Policies [ ] string ` json:"policies" structs:"policies" mapstructure:"policies" `
// Number of times the SecretID generated against this role can be
// used to perform login operation
SecretIDNumUses int ` json:"secret_id_num_uses" structs:"secret_id_num_uses" mapstructure:"secret_id_num_uses" `
// Duration (less than the backend mount's max TTL) after which a
// SecretID generated against the role will expire
SecretIDTTL time . Duration ` json:"secret_id_ttl" structs:"secret_id_ttl" mapstructure:"secret_id_ttl" `
2017-03-03 14:31:20 +00:00
// TokenNumUses defines the number of allowed uses of the token issued
TokenNumUses int ` json:"token_num_uses" mapstructure:"token_num_uses" structs:"token_num_uses" `
2016-05-30 18:30:01 +00:00
// Duration before which an issued token must be renewed
TokenTTL time . Duration ` json:"token_ttl" structs:"token_ttl" mapstructure:"token_ttl" `
// Duration after which an issued token should not be allowed to be renewed
TokenMaxTTL time . Duration ` json:"token_max_ttl" structs:"token_max_ttl" mapstructure:"token_max_ttl" `
// A constraint, if set, requires 'secret_id' credential to be presented during login
BindSecretID bool ` json:"bind_secret_id" structs:"bind_secret_id" mapstructure:"bind_secret_id" `
// A constraint, if set, specifies the CIDR blocks from which logins should be allowed
2018-03-08 22:49:08 +00:00
BoundCIDRListOld string ` json:"bound_cidr_list,omitempty" `
// A constraint, if set, specifies the CIDR blocks from which logins should be allowed
BoundCIDRList [ ] string ` json:"bound_cidr_list_list" structs:"bound_cidr_list" mapstructure:"bound_cidr_list" `
2016-05-30 18:30:01 +00:00
// Period, if set, indicates that the token generated using this role
// should never expire. The token should be renewed within the duration
// specified by this value. The renewal duration will be fixed if the
// value is not modified on the role. If the `Period` in the role is modified,
// a token will pick up the new value during its next renewal.
Period time . Duration ` json:"period" mapstructure:"period" structs:"period" `
2017-12-11 21:41:17 +00:00
// LowerCaseRoleName enforces the lower casing of role names for all the
// roles that get created since this field was introduced.
LowerCaseRoleName bool ` json:"lower_case_role_name" mapstructure:"lower_case_role_name" structs:"lower_case_role_name" `
2018-04-23 14:51:55 +00:00
2018-04-23 21:05:53 +00:00
// SecretIDPrefix is the storage prefix for persisting secret IDs. This
// differs based on whether the secret IDs are cluster local or not.
2018-04-23 15:59:37 +00:00
SecretIDPrefix string ` json:"secret_id_prefix" mapstructure:"secret_id_prefix" structs:"secret_id_prefix" `
2016-05-30 18:30:01 +00:00
}
// roleIDStorageEntry represents the reverse mapping from RoleID to Role
type roleIDStorageEntry struct {
Name string ` json:"name" structs:"name" mapstructure:"name" `
}
// rolePaths creates all the paths that are used to register and manage an role.
//
// Paths returned:
// role/ - For listing all the registered roles
// role/<role_name> - For registering an role
// role/<role_name>/policies - For updating the param
// role/<role_name>/secret-id-num-uses - For updating the param
// role/<role_name>/secret-id-ttl - For updating the param
// role/<role_name>/token-ttl - For updating the param
// role/<role_name>/token-max-ttl - For updating the param
2017-03-03 14:31:20 +00:00
// role/<role_name>/token-num-uses - For updating the param
2016-05-30 18:30:01 +00:00
// role/<role_name>/bind-secret-id - For updating the param
// role/<role_name>/bound-cidr-list - For updating the param
// role/<role_name>/period - For updating the param
// role/<role_name>/role-id - For fetching the role_id of an role
2018-03-20 18:54:10 +00:00
// role/<role_name>/secret-id - For issuing a secret_id against an role, also to list the secret_id_accessors
2016-05-30 18:30:01 +00:00
// role/<role_name>/custom-secret-id - For assigning a custom SecretID against an role
2016-09-29 00:22:37 +00:00
// role/<role_name>/secret-id/lookup - For reading the properties of a secret_id
// role/<role_name>/secret-id/destroy - For deleting a secret_id
2016-09-29 02:11:48 +00:00
// role/<role_name>/secret-id-accessor/lookup - For reading secret_id using accessor
// role/<role_name>/secret-id-accessor/destroy - For deleting secret_id using accessor
2016-05-30 18:30:01 +00:00
func rolePaths ( b * backend ) [ ] * framework . Path {
return [ ] * framework . Path {
& framework . Path {
Pattern : "role/?" ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . ListOperation : b . pathRoleList ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-list" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-list" ] [ 1 ] ) ,
} ,
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"bind_secret_id" : & framework . FieldSchema {
Type : framework . TypeBool ,
Default : true ,
Description : "Impose secret_id to be presented when logging in using this role. Defaults to 'true'." ,
} ,
"bound_cidr_list" : & framework . FieldSchema {
2018-03-08 22:49:08 +00:00
Type : framework . TypeCommaStringSlice ,
Description : ` Comma separated string or list of CIDR blocks . If set , specifies the blocks of
IP addresses which can perform the login operation . ` ,
2016-05-30 18:30:01 +00:00
} ,
"policies" : & framework . FieldSchema {
2017-08-15 00:15:51 +00:00
Type : framework . TypeCommaStringSlice ,
2016-05-30 18:30:01 +00:00
Default : "default" ,
Description : "Comma separated list of policies on the role." ,
} ,
"secret_id_num_uses" : & framework . FieldSchema {
Type : framework . TypeInt ,
Description : ` Number of times a SecretID can access the role , after which the SecretID
will expire . Defaults to 0 meaning that the the secret_id is of unlimited use . ` ,
} ,
"secret_id_ttl" : & framework . FieldSchema {
Type : framework . TypeDurationSecond ,
Description : ` Duration in seconds after which the issued SecretID should expire . Defaults
2016-11-15 16:50:51 +00:00
to 0 , meaning no expiration . ` ,
2016-05-30 18:30:01 +00:00
} ,
2017-03-03 14:31:20 +00:00
"token_num_uses" : & framework . FieldSchema {
Type : framework . TypeInt ,
Description : ` Number of times issued tokens can be used ` ,
} ,
2016-05-30 18:30:01 +00:00
"token_ttl" : & framework . FieldSchema {
Type : framework . TypeDurationSecond ,
Description : ` Duration in seconds after which the issued token should expire . Defaults
to 0 , in which case the value will fall back to the system / mount defaults . ` ,
} ,
"token_max_ttl" : & framework . FieldSchema {
Type : framework . TypeDurationSecond ,
Description : ` Duration in seconds after which the issued token should not be allowed to
be renewed . Defaults to 0 , in which case the value will fall back to the system / mount defaults . ` ,
} ,
"period" : & framework . FieldSchema {
Type : framework . TypeDurationSecond ,
Default : 0 ,
Description : ` If set , indicates that the token generated using this role
should never expire . The token should be renewed within the
duration specified by this value . At each renewal , the token ' s
TTL will be set to the value of this parameter . ` ,
} ,
"role_id" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Identifier of the role. Defaults to a UUID." ,
} ,
2018-04-23 20:52:09 +00:00
"enable_local_secret_ids" : & framework . FieldSchema {
2018-04-23 14:51:55 +00:00
Type : framework . TypeBool ,
Description : `
2018-04-23 21:05:53 +00:00
If set , the secret IDs generated using this role will be cluster local . This
can only be set during role creation and once set , it can ' t be reset later . ` ,
2018-04-23 14:51:55 +00:00
} ,
2016-05-30 18:30:01 +00:00
} ,
ExistenceCheck : b . pathRoleExistenceCheck ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . CreateOperation : b . pathRoleCreateUpdate ,
logical . UpdateOperation : b . pathRoleCreateUpdate ,
logical . ReadOperation : b . pathRoleRead ,
logical . DeleteOperation : b . pathRoleDelete ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role" ] [ 1 ] ) ,
} ,
2018-04-23 14:51:55 +00:00
& framework . Path {
2018-04-23 20:52:09 +00:00
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/enable_local_secret_ids$" ,
2018-04-23 14:51:55 +00:00
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
2018-04-23 20:52:09 +00:00
"enable_local_secret_ids" : & framework . FieldSchema {
2018-04-23 14:51:55 +00:00
Type : framework . TypeBool ,
Description : `
2018-04-23 21:05:53 +00:00
If set , the secret IDs generated using this role will be cluster local . This
can only be set during role creation and once set , it can ' t be reset later . ` ,
2018-04-23 14:51:55 +00:00
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . ReadOperation : b . pathRoleLocalSecretIDsRead ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-local-secret-ids" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-local-secret-ids" ] [ 1 ] ) ,
} ,
2016-05-30 18:30:01 +00:00
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/policies$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"policies" : & framework . FieldSchema {
2017-08-15 00:15:51 +00:00
Type : framework . TypeCommaStringSlice ,
2016-05-30 18:30:01 +00:00
Default : "default" ,
Description : "Comma separated list of policies on the role." ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRolePoliciesUpdate ,
logical . ReadOperation : b . pathRolePoliciesRead ,
logical . DeleteOperation : b . pathRolePoliciesDelete ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-policies" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-policies" ] [ 1 ] ) ,
} ,
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/bound-cidr-list$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"bound_cidr_list" : & framework . FieldSchema {
2018-03-08 22:49:08 +00:00
Type : framework . TypeCommaStringSlice ,
Description : ` Comma separated string or list of CIDR blocks . If set , specifies the blocks of
IP addresses which can perform the login operation . ` ,
2016-05-30 18:30:01 +00:00
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRoleBoundCIDRListUpdate ,
logical . ReadOperation : b . pathRoleBoundCIDRListRead ,
logical . DeleteOperation : b . pathRoleBoundCIDRListDelete ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-bound-cidr-list" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-bound-cidr-list" ] [ 1 ] ) ,
} ,
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/bind-secret-id$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"bind_secret_id" : & framework . FieldSchema {
Type : framework . TypeBool ,
Default : true ,
Description : "Impose secret_id to be presented when logging in using this role." ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRoleBindSecretIDUpdate ,
logical . ReadOperation : b . pathRoleBindSecretIDRead ,
logical . DeleteOperation : b . pathRoleBindSecretIDDelete ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-bind-secret-id" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-bind-secret-id" ] [ 1 ] ) ,
} ,
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/secret-id-num-uses$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"secret_id_num_uses" : & framework . FieldSchema {
Type : framework . TypeInt ,
Description : "Number of times a SecretID can access the role, after which the SecretID will expire." ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRoleSecretIDNumUsesUpdate ,
logical . ReadOperation : b . pathRoleSecretIDNumUsesRead ,
logical . DeleteOperation : b . pathRoleSecretIDNumUsesDelete ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-secret-id-num-uses" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-secret-id-num-uses" ] [ 1 ] ) ,
} ,
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/secret-id-ttl$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"secret_id_ttl" : & framework . FieldSchema {
Type : framework . TypeDurationSecond ,
Description : ` Duration in seconds after which the issued SecretID should expire . Defaults
2016-11-15 16:50:51 +00:00
to 0 , meaning no expiration . ` ,
2016-05-30 18:30:01 +00:00
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRoleSecretIDTTLUpdate ,
logical . ReadOperation : b . pathRoleSecretIDTTLRead ,
logical . DeleteOperation : b . pathRoleSecretIDTTLDelete ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-secret-id-ttl" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-secret-id-ttl" ] [ 1 ] ) ,
} ,
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/period$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"period" : & framework . FieldSchema {
Type : framework . TypeDurationSecond ,
Default : 0 ,
Description : ` If set , indicates that the token generated using this role
should never expire . The token should be renewed within the
duration specified by this value . At each renewal , the token ' s
TTL will be set to the value of this parameter . ` ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRolePeriodUpdate ,
logical . ReadOperation : b . pathRolePeriodRead ,
logical . DeleteOperation : b . pathRolePeriodDelete ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-period" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-period" ] [ 1 ] ) ,
} ,
2017-03-03 14:31:20 +00:00
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/token-num-uses$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"token_num_uses" : & framework . FieldSchema {
Type : framework . TypeInt ,
Description : ` Number of times issued tokens can be used ` ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRoleTokenNumUsesUpdate ,
logical . ReadOperation : b . pathRoleTokenNumUsesRead ,
logical . DeleteOperation : b . pathRoleTokenNumUsesDelete ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-token-num-uses" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-token-num-uses" ] [ 1 ] ) ,
} ,
2016-05-30 18:30:01 +00:00
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/token-ttl$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"token_ttl" : & framework . FieldSchema {
Type : framework . TypeDurationSecond ,
Description : ` Duration in seconds after which the issued token should expire . Defaults
to 0 , in which case the value will fall back to the system / mount defaults . ` ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRoleTokenTTLUpdate ,
logical . ReadOperation : b . pathRoleTokenTTLRead ,
logical . DeleteOperation : b . pathRoleTokenTTLDelete ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-token-ttl" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-token-ttl" ] [ 1 ] ) ,
} ,
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/token-max-ttl$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"token_max_ttl" : & framework . FieldSchema {
Type : framework . TypeDurationSecond ,
Description : ` Duration in seconds after which the issued token should not be allowed to
be renewed . Defaults to 0 , in which case the value will fall back to the system / mount defaults . ` ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRoleTokenMaxTTLUpdate ,
logical . ReadOperation : b . pathRoleTokenMaxTTLRead ,
logical . DeleteOperation : b . pathRoleTokenMaxTTLDelete ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-token-max-ttl" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-token-max-ttl" ] [ 1 ] ) ,
} ,
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/role-id$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"role_id" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Identifier of the role. Defaults to a UUID." ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . ReadOperation : b . pathRoleRoleIDRead ,
logical . UpdateOperation : b . pathRoleRoleIDUpdate ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-id" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-id" ] [ 1 ] ) ,
} ,
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/secret-id/?$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"metadata" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : ` Metadata to be tied to the SecretID . This should be a JSON
formatted string containing the metadata in key value pairs . ` ,
} ,
2016-09-19 18:40:43 +00:00
"cidr_list" : & framework . FieldSchema {
2018-03-08 22:49:08 +00:00
Type : framework . TypeCommaStringSlice ,
Description : ` Comma separated string or list of CIDR blocks enforcing secret IDs to be used from
2016-09-19 18:40:43 +00:00
specific set of IP addresses . If ' bound_cidr_list ' is set on the role , then the
list of CIDR blocks listed here should be a subset of the CIDR blocks listed on
the role . ` ,
} ,
2016-05-30 18:30:01 +00:00
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRoleSecretIDUpdate ,
logical . ListOperation : b . pathRoleSecretIDList ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-secret-id" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-secret-id" ] [ 1 ] ) ,
} ,
& framework . Path {
2016-09-29 00:22:37 +00:00
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/secret-id/lookup/?$" ,
2016-08-21 18:42:49 +00:00
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"secret_id" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "SecretID attached to the role." ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
2016-09-29 00:22:37 +00:00
logical . UpdateOperation : b . pathRoleSecretIDLookupUpdate ,
2016-08-21 18:42:49 +00:00
} ,
2016-09-29 00:22:37 +00:00
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-secret-id-lookup" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-secret-id-lookup" ] [ 1 ] ) ,
2016-08-21 18:42:49 +00:00
} ,
& framework . Path {
2016-09-29 00:22:37 +00:00
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/secret-id/destroy/?$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"secret_id" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "SecretID attached to the role." ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRoleSecretIDDestroyUpdateDelete ,
logical . DeleteOperation : b . pathRoleSecretIDDestroyUpdateDelete ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-secret-id-destroy" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-secret-id-destroy" ] [ 1 ] ) ,
} ,
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/secret-id-accessor/lookup/?$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"secret_id_accessor" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Accessor of the SecretID" ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRoleSecretIDAccessorLookupUpdate ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-secret-id-accessor" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-secret-id-accessor" ] [ 1 ] ) ,
} ,
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/secret-id-accessor/destroy/?$" ,
2016-05-30 18:30:01 +00:00
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"secret_id_accessor" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Accessor of the SecretID" ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
2016-09-29 00:22:37 +00:00
logical . UpdateOperation : b . pathRoleSecretIDAccessorDestroyUpdateDelete ,
logical . DeleteOperation : b . pathRoleSecretIDAccessorDestroyUpdateDelete ,
2016-05-30 18:30:01 +00:00
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-secret-id-accessor" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-secret-id-accessor" ] [ 1 ] ) ,
} ,
& framework . Path {
Pattern : "role/" + framework . GenericNameRegex ( "role_name" ) + "/custom-secret-id$" ,
Fields : map [ string ] * framework . FieldSchema {
"role_name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
"secret_id" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "SecretID to be attached to the role." ,
} ,
"metadata" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : ` Metadata to be tied to the SecretID . This should be a JSON
formatted string containing metadata in key value pairs . ` ,
} ,
2016-09-19 18:40:43 +00:00
"cidr_list" : & framework . FieldSchema {
2018-03-08 22:49:08 +00:00
Type : framework . TypeCommaStringSlice ,
Description : ` Comma separated string or list of CIDR blocks enforcing secret IDs to be used from
2016-09-19 18:40:43 +00:00
specific set of IP addresses . If ' bound_cidr_list ' is set on the role , then the
list of CIDR blocks listed here should be a subset of the CIDR blocks listed on
the role . ` ,
} ,
2016-05-30 18:30:01 +00:00
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . UpdateOperation : b . pathRoleCustomSecretIDUpdate ,
} ,
HelpSynopsis : strings . TrimSpace ( roleHelp [ "role-custom-secret-id" ] [ 0 ] ) ,
HelpDescription : strings . TrimSpace ( roleHelp [ "role-custom-secret-id" ] [ 1 ] ) ,
} ,
}
}
// pathRoleExistenceCheck returns whether the role with the given name exists or not.
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleExistenceCheck ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( bool , error ) {
2017-11-10 16:32:04 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return false , fmt . Errorf ( "missing role_name" )
}
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return false , err
}
2017-11-10 16:32:04 +00:00
2016-05-30 18:30:01 +00:00
return role != nil , nil
}
// pathRoleList is used to list all the Roles registered with the backend.
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleList ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-08-26 23:34:32 +00:00
lock := b . roleLock ( "" )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
roles , err := req . Storage . List ( ctx , "role/" )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
return logical . ListResponse ( roles ) , nil
}
// pathRoleSecretIDList is used to list all the 'secret_id_accessor's issued against the role.
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleSecretIDList ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2016-05-30 18:30:01 +00:00
// Get the role entry
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
2017-11-10 16:32:04 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "role %q does not exist" , roleName ) ) , nil
2016-05-30 18:30:01 +00:00
}
2017-12-11 21:41:17 +00:00
if role . LowerCaseRoleName {
roleName = strings . ToLower ( roleName )
}
2017-02-01 23:13:49 +00:00
// Guard the list operation with an outer lock
b . secretIDListingLock . RLock ( )
defer b . secretIDListingLock . RUnlock ( )
2016-05-30 18:30:01 +00:00
roleNameHMAC , err := createHMAC ( role . HMACKey , roleName )
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to create HMAC of role_name: {{err}}" , err )
2016-05-30 18:30:01 +00:00
}
// Listing works one level at a time. Get the first level of data
// which could then be used to get the actual SecretID storage entries.
2018-04-23 14:51:55 +00:00
secretIDHMACs , err := req . Storage . List ( ctx , fmt . Sprintf ( "%s%s/" , role . SecretIDPrefix , roleNameHMAC ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
var listItems [ ] string
for _ , secretIDHMAC := range secretIDHMACs {
2017-02-01 23:13:49 +00:00
// For sanity
if secretIDHMAC == "" {
continue
}
2016-05-30 18:30:01 +00:00
// Prepare the full index of the SecretIDs.
2018-04-23 14:51:55 +00:00
entryIndex := fmt . Sprintf ( "%s%s/%s" , role . SecretIDPrefix , roleNameHMAC , secretIDHMAC )
2016-05-30 18:30:01 +00:00
// SecretID locks are not indexed by SecretIDs itself.
// This is because SecretIDs are not stored in plaintext
// form anywhere in the backend, and hence accessing its
// corresponding lock many times using SecretIDs is not
// possible. Also, indexing it everywhere using secretIDHMACs
// makes listing operation easier.
2017-02-01 23:13:49 +00:00
secretIDLock := b . secretIDLock ( secretIDHMAC )
secretIDLock . RLock ( )
2016-05-30 18:30:01 +00:00
result := secretIDStorageEntry { }
2018-01-19 06:44:44 +00:00
if entry , err := req . Storage . Get ( ctx , entryIndex ) ; err != nil {
2017-02-01 23:13:49 +00:00
secretIDLock . RUnlock ( )
2016-05-30 18:30:01 +00:00
return nil , err
} else if entry == nil {
2017-02-01 23:13:49 +00:00
secretIDLock . RUnlock ( )
2016-05-30 18:30:01 +00:00
return nil , fmt . Errorf ( "storage entry for SecretID is present but no content found at the index" )
} else if err := entry . DecodeJSON ( & result ) ; err != nil {
2017-02-01 23:13:49 +00:00
secretIDLock . RUnlock ( )
2016-05-30 18:30:01 +00:00
return nil , err
}
listItems = append ( listItems , result . SecretIDAccessor )
2017-02-01 23:13:49 +00:00
secretIDLock . RUnlock ( )
2016-05-30 18:30:01 +00:00
}
return logical . ListResponse ( listItems ) , nil
}
2016-09-13 22:30:04 +00:00
// validateRoleConstraints checks if the role has at least one constraint
2016-09-15 16:10:40 +00:00
// enabled.
2016-09-13 22:30:04 +00:00
func validateRoleConstraints ( role * roleStorageEntry ) error {
2016-09-15 16:10:40 +00:00
if role == nil {
return fmt . Errorf ( "nil role" )
}
2016-09-13 21:44:07 +00:00
// At least one constraint should be enabled on the role
switch {
case role . BindSecretID :
2018-03-08 22:49:08 +00:00
case len ( role . BoundCIDRList ) != 0 :
2016-09-13 21:44:07 +00:00
default :
2016-09-13 22:30:04 +00:00
return fmt . Errorf ( "at least one constraint should be enabled on the role" )
2016-09-13 21:44:07 +00:00
}
2016-09-13 22:30:04 +00:00
return nil
2016-09-13 21:44:07 +00:00
}
2017-11-10 16:32:04 +00:00
// setRoleEntry persists the role and creates an index from roleID to role
// name.
2018-01-19 06:44:44 +00:00
func ( b * backend ) setRoleEntry ( ctx context . Context , s logical . Storage , roleName string , role * roleStorageEntry , previousRoleID string ) error {
2016-09-13 20:03:15 +00:00
if roleName == "" {
return fmt . Errorf ( "missing role name" )
}
if role == nil {
return fmt . Errorf ( "nil role" )
}
2016-09-13 21:44:07 +00:00
// Check if role constraints are properly set
2016-09-13 22:30:04 +00:00
if err := validateRoleConstraints ( role ) ; err != nil {
2016-09-13 21:44:07 +00:00
return err
}
2016-09-13 20:03:15 +00:00
2016-05-30 18:30:01 +00:00
// Create a storage entry for the role
entry , err := logical . StorageEntryJSON ( "role/" + strings . ToLower ( roleName ) , role )
if err != nil {
return err
}
if entry == nil {
2017-11-10 16:32:04 +00:00
return fmt . Errorf ( "failed to create storage entry for role %q" , roleName )
2016-05-30 18:30:01 +00:00
}
// Check if the index from the role_id to role already exists
2018-01-19 06:44:44 +00:00
roleIDIndex , err := b . roleIDEntry ( ctx , s , role . RoleID )
2016-05-30 18:30:01 +00:00
if err != nil {
2018-04-05 15:49:21 +00:00
return errwrap . Wrapf ( "failed to read role_id index: {{err}}" , err )
2016-05-30 18:30:01 +00:00
}
// If the entry exists, make sure that it belongs to the current role
if roleIDIndex != nil && roleIDIndex . Name != roleName {
return fmt . Errorf ( "role_id already in use" )
}
// When role_id is getting updated, delete the old index before
// a new one is created
if previousRoleID != "" && previousRoleID != role . RoleID {
2018-01-19 06:44:44 +00:00
if err = b . roleIDEntryDelete ( ctx , s , previousRoleID ) ; err != nil {
2016-05-30 18:30:01 +00:00
return fmt . Errorf ( "failed to delete previous role ID index" )
}
}
// Save the role entry only after all the validations
2018-01-19 06:44:44 +00:00
if err = s . Put ( ctx , entry ) ; err != nil {
2016-05-30 18:30:01 +00:00
return err
}
2016-09-28 16:01:16 +00:00
// If previousRoleID is still intact, don't create another one
2016-10-14 16:56:29 +00:00
if previousRoleID != "" && previousRoleID == role . RoleID {
2016-09-28 16:01:16 +00:00
return nil
}
2016-05-30 18:30:01 +00:00
// Create a storage entry for reverse mapping of RoleID to role.
// Note that secondary index is created when the roleLock is held.
2018-01-19 06:44:44 +00:00
return b . setRoleIDEntry ( ctx , s , role . RoleID , & roleIDStorageEntry {
2016-05-30 18:30:01 +00:00
Name : roleName ,
} )
}
2017-11-10 16:32:04 +00:00
// roleEntry reads the role from storage
2018-01-19 06:44:44 +00:00
func ( b * backend ) roleEntry ( ctx context . Context , s logical . Storage , roleName string ) ( * roleStorageEntry , error ) {
2016-05-30 18:30:01 +00:00
if roleName == "" {
return nil , fmt . Errorf ( "missing role_name" )
}
2016-09-28 16:01:16 +00:00
var role roleStorageEntry
2016-05-30 18:30:01 +00:00
2018-01-19 06:44:44 +00:00
if entry , err := s . Get ( ctx , "role/" + strings . ToLower ( roleName ) ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
} else if entry == nil {
return nil , nil
2016-09-28 16:01:16 +00:00
} else if err := entry . DecodeJSON ( & role ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
}
2018-03-08 22:49:08 +00:00
needsUpgrade := false
if role . BoundCIDRListOld != "" {
role . BoundCIDRList = strings . Split ( role . BoundCIDRListOld , "," )
role . BoundCIDRListOld = ""
needsUpgrade = true
}
2018-04-23 20:31:47 +00:00
if role . SecretIDPrefix == "" {
role . SecretIDPrefix = secretIDPrefix
needsUpgrade = true
}
2018-03-08 22:49:08 +00:00
if needsUpgrade && ( b . System ( ) . LocalMount ( ) || ! b . System ( ) . ReplicationState ( ) . HasState ( consts . ReplicationPerformanceSecondary ) ) {
entry , err := logical . StorageEntryJSON ( "role/" + strings . ToLower ( roleName ) , & role )
if err != nil {
return nil , err
}
if err := s . Put ( ctx , entry ) ; err != nil {
// Only perform upgrades on replication primary
if ! strings . Contains ( err . Error ( ) , logical . ErrReadOnly . Error ( ) ) {
return nil , err
}
}
}
2016-09-28 16:01:16 +00:00
return & role , nil
2016-05-30 18:30:01 +00:00
}
// pathRoleCreateUpdate registers a new role with the backend or updates the options
// of an existing role
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleCreateUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2016-05-30 18:30:01 +00:00
// Check if the role already exists
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , roleName )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
// Create a new entry object if this is a CreateOperation
if role == nil && req . Operation == logical . CreateOperation {
hmacKey , err := uuid . GenerateUUID ( )
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to create role_id: {{err}}" , err )
2016-05-30 18:30:01 +00:00
}
role = & roleStorageEntry {
2017-12-11 21:41:17 +00:00
HMACKey : hmacKey ,
LowerCaseRoleName : true ,
2016-05-30 18:30:01 +00:00
}
} else if role == nil {
2018-04-24 14:05:17 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "role name %q doesn't exist" , roleName ) ) , nil
2016-05-30 18:30:01 +00:00
}
2018-04-23 20:52:09 +00:00
localSecretIDsRaw , ok := data . GetOk ( "enable_local_secret_ids" )
2018-04-23 21:05:53 +00:00
if ok {
if req . Operation == logical . CreateOperation {
localSecretIDs := localSecretIDsRaw . ( bool )
if localSecretIDs {
role . SecretIDPrefix = secretIDLocalPrefix
}
} else {
return logical . ErrorResponse ( "enable_local_secret_ids can only be modified during role creation" ) , nil
2018-04-23 14:51:55 +00:00
}
}
if role . SecretIDPrefix == "" {
role . SecretIDPrefix = secretIDPrefix
}
2016-05-30 18:30:01 +00:00
previousRoleID := role . RoleID
if roleIDRaw , ok := data . GetOk ( "role_id" ) ; ok {
role . RoleID = roleIDRaw . ( string )
} else if req . Operation == logical . CreateOperation {
roleID , err := uuid . GenerateUUID ( )
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to generate role_id: {{err}}" , err )
2016-05-30 18:30:01 +00:00
}
role . RoleID = roleID
}
if role . RoleID == "" {
2017-11-10 16:32:04 +00:00
return logical . ErrorResponse ( "invalid role_id supplied, or failed to generate a role_id" ) , nil
2016-05-30 18:30:01 +00:00
}
if bindSecretIDRaw , ok := data . GetOk ( "bind_secret_id" ) ; ok {
role . BindSecretID = bindSecretIDRaw . ( bool )
} else if req . Operation == logical . CreateOperation {
role . BindSecretID = data . Get ( "bind_secret_id" ) . ( bool )
}
if boundCIDRListRaw , ok := data . GetOk ( "bound_cidr_list" ) ; ok {
2018-03-08 22:49:08 +00:00
role . BoundCIDRList = boundCIDRListRaw . ( [ ] string )
2016-05-30 18:30:01 +00:00
} else if req . Operation == logical . CreateOperation {
2018-03-08 22:49:08 +00:00
role . BoundCIDRList = data . Get ( "bound_cidr_list" ) . ( [ ] string )
2016-05-30 18:30:01 +00:00
}
2016-09-21 19:44:54 +00:00
2018-03-08 22:49:08 +00:00
if len ( role . BoundCIDRList ) != 0 {
valid , err := cidrutil . ValidateCIDRListSlice ( role . BoundCIDRList )
2016-09-21 19:44:54 +00:00
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to validate CIDR blocks: {{err}}" , err )
2016-09-21 19:44:54 +00:00
}
if ! valid {
return logical . ErrorResponse ( "invalid CIDR blocks" ) , nil
}
2016-05-30 18:30:01 +00:00
}
if policiesRaw , ok := data . GetOk ( "policies" ) ; ok {
2017-08-15 00:15:51 +00:00
role . Policies = policyutil . ParsePolicies ( policiesRaw )
2016-05-30 18:30:01 +00:00
} else if req . Operation == logical . CreateOperation {
2017-08-15 00:15:51 +00:00
role . Policies = policyutil . ParsePolicies ( data . Get ( "policies" ) )
2016-05-30 18:30:01 +00:00
}
periodRaw , ok := data . GetOk ( "period" )
if ok {
role . Period = time . Second * time . Duration ( periodRaw . ( int ) )
} else if req . Operation == logical . CreateOperation {
role . Period = time . Second * time . Duration ( data . Get ( "period" ) . ( int ) )
}
if role . Period > b . System ( ) . MaxLeaseTTL ( ) {
2017-11-10 16:32:04 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "period of %q is greater than the backend's maximum lease TTL of %q" , role . Period . String ( ) , b . System ( ) . MaxLeaseTTL ( ) . String ( ) ) ) , nil
2016-05-30 18:30:01 +00:00
}
if secretIDNumUsesRaw , ok := data . GetOk ( "secret_id_num_uses" ) ; ok {
role . SecretIDNumUses = secretIDNumUsesRaw . ( int )
} else if req . Operation == logical . CreateOperation {
role . SecretIDNumUses = data . Get ( "secret_id_num_uses" ) . ( int )
}
if role . SecretIDNumUses < 0 {
return logical . ErrorResponse ( "secret_id_num_uses cannot be negative" ) , nil
}
if secretIDTTLRaw , ok := data . GetOk ( "secret_id_ttl" ) ; ok {
role . SecretIDTTL = time . Second * time . Duration ( secretIDTTLRaw . ( int ) )
} else if req . Operation == logical . CreateOperation {
role . SecretIDTTL = time . Second * time . Duration ( data . Get ( "secret_id_ttl" ) . ( int ) )
}
2017-03-03 14:31:20 +00:00
if tokenNumUsesRaw , ok := data . GetOk ( "token_num_uses" ) ; ok {
role . TokenNumUses = tokenNumUsesRaw . ( int )
} else if req . Operation == logical . CreateOperation {
role . TokenNumUses = data . Get ( "token_num_uses" ) . ( int )
}
if role . TokenNumUses < 0 {
return logical . ErrorResponse ( "token_num_uses cannot be negative" ) , nil
}
2016-05-30 18:30:01 +00:00
if tokenTTLRaw , ok := data . GetOk ( "token_ttl" ) ; ok {
role . TokenTTL = time . Second * time . Duration ( tokenTTLRaw . ( int ) )
} else if req . Operation == logical . CreateOperation {
role . TokenTTL = time . Second * time . Duration ( data . Get ( "token_ttl" ) . ( int ) )
}
if tokenMaxTTLRaw , ok := data . GetOk ( "token_max_ttl" ) ; ok {
role . TokenMaxTTL = time . Second * time . Duration ( tokenMaxTTLRaw . ( int ) )
} else if req . Operation == logical . CreateOperation {
role . TokenMaxTTL = time . Second * time . Duration ( data . Get ( "token_max_ttl" ) . ( int ) )
}
// Check that the TokenTTL value provided is less than the TokenMaxTTL.
// Sanitizing the TTL and MaxTTL is not required now and can be performed
// at credential issue time.
if role . TokenMaxTTL > time . Duration ( 0 ) && role . TokenTTL > role . TokenMaxTTL {
return logical . ErrorResponse ( "token_ttl should not be greater than token_max_ttl" ) , nil
}
var resp * logical . Response
if role . TokenMaxTTL > b . System ( ) . MaxLeaseTTL ( ) {
resp = & logical . Response { }
resp . AddWarning ( "token_max_ttl is greater than the backend mount's maximum TTL value; issued tokens' max TTL value will be truncated" )
}
// Store the entry.
2018-01-19 06:44:44 +00:00
return resp , b . setRoleEntry ( ctx , req . Storage , roleName , role , previousRoleID )
2016-05-30 18:30:01 +00:00
}
// pathRoleRead grabs a read lock and reads the options set on the role from the storage
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
lockRelease := lock . RUnlock
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2017-11-10 16:32:04 +00:00
if err != nil {
lockRelease ( )
2016-05-30 18:30:01 +00:00
return nil , err
2017-11-10 16:32:04 +00:00
}
if role == nil {
lockRelease ( )
2016-05-30 18:30:01 +00:00
return nil , nil
2017-11-10 16:32:04 +00:00
}
2016-05-30 18:30:01 +00:00
2017-11-10 16:32:04 +00:00
respData := map [ string ] interface { } {
2018-04-24 13:53:36 +00:00
"bind_secret_id" : role . BindSecretID ,
"bound_cidr_list" : role . BoundCIDRList ,
"period" : role . Period / time . Second ,
"policies" : role . Policies ,
"secret_id_num_uses" : role . SecretIDNumUses ,
"secret_id_ttl" : role . SecretIDTTL / time . Second ,
"token_max_ttl" : role . TokenMaxTTL / time . Second ,
"token_num_uses" : role . TokenNumUses ,
"token_ttl" : role . TokenTTL / time . Second ,
"enable_local_secret_ids" : false ,
}
if role . SecretIDPrefix == secretIDLocalPrefix {
respData [ "enable_local_secret_ids" ] = true
2017-11-10 16:32:04 +00:00
}
2016-05-30 18:30:01 +00:00
2017-11-10 16:32:04 +00:00
resp := & logical . Response {
Data : respData ,
}
if err := validateRoleConstraints ( role ) ; err != nil {
resp . AddWarning ( "Role does not have any constraints set on it. Updates to this role will require a constraint to be set" )
}
2016-09-13 21:44:07 +00:00
2017-11-10 16:32:04 +00:00
// For sanity, verify that the index still exists. If the index is missing,
// add one and return a warning so it can be reported.
2018-01-19 06:44:44 +00:00
roleIDIndex , err := b . roleIDEntry ( ctx , req . Storage , role . RoleID )
2017-11-10 16:32:04 +00:00
if err != nil {
lockRelease ( )
return nil , err
}
if roleIDIndex == nil {
// Switch to a write lock
lock . RUnlock ( )
lock . Lock ( )
lockRelease = lock . Unlock
// Check again if the index is missing
2018-01-19 06:44:44 +00:00
roleIDIndex , err = b . roleIDEntry ( ctx , req . Storage , role . RoleID )
2017-11-10 16:32:04 +00:00
if err != nil {
lockRelease ( )
return nil , err
2016-09-13 21:44:07 +00:00
}
2017-11-10 16:32:04 +00:00
if roleIDIndex == nil {
// Create a new index
2018-01-19 06:44:44 +00:00
err = b . setRoleIDEntry ( ctx , req . Storage , role . RoleID , & roleIDStorageEntry {
2017-11-10 16:32:04 +00:00
Name : roleName ,
} )
if err != nil {
lockRelease ( )
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( fmt . Sprintf ( "failed to create secondary index for role_id %q: {{err}}" , role . RoleID ) , err )
2017-11-10 16:32:04 +00:00
}
resp . AddWarning ( "Role identifier was missing an index back to role name. A new index has been added. Please report this observation." )
}
2016-05-30 18:30:01 +00:00
}
2017-11-10 16:32:04 +00:00
lockRelease ( )
return resp , nil
2016-05-30 18:30:01 +00:00
}
// pathRoleDelete removes the role from the storage
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleDelete ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
2016-09-26 13:55:08 +00:00
if role == nil {
return nil , nil
}
2016-05-30 18:30:01 +00:00
// Just before the role is deleted, remove all the SecretIDs issued as part of the role.
2018-04-23 14:51:55 +00:00
if err = b . flushRoleSecrets ( ctx , req . Storage , roleName , role . HMACKey , role . SecretIDPrefix ) ; err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( fmt . Sprintf ( "failed to invalidate the secrets belonging to role %q: {{err}}" , roleName ) , err )
2016-05-30 18:30:01 +00:00
}
// Delete the reverse mapping from RoleID to the role
2018-01-19 06:44:44 +00:00
if err = b . roleIDEntryDelete ( ctx , req . Storage , role . RoleID ) ; err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( fmt . Sprintf ( "failed to delete the mapping from RoleID to role %q: {{err}}" , roleName ) , err )
2016-05-30 18:30:01 +00:00
}
// After deleting the SecretIDs and the RoleID, delete the role itself
2018-01-19 06:44:44 +00:00
if err = req . Storage . Delete ( ctx , "role/" + strings . ToLower ( roleName ) ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
}
return nil , nil
}
2016-08-21 18:42:49 +00:00
// Returns the properties of the SecretID
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleSecretIDLookupUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-08-21 18:42:49 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
secretID := data . Get ( "secret_id" ) . ( string )
if secretID == "" {
return logical . ErrorResponse ( "missing secret_id" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2016-08-21 18:42:49 +00:00
// Fetch the role
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-08-21 18:42:49 +00:00
if err != nil {
return nil , err
}
if role == nil {
2017-11-10 16:32:04 +00:00
return nil , fmt . Errorf ( "role %q does not exist" , roleName )
2016-08-21 18:42:49 +00:00
}
2017-12-11 21:41:17 +00:00
if role . LowerCaseRoleName {
roleName = strings . ToLower ( roleName )
}
2016-08-21 18:42:49 +00:00
// Create the HMAC of the secret ID using the per-role HMAC key
secretIDHMAC , err := createHMAC ( role . HMACKey , secretID )
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to create HMAC of secret_id: {{err}}" , err )
2016-08-21 18:42:49 +00:00
}
// Create the HMAC of the roleName using the per-role HMAC key
roleNameHMAC , err := createHMAC ( role . HMACKey , roleName )
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to create HMAC of role_name: {{err}}" , err )
2016-08-21 18:42:49 +00:00
}
// Create the index at which the secret_id would've been stored
2018-04-23 14:51:55 +00:00
entryIndex := fmt . Sprintf ( "%s%s/%s" , role . SecretIDPrefix , roleNameHMAC , secretIDHMAC )
2016-08-21 18:42:49 +00:00
2018-01-19 06:44:44 +00:00
return b . secretIDCommon ( ctx , req . Storage , entryIndex , secretIDHMAC )
2016-08-21 19:46:11 +00:00
}
2018-01-19 06:44:44 +00:00
func ( b * backend ) secretIDCommon ( ctx context . Context , s logical . Storage , entryIndex , secretIDHMAC string ) ( * logical . Response , error ) {
2016-08-21 18:42:49 +00:00
lock := b . secretIDLock ( secretIDHMAC )
lock . RLock ( )
defer lock . RUnlock ( )
result := secretIDStorageEntry { }
2018-01-19 06:44:44 +00:00
if entry , err := s . Get ( ctx , entryIndex ) ; err != nil {
2016-08-21 18:42:49 +00:00
return nil , err
} else if entry == nil {
return nil , nil
} else if err := entry . DecodeJSON ( & result ) ; err != nil {
return nil , err
}
result . SecretIDTTL /= time . Second
d := structs . New ( result ) . Map ( )
// Converting the time values to RFC3339Nano format.
//
// Map() from 'structs' package formats time in RFC3339Nano.
// In order to not break the API due to a modification in the
// third party package, converting the time values again.
2016-09-23 16:32:07 +00:00
d [ "creation_time" ] = result . CreationTime . Format ( time . RFC3339Nano )
d [ "expiration_time" ] = result . ExpirationTime . Format ( time . RFC3339Nano )
d [ "last_updated_time" ] = result . LastUpdatedTime . Format ( time . RFC3339Nano )
2016-08-21 18:42:49 +00:00
2016-09-28 18:20:03 +00:00
resp := & logical . Response {
2016-08-21 18:42:49 +00:00
Data : d ,
2016-09-28 18:20:03 +00:00
}
if _ , ok := d [ "SecretIDNumUses" ] ; ok {
2016-09-28 19:24:19 +00:00
resp . AddWarning ( "The field SecretIDNumUses is deprecated and will be removed in a future release; refer to secret_id_num_uses instead" )
2016-09-28 18:20:03 +00:00
}
return resp , nil
2016-08-21 18:42:49 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleSecretIDDestroyUpdateDelete ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-08-21 18:42:49 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
secretID := data . Get ( "secret_id" ) . ( string )
if secretID == "" {
return logical . ErrorResponse ( "missing secret_id" ) , nil
}
2017-11-10 16:32:04 +00:00
roleLock := b . roleLock ( roleName )
roleLock . RLock ( )
defer roleLock . RUnlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-08-21 18:42:49 +00:00
if err != nil {
return nil , err
}
if role == nil {
2017-11-10 16:32:04 +00:00
return nil , fmt . Errorf ( "role %q does not exist" , roleName )
2016-08-21 18:42:49 +00:00
}
secretIDHMAC , err := createHMAC ( role . HMACKey , secretID )
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to create HMAC of secret_id: {{err}}" , err )
2016-08-21 18:42:49 +00:00
}
roleNameHMAC , err := createHMAC ( role . HMACKey , roleName )
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to create HMAC of role_name: {{err}}" , err )
2016-08-21 18:42:49 +00:00
}
2018-04-23 14:51:55 +00:00
entryIndex := fmt . Sprintf ( "%s%s/%s" , role . SecretIDPrefix , roleNameHMAC , secretIDHMAC )
2016-08-21 18:42:49 +00:00
lock := b . secretIDLock ( secretIDHMAC )
lock . Lock ( )
defer lock . Unlock ( )
result := secretIDStorageEntry { }
2018-01-19 06:44:44 +00:00
if entry , err := req . Storage . Get ( ctx , entryIndex ) ; err != nil {
2016-08-21 18:42:49 +00:00
return nil , err
} else if entry == nil {
return nil , nil
} else if err := entry . DecodeJSON ( & result ) ; err != nil {
return nil , err
}
// Delete the accessor of the SecretID first
2018-04-23 20:19:05 +00:00
if err := b . deleteSecretIDAccessorEntry ( ctx , req . Storage , result . SecretIDAccessor , role . SecretIDPrefix ) ; err != nil {
2016-09-15 21:49:14 +00:00
return nil , err
2016-08-21 18:42:49 +00:00
}
// Delete the storage entry that corresponds to the SecretID
2018-01-19 06:44:44 +00:00
if err := req . Storage . Delete ( ctx , entryIndex ) ; err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to delete secret_id: {{err}}" , err )
2016-08-21 18:42:49 +00:00
}
return nil , nil
}
2016-09-29 00:22:37 +00:00
// pathRoleSecretIDAccessorLookupUpdate returns the properties of the SecretID
// given its accessor
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleSecretIDAccessorLookupUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
secretIDAccessor := data . Get ( "secret_id_accessor" ) . ( string )
if secretIDAccessor == "" {
return logical . ErrorResponse ( "missing secret_id_accessor" ) , nil
}
// SecretID is indexed based on HMACed roleName and HMACed SecretID.
// Get the role details to fetch the RoleID and accessor to get
// the HMACed SecretID.
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
2017-11-10 16:32:04 +00:00
return nil , fmt . Errorf ( "role %q does not exist" , roleName )
2016-05-30 18:30:01 +00:00
}
2018-04-23 20:19:05 +00:00
accessorEntry , err := b . secretIDAccessorEntry ( ctx , req . Storage , secretIDAccessor , role . SecretIDPrefix )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if accessorEntry == nil {
2018-04-05 15:49:21 +00:00
return nil , fmt . Errorf ( "failed to find accessor entry for secret_id_accessor: %q" , secretIDAccessor )
2016-05-30 18:30:01 +00:00
}
roleNameHMAC , err := createHMAC ( role . HMACKey , roleName )
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to create HMAC of role_name: {{err}}" , err )
2016-05-30 18:30:01 +00:00
}
2018-04-23 14:51:55 +00:00
entryIndex := fmt . Sprintf ( "%s%s/%s" , role . SecretIDPrefix , roleNameHMAC , accessorEntry . SecretIDHMAC )
2016-05-30 18:30:01 +00:00
2018-01-19 06:44:44 +00:00
return b . secretIDCommon ( ctx , req . Storage , entryIndex , accessorEntry . SecretIDHMAC )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleSecretIDAccessorDestroyUpdateDelete ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
secretIDAccessor := data . Get ( "secret_id_accessor" ) . ( string )
if secretIDAccessor == "" {
return logical . ErrorResponse ( "missing secret_id_accessor" ) , nil
}
// SecretID is indexed based on HMACed roleName and HMACed SecretID.
// Get the role details to fetch the RoleID and accessor to get
// the HMACed SecretID.
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
2017-11-10 16:32:04 +00:00
return nil , fmt . Errorf ( "role %q does not exist" , roleName )
2016-05-30 18:30:01 +00:00
}
2018-04-23 20:19:05 +00:00
accessorEntry , err := b . secretIDAccessorEntry ( ctx , req . Storage , secretIDAccessor , role . SecretIDPrefix )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if accessorEntry == nil {
2018-04-05 15:49:21 +00:00
return nil , fmt . Errorf ( "failed to find accessor entry for secret_id_accessor: %q" , secretIDAccessor )
2016-05-30 18:30:01 +00:00
}
roleNameHMAC , err := createHMAC ( role . HMACKey , roleName )
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to create HMAC of role_name: {{err}}" , err )
2016-05-30 18:30:01 +00:00
}
2018-04-23 14:51:55 +00:00
entryIndex := fmt . Sprintf ( "%s%s/%s" , role . SecretIDPrefix , roleNameHMAC , accessorEntry . SecretIDHMAC )
2016-05-30 18:30:01 +00:00
lock := b . secretIDLock ( accessorEntry . SecretIDHMAC )
lock . Lock ( )
defer lock . Unlock ( )
// Delete the accessor of the SecretID first
2018-04-23 20:19:05 +00:00
if err := b . deleteSecretIDAccessorEntry ( ctx , req . Storage , secretIDAccessor , role . SecretIDPrefix ) ; err != nil {
2016-09-15 21:49:14 +00:00
return nil , err
2016-05-30 18:30:01 +00:00
}
// Delete the storage entry that corresponds to the SecretID
2018-01-19 06:44:44 +00:00
if err := req . Storage . Delete ( ctx , entryIndex ) ; err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to delete secret_id: {{err}}" , err )
2016-05-30 18:30:01 +00:00
}
return nil , nil
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleBoundCIDRListUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
// Re-read the role after grabbing the lock
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
2018-03-08 22:49:08 +00:00
role . BoundCIDRList = data . Get ( "bound_cidr_list" ) . ( [ ] string )
if len ( role . BoundCIDRList ) == 0 {
2016-05-30 18:30:01 +00:00
return logical . ErrorResponse ( "missing bound_cidr_list" ) , nil
}
2018-03-08 22:49:08 +00:00
valid , err := cidrutil . ValidateCIDRListSlice ( role . BoundCIDRList )
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to validate CIDR blocks: {{err}}" , err )
2018-03-08 22:49:08 +00:00
}
if ! valid {
return logical . ErrorResponse ( "failed to validate CIDR blocks" ) , nil
2016-05-30 18:30:01 +00:00
}
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleBoundCIDRListRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
if role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
} else if role == nil {
return nil , nil
} else {
return & logical . Response {
Data : map [ string ] interface { } {
"bound_cidr_list" : role . BoundCIDRList ,
} ,
} , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleBoundCIDRListDelete ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
// Deleting a field implies setting the value to it's default value.
2018-03-08 22:49:08 +00:00
role . BoundCIDRList = data . GetDefaultOrZero ( "bound_cidr_list" ) . ( [ ] string )
2016-05-30 18:30:01 +00:00
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleBindSecretIDUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
if bindSecretIDRaw , ok := data . GetOk ( "bind_secret_id" ) ; ok {
role . BindSecretID = bindSecretIDRaw . ( bool )
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
} else {
return logical . ErrorResponse ( "missing bind_secret_id" ) , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleBindSecretIDRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
if role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
} else if role == nil {
return nil , nil
} else {
return & logical . Response {
Data : map [ string ] interface { } {
"bind_secret_id" : role . BindSecretID ,
} ,
} , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleBindSecretIDDelete ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
// Deleting a field implies setting the value to it's default value.
role . BindSecretID = data . GetDefaultOrZero ( "bind_secret_id" ) . ( bool )
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
}
2018-04-23 14:51:55 +00:00
func ( b * backend ) pathRoleLocalSecretIDsRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
if role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) ) ; err != nil {
return nil , err
} else if role == nil {
return nil , nil
} else {
localSecretIDs := false
if role . SecretIDPrefix == secretIDLocalPrefix {
localSecretIDs = true
}
return & logical . Response {
Data : map [ string ] interface { } {
2018-04-23 20:52:09 +00:00
"enable_local_secret_ids" : localSecretIDs ,
2018-04-23 14:51:55 +00:00
} ,
} , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRolePoliciesUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
2017-08-15 00:15:51 +00:00
policiesRaw , ok := data . GetOk ( "policies" )
if ! ok {
2016-05-30 18:30:01 +00:00
return logical . ErrorResponse ( "missing policies" ) , nil
}
2017-08-15 00:15:51 +00:00
role . Policies = policyutil . ParsePolicies ( policiesRaw )
2016-05-30 18:30:01 +00:00
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRolePoliciesRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
if role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
} else if role == nil {
return nil , nil
} else {
return & logical . Response {
Data : map [ string ] interface { } {
"policies" : role . Policies ,
} ,
} , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRolePoliciesDelete ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
2017-09-13 15:36:52 +00:00
role . Policies = [ ] string { }
2016-05-30 18:30:01 +00:00
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleSecretIDNumUsesUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
if numUsesRaw , ok := data . GetOk ( "secret_id_num_uses" ) ; ok {
role . SecretIDNumUses = numUsesRaw . ( int )
if role . SecretIDNumUses < 0 {
return logical . ErrorResponse ( "secret_id_num_uses cannot be negative" ) , nil
}
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
} else {
return logical . ErrorResponse ( "missing secret_id_num_uses" ) , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleRoleIDUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
previousRoleID := role . RoleID
role . RoleID = data . Get ( "role_id" ) . ( string )
if role . RoleID == "" {
return logical . ErrorResponse ( "missing role_id" ) , nil
}
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , previousRoleID )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleRoleIDRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
if role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
} else if role == nil {
return nil , nil
} else {
return & logical . Response {
Data : map [ string ] interface { } {
"role_id" : role . RoleID ,
} ,
} , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleSecretIDNumUsesRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
if role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
} else if role == nil {
return nil , nil
} else {
return & logical . Response {
Data : map [ string ] interface { } {
"secret_id_num_uses" : role . SecretIDNumUses ,
} ,
} , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleSecretIDNumUsesDelete ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
role . SecretIDNumUses = data . GetDefaultOrZero ( "secret_id_num_uses" ) . ( int )
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleSecretIDTTLUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
if secretIDTTLRaw , ok := data . GetOk ( "secret_id_ttl" ) ; ok {
role . SecretIDTTL = time . Second * time . Duration ( secretIDTTLRaw . ( int ) )
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
} else {
return logical . ErrorResponse ( "missing secret_id_ttl" ) , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleSecretIDTTLRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
if role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
} else if role == nil {
return nil , nil
} else {
role . SecretIDTTL /= time . Second
return & logical . Response {
Data : map [ string ] interface { } {
"secret_id_ttl" : role . SecretIDTTL ,
} ,
} , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleSecretIDTTLDelete ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
role . SecretIDTTL = time . Second * time . Duration ( data . GetDefaultOrZero ( "secret_id_ttl" ) . ( int ) )
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRolePeriodUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
if periodRaw , ok := data . GetOk ( "period" ) ; ok {
role . Period = time . Second * time . Duration ( periodRaw . ( int ) )
if role . Period > b . System ( ) . MaxLeaseTTL ( ) {
2017-11-10 16:32:04 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "period of %q is greater than the backend's maximum lease TTL of %q" , role . Period . String ( ) , b . System ( ) . MaxLeaseTTL ( ) . String ( ) ) ) , nil
2016-05-30 18:30:01 +00:00
}
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
} else {
return logical . ErrorResponse ( "missing period" ) , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRolePeriodRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
if role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
} else if role == nil {
return nil , nil
} else {
role . Period /= time . Second
return & logical . Response {
Data : map [ string ] interface { } {
"period" : role . Period ,
} ,
} , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRolePeriodDelete ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
role . Period = time . Second * time . Duration ( data . GetDefaultOrZero ( "period" ) . ( int ) )
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleTokenNumUsesUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2017-03-03 14:31:20 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2017-03-03 14:31:20 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
if tokenNumUsesRaw , ok := data . GetOk ( "token_num_uses" ) ; ok {
role . TokenNumUses = tokenNumUsesRaw . ( int )
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2017-03-03 14:31:20 +00:00
} else {
return logical . ErrorResponse ( "missing token_num_uses" ) , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleTokenNumUsesRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2017-03-03 14:31:20 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
if role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) ) ; err != nil {
2017-03-03 14:31:20 +00:00
return nil , err
} else if role == nil {
return nil , nil
} else {
return & logical . Response {
Data : map [ string ] interface { } {
"token_num_uses" : role . TokenNumUses ,
} ,
} , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleTokenNumUsesDelete ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2017-03-03 14:31:20 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2017-03-03 14:31:20 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
role . TokenNumUses = data . GetDefaultOrZero ( "token_num_uses" ) . ( int )
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2017-03-03 14:31:20 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleTokenTTLUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
if tokenTTLRaw , ok := data . GetOk ( "token_ttl" ) ; ok {
role . TokenTTL = time . Second * time . Duration ( tokenTTLRaw . ( int ) )
if role . TokenMaxTTL > time . Duration ( 0 ) && role . TokenTTL > role . TokenMaxTTL {
return logical . ErrorResponse ( "token_ttl should not be greater than token_max_ttl" ) , nil
}
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
} else {
return logical . ErrorResponse ( "missing token_ttl" ) , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleTokenTTLRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
if role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
} else if role == nil {
return nil , nil
} else {
role . TokenTTL /= time . Second
return & logical . Response {
Data : map [ string ] interface { } {
"token_ttl" : role . TokenTTL ,
} ,
} , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleTokenTTLDelete ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
role . TokenTTL = time . Second * time . Duration ( data . GetDefaultOrZero ( "token_ttl" ) . ( int ) )
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleTokenMaxTTLUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
if tokenMaxTTLRaw , ok := data . GetOk ( "token_max_ttl" ) ; ok {
role . TokenMaxTTL = time . Second * time . Duration ( tokenMaxTTLRaw . ( int ) )
if role . TokenMaxTTL > time . Duration ( 0 ) && role . TokenTTL > role . TokenMaxTTL {
return logical . ErrorResponse ( "token_max_ttl should be greater than or equal to token_ttl" ) , nil
}
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
} else {
return logical . ErrorResponse ( "missing token_max_ttl" ) , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleTokenMaxTTLRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
if role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
} else if role == nil {
return nil , nil
} else {
role . TokenMaxTTL /= time . Second
return & logical . Response {
Data : map [ string ] interface { } {
"token_max_ttl" : role . TokenMaxTTL ,
} ,
} , nil
}
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleTokenMaxTTLDelete ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . Lock ( )
defer lock . Unlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
return nil , nil
}
role . TokenMaxTTL = time . Second * time . Duration ( data . GetDefaultOrZero ( "token_max_ttl" ) . ( int ) )
2018-01-19 06:44:44 +00:00
return nil , b . setRoleEntry ( ctx , req . Storage , roleName , role , "" )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleSecretIDUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
secretID , err := uuid . GenerateUUID ( )
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to generate secret_id: {{err}}" , err )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
return b . handleRoleSecretIDCommon ( ctx , req , data , secretID )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleCustomSecretIDUpdate ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
return b . handleRoleSecretIDCommon ( ctx , req , data , data . Get ( "secret_id" ) . ( string ) )
2016-05-30 18:30:01 +00:00
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) handleRoleSecretIDCommon ( ctx context . Context , req * logical . Request , data * framework . FieldData , secretID string ) ( * logical . Response , error ) {
2016-05-30 18:30:01 +00:00
roleName := data . Get ( "role_name" ) . ( string )
if roleName == "" {
return logical . ErrorResponse ( "missing role_name" ) , nil
}
if secretID == "" {
return logical . ErrorResponse ( "missing secret_id" ) , nil
}
2017-11-10 16:32:04 +00:00
lock := b . roleLock ( roleName )
lock . RLock ( )
defer lock . RUnlock ( )
2018-01-19 06:44:44 +00:00
role , err := b . roleEntry ( ctx , req . Storage , strings . ToLower ( roleName ) )
2016-05-30 18:30:01 +00:00
if err != nil {
return nil , err
}
if role == nil {
2017-11-10 16:32:04 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "role %q does not exist" , roleName ) ) , nil
2016-05-30 18:30:01 +00:00
}
if ! role . BindSecretID {
return logical . ErrorResponse ( "bind_secret_id is not set on the role" ) , nil
}
2018-03-08 22:49:08 +00:00
secretIDCIDRs := data . Get ( "cidr_list" ) . ( [ ] string )
2016-09-19 18:40:43 +00:00
// Validate the list of CIDR blocks
2018-03-08 22:49:08 +00:00
if len ( secretIDCIDRs ) != 0 {
valid , err := cidrutil . ValidateCIDRListSlice ( secretIDCIDRs )
2016-09-21 19:44:54 +00:00
if err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to validate CIDR blocks: {{err}}" , err )
2016-09-21 19:44:54 +00:00
}
if ! valid {
return logical . ErrorResponse ( "failed to validate CIDR blocks" ) , nil
}
2016-09-19 18:40:43 +00:00
}
2016-09-21 23:41:08 +00:00
// Ensure that the CIDRs on the secret ID are a subset of that of role's
if err := verifyCIDRRoleSecretIDSubset ( secretIDCIDRs , role . BoundCIDRList ) ; err != nil {
return nil , err
2016-09-19 18:40:43 +00:00
}
2016-05-30 18:30:01 +00:00
secretIDStorage := & secretIDStorageEntry {
SecretIDNumUses : role . SecretIDNumUses ,
SecretIDTTL : role . SecretIDTTL ,
Metadata : make ( map [ string ] string ) ,
2016-09-21 23:41:08 +00:00
CIDRList : secretIDCIDRs ,
2016-05-30 18:30:01 +00:00
}
2016-08-03 18:18:22 +00:00
if err = strutil . ParseArbitraryKeyValues ( data . Get ( "metadata" ) . ( string ) , secretIDStorage . Metadata , "," ) ; err != nil {
2016-05-30 18:30:01 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "failed to parse metadata: %v" , err ) ) , nil
}
2017-12-11 21:41:17 +00:00
if role . LowerCaseRoleName {
roleName = strings . ToLower ( roleName )
}
2018-04-23 14:51:55 +00:00
if secretIDStorage , err = b . registerSecretIDEntry ( ctx , req . Storage , roleName , secretID , role . HMACKey , role . SecretIDPrefix , secretIDStorage ) ; err != nil {
2018-04-05 15:49:21 +00:00
return nil , errwrap . Wrapf ( "failed to store secret_id: {{err}}" , err )
2016-05-30 18:30:01 +00:00
}
2016-09-28 18:20:03 +00:00
return & logical . Response {
2016-05-30 18:30:01 +00:00
Data : map [ string ] interface { } {
"secret_id" : secretID ,
"secret_id_accessor" : secretIDStorage . SecretIDAccessor ,
} ,
2016-09-28 18:20:03 +00:00
} , nil
2016-05-30 18:30:01 +00:00
}
2017-03-07 16:21:32 +00:00
func ( b * backend ) roleIDLock ( roleID string ) * locksutil . LockEntry {
return locksutil . LockForKey ( b . roleIDLocks , roleID )
2016-05-30 18:30:01 +00:00
}
2017-03-07 16:21:32 +00:00
func ( b * backend ) roleLock ( roleName string ) * locksutil . LockEntry {
return locksutil . LockForKey ( b . roleLocks , roleName )
2016-08-26 23:34:32 +00:00
}
2016-05-30 18:30:01 +00:00
// setRoleIDEntry creates a storage entry that maps RoleID to Role
2018-01-19 06:44:44 +00:00
func ( b * backend ) setRoleIDEntry ( ctx context . Context , s logical . Storage , roleID string , roleIDEntry * roleIDStorageEntry ) error {
2016-05-30 18:30:01 +00:00
lock := b . roleIDLock ( roleID )
lock . Lock ( )
defer lock . Unlock ( )
2018-03-08 19:21:11 +00:00
salt , err := b . Salt ( ctx )
2017-05-09 21:51:09 +00:00
if err != nil {
return err
}
entryIndex := "role_id/" + salt . SaltID ( roleID )
2016-05-30 18:30:01 +00:00
entry , err := logical . StorageEntryJSON ( entryIndex , roleIDEntry )
if err != nil {
return err
}
2018-01-19 06:44:44 +00:00
if err = s . Put ( ctx , entry ) ; err != nil {
2016-05-30 18:30:01 +00:00
return err
}
return nil
}
// roleIDEntry is used to read the storage entry that maps RoleID to Role
2018-01-19 06:44:44 +00:00
func ( b * backend ) roleIDEntry ( ctx context . Context , s logical . Storage , roleID string ) ( * roleIDStorageEntry , error ) {
2016-05-30 18:30:01 +00:00
if roleID == "" {
2018-04-05 15:49:21 +00:00
return nil , fmt . Errorf ( "missing role id" )
2016-05-30 18:30:01 +00:00
}
lock := b . roleIDLock ( roleID )
lock . RLock ( )
defer lock . RUnlock ( )
var result roleIDStorageEntry
2018-03-08 19:21:11 +00:00
salt , err := b . Salt ( ctx )
2017-05-09 21:51:09 +00:00
if err != nil {
return nil , err
}
entryIndex := "role_id/" + salt . SaltID ( roleID )
2016-05-30 18:30:01 +00:00
2018-01-19 06:44:44 +00:00
if entry , err := s . Get ( ctx , entryIndex ) ; err != nil {
2016-05-30 18:30:01 +00:00
return nil , err
} else if entry == nil {
return nil , nil
} else if err := entry . DecodeJSON ( & result ) ; err != nil {
return nil , err
}
return & result , nil
}
// roleIDEntryDelete is used to remove the secondary index that maps the
// RoleID to the Role itself.
2018-01-19 06:44:44 +00:00
func ( b * backend ) roleIDEntryDelete ( ctx context . Context , s logical . Storage , roleID string ) error {
2016-05-30 18:30:01 +00:00
if roleID == "" {
2018-04-05 15:49:21 +00:00
return fmt . Errorf ( "missing role id" )
2016-05-30 18:30:01 +00:00
}
lock := b . roleIDLock ( roleID )
lock . Lock ( )
defer lock . Unlock ( )
2018-03-08 19:21:11 +00:00
salt , err := b . Salt ( ctx )
2017-05-09 21:51:09 +00:00
if err != nil {
return err
}
entryIndex := "role_id/" + salt . SaltID ( roleID )
2016-05-30 18:30:01 +00:00
2018-01-19 06:44:44 +00:00
return s . Delete ( ctx , entryIndex )
2016-05-30 18:30:01 +00:00
}
var roleHelp = map [ string ] [ 2 ] string {
"role-list" : {
"Lists all the roles registered with the backend." ,
"The list will contain the names of the roles." ,
} ,
"role" : {
"Register an role with the backend." ,
` A role can represent a service , a machine or anything that can be IDed .
The set of policies on the role defines access to the role , meaning , any
Vault token with a policy set that is a superset of the policies on the
role registered here will have access to the role . If a SecretID is desired
to be generated against only this specific role , it can be done via
' role / < role_name > / secret - id ' and ' role / < role_name > / custom - secret - id ' endpoints .
The properties of the SecretID created against the role and the properties
2018-01-03 18:56:14 +00:00
of the token issued with the SecretID generated against the role , can be
2016-05-30 18:30:01 +00:00
configured using the parameters of this endpoint . ` ,
} ,
"role-bind-secret-id" : {
"Impose secret_id to be presented during login using this role." ,
` By setting this to ' true ' , during login the parameter ' secret_id ' becomes a mandatory argument .
The value of ' secret_id ' can be retrieved using ' role / < role_name > / secret - id ' endpoint . ` ,
} ,
"role-bound-cidr-list" : {
` Comma separated list of CIDR blocks , if set , specifies blocks of IP
addresses which can perform the login operation ` ,
` During login , the IP address of the client will be checked to see if it
belongs to the CIDR blocks specified . If CIDR blocks were set and if the
IP is not encompassed by it , login fails ` ,
} ,
"role-policies" : {
"Policies of the role." ,
` A comma - delimited set of Vault policies that defines access to the role .
All the Vault tokens with policies that encompass the policy set
defined on the role , can access the role . ` ,
} ,
"role-secret-id-num-uses" : {
"Use limit of the SecretID generated against the role." ,
` If the SecretIDs are generated / assigned against the role using the
' role / < role_name > / secret - id ' or ' role / < role_name > / custom - secret - id ' endpoints ,
then the number of times that SecretID can access the role is defined by
this option . ` ,
} ,
"role-secret-id-ttl" : {
` Duration in seconds , representing the lifetime of the SecretIDs
that are generated against the role using ' role / < role_name > / secret - id ' or
' role / < role_name > / custom - secret - id ' endpoints . ` ,
` ` ,
} ,
2016-09-29 00:22:37 +00:00
"role-secret-id-lookup" : {
"Read the properties of an issued secret_id" ,
` This endpoint is used to read the properties of a secret_id associated to a
role . ` } ,
"role-secret-id-destroy" : {
"Invalidate an issued secret_id" ,
` This endpoint is used to delete the properties of a secret_id associated to a
role . ` } ,
"role-secret-id-accessor-lookup" : {
"Read an issued secret_id, using its accessor" ,
` This is particularly useful to lookup the non - expiring ' secret_id ' s .
The list operation on the ' role / < role_name > / secret - id ' endpoint will return
the ' secret_id_accessor ' s . This endpoint can be used to read the properties
of the secret . If the ' secret_id_num_uses ' field in the response is 0 , it
represents a non - expiring ' secret_id ' . ` ,
2016-08-21 18:42:49 +00:00
} ,
2016-09-29 00:22:37 +00:00
"role-secret-id-accessor-destroy" : {
"Delete an issued secret_id, using its accessor" ,
2016-05-30 18:30:01 +00:00
` This is particularly useful to clean - up the non - expiring ' secret_id ' s .
The list operation on the ' role / < role_name > / secret - id ' endpoint will return
the ' secret_id_accessor ' s . This endpoint can be used to read the properties
of the secret . If the ' secret_id_num_uses ' field in the response is 0 , it
2016-09-29 00:22:37 +00:00
represents a non - expiring ' secret_id ' . ` ,
2017-03-03 14:31:20 +00:00
} ,
"role-token-num-uses" : {
"Number of times issued tokens can be used" ,
` By default , this will be set to zero , indicating that the issued
tokens can be used any number of times . ` ,
2016-05-30 18:30:01 +00:00
} ,
"role-token-ttl" : {
` Duration in seconds , the lifetime of the token issued by using the SecretID that
is generated against this role , before which the token needs to be renewed . ` ,
` If SecretIDs are generated against the role , using ' role / < role_name > / secret - id ' or the
' role / < role_name > / custom - secret - id ' endpoints , and if those SecretIDs are used
to perform the login operation , then the value of ' token - ttl ' defines the
lifetime of the token issued , before which the token needs to be renewed . ` ,
} ,
"role-token-max-ttl" : {
` Duration in seconds , the maximum lifetime of the tokens issued by using
the SecretIDs that were generated against this role , after which the
tokens are not allowed to be renewed . ` ,
` If SecretIDs are generated against the role using ' role / < role_name > / secret - id '
or the ' role / < role_name > / custom - secret - id ' endpoints , and if those SecretIDs
are used to perform the login operation , then the value of ' token - max - ttl '
defines the maximum lifetime of the tokens issued , after which the tokens
cannot be renewed . A reauthentication is required after this duration .
2017-04-04 16:29:18 +00:00
This value will be capped by the backend mount ' s maximum TTL value . ` ,
2016-05-30 18:30:01 +00:00
} ,
"role-id" : {
"Returns the 'role_id' of the role." ,
` If login is performed from an role , then its ' role_id ' should be presented
as a credential during the login . This ' role_id ' can be retrieved using
this endpoint . ` ,
} ,
"role-secret-id" : {
"Generate a SecretID against this role." ,
` The SecretID generated using this endpoint will be scoped to access
just this role and none else . The properties of this SecretID will be
based on the options set on the role . It will expire after a period
defined by the ' secret_id_ttl ' option on the role and / or the backend
mount ' s maximum TTL value . ` ,
} ,
"role-custom-secret-id" : {
"Assign a SecretID of choice against the role." ,
` This option is not recommended unless there is a specific need
to do so . This will assign a client supplied SecretID to be used to access
the role . This SecretID will behave similarly to the SecretIDs generated by
the backend . The properties of this SecretID will be based on the options
set on the role . It will expire after a period defined by the ' secret_id_ttl '
option on the role and / or the backend mount ' s maximum TTL value . ` ,
} ,
"role-period" : {
"Updates the value of 'period' on the role" ,
` If set , indicates that the token generated using this role
should never expire . The token should be renewed within the
duration specified by this value . The renewal duration will
be fixed . If the Period in the role is modified , the token
will pick up the new value during its next renewal . ` ,
} ,
2018-04-23 14:51:55 +00:00
"role-local-secret-ids" : {
2018-04-23 20:52:09 +00:00
"Enables cluster local secret IDs" ,
2018-04-23 14:51:55 +00:00
` If set , indicates that the secret IDs generated using this role should be
cluster local . This can only be set during role creation and once set , it can ' t
be reset later . ` ,
} ,
2016-05-30 18:30:01 +00:00
}