auth/aws: Allow wildcard in bound_iam_principal_id (#3213)

This commit is contained in:
Joel Thompson 2017-08-30 17:51:48 -04:00 committed by Jeff Mitchell
parent add6396298
commit caf90f58d8
7 changed files with 412 additions and 180 deletions

View File

@ -10,6 +10,7 @@ import (
"github.com/aws/aws-sdk-go/service/iam"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
"github.com/patrickmn/go-cache"
)
func Factory(conf *logical.BackendConfig) (logical.Backend, error) {
@ -60,6 +61,11 @@ type backend struct {
// will be flushed. The empty STS role signifies the master account
IAMClientsMap map[string]map[string]*iam.IAM
// Map of AWS unique IDs to the full ARN corresponding to that unique ID
// This avoids the overhead of an AWS API hit for every login request
// using the IAM auth method when bound_iam_principal_arn contains a wildcard
iamUserIdToArnCache *cache.Cache
// AWS Account ID of the "default" AWS credentials
// This cache avoids the need to call GetCallerIdentity repeatedly to learn it
// We can't store this because, in certain pathological cases, it could change
@ -74,9 +80,10 @@ func Backend(conf *logical.BackendConfig) (*backend, error) {
b := &backend{
// Setting the periodic func to be run once in an hour.
// If there is a real need, this can be made configurable.
tidyCooldownPeriod: time.Hour,
EC2ClientsMap: make(map[string]map[string]*ec2.EC2),
IAMClientsMap: make(map[string]map[string]*iam.IAM),
tidyCooldownPeriod: time.Hour,
EC2ClientsMap: make(map[string]map[string]*ec2.EC2),
IAMClientsMap: make(map[string]map[string]*iam.IAM),
iamUserIdToArnCache: cache.New(7*24*time.Hour, 24*time.Hour),
}
b.resolveArnToUniqueIDFunc = b.resolveArnToRealUniqueId

View File

@ -1522,22 +1522,14 @@ func TestBackendAcc_LoginWithCallerIdentity(t *testing.T) {
t.Fatalf("bad: expected valid login: resp:%#v", resp)
}
renewReq := &logical.Request{
Storage: storage,
Auth: &logical.Auth{},
}
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"
empty_login_fd := &framework.FieldData{
Raw: map[string]interface{}{},
Schema: pathLogin(b).Fields,
}
renewReq.Auth.InternalData = resp.Auth.InternalData
renewReq.Auth.Metadata = resp.Auth.Metadata
renewReq.Auth.LeaseOptions = resp.Auth.LeaseOptions
renewReq.Auth.Policies = resp.Auth.Policies
renewReq.Auth.IssueTime = time.Now()
// 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"
// ensure we can renew
resp, err = b.pathLoginRenew(renewReq, empty_login_fd)
if err != nil {
@ -1571,5 +1563,57 @@ func TestBackendAcc_LoginWithCallerIdentity(t *testing.T) {
if err == nil || (resp != nil && !resp.IsError()) {
t.Errorf("bad: expected failed renew due to changed AWS role ID: resp: %#v", resp, err)
}
// Undo the fake resolver...
b.resolveArnToUniqueIDFunc = b.resolveArnToRealUniqueId
// Now test that wildcard matching works
wildcardRoleName := "valid_wildcard"
wildcardEntity := *entity
wildcardEntity.FriendlyName = "*"
roleData["bound_iam_principal_arn"] = wildcardEntity.canonicalArn()
roleRequest.Path = "role/" + wildcardRoleName
resp, err = b.HandleRequest(roleRequest)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("bad: failed to create wildcard role: resp:%#v\nerr:%v", resp, err)
}
loginData["role"] = wildcardRoleName
resp, err = b.HandleRequest(loginRequest)
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)
resp, err = b.pathLoginRenew(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)
}
// 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")
}
}
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
renewReq.Auth.IssueTime = time.Now()
return renewReq
}

View File

