2017-04-24 19:15:50 +00:00
package awsauth
2016-05-03 16:14:07 +00:00
import (
2018-01-08 18:31:38 +00:00
"context"
2019-06-20 14:31:31 +00:00
"errors"
2016-05-03 16:14:07 +00:00
"fmt"
"strings"
"time"
2019-01-09 00:48:57 +00:00
uuid "github.com/hashicorp/go-uuid"
2019-04-13 07:44:06 +00:00
"github.com/hashicorp/vault/sdk/framework"
2019-04-12 21:54:35 +00:00
"github.com/hashicorp/vault/sdk/helper/consts"
2019-07-01 20:29:34 +00:00
"github.com/hashicorp/vault/sdk/helper/tokenutil"
2019-04-12 21:54:35 +00:00
"github.com/hashicorp/vault/sdk/logical"
2019-06-20 14:31:31 +00:00
"github.com/mitchellh/copystructure"
2016-05-03 16:14:07 +00:00
)
2021-04-08 16:43:39 +00:00
var currentRoleStorageVersion = 3
2018-03-02 16:09:14 +00:00
2019-07-31 23:11:35 +00:00
func ( b * backend ) pathRole ( ) * framework . Path {
2019-07-01 20:29:34 +00:00
p := & framework . Path {
2016-05-13 18:31:13 +00:00
Pattern : "role/" + framework . GenericNameRegex ( "role" ) ,
2016-05-03 16:14:07 +00:00
Fields : map [ string ] * framework . FieldSchema {
2016-08-09 21:29:45 +00:00
"role" : {
2016-05-03 16:14:07 +00:00
Type : framework . TypeString ,
Description : "Name of the role." ,
} ,
2017-04-24 19:15:50 +00:00
"auth_type" : {
Type : framework . TypeString ,
Description : ` The auth_type permitted to authenticate to this role . Must be one of
iam or ec2 and cannot be changed after role creation . ` ,
} ,
2016-08-09 21:29:45 +00:00
"bound_ami_id" : {
2018-03-02 16:09:14 +00:00
Type : framework . TypeCommaStringSlice ,
2016-05-12 11:19:29 +00:00
Description : ` If set , defines a constraint on the EC2 instances that they should be
2018-03-02 16:09:14 +00:00
using one of the AMI IDs specified by this parameter . This is only applicable
when auth_type is ec2 or inferred_entity_type is ec2_instance . ` ,
2016-05-03 16:14:07 +00:00
} ,
2016-08-09 21:29:45 +00:00
"bound_account_id" : {
2018-03-02 16:09:14 +00:00
Type : framework . TypeCommaStringSlice ,
2016-06-14 15:58:19 +00:00
Description : ` If set , defines a constraint on the EC2 instances that the account ID
2018-03-02 16:09:14 +00:00
in its identity document to match one of the IDs specified by this parameter .
This is only applicable when auth_type is ec2 or inferred_entity_type is
ec2_instance . ` ,
2017-04-24 19:15:50 +00:00
} ,
"bound_iam_principal_arn" : {
2018-03-02 16:09:14 +00:00
Type : framework . TypeCommaStringSlice ,
Description : ` ARN of the IAM principals to bind to this role . Only applicable when
2017-04-24 19:15:50 +00:00
auth_type is iam . ` ,
2016-09-23 16:47:35 +00:00
} ,
2017-02-24 19:19:10 +00:00
"bound_region" : {
2018-03-02 16:09:14 +00:00
Type : framework . TypeCommaStringSlice ,
2017-04-24 19:15:50 +00:00
Description : ` If set , defines a constraint on the EC2 instances that the region in
2018-03-02 16:09:14 +00:00
its identity document match one of the regions specified by this parameter . This is only
2017-10-23 14:53:09 +00:00
applicable when auth_type is ec2 . ` ,
2017-02-24 19:19:10 +00:00
} ,
2016-09-23 16:47:35 +00:00
"bound_iam_role_arn" : {
2018-03-02 16:09:14 +00:00
Type : framework . TypeCommaStringSlice ,
2016-09-28 22:30:32 +00:00
Description : ` If set , defines a constraint on the authenticating EC2 instance
2018-03-02 16:09:14 +00:00
that it must match one of the IAM role ARNs specified by this parameter .
2016-09-28 22:30:32 +00:00
The value is prefix - matched ( as though it were a glob ending in
'*' ) . The configured IAM user or EC2 instance role must be allowed
2017-10-23 14:53:09 +00:00
to execute the ' iam : GetInstanceProfile ' action if this is specified . This is
only applicable when auth_type is ec2 or inferred_entity_type is
ec2_instance . ` ,
2016-06-14 15:58:19 +00:00
} ,
2016-09-23 15:22:23 +00:00
"bound_iam_instance_profile_arn" : {
2018-03-02 16:09:14 +00:00
Type : framework . TypeCommaStringSlice ,
2016-09-28 22:30:32 +00:00
Description : ` If set , defines a constraint on the EC2 instances to be associated
with an IAM instance profile ARN which has a prefix that matches
2018-03-02 16:09:14 +00:00
one of the values specified by this parameter . The value is prefix - matched
2017-10-23 14:53:09 +00:00
( as though it were a glob ending in '*' ) . This is only applicable when
auth_type is ec2 or inferred_entity_type is ec2_instance . ` ,
2018-03-15 16:19:28 +00:00
} ,
"bound_ec2_instance_id" : {
Type : framework . TypeCommaStringSlice ,
Description : ` If set , defines a constraint on the EC2 instances to have one of the
given instance IDs . Can be a list or comma - separated string of EC2 instance
IDs . This is only applicable when auth_type is ec2 or inferred_entity_type is
ec2_instance . ` ,
2017-06-07 14:27:11 +00:00
} ,
"resolve_aws_unique_ids" : {
Type : framework . TypeBool ,
Default : true ,
Description : ` If set , resolve all AWS IAM ARNs into AWS ' s internal unique IDs .
When an IAM entity ( e . g . , user , role , or instance profile ) is deleted , then all references
to it within the role will be invalidated , which prevents a new IAM entity from being created
with the same name and matching the role ' s IAM binds . Once set , this cannot be unset . ` ,
2017-04-24 19:15:50 +00:00
} ,
"inferred_entity_type" : {
Type : framework . TypeString ,
Description : ` When auth_type is iam , the
AWS entity type to infer from the authenticated principal . The only supported
value is ec2_instance , which will extract the EC2 instance ID from the
authenticated role and apply the following restrictions specific to EC2
instances : bound_ami_id , bound_account_id , bound_iam_role_arn ,
bound_iam_instance_profile_arn , bound_vpc_id , bound_subnet_id . The configured
EC2 client must be able to find the inferred instance ID in the results , and the
instance must be running . If unable to determine the EC2 instance ID or unable
to find the EC2 instance ID among running instances , then authentication will
fail . ` ,
} ,
"inferred_aws_region" : {
Type : framework . TypeString ,
Description : ` When auth_type is iam and
inferred_entity_type is set , the region to assume the inferred entity exists in . ` ,
2017-02-24 19:19:10 +00:00
} ,
"bound_vpc_id" : {
2018-03-02 16:09:14 +00:00
Type : framework . TypeCommaStringSlice ,
2017-02-24 19:19:10 +00:00
Description : `
2018-03-02 16:09:14 +00:00
If set , defines a constraint on the EC2 instance to be associated with a VPC
ID that matches one of the value specified by this parameter . This is only
applicable when auth_type is ec2 or inferred_entity_type is ec2_instance . ` ,
2017-02-24 19:19:10 +00:00
} ,
"bound_subnet_id" : {
2018-03-02 16:09:14 +00:00
Type : framework . TypeCommaStringSlice ,
2017-02-24 19:19:10 +00:00
Description : `
If set , defines a constraint on the EC2 instance to be associated with the
2018-03-02 16:09:14 +00:00
subnet ID that matches one of the values specified by this parameter . This is
only applicable when auth_type is ec2 or inferred_entity_type is
ec2_instance . ` ,
2016-06-14 14:49:36 +00:00
} ,
2016-08-09 21:29:45 +00:00
"role_tag" : {
2017-04-24 19:15:50 +00:00
Type : framework . TypeString ,
Default : "" ,
Description : ` If set , enables the role tags for this role . The value set for this
field should be the ' key ' of the tag on the EC2 instance . The ' value '
of the tag should be generated using ' role / < role > / tag ' endpoint .
Defaults to an empty string , meaning that role tags are disabled . This
is only allowed if auth_type is ec2 . ` ,
2016-05-03 16:14:07 +00:00
} ,
2019-07-31 23:11:35 +00:00
"period" : {
2019-07-01 20:29:34 +00:00
Type : framework . TypeDurationSecond ,
Description : tokenutil . DeprecationText ( "token_period" ) ,
Deprecated : true ,
2017-02-02 18:28:01 +00:00
} ,
2016-08-09 21:29:45 +00:00
"ttl" : {
2019-07-01 20:29:34 +00:00
Type : framework . TypeDurationSecond ,
Description : tokenutil . DeprecationText ( "token_ttl" ) ,
Deprecated : true ,
2016-08-09 21:29:45 +00:00
} ,
"max_ttl" : {
2016-05-03 16:14:07 +00:00
Type : framework . TypeDurationSecond ,
2019-07-01 20:29:34 +00:00
Description : tokenutil . DeprecationText ( "token_max_ttl" ) ,
Deprecated : true ,
2016-05-03 16:14:07 +00:00
} ,
2016-08-09 21:29:45 +00:00
"policies" : {
2017-09-13 15:36:52 +00:00
Type : framework . TypeCommaStringSlice ,
2019-07-01 20:29:34 +00:00
Description : tokenutil . DeprecationText ( "token_policies" ) ,
Deprecated : true ,
2016-05-03 16:14:07 +00:00
} ,
2016-08-09 21:29:45 +00:00
"allow_instance_migration" : {
2017-04-24 19:15:50 +00:00
Type : framework . TypeBool ,
Default : false ,
Description : ` If set , allows migration of the underlying instance where the client
resides . This keys off of pendingTime in the metadata document , so
essentially , this disables the client nonce check whenever the
instance is migrated to a new host and pendingTime is newer than the
previously - remembered time . Use with caution . This is only checked when
auth_type is ec2 . ` ,
2016-05-03 16:14:07 +00:00
} ,
2016-08-09 21:29:45 +00:00
"disallow_reauthentication" : {
2017-10-23 14:53:09 +00:00
Type : framework . TypeBool ,
Default : false ,
Description : ` If set , only allows a single token to be granted per
2021-02-26 07:23:34 +00:00
instance ID . In order to perform a fresh login , the entry in the access list
2017-10-23 14:53:09 +00:00
for the instance ID needs to be cleared using
2021-02-26 07:23:34 +00:00
' auth / aws - ec2 / identity - accesslist / < instance_id > ' endpoint . This is only
2017-10-23 14:53:09 +00:00
applicable when auth_type is ec2 . ` ,
2016-05-03 16:14:07 +00:00
} ,
} ,
ExistenceCheck : b . pathRoleExistenceCheck ,
2019-07-31 23:11:35 +00:00
Operations : map [ logical . Operation ] framework . OperationHandler {
logical . CreateOperation : & framework . PathOperation {
Callback : b . pathRoleCreateUpdate ,
} ,
logical . UpdateOperation : & framework . PathOperation {
Callback : b . pathRoleCreateUpdate ,
} ,
logical . ReadOperation : & framework . PathOperation {
Callback : b . pathRoleRead ,
} ,
logical . DeleteOperation : & framework . PathOperation {
Callback : b . pathRoleDelete ,
} ,
2016-05-03 16:14:07 +00:00
} ,
HelpSynopsis : pathRoleSyn ,
HelpDescription : pathRoleDesc ,
}
2019-07-01 20:29:34 +00:00
tokenutil . AddTokenFields ( p . Fields )
return p
2016-05-03 16:14:07 +00:00
}
2019-07-31 23:11:35 +00:00
func ( b * backend ) pathListRole ( ) * framework . Path {
2016-05-05 18:51:09 +00:00
return & framework . Path {
Pattern : "role/?" ,
2019-07-31 23:11:35 +00:00
Operations : map [ logical . Operation ] framework . OperationHandler {
logical . ListOperation : & framework . PathOperation {
Callback : b . pathRoleList ,
} ,
2016-05-05 18:51:09 +00:00
} ,
HelpSynopsis : pathListRolesHelpSyn ,
HelpDescription : pathListRolesHelpDesc ,
}
}
2019-07-31 23:11:35 +00:00
func ( b * backend ) pathListRoles ( ) * framework . Path {
2016-05-03 16:14:07 +00:00
return & framework . Path {
Pattern : "roles/?" ,
2019-07-31 23:11:35 +00:00
Operations : map [ logical . Operation ] framework . OperationHandler {
logical . ListOperation : & framework . PathOperation {
Callback : b . pathRoleList ,
} ,
2016-05-03 16:14:07 +00:00
} ,
HelpSynopsis : pathListRolesHelpSyn ,
HelpDescription : pathListRolesHelpDesc ,
}
}
// Establishes dichotomy of request operation between CreateOperation and UpdateOperation.
// Returning 'true' forces an UpdateOperation, CreateOperation otherwise.
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleExistenceCheck ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( bool , error ) {
2019-06-20 14:31:31 +00:00
entry , err := b . role ( ctx , req . Storage , strings . ToLower ( data . Get ( "role" ) . ( string ) ) )
2016-05-03 16:14:07 +00:00
if err != nil {
return false , err
}
return entry != nil , nil
}
2019-06-20 14:31:31 +00:00
// role fetches the role entry from cache, or loads from disk if necessary
func ( b * backend ) role ( ctx context . Context , s logical . Storage , roleName string ) ( * awsRoleEntry , error ) {
2016-09-23 15:22:23 +00:00
if roleName == "" {
return nil , fmt . Errorf ( "missing role name" )
}
2019-06-20 14:31:31 +00:00
roleEntryRaw , found := b . roleCache . Get ( roleName )
if found && roleEntryRaw != nil {
roleEntry , ok := roleEntryRaw . ( * awsRoleEntry )
if ! ok {
return nil , errors . New ( "could not convert role entry internally" )
}
if roleEntry == nil {
return nil , errors . New ( "converted role entry is nil" )
}
}
// Not found, or was nil
b . roleMutex . Lock ( )
defer b . roleMutex . Unlock ( )
return b . roleInternal ( ctx , s , roleName )
}
// roleInternal does not perform locking, and rechecks the cache, going to disk if necessar
func ( b * backend ) roleInternal ( ctx context . Context , s logical . Storage , roleName string ) ( * awsRoleEntry , error ) {
// Check cache again now that we have the lock
roleEntryRaw , found := b . roleCache . Get ( roleName )
if found && roleEntryRaw != nil {
roleEntry , ok := roleEntryRaw . ( * awsRoleEntry )
if ! ok {
return nil , errors . New ( "could not convert role entry internally" )
}
if roleEntry == nil {
return nil , errors . New ( "converted role entry is nil" )
}
}
// Fetch from storage
entry , err := s . Get ( ctx , "role/" + strings . ToLower ( roleName ) )
2017-04-24 19:15:50 +00:00
if err != nil {
return nil , err
}
2019-06-20 14:31:31 +00:00
if entry == nil {
2017-04-24 19:15:50 +00:00
return nil , nil
}
2019-06-20 14:31:31 +00:00
result := new ( awsRoleEntry )
if err := entry . DecodeJSON ( result ) ; err != nil {
return nil , err
}
needUpgrade , err := b . upgradeRole ( ctx , s , result )
2017-04-24 19:15:50 +00:00
if err != nil {
2021-04-22 15:20:59 +00:00
return nil , fmt . Errorf ( "error upgrading roleEntry: %w" , err )
2017-04-24 19:15:50 +00:00
}
2019-02-01 21:56:57 +00:00
if needUpgrade && ( b . System ( ) . LocalMount ( ) || ! b . System ( ) . ReplicationState ( ) . HasState ( consts . ReplicationPerformanceSecondary | consts . ReplicationPerformanceStandby ) ) {
2019-06-20 14:31:31 +00:00
if err = b . setRole ( ctx , s , roleName , result ) ; err != nil {
2021-04-22 15:20:59 +00:00
return nil , fmt . Errorf ( "error saving upgraded roleEntry: %w" , err )
2017-04-24 19:15:50 +00:00
}
2016-09-23 15:22:23 +00:00
}
2019-06-20 14:31:31 +00:00
b . roleCache . SetDefault ( roleName , result )
2016-09-23 15:22:23 +00:00
2019-06-20 14:31:31 +00:00
return result , nil
2016-09-23 15:22:23 +00:00
}
2019-06-20 14:31:31 +00:00
// setRole creates or updates a role in the storage. The caller must hold
// the write lock.
func ( b * backend ) setRole ( ctx context . Context , s logical . Storage , roleName string ,
2016-09-23 15:22:23 +00:00
roleEntry * awsRoleEntry ) error {
if roleName == "" {
return fmt . Errorf ( "missing role name" )
}
if roleEntry == nil {
return fmt . Errorf ( "nil role entry" )
}
entry , err := logical . StorageEntryJSON ( "role/" + strings . ToLower ( roleName ) , roleEntry )
if err != nil {
return err
}
2018-01-19 06:44:44 +00:00
if err := s . Put ( ctx , entry ) ; err != nil {
2016-09-23 15:22:23 +00:00
return err
}
2019-06-20 14:31:31 +00:00
b . roleCache . SetDefault ( roleName , roleEntry )
2016-09-23 15:22:23 +00:00
return nil
2016-05-05 18:51:09 +00:00
}
2019-07-05 23:55:40 +00:00
// initialize is used to initialize the AWS roles
func ( b * backend ) initialize ( ctx context . Context , req * logical . InitializationRequest ) error {
// on standbys and DR secondaries we do not want to run any kind of upgrade logic
if b . System ( ) . ReplicationState ( ) . HasState ( consts . ReplicationPerformanceStandby | consts . ReplicationDRSecondary ) {
return nil
}
// Initialize only if we are either:
// (1) A local mount.
// (2) Are _NOT_ a replicated performance secondary
if b . System ( ) . LocalMount ( ) || ! b . System ( ) . ReplicationState ( ) . HasState ( consts . ReplicationPerformanceSecondary ) {
s := req . Storage
logger := b . Logger ( ) . Named ( "initialize" )
logger . Debug ( "starting initialization" )
var upgradeCtx context . Context
upgradeCtx , b . upgradeCancelFunc = context . WithCancel ( context . Background ( ) )
go func ( ) {
// The vault will become unsealed while this goroutine is running,
// so we could see some role requests block until the lock is
// released. However we'd rather see those requests block (and
// potentially start timing out) than allow a non-upgraded role to
// be fetched.
b . roleMutex . Lock ( )
defer b . roleMutex . Unlock ( )
upgraded , err := b . upgrade ( upgradeCtx , s )
if err != nil {
logger . Error ( "error running initialization" , "error" , err )
return
}
if upgraded {
logger . Info ( "an upgrade was performed during initialization" )
}
} ( )
}
return nil
}
// awsVersion stores info about the the latest aws version that we have
// upgraded to.
type awsVersion struct {
Version int ` json:"version" `
}
// currentAwsVersion stores the latest version that we have upgraded to.
// Note that this is tracked independently from currentRoleStorageVersion.
const currentAwsVersion = 1
// upgrade does an upgrade, if necessary
func ( b * backend ) upgrade ( ctx context . Context , s logical . Storage ) ( bool , error ) {
entry , err := s . Get ( ctx , "config/version" )
if err != nil {
return false , err
}
var version awsVersion
if entry != nil {
err = entry . DecodeJSON ( & version )
if err != nil {
return false , err
}
}
upgraded := version . Version < currentAwsVersion
switch version . Version {
case 0 :
// Read all the role names.
roleNames , err := s . List ( ctx , "role/" )
if err != nil {
return false , err
}
// Upgrade the roles as necessary.
for _ , roleName := range roleNames {
// make sure the context hasn't been canceled
if ctx . Err ( ) != nil {
2021-04-07 23:48:40 +00:00
return false , ctx . Err ( )
2019-07-05 23:55:40 +00:00
}
_ , err := b . roleInternal ( ctx , s , roleName )
if err != nil {
return false , err
}
}
fallthrough
case currentAwsVersion :
version . Version = currentAwsVersion
default :
return false , fmt . Errorf ( "unrecognized role version: %d" , version . Version )
}
// save the current version
if upgraded {
entry , err = logical . StorageEntryJSON ( "config/version" , & version )
if err != nil {
return false , err
}
err = s . Put ( ctx , entry )
if err != nil {
return false , err
}
}
return upgraded , nil
}
2017-04-24 19:15:50 +00:00
// If needed, updates the role entry and returns a bool indicating if it was updated
// (and thus needs to be persisted)
2019-06-20 14:31:31 +00:00
func ( b * backend ) upgradeRole ( ctx context . Context , s logical . Storage , roleEntry * awsRoleEntry ) ( bool , error ) {
2017-04-24 19:15:50 +00:00
if roleEntry == nil {
return false , fmt . Errorf ( "received nil roleEntry" )
}
2018-03-18 01:24:49 +00:00
upgraded := roleEntry . Version < currentRoleStorageVersion
2018-03-02 16:09:14 +00:00
switch roleEntry . Version {
case 0 :
// Check if the value held by role ARN field is actually an instance profile ARN
if roleEntry . BoundIamRoleARN != "" && strings . Contains ( roleEntry . BoundIamRoleARN , ":instance-profile/" ) {
// If yes, move it to the correct field
roleEntry . BoundIamInstanceProfileARN = roleEntry . BoundIamRoleARN
2017-04-24 19:15:50 +00:00
2018-03-02 16:09:14 +00:00
// Reset the old field
roleEntry . BoundIamRoleARN = ""
}
2017-04-24 19:15:50 +00:00
2018-03-02 16:09:14 +00:00
// Check if there was no pre-existing AuthType set (from older versions)
if roleEntry . AuthType == "" {
// then default to the original behavior of ec2
roleEntry . AuthType = ec2AuthType
}
2017-04-24 19:15:50 +00:00
2018-03-02 16:09:14 +00:00
// Check if we need to resolve the unique ID on the role
if roleEntry . AuthType == iamAuthType &&
roleEntry . ResolveAWSUniqueIDs &&
roleEntry . BoundIamPrincipalARN != "" &&
roleEntry . BoundIamPrincipalID == "" &&
! strings . HasSuffix ( roleEntry . BoundIamPrincipalARN , "*" ) {
principalId , err := b . resolveArnToUniqueIDFunc ( ctx , s , roleEntry . BoundIamPrincipalARN )
if err != nil {
return false , err
}
roleEntry . BoundIamPrincipalID = principalId
// Not setting roleEntry.BoundIamPrincipalARN to "" here so that clients can see the original
// ARN that the role was bound to
}
// Check if we need to convert individual string values to lists
if roleEntry . BoundAmiID != "" {
roleEntry . BoundAmiIDs = [ ] string { roleEntry . BoundAmiID }
roleEntry . BoundAmiID = ""
}
if roleEntry . BoundAccountID != "" {
roleEntry . BoundAccountIDs = [ ] string { roleEntry . BoundAccountID }
roleEntry . BoundAccountID = ""
}
if roleEntry . BoundIamPrincipalARN != "" {
roleEntry . BoundIamPrincipalARNs = [ ] string { roleEntry . BoundIamPrincipalARN }
roleEntry . BoundIamPrincipalARN = ""
}
if roleEntry . BoundIamPrincipalID != "" {
roleEntry . BoundIamPrincipalIDs = [ ] string { roleEntry . BoundIamPrincipalID }
roleEntry . BoundIamPrincipalID = ""
}
if roleEntry . BoundIamRoleARN != "" {
roleEntry . BoundIamRoleARNs = [ ] string { roleEntry . BoundIamRoleARN }
roleEntry . BoundIamRoleARN = ""
}
if roleEntry . BoundIamInstanceProfileARN != "" {
roleEntry . BoundIamInstanceProfileARNs = [ ] string { roleEntry . BoundIamInstanceProfileARN }
roleEntry . BoundIamInstanceProfileARN = ""
}
if roleEntry . BoundRegion != "" {
roleEntry . BoundRegions = [ ] string { roleEntry . BoundRegion }
roleEntry . BoundRegion = ""
2017-06-07 14:27:11 +00:00
}
2018-03-02 16:09:14 +00:00
if roleEntry . BoundSubnetID != "" {
roleEntry . BoundSubnetIDs = [ ] string { roleEntry . BoundSubnetID }
roleEntry . BoundSubnetID = ""
}
if roleEntry . BoundVpcID != "" {
roleEntry . BoundVpcIDs = [ ] string { roleEntry . BoundVpcID }
roleEntry . BoundVpcID = ""
}
fallthrough
2019-01-30 20:46:43 +00:00
2018-03-18 01:24:49 +00:00
case 1 :
// Make BoundIamRoleARNs and BoundIamInstanceProfileARNs explicitly prefix-matched
for i , arn := range roleEntry . BoundIamRoleARNs {
roleEntry . BoundIamRoleARNs [ i ] = fmt . Sprintf ( "%s*" , arn )
}
for i , arn := range roleEntry . BoundIamInstanceProfileARNs {
roleEntry . BoundIamInstanceProfileARNs [ i ] = fmt . Sprintf ( "%s*" , arn )
}
fallthrough
2019-01-30 20:46:43 +00:00
case 2 :
roleID , err := uuid . GenerateUUID ( )
if err != nil {
return false , err
}
roleEntry . RoleID = roleID
fallthrough
2018-03-02 16:09:14 +00:00
case currentRoleStorageVersion :
2019-01-30 20:46:43 +00:00
roleEntry . Version = currentRoleStorageVersion
2018-03-02 16:09:14 +00:00
default :
return false , fmt . Errorf ( "unrecognized role version: %q" , roleEntry . Version )
2017-06-07 14:27:11 +00:00
}
2019-07-01 20:29:34 +00:00
// Add tokenutil upgrades. These don't need to be persisted, they're fine
// being upgraded each time until changed.
if roleEntry . TokenTTL == 0 && roleEntry . TTL > 0 {
roleEntry . TokenTTL = roleEntry . TTL
}
if roleEntry . TokenMaxTTL == 0 && roleEntry . MaxTTL > 0 {
roleEntry . TokenMaxTTL = roleEntry . MaxTTL
}
if roleEntry . TokenPeriod == 0 && roleEntry . Period > 0 {
roleEntry . TokenPeriod = roleEntry . Period
}
if len ( roleEntry . TokenPolicies ) == 0 && len ( roleEntry . Policies ) > 0 {
roleEntry . TokenPolicies = roleEntry . Policies
}
2017-04-24 19:15:50 +00:00
return upgraded , nil
}
2016-05-03 16:14:07 +00:00
// pathRoleDelete is used to delete the information registered for a given AMI ID.
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-13 18:31:13 +00:00
roleName := data . Get ( "role" ) . ( string )
2016-05-03 16:14:07 +00:00
if roleName == "" {
2016-05-13 18:31:13 +00:00
return logical . ErrorResponse ( "missing role" ) , nil
2016-05-03 16:14:07 +00:00
}
2016-05-05 18:51:09 +00:00
b . roleMutex . Lock ( )
defer b . roleMutex . Unlock ( )
2019-06-20 14:31:31 +00:00
err := req . Storage . Delete ( ctx , "role/" + strings . ToLower ( roleName ) )
if err != nil {
2021-04-22 15:20:59 +00:00
return nil , fmt . Errorf ( "error deleting role: %w" , err )
2019-06-20 14:31:31 +00:00
}
b . roleCache . Delete ( roleName )
return nil , nil
2016-05-03 16:14:07 +00:00
}
// pathRoleList is used to list all the AMI IDs registered with Vault.
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleList ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2018-01-19 06:44:44 +00:00
roles , err := req . Storage . List ( ctx , "role/" )
2016-05-03 16:14:07 +00:00
if err != nil {
return nil , err
}
2019-06-20 14:31:31 +00:00
2016-05-03 16:14:07 +00:00
return logical . ListResponse ( roles ) , nil
}
// pathRoleRead is used to view the information registered for a given AMI ID.
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathRoleRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2019-06-20 14:31:31 +00:00
roleEntry , err := b . role ( ctx , req . Storage , strings . ToLower ( data . Get ( "role" ) . ( string ) ) )
2016-05-03 16:14:07 +00:00
if err != nil {
return nil , err
}
if roleEntry == nil {
return nil , nil
}
2016-09-23 16:47:35 +00:00
return & logical . Response {
2018-03-02 16:09:14 +00:00
Data : roleEntry . ToResponseData ( ) ,
2016-09-23 16:47:35 +00:00
} , nil
2016-05-03 16:14:07 +00:00
}
// pathRoleCreateUpdate is used to associate Vault policies to a given AMI ID.
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-13 18:31:13 +00:00
roleName := strings . ToLower ( data . Get ( "role" ) . ( string ) )
2016-05-03 16:14:07 +00:00
if roleName == "" {
2016-05-13 18:31:13 +00:00
return logical . ErrorResponse ( "missing role" ) , nil
2016-05-03 16:14:07 +00:00
}
2016-05-05 18:51:09 +00:00
b . roleMutex . Lock ( )
defer b . roleMutex . Unlock ( )
2019-06-20 14:31:31 +00:00
// We use the internal one here to ensure that we have fresh data and
// nobody else is concurrently modifying. This will also call the upgrade
// path on existing role entries.
roleEntry , err := b . roleInternal ( ctx , req . Storage , roleName )
2016-05-03 16:14:07 +00:00
if err != nil {
return nil , err
}
if roleEntry == nil {
2019-01-30 20:46:43 +00:00
roleID , err := uuid . GenerateUUID ( )
if err != nil {
return nil , err
}
2018-03-02 16:09:14 +00:00
roleEntry = & awsRoleEntry {
2019-01-30 20:46:43 +00:00
RoleID : roleID ,
2018-03-02 16:09:14 +00:00
Version : currentRoleStorageVersion ,
}
2017-04-24 19:15:50 +00:00
} else {
2019-06-20 14:31:31 +00:00
// We want to always use a copy so we aren't modifying items in the
// version in the cache while other users may be looking it up (or if
// we fail somewhere)
cp , err := copystructure . Copy ( roleEntry )
2017-04-24 19:15:50 +00:00
if err != nil {
2019-06-20 14:31:31 +00:00
return nil , err
2017-04-24 19:15:50 +00:00
}
2019-06-20 14:31:31 +00:00
roleEntry = cp . ( * awsRoleEntry )
2016-05-03 16:14:07 +00:00
}
2016-09-23 16:47:35 +00:00
// Fetch and set the bound parameters. There can't be default values
// for these.
2016-06-14 15:58:19 +00:00
if boundAmiIDRaw , ok := data . GetOk ( "bound_ami_id" ) ; ok {
2018-03-02 16:09:14 +00:00
roleEntry . BoundAmiIDs = boundAmiIDRaw . ( [ ] string )
2016-06-14 15:58:19 +00:00
}
if boundAccountIDRaw , ok := data . GetOk ( "bound_account_id" ) ; ok {
2018-03-02 16:09:14 +00:00
roleEntry . BoundAccountIDs = boundAccountIDRaw . ( [ ] string )
2016-05-03 16:14:07 +00:00
}
2017-02-24 19:19:10 +00:00
if boundRegionRaw , ok := data . GetOk ( "bound_region" ) ; ok {
2018-03-02 16:09:14 +00:00
roleEntry . BoundRegions = boundRegionRaw . ( [ ] string )
2017-02-24 19:19:10 +00:00
}
if boundVpcIDRaw , ok := data . GetOk ( "bound_vpc_id" ) ; ok {
2018-03-02 16:09:14 +00:00
roleEntry . BoundVpcIDs = boundVpcIDRaw . ( [ ] string )
2017-02-24 19:19:10 +00:00
}
if boundSubnetIDRaw , ok := data . GetOk ( "bound_subnet_id" ) ; ok {
2018-03-02 16:09:14 +00:00
roleEntry . BoundSubnetIDs = boundSubnetIDRaw . ( [ ] string )
2017-02-24 19:19:10 +00:00
}
2017-06-07 14:27:11 +00:00
if resolveAWSUniqueIDsRaw , ok := data . GetOk ( "resolve_aws_unique_ids" ) ; ok {
switch {
case req . Operation == logical . CreateOperation :
roleEntry . ResolveAWSUniqueIDs = resolveAWSUniqueIDsRaw . ( bool )
case roleEntry . ResolveAWSUniqueIDs && ! resolveAWSUniqueIDsRaw . ( bool ) :
return logical . ErrorResponse ( "changing resolve_aws_unique_ids from true to false is not allowed" ) , nil
default :
roleEntry . ResolveAWSUniqueIDs = resolveAWSUniqueIDsRaw . ( bool )
}
} else if req . Operation == logical . CreateOperation {
roleEntry . ResolveAWSUniqueIDs = data . Get ( "resolve_aws_unique_ids" ) . ( bool )
}
2016-09-23 16:47:35 +00:00
if boundIamRoleARNRaw , ok := data . GetOk ( "bound_iam_role_arn" ) ; ok {
2018-03-02 16:09:14 +00:00
roleEntry . BoundIamRoleARNs = boundIamRoleARNRaw . ( [ ] string )
2016-09-23 16:47:35 +00:00
}
2016-09-23 15:22:23 +00:00
if boundIamInstanceProfileARNRaw , ok := data . GetOk ( "bound_iam_instance_profile_arn" ) ; ok {
2018-03-02 16:09:14 +00:00
roleEntry . BoundIamInstanceProfileARNs = boundIamInstanceProfileARNRaw . ( [ ] string )
2016-06-14 18:46:08 +00:00
}
2018-03-15 16:19:28 +00:00
if boundEc2InstanceIDRaw , ok := data . GetOk ( "bound_ec2_instance_id" ) ; ok {
roleEntry . BoundEc2InstanceIDs = boundEc2InstanceIDRaw . ( [ ] string )
}
2017-04-24 19:15:50 +00:00
if boundIamPrincipalARNRaw , ok := data . GetOk ( "bound_iam_principal_arn" ) ; ok {
2018-03-02 16:09:14 +00:00
principalARNs := boundIamPrincipalARNRaw . ( [ ] string )
roleEntry . BoundIamPrincipalARNs = principalARNs
roleEntry . BoundIamPrincipalIDs = [ ] string { }
}
if roleEntry . ResolveAWSUniqueIDs && len ( roleEntry . BoundIamPrincipalIDs ) == 0 {
// we might be turning on resolution on this role, so ensure we update the IDs
for _ , principalARN := range roleEntry . BoundIamPrincipalARNs {
if ! strings . HasSuffix ( principalARN , "*" ) {
principalID , err := b . resolveArnToUniqueIDFunc ( ctx , req . Storage , principalARN )
if err != nil {
2018-08-01 23:20:56 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "unable to resolve ARN %#v to internal ID: %s" , principalARN , err . Error ( ) ) ) , nil
2018-03-02 16:09:14 +00:00
}
roleEntry . BoundIamPrincipalIDs = append ( roleEntry . BoundIamPrincipalIDs , principalID )
2017-06-07 14:27:11 +00:00
}
}
2017-04-24 19:15:50 +00:00
}
if inferRoleTypeRaw , ok := data . GetOk ( "inferred_entity_type" ) ; ok {
roleEntry . InferredEntityType = inferRoleTypeRaw . ( string )
}
if inferredAWSRegionRaw , ok := data . GetOk ( "inferred_aws_region" ) ; ok {
roleEntry . InferredAWSRegion = inferredAWSRegionRaw . ( string )
}
// auth_type is a special case as it's immutable and can't be changed once a role is created
if authTypeRaw , ok := data . GetOk ( "auth_type" ) ; ok {
// roleEntry.AuthType should only be "" when it's a new role; existing roles without an
// auth_type should have already been upgraded to have one before we get here
if roleEntry . AuthType == "" {
switch authTypeRaw . ( string ) {
case ec2AuthType , iamAuthType :
roleEntry . AuthType = authTypeRaw . ( string )
default :
return logical . ErrorResponse ( fmt . Sprintf ( "unrecognized auth_type: %v" , authTypeRaw . ( string ) ) ) , nil
}
} else if authTypeRaw . ( string ) != roleEntry . AuthType {
return logical . ErrorResponse ( "changing auth_type on a role is not allowed" ) , nil
}
} else if req . Operation == logical . CreateOperation {
switch req . MountType {
// maintain backwards compatibility for old aws-ec2 auth types
case "aws-ec2" :
roleEntry . AuthType = ec2AuthType
// but default to iamAuth for new mounts going forward
case "aws" :
roleEntry . AuthType = iamAuthType
default :
roleEntry . AuthType = iamAuthType
}
}
allowEc2Binds := roleEntry . AuthType == ec2AuthType
if roleEntry . InferredEntityType != "" {
switch {
case roleEntry . AuthType != iamAuthType :
return logical . ErrorResponse ( "specified inferred_entity_type but didn't allow iam auth_type" ) , nil
case roleEntry . InferredEntityType != ec2EntityType :
return logical . ErrorResponse ( fmt . Sprintf ( "specified invalid inferred_entity_type: %s" , roleEntry . InferredEntityType ) ) , nil
case roleEntry . InferredAWSRegion == "" :
return logical . ErrorResponse ( "specified inferred_entity_type but not inferred_aws_region" ) , nil
}
allowEc2Binds = true
} else if roleEntry . InferredAWSRegion != "" {
return logical . ErrorResponse ( "specified inferred_aws_region but not inferred_entity_type" ) , nil
}
numBinds := 0
2018-03-02 16:09:14 +00:00
if len ( roleEntry . BoundAccountIDs ) > 0 {
2017-04-24 19:15:50 +00:00
if ! allowEc2Binds {
2018-03-15 16:19:28 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "specified bound_account_id but not specifying ec2 auth_type or inferring %s" , ec2EntityType ) ) , nil
2017-04-24 19:15:50 +00:00
}
numBinds ++
}
2018-03-02 16:09:14 +00:00
if len ( roleEntry . BoundRegions ) > 0 {
2017-04-24 19:15:50 +00:00
if roleEntry . AuthType != ec2AuthType {
2018-03-15 16:19:28 +00:00
return logical . ErrorResponse ( "specified bound_region but not specifying ec2 auth_type" ) , nil
2017-04-24 19:15:50 +00:00
}
numBinds ++
}
2018-03-02 16:09:14 +00:00
if len ( roleEntry . BoundAmiIDs ) > 0 {
2017-04-24 19:15:50 +00:00
if ! allowEc2Binds {
2018-03-15 16:19:28 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "specified bound_ami_id but not specifying ec2 auth_type or inferring %s" , ec2EntityType ) ) , nil
2017-04-24 19:15:50 +00:00
}
numBinds ++
}
2018-03-02 16:09:14 +00:00
if len ( roleEntry . BoundIamInstanceProfileARNs ) > 0 {
2017-04-24 19:15:50 +00:00
if ! allowEc2Binds {
2018-03-15 16:19:28 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "specified bound_iam_instance_profile_arn but not specifying ec2 auth_type or inferring %s" , ec2EntityType ) ) , nil
}
numBinds ++
}
if len ( roleEntry . BoundEc2InstanceIDs ) > 0 {
if ! allowEc2Binds {
return logical . ErrorResponse ( fmt . Sprintf ( "specified bound_ec2_instance_id but not specifying ec2 auth_type or inferring %s" , ec2EntityType ) ) , nil
2017-04-24 19:15:50 +00:00
}
numBinds ++
}
2018-03-02 16:09:14 +00:00
if len ( roleEntry . BoundIamRoleARNs ) > 0 {
2017-04-24 19:15:50 +00:00
if ! allowEc2Binds {
2018-03-15 16:19:28 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "specified bound_iam_role_arn but not specifying ec2 auth_type or inferring %s" , ec2EntityType ) ) , nil
2017-04-24 19:15:50 +00:00
}
numBinds ++
}
2018-03-02 16:09:14 +00:00
if len ( roleEntry . BoundIamPrincipalARNs ) > 0 {
2017-04-24 19:15:50 +00:00
if roleEntry . AuthType != iamAuthType {
2018-03-15 16:19:28 +00:00
return logical . ErrorResponse ( "specified bound_iam_principal_arn but not specifying iam auth_type" ) , nil
2017-04-24 19:15:50 +00:00
}
numBinds ++
}
2018-03-02 16:09:14 +00:00
if len ( roleEntry . BoundVpcIDs ) > 0 {
2017-04-24 19:15:50 +00:00
if ! allowEc2Binds {
2018-03-15 16:19:28 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "specified bound_vpc_id but not specifying ec2 auth_type or inferring %s" , ec2EntityType ) ) , nil
2017-04-24 19:15:50 +00:00
}
numBinds ++
}
2018-03-02 16:09:14 +00:00
if len ( roleEntry . BoundSubnetIDs ) > 0 {
2017-04-24 19:15:50 +00:00
if ! allowEc2Binds {
2018-03-15 16:19:28 +00:00
return logical . ErrorResponse ( fmt . Sprintf ( "specified bound_subnet_id but not specifying ec2 auth_type or inferring %s" , ec2EntityType ) ) , nil
2017-04-24 19:15:50 +00:00
}
numBinds ++
}
if numBinds == 0 {
2019-01-17 18:28:27 +00:00
return logical . ErrorResponse ( "at least one bound parameter should be specified on the role" ) , nil
2016-05-03 16:14:07 +00:00
}
disallowReauthenticationBool , ok := data . GetOk ( "disallow_reauthentication" )
if ok {
2017-04-24 19:15:50 +00:00
if roleEntry . AuthType != ec2AuthType {
return logical . ErrorResponse ( "specified disallow_reauthentication when not using ec2 auth type" ) , nil
}
2016-05-03 16:14:07 +00:00
roleEntry . DisallowReauthentication = disallowReauthenticationBool . ( bool )
2017-04-24 19:15:50 +00:00
} else if req . Operation == logical . CreateOperation && roleEntry . AuthType == ec2AuthType {
2016-05-03 16:14:07 +00:00
roleEntry . DisallowReauthentication = data . Get ( "disallow_reauthentication" ) . ( bool )
}
allowInstanceMigrationBool , ok := data . GetOk ( "allow_instance_migration" )
if ok {
2017-04-24 19:15:50 +00:00
if roleEntry . AuthType != ec2AuthType {
return logical . ErrorResponse ( "specified allow_instance_migration when not using ec2 auth type" ) , nil
}
2016-05-03 16:14:07 +00:00
roleEntry . AllowInstanceMigration = allowInstanceMigrationBool . ( bool )
2017-04-24 19:15:50 +00:00
} else if req . Operation == logical . CreateOperation && roleEntry . AuthType == ec2AuthType {
2016-05-03 16:14:07 +00:00
roleEntry . AllowInstanceMigration = data . Get ( "allow_instance_migration" ) . ( bool )
}
2017-11-06 22:12:07 +00:00
if roleEntry . AllowInstanceMigration && roleEntry . DisallowReauthentication {
return logical . ErrorResponse ( "cannot specify both disallow_reauthentication=true and allow_instance_migration=true" ) , nil
}
2016-05-05 19:32:14 +00:00
var resp logical . Response
2019-07-01 20:29:34 +00:00
if err := roleEntry . ParseTokenFields ( req , data ) ; err != nil {
return logical . ErrorResponse ( err . Error ( ) ) , logical . ErrInvalidRequest
2016-08-09 21:29:45 +00:00
}
2019-07-01 20:29:34 +00:00
// Handle upgrade cases
{
2019-07-02 13:52:05 +00:00
if err := tokenutil . UpgradeValue ( data , "policies" , "token_policies" , & roleEntry . Policies , & roleEntry . TokenPolicies ) ; err != nil {
return logical . ErrorResponse ( err . Error ( ) ) , nil
2019-07-01 20:29:34 +00:00
}
2019-07-02 13:52:05 +00:00
if err := tokenutil . UpgradeValue ( data , "ttl" , "token_ttl" , & roleEntry . TTL , & roleEntry . TokenTTL ) ; err != nil {
return logical . ErrorResponse ( err . Error ( ) ) , nil
}
// Special case here for old lease value
_ , ok := data . GetOk ( "token_ttl" )
2019-07-01 20:29:34 +00:00
if ! ok {
_ , ok = data . GetOk ( "ttl" )
2019-07-02 13:52:05 +00:00
if ! ok {
ttlRaw , ok := data . GetOk ( "lease" )
if ok {
roleEntry . TTL = time . Duration ( ttlRaw . ( int ) ) * time . Second
roleEntry . TokenTTL = roleEntry . TTL
}
2019-07-01 20:29:34 +00:00
}
2016-05-03 16:14:07 +00:00
}
2019-07-02 13:52:05 +00:00
if err := tokenutil . UpgradeValue ( data , "max_ttl" , "token_max_ttl" , & roleEntry . MaxTTL , & roleEntry . TokenMaxTTL ) ; err != nil {
return logical . ErrorResponse ( err . Error ( ) ) , nil
2016-05-03 16:14:07 +00:00
}
2019-07-02 13:52:05 +00:00
if err := tokenutil . UpgradeValue ( data , "period" , "token_period" , & roleEntry . Period , & roleEntry . TokenPeriod ) ; err != nil {
return logical . ErrorResponse ( err . Error ( ) ) , nil
2019-07-01 20:29:34 +00:00
}
2016-05-03 16:14:07 +00:00
}
2019-07-01 20:29:34 +00:00
defaultLeaseTTL := b . System ( ) . DefaultLeaseTTL ( )
systemMaxTTL := b . System ( ) . MaxLeaseTTL ( )
if roleEntry . TokenTTL > defaultLeaseTTL {
resp . AddWarning ( fmt . Sprintf ( "Given ttl of %d seconds greater than current mount/system default of %d seconds; ttl will be capped at login time" , roleEntry . TokenTTL / time . Second , defaultLeaseTTL / time . Second ) )
2016-08-09 21:29:45 +00:00
}
2019-07-01 20:29:34 +00:00
if roleEntry . TokenMaxTTL > systemMaxTTL {
resp . AddWarning ( fmt . Sprintf ( "Given max ttl of %d seconds greater than current mount/system default of %d seconds; max ttl will be capped at login time" , roleEntry . TokenMaxTTL / time . Second , systemMaxTTL / time . Second ) )
2017-02-02 18:28:01 +00:00
}
2019-07-01 20:29:34 +00:00
if roleEntry . TokenMaxTTL != 0 && roleEntry . TokenMaxTTL < roleEntry . TokenTTL {
return logical . ErrorResponse ( "ttl should be shorter than max ttl" ) , nil
}
if roleEntry . TokenPeriod > b . System ( ) . MaxLeaseTTL ( ) {
return logical . ErrorResponse ( fmt . Sprintf ( "period of '%s' is greater than the backend's maximum lease TTL of '%s'" , roleEntry . TokenPeriod . String ( ) , b . System ( ) . MaxLeaseTTL ( ) . String ( ) ) ) , nil
2017-02-02 18:28:01 +00:00
}
2016-05-03 16:14:07 +00:00
roleTagStr , ok := data . GetOk ( "role_tag" )
if ok {
2017-04-24 19:15:50 +00:00
if roleEntry . AuthType != ec2AuthType {
return logical . ErrorResponse ( "tried to enable role_tag when not using ec2 auth method" ) , nil
}
2016-05-03 16:14:07 +00:00
roleEntry . RoleTag = roleTagStr . ( string )
// There is a limit of 127 characters on the tag key for AWS EC2 instances.
// Complying to that requirement, do not allow the value of 'key' to be more than that.
if len ( roleEntry . RoleTag ) > 127 {
2016-05-05 18:51:09 +00:00
return logical . ErrorResponse ( "length of role tag exceeds the EC2 key limit of 127 characters" ) , nil
2016-05-03 16:14:07 +00:00
}
2017-04-24 19:15:50 +00:00
} else if req . Operation == logical . CreateOperation && roleEntry . AuthType == ec2AuthType {
2016-05-03 16:14:07 +00:00
roleEntry . RoleTag = data . Get ( "role_tag" ) . ( string )
}
2016-05-05 18:51:09 +00:00
if roleEntry . HMACKey == "" {
roleEntry . HMACKey , err = uuid . GenerateUUID ( )
if err != nil {
2021-04-22 15:20:59 +00:00
return nil , fmt . Errorf ( "failed to generate role HMAC key: %w" , err )
2016-05-05 18:51:09 +00:00
}
2016-05-03 16:14:07 +00:00
}
2019-06-20 14:31:31 +00:00
if err := b . setRole ( ctx , req . Storage , roleName , roleEntry ) ; err != nil {
2016-05-03 16:14:07 +00:00
return nil , err
}
2017-06-05 14:52:43 +00:00
if len ( resp . Warnings ) == 0 {
2016-05-05 19:32:14 +00:00
return nil , nil
}
return & resp , nil
2016-05-03 16:14:07 +00:00
}
2018-03-02 16:09:14 +00:00
// Struct to hold the information associated with a Vault role
2016-05-03 16:14:07 +00:00
type awsRoleEntry struct {
2019-07-01 20:29:34 +00:00
tokenutil . TokenParams
RoleID string ` json:"role_id" `
AuthType string ` json:"auth_type" `
BoundAmiIDs [ ] string ` json:"bound_ami_id_list" `
BoundAccountIDs [ ] string ` json:"bound_account_id_list" `
BoundEc2InstanceIDs [ ] string ` json:"bound_ec2_instance_id_list" `
BoundIamPrincipalARNs [ ] string ` json:"bound_iam_principal_arn_list" `
BoundIamPrincipalIDs [ ] string ` json:"bound_iam_principal_id_list" `
BoundIamRoleARNs [ ] string ` json:"bound_iam_role_arn_list" `
BoundIamInstanceProfileARNs [ ] string ` json:"bound_iam_instance_profile_arn_list" `
BoundRegions [ ] string ` json:"bound_region_list" `
BoundSubnetIDs [ ] string ` json:"bound_subnet_id_list" `
BoundVpcIDs [ ] string ` json:"bound_vpc_id_list" `
InferredEntityType string ` json:"inferred_entity_type" `
InferredAWSRegion string ` json:"inferred_aws_region" `
ResolveAWSUniqueIDs bool ` json:"resolve_aws_unique_ids" `
RoleTag string ` json:"role_tag" `
AllowInstanceMigration bool ` json:"allow_instance_migration" `
DisallowReauthentication bool ` json:"disallow_reauthentication" `
HMACKey string ` json:"hmac_key" `
Version int ` json:"version" `
// Deprecated: These are superceded by TokenUtil
TTL time . Duration ` json:"ttl" `
MaxTTL time . Duration ` json:"max_ttl" `
Period time . Duration ` json:"period" `
Policies [ ] string ` json:"policies" `
2018-03-02 16:09:14 +00:00
// DEPRECATED -- these are the old fields before we supported lists and exist for backwards compatibility
BoundAmiID string ` json:"bound_ami_id,omitempty" `
BoundAccountID string ` json:"bound_account_id,omitempty" `
BoundIamPrincipalARN string ` json:"bound_iam_principal_arn,omitempty" `
BoundIamPrincipalID string ` json:"bound_iam_principal_id,omitempty" `
BoundIamRoleARN string ` json:"bound_iam_role_arn,omitempty" `
BoundIamInstanceProfileARN string ` json:"bound_iam_instance_profile_arn,omitempty" `
BoundRegion string ` json:"bound_region,omitempty" `
BoundSubnetID string ` json:"bound_subnet_id,omitempty" `
BoundVpcID string ` json:"bound_vpc_id,omitempty" `
}
func ( r * awsRoleEntry ) ToResponseData ( ) map [ string ] interface { } {
responseData := map [ string ] interface { } {
"auth_type" : r . AuthType ,
"bound_ami_id" : r . BoundAmiIDs ,
"bound_account_id" : r . BoundAccountIDs ,
2018-03-15 16:19:28 +00:00
"bound_ec2_instance_id" : r . BoundEc2InstanceIDs ,
2018-03-02 16:09:14 +00:00
"bound_iam_principal_arn" : r . BoundIamPrincipalARNs ,
"bound_iam_principal_id" : r . BoundIamPrincipalIDs ,
"bound_iam_role_arn" : r . BoundIamRoleARNs ,
"bound_iam_instance_profile_arn" : r . BoundIamInstanceProfileARNs ,
"bound_region" : r . BoundRegions ,
"bound_subnet_id" : r . BoundSubnetIDs ,
"bound_vpc_id" : r . BoundVpcIDs ,
"inferred_entity_type" : r . InferredEntityType ,
"inferred_aws_region" : r . InferredAWSRegion ,
"resolve_aws_unique_ids" : r . ResolveAWSUniqueIDs ,
2019-01-30 20:46:43 +00:00
"role_id" : r . RoleID ,
2018-03-02 16:09:14 +00:00
"role_tag" : r . RoleTag ,
"allow_instance_migration" : r . AllowInstanceMigration ,
2018-09-04 16:29:18 +00:00
"disallow_reauthentication" : r . DisallowReauthentication ,
2019-07-01 20:29:34 +00:00
}
r . PopulateTokenData ( responseData )
if r . TTL > 0 {
responseData [ "ttl" ] = int64 ( r . TTL . Seconds ( ) )
}
if r . MaxTTL > 0 {
responseData [ "max_ttl" ] = int64 ( r . MaxTTL . Seconds ( ) )
}
if r . Period > 0 {
responseData [ "period" ] = int64 ( r . Period . Seconds ( ) )
}
if len ( r . Policies ) > 0 {
responseData [ "policies" ] = responseData [ "token_policies" ]
2018-03-02 16:09:14 +00:00
}
convertNilToEmptySlice := func ( data map [ string ] interface { } , field string ) {
if data [ field ] == nil || len ( data [ field ] . ( [ ] string ) ) == 0 {
data [ field ] = [ ] string { }
}
}
convertNilToEmptySlice ( responseData , "bound_ami_id" )
convertNilToEmptySlice ( responseData , "bound_account_id" )
convertNilToEmptySlice ( responseData , "bound_iam_principal_arn" )
convertNilToEmptySlice ( responseData , "bound_iam_principal_id" )
convertNilToEmptySlice ( responseData , "bound_iam_role_arn" )
convertNilToEmptySlice ( responseData , "bound_iam_instance_profile_arn" )
convertNilToEmptySlice ( responseData , "bound_region" )
convertNilToEmptySlice ( responseData , "bound_subnet_id" )
convertNilToEmptySlice ( responseData , "bound_vpc_id" )
return responseData
2016-05-03 16:14:07 +00:00
}
const pathRoleSyn = `
Create a role and associate policies to it .
`
const pathRoleDesc = `
A precondition for login is that a role should be created in the backend .
2018-09-04 17:55:02 +00:00
The login endpoint takes in the role name against which the client
should be validated . After authenticating the client , the authorization
to access Vault ' s resources is determined by the policies that are
associated to the role though this endpoint .
2016-05-03 16:14:07 +00:00
2018-09-04 17:55:02 +00:00
When an EC2 instance requires only a subset of policies on the role , then
2016-05-03 16:14:07 +00:00
' role_tag ' option on the role can be enabled to create a role tag via the
2016-05-13 18:31:13 +00:00
endpoint ' role / < role > / tag ' . This tag then needs to be applied on the
2016-05-03 16:14:07 +00:00
instance before it attempts a login . The policies on the tag should be a
subset of policies that are associated to the role . In order to enable
login using tags , ' role_tag ' option should be set while creating a role .
2017-04-24 19:15:50 +00:00
This only applies when authenticating EC2 instances .
2016-05-03 16:14:07 +00:00
Also , a ' max_ttl ' can be configured in this endpoint that determines the maximum
2016-05-05 18:51:09 +00:00
duration for which a login can be renewed . Note that the ' max_ttl ' has an upper
2016-05-03 16:14:07 +00:00
limit of the ' max_ttl ' value on the backend ' s mount .
`
const pathListRolesHelpSyn = `
Lists all the roles that are registered with Vault .
`
const pathListRolesHelpDesc = `
Roles will be listed by their respective role names .
`