This commit is contained in:
Laura Bennett 2016-07-20 14:47:43 -04:00
commit baaab17dda
7 changed files with 115 additions and 13 deletions

View file

@ -56,6 +56,8 @@ IMPROVEMENTS:
configuration [GH-1581]
* secret/mssql,mysql,postgresql: Reading of connection settings is supported
in all the sql backends [GH-1515]
* secret/mysql: Use a combination of the role name and token display name in
generated user names and allow the length to be controlled [GH-1604]
* credential/ldap, secret/cassandra, physical/consul: Clients with `tls.Config`
will have `MinVersion` set to TLS 1.2 by default.
* logical/ssh: Added `allowed_roles` to vault-ssh-helper's config and returning
@ -74,6 +76,7 @@ BUG FIXES:
[GH-1575]
* secret/postgresql(,mysql,mssql): Fix incorrect use of database over
transaction object which could lead to connection exhaustion [GH-1572]
* secret/pki: Fix parsing CA bundle containing trailing whitespace [GH-1634]
* physical/postgres: Remove use of prepared statements as this causes
connection multiplexing software to break [GH-1548]
* physical/consul: Multiple Vault nodes on the same machine leading to check ID

View file

@ -50,18 +50,31 @@ func (b *backend) pathRoleCreateRead(
lease = &configLease{}
}
// Generate our username and password. MySQL limits user to 16 characters
// Generate our username and password. The username will be a
// concatenation of:
//
// - the role name, truncated to role.rolenameLength (default 4)
// - the token display name, truncated to role.displaynameLength (default 4)
// - a UUID
//
// the entire contactenated string is then truncated to role.usernameLength,
// which by default is 16 due to limitations in older but still-prevalant
// versions of MySQL.
roleName := name
if len(roleName) > role.RolenameLength {
roleName = roleName[:role.RolenameLength]
}
displayName := req.DisplayName
if len(displayName) > 10 {
displayName = displayName[:10]
if len(displayName) > role.DisplaynameLength {
displayName = displayName[:role.DisplaynameLength]
}
userUUID, err := uuid.GenerateUUID()
if err != nil {
return nil, err
}
username := fmt.Sprintf("%s-%s", displayName, userUUID)
if len(username) > 16 {
username = username[:16]
username := fmt.Sprintf("%s-%s-%s", roleName, displayName, userUUID)
if len(username) > role.UsernameLength {
username = username[:role.UsernameLength]
}
password, err := uuid.GenerateUUID()
if err != nil {

View file

@ -34,6 +34,24 @@ func pathRoles(b *backend) *framework.Path {
Type: framework.TypeString,
Description: "SQL string to create a user. See help for more info.",
},
"username_length": &framework.FieldSchema{
Type: framework.TypeInt,
Description: "number of characters to truncate generated mysql usernames to (default 16)",
Default: 16,
},
"rolename_length": &framework.FieldSchema{
Type: framework.TypeInt,
Description: "number of characters to truncate the rolename portion of generated mysql usernames to (default 4)",
Default: 4,
},
"displayname_length": &framework.FieldSchema{
Type: framework.TypeInt,
Description: "number of characters to truncate the displayname portion of generated mysql usernames to (default 4)",
Default: 4,
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
@ -56,7 +74,13 @@ func (b *backend) Role(s logical.Storage, n string) (*roleEntry, error) {
return nil, nil
}
var result roleEntry
// Set defaults to handle upgrade cases
result := roleEntry{
UsernameLength: 16,
RolenameLength: 4,
DisplaynameLength: 4,
}
if err := entry.DecodeJSON(&result); err != nil {
return nil, err
}
@ -105,6 +129,9 @@ func (b *backend) pathRoleCreate(
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
name := data.Get("name").(string)
sql := data.Get("sql").(string)
username_length := data.Get("username_length").(int)
rolename_length := data.Get("rolename_length").(int)
displayname_length := data.Get("displayname_length").(int)
// Get our connection
db, err := b.DB(req.Storage)
@ -127,7 +154,10 @@ func (b *backend) pathRoleCreate(
// Store it
entry, err := logical.StorageEntryJSON("role/"+name, &roleEntry{
SQL: sql,
SQL: sql,
UsernameLength: username_length,
DisplaynameLength: displayname_length,
RolenameLength: rolename_length,
})
if err != nil {
return nil, err
@ -139,7 +169,10 @@ func (b *backend) pathRoleCreate(
}
type roleEntry struct {
SQL string `json:"sql"`
SQL string `json:"sql"`
UsernameLength int `json:"username_length"`
DisplaynameLength int `json:"displayname_length"`
RolenameLength int `json:"rolename_length"`
}
const pathRoleHelpSyn = `
@ -165,4 +198,24 @@ Example of a decent SQL query to use:
Note the above user would be able to access anything in db1. Please see the MySQL
manual on the GRANT command to learn how to do more fine grained access.
The "rolename_length" parameter determines how many characters of the role name
will be used in creating the generated mysql username; the default is 4.
The "displayname_length" parameter determines how many characters of the token
display name will be used in creating the generated mysql username; the default
is 4.
The "username_length" parameter determines how many total characters the
generated username (including the role name, token display name and the uuid
portion) will be truncated to. Versions of MySQL prior to 5.7.8 are limited to
16 characters total (see
http://dev.mysql.com/doc/refman/5.7/en/user-names.html) so that is the default;
for versions >=5.7.8 it is safe to increase this to 32.
For best readability in MySQL process lists, we recommend using MySQL 5.7.8 or
later, setting "username_length" to 32 and setting both "rolename_length" and
"displayname_length" to 8. However due the the prevalence of older versions of
MySQL in general deployment, the defaults are currently tuned for a
username_length of 16.
`

View file

@ -75,7 +75,7 @@ func listenerWrapTLS(
tlsConf := &tls.Config{}
tlsConf.GetCertificate = cg.getCertificate
tlsConf.NextProtos = []string{"http/1.1"}
tlsConf.NextProtos = []string{"h2", "http/1.1"}
tlsConf.MinVersion, ok = tlsutil.TLSLookup[tlsvers]
if !ok {
return nil, nil, nil, fmt.Errorf("'tls_min_version' value %s not supported, please specify one of [tls10,tls11,tls12]", tlsvers)

View file

@ -109,6 +109,8 @@ func ParsePEMBundle(pemBundle string) (*ParsedCertBundle, error) {
return nil, UserError{"empty pem bundle"}
}
pemBundle = strings.TrimSpace(pemBundle)
pemBytes := []byte(pemBundle)
var pemBlock *pem.Block
parsedBundle := &ParsedCertBundle{}

View file

@ -437,7 +437,7 @@ func (p *ParsedCertBundle) GetTLSConfig(usage TLSUsage) (*tls.Config, error) {
}
tlsConfig := &tls.Config{
NextProtos: []string{"http/1.1"},
NextProtos: []string{"h2", "http/1.1"},
MinVersion: tls.VersionTLS12,
}

View file

@ -92,7 +92,7 @@ Key Value
lease_id mysql/creds/readonly/bd404e98-0f35-b378-269a-b7770ef01897
lease_duration 3600
password 132ae3ef-5a64-7499-351e-bfe59f3a2a21
username root-aefa635a-18
username readonly-aefa635a-18
```
By reading from the `creds/readonly` path, Vault has generated a new
@ -105,6 +105,16 @@ that trusted operators can manage the role definitions, and both
users and applications are restricted in the credentials they are
allowed to read.
Optionally, you may configure both the number of characters from the role name
that are truncated to form the display name portion of the mysql username
interpolated into the `{{name}}` field: the default is 10.
You may also configure the total number of characters allowed in the entire
generated username (the sum of the display name and uuid poritions); the
default is 16. Note that versions of MySQL prior to 5.8 have a 16 character
total limit on user names, so it is probably not safe to increase this above
the default on versions prior to that.
## API
### /mysql/config/connection
@ -234,6 +244,27 @@ allowed to read.
Must be semi-colon separated. The '{{name}}' and '{{password}}'
values will be substituted.
</li>
<li>
<span class="param">rolename_length</span>
<span class="param-flags">optional</span>
Determines how many characters from the role name will be used
to form the mysql username interpolated into the '{{name}}' field
of the sql parameter. The default is 4.
</li>
<li>
<span class="param">displayname_length</span>
<span class="param-flags">optional</span>
Determines how many characters from the token display name will be used
to form the mysql username interpolated into the '{{name}}' field
of the sql parameter. The default is 4.
</li>
<li>
<span class="param">username_length</span>
<span class="param-flags">optional</span>
Determines the maximum total length in characters of the
mysql username interpolated into the '{{name}}' field
of the sql parameter. The default is 16.
</li>
</ul>
</dd>
@ -365,7 +396,7 @@ allowed to read.
```javascript
{
"data": {
"username": "root-aefa635a-18",
"username": "user-role-aefa63",
"password": "132ae3ef-5a64-7499-351e-bfe59f3a2a21"
}
}