open-vault/logical/request.go

280 lines
9.7 KiB
Go
Raw Normal View History

package logical
import (
"errors"
"fmt"
2017-10-23 20:42:56 +00:00
"strings"
"time"
)
2017-01-04 21:44:03 +00:00
// RequestWrapInfo is a struct that stores information about desired response
// and seal wrapping behavior
2017-01-04 21:44:03 +00:00
type RequestWrapInfo struct {
// Setting to non-zero specifies that the response should be wrapped.
// Specifies the desired TTL of the wrapping token.
2017-10-23 20:42:56 +00:00
TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl" sentinel:""`
2017-01-04 21:44:03 +00:00
// The format to use for the wrapped response; if not specified it's a bare
// token
2017-10-23 20:42:56 +00:00
Format string `json:"format" structs:"format" mapstructure:"format" sentinel:""`
// A flag to conforming backends that data for a given request should be
// seal wrapped
SealWrap bool `json:"seal_wrap" structs:"seal_wrap" mapstructure:"seal_wrap" sentinel:""`
2017-01-04 21:44:03 +00:00
}
2017-10-23 20:42:56 +00:00
func (r *RequestWrapInfo) SentinelGet(key string) (interface{}, error) {
if r == nil {
return nil, nil
}
switch key {
case "ttl":
return r.TTL, nil
case "ttl_seconds":
return int64(r.TTL.Seconds()), nil
}
return nil, nil
}
2017-11-13 20:31:32 +00:00
func (r *RequestWrapInfo) SentinelKeys() []string {
return []string{
"ttl",
"ttl_seconds",
}
}
2017-10-23 20:42:56 +00:00
// Request is a struct that stores the parameters and context of a request
// being made to Vault. It is used to abstract the details of the higher level
// request protocol from the handlers.
//
// Note: Many of these have Sentinel disabled because they are values populated
// by the router after policy checks; the token namespace would be the right
// place to access them via Sentinel
type Request struct {
2016-07-24 01:46:28 +00:00
// Id is the uuid associated with each request
2017-10-23 20:42:56 +00:00
ID string `json:"id" structs:"id" mapstructure:"id" sentinel:""`
2016-07-24 01:46:28 +00:00
// If set, the name given to the replication secondary where this request
// originated
2017-10-23 20:42:56 +00:00
ReplicationCluster string `json:"replication_cluster" structs:"replication_cluster" mapstructure:"replication_cluster" sentinel:""`
// Operation is the requested operation type
2016-07-24 01:46:28 +00:00
Operation Operation `json:"operation" structs:"operation" mapstructure:"operation"`
// Path is the part of the request path not consumed by the
// routing. As an example, if the original request path is "prod/aws/foo"
// and the AWS logical backend is mounted at "prod/aws/", then the
// final path is "foo" since the mount prefix is trimmed.
2017-10-23 20:42:56 +00:00
Path string `json:"path" structs:"path" mapstructure:"path" sentinel:""`
// Request data is an opaque map that must have string keys.
2016-07-24 01:46:28 +00:00
Data map[string]interface{} `json:"map" structs:"data" mapstructure:"data"`
// Storage can be used to durably store and retrieve state.
2017-10-23 20:42:56 +00:00
Storage Storage `json:"-" sentinel:""`
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
// Secret will be non-nil only for Revoke and Renew operations
// to represent the secret that was returned prior.
2017-10-23 20:42:56 +00:00
Secret *Secret `json:"secret" structs:"secret" mapstructure:"secret" sentinel:""`
2015-03-24 18:09:25 +00:00
// Auth will be non-nil only for Renew operations
// to represent the auth that was returned prior.
2017-10-23 20:42:56 +00:00
Auth *Auth `json:"auth" structs:"auth" mapstructure:"auth" sentinel:""`
// Headers will contain the http headers from the request. This value will
// be used in the audit broker to ensure we are auditing only the allowed
// headers.
2017-10-23 20:42:56 +00:00
Headers map[string][]string `json:"headers" structs:"headers" mapstructure:"headers" sentinel:""`
// Connection will be non-nil only for credential providers to
// inspect the connection information and potentially use it for
// authentication/protection.
2016-07-24 01:46:28 +00:00
Connection *Connection `json:"connection" structs:"connection" mapstructure:"connection"`
2015-03-24 18:09:25 +00:00
// ClientToken is provided to the core so that the identity
// can be verified and ACLs applied. This value is passed
// through to the logical backends but after being salted and
// hashed.
2017-10-23 20:42:56 +00:00
ClientToken string `json:"client_token" structs:"client_token" mapstructure:"client_token" sentinel:""`
// ClientTokenAccessor is provided to the core so that the it can get
// logged as part of request audit logging.
2017-10-23 20:42:56 +00:00
ClientTokenAccessor string `json:"client_token_accessor" structs:"client_token_accessor" mapstructure:"client_token_accessor" sentinel:""`
// DisplayName is provided to the logical backend to help associate
// dynamic secrets with the source entity. This is not a sensitive
// name, but is useful for operators.
2017-10-23 20:42:56 +00:00
DisplayName string `json:"display_name" structs:"display_name" mapstructure:"display_name" sentinel:""`
// MountPoint is provided so that a logical backend can generate
// paths relative to itself. The `Path` is effectively the client
// request path with the MountPoint trimmed off.
2017-10-23 20:42:56 +00:00
MountPoint string `json:"mount_point" structs:"mount_point" mapstructure:"mount_point" sentinel:""`
Create unified aws auth backend (#2441) * Rename builtin/credential/aws-ec2 to aws The aws-ec2 authentication backend is being expanded and will become the generic aws backend. This is a small rename commit to keep the commit history clean. * Expand aws-ec2 backend to more generic aws This adds the ability to authenticate arbitrary AWS IAM principals using AWS's sts:GetCallerIdentity method. The AWS-EC2 auth backend is being to just AWS with the expansion. * Add missing aws auth handler to CLI This was omitted from the previous commit * aws auth backend general variable name cleanup Also fixed a bug where allowed auth types weren't being checked upon login, and added tests for it. * Update docs for the aws auth backend * Refactor aws bind validation * Fix env var override in aws backend test Intent is to override the AWS environment variables with the TEST_* versions if they are set, but the reverse was happening. * Update docs on use of IAM authentication profile AWS now allows you to change the instance profile of a running instance, so the use case of "a long-lived instance that's not in an instance profile" no longer means you have to use the the EC2 auth method. You can now just change the instance profile on the fly. * Fix typo in aws auth cli help * Respond to PR feedback * More PR feedback * Respond to additional PR feedback * Address more feedback on aws auth PR * Make aws auth_type immutable per role * Address more aws auth PR feedback * Address more iam auth PR feedback * Rename aws-ec2.html.md to aws.html.md Per PR feedback, to go along with new backend name. * Add MountType to logical.Request * Make default aws auth_type dependent upon MountType When MountType is aws-ec2, default to ec2 auth_type for backwards compatibility with legacy roles. Otherwise, default to iam. * Pass MountPoint and MountType back up to the core Previously the request router reset the MountPoint and MountType back to the empty string before returning to the core. This ensures they get set back to the correct values.
2017-04-24 19:15:50 +00:00
// MountType is provided so that a logical backend can make decisions
// based on the specific mount type (e.g., if a mount type has different
// aliases, generating different defaults depending on the alias)
2017-10-23 20:42:56 +00:00
MountType string `json:"mount_type" structs:"mount_type" mapstructure:"mount_type" sentinel:""`
Create unified aws auth backend (#2441) * Rename builtin/credential/aws-ec2 to aws The aws-ec2 authentication backend is being expanded and will become the generic aws backend. This is a small rename commit to keep the commit history clean. * Expand aws-ec2 backend to more generic aws This adds the ability to authenticate arbitrary AWS IAM principals using AWS's sts:GetCallerIdentity method. The AWS-EC2 auth backend is being to just AWS with the expansion. * Add missing aws auth handler to CLI This was omitted from the previous commit * aws auth backend general variable name cleanup Also fixed a bug where allowed auth types weren't being checked upon login, and added tests for it. * Update docs for the aws auth backend * Refactor aws bind validation * Fix env var override in aws backend test Intent is to override the AWS environment variables with the TEST_* versions if they are set, but the reverse was happening. * Update docs on use of IAM authentication profile AWS now allows you to change the instance profile of a running instance, so the use case of "a long-lived instance that's not in an instance profile" no longer means you have to use the the EC2 auth method. You can now just change the instance profile on the fly. * Fix typo in aws auth cli help * Respond to PR feedback * More PR feedback * Respond to additional PR feedback * Address more feedback on aws auth PR * Make aws auth_type immutable per role * Address more aws auth PR feedback * Address more iam auth PR feedback * Rename aws-ec2.html.md to aws.html.md Per PR feedback, to go along with new backend name. * Add MountType to logical.Request * Make default aws auth_type dependent upon MountType When MountType is aws-ec2, default to ec2 auth_type for backwards compatibility with legacy roles. Otherwise, default to iam. * Pass MountPoint and MountType back up to the core Previously the request router reset the MountPoint and MountType back to the empty string before returning to the core. This ensures they get set back to the correct values.
2017-04-24 19:15:50 +00:00
// MountAccessor is provided so that identities returned by the authentication
// backends can be tied to the mount it belongs to.
2017-10-23 20:42:56 +00:00
MountAccessor string `json:"mount_accessor" structs:"mount_accessor" mapstructure:"mount_accessor" sentinel:""`
2017-01-04 21:44:03 +00:00
// WrapInfo contains requested response wrapping parameters
2017-10-23 20:42:56 +00:00
WrapInfo *RequestWrapInfo `json:"wrap_info" structs:"wrap_info" mapstructure:"wrap_info" sentinel:""`
2017-03-01 17:39:42 +00:00
2017-03-09 01:05:23 +00:00
// ClientTokenRemainingUses represents the allowed number of uses left on the
// token supplied
ClientTokenRemainingUses int `json:"client_token_remaining_uses" structs:"client_token_remaining_uses" mapstructure:"client_token_remaining_uses"`
// EntityID is the identity of the caller extracted out of the token used
// to make this request
2017-10-23 20:42:56 +00:00
EntityID string `json:"entity_id" structs:"entity_id" mapstructure:"entity_id" sentinel:""`
// PolicyOverride indicates that the requestor wishes to override
// soft-mandatory Sentinel policies
PolicyOverride bool `json:"policy_override" structs:"policy_override" mapstructure:"policy_override"`
// Whether the request is unauthenticated, as in, had no client token
// attached. Useful in some situations where the client token is not made
// accessible.
Unauthenticated bool `json:"unauthenticated" structs:"unauthenticated" mapstructure:"unauthenticated"`
2017-03-01 17:39:42 +00:00
// For replication, contains the last WAL on the remote side after handling
// the request, used for best-effort avoidance of stale read-after-write
2017-10-23 20:42:56 +00:00
lastRemoteWAL uint64 `sentinel:""`
}
// Get returns a data field and guards for nil Data
func (r *Request) Get(key string) interface{} {
if r.Data == nil {
return nil
}
return r.Data[key]
}
// GetString returns a data field as a string
func (r *Request) GetString(key string) string {
raw := r.Get(key)
s, _ := raw.(string)
return s
}
func (r *Request) GoString() string {
return fmt.Sprintf("*%#v", *r)
}
2017-10-23 20:42:56 +00:00
func (r *Request) SentinelGet(key string) (interface{}, error) {
switch key {
case "path":
// Sanitize it here so that it's consistent in policies
return strings.TrimPrefix(r.Path, "/"), nil
case "wrapping", "wrap_info":
// If the pointer is nil accessing the wrap info is considered
// "undefined" so this allows us to instead discover a TTL of zero
if r.WrapInfo == nil {
return &RequestWrapInfo{}, nil
}
return r.WrapInfo, nil
}
return nil, nil
}
2017-11-13 20:31:32 +00:00
func (r *Request) SentinelKeys() []string {
return []string{
"path",
"wrapping",
"wrap_info",
}
}
2017-03-01 17:39:42 +00:00
func (r *Request) LastRemoteWAL() uint64 {
return r.lastRemoteWAL
}
func (r *Request) SetLastRemoteWAL(last uint64) {
r.lastRemoteWAL = last
}
2015-03-19 19:20:25 +00:00
// RenewRequest creates the structure of the renew request.
func RenewRequest(path string, secret *Secret, data map[string]interface{}) *Request {
2015-03-19 19:20:25 +00:00
return &Request{
Operation: RenewOperation,
Path: path,
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Data: data,
Secret: secret,
2015-03-19 19:20:25 +00:00
}
}
// RenewAuthRequest creates the structure of the renew request for an auth.
func RenewAuthRequest(path string, auth *Auth, data map[string]interface{}) *Request {
return &Request{
Operation: RenewOperation,
Path: path,
Data: data,
Auth: auth,
}
}
2015-03-19 19:20:25 +00:00
// RevokeRequest creates the structure of the revoke request.
func RevokeRequest(path string, secret *Secret, data map[string]interface{}) *Request {
2015-03-19 19:20:25 +00:00
return &Request{
Operation: RevokeOperation,
Path: path,
vault: clean up VaultID duplications, make secret responses clearer /cc @armon - This is a reasonably major refactor that I think cleans up a lot of the logic with secrets in responses. The reason for the refactor is that while implementing Renew/Revoke in logical/framework I found the existing API to be really awkward to work with. Primarily, we needed a way to send down internal data for Vault core to store since not all the data you need to revoke a key is always sent down to the user (for example the user than AWS key belongs to). At first, I was doing this manually in logical/framework with req.Storage, but this is going to be such a common event that I think its something core should assist with. Additionally, I think the added context for secrets will be useful in the future when we have a Vault API for returning orphaned out keys: we can also return the internal data that might help an operator. So this leads me to this refactor. I've removed most of the fields in `logical.Response` and replaced it with a single `*Secret` pointer. If this is non-nil, then the response represents a secret. The Secret struct encapsulates all the lease info and such. It also has some fields on it that are only populated at _request_ time for Revoke/Renew operations. There is precedent for this sort of behavior in the Go stdlib where http.Request/http.Response have fields that differ based on client/server. I copied this style. All core unit tests pass. The APIs fail for obvious reasons but I'll fix that up in the next commit.
2015-03-19 22:11:42 +00:00
Data: data,
Secret: secret,
2015-03-19 19:20:25 +00:00
}
}
// RollbackRequest creates the structure of the revoke request.
func RollbackRequest(path string) *Request {
return &Request{
Operation: RollbackOperation,
Path: path,
Data: make(map[string]interface{}),
}
}
// Operation is an enum that is used to specify the type
// of request being made
type Operation string
const (
2015-03-19 18:41:41 +00:00
// The operations below are called per path
CreateOperation Operation = "create"
ReadOperation = "read"
UpdateOperation = "update"
DeleteOperation = "delete"
ListOperation = "list"
HelpOperation = "help"
AliasLookaheadOperation = "alias-lookahead"
2015-03-19 18:41:41 +00:00
// The operations below are called globally, the path is less relevant.
RevokeOperation Operation = "revoke"
RenewOperation = "renew"
RollbackOperation = "rollback"
)
var (
// ErrUnsupportedOperation is returned if the operation is not supported
// by the logical backend.
ErrUnsupportedOperation = errors.New("unsupported operation")
// ErrUnsupportedPath is returned if the path is not supported
// by the logical backend.
ErrUnsupportedPath = errors.New("unsupported path")
// ErrInvalidRequest is returned if the request is invalid
ErrInvalidRequest = errors.New("invalid request")
2015-08-09 19:20:06 +00:00
// ErrPermissionDenied is returned if the client is not authorized
ErrPermissionDenied = errors.New("permission denied")
2017-11-13 20:31:32 +00:00
// ErrMultiAuthzPending is returned if the the request needs more
// authorizations
ErrMultiAuthzPending = errors.New("request needs further approval")
)