mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2026-01-10 22:21:40 +00:00
Added bound_account_id to aws-ec2 auth backend
This commit is contained in:
@@ -1056,9 +1056,16 @@ func TestBackend_PathBlacklistRoleTag(t *testing.T) {
|
||||
}
|
||||
|
||||
// This is an acceptance test.
|
||||
// Requires TEST_AWS_EC2_PKCS7, TEST_AWS_EC2_AMI_ID to be set.
|
||||
// If the test is not being run on an EC2 instance that has access to credentials using EC2RoleProvider,
|
||||
// then TEST_AWS_SECRET_KEY and TEST_AWS_ACCESS_KEY env vars are also required.
|
||||
// Requires the following env vars:
|
||||
// TEST_AWS_EC2_PKCS7
|
||||
// TEST_AWS_EC2_AMI_ID
|
||||
// TEST_AWS_EC2_ACCOUNT_ID
|
||||
//
|
||||
// If the test is not being run on an EC2 instance that has access to
|
||||
// credentials using EC2RoleProvider, on top of the above vars, following
|
||||
// needs to be set:
|
||||
// TEST_AWS_SECRET_KEY
|
||||
// TEST_AWS_ACCESS_KEY
|
||||
func TestBackendAcc_LoginAndWhitelistIdentity(t *testing.T) {
|
||||
// This test case should be run only when certain env vars are set and
|
||||
// executed as an acceptance test.
|
||||
@@ -1077,6 +1084,11 @@ func TestBackendAcc_LoginAndWhitelistIdentity(t *testing.T) {
|
||||
t.Fatalf("env var TEST_AWS_EC2_AMI_ID not set")
|
||||
}
|
||||
|
||||
accountID := os.Getenv("TEST_AWS_EC2_ACCOUNT_ID")
|
||||
if accountID == "" {
|
||||
t.Fatalf("env var TEST_AWS_EC2_ACCOUNT_ID not set")
|
||||
}
|
||||
|
||||
roleName := amiID
|
||||
|
||||
// create the backend
|
||||
@@ -1123,9 +1135,10 @@ func TestBackendAcc_LoginAndWhitelistIdentity(t *testing.T) {
|
||||
|
||||
// create an entry for the role. This is required for login to work.
|
||||
data := map[string]interface{}{
|
||||
"policies": "root",
|
||||
"max_ttl": "120s",
|
||||
"bound_ami_id": "wrong_ami_id",
|
||||
"policies": "root",
|
||||
"max_ttl": "120s",
|
||||
"bound_ami_id": "wrong_ami_id",
|
||||
"bound_account_id": accountID,
|
||||
}
|
||||
|
||||
roleReq := &logical.Request{
|
||||
@@ -1136,11 +1149,8 @@ func TestBackendAcc_LoginAndWhitelistIdentity(t *testing.T) {
|
||||
}
|
||||
|
||||
resp, err := b.HandleRequest(roleReq)
|
||||
if resp != nil && resp.IsError() {
|
||||
t.Fatalf("failed to create role")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
if err != nil && (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: resp: %#v\nerr:%v", resp, err)
|
||||
}
|
||||
|
||||
loginInput := map[string]interface{}{
|
||||
@@ -1163,18 +1173,29 @@ func TestBackendAcc_LoginAndWhitelistIdentity(t *testing.T) {
|
||||
|
||||
// Place the correct AMI ID on the role
|
||||
data["bound_ami_id"] = amiID
|
||||
// Place incorrect AccountID on the role
|
||||
data["bound_account_id"] = "wrong-account-id"
|
||||
resp, err = b.HandleRequest(roleReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: failed to create role: resp:%#v\nerr:%v", resp, err)
|
||||
}
|
||||
|
||||
// Try to login after the role has a matching AMI ID
|
||||
// Try to login with incorrect AccountID
|
||||
resp, err = b.HandleRequest(loginRequest)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
if err != nil || resp == nil || (resp != nil && !resp.IsError()) {
|
||||
t.Fatalf("bad: expected error response: resp:%#v\nerr:%v", resp, err)
|
||||
}
|
||||
if resp == nil || resp.Auth == nil || resp.IsError() {
|
||||
t.Fatalf("first login attempt failed")
|
||||
|
||||
data["bound_account_id"] = accountID
|
||||
resp, err = b.HandleRequest(roleReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("bad: failed to create role: resp:%#v\nerr:%v", resp, err)
|
||||
}
|
||||
|
||||
// Try to login after the role has a matching AMI ID and AccountID
|
||||
resp, err = b.HandleRequest(loginRequest)
|
||||
if err != nil || resp == nil || resp.Auth == nil || resp.IsError() {
|
||||
t.Fatalf("bad: first login attempt failed: resp:%#v\nerr:%v", resp, err)
|
||||
}
|
||||
|
||||
// Attempt to login again and see if it succeeds
|
||||
|
||||
@@ -244,11 +244,18 @@ func (b *backend) pathLoginUpdate(
|
||||
return logical.ErrorResponse("role entry not found"), nil
|
||||
}
|
||||
|
||||
// Only 'bound_ami_id' constraint is supported on the role currently.
|
||||
// Check if the AMI ID of the instance trying to login matches the
|
||||
//log.Printf("\nrole:%#v\n", roleEntry)
|
||||
//log.Printf("\nidentityDoc:%#v\n", identityDoc)
|
||||
// Verify that the AMI ID of the instance trying to login matches the
|
||||
// AMI ID specified as a constraint on the role.
|
||||
if identityDoc.AmiID != roleEntry.BoundAmiID {
|
||||
return logical.ErrorResponse(fmt.Sprintf("AMI ID %s does not belong to role %s", identityDoc.AmiID, roleName)), nil
|
||||
if roleEntry.BoundAmiID != "" && identityDoc.AmiID != roleEntry.BoundAmiID {
|
||||
return logical.ErrorResponse(fmt.Sprintf("AMI ID '%s' does not belong to role '%s'", identityDoc.AmiID, roleName)), nil
|
||||
}
|
||||
|
||||
// Verify that the AccountID of the instance trying to login matches the
|
||||
// AccountID specified as a constraint on the role.
|
||||
if roleEntry.BoundAccountID != "" && identityDoc.AccountID != roleEntry.BoundAccountID {
|
||||
return logical.ErrorResponse(fmt.Sprintf("Account ID '%s' does not belong to role '%s'", identityDoc.AccountID, roleName)), nil
|
||||
}
|
||||
|
||||
// Get the entry from the identity whitelist, if there is one.
|
||||
@@ -543,6 +550,7 @@ type identityDocument struct {
|
||||
Tags map[string]interface{} `json:"tags,omitempty" structs:"tags" mapstructure:"tags"`
|
||||
InstanceID string `json:"instanceId,omitempty" structs:"instanceId" mapstructure:"instanceId"`
|
||||
AmiID string `json:"imageId,omitempty" structs:"imageId" mapstructure:"imageId"`
|
||||
AccountID string `json:"accountId,omitempty" structs:"accountId" mapstructure:"accountId"`
|
||||
Region string `json:"region,omitempty" structs:"region" mapstructure:"region"`
|
||||
PendingTime string `json:"pendingTime,omitempty" structs:"pendingTime" mapstructure:"pendingTime"`
|
||||
}
|
||||
|
||||
@@ -20,37 +20,36 @@ func pathRole(b *backend) *framework.Path {
|
||||
Type: framework.TypeString,
|
||||
Description: "Name of the role.",
|
||||
},
|
||||
|
||||
"bound_ami_id": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: `If set, defines a constraint on the EC2 instances that they should be
|
||||
using the AMI ID specified by this parameter.`,
|
||||
},
|
||||
|
||||
"bound_account_id": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: `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.`,
|
||||
},
|
||||
"role_tag": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Default: "",
|
||||
Description: "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.",
|
||||
},
|
||||
|
||||
"max_ttl": &framework.FieldSchema{
|
||||
Type: framework.TypeDurationSecond,
|
||||
Default: 0,
|
||||
Description: "The maximum allowed lifetime of tokens issued using this role.",
|
||||
},
|
||||
|
||||
"policies": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Default: "default",
|
||||
Description: "Policies to be set on tokens issued using this role.",
|
||||
},
|
||||
|
||||
"allow_instance_migration": &framework.FieldSchema{
|
||||
Type: framework.TypeBool,
|
||||
Default: false,
|
||||
Description: "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.",
|
||||
},
|
||||
|
||||
"disallow_reauthentication": &framework.FieldSchema{
|
||||
Type: framework.TypeBool,
|
||||
Default: false,
|
||||
@@ -204,17 +203,19 @@ func (b *backend) pathRoleCreateUpdate(
|
||||
roleEntry = &awsRoleEntry{}
|
||||
}
|
||||
|
||||
// Set the bound parameters only if they are supplied.
|
||||
// There are no default values for bound parameters.
|
||||
boundAmiIDStr, ok := data.GetOk("bound_ami_id")
|
||||
if ok {
|
||||
roleEntry.BoundAmiID = boundAmiIDStr.(string)
|
||||
// Set BoundAmiID only if it is supplied. There can't be a default value.
|
||||
if boundAmiIDRaw, ok := data.GetOk("bound_ami_id"); ok {
|
||||
roleEntry.BoundAmiID = boundAmiIDRaw.(string)
|
||||
}
|
||||
|
||||
// At least one bound parameter should be set. Currently, only
|
||||
// 'bound_ami_id' is supported. Check if that is set.
|
||||
if roleEntry.BoundAmiID == "" {
|
||||
return logical.ErrorResponse("role is not bounded to any resource; set bound_ami_id"), nil
|
||||
// Set BoundAccountID only if it is supplied. There can't be a default value.
|
||||
if boundAccountIDRaw, ok := data.GetOk("bound_account_id"); ok {
|
||||
roleEntry.BoundAccountID = boundAccountIDRaw.(string)
|
||||
}
|
||||
|
||||
// Ensure that at least one bound is set on the role
|
||||
if roleEntry.BoundAccountID == "" && roleEntry.BoundAmiID == "" {
|
||||
return logical.ErrorResponse("at least be one bound parameter should be specified on the role"), nil
|
||||
}
|
||||
|
||||
policiesStr, ok := data.GetOk("policies")
|
||||
@@ -295,6 +296,7 @@ func (b *backend) pathRoleCreateUpdate(
|
||||
// Struct to hold the information associated with an AMI ID in Vault.
|
||||
type awsRoleEntry struct {
|
||||
BoundAmiID string `json:"bound_ami_id" structs:"bound_ami_id" mapstructure:"bound_ami_id"`
|
||||
BoundAccountID string `json:"bound_account_id" structs:"bound_account_id" mapstructure:"bound_account_id"`
|
||||
RoleTag string `json:"role_tag" structs:"role_tag" mapstructure:"role_tag"`
|
||||
AllowInstanceMigration bool `json:"allow_instance_migration" structs:"allow_instance_migration" mapstructure:"allow_instance_migration"`
|
||||
MaxTTL time.Duration `json:"max_ttl" structs:"max_ttl" mapstructure:"max_ttl"`
|
||||
|
||||
@@ -790,11 +790,11 @@ The response will be in JSON. For example:
|
||||
<dl class="api">
|
||||
<dt>Description</dt>
|
||||
<dd>
|
||||
Registers a role in the backend. Only those instances which are using the role registered using this endpoint,
|
||||
will be able to perform the login operation. Contraints can be specified on the role, that are applied on the
|
||||
instances attempting to login. Currently only one constraint is supported which is 'bound_ami_id', which must
|
||||
be specified. Going forward, when more than one constraint is supported, the requirement will be to specify at
|
||||
least one constraint, but not necessarily 'bound_ami_id'.
|
||||
Registers a role in the backend. Only those instances which are using
|
||||
the role registered using this endpoint, will be able to perform the login
|
||||
operation. Contraints can be specified on the role, that are applied on the
|
||||
instances attempting to login. At least one constraint should be specified
|
||||
on the role.
|
||||
</dd>
|
||||
|
||||
<dt>Method</dt>
|
||||
@@ -815,8 +815,17 @@ The response will be in JSON. For example:
|
||||
<ul>
|
||||
<li>
|
||||
<span class="param">bound_ami_id</span>
|
||||
<span class="param-flags">required</span>
|
||||
If set, defines a constraint on the EC2 instances that they should be using the AMI ID specified by this parameter.
|
||||
<span class="param-flags">optional</span>
|
||||
If set, defines a constraint on the EC2 instances that they
|
||||
should be using the AMI ID specified by this parameter.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="param">bound_account_id</span>
|
||||
<span class="param-flags">optional</span>
|
||||
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.
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
|
||||
Reference in New Issue
Block a user