Implemented bound_iam_role_arn constraint
This commit is contained in:
parent
2d4bfeff49
commit
bf0b7f218e
|
@ -5,6 +5,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/service/ec2"
|
"github.com/aws/aws-sdk-go/service/ec2"
|
||||||
|
"github.com/aws/aws-sdk-go/service/iam"
|
||||||
"github.com/hashicorp/vault/helper/salt"
|
"github.com/hashicorp/vault/helper/salt"
|
||||||
"github.com/hashicorp/vault/logical"
|
"github.com/hashicorp/vault/logical"
|
||||||
"github.com/hashicorp/vault/logical/framework"
|
"github.com/hashicorp/vault/logical/framework"
|
||||||
|
@ -49,6 +50,12 @@ type backend struct {
|
||||||
// the credentials are modified or deleted, all the cached client objects
|
// the credentials are modified or deleted, all the cached client objects
|
||||||
// will be flushed.
|
// will be flushed.
|
||||||
EC2ClientsMap map[string]*ec2.EC2
|
EC2ClientsMap map[string]*ec2.EC2
|
||||||
|
|
||||||
|
// Map to hold the IAM client objects indexed by region. This avoids
|
||||||
|
// the overhead of creating a client object for every login request.
|
||||||
|
// When the credentials are modified or deleted, all the cached client
|
||||||
|
// objects will be flushed.
|
||||||
|
IAMClientsMap map[string]*iam.IAM
|
||||||
}
|
}
|
||||||
|
|
||||||
func Backend(conf *logical.BackendConfig) (*backend, error) {
|
func Backend(conf *logical.BackendConfig) (*backend, error) {
|
||||||
|
@ -65,6 +72,7 @@ func Backend(conf *logical.BackendConfig) (*backend, error) {
|
||||||
tidyCooldownPeriod: time.Hour,
|
tidyCooldownPeriod: time.Hour,
|
||||||
Salt: salt,
|
Salt: salt,
|
||||||
EC2ClientsMap: make(map[string]*ec2.EC2),
|
EC2ClientsMap: make(map[string]*ec2.EC2),
|
||||||
|
IAMClientsMap: make(map[string]*iam.IAM),
|
||||||
}
|
}
|
||||||
|
|
||||||
b.Backend = &framework.Backend{
|
b.Backend = &framework.Backend{
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/aws/session"
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
"github.com/aws/aws-sdk-go/service/ec2"
|
"github.com/aws/aws-sdk-go/service/ec2"
|
||||||
|
"github.com/aws/aws-sdk-go/service/iam"
|
||||||
"github.com/hashicorp/go-cleanhttp"
|
"github.com/hashicorp/go-cleanhttp"
|
||||||
"github.com/hashicorp/vault/helper/awsutil"
|
"github.com/hashicorp/vault/helper/awsutil"
|
||||||
"github.com/hashicorp/vault/logical"
|
"github.com/hashicorp/vault/logical"
|
||||||
|
@ -61,43 +62,82 @@ func (b *backend) getClientConfig(s logical.Storage, region string) (*aws.Config
|
||||||
|
|
||||||
// flushCachedEC2Clients deletes all the cached ec2 client objects from the backend.
|
// flushCachedEC2Clients deletes all the cached ec2 client objects from the backend.
|
||||||
// If the client credentials configuration is deleted or updated in the backend, all
|
// If the client credentials configuration is deleted or updated in the backend, all
|
||||||
// the cached EC2 client objects will be flushed.
|
// the cached EC2 client objects will be flushed. Config mutex lock should be
|
||||||
//
|
// acquired for write operation before calling this method.
|
||||||
// Write lock should be acquired using b.configMutex.Lock() before calling this method
|
|
||||||
// and lock should be released using b.configMutex.Unlock() after the method returns.
|
|
||||||
func (b *backend) flushCachedEC2Clients() {
|
func (b *backend) flushCachedEC2Clients() {
|
||||||
// deleting items in map during iteration is safe.
|
// deleting items in map during iteration is safe
|
||||||
for region, _ := range b.EC2ClientsMap {
|
for region, _ := range b.EC2ClientsMap {
|
||||||
delete(b.EC2ClientsMap, region)
|
delete(b.EC2ClientsMap, region)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clientEC2 creates a client to interact with AWS EC2 API.
|
// flushCachedIAMClients deletes all the cached iam client objects from the
|
||||||
|
// backend. If the client credentials configuration is deleted or updated in
|
||||||
|
// the backend, all the cached IAM client objects will be flushed. Config mutex
|
||||||
|
// lock should be acquired for write operation before calling this method.
|
||||||
|
func (b *backend) flushCachedIAMClients() {
|
||||||
|
// deleting items in map during iteration is safe
|
||||||
|
for region, _ := range b.IAMClientsMap {
|
||||||
|
delete(b.IAMClientsMap, region)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clientEC2 creates a client to interact with AWS EC2 API
|
||||||
func (b *backend) clientEC2(s logical.Storage, region string) (*ec2.EC2, error) {
|
func (b *backend) clientEC2(s logical.Storage, region string) (*ec2.EC2, error) {
|
||||||
b.configMutex.RLock()
|
b.configMutex.RLock()
|
||||||
if b.EC2ClientsMap[region] != nil {
|
if b.EC2ClientsMap[region] != nil {
|
||||||
defer b.configMutex.RUnlock()
|
defer b.configMutex.RUnlock()
|
||||||
// If the client object was already created, return it.
|
// If the client object was already created, return it
|
||||||
return b.EC2ClientsMap[region], nil
|
return b.EC2ClientsMap[region], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release the read lock and acquire the write lock.
|
// Release the read lock and acquire the write lock
|
||||||
b.configMutex.RUnlock()
|
b.configMutex.RUnlock()
|
||||||
b.configMutex.Lock()
|
b.configMutex.Lock()
|
||||||
defer b.configMutex.Unlock()
|
defer b.configMutex.Unlock()
|
||||||
|
|
||||||
// If the client gets created while switching the locks, return it.
|
// If the client gets created while switching the locks, return it
|
||||||
if b.EC2ClientsMap[region] != nil {
|
if b.EC2ClientsMap[region] != nil {
|
||||||
return b.EC2ClientsMap[region], nil
|
return b.EC2ClientsMap[region], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a AWS config object using a chain of providers.
|
// Create an AWS config object using a chain of providers
|
||||||
awsConfig, err := b.getClientConfig(s, region)
|
awsConfig, err := b.getClientConfig(s, region)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new EC2 client object, cache it and return the same.
|
// Create a new EC2 client object, cache it and return the same
|
||||||
b.EC2ClientsMap[region] = ec2.New(session.New(awsConfig))
|
b.EC2ClientsMap[region] = ec2.New(session.New(awsConfig))
|
||||||
return b.EC2ClientsMap[region], nil
|
return b.EC2ClientsMap[region], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clientIAM creates a client to interact with AWS IAM API
|
||||||
|
func (b *backend) clientIAM(s logical.Storage, region string) (*iam.IAM, error) {
|
||||||
|
b.configMutex.RLock()
|
||||||
|
if b.IAMClientsMap[region] != nil {
|
||||||
|
defer b.configMutex.RUnlock()
|
||||||
|
// If the client object was already created, return it
|
||||||
|
return b.IAMClientsMap[region], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the read lock and acquire the write lock
|
||||||
|
b.configMutex.RUnlock()
|
||||||
|
b.configMutex.Lock()
|
||||||
|
defer b.configMutex.Unlock()
|
||||||
|
|
||||||
|
// If the client gets created while switching the locks, return it
|
||||||
|
if b.IAMClientsMap[region] != nil {
|
||||||
|
return b.IAMClientsMap[region], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an AWS config object using a chain of providers
|
||||||
|
awsConfig, err := b.getClientConfig(s, region)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new IAM client object, cache it and return the same
|
||||||
|
b.IAMClientsMap[region] = iam.New(session.New(awsConfig))
|
||||||
|
return b.IAMClientsMap[region], nil
|
||||||
|
}
|
||||||
|
|
|
@ -108,6 +108,9 @@ func (b *backend) pathConfigClientDelete(
|
||||||
// Remove all the cached EC2 client objects in the backend.
|
// Remove all the cached EC2 client objects in the backend.
|
||||||
b.flushCachedEC2Clients()
|
b.flushCachedEC2Clients()
|
||||||
|
|
||||||
|
// Remove all the cached EC2 client objects in the backend.
|
||||||
|
b.flushCachedIAMClients()
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +178,7 @@ func (b *backend) pathConfigClientCreateUpdate(
|
||||||
|
|
||||||
if changedCreds {
|
if changedCreds {
|
||||||
b.flushCachedEC2Clients()
|
b.flushCachedEC2Clients()
|
||||||
|
b.flushCachedIAMClients()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
@ -4,10 +4,12 @@ import (
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/service/ec2"
|
"github.com/aws/aws-sdk-go/service/ec2"
|
||||||
|
"github.com/aws/aws-sdk-go/service/iam"
|
||||||
"github.com/fullsailor/pkcs7"
|
"github.com/fullsailor/pkcs7"
|
||||||
"github.com/hashicorp/go-uuid"
|
"github.com/hashicorp/go-uuid"
|
||||||
"github.com/hashicorp/vault/helper/jsonutil"
|
"github.com/hashicorp/vault/helper/jsonutil"
|
||||||
|
@ -61,6 +63,39 @@ on either the role or the role tag, the 'nonce' holds no significance.`,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// instanceIamRoleARN fetches the IAM role ARN associated with the given
|
||||||
|
// instance profile name
|
||||||
|
func (b *backend) instanceIamRoleARN(s logical.Storage, instanceProfileName, region string) (string, error) {
|
||||||
|
iamClient, err := b.clientIAM(s, region)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
profile, err := iamClient.GetInstanceProfile(&iam.GetInstanceProfileInput{
|
||||||
|
InstanceProfileName: aws.String(instanceProfileName),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if profile == nil {
|
||||||
|
return "", fmt.Errorf("nil output while getting instance profile details")
|
||||||
|
}
|
||||||
|
|
||||||
|
if profile.InstanceProfile == nil {
|
||||||
|
return "", fmt.Errorf("nil instance profile in the output of instance profile details")
|
||||||
|
}
|
||||||
|
|
||||||
|
if profile.InstanceProfile.Roles == nil || len(profile.InstanceProfile.Roles) != 1 {
|
||||||
|
return "", fmt.Errorf("invalid roles in the output of instance profile details")
|
||||||
|
}
|
||||||
|
|
||||||
|
if profile.InstanceProfile.Roles[0].Arn == nil {
|
||||||
|
return "", fmt.Errorf("nil role ARN in the output of instance profile details")
|
||||||
|
}
|
||||||
|
|
||||||
|
return *profile.InstanceProfile.Roles[0].Arn, nil
|
||||||
|
}
|
||||||
|
|
||||||
// validateInstance queries the status of the EC2 instance using AWS EC2 API and
|
// validateInstance queries the status of the EC2 instance using AWS EC2 API and
|
||||||
// checks if the instance is running and is healthy.
|
// checks if the instance is running and is healthy.
|
||||||
func (b *backend) validateInstance(s logical.Storage, instanceID, region string) (*ec2.DescribeInstancesOutput, error) {
|
func (b *backend) validateInstance(s logical.Storage, instanceID, region string) (*ec2.DescribeInstancesOutput, error) {
|
||||||
|
@ -83,6 +118,9 @@ func (b *backend) validateInstance(s logical.Storage, instanceID, region string)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error fetching description for instance ID %s: %s\n", instanceID, err)
|
return nil, fmt.Errorf("error fetching description for instance ID %s: %s\n", instanceID, err)
|
||||||
}
|
}
|
||||||
|
if status == nil {
|
||||||
|
return nil, fmt.Errorf("nil output from describe instances")
|
||||||
|
}
|
||||||
if len(status.Reservations) == 0 {
|
if len(status.Reservations) == 0 {
|
||||||
return nil, fmt.Errorf("no reservations found in instance description")
|
return nil, fmt.Errorf("no reservations found in instance description")
|
||||||
|
|
||||||
|
@ -284,9 +322,41 @@ func (b *backend) pathLoginUpdate(
|
||||||
if instanceDesc.Reservations[0].Instances[0].IamInstanceProfile.Arn == nil {
|
if instanceDesc.Reservations[0].Instances[0].IamInstanceProfile.Arn == nil {
|
||||||
return nil, fmt.Errorf("IAM instance profile ARN in the instance description is nil")
|
return nil, fmt.Errorf("IAM instance profile ARN in the instance description is nil")
|
||||||
}
|
}
|
||||||
iamInstanceProfileArn := *instanceDesc.Reservations[0].Instances[0].IamInstanceProfile.Arn
|
iamInstanceProfileARN := *instanceDesc.Reservations[0].Instances[0].IamInstanceProfile.Arn
|
||||||
if iamInstanceProfileArn != roleEntry.BoundIamInstanceProfileARN {
|
if iamInstanceProfileARN != roleEntry.BoundIamInstanceProfileARN {
|
||||||
return logical.ErrorResponse(fmt.Sprintf("IAM instance profile ARN %q does not satisfy the constraint role %q", iamInstanceProfileArn, roleName)), nil
|
return logical.ErrorResponse(fmt.Sprintf("IAM instance profile ARN %q does not satisfy the constraint role %q", iamInstanceProfileARN, roleName)), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the IAM role ARN of the instance trying to login, matches
|
||||||
|
// the IAM role ARN specified as a constraint on the role.
|
||||||
|
if roleEntry.BoundIamRoleARN != "" {
|
||||||
|
if instanceDesc.Reservations[0].Instances[0].IamInstanceProfile == nil {
|
||||||
|
return nil, fmt.Errorf("IAM instance profile in the instance description is nil")
|
||||||
|
}
|
||||||
|
if instanceDesc.Reservations[0].Instances[0].IamInstanceProfile.Id == nil {
|
||||||
|
return nil, fmt.Errorf("IAM instance profile identifier in the instance description is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the instance profile ARN from the instance description
|
||||||
|
iamInstanceProfileARN := *instanceDesc.Reservations[0].Instances[0].IamInstanceProfile.Arn
|
||||||
|
|
||||||
|
// Extract out the instance profile name from the instance
|
||||||
|
// profile ARN
|
||||||
|
iamInstanceProfileARNSlice := strings.SplitAfter(iamInstanceProfileARN, ":instance-profile/")
|
||||||
|
iamInstanceProfileName := iamInstanceProfileARNSlice[len(iamInstanceProfileARNSlice)-1]
|
||||||
|
|
||||||
|
// Use instance profile ARN to fetch the associated role ARN
|
||||||
|
iamRoleARN, err := b.instanceIamRoleARN(req.Storage, iamInstanceProfileName, identityDoc.Region)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("IAM role ARN could not be fetched: %v", err)
|
||||||
|
}
|
||||||
|
if iamRoleARN == "" {
|
||||||
|
return nil, fmt.Errorf("IAM role ARN could not be fetched")
|
||||||
|
}
|
||||||
|
|
||||||
|
if iamRoleARN != roleEntry.BoundIamRoleARN {
|
||||||
|
return logical.ErrorResponse(fmt.Sprintf("IAM role ARN %q does not satisfy the constraint role %q", iamRoleARN, roleName)), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,11 @@ using the AMI ID specified by this parameter.`,
|
||||||
Type: framework.TypeString,
|
Type: framework.TypeString,
|
||||||
Description: `If set, defines a constraint on the EC2 instances that the account ID
|
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.`,
|
in its identity document to match the one specified by this parameter.`,
|
||||||
|
},
|
||||||
|
"bound_iam_role_arn": {
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Description: `If set, defines a constraint on the EC2 instances that they should be using the
|
||||||
|
IAM role ARN specified by this parameter.`,
|
||||||
},
|
},
|
||||||
"bound_iam_instance_profile_arn": {
|
"bound_iam_instance_profile_arn": {
|
||||||
Type: framework.TypeString,
|
Type: framework.TypeString,
|
||||||
|
@ -194,22 +199,22 @@ func (b *backend) nonLockedAWSRole(s logical.Storage, roleName string) (*awsRole
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upgrade code to use proper field for bound_iam_instance_profile_arn
|
// Check if the value held by role ARN field is actually an instance profile ARN
|
||||||
if result.DeprecatedBoundIamARN != "" {
|
if result.BoundIamRoleARN != "" && strings.Contains(result.BoundIamRoleARN, ":instance-profile/") {
|
||||||
// For sanity
|
// For sanity
|
||||||
if result.BoundIamInstanceProfileARN != "" {
|
if result.BoundIamInstanceProfileARN != "" {
|
||||||
return nil, fmt.Errorf("both bound_iam_role_arn and bound_iam_instance_profile_arn are set")
|
return nil, fmt.Errorf("bound_iam_role_arn contains instance profile ARN and bound_iam_instance_profile_arn is non empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in the new field
|
// If yes, move it to the correct field
|
||||||
result.BoundIamInstanceProfileARN = result.DeprecatedBoundIamARN
|
result.BoundIamInstanceProfileARN = result.BoundIamRoleARN
|
||||||
|
|
||||||
// Reset the old field
|
// Reset the old field
|
||||||
result.DeprecatedBoundIamARN = ""
|
result.BoundIamRoleARN = ""
|
||||||
|
|
||||||
// Save the update
|
// Save the update
|
||||||
if err = b.nonLockedSetAWSRole(s, roleName, &result); err != nil {
|
if err = b.nonLockedSetAWSRole(s, roleName, &result); err != nil {
|
||||||
return nil, fmt.Errorf("failed to upgrade bound_iam_role_arn to bound_iam_instance_profile_arn")
|
return nil, fmt.Errorf("failed to move instance profile ARN to bound_iam_instance_profile_arn field")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,8 +251,6 @@ func (b *backend) pathRoleList(
|
||||||
// pathRoleRead is used to view the information registered for a given AMI ID.
|
// pathRoleRead is used to view the information registered for a given AMI ID.
|
||||||
func (b *backend) pathRoleRead(
|
func (b *backend) pathRoleRead(
|
||||||
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
resp := &logical.Response{}
|
|
||||||
|
|
||||||
roleEntry, err := b.lockedAWSRole(req.Storage, strings.ToLower(data.Get("role").(string)))
|
roleEntry, err := b.lockedAWSRole(req.Storage, strings.ToLower(data.Get("role").(string)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -267,15 +270,9 @@ func (b *backend) pathRoleRead(
|
||||||
// Display the max_ttl in seconds.
|
// Display the max_ttl in seconds.
|
||||||
respData["max_ttl"] = roleEntry.MaxTTL / time.Second
|
respData["max_ttl"] = roleEntry.MaxTTL / time.Second
|
||||||
|
|
||||||
// To be removed in the coming releases
|
return &logical.Response{
|
||||||
if respData["bound_iam_instance_profile_arn"] != "" {
|
Data: respData,
|
||||||
respData["bound_iam_role_arn"] = respData["bound_iam_instance_profile_arn"]
|
}, nil
|
||||||
resp.AddWarning("The field bound_iam_role_arn is deprecated and will be removed in future releases; refer bound_iam_instance_profile_arn instead.")
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.Data = respData
|
|
||||||
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pathRoleCreateUpdate is used to associate Vault policies to a given AMI ID.
|
// pathRoleCreateUpdate is used to associate Vault policies to a given AMI ID.
|
||||||
|
@ -298,16 +295,20 @@ func (b *backend) pathRoleCreateUpdate(
|
||||||
roleEntry = &awsRoleEntry{}
|
roleEntry = &awsRoleEntry{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set BoundAmiID only if it is supplied. There can't be a default value.
|
// Fetch and set the bound parameters. There can't be default values
|
||||||
|
// for these.
|
||||||
if boundAmiIDRaw, ok := data.GetOk("bound_ami_id"); ok {
|
if boundAmiIDRaw, ok := data.GetOk("bound_ami_id"); ok {
|
||||||
roleEntry.BoundAmiID = boundAmiIDRaw.(string)
|
roleEntry.BoundAmiID = boundAmiIDRaw.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set BoundAccountID only if it is supplied. There can't be a default value.
|
|
||||||
if boundAccountIDRaw, ok := data.GetOk("bound_account_id"); ok {
|
if boundAccountIDRaw, ok := data.GetOk("bound_account_id"); ok {
|
||||||
roleEntry.BoundAccountID = boundAccountIDRaw.(string)
|
roleEntry.BoundAccountID = boundAccountIDRaw.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if boundIamRoleARNRaw, ok := data.GetOk("bound_iam_role_arn"); ok {
|
||||||
|
roleEntry.BoundIamRoleARN = boundIamRoleARNRaw.(string)
|
||||||
|
}
|
||||||
|
|
||||||
if boundIamInstanceProfileARNRaw, ok := data.GetOk("bound_iam_instance_profile_arn"); ok {
|
if boundIamInstanceProfileARNRaw, ok := data.GetOk("bound_iam_instance_profile_arn"); ok {
|
||||||
roleEntry.BoundIamInstanceProfileARN = boundIamInstanceProfileARNRaw.(string)
|
roleEntry.BoundIamInstanceProfileARN = boundIamInstanceProfileARNRaw.(string)
|
||||||
}
|
}
|
||||||
|
@ -317,6 +318,7 @@ func (b *backend) pathRoleCreateUpdate(
|
||||||
case roleEntry.BoundAccountID != "":
|
case roleEntry.BoundAccountID != "":
|
||||||
case roleEntry.BoundAmiID != "":
|
case roleEntry.BoundAmiID != "":
|
||||||
case roleEntry.BoundIamInstanceProfileARN != "":
|
case roleEntry.BoundIamInstanceProfileARN != "":
|
||||||
|
case roleEntry.BoundIamRoleARN != "":
|
||||||
default:
|
default:
|
||||||
|
|
||||||
return logical.ErrorResponse("at least be one bound parameter should be specified on the role"), nil
|
return logical.ErrorResponse("at least be one bound parameter should be specified on the role"), nil
|
||||||
|
@ -412,7 +414,7 @@ func (b *backend) pathRoleCreateUpdate(
|
||||||
type awsRoleEntry struct {
|
type awsRoleEntry struct {
|
||||||
BoundAmiID string `json:"bound_ami_id" structs:"bound_ami_id" mapstructure:"bound_ami_id"`
|
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"`
|
BoundAccountID string `json:"bound_account_id" structs:"bound_account_id" mapstructure:"bound_account_id"`
|
||||||
DeprecatedBoundIamARN string `json:"bound_iam_role_arn" structs:"bound_iam_role_arn" mapstructure:"bound_iam_role_arn"`
|
BoundIamRoleARN string `json:"bound_iam_role_arn" structs:"bound_iam_role_arn" mapstructure:"bound_iam_role_arn"`
|
||||||
BoundIamInstanceProfileARN string `json:"bound_iam_instance_profile_arn" structs:"bound_iam_instance_profile_arn" mapstructure:"bound_iam_instance_profile_arn"`
|
BoundIamInstanceProfileARN string `json:"bound_iam_instance_profile_arn" structs:"bound_iam_instance_profile_arn" mapstructure:"bound_iam_instance_profile_arn"`
|
||||||
RoleTag string `json:"role_tag" structs:"role_tag" mapstructure:"role_tag"`
|
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"`
|
AllowInstanceMigration bool `json:"allow_instance_migration" structs:"allow_instance_migration" mapstructure:"allow_instance_migration"`
|
||||||
|
|
Loading…
Reference in New Issue