2017-04-24 19:15:50 +00:00
package awsauth
2016-04-06 00:42:26 +00:00
import (
2018-01-08 18:31:38 +00:00
"context"
2016-04-25 14:40:05 +00:00
"encoding/base64"
2017-04-24 19:15:50 +00:00
"encoding/json"
2016-04-11 23:21:53 +00:00
"fmt"
2017-04-24 19:15:50 +00:00
"io/ioutil"
"net/http"
2016-04-11 23:21:53 +00:00
"os"
2016-04-06 23:25:35 +00:00
"strings"
2016-04-06 00:42:26 +00:00
"testing"
2017-06-07 14:27:11 +00:00
"time"
2016-04-06 00:42:26 +00:00
2017-04-24 19:15:50 +00:00
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/sts"
2019-04-13 07:44:06 +00:00
logicaltest "github.com/hashicorp/vault/helper/testhelpers/logical"
"github.com/hashicorp/vault/sdk/framework"
2019-04-12 22:08:46 +00:00
"github.com/hashicorp/vault/sdk/helper/policyutil"
2019-04-12 21:54:35 +00:00
"github.com/hashicorp/vault/sdk/logical"
2016-04-06 00:42:26 +00:00
)
2018-09-12 21:16:16 +00:00
const testVaultHeaderValue = "VaultAcceptanceTesting"
const testValidRoleName = "valid-role"
const testInvalidRoleName = "invalid-role"
2016-04-25 16:13:12 +00:00
func TestBackend_CreateParseVerifyRoleTag ( t * testing . T ) {
// create a backend
2016-04-25 15:44:58 +00:00
config := logical . TestBackendConfig ( )
storage := & logical . InmemStorage { }
config . StorageView = storage
2016-06-01 16:17:47 +00:00
b , err := Backend ( config )
2016-05-10 02:07:46 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2016-04-25 15:44:58 +00:00
if err != nil {
t . Fatal ( err )
}
2016-05-03 16:14:07 +00:00
// create a role entry
2016-04-25 15:44:58 +00:00
data := map [ string ] interface { } {
2017-04-24 19:15:50 +00:00
"auth_type" : "ec2" ,
2016-05-03 16:14:07 +00:00
"policies" : "p,q,r,s" ,
"bound_ami_id" : "abcd-123" ,
2016-04-25 15:44:58 +00:00
}
2018-01-08 18:31:38 +00:00
resp , err := b . HandleRequest ( context . Background ( ) , & logical . Request {
2017-04-24 19:15:50 +00:00
Operation : logical . CreateOperation ,
2016-05-03 16:14:07 +00:00
Path : "role/abcd-123" ,
2016-04-25 15:44:58 +00:00
Storage : storage ,
Data : data ,
} )
2016-05-03 16:14:07 +00:00
if resp != nil && resp . IsError ( ) {
t . Fatalf ( "failed to create role" )
}
2016-04-25 15:44:58 +00:00
if err != nil {
t . Fatal ( err )
}
2016-05-03 16:14:07 +00:00
// read the created role entry
2018-01-19 06:44:44 +00:00
roleEntry , err := b . lockedAWSRole ( context . Background ( ) , storage , "abcd-123" )
2016-04-25 15:44:58 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-25 16:13:12 +00:00
// create a nonce for the role tag
2016-04-25 15:44:58 +00:00
nonce , err := createRoleTagNonce ( )
if err != nil {
t . Fatal ( err )
}
2016-04-25 16:13:12 +00:00
rTag1 := & roleTag {
2016-04-25 15:44:58 +00:00
Version : "v1" ,
2016-05-13 18:31:13 +00:00
Role : "abcd-123" ,
2016-04-25 15:44:58 +00:00
Nonce : nonce ,
Policies : [ ] string { "p" , "q" , "r" } ,
2016-05-10 02:07:46 +00:00
MaxTTL : 200000000000 , // 200s
2016-04-25 15:44:58 +00:00
}
2016-04-25 16:13:12 +00:00
2016-05-03 16:14:07 +00:00
// create a role tag against the role entry
val , err := createRoleTagValue ( rTag1 , roleEntry )
2016-04-25 15:44:58 +00:00
if err != nil {
t . Fatal ( err )
}
if val == "" {
t . Fatalf ( "failed to create role tag" )
}
2016-04-25 16:13:12 +00:00
// parse the created role tag
2018-01-19 06:44:44 +00:00
rTag2 , err := b . parseAndVerifyRoleTagValue ( context . Background ( ) , storage , val )
2016-04-25 16:13:12 +00:00
if err != nil {
t . Fatal ( err )
}
// check the values in parsed role tag
if rTag2 . Version != "v1" ||
rTag2 . Nonce != nonce ||
2016-05-13 18:31:13 +00:00
rTag2 . Role != "abcd-123" ||
2016-05-10 02:07:46 +00:00
rTag2 . MaxTTL != 200000000000 || // 200s
2016-04-25 16:13:12 +00:00
! policyutil . EquivalentPolicies ( rTag2 . Policies , [ ] string { "p" , "q" , "r" } ) ||
len ( rTag2 . HMAC ) == 0 {
t . Fatalf ( "parsed role tag is invalid" )
}
2016-05-03 16:14:07 +00:00
// verify the tag contents using role specific HMAC key
verified , err := verifyRoleTagValue ( rTag2 , roleEntry )
2016-04-25 16:13:12 +00:00
if err != nil {
t . Fatal ( err )
}
if ! verified {
t . Fatalf ( "failed to verify the role tag" )
}
2016-05-03 16:14:07 +00:00
// register a different role
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , & logical . Request {
2017-04-24 19:15:50 +00:00
Operation : logical . CreateOperation ,
2016-05-03 16:14:07 +00:00
Path : "role/ami-6789" ,
2016-04-25 16:13:12 +00:00
Storage : storage ,
Data : data ,
} )
2016-05-03 16:14:07 +00:00
if resp != nil && resp . IsError ( ) {
t . Fatalf ( "failed to create role" )
}
2016-04-25 16:13:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-05-03 16:14:07 +00:00
// get the entry of the newly created role entry
2018-01-19 06:44:44 +00:00
roleEntry2 , err := b . lockedAWSRole ( context . Background ( ) , storage , "ami-6789" )
2016-04-25 16:13:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-05-03 16:14:07 +00:00
// try to verify the tag created with previous role's HMAC key
2016-04-25 16:13:12 +00:00
// with the newly registered entry's HMAC key
2016-05-03 16:14:07 +00:00
verified , err = verifyRoleTagValue ( rTag2 , roleEntry2 )
2016-04-25 16:13:12 +00:00
if err != nil {
t . Fatal ( err )
}
if verified {
2016-05-03 16:14:07 +00:00
t . Fatalf ( "verification of role tag should have failed" )
2016-04-25 16:13:12 +00:00
}
// modify any value in role tag and try to verify it
rTag2 . Version = "v2"
2016-05-03 16:14:07 +00:00
verified , err = verifyRoleTagValue ( rTag2 , roleEntry )
2016-04-25 16:13:12 +00:00
if err != nil {
t . Fatal ( err )
}
if verified {
t . Fatalf ( "verification of role tag should have failed: invalid Version" )
}
2016-04-25 15:44:58 +00:00
}
func TestBackend_prepareRoleTagPlaintextValue ( t * testing . T ) {
2016-04-25 16:13:12 +00:00
// create a nonce for the role tag
2016-04-25 14:40:05 +00:00
nonce , err := createRoleTagNonce ( )
if err != nil {
t . Fatal ( err )
}
rTag := & roleTag {
2016-05-13 18:31:13 +00:00
Version : "v1" ,
Nonce : nonce ,
Role : "abcd-123" ,
2016-04-25 14:40:05 +00:00
}
rTag . Version = ""
2016-04-25 16:13:12 +00:00
// try to create plaintext part of role tag
// without specifying version
2016-04-25 14:40:05 +00:00
val , err := prepareRoleTagPlaintextValue ( rTag )
if err == nil {
t . Fatalf ( "expected error for missing version" )
}
rTag . Version = "v1"
rTag . Nonce = ""
2016-04-25 16:13:12 +00:00
// try to create plaintext part of role tag
// without specifying nonce
2016-04-25 14:40:05 +00:00
val , err = prepareRoleTagPlaintextValue ( rTag )
if err == nil {
t . Fatalf ( "expected error for missing nonce" )
}
rTag . Nonce = nonce
2016-05-13 18:31:13 +00:00
rTag . Role = ""
2016-04-25 16:13:12 +00:00
// try to create plaintext part of role tag
2016-05-13 18:31:13 +00:00
// without specifying role
2016-04-25 14:40:05 +00:00
val , err = prepareRoleTagPlaintextValue ( rTag )
if err == nil {
2016-05-13 18:31:13 +00:00
t . Fatalf ( "expected error for missing role" )
2016-04-25 14:40:05 +00:00
}
2016-05-13 18:31:13 +00:00
rTag . Role = "abcd-123"
2016-04-25 14:40:05 +00:00
2016-04-25 16:13:12 +00:00
// create the plaintext part of the tag
2016-04-25 14:40:05 +00:00
val , err = prepareRoleTagPlaintextValue ( rTag )
if err != nil {
t . Fatal ( err )
}
2016-04-25 16:13:12 +00:00
// verify if it contains known fields
2016-05-03 16:14:07 +00:00
if ! strings . Contains ( val , "r=" ) ||
2016-04-25 14:40:05 +00:00
! strings . Contains ( val , "d=" ) ||
2016-05-10 02:07:46 +00:00
! strings . Contains ( val , "m=" ) ||
2016-04-25 14:40:05 +00:00
! strings . HasPrefix ( val , "v1" ) {
t . Fatalf ( "incorrect information in role tag plaintext value" )
}
rTag . InstanceID = "instance-123"
2016-04-25 16:13:12 +00:00
// create the role tag with instance_id specified
2016-04-25 14:40:05 +00:00
val , err = prepareRoleTagPlaintextValue ( rTag )
if err != nil {
t . Fatal ( err )
}
2016-04-25 16:13:12 +00:00
// verify it
2016-04-25 14:40:05 +00:00
if ! strings . Contains ( val , "i=" ) {
t . Fatalf ( "missing instance ID in role tag plaintext value" )
}
2016-05-10 02:07:46 +00:00
rTag . MaxTTL = 200000000000
2016-04-25 16:13:12 +00:00
// create the role tag with max_ttl specified
2016-04-25 14:40:05 +00:00
val , err = prepareRoleTagPlaintextValue ( rTag )
if err != nil {
t . Fatal ( err )
}
2016-04-25 16:13:12 +00:00
// verify it
2016-04-25 14:40:05 +00:00
if ! strings . Contains ( val , "t=" ) {
2016-05-10 02:07:46 +00:00
t . Fatalf ( "missing max_ttl field in role tag plaintext value" )
2016-04-25 14:40:05 +00:00
}
}
func TestBackend_CreateRoleTagNonce ( t * testing . T ) {
2016-04-25 16:13:12 +00:00
// create a nonce for the role tag
2016-04-25 14:40:05 +00:00
nonce , err := createRoleTagNonce ( )
if err != nil {
t . Fatal ( err )
}
if nonce == "" {
t . Fatalf ( "failed to create role tag nonce" )
}
2016-04-25 16:13:12 +00:00
// verify that the value returned is base64 encoded
2016-04-25 14:40:05 +00:00
nonceBytes , err := base64 . StdEncoding . DecodeString ( nonce )
if err != nil {
t . Fatal ( err )
}
if len ( nonceBytes ) == 0 {
t . Fatalf ( "length of role tag nonce is zero" )
}
}
2016-04-25 11:19:30 +00:00
func TestBackend_ConfigTidyIdentities ( t * testing . T ) {
2016-04-25 16:13:12 +00:00
// create a backend
2016-04-25 11:19:30 +00:00
config := logical . TestBackendConfig ( )
storage := & logical . InmemStorage { }
config . StorageView = storage
2016-06-01 16:17:47 +00:00
b , err := Backend ( config )
2016-05-10 02:07:46 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2016-04-25 11:19:30 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-27 03:40:11 +00:00
// test update operation
tidyRequest := & logical . Request {
2016-04-25 11:19:30 +00:00
Operation : logical . UpdateOperation ,
2016-05-10 02:07:46 +00:00
Path : "config/tidy/identity-whitelist" ,
2016-04-25 11:19:30 +00:00
Storage : storage ,
2016-04-27 03:40:11 +00:00
}
data := map [ string ] interface { } {
"safety_buffer" : "60" ,
"disable_periodic_tidy" : true ,
}
tidyRequest . Data = data
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , tidyRequest )
2016-04-25 11:19:30 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-27 03:40:11 +00:00
// test read operation
tidyRequest . Operation = logical . ReadOperation
2018-01-08 18:31:38 +00:00
resp , err := b . HandleRequest ( context . Background ( ) , tidyRequest )
2016-04-27 03:40:11 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . IsError ( ) {
2016-05-10 02:07:46 +00:00
t . Fatalf ( "failed to read config/tidy/identity-whitelist endpoint" )
2016-04-27 03:40:11 +00:00
}
if resp . Data [ "safety_buffer" ] . ( int ) != 60 || ! resp . Data [ "disable_periodic_tidy" ] . ( bool ) {
2018-02-05 19:26:31 +00:00
t . Fatalf ( "bad: expected: safety_buffer:60 disable_periodic_tidy:true actual: safety_buffer:%d disable_periodic_tidy:%t\n" , resp . Data [ "safety_buffer" ] . ( int ) , resp . Data [ "disable_periodic_tidy" ] . ( bool ) )
2016-04-27 03:40:11 +00:00
}
// test delete operation
tidyRequest . Operation = logical . DeleteOperation
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , tidyRequest )
2016-04-27 03:40:11 +00:00
if err != nil {
t . Fatal ( err )
}
if resp != nil {
2016-05-10 02:07:46 +00:00
t . Fatalf ( "failed to delete config/tidy/identity-whitelist" )
2016-04-27 03:40:11 +00:00
}
2016-04-25 11:19:30 +00:00
}
func TestBackend_ConfigTidyRoleTags ( t * testing . T ) {
config := logical . TestBackendConfig ( )
storage := & logical . InmemStorage { }
config . StorageView = storage
2016-06-01 16:17:47 +00:00
b , err := Backend ( config )
2016-05-10 02:07:46 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2016-04-25 11:19:30 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-27 03:40:11 +00:00
// test update operation
tidyRequest := & logical . Request {
2016-04-25 11:19:30 +00:00
Operation : logical . UpdateOperation ,
2016-05-10 02:07:46 +00:00
Path : "config/tidy/roletag-blacklist" ,
2016-04-25 11:19:30 +00:00
Storage : storage ,
2016-04-27 03:40:11 +00:00
}
data := map [ string ] interface { } {
"safety_buffer" : "60" ,
"disable_periodic_tidy" : true ,
}
tidyRequest . Data = data
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , tidyRequest )
2016-04-25 11:19:30 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-25 16:13:12 +00:00
2016-04-27 03:40:11 +00:00
// test read operation
tidyRequest . Operation = logical . ReadOperation
2018-01-08 18:31:38 +00:00
resp , err := b . HandleRequest ( context . Background ( ) , tidyRequest )
2016-04-27 03:40:11 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . IsError ( ) {
2016-05-10 02:07:46 +00:00
t . Fatalf ( "failed to read config/tidy/roletag-blacklist endpoint" )
2016-04-27 03:40:11 +00:00
}
if resp . Data [ "safety_buffer" ] . ( int ) != 60 || ! resp . Data [ "disable_periodic_tidy" ] . ( bool ) {
2018-02-05 19:26:31 +00:00
t . Fatalf ( "bad: expected: safety_buffer:60 disable_periodic_tidy:true actual: safety_buffer:%d disable_periodic_tidy:%t\n" , resp . Data [ "safety_buffer" ] . ( int ) , resp . Data [ "disable_periodic_tidy" ] . ( bool ) )
2016-04-27 03:40:11 +00:00
}
// test delete operation
tidyRequest . Operation = logical . DeleteOperation
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , tidyRequest )
2016-04-25 16:13:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-27 03:40:11 +00:00
if resp != nil {
2016-05-10 02:07:46 +00:00
t . Fatalf ( "failed to delete config/tidy/roletag-blacklist" )
2016-04-27 03:40:11 +00:00
}
2016-04-25 11:19:30 +00:00
}
func TestBackend_TidyIdentities ( t * testing . T ) {
config := logical . TestBackendConfig ( )
storage := & logical . InmemStorage { }
config . StorageView = storage
2016-06-01 16:17:47 +00:00
b , err := Backend ( config )
2016-05-10 02:07:46 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2016-04-25 11:19:30 +00:00
if err != nil {
t . Fatal ( err )
}
2018-06-20 00:58:12 +00:00
expiredIdentityWhitelist := & whitelistIdentity {
ExpirationTime : time . Now ( ) . Add ( - 1 * 24 * 365 * time . Hour ) ,
}
entry , err := logical . StorageEntryJSON ( "whitelist/identity/id1" , expiredIdentityWhitelist )
if err != nil {
t . Fatal ( err )
}
if err := storage . Put ( context . Background ( ) , entry ) ; err != nil {
t . Fatal ( err )
}
2016-04-27 03:40:11 +00:00
// test update operation
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-25 11:19:30 +00:00
Operation : logical . UpdateOperation ,
2016-05-12 11:19:29 +00:00
Path : "tidy/identity-whitelist" ,
2016-04-25 11:19:30 +00:00
Storage : storage ,
} )
if err != nil {
t . Fatal ( err )
}
2018-06-20 00:58:12 +00:00
// let tidy finish in the background
time . Sleep ( 1 * time . Second )
entry , err = storage . Get ( context . Background ( ) , "whitelist/identity/id1" )
if err != nil {
t . Fatal ( err )
}
if entry != nil {
t . Fatal ( "wl tidy did not remove expired entry" )
}
2016-04-25 11:19:30 +00:00
}
func TestBackend_TidyRoleTags ( t * testing . T ) {
config := logical . TestBackendConfig ( )
storage := & logical . InmemStorage { }
config . StorageView = storage
2016-06-01 16:17:47 +00:00
b , err := Backend ( config )
2016-05-10 02:07:46 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2016-04-25 11:19:30 +00:00
if err != nil {
t . Fatal ( err )
}
2018-06-20 00:58:12 +00:00
expiredIdentityWhitelist := & roleTagBlacklistEntry {
ExpirationTime : time . Now ( ) . Add ( - 1 * 24 * 365 * time . Hour ) ,
}
entry , err := logical . StorageEntryJSON ( "blacklist/roletag/id1" , expiredIdentityWhitelist )
if err != nil {
t . Fatal ( err )
}
if err := storage . Put ( context . Background ( ) , entry ) ; err != nil {
t . Fatal ( err )
}
2016-04-27 03:40:11 +00:00
// test update operation
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-25 11:19:30 +00:00
Operation : logical . UpdateOperation ,
2016-05-12 11:19:29 +00:00
Path : "tidy/roletag-blacklist" ,
2016-04-25 11:19:30 +00:00
Storage : storage ,
} )
if err != nil {
t . Fatal ( err )
}
2018-06-20 00:58:12 +00:00
// let tidy finish in the background
time . Sleep ( 1 * time . Second )
entry , err = storage . Get ( context . Background ( ) , "blacklist/roletag/id1" )
if err != nil {
t . Fatal ( err )
}
if entry != nil {
t . Fatal ( "bl tidy did not remove expired entry" )
}
2016-04-25 11:19:30 +00:00
}
2016-04-06 00:42:26 +00:00
func TestBackend_ConfigClient ( t * testing . T ) {
config := logical . TestBackendConfig ( )
2016-04-06 23:25:35 +00:00
storage := & logical . InmemStorage { }
config . StorageView = storage
2016-04-06 00:42:26 +00:00
2016-06-01 16:17:47 +00:00
b , err := Backend ( config )
2016-05-10 02:07:46 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2016-04-06 00:42:26 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-06 16:27:47 +00:00
data := map [ string ] interface { } { "access_key" : "AKIAJBRHKV6EVTTNXDHA" ,
"secret_key" : "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" ,
}
stepCreate := logicaltest . TestStep {
Operation : logical . CreateOperation ,
Path : "config/client" ,
Data : data ,
}
stepUpdate := logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "config/client" ,
Data : data ,
}
data3 := map [ string ] interface { } { "access_key" : "" ,
"secret_key" : "mCtSM8ZUEQ3mOFVZYPBQkf2sO6F/W7a5TVzrl3Oj" ,
}
stepInvalidAccessKey := logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "config/client" ,
Data : data3 ,
ErrorOk : true ,
}
data4 := map [ string ] interface { } { "access_key" : "accesskey" ,
"secret_key" : "" ,
}
stepInvalidSecretKey := logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "config/client" ,
Data : data4 ,
ErrorOk : true ,
}
2016-04-06 00:42:26 +00:00
logicaltest . Test ( t , logicaltest . TestCase {
2018-11-07 01:21:24 +00:00
AcceptanceTest : false ,
CredentialBackend : b ,
2016-04-06 16:27:47 +00:00
Steps : [ ] logicaltest . TestStep {
stepCreate ,
stepInvalidAccessKey ,
stepInvalidSecretKey ,
stepUpdate ,
} ,
2016-04-06 00:42:26 +00:00
} )
2016-04-06 16:27:47 +00:00
2016-04-27 03:40:11 +00:00
// test existence check returning false
2018-01-08 18:31:38 +00:00
checkFound , exists , err := b . HandleExistenceCheck ( context . Background ( ) , & logical . Request {
2016-04-07 00:59:05 +00:00
Operation : logical . CreateOperation ,
Path : "config/client" ,
Storage : storage ,
} )
if err != nil {
t . Fatal ( err )
}
if ! checkFound {
t . Fatal ( "existence check not found for path 'config/client'" )
}
if exists {
2016-04-07 15:26:10 +00:00
t . Fatal ( "existence check should have returned 'false' for 'config/client'" )
2016-04-07 00:59:05 +00:00
}
2016-04-27 03:40:11 +00:00
// create an entry
2016-04-06 16:27:47 +00:00
configClientCreateRequest := & logical . Request {
Operation : logical . UpdateOperation ,
Path : "config/client" ,
Data : data ,
2016-04-06 23:25:35 +00:00
Storage : storage ,
2016-04-06 16:27:47 +00:00
}
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , configClientCreateRequest )
2016-04-06 16:27:47 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-27 03:40:11 +00:00
//test existence check returning true
2018-01-08 18:31:38 +00:00
checkFound , exists , err = b . HandleExistenceCheck ( context . Background ( ) , & logical . Request {
2016-04-07 00:59:05 +00:00
Operation : logical . CreateOperation ,
Path : "config/client" ,
Storage : storage ,
} )
if err != nil {
t . Fatal ( err )
}
if ! checkFound {
t . Fatal ( "existence check not found for path 'config/client'" )
}
if ! exists {
2016-04-07 15:26:10 +00:00
t . Fatal ( "existence check should have returned 'true' for 'config/client'" )
2016-04-07 00:59:05 +00:00
}
2016-05-02 21:21:52 +00:00
endpointData := map [ string ] interface { } {
"secret_key" : "secretkey" ,
"access_key" : "accesskey" ,
"endpoint" : "endpointvalue" ,
}
endpointReq := & logical . Request {
Operation : logical . UpdateOperation ,
Path : "config/client" ,
Storage : storage ,
Data : endpointData ,
}
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , endpointReq )
2016-05-02 21:21:52 +00:00
if err != nil {
t . Fatal ( err )
}
endpointReq . Operation = logical . ReadOperation
2018-01-08 18:31:38 +00:00
resp , err := b . HandleRequest ( context . Background ( ) , endpointReq )
2016-05-02 21:21:52 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil ||
resp . IsError ( ) {
t . Fatalf ( "" )
}
actual := resp . Data [ "endpoint" ] . ( string )
if actual != "endpointvalue" {
t . Fatalf ( "bad: endpoint: expected:endpointvalue actual:%s\n" , actual )
}
2016-04-06 00:42:26 +00:00
}
2016-04-27 03:40:11 +00:00
func TestBackend_pathConfigCertificate ( t * testing . T ) {
2016-04-07 15:26:10 +00:00
config := logical . TestBackendConfig ( )
storage := & logical . InmemStorage { }
config . StorageView = storage
2016-06-01 16:17:47 +00:00
b , err := Backend ( config )
2016-05-10 02:07:46 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2016-04-07 15:26:10 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-27 03:40:11 +00:00
certReq := & logical . Request {
2016-04-07 15:26:10 +00:00
Operation : logical . CreateOperation ,
Storage : storage ,
2016-04-27 03:40:11 +00:00
Path : "config/certificate/cert1" ,
}
2018-01-08 18:31:38 +00:00
checkFound , exists , err := b . HandleExistenceCheck ( context . Background ( ) , certReq )
2016-04-07 15:26:10 +00:00
if err != nil {
t . Fatal ( err )
}
if ! checkFound {
2016-04-14 16:42:18 +00:00
t . Fatal ( "existence check not found for path 'config/certificate/cert1'" )
2016-04-07 15:26:10 +00:00
}
if exists {
2016-04-14 16:42:18 +00:00
t . Fatal ( "existence check should have returned 'false' for 'config/certificate/cert1'" )
2016-04-07 15:26:10 +00:00
}
data := map [ string ] interface { } {
2016-10-04 00:25:07 +00:00
"type" : "pkcs7" ,
2016-04-07 15:26:10 +00:00
"aws_public_cert" : ` LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM3VENDQXEwQ0NRQ1d1a2paNVY0YVp6QUpC
Z2NxaGtqT09BUURNRnd4Q3pBSkJnTlZCQVlUQWxWVE1Sa3cKRndZRFZRUUlFeEJYWVhOb2FXNW5k
Rzl1SUZOMFlYUmxNUkF3RGdZRFZRUUhFd2RUWldGMGRHeGxNU0F3SGdZRApWUVFLRXhkQmJXRjZi
MjRnVjJWaUlGTmxjblpwWTJWeklFeE1RekFlRncweE1qQXhNRFV4TWpVMk1USmFGdzB6Ck9EQXhN
RFV4TWpVMk1USmFNRnd4Q3pBSkJnTlZCQVlUQWxWVE1Sa3dGd1lEVlFRSUV4QlhZWE5vYVc1bmRH
OXUKSUZOMFlYUmxNUkF3RGdZRFZRUUhFd2RUWldGMGRHeGxNU0F3SGdZRFZRUUtFeGRCYldGNmIy
NGdWMlZpSUZObApjblpwWTJWeklFeE1RekNDQWJjd2dnRXNCZ2NxaGtqT09BUUJNSUlCSHdLQmdR
Q2prdmNTMmJiMVZRNHl0LzVlCmloNU9PNmtLL24xTHpsbHI3RDhad3RRUDhmT0VwcDVFMm5nK0Q2
VWQxWjFnWWlwcjU4S2ozbnNzU05wSTZiWDMKVnlJUXpLN3dMY2xuZC9Zb3pxTk5tZ0l5WmVjTjdF
Z2xLOUlUSEpMUCt4OEZ0VXB0M1FieVlYSmRtVk1lZ042UApodmlZdDVKSC9uWWw0aGgzUGExSEpk
c2tnUUlWQUxWSjNFUjExK0tvNHRQNm53dkh3aDYrRVJZUkFvR0JBSTFqCmsrdGtxTVZIdUFGY3ZB
R0tvY1Rnc2pKZW02LzVxb216SnVLRG1iSk51OVF4dzNyQW90WGF1OFFlK01CY0psL1UKaGh5MUtI
VnBDR2w5ZnVlUTJzNklMMENhTy9idXljVTFDaVlRazQwS05IQ2NIZk5pWmJkbHgxRTlycFVwN2Ju
RgpsUmEydjFudE1YM2NhUlZEZGJ0UEVXbWR4U0NZc1lGRGs0bVpyT0xCQTRHRUFBS0JnRWJtZXZl
NWY4TElFL0dmCk1ObVA5Q001ZW92UU9HeDVobzhXcUQrYVRlYnMrazJ0bjkyQkJQcWVacXBXUmE1
UC8ranJkS21sMXF4NGxsSFcKTVhyczNJZ0liNitoVUlCK1M4ZHo4L21tTzBicHI3NlJvWlZDWFlh
YjJDWmVkRnV0N3FjM1dVSDkrRVVBSDVtdwp2U2VEQ09VTVlRUjdSOUxJTll3b3VISXppcVFZTUFr
R0J5cUdTTTQ0QkFNREx3QXdMQUlVV1hCbGs0MHhUd1N3CjdIWDMyTXhYWXJ1c2U5QUNGQk5HbWRY
MlpCclZOR3JOOU4yZjZST2swazlLCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
` ,
}
2016-04-27 03:40:11 +00:00
certReq . Data = data
// test create operation
2018-01-08 18:31:38 +00:00
resp , err := b . HandleRequest ( context . Background ( ) , certReq )
2016-10-04 00:25:07 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "resp: %#v, err: %v" , resp , err )
2016-04-07 15:26:10 +00:00
}
2016-04-27 03:40:11 +00:00
certReq . Data = nil
// test existence check
2018-01-08 18:31:38 +00:00
checkFound , exists , err = b . HandleExistenceCheck ( context . Background ( ) , certReq )
2016-04-07 15:26:10 +00:00
if err != nil {
t . Fatal ( err )
}
if ! checkFound {
2016-04-14 16:42:18 +00:00
t . Fatal ( "existence check not found for path 'config/certificate/cert1'" )
2016-04-07 15:26:10 +00:00
}
if ! exists {
2016-04-14 16:42:18 +00:00
t . Fatal ( "existence check should have returned 'true' for 'config/certificate/cert1'" )
2016-04-07 15:26:10 +00:00
}
2016-04-27 03:40:11 +00:00
certReq . Operation = logical . ReadOperation
// test read operation
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , certReq )
2017-07-07 12:23:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-07 15:26:10 +00:00
expectedCert := ` -- -- - BEGIN CERTIFICATE -- -- -
MIIC7TCCAq0CCQCWukjZ5V4aZzAJBgcqhkjOOAQDMFwxCzAJBgNVBAYTAlVTMRkw
FwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYD
VQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAeFw0xMjAxMDUxMjU2MTJaFw0z
ODAxMDUxMjU2MTJaMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9u
IFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNl
cnZpY2VzIExMQzCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQCjkvcS2bb1VQ4yt / 5 e
ih5OO6kK / n1Lzllr7D8ZwtQP8fOEpp5E2ng + D6Ud1Z1gYipr58Kj3nssSNpI6bX3
VyIQzK7wLclnd / YozqNNmgIyZecN7EglK9ITHJLP + x8FtUpt3QbyYXJdmVMegN6P
hviYt5JH / nYl4hh3Pa1HJdskgQIVALVJ3ER11 + Ko4tP6nwvHwh6 + ERYRAoGBAI1j
k + tkqMVHuAFcvAGKocTgsjJem6 / 5 qomzJuKDmbJNu9Qxw3rAotXau8Qe + MBcJl / U
hhy1KHVpCGl9fueQ2s6IL0CaO / buycU1CiYQk40KNHCcHfNiZbdlx1E9rpUp7bnF
lRa2v1ntMX3caRVDdbtPEWmdxSCYsYFDk4mZrOLBA4GEAAKBgEbmeve5f8LIE / Gf
MNmP9CM5eovQOGx5ho8WqD + aTebs + k2tn92BBPqeZqpWRa5P / + jrdKml1qx4llHW
MXrs3IgIb6 + hUIB + S8dz8 / mmO0bpr76RoZVCXYab2CZedFut7qc3WUH9 + EUAH5mw
vSeDCOUMYQR7R9LINYwouHIziqQYMAkGByqGSM44BAMDLwAwLAIUWXBlk40xTwSw
7 HX32MxXYruse9ACFBNGmdX2ZBrVNGrN9N2f6ROk0k9K
-- -- - END CERTIFICATE -- -- -
`
if resp . Data [ "aws_public_cert" ] . ( string ) != expectedCert {
2016-12-21 18:08:27 +00:00
t . Fatalf ( "bad: expected:%s\n got:%s\n" , expectedCert , resp . Data [ "aws_public_cert" ] . ( string ) )
2016-04-07 15:26:10 +00:00
}
2016-04-27 03:40:11 +00:00
certReq . Operation = logical . CreateOperation
certReq . Path = "config/certificate/cert2"
certReq . Data = data
// create another entry to test the list operation
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , certReq )
2016-04-27 03:40:11 +00:00
if err != nil {
t . Fatal ( err )
}
certReq . Operation = logical . ListOperation
certReq . Path = "config/certificates"
// test list operation
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , certReq )
2016-04-27 03:40:11 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . IsError ( ) {
t . Fatalf ( "failed to list config/certificates" )
}
keys := resp . Data [ "keys" ] . ( [ ] string )
if len ( keys ) != 2 {
t . Fatalf ( "invalid keys listed: %#v\n" , keys )
}
certReq . Operation = logical . DeleteOperation
certReq . Path = "config/certificate/cert1"
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , certReq )
2016-04-27 03:40:11 +00:00
if err != nil {
t . Fatal ( err )
}
certReq . Path = "config/certificate/cert2"
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , certReq )
2016-04-27 03:40:11 +00:00
if err != nil {
t . Fatal ( err )
}
certReq . Operation = logical . ListOperation
certReq . Path = "config/certificates"
// test list operation
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , certReq )
2016-04-27 03:40:11 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . IsError ( ) {
t . Fatalf ( "failed to list config/certificates" )
}
if resp . Data [ "keys" ] != nil {
t . Fatalf ( "no entries should be present" )
}
2016-04-07 00:59:05 +00:00
}
2016-04-28 01:29:32 +00:00
func TestBackend_parseAndVerifyRoleTagValue ( t * testing . T ) {
2016-04-25 14:40:05 +00:00
// create a backend
2016-04-08 18:56:27 +00:00
config := logical . TestBackendConfig ( )
storage := & logical . InmemStorage { }
config . StorageView = storage
2016-06-01 16:17:47 +00:00
b , err := Backend ( config )
2016-05-10 02:07:46 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2016-04-06 00:42:26 +00:00
if err != nil {
2016-04-08 18:56:27 +00:00
t . Fatal ( err )
2016-04-06 00:42:26 +00:00
}
2016-04-08 18:56:27 +00:00
2016-05-03 16:14:07 +00:00
// create a role
2016-04-08 18:56:27 +00:00
data := map [ string ] interface { } {
2017-04-24 19:15:50 +00:00
"auth_type" : "ec2" ,
2016-05-03 16:14:07 +00:00
"policies" : "p,q,r,s" ,
"max_ttl" : "120s" ,
"role_tag" : "VaultRole" ,
"bound_ami_id" : "abcd-123" ,
2016-04-08 18:56:27 +00:00
}
2018-01-08 18:31:38 +00:00
resp , err := b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-08 18:56:27 +00:00
Operation : logical . CreateOperation ,
2016-05-03 16:14:07 +00:00
Path : "role/abcd-123" ,
2016-04-08 18:56:27 +00:00
Storage : storage ,
Data : data ,
} )
2016-05-03 16:14:07 +00:00
if resp != nil && resp . IsError ( ) {
t . Fatalf ( "failed to create role" )
}
2016-04-08 18:56:27 +00:00
if err != nil {
t . Fatal ( err )
2016-04-06 00:42:26 +00:00
}
2016-04-25 14:40:05 +00:00
// verify that the entry is created
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-08 18:56:27 +00:00
Operation : logical . ReadOperation ,
2016-05-03 16:14:07 +00:00
Path : "role/abcd-123" ,
2016-04-08 18:56:27 +00:00
Storage : storage ,
} )
2017-07-07 12:23:12 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-08 18:56:27 +00:00
if resp == nil {
2016-05-03 16:14:07 +00:00
t . Fatalf ( "expected an role entry for abcd-123" )
2016-04-06 00:42:26 +00:00
}
2016-04-25 14:40:05 +00:00
// create a role tag
2016-04-08 18:56:27 +00:00
data2 := map [ string ] interface { } {
"policies" : "p,q,r,s" ,
2016-04-06 00:42:26 +00:00
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-08 18:56:27 +00:00
Operation : logical . UpdateOperation ,
2016-05-03 16:14:07 +00:00
Path : "role/abcd-123/tag" ,
2016-04-08 18:56:27 +00:00
Storage : storage ,
Data : data2 ,
} )
2016-04-06 00:42:26 +00:00
if err != nil {
2016-04-08 18:56:27 +00:00
t . Fatal ( err )
}
if resp . Data [ "tag_key" ] . ( string ) == "" ||
resp . Data [ "tag_value" ] . ( string ) == "" {
t . Fatalf ( "invalid tag response: %#v\n" , resp )
2016-04-06 00:42:26 +00:00
}
2016-04-08 18:56:27 +00:00
tagValue := resp . Data [ "tag_value" ] . ( string )
2016-04-06 00:42:26 +00:00
2016-04-25 14:40:05 +00:00
// parse the value and check if the verifiable values match
2018-01-19 06:44:44 +00:00
rTag , err := b . parseAndVerifyRoleTagValue ( context . Background ( ) , storage , tagValue )
2016-04-08 18:56:27 +00:00
if err != nil {
t . Fatalf ( "err: %s" , err )
}
if rTag == nil {
t . Fatalf ( "failed to parse role tag" )
}
if rTag . Version != "v1" ||
! policyutil . EquivalentPolicies ( rTag . Policies , [ ] string { "p" , "q" , "r" , "s" } ) ||
2016-05-13 18:31:13 +00:00
rTag . Role != "abcd-123" {
2016-04-08 18:56:27 +00:00
t . Fatalf ( "bad: parsed role tag contains incorrect values. Got: %#v\n" , rTag )
2016-04-06 00:42:26 +00:00
}
}
2016-04-08 19:43:24 +00:00
2016-05-03 16:14:07 +00:00
func TestBackend_PathRoleTag ( t * testing . T ) {
2016-04-08 19:43:24 +00:00
config := logical . TestBackendConfig ( )
storage := & logical . InmemStorage { }
config . StorageView = storage
2016-06-01 16:17:47 +00:00
b , err := Backend ( config )
2016-05-10 02:07:46 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2016-04-08 19:43:24 +00:00
if err != nil {
t . Fatal ( err )
}
data := map [ string ] interface { } {
2017-04-24 19:15:50 +00:00
"auth_type" : "ec2" ,
2016-05-03 16:14:07 +00:00
"policies" : "p,q,r,s" ,
"max_ttl" : "120s" ,
"role_tag" : "VaultRole" ,
"bound_ami_id" : "abcd-123" ,
2016-04-08 19:43:24 +00:00
}
2018-01-08 18:31:38 +00:00
resp , err := b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-08 19:43:24 +00:00
Operation : logical . CreateOperation ,
2016-05-03 16:14:07 +00:00
Path : "role/abcd-123" ,
2016-04-08 19:43:24 +00:00
Storage : storage ,
Data : data ,
} )
2016-05-03 16:14:07 +00:00
if resp != nil && resp . IsError ( ) {
t . Fatalf ( "failed to create role" )
}
2016-04-08 19:43:24 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-08 19:43:24 +00:00
Operation : logical . ReadOperation ,
2016-05-03 16:14:07 +00:00
Path : "role/abcd-123" ,
2016-04-08 19:43:24 +00:00
Storage : storage ,
} )
if err != nil {
t . Fatal ( err )
}
if resp == nil {
2016-05-03 16:14:07 +00:00
t . Fatalf ( "failed to find a role entry for abcd-123" )
2016-04-08 19:43:24 +00:00
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-08 19:43:24 +00:00
Operation : logical . UpdateOperation ,
2016-05-03 16:14:07 +00:00
Path : "role/abcd-123/tag" ,
2016-04-08 19:43:24 +00:00
Storage : storage ,
} )
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . Data == nil {
2016-05-03 16:14:07 +00:00
t . Fatalf ( "failed to create a tag on role: abcd-123" )
2016-04-08 19:43:24 +00:00
}
if resp . IsError ( ) {
2016-05-03 16:14:07 +00:00
t . Fatalf ( "failed to create a tag on role: abcd-123: %s\n" , resp . Data [ "error" ] )
2016-04-08 19:43:24 +00:00
}
if resp . Data [ "tag_value" ] . ( string ) == "" {
t . Fatalf ( "role tag not present in the response data: %#v\n" , resp . Data )
}
}
2016-04-11 20:18:41 +00:00
func TestBackend_PathBlacklistRoleTag ( t * testing . T ) {
2016-04-25 11:19:30 +00:00
// create the backend
2016-04-11 20:18:41 +00:00
storage := & logical . InmemStorage { }
config := logical . TestBackendConfig ( )
config . StorageView = storage
2016-06-01 16:17:47 +00:00
b , err := Backend ( config )
2016-05-10 02:07:46 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2016-04-11 20:18:41 +00:00
if err != nil {
t . Fatal ( err )
}
2016-05-03 16:14:07 +00:00
// create an role entry
2016-04-11 20:18:41 +00:00
data := map [ string ] interface { } {
2017-04-24 19:15:50 +00:00
"auth_type" : "ec2" ,
2016-05-03 16:14:07 +00:00
"policies" : "p,q,r,s" ,
"role_tag" : "VaultRole" ,
"bound_ami_id" : "abcd-123" ,
2016-04-11 20:18:41 +00:00
}
2018-01-08 18:31:38 +00:00
resp , err := b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-11 20:18:41 +00:00
Operation : logical . CreateOperation ,
2016-05-03 16:14:07 +00:00
Path : "role/abcd-123" ,
2016-04-11 20:18:41 +00:00
Storage : storage ,
Data : data ,
} )
2016-05-03 16:14:07 +00:00
if resp != nil && resp . IsError ( ) {
t . Fatalf ( "failed to create role" )
}
2016-04-11 20:18:41 +00:00
if err != nil {
t . Fatal ( err )
}
2016-05-03 16:14:07 +00:00
// create a role tag against an role registered before
2016-04-11 20:18:41 +00:00
data2 := map [ string ] interface { } {
"policies" : "p,q,r,s" ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-11 20:18:41 +00:00
Operation : logical . UpdateOperation ,
2016-05-03 16:14:07 +00:00
Path : "role/abcd-123/tag" ,
2016-04-11 20:18:41 +00:00
Storage : storage ,
Data : data2 ,
} )
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . Data == nil {
2016-05-03 16:14:07 +00:00
t . Fatalf ( "failed to create a tag on role: abcd-123" )
2016-04-11 20:18:41 +00:00
}
if resp . IsError ( ) {
2016-05-03 16:14:07 +00:00
t . Fatalf ( "failed to create a tag on role: abcd-123: %s\n" , resp . Data [ "error" ] )
2016-04-11 20:18:41 +00:00
}
tag := resp . Data [ "tag_value" ] . ( string )
if tag == "" {
t . Fatalf ( "role tag not present in the response data: %#v\n" , resp . Data )
}
2016-04-25 11:19:30 +00:00
// blacklist that role tag
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-11 20:18:41 +00:00
Operation : logical . UpdateOperation ,
2016-05-10 02:07:46 +00:00
Path : "roletag-blacklist/" + tag ,
2016-04-11 20:18:41 +00:00
Storage : storage ,
} )
if err != nil {
t . Fatal ( err )
}
if resp != nil {
t . Fatalf ( "failed to blacklist the roletag: %s\n" , tag )
}
2016-04-25 11:19:30 +00:00
// read the blacklist entry
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-11 20:18:41 +00:00
Operation : logical . ReadOperation ,
2016-05-10 02:07:46 +00:00
Path : "roletag-blacklist/" + tag ,
2016-04-11 20:18:41 +00:00
Storage : storage ,
} )
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . Data == nil {
t . Fatalf ( "failed to read the blacklisted role tag: %s\n" , tag )
}
if resp . IsError ( ) {
t . Fatalf ( "failed to read the blacklisted role tag:%s. Err: %s\n" , tag , resp . Data [ "error" ] )
}
2016-04-25 11:19:30 +00:00
// delete the blacklisted entry
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-11 20:18:41 +00:00
Operation : logical . DeleteOperation ,
2016-05-10 02:07:46 +00:00
Path : "roletag-blacklist/" + tag ,
2016-04-11 20:18:41 +00:00
Storage : storage ,
} )
if err != nil {
t . Fatal ( err )
}
2016-04-25 11:19:30 +00:00
// try to read the deleted entry
2018-01-19 06:44:44 +00:00
tagEntry , err := b . lockedBlacklistRoleTagEntry ( context . Background ( ) , storage , tag )
2016-04-11 20:18:41 +00:00
if err != nil {
t . Fatal ( err )
}
if tagEntry != nil {
t . Fatalf ( "role tag should not have been present: %s\n" , tag )
}
}
2016-04-11 23:21:53 +00:00
2018-02-23 01:55:45 +00:00
/ * This is an acceptance test .
Requires the following env vars :
TEST_AWS_EC2_PKCS7
TEST_AWS_EC2_IDENTITY_DOCUMENT
TEST_AWS_EC2_IDENTITY_DOCUMENT_SIG
TEST_AWS_EC2_AMI_ID
TEST_AWS_EC2_ACCOUNT_ID
TEST_AWS_EC2_IAM_ROLE_ARN
If this is being run on an EC2 instance , you can set the environment vars using this bash snippet :
export TEST_AWS_EC2_PKCS7 = $ ( curl - s http : //169.254.169.254/latest/dynamic/instance-identity/pkcs7)
export TEST_AWS_EC2_IDENTITY_DOCUMENT = $ ( curl - s http : //169.254.169.254/latest/dynamic/instance-identity/document | base64 -w 0)
export TEST_AWS_EC2_IDENTITY_DOCUMENT_SIG = $ ( curl - s http : //169.254.169.254/latest/dynamic/instance-identity/signature | tr -d '\n')
export TEST_AWS_EC2_AMI_ID = $ ( curl - s http : //169.254.169.254/latest/meta-data/ami-id)
export TEST_AWS_EC2_IAM_ROLE_ARN = $ ( aws iam get - role -- role - name $ ( curl - q http : //169.254.169.254/latest/meta-data/iam/security-credentials/ -S -s) --query Role.Arn --output text)
export TEST_AWS_EC2_ACCOUNT_ID = $ ( aws sts get - caller - identity -- query Account -- output text )
If the test is not being run on an EC2 instance that has access to
credentials using EC2RoleProvider , on top of the above vars , following
needs to be set :
TEST_AWS_SECRET_KEY
TEST_AWS_ACCESS_KEY
* /
2017-04-24 19:15:50 +00:00
func TestBackendAcc_LoginWithInstanceIdentityDocAndWhitelistIdentity ( t * testing . T ) {
2016-04-27 03:40:11 +00:00
// This test case should be run only when certain env vars are set and
// executed as an acceptance test.
2016-04-11 23:21:53 +00:00
if os . Getenv ( logicaltest . TestEnvVar ) == "" {
t . Skip ( fmt . Sprintf ( "Acceptance tests skipped unless env '%s' set" , logicaltest . TestEnvVar ) )
return
}
2016-04-27 03:40:11 +00:00
pkcs7 := os . Getenv ( "TEST_AWS_EC2_PKCS7" )
if pkcs7 == "" {
2018-04-13 14:18:06 +00:00
t . Skipf ( "env var TEST_AWS_EC2_PKCS7 not set, skipping test" )
2016-04-27 03:40:11 +00:00
}
2018-02-23 01:55:45 +00:00
identityDoc := os . Getenv ( "TEST_AWS_EC2_IDENTITY_DOCUMENT" )
if identityDoc == "" {
2018-04-13 14:18:06 +00:00
t . Skipf ( "env var TEST_AWS_EC2_IDENTITY_DOCUMENT not set, skipping test" )
2018-02-23 01:55:45 +00:00
}
identityDocSig := os . Getenv ( "TEST_AWS_EC2_IDENTITY_DOCUMENT_SIG" )
if identityDocSig == "" {
2018-04-13 14:18:06 +00:00
t . Skipf ( "env var TEST_AWS_EC2_IDENTITY_DOCUMENT_SIG not set, skipping test" )
2018-02-23 01:55:45 +00:00
}
2016-04-27 03:40:11 +00:00
amiID := os . Getenv ( "TEST_AWS_EC2_AMI_ID" )
if amiID == "" {
2018-04-13 14:18:06 +00:00
t . Skipf ( "env var TEST_AWS_EC2_AMI_ID not set, skipping test" )
2016-04-27 03:40:11 +00:00
}
2016-06-14 16:58:50 +00:00
iamARN := os . Getenv ( "TEST_AWS_EC2_IAM_ROLE_ARN" )
if iamARN == "" {
2018-04-13 14:18:06 +00:00
t . Skipf ( "env var TEST_AWS_EC2_IAM_ROLE_ARN not set, skipping test" )
2016-06-14 16:58:50 +00:00
}
2016-06-14 15:58:19 +00:00
accountID := os . Getenv ( "TEST_AWS_EC2_ACCOUNT_ID" )
if accountID == "" {
2018-04-13 14:18:06 +00:00
t . Skipf ( "env var TEST_AWS_EC2_ACCOUNT_ID not set, skipping test" )
2016-06-14 15:58:19 +00:00
}
2016-05-03 16:14:07 +00:00
roleName := amiID
2016-04-25 14:40:05 +00:00
// create the backend
2016-04-11 23:21:53 +00:00
storage := & logical . InmemStorage { }
config := logical . TestBackendConfig ( )
config . StorageView = storage
2016-06-01 16:17:47 +00:00
b , err := Backend ( config )
2016-05-10 02:07:46 +00:00
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2016-04-11 23:21:53 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-27 03:40:11 +00:00
accessKey := os . Getenv ( "TEST_AWS_ACCESS_KEY" )
secretKey := os . Getenv ( "TEST_AWS_SECRET_KEY" )
2016-04-11 23:21:53 +00:00
2016-04-27 03:40:11 +00:00
// In case of problems with making API calls using the credentials (2FA enabled,
// for instance), the keys need not be set if the test is running on an EC2
// instance with permissions to get the credentials using EC2RoleProvider.
if accessKey != "" && secretKey != "" {
// get the API credentials from env vars
clientConfig := map [ string ] interface { } {
"access_key" : accessKey ,
"secret_key" : secretKey ,
}
if clientConfig [ "access_key" ] == "" ||
clientConfig [ "secret_key" ] == "" {
t . Fatalf ( "credentials not configured" )
}
// store the credentials
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , & logical . Request {
2016-04-27 03:40:11 +00:00
Operation : logical . UpdateOperation ,
Storage : storage ,
Path : "config/client" ,
Data : clientConfig ,
} )
if err != nil {
t . Fatal ( err )
}
2016-04-11 23:21:53 +00:00
}
2016-04-27 03:40:11 +00:00
loginInput := map [ string ] interface { } {
"pkcs7" : pkcs7 ,
2016-04-11 23:21:53 +00:00
"nonce" : "vault-client-nonce" ,
}
2018-03-15 16:19:28 +00:00
parsedIdentityDoc , err := b . parseIdentityDocument ( context . Background ( ) , storage , pkcs7 )
if err != nil {
t . Fatal ( err )
}
2016-06-13 12:56:39 +00:00
// Perform the login operation with a AMI ID that is not matching
// the bound on the role.
2016-04-11 23:21:53 +00:00
loginRequest := & logical . Request {
Operation : logical . UpdateOperation ,
Path : "login" ,
Storage : storage ,
Data : loginInput ,
}
2016-06-14 18:46:08 +00:00
2018-03-18 01:24:49 +00:00
// Baseline role data that should succeed permit login
2016-04-11 23:21:53 +00:00
data := map [ string ] interface { } {
2018-03-15 16:19:28 +00:00
"auth_type" : "ec2" ,
"policies" : "root" ,
"max_ttl" : "120s" ,
2018-03-18 01:24:49 +00:00
"bound_ami_id" : [ ] string { "wrong_ami_id" , amiID , "wrong_ami_id2" } ,
2018-03-15 16:19:28 +00:00
"bound_account_id" : accountID ,
"bound_iam_role_arn" : iamARN ,
"bound_ec2_instance_id" : [ ] string { parsedIdentityDoc . InstanceID , "i-1234567" } ,
2016-04-11 23:21:53 +00:00
}
2016-04-27 03:40:11 +00:00
2016-06-13 12:56:39 +00:00
roleReq := & logical . Request {
2017-04-24 19:15:50 +00:00
Operation : logical . CreateOperation ,
2016-05-03 16:14:07 +00:00
Path : "role/" + roleName ,
2016-04-11 23:21:53 +00:00
Storage : storage ,
Data : data ,
2016-06-13 12:56:39 +00:00
}
2018-03-18 01:24:49 +00:00
updateRoleExpectLoginFail := func ( roleRequest , loginRequest * logical . Request ) error {
resp , err := b . HandleRequest ( context . Background ( ) , roleRequest )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
return fmt . Errorf ( "bad: failed to create role: resp:%#v\nerr:%v" , resp , err )
}
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
if err != nil || resp == nil || ( resp != nil && ! resp . IsError ( ) ) {
return fmt . Errorf ( "bad: expected login failure: resp:%#v\nerr:%v" , resp , err )
}
return nil
2016-04-11 23:21:53 +00:00
}
2018-03-18 01:24:49 +00:00
// Test a role with the wrong AMI ID
data [ "bound_ami_id" ] = [ ] string { "ami-1234567" , "ami-7654321" }
if err := updateRoleExpectLoginFail ( roleReq , loginRequest ) ; err != nil {
t . Fatal ( err )
2016-06-13 12:56:39 +00:00
}
2017-04-24 19:15:50 +00:00
roleReq . Operation = logical . UpdateOperation
2018-03-18 01:24:49 +00:00
// Place the correct AMI ID in one of the values, but make the AccountID wrong
2018-03-02 16:09:14 +00:00
data [ "bound_ami_id" ] = [ ] string { "wrong_ami_id_1" , amiID , "wrong_ami_id_2" }
data [ "bound_account_id" ] = [ ] string { "wrong-account-id" , "wrong-account-id-2" }
2018-03-18 01:24:49 +00:00
if err := updateRoleExpectLoginFail ( roleReq , loginRequest ) ; err != nil {
t . Fatal ( err )
2016-04-11 23:21:53 +00:00
}
2016-06-14 15:58:19 +00:00
2018-03-02 16:09:14 +00:00
// Place the correct AccountID in one of the values, but make the wrong IAMRoleARN
data [ "bound_account_id" ] = [ ] string { "wrong-account-id-1" , accountID , "wrong-account-id-2" }
data [ "bound_iam_role_arn" ] = [ ] string { "wrong_iam_role_arn" , "wrong_iam_role_arn_2" }
2018-03-18 01:24:49 +00:00
if err := updateRoleExpectLoginFail ( roleReq , loginRequest ) ; err != nil {
t . Fatal ( err )
2016-06-14 18:17:41 +00:00
}
2018-03-18 01:24:49 +00:00
// Place correct IAM role ARN, but incorrect instance ID
2018-03-02 16:09:14 +00:00
data [ "bound_iam_role_arn" ] = [ ] string { "wrong_iam_role_arn_1" , iamARN , "wrong_iam_role_arn_2" }
2018-03-15 16:19:28 +00:00
data [ "bound_ec2_instance_id" ] = "i-1234567"
2018-03-18 01:24:49 +00:00
if err := updateRoleExpectLoginFail ( roleReq , loginRequest ) ; err != nil {
t . Fatal ( err )
2018-03-15 16:19:28 +00:00
}
2018-03-18 01:24:49 +00:00
// Place correct instance ID, but substring of the IAM role ARN
2018-03-15 16:19:28 +00:00
data [ "bound_ec2_instance_id" ] = [ ] string { parsedIdentityDoc . InstanceID , "i-1234567" }
2018-03-18 01:24:49 +00:00
data [ "bound_iam_role_arn" ] = [ ] string { "wrong_iam_role_arn" , iamARN [ : len ( iamARN ) - 2 ] , "wrong_iam_role_arn_2" }
if err := updateRoleExpectLoginFail ( roleReq , loginRequest ) ; err != nil {
t . Fatal ( err )
}
// place a wildcard in the middle of the role ARN
// The :31 gets arn:aws:iam::123456789012:role/
// This test relies on the role name having at least two characters
data [ "bound_iam_role_arn" ] = [ ] string { "wrong_iam_role_arn" , fmt . Sprintf ( "%s*%s" , iamARN [ : 31 ] , iamARN [ 32 : ] ) }
if err := updateRoleExpectLoginFail ( roleReq , loginRequest ) ; err != nil {
t . Fatal ( err )
}
// globbed IAM role ARN
data [ "bound_iam_role_arn" ] = [ ] string { "wrong_iam_role_arn_1" , fmt . Sprintf ( "%s*" , iamARN [ : len ( iamARN ) - 2 ] ) , "wrong_iam_role_arn_2" }
resp , err := b . HandleRequest ( context . Background ( ) , roleReq )
2016-06-14 18:17:41 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: failed to create role: resp:%#v\nerr:%v" , resp , err )
2016-04-11 23:21:53 +00:00
}
2016-06-14 18:46:08 +00:00
// Now, the login attempt should succeed
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
2016-04-11 23:21:53 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-27 03:40:11 +00:00
if resp == nil || resp . Auth == nil || resp . IsError ( ) {
2016-06-14 18:46:08 +00:00
t . Fatalf ( "bad: failed to login: resp:%#v\nerr:%v" , resp , err )
2016-04-11 23:21:53 +00:00
}
2018-03-20 18:54:10 +00:00
// Attempt to re-login with the identity signature
2018-02-23 01:55:45 +00:00
delete ( loginInput , "pkcs7" )
loginInput [ "identity" ] = identityDoc
loginInput [ "signature" ] = identityDocSig
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . Auth == nil || resp . IsError ( ) {
t . Fatalf ( "bad: failed to login: resp:%#v\nerr:%v" , resp , err )
}
2016-04-27 03:40:11 +00:00
// verify the presence of instance_id in the response object.
2016-04-11 23:21:53 +00:00
instanceID := resp . Auth . Metadata [ "instance_id" ]
if instanceID == "" {
t . Fatalf ( "instance ID not present in the response object" )
}
2018-03-15 16:19:28 +00:00
if instanceID != parsedIdentityDoc . InstanceID {
t . Fatalf ( "instance ID in response (%q) did not match instance ID from identity document (%q)" , instanceID , parsedIdentityDoc . InstanceID )
}
2016-04-11 23:21:53 +00:00
2017-10-27 15:23:15 +00:00
_ , ok := resp . Auth . Metadata [ "nonce" ]
if ok {
t . Fatalf ( "client nonce should not have been returned" )
}
2016-04-11 23:21:53 +00:00
loginInput [ "nonce" ] = "changed-vault-client-nonce"
// try to login again with changed nonce
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
2016-04-11 23:21:53 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil || ! resp . IsError ( ) {
t . Fatalf ( "login attempt should have failed due to client nonce mismatch" )
}
2016-04-27 03:40:11 +00:00
// Check if a whitelist identity entry is created after the login.
2016-04-11 23:21:53 +00:00
wlRequest := & logical . Request {
Operation : logical . ReadOperation ,
2016-05-10 02:07:46 +00:00
Path : "identity-whitelist/" + instanceID ,
2016-04-11 23:21:53 +00:00
Storage : storage ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , wlRequest )
2016-04-11 23:21:53 +00:00
if err != nil {
t . Fatal ( err )
}
2016-05-13 18:31:13 +00:00
if resp == nil || resp . Data == nil || resp . Data [ "role" ] != roleName {
2016-04-11 23:21:53 +00:00
t . Fatalf ( "failed to read whitelist identity" )
}
2016-04-27 03:40:11 +00:00
// Delete the whitelist identity entry.
2016-04-11 23:21:53 +00:00
wlRequest . Operation = logical . DeleteOperation
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , wlRequest )
2016-04-11 23:21:53 +00:00
if err != nil {
t . Fatal ( err )
}
if resp . IsError ( ) {
t . Fatalf ( "failed to delete whitelist identity" )
}
2017-10-27 15:23:15 +00:00
// Allow a fresh login without supplying the nonce
delete ( loginInput , "nonce" )
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
2016-04-11 23:21:53 +00:00
if err != nil {
t . Fatal ( err )
}
2016-04-27 03:40:11 +00:00
if resp == nil || resp . Auth == nil || resp . IsError ( ) {
2016-04-11 23:21:53 +00:00
t . Fatalf ( "login attempt failed" )
}
2017-10-27 15:23:15 +00:00
_ , ok = resp . Auth . Metadata [ "nonce" ]
if ! ok {
t . Fatalf ( "expected nonce to be returned" )
}
2016-04-11 23:21:53 +00:00
}
2017-02-01 19:16:03 +00:00
func TestBackend_pathStsConfig ( t * testing . T ) {
config := logical . TestBackendConfig ( )
storage := & logical . InmemStorage { }
config . StorageView = storage
b , err := Backend ( config )
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2017-02-01 19:16:03 +00:00
if err != nil {
t . Fatal ( err )
}
stsReq := & logical . Request {
Operation : logical . CreateOperation ,
Storage : storage ,
Path : "config/sts/account1" ,
}
2018-01-08 18:31:38 +00:00
checkFound , exists , err := b . HandleExistenceCheck ( context . Background ( ) , stsReq )
2017-02-01 19:16:03 +00:00
if err != nil {
t . Fatal ( err )
}
if ! checkFound {
t . Fatal ( "existence check not found for path 'config/sts/account1'" )
}
if exists {
t . Fatal ( "existence check should have returned 'false' for 'config/sts/account1'" )
}
data := map [ string ] interface { } {
"sts_role" : "arn:aws:iam:account1:role/myRole" ,
}
stsReq . Data = data
// test create operation
2018-01-08 18:31:38 +00:00
resp , err := b . HandleRequest ( context . Background ( ) , stsReq )
2017-02-01 19:16:03 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "resp: %#v, err: %v" , resp , err )
}
stsReq . Data = nil
// test existence check
2018-01-08 18:31:38 +00:00
checkFound , exists , err = b . HandleExistenceCheck ( context . Background ( ) , stsReq )
2017-02-01 19:16:03 +00:00
if err != nil {
t . Fatal ( err )
}
if ! checkFound {
t . Fatal ( "existence check not found for path 'config/sts/account1'" )
}
if ! exists {
t . Fatal ( "existence check should have returned 'true' for 'config/sts/account1'" )
}
stsReq . Operation = logical . ReadOperation
// test read operation
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , stsReq )
2017-07-07 12:23:12 +00:00
if err != nil {
t . Fatal ( err )
}
2017-02-01 19:16:03 +00:00
expectedStsRole := "arn:aws:iam:account1:role/myRole"
if resp . Data [ "sts_role" ] . ( string ) != expectedStsRole {
t . Fatalf ( "bad: expected:%s\n got:%s\n" , expectedStsRole , resp . Data [ "sts_role" ] . ( string ) )
}
stsReq . Operation = logical . CreateOperation
stsReq . Path = "config/sts/account2"
stsReq . Data = data
// create another entry to test the list operation
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , stsReq )
2017-02-01 19:16:03 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatal ( err )
}
stsReq . Operation = logical . ListOperation
stsReq . Path = "config/sts"
// test list operation
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , stsReq )
2017-02-01 19:16:03 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . IsError ( ) {
t . Fatalf ( "failed to list config/sts" )
}
keys := resp . Data [ "keys" ] . ( [ ] string )
if len ( keys ) != 2 {
t . Fatalf ( "invalid keys listed: %#v\n" , keys )
}
stsReq . Operation = logical . DeleteOperation
stsReq . Path = "config/sts/account1"
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , stsReq )
2017-02-01 19:16:03 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatal ( err )
}
stsReq . Path = "config/sts/account2"
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , stsReq )
2017-02-01 19:16:03 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatal ( err )
}
stsReq . Operation = logical . ListOperation
stsReq . Path = "config/sts"
// test list operation
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , stsReq )
2017-02-01 19:16:03 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . IsError ( ) {
t . Fatalf ( "failed to list config/sts" )
}
if resp . Data [ "keys" ] != nil {
t . Fatalf ( "no entries should be present" )
}
}
2017-04-24 19:15:50 +00:00
func buildCallerIdentityLoginData ( request * http . Request , roleName string ) ( map [ string ] interface { } , error ) {
headersJson , err := json . Marshal ( request . Header )
if err != nil {
return nil , err
}
requestBody , err := ioutil . ReadAll ( request . Body )
if err != nil {
return nil , err
}
return map [ string ] interface { } {
"iam_http_request_method" : request . Method ,
"iam_request_url" : base64 . StdEncoding . EncodeToString ( [ ] byte ( request . URL . String ( ) ) ) ,
"iam_request_headers" : base64 . StdEncoding . EncodeToString ( headersJson ) ,
"iam_request_body" : base64 . StdEncoding . EncodeToString ( requestBody ) ,
"request_role" : roleName ,
} , nil
}
// This is an acceptance test.
// If the test is NOT being run on an AWS EC2 instance in an instance profile,
// it requires the following environment variables to be set:
// TEST_AWS_ACCESS_KEY_ID
// TEST_AWS_SECRET_ACCESS_KEY
// TEST_AWS_SECURITY_TOKEN or TEST_AWS_SESSION_TOKEN (optional, if you are using short-lived creds)
// These are intentionally NOT the "standard" variables to prevent accidentally
// using prod creds in acceptance tests
func TestBackendAcc_LoginWithCallerIdentity ( t * testing . T ) {
// This test case should be run only when certain env vars are set and
// executed as an acceptance test.
if os . Getenv ( logicaltest . TestEnvVar ) == "" {
t . Skip ( fmt . Sprintf ( "Acceptance tests skipped unless env '%s' set" , logicaltest . TestEnvVar ) )
return
}
storage := & logical . InmemStorage { }
config := logical . TestBackendConfig ( )
config . StorageView = storage
b , err := Backend ( config )
if err != nil {
t . Fatal ( err )
}
2018-01-19 06:44:44 +00:00
err = b . Setup ( context . Background ( ) , config )
2017-04-24 19:15:50 +00:00
if err != nil {
t . Fatal ( err )
}
// Override the default AWS env vars (if set) with our test creds
// so that the credential provider chain will pick them up
// NOTE that I'm not bothing to override the shared config file location,
// so if creds are specified there, they will be used before IAM
// instance profile creds
// This doesn't provide perfect leakage protection (e.g., it will still
// potentially pick up credentials from the ~/.config files), but probably
// good enough rather than having to muck around in the low-level details
for _ , envvar := range [ ] string {
"AWS_ACCESS_KEY_ID" , "AWS_SECRET_ACCESS_KEY" , "AWS_SECURITY_TOKEN" , "AWS_SESSION_TOKEN" } {
2018-04-13 14:18:06 +00:00
// Skip test if any of the required env vars are missing
testEnvVar := os . Getenv ( "TEST_" + envvar )
if testEnvVar == "" {
t . Skipf ( "env var %s not set, skipping test" , "TEST_" + envvar )
}
2017-04-24 19:15:50 +00:00
// restore existing environment variables (in case future tests need them)
defer os . Setenv ( envvar , os . Getenv ( envvar ) )
2018-04-13 14:18:06 +00:00
os . Setenv ( envvar , testEnvVar )
2017-04-24 19:15:50 +00:00
}
awsSession , err := session . NewSession ( )
if err != nil {
fmt . Println ( "failed to create session," , err )
return
}
stsService := sts . New ( awsSession )
stsInputParams := & sts . GetCallerIdentityInput { }
testIdentity , err := stsService . GetCallerIdentity ( stsInputParams )
if err != nil {
t . Fatalf ( "Received error retrieving identity: %s" , err )
}
2017-06-07 14:27:11 +00:00
entity , err := parseIamArn ( * testIdentity . Arn )
2017-04-24 19:15:50 +00:00
if err != nil {
t . Fatal ( err )
}
// Test setup largely done
// At this point, we're going to:
// 1. Configure the client to require our test header value
2018-09-26 15:27:12 +00:00
// 2. Configure identity to use the ARN for the alias
// 3. Configure two different roles:
2017-04-24 19:15:50 +00:00
// a. One bound to our test user
// b. One bound to a garbage ARN
2018-09-26 15:27:12 +00:00
// 4. Pass in a request that doesn't have the signed header, ensure
2017-04-24 19:15:50 +00:00
// we're not allowed to login
2018-09-26 15:27:12 +00:00
// 5. Passin a request that has a validly signed header, but the wrong
2017-04-24 19:15:50 +00:00
// value, ensure it doesn't allow login
2018-09-26 15:27:12 +00:00
// 6. Pass in a request that has a validly signed request, ensure
2017-04-24 19:15:50 +00:00
// it allows us to login to our role
2018-09-26 15:27:12 +00:00
// 7. Pass in a request that has a validly signed request, asking for
2017-04-24 19:15:50 +00:00
// the other role, ensure it fails
clientConfigData := map [ string ] interface { } {
"iam_server_id_header_value" : testVaultHeaderValue ,
}
clientRequest := & logical . Request {
Operation : logical . UpdateOperation ,
Path : "config/client" ,
Storage : storage ,
Data : clientConfigData ,
}
2018-01-08 18:31:38 +00:00
_ , err = b . HandleRequest ( context . Background ( ) , clientRequest )
2017-04-24 19:15:50 +00:00
if err != nil {
t . Fatal ( err )
}
2018-09-26 15:27:12 +00:00
configIdentityData := map [ string ] interface { } {
"iam_alias" : identityAliasIAMFullArn ,
}
configIdentityRequest := & logical . Request {
Operation : logical . UpdateOperation ,
Path : "config/identity" ,
Storage : storage ,
Data : configIdentityData ,
}
resp , err := b . HandleRequest ( context . Background ( ) , configIdentityRequest )
if err != nil {
t . Fatal ( err )
}
if resp != nil && resp . IsError ( ) {
t . Fatalf ( "received error response when configuring identity: %#v" , resp )
}
2017-04-24 19:15:50 +00:00
// configuring the valid role we'll be able to login to
roleData := map [ string ] interface { } {
2018-03-02 16:09:14 +00:00
"bound_iam_principal_arn" : [ ] string { entity . canonicalArn ( ) , "arn:aws:iam::123456789012:role/FakeRoleArn1*" } , // Fake ARN MUST be wildcard terminated because we're resolving unique IDs, and the wildcard termination prevents unique ID resolution
2017-04-24 19:15:50 +00:00
"policies" : "root" ,
"auth_type" : iamAuthType ,
}
roleRequest := & logical . Request {
Operation : logical . CreateOperation ,
Path : "role/" + testValidRoleName ,
Storage : storage ,
Data : roleData ,
}
2018-09-26 15:27:12 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , roleRequest )
2017-04-24 19:15:50 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: failed to create role: resp:%#v\nerr:%v" , resp , err )
}
// configuring a valid role we won't be able to login to
roleDataEc2 := map [ string ] interface { } {
"auth_type" : "ec2" ,
"policies" : "root" ,
"bound_ami_id" : "ami-1234567" ,
}
roleRequestEc2 := & logical . Request {
Operation : logical . CreateOperation ,
Path : "role/ec2only" ,
Storage : storage ,
Data : roleDataEc2 ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , roleRequestEc2 )
2017-04-24 19:15:50 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: failed to create role; resp:%#v\nerr:%v" , resp , err )
}
2017-07-17 14:59:18 +00:00
fakeArn := "arn:aws:iam::123456789012:role/somePath/FakeRole"
2018-03-02 16:09:14 +00:00
fakeArn2 := "arn:aws:iam::123456789012:role/somePath/FakeRole2"
fakeArnResolverCount := 0
2018-01-19 06:44:44 +00:00
fakeArnResolver := func ( ctx context . Context , s logical . Storage , arn string ) ( string , error ) {
2018-03-02 16:09:14 +00:00
if strings . HasPrefix ( arn , fakeArn ) {
fakeArnResolverCount ++
return fmt . Sprintf ( "FakeUniqueIdFor%s%d" , arn , fakeArnResolverCount ) , nil
2017-06-07 14:27:11 +00:00
}
2018-01-19 06:44:44 +00:00
return b . resolveArnToRealUniqueId ( context . Background ( ) , s , arn )
2017-06-07 14:27:11 +00:00
}
b . resolveArnToUniqueIDFunc = fakeArnResolver
2017-04-24 19:15:50 +00:00
// now we're creating the invalid role we won't be able to login to
2018-03-02 16:09:14 +00:00
roleData [ "bound_iam_principal_arn" ] = [ ] string { fakeArn , fakeArn2 }
2017-04-24 19:15:50 +00:00
roleRequest . Path = "role/" + testInvalidRoleName
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , roleRequest )
2017-04-24 19:15:50 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: didn't fail to create role: resp:%#v\nerr:%v" , resp , err )
}
// now, create the request without the signed header
stsRequestNoHeader , _ := stsService . GetCallerIdentityRequest ( stsInputParams )
stsRequestNoHeader . Sign ( )
loginData , err := buildCallerIdentityLoginData ( stsRequestNoHeader . HTTPRequest , testValidRoleName )
if err != nil {
t . Fatal ( err )
}
loginRequest := & logical . Request {
Operation : logical . UpdateOperation ,
Path : "login" ,
Storage : storage ,
Data : loginData ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
2017-04-24 19:15:50 +00:00
if err != nil || resp == nil || ! resp . IsError ( ) {
t . Errorf ( "bad: expected failed login due to missing header: resp:%#v\nerr:%v" , resp , err )
}
// create the request with the invalid header value
// Not reusing stsRequestNoHeader because the process of signing the request
// and reading the body modifies the underlying request, so it's just cleaner
// to get new requests.
stsRequestInvalidHeader , _ := stsService . GetCallerIdentityRequest ( stsInputParams )
stsRequestInvalidHeader . HTTPRequest . Header . Add ( iamServerIdHeader , "InvalidValue" )
stsRequestInvalidHeader . Sign ( )
loginData , err = buildCallerIdentityLoginData ( stsRequestInvalidHeader . HTTPRequest , testValidRoleName )
if err != nil {
t . Fatal ( err )
}
loginRequest = & logical . Request {
Operation : logical . UpdateOperation ,
Path : "login" ,
Storage : storage ,
Data : loginData ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
2017-04-24 19:15:50 +00:00
if err != nil || resp == nil || ! resp . IsError ( ) {
t . Errorf ( "bad: expected failed login due to invalid header: resp:%#v\nerr:%v" , resp , err )
}
// Now, valid request against invalid role
stsRequestValid , _ := stsService . GetCallerIdentityRequest ( stsInputParams )
stsRequestValid . HTTPRequest . Header . Add ( iamServerIdHeader , testVaultHeaderValue )
stsRequestValid . Sign ( )
loginData , err = buildCallerIdentityLoginData ( stsRequestValid . HTTPRequest , testInvalidRoleName )
if err != nil {
t . Fatal ( err )
}
loginRequest = & logical . Request {
Operation : logical . UpdateOperation ,
Path : "login" ,
Storage : storage ,
Data : loginData ,
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
2017-04-24 19:15:50 +00:00
if err != nil || resp == nil || ! resp . IsError ( ) {
t . Errorf ( "bad: expected failed login due to invalid role: resp:%#v\nerr:%v" , resp , err )
}
loginData [ "role" ] = "ec2only"
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
2017-04-24 19:15:50 +00:00
if err != nil || resp == nil || ! resp . IsError ( ) {
t . Errorf ( "bad: expected failed login due to bad auth type: resp:%#v\nerr:%v" , resp , err )
}
2017-06-07 14:27:11 +00:00
// finally, the happy path test :)
2017-04-24 19:15:50 +00:00
loginData [ "role" ] = testValidRoleName
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
2017-04-24 19:15:50 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . Auth == nil || resp . IsError ( ) {
2017-07-18 13:51:45 +00:00
t . Fatalf ( "bad: expected valid login: resp:%#v" , resp )
2017-04-24 19:15:50 +00:00
}
2018-09-26 15:27:12 +00:00
if resp . Auth . Alias == nil {
t . Fatalf ( "bad: nil auth Alias" )
}
if resp . Auth . Alias . Name != * testIdentity . Arn {
t . Fatalf ( "bad: expected identity alias of %q, got %q instead" , * testIdentity . Arn , resp . Auth . Alias . Name )
}
2017-06-07 14:27:11 +00:00
2017-08-30 21:51:48 +00:00
renewReq := generateRenewRequest ( storage , resp . Auth )
// dump a fake ARN into the metadata to ensure that we ONLY look
// at the unique ID that has been generated
renewReq . Auth . Metadata [ "canonical_arn" ] = "fake_arn"
2017-06-07 14:27:11 +00:00
empty_login_fd := & framework . FieldData {
Raw : map [ string ] interface { } { } ,
Schema : pathLogin ( b ) . Fields ,
}
// ensure we can renew
2018-01-08 18:31:38 +00:00
resp , err = b . pathLoginRenew ( context . Background ( ) , renewReq , empty_login_fd )
2017-06-07 14:27:11 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil {
t . Fatal ( "got nil response from renew" )
}
if resp . IsError ( ) {
t . Fatalf ( "got error when renewing: %#v" , * resp )
}
// Now, fake out the unique ID resolver to ensure we fail login if the unique ID
// changes from under us
b . resolveArnToUniqueIDFunc = resolveArnToFakeUniqueId
// First, we need to update the role to force Vault to use our fake resolver to
// pick up the fake user ID
roleData [ "bound_iam_principal_arn" ] = entity . canonicalArn ( )
roleRequest . Path = "role/" + testValidRoleName
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , roleRequest )
2017-06-07 14:27:11 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: failed to recreate role: resp:%#v\nerr:%v" , resp , err )
}
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
2017-06-07 14:27:11 +00:00
if err != nil || resp == nil || ! resp . IsError ( ) {
t . Errorf ( "bad: expected failed login due to changed AWS role ID: resp: %#v\nerr:%v" , resp , err )
}
// and ensure a renew no longer works
2018-01-08 18:31:38 +00:00
resp , err = b . pathLoginRenew ( context . Background ( ) , renewReq , empty_login_fd )
2017-06-07 14:27:11 +00:00
if err == nil || ( resp != nil && ! resp . IsError ( ) ) {
2018-02-05 19:26:31 +00:00
t . Errorf ( "bad: expected failed renew due to changed AWS role ID: resp: %#v" , resp )
2017-06-07 14:27:11 +00:00
}
2017-08-30 21:51:48 +00:00
// Undo the fake resolver...
b . resolveArnToUniqueIDFunc = b . resolveArnToRealUniqueId
// Now test that wildcard matching works
wildcardRoleName := "valid_wildcard"
wildcardEntity := * entity
wildcardEntity . FriendlyName = "*"
2018-03-02 16:09:14 +00:00
roleData [ "bound_iam_principal_arn" ] = [ ] string { wildcardEntity . canonicalArn ( ) , "arn:aws:iam::123456789012:role/DoesNotExist/Vault_Fake_Role*" }
2017-08-30 21:51:48 +00:00
roleRequest . Path = "role/" + wildcardRoleName
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , roleRequest )
2017-08-30 21:51:48 +00:00
if err != nil || ( resp != nil && resp . IsError ( ) ) {
2018-03-02 16:09:14 +00:00
t . Fatalf ( "bad: failed to create wildcard roles: resp:%#v\nerr:%v" , resp , err )
2017-08-30 21:51:48 +00:00
}
loginData [ "role" ] = wildcardRoleName
2018-01-08 18:31:38 +00:00
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
2017-08-30 21:51:48 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . Auth == nil || resp . IsError ( ) {
t . Fatalf ( "bad: expected valid login: resp:%#v" , resp )
}
// and ensure we can renew
renewReq = generateRenewRequest ( storage , resp . Auth )
2018-01-08 18:31:38 +00:00
resp , err = b . pathLoginRenew ( context . Background ( ) , renewReq , empty_login_fd )
2017-08-30 21:51:48 +00:00
if err != nil {
t . Fatal ( err )
}
if resp == nil {
t . Fatal ( "got nil response from renew" )
}
if resp . IsError ( ) {
t . Fatalf ( "got error when renewing: %#v" , * resp )
}
// ensure the cache is populated
cachedArn := b . getCachedUserId ( resp . Auth . Metadata [ "client_user_id" ] )
if cachedArn == "" {
t . Errorf ( "got empty ARN back from user ID cache; expected full arn" )
}
2018-01-18 17:19:18 +00:00
// Test for renewal with period
period := 600 * time . Second
roleData [ "period" ] = period . String ( )
roleRequest . Path = "role/" + testValidRoleName
resp , err = b . HandleRequest ( context . Background ( ) , roleRequest )
if err != nil || ( resp != nil && resp . IsError ( ) ) {
t . Fatalf ( "bad: failed to create wildcard role: resp:%#v\nerr:%v" , resp , err )
}
loginData [ "role" ] = testValidRoleName
resp , err = b . HandleRequest ( context . Background ( ) , loginRequest )
if err != nil {
t . Fatal ( err )
}
if resp == nil || resp . Auth == nil || resp . IsError ( ) {
t . Fatalf ( "bad: expected valid login: resp:%#v" , resp )
}
renewReq = generateRenewRequest ( storage , resp . Auth )
resp , err = b . pathLoginRenew ( context . Background ( ) , renewReq , empty_login_fd )
if err != nil {
t . Fatal ( err )
}
if resp == nil {
t . Fatal ( "got nil response from renew" )
}
if resp . IsError ( ) {
t . Fatalf ( "got error when renewing: %#v" , * resp )
}
if resp . Auth . Period != period {
t . Fatalf ( "expected a period value of %s in the response, got: %s" , period , resp . Auth . Period )
}
2017-08-30 21:51:48 +00:00
}
func generateRenewRequest ( s logical . Storage , auth * logical . Auth ) * logical . Request {
renewReq := & logical . Request {
Storage : s ,
Auth : & logical . Auth { } ,
}
renewReq . Auth . InternalData = auth . InternalData
renewReq . Auth . Metadata = auth . Metadata
renewReq . Auth . LeaseOptions = auth . LeaseOptions
renewReq . Auth . Policies = auth . Policies
2018-01-18 17:19:18 +00:00
renewReq . Auth . Period = auth . Period
2017-06-07 14:27:11 +00:00
2017-08-30 21:51:48 +00:00
return renewReq
2017-04-24 19:15:50 +00:00
}