secret/aws: Using roles instead of policy

This commit is contained in:
Armon Dadgar 2015-04-27 14:20:28 -07:00
parent 5edf8cf3a8
commit 434305a6c2
5 changed files with 53 additions and 50 deletions

View File

@ -26,7 +26,7 @@ func Backend() *framework.Backend {
Paths: []*framework.Path{ Paths: []*framework.Path{
pathConfigRoot(), pathConfigRoot(),
pathConfigLease(&b), pathConfigLease(&b),
pathPolicy(), pathRoles(),
pathUser(&b), pathUser(&b),
}, },
@ -52,5 +52,5 @@ are automatically revoked at the end of the lease.
After mounting this backend, credentials to generate IAM keys must After mounting this backend, credentials to generate IAM keys must
be configured with the "root" path and policies must be written using be configured with the "root" path and policies must be written using
the "policy/" endpoints before any access keys can be generated. the "roles/" endpoints before any access keys can be generated.
` `

View File

@ -76,7 +76,7 @@ func testAccStepConfig(t *testing.T) logicaltest.TestStep {
func testAccStepReadUser(t *testing.T, name string) logicaltest.TestStep { func testAccStepReadUser(t *testing.T, name string) logicaltest.TestStep {
return logicaltest.TestStep{ return logicaltest.TestStep{
Operation: logical.ReadOperation, Operation: logical.ReadOperation,
Path: name, Path: "creds/" + name,
Check: func(resp *logical.Response) error { Check: func(resp *logical.Response) error {
var d struct { var d struct {
AccessKey string `mapstructure:"access_key"` AccessKey string `mapstructure:"access_key"`
@ -109,7 +109,7 @@ func testAccStepReadUser(t *testing.T, name string) logicaltest.TestStep {
func testAccStepWritePolicy(t *testing.T, name string, policy string) logicaltest.TestStep { func testAccStepWritePolicy(t *testing.T, name string, policy string) logicaltest.TestStep {
return logicaltest.TestStep{ return logicaltest.TestStep{
Operation: logical.WriteOperation, Operation: logical.WriteOperation,
Path: "policy/" + name, Path: "roles/" + name,
Data: map[string]interface{}{ Data: map[string]interface{}{
"policy": testPolicy, "policy": testPolicy,
}, },
@ -119,14 +119,14 @@ func testAccStepWritePolicy(t *testing.T, name string, policy string) logicaltes
func testAccStepDeletePolicy(t *testing.T, n string) logicaltest.TestStep { func testAccStepDeletePolicy(t *testing.T, n string) logicaltest.TestStep {
return logicaltest.TestStep{ return logicaltest.TestStep{
Operation: logical.DeleteOperation, Operation: logical.DeleteOperation,
Path: "policy/" + n, Path: "roles/" + n,
} }
} }
func testAccStepReadPolicy(t *testing.T, name string, value string) logicaltest.TestStep { func testAccStepReadPolicy(t *testing.T, name string, value string) logicaltest.TestStep {
return logicaltest.TestStep{ return logicaltest.TestStep{
Operation: logical.ReadOperation, Operation: logical.ReadOperation,
Path: "policy/" + name, Path: "roles/" + name,
Check: func(resp *logical.Response) error { Check: func(resp *logical.Response) error {
if resp == nil { if resp == nil {
if value == "" { if value == "" {

View File

@ -9,9 +9,9 @@ import (
"github.com/hashicorp/vault/logical/framework" "github.com/hashicorp/vault/logical/framework"
) )
func pathPolicy() *framework.Path { func pathRoles() *framework.Path {
return &framework.Path{ return &framework.Path{
Pattern: `policy/(?P<name>\w+)`, Pattern: `roles/(?P<name>\w+)`,
Fields: map[string]*framework.FieldSchema{ Fields: map[string]*framework.FieldSchema{
"name": &framework.FieldSchema{ "name": &framework.FieldSchema{
Type: framework.TypeString, Type: framework.TypeString,
@ -25,17 +25,17 @@ func pathPolicy() *framework.Path {
}, },
Callbacks: map[logical.Operation]framework.OperationFunc{ Callbacks: map[logical.Operation]framework.OperationFunc{
logical.DeleteOperation: pathPolicyDelete, logical.DeleteOperation: pathRolesDelete,
logical.ReadOperation: pathPolicyRead, logical.ReadOperation: pathRolesRead,
logical.WriteOperation: pathPolicyWrite, logical.WriteOperation: pathRolesWrite,
}, },
HelpSynopsis: pathPolicyHelpSyn, HelpSynopsis: pathRolesHelpSyn,
HelpDescription: pathPolicyHelpDesc, HelpDescription: pathRolesHelpDesc,
} }
} }
func pathPolicyDelete( func pathRolesDelete(
req *logical.Request, d *framework.FieldData) (*logical.Response, error) { req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
err := req.Storage.Delete("policy/" + d.Get("name").(string)) err := req.Storage.Delete("policy/" + d.Get("name").(string))
if err != nil { if err != nil {
@ -45,7 +45,7 @@ func pathPolicyDelete(
return nil, nil return nil, nil
} }
func pathPolicyRead( func pathRolesRead(
req *logical.Request, d *framework.FieldData) (*logical.Response, error) { req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
entry, err := req.Storage.Get("policy/" + d.Get("name").(string)) entry, err := req.Storage.Get("policy/" + d.Get("name").(string))
if err != nil { if err != nil {
@ -62,7 +62,7 @@ func pathPolicyRead(
}, nil }, nil
} }
func pathPolicyWrite( func pathRolesWrite(
req *logical.Request, d *framework.FieldData) (*logical.Response, error) { req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
var buf bytes.Buffer var buf bytes.Buffer
if err := json.Compact(&buf, []byte(d.Get("policy").(string))); err != nil { if err := json.Compact(&buf, []byte(d.Get("policy").(string))); err != nil {
@ -82,16 +82,16 @@ func pathPolicyWrite(
return nil, nil return nil, nil
} }
const pathPolicyHelpSyn = ` const pathRolesHelpSyn = `
Read and write IAM policies that access keys can be made for. Read and write IAM policies that access keys can be made for.
` `
const pathPolicyHelpDesc = ` const pathRolesHelpDesc = `
This path allows you to read and write policies that are used to This path allows you to read and write roles that are used to
create access keys. These policies map directly to the route to read the create access keys. These roles have IAM policies that map directly to the route to read the
access keys. For example, if the backend is mounted at "aws" and you access keys. For example, if the backend is mounted at "aws" and you
wrote a policy to "aws/policy/deploy" then a user could request access create a role at "aws/roles/deploy" then a user could request access
credentials at "aws/deploy". credentials at "aws/creds/deploy".
The policies written are normal IAM policies. Vault will not attempt to The policies written are normal IAM policies. Vault will not attempt to
parse these except to validate that they're basic JSON. To validate the parse these except to validate that they're basic JSON. To validate the

View File

@ -12,11 +12,11 @@ import (
func pathUser(b *backend) *framework.Path { func pathUser(b *backend) *framework.Path {
return &framework.Path{ return &framework.Path{
Pattern: `(?P<name>\w+)`, Pattern: `creds/(?P<name>\w+)`,
Fields: map[string]*framework.FieldSchema{ Fields: map[string]*framework.FieldSchema{
"name": &framework.FieldSchema{ "name": &framework.FieldSchema{
Type: framework.TypeString, Type: framework.TypeString,
Description: "Name of the policy", Description: "Name of the role",
}, },
}, },
@ -36,11 +36,11 @@ func (b *backend) pathUserRead(
// Read the policy // Read the policy
policy, err := req.Storage.Get("policy/" + policyName) policy, err := req.Storage.Get("policy/" + policyName)
if err != nil { if err != nil {
return nil, fmt.Errorf("error retrieving policy: %s", err) return nil, fmt.Errorf("error retrieving role: %s", err)
} }
if policy == nil { if policy == nil {
return logical.ErrorResponse(fmt.Sprintf( return logical.ErrorResponse(fmt.Sprintf(
"Policy '%s' not found", policyName)), nil "Role '%s' not found", policyName)), nil
} }
// Use the helper to create the secret // Use the helper to create the secret
@ -138,14 +138,14 @@ type walUser struct {
} }
const pathUserHelpSyn = ` const pathUserHelpSyn = `
Generate an access key pair for a specific policy. Generate an access key pair for a specific role.
` `
const pathUserHelpDesc = ` const pathUserHelpDesc = `
This path will generate a new, never before used key pair for This path will generate a new, never before used key pair for
accessing AWS. The IAM policy used to back this key pair will be accessing AWS. The IAM policy used to back this key pair will be
the "name" parameter. For example, if this backend is mounted at "aws", the "name" parameter. For example, if this backend is mounted at "aws",
then "aws/deploy" would generate access keys for the "deploy" policy. then "aws/creds/deploy" would generate access keys for the "deploy" role.
The access keys will have a lease associated with them. The access keys The access keys will have a lease associated with them. The access keys
can be revoked by using the lease ID. can be revoked by using the lease ID.

View File

@ -20,14 +20,15 @@ on every path, use `vault help` after mounting the backend.
## Quick Start ## Quick Start
Mount the aws secret backend using the `vault mount` command: The first step to using the aws backend is to mount it.
Unlike the `generic` backend, the `aws` backend is not mounted by default.
```text ```text
$ vault mount aws $ vault mount aws
Successfully mounted 'aws' at 'aws'! Successfully mounted 'aws' at 'aws'!
``` ```
Configure the root credentials that are used to manage IAM credentials: Next, we must configure the root credentials that are used to manage IAM credentials:
```text ```text
$ vault write aws/config/root \ $ vault write aws/config/root \
@ -44,17 +45,19 @@ The following parameters are required:
credentials. credentials.
- `region` the AWS region for API calls. - `region` the AWS region for API calls.
Create an IAM policy: The next step is to configure a role. A role is a logical name that maps
to a policy used to generated those credentials. For example, lets create
a "deploy" role:
```text ```text
$ vault write aws/policy/deploy \ $ vault write aws/roles/deploy \
name=deploy \ name=deploy \
policy=@policy.json policy=@policy.json
``` ```
This path will generate a new, never before used key pair for This path will create a named role along with the IAM policy used
accessing AWS. The IAM policy used to back this key pair will be to restrict permissions for it. This is used to dynamically create
the "name" parameter, which is "deploy" in this example. a new pair of IAM credentials when needed.
The `@` tells Vault to load the policy from the file named `policy.json`. Here The `@` tells Vault to load the policy from the file named `policy.json`. Here
is an example IAM policy to get started: is an example IAM policy to get started:
@ -73,12 +76,12 @@ is an example IAM policy to get started:
For more information on IAM policies, please see the For more information on IAM policies, please see the
[AWS IAM policy documentation](http://docs.aws.amazon.com/IAM/latest/UserGuide/PoliciesOverview.html). [AWS IAM policy documentation](http://docs.aws.amazon.com/IAM/latest/UserGuide/PoliciesOverview.html).
Vault can now generate IAM credentials under the given policy: To generate a new set of IAM credentials, we simply read from that role:
```text ```text
$ vault read aws/deploy $ vault read aws/creds/deploy
Key Value Key Value
lease_id aws/deploy/7cb8df71-782f-3de1-79dd-251778e49f58 lease_id aws/creds/deploy/7cb8df71-782f-3de1-79dd-251778e49f58
lease_duration 3600 lease_duration 3600
access_key AKIAIOMYUTSLGJOGLHTQ access_key AKIAIOMYUTSLGJOGLHTQ
secret_key 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 secret_key BK9++oBABaBvRKcT5KEF69xQGcH7ZpPRF3oqVEv7
@ -87,9 +90,9 @@ secret_key BK9++oBABaBvRKcT5KEF69xQGcH7ZpPRF3oqVEv7
If you run the command again, you will get a new set of credentials: If you run the command again, you will get a new set of credentials:
```text ```text
$ vault read aws/deploy $ vault read aws/creds/deploy
Key Value Key Value
lease_id aws/deploy/82d89562-ff19-382e-6be9-cb45c8f6a42d lease_id aws/creds/deploy/82d89562-ff19-382e-6be9-cb45c8f6a42d
lease_duration 3600 lease_duration 3600
access_key AKIAJZ5YRPHFH3QHRRRQ access_key AKIAJZ5YRPHFH3QHRRRQ
secret_key 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 secret_key vS61xxXgwwX/V4qZMUv8O8wd2RLqngXz6WmN04uW
@ -183,20 +186,20 @@ interactive help output.
</dd> </dd>
</dl> </dl>
### /aws/policy/ ### /aws/roles/
#### POST #### POST
<dl class="api"> <dl class="api">
<dt>Description</dt> <dt>Description</dt>
<dd> <dd>
Creates or updates a named policy. Creates or updates a named role.
</dd> </dd>
<dt>Method</dt> <dt>Method</dt>
<dd>POST</dd> <dd>POST</dd>
<dt>URL</dt> <dt>URL</dt>
<dd>`/aws/policy/<name>`</dd> <dd>`/aws/roles/<name>`</dd>
<dt>Parameters</dt> <dt>Parameters</dt>
<dd> <dd>
@ -220,14 +223,14 @@ interactive help output.
<dl class="api"> <dl class="api">
<dt>Description</dt> <dt>Description</dt>
<dd> <dd>
Queries a named policy. Queries a named role.
</dd> </dd>
<dt>Method</dt> <dt>Method</dt>
<dd>GET</dd> <dd>GET</dd>
<dt>URL</dt> <dt>URL</dt>
<dd>`/aws/policy/<name>`</dd> <dd>`/aws/roles/<name>`</dd>
<dt>Parameters</dt> <dt>Parameters</dt>
<dd> <dd>
@ -253,14 +256,14 @@ interactive help output.
<dl class="api"> <dl class="api">
<dt>Description</dt> <dt>Description</dt>
<dd> <dd>
Deletes a named policy. Deletes a named role.
</dd> </dd>
<dt>Method</dt> <dt>Method</dt>
<dd>DELETE</dd> <dd>DELETE</dd>
<dt>URL</dt> <dt>URL</dt>
<dd>`/aws/policy/<name>`</dd> <dd>`/aws/roles/<name>`</dd>
<dt>Parameters</dt> <dt>Parameters</dt>
<dd> <dd>
@ -274,20 +277,20 @@ interactive help output.
</dl> </dl>
### /aws/ ### /aws/creds/
#### GET #### GET
<dl class="api"> <dl class="api">
<dt>Description</dt> <dt>Description</dt>
<dd> <dd>
Generates a dynamic IAM credential based on the named policy. Generates a dynamic IAM credential based on the named role.
</dd> </dd>
<dt>Method</dt> <dt>Method</dt>
<dd>GET</dd> <dd>GET</dd>
<dt>URL</dt> <dt>URL</dt>
<dd>`/aws/<name>`</dd> <dd>`/aws/creds/<name>`</dd>
<dt>Parameters</dt> <dt>Parameters</dt>
<dd> <dd>