secret/aws: Using roles instead of policy
This commit is contained in:
parent
5edf8cf3a8
commit
434305a6c2
|
@ -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.
|
||||||
`
|
`
|
||||||
|
|
|
@ -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 == "" {
|
||||||
|
|
|
@ -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
|
|
@ -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.
|
||||||
|
|
|
@ -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 BK9++oBABaBvRKcT5KEF69xQGcH7ZpPRF3oqVEv7
|
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 vS61xxXgwwX/V4qZMUv8O8wd2RLqngXz6WmN04uW
|
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>
|
||||||
|
|
Loading…
Reference in a new issue