mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-30 18:17:55 +00:00 
			
		
		
		
	database/mssql: set default root rotation stmt for contained db (#29399)
* database/mssql: set default root rotation stmt for contained db * changelog * add rotate root test * fix test * update passwords to make mssql happy * create admin user * update contained user create query * remove test
This commit is contained in:
		 John-Michael Faircloth
					John-Michael Faircloth
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							9d31bb8586
						
					
				
				
					commit
					04e75372fb
				
			
							
								
								
									
										3
									
								
								changelog/29399.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								changelog/29399.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -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. | ||||
| ``` | ||||
| @@ -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 | ||||
| @@ -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) | ||||
| @@ -431,3 +439,7 @@ EXEC (@stmt)` | ||||
| const alterLoginSQL = ` | ||||
| ALTER LOGIN [{{username}}] WITH PASSWORD = '{{password}}' | ||||
| ` | ||||
|  | ||||
| const alterUserContainedSQL = ` | ||||
| ALTER USER [{{username}}] WITH PASSWORD = '{{password}}' | ||||
| ` | ||||
|   | ||||
| @@ -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() | ||||
|  | ||||
| @@ -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() | ||||
|  | ||||
| @@ -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 | ||||
| @@ -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() | ||||
|  | ||||
| @@ -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() | ||||
|  | ||||
| @@ -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() | ||||
|  | ||||
| @@ -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() | ||||
|  | ||||
| @@ -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}}]; | ||||
| ` | ||||
|   | ||||
| @@ -115,13 +115,23 @@ 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 | ||||
|      | ||||
| @@ -129,6 +139,7 @@ First, we mount a database backend at the azuresql path with `vault secrets enab | ||||
| $ 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" | ||||
| ``` | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user