@ -141,6 +141,25 @@ func (b *backend) flushCachedIAMClients() {
}
}
// Gets an entry out of the user ID cache
func (b *backend) getCachedUserId(userId string) string {
if userId == "" {
return ""
}
if entry, ok := b.iamUserIdToArnCache.Get(userId); ok {
b.iamUserIdToArnCache.SetDefault(userId, entry)
return entry.(string)
}
return ""
}
// Sets an entry in the user ID cache
func (b *backend) setCachedUserId(userId, arn string) {
if userId != "" {
b.iamUserIdToArnCache.SetDefault(userId, arn)
}
}
func (b *backend) stsRoleForAccount(s logical.Storage, accountID string) (string, error) {
// Check if an STS configuration exists for the AWS account
sts, err := b.lockedAwsStsEntry(s, accountID)

View File

@ -928,6 +928,12 @@ func (b *backend) pathLoginRenewIam(
}
}
// Note that the error messages below can leak a little bit of information about the role information
// For example, if on renew, the client gets the "error parsing ARN..." error message, the client
// will know that it's a wildcard bind (but not the actual bind), even if the client can't actually
// read the role directly to know what the bind is. It's a relatively small amount of leakage, in
// some fairly corner cases, and in the most likely error case (role has been changed to a new ARN),
// the error message is identical.
if roleEntry.BoundIamPrincipalARN != "" {
// We might not get here if all bindings were on the inferred entity, which we've already validated
// above
@ -936,10 +942,31 @@ func (b *backend) pathLoginRenewIam(
// Resolving unique IDs is enabled and the auth metadata contains the unique ID, so checking the
// unique ID is authoritative at this stage
if roleEntry.BoundIamPrincipalID != clientUserId {
return nil, fmt.Errorf("role no longer bound to ID %q", clientUserId)
return nil, fmt.Errorf("role no longer bound to ARN %q", canonicalArn)
}
} else if strings.HasSuffix(roleEntry.BoundIamPrincipalARN, "*") {
fullArn := b.getCachedUserId(clientUserId)
if fullArn == "" {
entity, err := parseIamArn(canonicalArn)
if err != nil {
return nil, fmt.Errorf("error parsing ARN %q: %v", canonicalArn, err)
}
fullArn, err = b.fullArn(entity, req.Storage)
if err != nil {
return nil, fmt.Errorf("error looking up full ARN of entity %v: %v", entity, err)
}
if fullArn == "" {
return nil, fmt.Errorf("got empty string back when looking up full ARN of entity %v", entity)
}
if clientUserId != "" {
b.setCachedUserId(clientUserId, fullArn)
}
}
if !strutil.GlobbedStringsMatch(roleEntry.BoundIamPrincipalARN, fullArn) {
return nil, fmt.Errorf("role no longer bound to ARN %q", canonicalArn)
}
} else if roleEntry.BoundIamPrincipalARN != canonicalArn {
return nil, fmt.Errorf("role no longer bound to arn %q", canonicalArn)
return nil, fmt.Errorf("role no longer bound to ARN %q", canonicalArn)
}
}
@ -1129,7 +1156,7 @@ func (b *backend) pathLoginUpdateIam(
callerUniqueId := strings.Split(callerID.UserId, ":")[0]
entity, err := parseIamArn(callerID.Arn)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("Error parsing arn: %v", err)), nil
return logical.ErrorResponse(fmt.Sprintf("error parsing arn %q: %v", callerID.Arn, err)), nil
}
roleName := data.Get("role").(string)
@ -1158,8 +1185,27 @@ func (b *backend) pathLoginUpdateIam(
if callerUniqueId != roleEntry.BoundIamPrincipalID {
return logical.ErrorResponse(fmt.Sprintf("expected IAM %s %s to resolve to unique AWS ID %q but got %q instead", entity.Type, entity.FriendlyName, roleEntry.BoundIamPrincipalID, callerUniqueId)), nil
}
} else if roleEntry.BoundIamPrincipalARN != "" && roleEntry.BoundIamPrincipalARN != entity.canonicalArn() {
return logical.ErrorResponse(fmt.Sprintf("IAM Principal %q does not belong to the role %q", callerID.Arn, roleName)), nil
} else if roleEntry.BoundIamPrincipalARN != "" {
if strings.HasSuffix(roleEntry.BoundIamPrincipalARN, "*") {
fullArn := b.getCachedUserId(callerUniqueId)
if fullArn == "" {
fullArn, err = b.fullArn(entity, req.Storage)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("error looking up full ARN of entity %v: %v", entity, err)), nil
}
if fullArn == "" {
return logical.ErrorResponse(fmt.Sprintf("got empty string back when looking up full ARN of entity %v", entity)), nil
}
b.setCachedUserId(callerUniqueId, fullArn)
}
if !strutil.GlobbedStringsMatch(roleEntry.BoundIamPrincipalARN, fullArn) {
// Note: Intentionally giving the exact same error message as a few lines below. Otherwise, we might leak information
// about whether the bound IAM principal ARN is a wildcard or not, and what that wildcard is.
return logical.ErrorResponse(fmt.Sprintf("IAM Principal %q does not belong to the role %q", callerID.Arn, roleName)), nil
}
} else if roleEntry.BoundIamPrincipalARN != entity.canonicalArn() {
return logical.ErrorResponse(fmt.Sprintf("IAM Principal %q does not belong to the role %q", callerID.Arn, roleName)), nil
}
}
policies := roleEntry.Policies
@ -1508,6 +1554,7 @@ type iamEntity struct {
SessionInfo string
}
// Returns a Vault-internal canonical ARN for referring to an IAM entity
func (e *iamEntity) canonicalArn() string {
entityType := e.Type
// canonicalize "assumed-role" into "role"
@ -1522,6 +1569,46 @@ func (e *iamEntity) canonicalArn() string {
return fmt.Sprintf("arn:%s:iam::%s:%s/%s", e.Partition, e.AccountNumber, entityType, e.FriendlyName)
}
// This returns the "full" ARN of an iamEntity, how it would be referred to in AWS proper
func (b *backend) fullArn(e *iamEntity, s logical.Storage) (string, error) {
// Not assuming path is reliable for any entity types
client, err := b.clientIAM(s, getAnyRegionForAwsPartition(e.Partition).ID(), e.AccountNumber)
if err != nil {
return "", fmt.Errorf("error creating IAM client: %v", err)
}
switch e.Type {
case "user":
input := iam.GetUserInput{
UserName: aws.String(e.FriendlyName),
}
resp, err := client.GetUser(&input)
if err != nil {
return "", fmt.Errorf("error fetching user %q: %v", e.FriendlyName, err)
}
if resp == nil {
return "", fmt.Errorf("nil response from GetUser")
}
return *(resp.User.Arn), nil
case "assumed-role":
fallthrough
case "role":
input := iam.GetRoleInput{
RoleName: aws.String(e.FriendlyName),
}
resp, err := client.GetRole(&input)
if err != nil {
return "", fmt.Errorf("error fetching role %q: %v", e.FriendlyName, err)
}
if resp == nil {
return "", fmt.Errorf("nil response form GetRole")
}
return *(resp.Role.Arn), nil
default:
return "", fmt.Errorf("unrecognized entity type: %s", e.Type)
}
}
const iamServerIdHeader = "X-Vault-AWS-IAM-Server-ID"
const pathLoginSyn = `

View File

@ -318,7 +318,8 @@ func (b *backend) upgradeRoleEntry(s logical.Storage, roleEntry *awsRoleEntry) (
if roleEntry.AuthType == iamAuthType &&
roleEntry.ResolveAWSUniqueIDs &&
roleEntry.BoundIamPrincipalARN != "" &&
roleEntry.BoundIamPrincipalID == "" {
roleEntry.BoundIamPrincipalID == "" &&
!strings.HasSuffix(roleEntry.BoundIamPrincipalARN, "*") {
principalId, err := b.resolveArnToUniqueIDFunc(s, roleEntry.BoundIamPrincipalARN)
if err != nil {
return false, err
@ -493,14 +494,17 @@ func (b *backend) pathRoleCreateUpdate(
// This allows the user to sumbit an update with the same ARN to force Vault
// to re-resolve the ARN to the unique ID, in case an entity was deleted and
// recreated
if roleEntry.ResolveAWSUniqueIDs {
if roleEntry.ResolveAWSUniqueIDs && !strings.HasSuffix(roleEntry.BoundIamPrincipalARN, "*") {
principalID, err := b.resolveArnToUniqueIDFunc(req.Storage, principalARN)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("failed updating the unique ID of ARN %#v: %#v", principalARN, err)), nil
}
roleEntry.BoundIamPrincipalID = principalID
} else {
// Need to handle the case where we're switching from a non-wildcard principal to a wildcard principal
roleEntry.BoundIamPrincipalID = ""
}
} else if roleEntry.ResolveAWSUniqueIDs && roleEntry.BoundIamPrincipalARN != "" {
} else if roleEntry.ResolveAWSUniqueIDs && roleEntry.BoundIamPrincipalARN != "" && !strings.HasSuffix(roleEntry.BoundIamPrincipalARN, "*") {
// we're turning on resolution on this role, so ensure we update it
principalID, err := b.resolveArnToUniqueIDFunc(req.Storage, roleEntry.BoundIamPrincipalARN)
if err != nil {

View File

@ -35,29 +35,29 @@ capabilities, the credentials are fetched automatically.
### Parameters
- `access_key` `(string: "")` - AWS Access key with permissions to query AWS
- `access_key` `(string: "")` - AWS Access key with permissions to query AWS
APIs. The permissions required depend on the specific configurations. If using
the `iam` auth method without inferencing, then no credentials are necessary.
If using the `ec2` auth method or using the `iam` auth method with
the `iam` auth method without inferencing, then no credentials are necessary.
If using the `ec2` auth method or using the `iam` auth method with
inferencing, then these credentials need access to `ec2:DescribeInstances`. If
additionally a `bound_iam_role` is specified, then these credentials also need
access to `iam:GetInstanceProfile`. If, however, an alternate sts
additionally a `bound_iam_role` is specified, then these credentials also need
access to `iam:GetInstanceProfile`. If, however, an alternate sts
configuration is set for the target account, then the credentials must be
permissioned to call `sts:AssumeRole` on the configured role, and that role
permissioned to call `sts:AssumeRole` on the configured role, and that role
must have the permissions described here.
- `secret_key` `(string: "")` - AWS Secret key with permissions to query AWS
APIs.
- `secret_key` `(string: "")` - AWS Secret key with permissions to query AWS
APIs.
- `endpoint` `(string: "")` - URL to override the default generated endpoint for
making AWS EC2 API calls.
- `iam_endpoint` `(string: "")` - URL to override the default generated endpoint
for making AWS IAM API calls.
- `sts_endpoint` `(string: "")` - URL to override the default generated endpoint
for making AWS STS API calls.
- `iam_server_id_header_value` `(string: "")` - The value to require in the
`X-Vault-AWS-IAM-Server-ID` header as part of GetCallerIdentity requests that
are used in the iam auth method. If not set, then no value is required or
- `iam_server_id_header_value` `(string: "")` - The value to require in the
`X-Vault-AWS-IAM-Server-ID` header as part of GetCallerIdentity requests that
are used in the iam auth method. If not set, then no value is required or
validated. If set, clients must include an X-Vault-AWS-IAM-Server-ID header in
the headers of login requests, and further this header must be among the
the headers of login requests, and further this header must be among the
signed headers validated by AWS. This is to protect against different types of
replay attacks, for example a signed request sent to a dev server being resent
to a production server. Consider setting this to the Vault server's DNS name.
@ -149,12 +149,12 @@ using the "type" parameter.
### Parameters
- `cert_name` `(string: <required>)` - Name of the certificate.
- `aws_public_cert` `(string: <required>)` - AWS Public key required to verify
- `aws_public_cert` `(string: <required>)` - AWS Public key required to verify
PKCS7 signature of the EC2 instance metadata.
- `type` `(string: "pkcs7")` - Takes the value of either "pkcs7" or "identity",
indicating the type of document which can be verified using the given
certificate. The PKCS#7 document will have a DSA digest and the identity
signature will have an RSA signature, and accordingly the public certificates
- `type` `(string: "pkcs7")` - Takes the value of either "pkcs7" or "identity",
indicating the type of document which can be verified using the given
certificate. The PKCS#7 document will have a DSA digest and the identity
signature will have an RSA signature, and accordingly the public certificates
to verify those also vary. Defaults to "pkcs7".
### Sample Payload
@ -259,11 +259,11 @@ be verified using credentials obtained by assumption of these STS roles.
### Parameters
- `account_id` `(string: <required>)` - AWS account ID to be associated with
STS role. If set, Vault will use assumed credentials to verify any login
- `account_id` `(string: <required>)` - AWS account ID to be associated with
STS role. If set, Vault will use assumed credentials to verify any login
attempts from EC2 instances in this account.
- `sts_role` `(string: <required>)` - AWS ARN for STS role to be assumed when
interacting with the account specified. The Vault server must have
- `sts_role` `(string: <required>)` - AWS ARN for STS role to be assumed when
interacting with the account specified. The Vault server must have
permissions to assume this role.
### Sample Payload
@ -294,8 +294,8 @@ Returns the previously configured STS role.
### Parameters
- `account_id` `(string: <required>)` - AWS account ID to be associated with
STS role. If set, Vault will use assumed credentials to verify any login
- `account_id` `(string: <required>)` - AWS account ID to be associated with
STS role. If set, Vault will use assumed credentials to verify any login
attempts from EC2 instances in this account.
### Sample Request
@ -384,10 +384,10 @@ Configures the periodic tidying operation of the whitelisted identity entries.
### Parameters
- `safety_buffer` `(string: "72h")` - The amount of extra time that must have
passed beyond the `roletag` expiration, before it is removed from the backend
- `safety_buffer` `(string: "72h")` - The amount of extra time that must have
passed beyond the `roletag` expiration, before it is removed from the backend
storage. Defaults to 72h.
- `disable_periodic_tidy` `(bool: false)` - If set to 'true', disables the
- `disable_periodic_tidy` `(bool: false)` - If set to 'true', disables the
periodic tidying of the `identity-whitelist/<instance_id>` entries.
### Sample Payload
@ -467,10 +467,10 @@ Configures the periodic tidying operation of the blacklisted role tag entries.
### Parameters
- `safety_buffer` `(string: "72h")` - The amount of extra time that must have
passed beyond the `roletag` expiration, before it is removed from the backend
- `safety_buffer` `(string: "72h")` - The amount of extra time that must have
passed beyond the `roletag` expiration, before it is removed from the backend
storage. Defaults to 72h.
- `disable_periodic_tidy` `(bool: false)` - If set to 'true', disables the
- `disable_periodic_tidy` `(bool: false)` - If set to 'true', disables the
periodic tidying of the `roletag-blacklist/<instance_id>` entries.
### Sample Payload
@ -559,115 +559,121 @@ inferencing configuration of that role.
### Parameters
- `role` `(string: <required>)` - Name of the role.
- `auth_type` `(string: "iam")` - The auth type permitted for this role. Valid
choices are "ec2" or "iam". If no value is specified, then it will default to
"iam" (except for legacy `aws-ec2` auth types, for which it will default to
- `auth_type` `(string: "iam")` - The auth type permitted for this role. Valid
choices are "ec2" or "iam". If no value is specified, then it will default to
"iam" (except for legacy `aws-ec2` auth types, for which it will default to
"ec2"). Only those bindings applicable to the auth type chosen will be allowed
to be configured on the role.
- `bound_ami_id` `(string: "")` - If set, defines a constraint on the EC2
instances that they should be using the AMI ID specified by this parameter.
This constraint is checked during ec2 auth as well as the iam auth method only
- `bound_ami_id` `(string: "")` - If set, defines a constraint on the EC2
instances that they should be using the AMI ID specified by this parameter.
This constraint is checked during ec2 auth as well as the iam auth method only
when inferring an EC2 instance.
- `bound_account_id` `(string: "")` - If set, defines a constraint on the EC2
instances that the account ID in its identity document to match the one
specified by this parameter. This constraint is checked during ec2 auth as
- `bound_account_id` `(string: "")` - If set, defines a constraint on the EC2
instances that the account ID in its identity document to match the one
specified by this parameter. This constraint is checked during ec2 auth as
well as the iam auth method only when inferring an EC2 instance.
- `bound_region` `(string: "")` - If set, defines a constraint on the EC2
instances that the region in its identity document must match the one
specified by this parameter. This constraint is only checked by the ec2 auth
- `bound_region` `(string: "")` - If set, defines a constraint on the EC2
instances that the region in its identity document must match the one
specified by this parameter. This constraint is only checked by the ec2 auth
method as well as the iam auth method only when inferring an ec2 instance.
- `bound_vpc_id` `(string: "")` - If set, defines a constraint on the EC2
instance to be associated with the VPC ID that matches the value specified by
- `bound_vpc_id` `(string: "")` - If set, defines a constraint on the EC2
instance to be associated with the VPC ID that matches the value specified by
this parameter. This constraint is only checked by the ec2 auth method as well
as the iam auth method only when inferring an ec2 instance.
- `bound_subnet_id` `(string: "")` - If set, defines a constraint on the EC2
instance to be associated with the subnet ID that matches the value specified
by this parameter. This constraint is only checked by the ec2 auth method as
- `bound_subnet_id` `(string: "")` - If set, defines a constraint on the EC2
instance to be associated with the subnet ID that matches the value specified
by this parameter. This constraint is only checked by the ec2 auth method as
well as the iam auth method only when inferring an ec2 instance.
- `bound_iam_role_arn` `(string: "")` - If set, defines a constraint on the
authenticating EC2 instance that it must match the IAM role ARN specified by
this parameter. The value is refix-matched (as though it were a glob ending
in `*`). The configured IAM user or EC2 instance role must be allowed to
execute the `iam:GetInstanceProfile` action if this is specified. This
constraint is checked by the ec2 auth method as well as the iam auth method
- `bound_iam_role_arn` `(string: "")` - If set, defines a constraint on the
authenticating EC2 instance that it must match the IAM role ARN specified by
this parameter. The value is refix-matched (as though it were a glob ending
in `*`). The configured IAM user or EC2 instance role must be allowed to
execute the `iam:GetInstanceProfile` action if this is specified. This
constraint is checked by the ec2 auth method as well as the iam auth method
only when inferring an EC2 instance.
- `bound_iam_instance_profile_arn` `(string: "")` - If set, defines a constraint
on the EC2 instances to be associated with an IAM instance profile ARN which
has a prefix that matches the value specified by this parameter. The value is
prefix-matched (as though it were a glob ending in `*`). This constraint is
checked by the ec2 auth method as well as the iam auth method only when
- `bound_iam_instance_profile_arn` `(string: "")` - If set, defines a constraint
on the EC2 instances to be associated with an IAM instance profile ARN which
has a prefix that matches the value specified by this parameter. The value is
prefix-matched (as though it were a glob ending in `*`). This constraint is
checked by the ec2 auth method as well as the iam auth method only when
inferring an ec2 instance.
- `role_tag` `(string: "")` - 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
constraint is valid only with the ec2 auth method and is not allowed when an
- `role_tag` `(string: "")` - 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
constraint is valid only with the ec2 auth method and is not allowed when an
auth_type is iam.
- `bound_iam_principal_arn` `(string: "")` - Defines the IAM principal that must
be authenticated using the iam auth method. It should look like
"arn:aws:iam::123456789012:user/MyUserName" or
"arn:aws:iam::123456789012:role/MyRoleName". This constraint is only checked
by the iam auth method.
- `inferred_entity_type` `(string: "")` - When set, instructs Vault to turn on
inferencing. The only current valid value is "ec2_instance" instructing Vault
to infer that the role comes from an EC2 instance in an IAM instance profile.
This only applies to the iam auth method. If you set this on an existing role
where it had not previously been set, tokens that had been created prior will
"arn:aws:iam::123456789012:role/MyRoleName". Wildcards are supported at the
end of the ARN, e.g., "arn:aws:iam::123456789012:\*" will match any IAM
principal in the AWS account 123456789012. This constraint is only checked by
the iam auth method. Wildcards are supported at the end of the ARN, e.g.,
"arn:aws:iam::123456789012:role/\*" will match all roles in the AWS account.
- `inferred_entity_type` `(string: "")` - When set, instructs Vault to turn on
inferencing. The only current valid value is "ec2\_instance" instructing Vault
to infer that the role comes from an EC2 instance in an IAM instance profile.
This only applies to the iam auth method. If you set this on an existing role
where it had not previously been set, tokens that had been created prior will
not be renewable; clients will need to get a new token.
- `inferred_aws_region` `(string: "")` - When role inferencing is activated, the
region to search for the inferred entities (e.g., EC2 instances). Required if
- `inferred_aws_region` `(string: "")` - When role inferencing is activated, the
region to search for the inferred entities (e.g., EC2 instances). Required if
role inferencing is activated. This only applies to the iam auth method.
- `resolve_aws_unique_ids` `(bool: false)` - When set, resolves the
`bound_iam_principal_arn` to the [AWS Unique ID](http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-unique-ids).
This requires Vault to be able to call `iam:GetUser` or `iam:GetRole` on the
`bound_iam_principal_arn` that is being bound. Resolving to internal AWS IDs
more closely mimics the behavior of AWS services in that if an IAM user or
- `resolve_aws_unique_ids` `(bool: false)` - When set, resolves the
`bound_iam_principal_arn` to the
[AWS Unique ID](http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-unique-ids)
for the bound principal ARN. This field is ignored when
`bound_iam_principal_arn` ends with a wildcard character.
This requires Vault to be able to call `iam:GetUser` or `iam:GetRole` on the
`bound_iam_principal_arn` that is being bound. Resolving to internal AWS IDs
more closely mimics the behavior of AWS services in that if an IAM user or
role is deleted and a new one is recreated with the same name, those new users
or roles won't get access to roles in Vault that were permissioned to the
prior principals of the same name. The default value for new roles is true,
while the default value for roles that existed prior to this option existing
or roles won't get access to roles in Vault that were permissioned to the
prior principals of the same name. The default value for new roles is true,
while the default value for roles that existed prior to this option existing
is false (you can check the value for a given role using the GET method on the
role). Any authentication tokens created prior to this being supported won't
verify the unique ID upon token renewal. When this is changed from false to
true on an existing role, Vault will attempt to resolve the role's bound IAM
ARN to the unique ID and, if unable to do so, will fail to enable this option.
Changing this from `true` to `false` is not supported; if absolutely
necessary, you would need to delete the role and recreate it explicitly
setting it to `false`. However; the instances in which you would want to do
this should be rare. If the role creation (or upgrading to use this) succeed,
then Vault has already been able to resolve internal IDs, and it doesn't need
any further IAM permissions to authenticate users. If a role has been deleted
and recreated, and Vault has cached the old unique ID, you should just call
this endpoint specifying the same `bound_iam_principal_arn` and, as long as
Vault still has the necessary IAM permissions to resolve the unique ID, Vault
will update the unique ID. (If it does not have the necessary permissions to
verify the unique ID upon token renewal. When this is changed from false to
true on an existing role, Vault will attempt to resolve the role's bound IAM
ARN to the unique ID and, if unable to do so, will fail to enable this option.
Changing this from `true` to `false` is not supported; if absolutely
necessary, you would need to delete the role and recreate it explicitly
setting it to `false`. However; the instances in which you would want to do
this should be rare. If the role creation (or upgrading to use this) succeed,
then Vault has already been able to resolve internal IDs, and it doesn't need
any further IAM permissions to authenticate users. If a role has been deleted
and recreated, and Vault has cached the old unique ID, you should just call
this endpoint specifying the same `bound_iam_principal_arn` and, as long as
Vault still has the necessary IAM permissions to resolve the unique ID, Vault
will update the unique ID. (If it does not have the necessary permissions to
resolve the unique ID, then it will fail to update.) If this option is set to
false, then you MUST leave out the path component in bound_iam_principal_arn
false, then you MUST leave out the path component in bound_iam_principal_arn
for **roles** only, but not IAM users. That is, if your IAM role ARN is of the
form `arn:aws:iam::123456789012:role/some/path/to/MyRoleName`, you **must**
specify a bound_iam_principal_arn of
`arn:aws:iam::123456789012:role/MyRoleName` for authentication to work.
- `ttl` `(string: "")` - The TTL period of tokens issued using this role,
- `ttl` `(string: "")` - The TTL period of tokens issued using this role,
provided as "1h", where hour is the largest suffix.
- `max_ttl` `(string: "")` - The maximum allowed lifetime of tokens issued using
this role.
- `period` `(string: "")` - If set, indicates that the token generated using
- `period` `(string: "")` - If set, indicates that the token generated using
this role should never expire. The token should be renewed within the duration
specified by this value. At each renewal, the token's TTL will be set to the
specified by this value. At each renewal, the token's TTL will be set to the
value of this parameter. The maximum allowed lifetime of tokens issued using
this role.
- `policies` `(array: [])` - Policies to be set on tokens issued using this
- `policies` `(array: [])` - Policies to be set on tokens issued using this
role.
- `allow_instance_migration` `(bool: false)` - 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
- `allow_instance_migration` `(bool: false)` - 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 only applies to
authentications via the ec2 auth method.
- `disallow_reauthentication` `(bool: false)` - If set, only allows a single
token to be granted per instance ID. In order to perform a fresh login, the
- `disallow_reauthentication` `(bool: false)` - If set, only allows a single
token to be granted per instance ID. In order to perform a fresh login, the
entry in whitelist for the instance ID needs to be cleared using
'auth/aws/identity-whitelist/<instance_id>' endpoint. Defaults to 'false'.
'auth/aws/identity-whitelist/<instance_id>' endpoint. Defaults to 'false'.
This only applies to authentications via the ec2 auth method.
### Sample Payload
@ -822,20 +828,20 @@ given instance can be allowed to gain in a worst-case scenario.
### Parameters
- `role` `(string: <required>)` - Name of the role.
- `policies` `(array: [])` - Policies to be associated with the tag. If set,
must be a subset of the role's policies. If set, but set to an empty value,
- `policies` `(array: [])` - Policies to be associated with the tag. If set,
must be a subset of the role's policies. If set, but set to an empty value,
only the 'default' policy will be given to issued tokens.
- `max_ttl` `(string: "")` - The maximum allowed lifetime of tokens issued using
this role.
- `instance_id` `(string: "")` - Instance ID for which this tag is intended for.
- `instance_id` `(string: "")` - Instance ID for which this tag is intended for.
If set, the created tag can only be used by the instance with the given ID.
- `allow_instance_migration` `(bool: false)` - 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
- `allow_instance_migration` `(bool: false)` - 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. Defaults to 'false'.
- `disallow_reauthentication` `(bool: false)` - If set, only allows a single
token to be granted per instance ID. This can be cleared with the
- `disallow_reauthentication` `(bool: false)` - If set, only allows a single
token to be granted per instance ID. This can be cleared with the
auth/aws/identity-whitelist endpoint. Defaults to 'false'.
### Sample Payload
@ -888,54 +894,54 @@ along with its RSA digest can be supplied to this endpoint.
### Sample Payload
- `role` `(string: "")` - Name of the role against which the login is being
attempted. If `role` is not specified, then the login endpoint looks for a
- `role` `(string: "")` - Name of the role against which the login is being
attempted. If `role` is not specified, then the login endpoint looks for a
role bearing the name of the AMI ID of the EC2 instance that is trying to
login if using the ec2 auth method, or the "friendly name" (i.e., role name or
username) of the IAM principal authenticated. If a matching role is not found,
login fails.
- `identity` `(string: <required-ec2>)` - Base64 encoded EC2 instance identity
document. This needs to be supplied along with the `signature` parameter. If
using `curl` for fetching the identity document, consider using the option
- `identity` `(string: <required-ec2>)` - Base64 encoded EC2 instance identity
document. This needs to be supplied along with the `signature` parameter. If
using `curl` for fetching the identity document, consider using the option
`-w 0` while piping the output to `base64` binary.
- `signature` `(string: <required-ec2>)` - Base64 encoded SHA256 RSA signature of
the instance identity document. This needs to be supplied along with
- `signature` `(string: <required-ec2>)` - Base64 encoded SHA256 RSA signature of
the instance identity document. This needs to be supplied along with
`identity` parameter when using the ec2 auth method.
- `pkcs7` `(string: <required-ec2>)` - PKCS7 signature of the identity document with
all `\n` characters removed. Either this needs to be set *OR* both `identity`
and `signature` need to be set when using the ec2 auth method.
- `nonce` `(string: "")` - The nonce to be used for subsequent login requests.
If this parameter is not specified at all and if reauthentication is allowed,
- `nonce` `(string: "")` - The nonce to be used for subsequent login requests.
If this parameter is not specified at all and if reauthentication is allowed,
then the backend will generate a random nonce, attaches it to the instance's
identity-whitelist entry and returns the nonce back as part of auth metadata.
This value should be used with further login requests, to establish client
authenticity. Clients can choose to set a custom nonce if preferred, in which
case, it is recommended that clients provide a strong nonce. If a nonce is
provided but with an empty value, it indicates intent to disable
reauthentication. Note that, when `disallow_reauthentication` option is
identity-whitelist entry and returns the nonce back as part of auth metadata.
This value should be used with further login requests, to establish client
authenticity. Clients can choose to set a custom nonce if preferred, in which
case, it is recommended that clients provide a strong nonce. If a nonce is
provided but with an empty value, it indicates intent to disable
reauthentication. Note that, when `disallow_reauthentication` option is
enabled on either the role or the role tag, the `nonce` holds no significance.
This is ignored unless using the ec2 auth method.
- `iam_http_request_method` `(string: <required-iam>)` - HTTP method used in the
signed request. Currently only POST is supported, but other methods may be
- `iam_http_request_method` `(string: <required-iam>)` - HTTP method used in the
signed request. Currently only POST is supported, but other methods may be
supported in the future. This is required when using the iam auth method.
- `iam_request_url` `(string: <required-iam>)` - Base64-encoded HTTP URL used in
the signed request. Most likely just `aHR0cHM6Ly9zdHMuYW1hem9uYXdzLmNvbS8=`
(base64-encoding of `https://sts.amazonaws.com/`) as most requests will
the signed request. Most likely just `aHR0cHM6Ly9zdHMuYW1hem9uYXdzLmNvbS8=`
(base64-encoding of `https://sts.amazonaws.com/`) as most requests will
probably use POST with an empty URI. This is required when using the iam auth
method.
- `iam_request_body` `(string: <required-iam>)` - Base64-encoded body of the
- `iam_request_body` `(string: <required-iam>)` - Base64-encoded body of the
signed request. Most likely
`QWN0aW9uPUdldENhbGxlcklkZW50aXR5JlZlcnNpb249MjAxMS0wNi0xNQ==` which is the
base64 encoding of `Action=GetCallerIdentity&Version=2011-06-15`. This is
`QWN0aW9uPUdldENhbGxlcklkZW50aXR5JlZlcnNpb249MjAxMS0wNi0xNQ==` which is the
base64 encoding of `Action=GetCallerIdentity&Version=2011-06-15`. This is
required when using the iam auth method.
- `iam_request_headers` `(string: <required-iam>)` - Base64-encoded,
- `iam_request_headers` `(string: <required-iam>)` - Base64-encoded,
JSON-serialized representation of the sts:GetCallerIdentity HTTP request
headers. The JSON serialization assumes that each header key maps to either a
string value or an array of string values (though the length of that array
will probably only be one). If the `iam_server_id_header_value` is configured
headers. The JSON serialization assumes that each header key maps to either a
string value or an array of string values (though the length of that array
will probably only be one). If the `iam_server_id_header_value` is configured
in Vault for the aws auth mount, then the headers must include the
X-Vault-AWS-IAM-Server-ID header, its value must match the value configured,
and the header must be included in the signed headers. This is required when
X-Vault-AWS-IAM-Server-ID header, its value must match the value configured,
and the header must be included in the signed headers. This is required when
using the iam auth method.
@ -999,7 +1005,7 @@ token.
### Parameters
- `role_tag` `(string: <required>)` - Role tag to be blacklisted. The tag can be
supplied as-is. In order to avoid any encoding problems, it can be base64
supplied as-is. In order to avoid any encoding problems, it can be base64
encoded.
### Sample Request
@ -1022,7 +1028,7 @@ Returns the blacklist entry of a previously blacklisted role tag.
### Parameters
- `role_tag` `(string: <required>)` - Role tag to be blacklisted. The tag can be
supplied as-is. In order to avoid any encoding problems, it can be base64
supplied as-is. In order to avoid any encoding problems, it can be base64
encoded.
### Sample Request
@ -1096,7 +1102,7 @@ Deletes a blacklisted role tag.
### Parameters
- `role_tag` `(string: <required>)` - Role tag to be blacklisted. The tag can be
supplied as-is. In order to avoid any encoding problems, it can be base64
supplied as-is. In order to avoid any encoding problems, it can be base64
encoded.
@ -1120,8 +1126,8 @@ Cleans up the entries in the blacklist based on expiration time on the entry and
### Parameters
- `safety_buffer` `(string: "72h")` - The amount of extra time that must have
passed beyond the `roletag` expiration, before it is removed from the backend
- `safety_buffer` `(string: "72h")` - The amount of extra time that must have
passed beyond the `roletag` expiration, before it is removed from the backend
storage. Defaults to 72h.
### Sample Request
@ -1135,7 +1141,7 @@ $ curl \
### Read Identity Whitelist Information
Returns an entry in the whitelist. An entry will be created/updated by every
Returns an entry in the whitelist. An entry will be created/updated by every
successful login.
| Method | Path | Produces |
@ -1144,8 +1150,8 @@ successful login.
### Parameters
- `instance_id` `(string: <required>)` - EC2 instance ID. A successful login
operation from an EC2 instance gets cached in this whitelist, keyed off of
- `instance_id` `(string: <required>)` - EC2 instance ID. A successful login
operation from an EC2 instance gets cached in this whitelist, keyed off of
instance ID.
### Sample Request
@ -1221,8 +1227,8 @@ Deletes a cache of the successful login from an instance.
### Parameters
- `instance_id` `(string: <required>)` - EC2 instance ID. A successful login
operation from an EC2 instance gets cached in this whitelist, keyed off of
- `instance_id` `(string: <required>)` - EC2 instance ID. A successful login
operation from an EC2 instance gets cached in this whitelist, keyed off of
instance ID.
### Sample Request
@ -1236,7 +1242,7 @@ $ curl \
## Tidy Identity Whitelist Entries
Cleans up the entries in the whitelist based on expiration time and
Cleans up the entries in the whitelist based on expiration time and
`safety_buffer`.
| Method | Path | Produces |
@ -1245,8 +1251,8 @@ Cleans up the entries in the whitelist based on expiration time and
### Parameters
- `safety_buffer` `(string: "72h")` - The amount of extra time that must have
passed beyond the `roletag` expiration, before it is removed from the backend
- `safety_buffer` `(string: "72h")` - The amount of extra time that must have
passed beyond the `roletag` expiration, before it is removed from the backend
storage. Defaults to 72h.
### Sample Request
@ -1256,4 +1262,4 @@ $ curl \
--header "X-Vault-Token: ..." \
--request POST \
https://vault.rocks/v1/auth/aws/tidy/identity-whitelist
```
```

View File

@ -97,7 +97,7 @@ and relies upon AWS to authenticate that signature.
While AWS API endpoints support both signed GET and POST requests, for
simplicity, the aws backend supports only POST requests. It also does not
support `presigned` requests, i.e., requests with `X-Amz-Credential`,
`X-Amz-signature`, and `X-Amz-SignedHeaders` GET query parameters containing the
`X-Amz-Signature`, and `X-Amz-SignedHeaders` GET query parameters containing the
authenticating information.
It's also important to note that Amazon does NOT appear to include any sort
@ -119,6 +119,17 @@ are to be met during the login. For example, one such constraint that is
supported is to bind against AMI ID. A role which is bound to a specific AMI,
can only be used for login by EC2 instances that are deployed on the same AMI.
The iam authentication method allows you to specify a bound IAM principal ARN.
Clients authenticating to Vault must have an ARN that matches the ARN bound to
the role they are attempting to login to. The bound ARN allows specifying a
wildcard at the end of the bound ARN. For example, if the bound ARN were
`arn:aws:iam::123456789012:*` it would allow any principal in AWS account
123456789012 to login to it. Similarly, if it were
`arn:aws:iam::123456789012:role/*` it would allow any IAM role in the AWS
account to login to it. If you wish to specify a wildcard, you must give Vault
`iam:GetUser` and `iam:GetRole` permissions to properly resolve the full user
path.
In general, role bindings that are specific to an EC2 instance are only checked
when the ec2 auth method is used to login, while bindings specific to IAM
principals are only checked when the iam auth method is used to login. However,
@ -263,6 +274,60 @@ comparison of the two authentication methods.
to, or make use of inferencing. If you need to make use of role tags, then
you will need to use the ec2 auth method.
## Recommended Vault IAM Policy
This specifies the recommended IAM policy needed by the AWS auth backend. Note
that if you are using the same credentials for the AWS auth and secret backends
(e.g., if you're running Vault on an EC2 instance in an IAM instance profile),
then you will need to add additional permissions as required by the AWS secret
backend.
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"iam:GetInstanceProfile",
"iam:GetUser",
"iam:GetRole"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": ["sts:AssumeRole"],
"Resource": [
"arn:aws:iam:<AccountId>:role/<VaultRole>"
]
}
]
}
```
Here are some of the scenarios in which Vault would need to use each of these
permissions. This isn't intended to be an exhaustive list of all the scenarios
in which Vault might make an AWS API call, but rather illustrative of why these
are needed.
* `ec2:DescribeInstances` is necessary when you are using the `ec2` auth method
or when you are inferring an `ec2_instance` entity type to validate the EC2
instance meets binding requirements of the role
* `iam:GetInstanceProfile` is used when you have a `bound_iam_role_arn` in the
ec2 auth method. Vault needs determine which IAM role is attached to the
instance profile.
* `iam:GetUser` and `iam:GetRole` are used when using the iam auth method and
binding to an IAM user or role principal to determine the unique AWS user ID
or when using a wildcard on the bound ARN to resolve the full ARN of the user
or role.
* The `sts:AssumeRole` stanza is necessary when you are using [Cross Account
Access](#cross-account-access). The `Resource`s specified should be a list of
all the roles for which you have configured cross-account access, and each of
those roles should have this IAM policy attached (except for the
`sts:AssumeRole` statement).
## Client Nonce
Note: this only applies to the ec2 authentication method.
@ -639,4 +704,4 @@ The response will be in JSON. For example:
The AWS authentication backend has a full HTTP API. Please see the
[AWS Auth API](/api/auth/aws/index.html) for more
details.
details.