mirror of
https://github.com/hashicorp/vault.git
synced 2025-11-24 04:01:37 +01:00
Adds sts:AssumeRole support to the AWS secret backend
Support use cases where you want to provision STS tokens using Vault, but, you need to call AWS APIs that are blocked for federated tokens. For example, STS federated tokens cannot invoke IAM APIs, such as Terraform scripts containing `aws_iam_*` resources.
This commit is contained in:
parent
902b2c4c72
commit
69740e57e0
@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -13,6 +14,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/iam"
|
||||
"github.com/hashicorp/go-cleanhttp"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
logicaltest "github.com/hashicorp/vault/logical/testing"
|
||||
@ -40,15 +42,21 @@ func TestBackend_basic(t *testing.T) {
|
||||
func TestBackend_basicSTS(t *testing.T) {
|
||||
logicaltest.Test(t, logicaltest.TestCase{
|
||||
AcceptanceTest: true,
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Backend: getBackend(t),
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
createRole(t)
|
||||
},
|
||||
Backend: getBackend(t),
|
||||
Steps: []logicaltest.TestStep{
|
||||
testAccStepConfig(t),
|
||||
testAccStepWritePolicy(t, "test", testPolicy),
|
||||
testAccStepReadSTS(t, "test"),
|
||||
testAccStepWriteArnPolicyRef(t, "test", testPolicyArn),
|
||||
testAccStepReadSTSWithArnPolicy(t, "test"),
|
||||
testAccStepWriteArnRoleRef(t, testRoleName),
|
||||
testAccStepReadSTS(t, testRoleName),
|
||||
},
|
||||
Teardown: teardown,
|
||||
})
|
||||
}
|
||||
|
||||
@ -84,6 +92,123 @@ func testAccPreCheck(t *testing.T) {
|
||||
log.Println("[INFO] Test: Using us-west-2 as test region")
|
||||
os.Setenv("AWS_DEFAULT_REGION", "us-west-2")
|
||||
}
|
||||
|
||||
if v := os.Getenv("AWS_ACCOUNT_ID"); v == "" {
|
||||
accountId, err := getAccountId()
|
||||
if err != nil {
|
||||
t.Fatal("AWS_ACCOUNT_ID could not be read from iam:GetUser for acceptance tests")
|
||||
}
|
||||
log.Printf("[INFO] Test: Used %s as AWS_ACCOUNT_ID", accountId)
|
||||
os.Setenv("AWS_ACCOUNT_ID", accountId)
|
||||
}
|
||||
}
|
||||
|
||||
func getAccountId() (string, error) {
|
||||
creds := credentials.NewStaticCredentials(os.Getenv("AWS_ACCESS_KEY_ID"),
|
||||
os.Getenv("AWS_SECRET_ACCESS_KEY"),
|
||||
"")
|
||||
|
||||
awsConfig := &aws.Config{
|
||||
Credentials: creds,
|
||||
Region: aws.String("us-east-1"),
|
||||
HTTPClient: cleanhttp.DefaultClient(),
|
||||
}
|
||||
svc := iam.New(session.New(awsConfig))
|
||||
|
||||
params := &iam.GetUserInput{}
|
||||
res, err := svc.GetUser(params)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// split "arn:aws:iam::012345678912:user/username"
|
||||
accountId := strings.Split(*res.User.Arn, ":")[4]
|
||||
return accountId, nil
|
||||
}
|
||||
|
||||
const testRoleName = "Vault-Acceptance-Test-AWS-Assume-Role"
|
||||
|
||||
func createRole(t *testing.T) {
|
||||
const testRoleAssumePolicy = `{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect":"Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::%s:root"
|
||||
},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
creds := credentials.NewStaticCredentials(os.Getenv("AWS_ACCESS_KEY_ID"), os.Getenv("AWS_SECRET_ACCESS_KEY"), "")
|
||||
|
||||
awsConfig := &aws.Config{
|
||||
Credentials: creds,
|
||||
Region: aws.String("us-east-1"),
|
||||
HTTPClient: cleanhttp.DefaultClient(),
|
||||
}
|
||||
svc := iam.New(session.New(awsConfig))
|
||||
trustPolicy := fmt.Sprintf(testRoleAssumePolicy, os.Getenv("AWS_ACCOUNT_ID"))
|
||||
|
||||
params := &iam.CreateRoleInput{
|
||||
AssumeRolePolicyDocument: aws.String(trustPolicy),
|
||||
RoleName: aws.String(testRoleName),
|
||||
Path: aws.String("/"),
|
||||
}
|
||||
|
||||
log.Printf("[INFO] AWS CreateRole: %s", testRoleName)
|
||||
_, err := svc.CreateRole(params)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("AWS CreateRole failed: %v", err)
|
||||
}
|
||||
|
||||
attachment := &iam.AttachRolePolicyInput{
|
||||
PolicyArn: aws.String(testPolicyArn),
|
||||
RoleName: aws.String(testRoleName), // Required
|
||||
}
|
||||
_, err = svc.AttachRolePolicy(attachment)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("AWS CreateRole failed: %v", err)
|
||||
}
|
||||
|
||||
// Sleep sometime because AWS is eventually consistent
|
||||
log.Println("[WARN] Sleeping for 10 seconds waiting for AWS...")
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
|
||||
func teardown() error {
|
||||
creds := credentials.NewStaticCredentials(os.Getenv("AWS_ACCESS_KEY_ID"), os.Getenv("AWS_SECRET_ACCESS_KEY"), "")
|
||||
|
||||
awsConfig := &aws.Config{
|
||||
Credentials: creds,
|
||||
Region: aws.String("us-east-1"),
|
||||
HTTPClient: cleanhttp.DefaultClient(),
|
||||
}
|
||||
svc := iam.New(session.New(awsConfig))
|
||||
|
||||
attachment := &iam.DetachRolePolicyInput{
|
||||
PolicyArn: aws.String(testPolicyArn),
|
||||
RoleName: aws.String(testRoleName), // Required
|
||||
}
|
||||
_, err := svc.DetachRolePolicy(attachment)
|
||||
|
||||
params := &iam.DeleteRoleInput{
|
||||
RoleName: aws.String(testRoleName),
|
||||
}
|
||||
|
||||
log.Printf("[INFO] AWS DeleteRole: %s", testRoleName)
|
||||
_, err = svc.DeleteRole(params)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("[WARN] AWS DeleteRole failed: %v", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func testAccStepConfig(t *testing.T) logicaltest.TestStep {
|
||||
@ -178,7 +303,7 @@ func testAccStepReadSTSWithArnPolicy(t *testing.T, name string) logicaltest.Test
|
||||
ErrorOk: true,
|
||||
Check: func(resp *logical.Response) error {
|
||||
if resp.Data["error"] !=
|
||||
"Can't generate STS credentials for a managed policy; use an inline policy instead" {
|
||||
"Can't generate STS credentials for a managed policy; use a role to assume or an inline policy instead" {
|
||||
t.Fatalf("bad: %v", resp)
|
||||
}
|
||||
return nil
|
||||
@ -317,3 +442,13 @@ func testAccStepReadArnPolicy(t *testing.T, name string, value string) logicalte
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testAccStepWriteArnRoleRef(t *testing.T, roleName string) logicaltest.TestStep {
|
||||
return logicaltest.TestStep{
|
||||
Operation: logical.UpdateOperation,
|
||||
Path: "roles/" + roleName,
|
||||
Data: map[string]interface{}{
|
||||
"arn": fmt.Sprintf("arn:aws:iam::%s:role/%s", os.Getenv("AWS_ACCOUNT_ID"), roleName),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,9 +48,17 @@ func (b *backend) pathSTSRead(
|
||||
}
|
||||
policyValue := string(policy.Value)
|
||||
if strings.HasPrefix(policyValue, "arn:") {
|
||||
return logical.ErrorResponse(
|
||||
"Can't generate STS credentials for a managed policy; use an inline policy instead"),
|
||||
logical.ErrInvalidRequest
|
||||
if strings.Contains(policyValue, ":role/") {
|
||||
return b.assumeRole(
|
||||
req.Storage,
|
||||
req.DisplayName, policyName, policyValue,
|
||||
&ttl,
|
||||
)
|
||||
} else {
|
||||
return logical.ErrorResponse(
|
||||
"Can't generate STS credentials for a managed policy; use a role to assume or an inline policy instead"),
|
||||
logical.ErrInvalidRequest
|
||||
}
|
||||
}
|
||||
// Use the helper to create the secret
|
||||
return b.secretTokenCreate(
|
||||
|
||||
@ -111,6 +111,48 @@ func (b *backend) secretTokenCreate(s logical.Storage,
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (b *backend) assumeRole(s logical.Storage,
|
||||
displayName, policyName, policy string,
|
||||
lifeTimeInSeconds *int64) (*logical.Response, error) {
|
||||
STSClient, err := clientSTS(s)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(err.Error()), nil
|
||||
}
|
||||
|
||||
username, usernameWarning := genUsername(displayName, policyName, "iam_user")
|
||||
|
||||
tokenResp, err := STSClient.AssumeRole(
|
||||
&sts.AssumeRoleInput{
|
||||
RoleSessionName: aws.String(username),
|
||||
RoleArn: aws.String(policy),
|
||||
DurationSeconds: lifeTimeInSeconds,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf(
|
||||
"Error assuming role: %s", err)), nil
|
||||
}
|
||||
|
||||
resp := b.Secret(SecretAccessKeyType).Response(map[string]interface{}{
|
||||
"access_key": *tokenResp.Credentials.AccessKeyId,
|
||||
"secret_key": *tokenResp.Credentials.SecretAccessKey,
|
||||
"security_token": *tokenResp.Credentials.SessionToken,
|
||||
}, map[string]interface{}{
|
||||
"username": username,
|
||||
"policy": policy,
|
||||
"is_sts": true,
|
||||
})
|
||||
|
||||
// Set the secret TTL to appropriately match the expiration of the token
|
||||
resp.Secret.TTL = tokenResp.Credentials.Expiration.Sub(time.Now())
|
||||
|
||||
if usernameWarning != "" {
|
||||
resp.AddWarning(usernameWarning)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (b *backend) secretAccessKeysCreate(
|
||||
s logical.Storage,
|
||||
displayName, policyName string, policy string) (*logical.Response, error) {
|
||||
|
||||
@ -46,7 +46,7 @@ The following parameters are required:
|
||||
- `region` the AWS region for API calls.
|
||||
|
||||
The next step is to configure a role. A role is a logical name that maps
|
||||
to a policy used to generated those credentials.
|
||||
to a policy used to generated those credentials.
|
||||
You can either supply a user inline policy (via the policy argument), or
|
||||
provide a reference to an existing AWS policy by supplying the full ARN
|
||||
reference (via the arn argument).
|
||||
@ -114,38 +114,17 @@ secret_key vS61xxXgwwX/V4qZMUv8O8wd2RLqngXz6WmN04uW
|
||||
security_token <nil>
|
||||
```
|
||||
|
||||
If you want keys with an STS token use the 'sts' endpoint instead of 'creds.'
|
||||
The aws/sts endpoint will always fetch STS credentials with a 1hr ttl. Note that STS credentials can only be generated
|
||||
for user inline policies.
|
||||
## Dynamic IAM users
|
||||
|
||||
```text
|
||||
$vault read aws/sts/deploy
|
||||
Key Value
|
||||
lease_id aws/sts/deploy/31d771a6-fb39-f46b-fdc5-945109106422
|
||||
lease_duration 3600
|
||||
lease_renewable true
|
||||
access_key ASIAJYYYY2AA5K4WIXXX
|
||||
secret_key HSs0DYYYYYY9W81DXtI0K7X84H+OVZXK5BXXXX
|
||||
security_token AQoDYXdzEEwasAKwQyZUtZaCjVNDiXXXXXXXXgUgBBVUUbSyujLjsw6jYzboOQ89vUVIehUw/9MreAifXFmfdbjTr3g6zc0me9M+dB95DyhetFItX5QThw0lEsVQWSiIeIotGmg7mjT1//e7CJc4LpxbW707loFX1TYD1ilNnblEsIBKGlRNXZ+QJdguY4VkzXxv2urxIH0Sl14xtqsRPboV7eYruSEZlAuP3FLmqFbmA0AFPCT37cLf/vUHinSbvw49C4c9WQLH7CeFPhDub7/rub/QU/lCjjJ43IqIRo9jYgcEvvdRkQSt70zO8moGCc7pFvmL7XGhISegQpEzudErTE/PdhjlGpAKGR3d5qKrHpPYK/k480wk1Ai/t1dTa/8/3jUYTUeIkaJpNBnupQt7qoaXXXXXXXXXX
|
||||
```
|
||||
The `aws/creds` endpoint will dynamically create a new IAM user and respond
|
||||
with an IAM access key for the newly created user.
|
||||
|
||||
The [Quick Start](#quick-start) describes how to setup the `aws/creds` endpoint.
|
||||
|
||||
If you get an error message similar to either of the following, the root credentials that you wrote to `aws/config/root` have insufficient privilege:
|
||||
## Root Credentials for Dynamic IAM users
|
||||
|
||||
```text
|
||||
$ vault read aws/creds/deploy
|
||||
* Error creating IAM user: User: arn:aws:iam::000000000000:user/hashicorp is not authorized to perform: iam:CreateUser on resource: arn:aws:iam::000000000000:user/vault-root-1432735386-4059
|
||||
|
||||
$ vault revoke aws/creds/deploy/774cfb27-c22d-6e78-0077-254879d1af3c
|
||||
Revoke error: Error making API request.
|
||||
|
||||
URL: PUT http://127.0.0.1:8200/v1/sys/revoke/aws/creds/deploy/774cfb27-c22d-6e78-0077-254879d1af3c
|
||||
Code: 400. Errors:
|
||||
|
||||
* invalid request
|
||||
```
|
||||
|
||||
The root credentials need permission to perform various IAM actions. These are the actions that the AWS secret backend uses to manage IAM credentials. Here is an example IAM policy that would grant these permissions:
|
||||
The `aws/config/root` credentials need permission to manage dynamic IAM users.
|
||||
Here is an example IAM policy that would grant these permissions:
|
||||
|
||||
```javascript
|
||||
{
|
||||
@ -176,14 +155,196 @@ The root credentials need permission to perform various IAM actions. These are t
|
||||
}
|
||||
```
|
||||
|
||||
Note that this policy example is unrelated to the policy you wrote to `aws/roles/deploy`. This policy example should be applied to the IAM user (or role) associated with the root credentials that you wrote to `aws/config/root`. You have to apply it yourself in IAM. The policy you wrote to `aws/roles/deploy` is the policy you want the AWS secret backend to apply to the temporary credentials it returns from `aws/creds/deploy`.
|
||||
Note that this policy example is unrelated to the policy you wrote to `aws/roles/deploy`.
|
||||
This policy example should be applied to the IAM user (or role) associated with
|
||||
the root credentials that you wrote to `aws/config/root`. You have to apply it
|
||||
yourself in IAM. The policy you wrote to `aws/roles/deploy` is the policy you
|
||||
want the AWS secret backend to apply to the temporary credentials it returns
|
||||
from `aws/creds/deploy`.
|
||||
|
||||
Unfortunately, IAM credentials are eventually consistent with respect to other
|
||||
Amazon services. If you are planning on using these credential in a pipeline,
|
||||
you may need to add a delay of 5-10 seconds (or more) after fetching
|
||||
credentials before they can be used successfully.
|
||||
|
||||
If you want to be able to use credentials without the wait, consider using the STS
|
||||
method of fetching keys. IAM credentials supported by an STS token are available for use
|
||||
as soon as they are generated.
|
||||
|
||||
## STS credentials
|
||||
|
||||
Vault also supports an STS credentials instead of creating a new IAM user.
|
||||
|
||||
The `aws/sts` endpoint will always fetch credentials with a 1hr ttl.
|
||||
Unlike the `aws/creds` enpoint, the ttl is enforced by STS.
|
||||
|
||||
Vault supports two of the [STS APIs](http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html),
|
||||
[STS federation tokens](http://docs.aws.amazon.com/STS/latest/APIReference/API_GetFederationToken.html) and
|
||||
[STS AssumeRole](http://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html).
|
||||
|
||||
### STS Federation Tokens
|
||||
|
||||
An STS federation token inherits a set of permissions that are the combination
|
||||
(intersection) of three sets of permissions:
|
||||
|
||||
1. The permissions granted to the `aws/config/root` credentials
|
||||
2. The user inline policy configured for the `aws/role`
|
||||
3. An implicit deny policy on IAM or STS operations.
|
||||
|
||||
STS federation token credentials can only be generated for user inline
|
||||
policies; the AWS GetFederationToken API does not support managed policies.
|
||||
|
||||
The `aws/config/root` credentials require IAM permissions for
|
||||
`sts:GetFederationToken` and the permissions to delegate to the STS
|
||||
federation token. For example, this policy on the `aws/config/root` credentials
|
||||
would allow creation of an STS federated token with delegated `ec2:*` permissions:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": {
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"ec2:*",
|
||||
"sts:GetFederationToken"
|
||||
],
|
||||
"Resource": "*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Our "deploy" role would then assign an inline user policy with the same `ec2:*`
|
||||
permissions.
|
||||
|
||||
```text
|
||||
$ vault write aws/roles/deploy \
|
||||
policy=@policy.json
|
||||
```
|
||||
|
||||
The policy.json file would contain an inline policy with similar permissions,
|
||||
less the `sts:GetFederationToken` permission. (We could grant `sts` permissions,
|
||||
but STS would attach an implict deny on `sts` that overides the allow.)
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": {
|
||||
"Effect": "Allow",
|
||||
"Action": "ec2:*",
|
||||
"Resource": "*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To generate a new set of STS federation token credentials, we simply read from
|
||||
the role using the aws/sts endpoint:
|
||||
|
||||
```text
|
||||
$vault read aws/sts/deploy
|
||||
Key Value
|
||||
lease_id aws/sts/deploy/31d771a6-fb39-f46b-fdc5-945109106422
|
||||
lease_duration 3600
|
||||
lease_renewable true
|
||||
access_key ASIAJYYYY2AA5K4WIXXX
|
||||
secret_key HSs0DYYYYYY9W81DXtI0K7X84H+OVZXK5BXXXX
|
||||
security_token AQoDYXdzEEwasAKwQyZUtZaCjVNDiXXXXXXXXgUgBBVUUbSyujLjsw6jYzboOQ89vUVIehUw/9MreAifXFmfdbjTr3g6zc0me9M+dB95DyhetFItX5QThw0lEsVQWSiIeIotGmg7mjT1//e7CJc4LpxbW707loFX1TYD1ilNnblEsIBKGlRNXZ+QJdguY4VkzXxv2urxIH0Sl14xtqsRPboV7eYruSEZlAuP3FLmqFbmA0AFPCT37cLf/vUHinSbvw49C4c9WQLH7CeFPhDub7/rub/QU/lCjjJ43IqIRo9jYgcEvvdRkQSt70zO8moGCc7pFvmL7XGhISegQpEzudErTE/PdhjlGpAKGR3d5qKrHpPYK/k480wk1Ai/t1dTa/8/3jUYTUeIkaJpNBnupQt7qoaXXXXXXXXXX
|
||||
```
|
||||
|
||||
### STS AssumeRole
|
||||
|
||||
STS AssumeRole is typically used for cross-account authentication or single sign-on (SSO)
|
||||
scenarios. AssumeRole has additional complexity compared STS federation tokens:
|
||||
|
||||
1. The ARN of a IAM role to assume
|
||||
2. IAM inline policies and/or managed policies attached to the IAM role
|
||||
3. IAM trust policy attached to the IAM role to grant privileges for one identity
|
||||
to assume the role.
|
||||
|
||||
AssumeRole adds a few benefits over federation tokens:
|
||||
|
||||
1. Assumed roles can invoke IAM and STS operations, if granted by the role's
|
||||
IAM policies.
|
||||
2. Assumed roles support cross-account authenication
|
||||
|
||||
The `aws/config/root` credentials must have an IAM policy that allows `sts:AssumeRole`
|
||||
against the target role:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": {
|
||||
"Effect": "Allow",
|
||||
"Action": "sts:AssumeRole",
|
||||
"Resource": "arn:aws:iam::ACCOUNT-ID-WITHOUT-HYPHENS:role/RoleNameToAssume"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You must attach a trust policy to the target IAM role to assume, allowing
|
||||
the aws/root/config credentials to assume the role.
|
||||
|
||||
```javascript
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::ACCOUNT-ID-WITHOUT-HYPHENS:user/VAULT-AWS-ROOT-CONFIG-USER-NAME"
|
||||
},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Finally, let's create a "deploy" policy using the arn of our role to assume:
|
||||
|
||||
```text
|
||||
$ vault write aws/roles/deploy \
|
||||
policy=arn:aws:iam::ACCOUNT-ID-WITHOUT-HYPHENS:role/RoleNameToAssume
|
||||
```
|
||||
|
||||
To generate a new set of STS assumed role credentials, we again read from
|
||||
the role using the aws/sts endpoint:
|
||||
|
||||
```text
|
||||
$vault read aws/sts/deploy
|
||||
Key Value
|
||||
lease_id aws/sts/deploy/31d771a6-fb39-f46b-fdc5-945109106422
|
||||
lease_duration 3600
|
||||
lease_renewable true
|
||||
access_key ASIAJYYYY2AA5K4WIXXX
|
||||
secret_key HSs0DYYYYYY9W81DXtI0K7X84H+OVZXK5BXXXX
|
||||
security_token AQoDYXdzEEwasAKwQyZUtZaCjVNDiXXXXXXXXgUgBBVUUbSyujLjsw6jYzboOQ89vUVIehUw/9MreAifXFmfdbjTr3g6zc0me9M+dB95DyhetFItX5QThw0lEsVQWSiIeIotGmg7mjT1//e7CJc4LpxbW707loFX1TYD1ilNnblEsIBKGlRNXZ+QJdguY4VkzXxv2urxIH0Sl14xtqsRPboV7eYruSEZlAuP3FLmqFbmA0AFPCT37cLf/vUHinSbvw49C4c9WQLH7CeFPhDub7/rub/QU/lCjjJ43IqIRo9jYgcEvvdRkQSt70zO8moGCc7pFvmL7XGhISegQpEzudErTE/PdhjlGpAKGR3d5qKrHpPYK/k480wk1Ai/t1dTa/8/3jUYTUeIkaJpNBnupQt7qoaXXXXXXXXXX
|
||||
```
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Dynamic IAM user errors
|
||||
|
||||
If you get an error message similar to either of the following, the root credentials that you wrote to `aws/config/root` have insufficient privilege:
|
||||
|
||||
```text
|
||||
$ vault read aws/creds/deploy
|
||||
* Error creating IAM user: User: arn:aws:iam::000000000000:user/hashicorp is not authorized to perform: iam:CreateUser on resource: arn:aws:iam::000000000000:user/vault-root-1432735386-4059
|
||||
|
||||
$ vault revoke aws/creds/deploy/774cfb27-c22d-6e78-0077-254879d1af3c
|
||||
Revoke error: Error making API request.
|
||||
|
||||
URL: PUT http://127.0.0.1:8200/v1/sys/revoke/aws/creds/deploy/774cfb27-c22d-6e78-0077-254879d1af3c
|
||||
Code: 400. Errors:
|
||||
|
||||
* invalid request
|
||||
```
|
||||
|
||||
If you get stuck at any time, simply run `vault path-help aws` or with a subpath for
|
||||
interactive help output.
|
||||
|
||||
## A Note on STS Permissions
|
||||
### STS federated token errors
|
||||
|
||||
Vault generates STS tokens using the IAM credentials passed to aws/config.
|
||||
Vault generates STS tokens using the IAM credentials passed to `aws/config`.
|
||||
|
||||
Those credentials must have two properties:
|
||||
|
||||
@ -195,19 +356,8 @@ If either of those conditions are not met, a "403 not-authorized" error will be
|
||||
|
||||
See http://docs.aws.amazon.com/STS/latest/APIReference/API_GetFederationToken.html for more details.
|
||||
|
||||
Vault 0.5.1 or later is recommended when using STS tokens to avoid validation errors for exceeding
|
||||
the AWS limit of 32 characters on STS token names.
|
||||
|
||||
## A Note on Consistency
|
||||
|
||||
Unfortunately, IAM credentials are eventually consistent with respect to other
|
||||
Amazon services. If you are planning on using these credential in a pipeline,
|
||||
you may need to add a delay of 5-10 seconds (or more) after fetching
|
||||
credentials before they can be used successfully.
|
||||
|
||||
If you want to be able to use credentials without the wait, consider using the STS
|
||||
method of fetching keys. IAM credentials supported by an STS token are available for use
|
||||
as soon as they are generated.
|
||||
Vault 0.5.1 or later is recommended when using STS tokens to avoid validation
|
||||
errors for exceeding the AWS limit of 32 characters on STS token names.
|
||||
|
||||
## API
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user