func (b *backend) pathGroupWrite( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { // Store it entry, err := logical.StorageEntryJSON("group/"+d.Get("name").(string), &GroupEntry{ Policies: policyutil.ParsePolicies(d.Get("policies").(string)), }) if err != nil { return nil, err } if err := req.Storage.Put(entry); err != nil { return nil, err } return nil, nil }
func (b *backend) pathUserPoliciesUpdate( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { username := d.Get("username").(string) userEntry, err := b.user(req.Storage, username) if err != nil { return nil, err } if userEntry == nil { return nil, fmt.Errorf("username does not exist") } userEntry.Policies = policyutil.ParsePolicies(d.Get("policies").(string)) return nil, b.setUser(req.Storage, username, userEntry) }
func (b *backend) userCreateUpdate(req *logical.Request, d *framework.FieldData) (*logical.Response, error) { username := strings.ToLower(d.Get("username").(string)) userEntry, err := b.user(req.Storage, username) if err != nil { return nil, err } // Due to existence check, user will only be nil if it's a create operation if userEntry == nil { userEntry = &UserEntry{} } if _, ok := d.GetOk("password"); ok { userErr, intErr := b.updateUserPassword(req, d, userEntry) if intErr != nil { return nil, err } if userErr != nil { return logical.ErrorResponse(userErr.Error()), logical.ErrInvalidRequest } } if policiesRaw, ok := d.GetOk("policies"); ok { userEntry.Policies = policyutil.ParsePolicies(policiesRaw.(string)) } ttlStr := userEntry.TTL.String() if ttlStrRaw, ok := d.GetOk("ttl"); ok { ttlStr = ttlStrRaw.(string) } maxTTLStr := userEntry.MaxTTL.String() if maxTTLStrRaw, ok := d.GetOk("max_ttl"); ok { maxTTLStr = maxTTLStrRaw.(string) } userEntry.TTL, userEntry.MaxTTL, err = b.SanitizeTTLStr(ttlStr, maxTTLStr) if err != nil { return logical.ErrorResponse(fmt.Sprintf("err: %s", err)), nil } return nil, b.setUser(req.Storage, username, userEntry) }
func (b *backend) pathCertWrite( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { name := strings.ToLower(d.Get("name").(string)) certificate := d.Get("certificate").(string) displayName := d.Get("display_name").(string) policies := policyutil.ParsePolicies(d.Get("policies").(string)) // Default the display name to the certificate name if not given if displayName == "" { displayName = name } parsed := parsePEM([]byte(certificate)) if len(parsed) == 0 { return logical.ErrorResponse("failed to parse certificate"), nil } // If the certificate is not a CA cert, then ensure that x509.ExtKeyUsageClientAuth is set if !parsed[0].IsCA && parsed[0].ExtKeyUsage != nil { var clientAuth bool for _, usage := range parsed[0].ExtKeyUsage { if usage == x509.ExtKeyUsageClientAuth || usage == x509.ExtKeyUsageAny { clientAuth = true break } } if !clientAuth { return logical.ErrorResponse("non-CA certificates should have TLS client authentication set as an extended key usage"), nil } } certEntry := &CertEntry{ Name: name, Certificate: certificate, DisplayName: displayName, Policies: policies, } // Parse the lease duration or default to backend/system default maxTTL := b.System().MaxLeaseTTL() ttl := time.Duration(d.Get("ttl").(int)) * time.Second if ttl == time.Duration(0) { ttl = time.Second * time.Duration(d.Get("lease").(int)) } if ttl > maxTTL { return logical.ErrorResponse(fmt.Sprintf("Given TTL of %d seconds greater than current mount/system default of %d seconds", ttl/time.Second, maxTTL/time.Second)), nil } if ttl > time.Duration(0) { certEntry.TTL = ttl } // Store it entry, err := logical.StorageEntryJSON("cert/"+name, certEntry) if err != nil { return nil, err } if err := req.Storage.Put(entry); err != nil { return nil, err } return nil, nil }
// pathRoleCreateUpdate is used to associate Vault policies to a given AMI ID. func (b *backend) pathRoleCreateUpdate( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { roleName := strings.ToLower(data.Get("role").(string)) if roleName == "" { return logical.ErrorResponse("missing role"), nil } b.roleMutex.Lock() defer b.roleMutex.Unlock() roleEntry, err := b.nonLockedAWSRole(req.Storage, roleName) if err != nil { return nil, err } if roleEntry == nil { roleEntry = &awsRoleEntry{} } // Fetch and set the bound parameters. There can't be default values // for these. if boundAmiIDRaw, ok := data.GetOk("bound_ami_id"); ok { roleEntry.BoundAmiID = boundAmiIDRaw.(string) } if boundAccountIDRaw, ok := data.GetOk("bound_account_id"); ok { 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 { roleEntry.BoundIamInstanceProfileARN = boundIamInstanceProfileARNRaw.(string) } // Ensure that at least one bound is set on the role switch { case roleEntry.BoundAccountID != "": case roleEntry.BoundAmiID != "": case roleEntry.BoundIamInstanceProfileARN != "": case roleEntry.BoundIamRoleARN != "": default: return logical.ErrorResponse("at least be one bound parameter should be specified on the role"), nil } policiesStr, ok := data.GetOk("policies") if ok { roleEntry.Policies = policyutil.ParsePolicies(policiesStr.(string)) } else if req.Operation == logical.CreateOperation { roleEntry.Policies = []string{"default"} } disallowReauthenticationBool, ok := data.GetOk("disallow_reauthentication") if ok { roleEntry.DisallowReauthentication = disallowReauthenticationBool.(bool) } else if req.Operation == logical.CreateOperation { roleEntry.DisallowReauthentication = data.Get("disallow_reauthentication").(bool) } allowInstanceMigrationBool, ok := data.GetOk("allow_instance_migration") if ok { roleEntry.AllowInstanceMigration = allowInstanceMigrationBool.(bool) } else if req.Operation == logical.CreateOperation { roleEntry.AllowInstanceMigration = data.Get("allow_instance_migration").(bool) } var resp logical.Response ttlRaw, ok := data.GetOk("ttl") if ok { ttl := time.Duration(ttlRaw.(int)) * time.Second defaultLeaseTTL := b.System().DefaultLeaseTTL() if ttl > defaultLeaseTTL { resp.AddWarning(fmt.Sprintf("Given ttl of %d seconds greater than current mount/system default of %d seconds; ttl will be capped at login time", ttl/time.Second, defaultLeaseTTL/time.Second)) } roleEntry.TTL = ttl } else if req.Operation == logical.CreateOperation { roleEntry.TTL = time.Duration(data.Get("ttl").(int)) * time.Second } maxTTLInt, ok := data.GetOk("max_ttl") if ok { maxTTL := time.Duration(maxTTLInt.(int)) * time.Second systemMaxTTL := b.System().MaxLeaseTTL() if maxTTL > systemMaxTTL { resp.AddWarning(fmt.Sprintf("Given max_ttl of %d seconds greater than current mount/system default of %d seconds; max_ttl will be capped at login time", maxTTL/time.Second, systemMaxTTL/time.Second)) } if maxTTL < time.Duration(0) { return logical.ErrorResponse("max_ttl cannot be negative"), nil } roleEntry.MaxTTL = maxTTL } else if req.Operation == logical.CreateOperation { roleEntry.MaxTTL = time.Duration(data.Get("max_ttl").(int)) * time.Second } if roleEntry.MaxTTL != 0 && roleEntry.MaxTTL < roleEntry.TTL { return logical.ErrorResponse("ttl should be shorter than max_ttl"), nil } roleTagStr, ok := data.GetOk("role_tag") if ok { roleEntry.RoleTag = roleTagStr.(string) // There is a limit of 127 characters on the tag key for AWS EC2 instances. // Complying to that requirement, do not allow the value of 'key' to be more than that. if len(roleEntry.RoleTag) > 127 { return logical.ErrorResponse("length of role tag exceeds the EC2 key limit of 127 characters"), nil } } else if req.Operation == logical.CreateOperation { roleEntry.RoleTag = data.Get("role_tag").(string) } if roleEntry.HMACKey == "" { roleEntry.HMACKey, err = uuid.GenerateUUID() if err != nil { return nil, fmt.Errorf("failed to generate role HMAC key: %v", err) } } if err := b.nonLockedSetAWSRole(req.Storage, roleName, roleEntry); err != nil { return nil, err } if len(resp.Warnings()) == 0 { return nil, nil } return &resp, nil }
// pathRoleTagUpdate is used to create an EC2 instance tag which will // identify the Vault resources that the instance will be authorized for. func (b *backend) pathRoleTagUpdate( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { roleName := strings.ToLower(data.Get("role").(string)) if roleName == "" { return logical.ErrorResponse("missing role"), nil } // Fetch the role entry roleEntry, err := b.lockedAWSRole(req.Storage, roleName) if err != nil { return nil, err } if roleEntry == nil { return logical.ErrorResponse(fmt.Sprintf("entry not found for role %s", roleName)), nil } // If RoleTag is empty, disallow creation of tag. if roleEntry.RoleTag == "" { return logical.ErrorResponse("tag creation is not enabled for this role"), nil } // There should be a HMAC key present in the role entry if roleEntry.HMACKey == "" { // Not being able to find the HMACKey is an internal error return nil, fmt.Errorf("failed to find the HMAC key") } resp := &logical.Response{} // Instance ID is an optional field. instanceID := strings.ToLower(data.Get("instance_id").(string)) // If no policies field was not supplied, then the tag should inherit all the policies // on the role. But, it was provided, but set to empty explicitly, only "default" policy // should be inherited. So, by leaving the policies var unset to anything when it is not // supplied, we ensure that it inherits all the policies on the role. var policies []string policiesStr, ok := data.GetOk("policies") if ok { policies = policyutil.ParsePolicies(policiesStr.(string)) } if !strutil.StrListSubset(roleEntry.Policies, policies) { resp.AddWarning("Policies on the tag are not a subset of the policies set on the role. Login will not be allowed with this tag unless the role policies are updated.") } // This is an optional field. disallowReauthentication := data.Get("disallow_reauthentication").(bool) // This is an optional field. allowInstanceMigration := data.Get("allow_instance_migration").(bool) if allowInstanceMigration && !roleEntry.AllowInstanceMigration { resp.AddWarning("Role does not allow instance migration. Login will not be allowed with this tag unless the role value is updated.") } // max_ttl for the role tag should be less than the max_ttl set on the role. maxTTL := time.Duration(data.Get("max_ttl").(int)) * time.Second // max_ttl on the tag should not be greater than the system view's max_ttl value. if maxTTL > b.System().MaxLeaseTTL() { resp.AddWarning(fmt.Sprintf("Given max TTL of %d is greater than the mount maximum of %d seconds, and will be capped at login time.", maxTTL/time.Second, b.System().MaxLeaseTTL()/time.Second)) } // If max_ttl is set for the role, check the bounds for tag's max_ttl value using that. if roleEntry.MaxTTL != time.Duration(0) && maxTTL > roleEntry.MaxTTL { resp.AddWarning(fmt.Sprintf("Given max TTL of %d is greater than the role maximum of %d seconds, and will be capped at login time.", maxTTL/time.Second, roleEntry.MaxTTL/time.Second)) } if maxTTL < time.Duration(0) { return logical.ErrorResponse("max_ttl cannot be negative"), nil } // Create a random nonce. nonce, err := createRoleTagNonce() if err != nil { return nil, err } // Create a role tag out of all the information provided. rTagValue, err := createRoleTagValue(&roleTag{ Version: roleTagVersion, Role: roleName, Nonce: nonce, Policies: policies, MaxTTL: maxTTL, InstanceID: instanceID, DisallowReauthentication: disallowReauthentication, AllowInstanceMigration: allowInstanceMigration, }, roleEntry) if err != nil { return nil, err } // Return the key to be used for the tag and the value to be used for that tag key. // This key value pair should be set on the EC2 instance. resp.Data = map[string]interface{}{ "tag_key": roleEntry.RoleTag, "tag_value": rTagValue, } return resp, nil }
// pathRoleCreateUpdate is used to associate Vault policies to a given AMI ID. func (b *backend) pathRoleCreateUpdate( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { roleName := strings.ToLower(data.Get("role").(string)) if roleName == "" { return logical.ErrorResponse("missing role"), nil } b.roleMutex.Lock() defer b.roleMutex.Unlock() roleEntry, err := b.nonLockedAWSRole(req.Storage, roleName) if err != nil { return nil, err } if roleEntry == nil { 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) } boundIamARNStr, ok := data.GetOk("bound_iam_role_arn") if ok { roleEntry.BoundIamARN = boundIamARNStr.(string) } // At least one bound parameter should be set. Currently, only // 'bound_ami_id' and 'bound_iam_role_arn' are supported. Check if one of them is set. if roleEntry.BoundAmiID == "" { // check if an IAM Role ARN was provided instead of an AMI ID if roleEntry.BoundIamARN == "" { return logical.ErrorResponse("role is not bounded to any resource; set bound_ami_id or bount_iam_role_arn"), nil } } policiesStr, ok := data.GetOk("policies") if ok { roleEntry.Policies = policyutil.ParsePolicies(policiesStr.(string)) } else if req.Operation == logical.CreateOperation { roleEntry.Policies = []string{"default"} } disallowReauthenticationBool, ok := data.GetOk("disallow_reauthentication") if ok { roleEntry.DisallowReauthentication = disallowReauthenticationBool.(bool) } else if req.Operation == logical.CreateOperation { roleEntry.DisallowReauthentication = data.Get("disallow_reauthentication").(bool) } allowInstanceMigrationBool, ok := data.GetOk("allow_instance_migration") if ok { roleEntry.AllowInstanceMigration = allowInstanceMigrationBool.(bool) } else if req.Operation == logical.CreateOperation { roleEntry.AllowInstanceMigration = data.Get("allow_instance_migration").(bool) } var resp logical.Response maxTTLInt, ok := data.GetOk("max_ttl") if ok { maxTTL := time.Duration(maxTTLInt.(int)) * time.Second systemMaxTTL := b.System().MaxLeaseTTL() if maxTTL > systemMaxTTL { resp.AddWarning(fmt.Sprintf("Given TTL of %d seconds greater than current mount/system default of %d seconds; TTL will be capped at login time", maxTTL/time.Second, systemMaxTTL/time.Second)) } if maxTTL < time.Duration(0) { return logical.ErrorResponse("max_ttl cannot be negative"), nil } roleEntry.MaxTTL = maxTTL } else if req.Operation == logical.CreateOperation { roleEntry.MaxTTL = time.Duration(data.Get("max_ttl").(int)) * time.Second } roleTagStr, ok := data.GetOk("role_tag") if ok { roleEntry.RoleTag = roleTagStr.(string) // There is a limit of 127 characters on the tag key for AWS EC2 instances. // Complying to that requirement, do not allow the value of 'key' to be more than that. if len(roleEntry.RoleTag) > 127 { return logical.ErrorResponse("length of role tag exceeds the EC2 key limit of 127 characters"), nil } } else if req.Operation == logical.CreateOperation { roleEntry.RoleTag = data.Get("role_tag").(string) } if roleEntry.HMACKey == "" { roleEntry.HMACKey, err = uuid.GenerateUUID() if err != nil { return nil, fmt.Errorf("failed to generate role HMAC key: %v", err) } } entry, err := logical.StorageEntryJSON("role/"+roleName, roleEntry) if err != nil { return nil, err } if err := req.Storage.Put(entry); err != nil { return nil, err } if len(resp.Warnings()) == 0 { return nil, nil } return &resp, nil }