2023-03-15 16:00:52 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2015-08-29 19:24:15 +00:00
|
|
|
package ssh
|
|
|
|
|
|
|
|
import (
|
2018-01-08 18:31:38 +00:00
|
|
|
"context"
|
2015-08-29 19:24:15 +00:00
|
|
|
"fmt"
|
|
|
|
|
2021-07-16 00:17:31 +00:00
|
|
|
"github.com/hashicorp/go-secure-stdlib/strutil"
|
2019-03-14 15:56:40 +00:00
|
|
|
|
2019-04-12 21:54:35 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/framework"
|
2019-04-13 07:44:06 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/logical"
|
2015-08-29 19:24:15 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Structure to hold roles that are allowed to accept any IP address.
|
|
|
|
type zeroAddressRoles struct {
|
2015-08-31 21:03:46 +00:00
|
|
|
Roles []string `json:"roles" mapstructure:"roles"`
|
2015-08-29 19:24:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func pathConfigZeroAddress(b *backend) *framework.Path {
|
|
|
|
return &framework.Path{
|
|
|
|
Pattern: "config/zeroaddress",
|
|
|
|
Fields: map[string]*framework.FieldSchema{
|
2021-04-08 16:43:39 +00:00
|
|
|
"roles": {
|
2018-10-17 06:33:12 +00:00
|
|
|
Type: framework.TypeCommaStringSlice,
|
2015-08-29 19:24:15 +00:00
|
|
|
Description: `[Required] Comma separated list of role names which
|
|
|
|
allows credentials to be requested for any IP address. CIDR blocks
|
|
|
|
previously registered under these roles will be ignored.`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
2016-08-19 20:48:32 +00:00
|
|
|
logical.UpdateOperation: b.pathConfigZeroAddressWrite,
|
2015-08-30 00:22:34 +00:00
|
|
|
logical.ReadOperation: b.pathConfigZeroAddressRead,
|
|
|
|
logical.DeleteOperation: b.pathConfigZeroAddressDelete,
|
2015-08-29 19:24:15 +00:00
|
|
|
},
|
|
|
|
HelpSynopsis: pathConfigZeroAddressSyn,
|
|
|
|
HelpDescription: pathConfigZeroAddressDesc,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-08 18:31:38 +00:00
|
|
|
func (b *backend) pathConfigZeroAddressDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
2018-01-19 06:44:44 +00:00
|
|
|
err := req.Storage.Delete(ctx, "config/zeroaddress")
|
2015-08-30 00:22:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2018-01-08 18:31:38 +00:00
|
|
|
func (b *backend) pathConfigZeroAddressRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
2018-01-19 06:44:44 +00:00
|
|
|
entry, err := b.getZeroAddressRoles(ctx, req.Storage)
|
2015-08-29 19:24:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if entry == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return &logical.Response{
|
|
|
|
Data: map[string]interface{}{
|
|
|
|
"roles": entry.Roles,
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2018-01-08 18:31:38 +00:00
|
|
|
func (b *backend) pathConfigZeroAddressWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
2018-10-17 06:33:12 +00:00
|
|
|
roles := d.Get("roles").([]string)
|
|
|
|
if len(roles) == 0 {
|
2015-08-29 19:24:15 +00:00
|
|
|
return logical.ErrorResponse("Missing roles"), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the roles listed actually exist in the backend
|
|
|
|
for _, item := range roles {
|
2018-01-19 06:44:44 +00:00
|
|
|
role, err := b.getRole(ctx, req.Storage, item)
|
2015-08-29 19:24:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if role == nil {
|
2016-10-18 16:46:54 +00:00
|
|
|
return logical.ErrorResponse(fmt.Sprintf("Role %q does not exist", item)), nil
|
2015-08-29 19:24:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-19 06:44:44 +00:00
|
|
|
err := b.putZeroAddressRoles(ctx, req.Storage, roles)
|
2015-08-29 19:24:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stores the given list of roles at zeroaddress endpoint
|
2018-01-19 06:44:44 +00:00
|
|
|
func (b *backend) putZeroAddressRoles(ctx context.Context, s logical.Storage, roles []string) error {
|
2015-08-29 19:24:15 +00:00
|
|
|
entry, err := logical.StorageEntryJSON("config/zeroaddress", &zeroAddressRoles{
|
|
|
|
Roles: roles,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-01-19 06:44:44 +00:00
|
|
|
if err := s.Put(ctx, entry); err != nil {
|
2015-08-29 19:24:15 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Retrieves the list of roles from the zeroaddress endpoint.
|
2018-01-19 06:44:44 +00:00
|
|
|
func (b *backend) getZeroAddressRoles(ctx context.Context, s logical.Storage) (*zeroAddressRoles, error) {
|
|
|
|
entry, err := s.Get(ctx, "config/zeroaddress")
|
2015-08-29 19:24:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if entry == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var result zeroAddressRoles
|
|
|
|
if err := entry.DecodeJSON(&result); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &result, nil
|
|
|
|
}
|
|
|
|
|
2015-08-31 20:03:28 +00:00
|
|
|
// Removes a role from the list of roles present in config/zeroaddress path
|
2018-01-19 06:44:44 +00:00
|
|
|
func (b *backend) removeZeroAddressRole(ctx context.Context, s logical.Storage, roleName string) error {
|
|
|
|
zeroAddressEntry, err := b.getZeroAddressRoles(ctx, s)
|
2015-08-29 19:24:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if zeroAddressEntry == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-03-14 15:56:40 +00:00
|
|
|
zeroAddressEntry.Roles = strutil.StrListDelete(zeroAddressEntry.Roles, roleName)
|
2015-08-29 19:24:15 +00:00
|
|
|
|
2018-01-19 06:44:44 +00:00
|
|
|
return b.putZeroAddressRoles(ctx, s, zeroAddressEntry.Roles)
|
2015-08-29 19:24:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const pathConfigZeroAddressSyn = `
|
|
|
|
Assign zero address as default CIDR block for select roles.
|
|
|
|
`
|
|
|
|
|
|
|
|
const pathConfigZeroAddressDesc = `
|
|
|
|
Administrator can choose to make a select few registered roles to accept any IP
|
|
|
|
address, overriding the CIDR blocks registered during creation of roles. This
|
|
|
|
doesn't mean that the credentials are created for any IP address. Clients who
|
|
|
|
have access to these roles are trusted to make valid requests. Access to these
|
|
|
|
roles should be controlled using Vault policies. It is recommended that all the
|
|
|
|
roles that are allowed to accept any IP address should have an explicit policy
|
|
|
|
of deny for unintended clients.
|
|
|
|
|
|
|
|
This is a root authenticated endpoint. If backend is mounted at 'ssh' then use
|
|
|
|
the endpoint 'ssh/config/zeroaddress' to provide the list of allowed roles.
|
|
|
|
After mounting the backend, use 'path-help' for additional information.
|
|
|
|
`
|