Skip to content

Commit

Permalink
backport of commit 04e7537 (#29414)
Browse files Browse the repository at this point in the history
Co-authored-by: John-Michael Faircloth <[email protected]>
  • Loading branch information
1 parent 6179e91 commit 11713a2
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 10 deletions.
3 changes: 3 additions & 0 deletions changelog/29399.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
database/mssql: Fix a bug where contained databases would silently fail root rotation if a custom root rotation statement was not provided.
```
14 changes: 13 additions & 1 deletion plugins/database/mssql/mssql.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,11 @@ func (m *MSSQL) UpdateUser(ctx context.Context, req dbplugin.UpdateUserRequest)

func (m *MSSQL) updateUserPass(ctx context.Context, username string, changePass *dbplugin.ChangePassword) error {
stmts := changePass.Statements.Commands
if len(stmts) == 0 && !m.containedDB {
if len(stmts) == 0 {
stmts = []string{alterLoginSQL}
if m.containedDB {
stmts = []string{alterUserContainedSQL}
}
}

password := changePass.NewPassword
Expand Down Expand Up @@ -384,6 +387,11 @@ func (m *MSSQL) updateUserPass(ctx context.Context, username string, changePass
_ = tx.Rollback()
}()

if len(stmts) == 0 {
// should not happen, but guard against it anyway
return errors.New("no statement provided")
}

for _, stmt := range stmts {
for _, query := range strutil.ParseArbitraryStringSlice(stmt, ";") {
query = strings.TrimSpace(query)
Expand Down Expand Up @@ -431,3 +439,7 @@ EXEC (@stmt)`
const alterLoginSQL = `
ALTER LOGIN [{{username}}] WITH PASSWORD = '{{password}}'
`

const alterUserContainedSQL = `
ALTER USER [{{username}}] WITH PASSWORD = '{{password}}'
`
22 changes: 15 additions & 7 deletions plugins/database/mssql/mssql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"github.com/stretchr/testify/assert"
)

func TestInitialize(t *testing.T) {
func TestMSSQLInitialize(t *testing.T) {
cleanup, connURL := mssqlhelper.PrepareMSSQLTestContainer(t)
defer cleanup()

Expand Down Expand Up @@ -79,7 +79,7 @@ func TestInitialize(t *testing.T) {
}
}

func TestNewUser(t *testing.T) {
func TestMSSQLNewUser(t *testing.T) {
cleanup, connURL := mssqlhelper.PrepareMSSQLTestContainer(t)
defer cleanup()

Expand Down Expand Up @@ -185,7 +185,7 @@ func TestNewUser(t *testing.T) {
}
}

func TestUpdateUser_password(t *testing.T) {
func TestMSSQLUpdateUser_password(t *testing.T) {
type testCase struct {
req dbplugin.UpdateUserRequest
expectErr bool
Expand Down Expand Up @@ -312,7 +312,7 @@ func TestUpdateUser_password(t *testing.T) {
}
}

func TestDeleteUser(t *testing.T) {
func TestMSSQLDeleteUser(t *testing.T) {
cleanup, connURL := mssqlhelper.PrepareMSSQLTestContainer(t)
defer cleanup()

Expand Down Expand Up @@ -358,7 +358,7 @@ func TestDeleteUser(t *testing.T) {
assertCredsDoNotExist(t, connURL, dbUser, initPassword)
}

func TestDeleteUserContainedDB(t *testing.T) {
func TestMSSQLDeleteUserContainedDB(t *testing.T) {
cleanup, connURL := mssqlhelper.PrepareMSSQLTestContainer(t)
defer cleanup()

Expand Down Expand Up @@ -405,7 +405,7 @@ func TestDeleteUserContainedDB(t *testing.T) {
assertContainedDBCredsDoNotExist(t, connURL, dbUser)
}

func TestContainedDBSQLSanitization(t *testing.T) {
func TestMSSQLContainedDBSQLSanitization(t *testing.T) {
cleanup, connURL := mssqlhelper.PrepareMSSQLTestContainer(t)
defer cleanup()

Expand Down Expand Up @@ -443,7 +443,7 @@ func TestContainedDBSQLSanitization(t *testing.T) {
assert.EqualError(t, err, "mssql: Cannot alter the login 'vaultuser]', because it does not exist or you do not have permission.")
}

func TestSQLSanitization(t *testing.T) {
func TestMSSQLSanitization(t *testing.T) {
cleanup, connURL := mssqlhelper.PrepareMSSQLTestContainer(t)
defer cleanup()

Expand Down Expand Up @@ -576,3 +576,11 @@ const testMSSQLContainedLogin = `
CREATE LOGIN [{{name}}] WITH PASSWORD = '{{password}}';
CREATE USER [{{name}}] FOR LOGIN [{{name}}];
`

const testMSSQLContainedLoginAdmin = `
CREATE USER [{{name}}] WITH PASSWORD = '{{password}}';
ALTER ROLE db_datareader ADD MEMBER [{{name}}];
ALTER ROLE db_datawriter ADD MEMBER [{{name}}];
ALTER ROLE db_owner ADD MEMBER [{{name}}];
`
15 changes: 13 additions & 2 deletions website/content/docs/secrets/databases/mssql.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -115,20 +115,31 @@ the proper permission, it can generate credentials.

## Example for Azure SQL database

Here is a complete example using Azure SQL Database. Note that databases in Azure SQL Database are [contained databases](https://docs.microsoft.com/en-us/sql/relational-databases/databases/contained-databases) and that we do not create a login for the user; instead, we associate the password directly with the user itself. Also note that you will need a separate connection and role for each Azure SQL database for which you want to generate dynamic credentials. You can use a single database backend mount for all these databases or use a separate mount for each of them. In this example, we use a custom path for the database backend.
Here is a complete example using Azure SQL Database. Note that databases in
Azure SQL Database are [contained databases](https://docs.microsoft.com/en-us/sql/relational-databases/databases/contained-databases)
and that we do not create a login for the user; instead, we associate the
password directly with the user itself. Also note that you will need a separate
connection and role for each Azure SQL database for which you want to generate
dynamic credentials. You can use a single database backend mount for all these
databases or use a separate mount for each of them. In this example, we use a
custom path for the database backend.

<Note>
Azure SQL databases may use different authentication mechanism that are configured on the SQL server. Vault only supports SQL authentication. Azure AD authentication is not supported.
</Note>

First, we mount a database backend at the azuresql path with `vault secrets enable -path=azuresql database`. Then we configure a connection called "testvault" to connect to a database called "test-vault", using "azuresql" at the beginning of our path:
First, we mount a database backend at the azuresql path with `vault secrets
enable -path=azuresql database`. Then we configure a connection called
"testvault" to connect to a database called "test-vault", using "azuresql" at
the beginning of our path and set the `contained_db` field:

~> Note: If you are using a windows vault client with cmd.exe, change the single quotes to double quotes in the connection string. Windows cmd.exe does not interpret single quotes as a continous string

```shell-session
$ vault write azuresql/config/testvault \
plugin_name=mssql-database-plugin \
connection_url='server=hashisqlserver.database.windows.net;port=1433;user id=admin;password=pAssw0rd;database=test-vault;app name=vault;' \
contained_db=true \
allowed_roles="test"
```

Expand Down

0 comments on commit 11713a2

Please sign in to comment.