Skip to content

Commit

Permalink
Fixes20240722 (#27)
Browse files Browse the repository at this point in the history
* Fixes to user mapping through MSSQL_LOGIN_** to deal with orphaned users
* Cleanup orphaned users after database restores
* Improved test coverage for user mapping through MSSQL_LOGIN_**
  • Loading branch information
david-garcia-garcia committed Jul 22, 2024
1 parent 4f6092b commit d0abe6b
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 14 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ $ENV:IMAGE_VERSION = "1.0.32";
.\buildall.ps1
# Build and push to the registry
.\buildall.ps1 -Push $true
.\buildall.ps1 -Push
# Build and run tests
.\buildall.ps1 -Test $true
.\buildall.ps1 -Test
```

## Image List
Expand Down
24 changes: 19 additions & 5 deletions servercore2022/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,25 @@ This uses Machine Level DPAPI encryption, and this is just designed to avoid lea

This does NOT protect the information from being decoded by any other process running inside the container. That is totally possible.

## Environment hot reload and K8S config maps
## Environment hot reload and K8S config maps + secrets

The image can use a JSON file in disk to read the environment from:
The image can process json configmaps mounted anywhere in:

```powershell
c:\environment.d\
```
c:\environment.d\**.json

It will parse any file with the JSON, YAML and YML extension, recognizing both JSON and YAML Formats.

You can also mount any secrets as volumes in:

```powershell
c:\secrets.d\
```

Changes to this file are checked every 8 seconds in the entry point, and environment variables updated accordingly. Note that this **does not** mean that whatever this environment variables controls or affects is going to be updated, it depends on each specific setting and how it is used.
where the secret filename will be the environment variable name, and the file contents the environment variable value.

Changes to these files are checked every 8 seconds in the entry point, and **environment variables updated accordingly**. Note that this **does not** mean that whatever this environment variables controls or affects is going to be updated, it depends on each specific setting and how it is used.

Configuring environment through a Json file has some advantages:

Expand Down Expand Up @@ -148,10 +158,14 @@ resource "kubernetes_config_map" "env_config" {

When the environment configuration is refreshed, all powershell scripts in the refresh folder will be invoked

```
```powershell
c:\entrypoint\refreshenv
```

If you want to support hot-reloading of configuration in your application, place your configuration script in refreshenv.

Note that these scripts are **NOT** executed on container initial startup, only after the system detects changes in the configuration values.

## Memory and CPU footprint

Because the entry point to this image is a powershell script, the minimum memory footprint for this image is **about 80Mb** (doing nothing). That is what powershell.exe plus some other windows services will need.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ function SbsMssqlAddLogin {
$password = $parsedLoginConfiguration["Password"];
$defaultDatabase = $parsedLoginConfiguration["DefaultDatabase"];
$databasesRegex = $parsedLoginConfiguration["DatabasesRegex"];
$permissions = ($parsedLoginConfiguration["Permissions"] -split ",") | Where-Object { $allowedPermissions -contains $_.Trim() }
$roles = ($parsedLoginConfiguration["Roles"] -split ",") | Where-Object { $allowedRoles -contains $_ }
$permissions = ($parsedLoginConfiguration["Permissions"] -split ",") | ForEach-Object { $_.Trim().ToLower() } | Where-Object { $allowedPermissions -contains $_ }
$roles = ($parsedLoginConfiguration["Roles"] -split ",") | ForEach-Object { $_.Trim().ToLower() } | Where-Object { $allowedRoles -contains $_ }

SbsWriteDebug "Setting up MSSQL server login '$($loginName)'";

Expand Down Expand Up @@ -70,11 +70,7 @@ function SbsMssqlAddLogin {
} | Select-Object -ExpandProperty Name;

foreach ($db in $databases) {
SbsWriteDebug "Processing roles for '$($db)'"
$user = Get-DbaDbUser -SqlInstance $instance -Database $db -User $loginName;
if ($user) {
Remove-DbaDbOrphanUser -SqlInstance $instance -Database $db -User $user;
}
Repair-DbaDbOrphanUser -SqlInstance $instance -Database $db -User $loginName -Confirm:$false;
$user = Get-DbaDbUser -SqlInstance $instance -Database $db -User $loginName;
if (-not $user) {
SbsWriteDebug "Creating database user $loginName for '$($db)'"
Expand All @@ -95,5 +91,17 @@ function SbsMssqlAddLogin {

SbsWriteHost "Adding roles '$($roles -Join ", ")' to '$($loginName)' in '$($db)'"
Add-DbaDbRoleMember @addDbaRolesArguments;

# Now remove roles
$rolesToDelete = Get-DbaDbRoleMember -SqlInstance $instance -Database $db -ExcludeRole $roles | Where-Object {
$_.Login -eq $loginName
} | Select-object -ExpandProperty "Role" | Where-Object {
-not($roles -contains $_.Role)
};

if ($rolesToDelete) {
SbsWriteWarning "Removing roles '$($rolesToDelete -Join ", ")' to '$($loginName)' in '$($db)'"
Remove-DbaDbRoleMember -SqlInstance $instance -Database $db -User $loginName -Role $rolesToDelete -Confirm:$false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,8 @@ function SbsRestoreDatabase {
}

SbsWriteHost "Database $($databaseName) restored successfully."

Repair-DbaDbOrphanUser -SqlInstance $SqlInstance -Database $databaseName -RemoveNotExisting -Confirm:$false;

return $true
}
28 changes: 28 additions & 0 deletions sqlserver2022k8s/tests/Compose.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ Describe 'compose.yaml' {
Remove-Item -Path "$env:BUILD_TEMP\datavolume\data\*", "$env:BUILD_TEMP\datavolume\log\*", "$env:BUILD_TEMP\datavolume\backup\*" -Recurse -Force
$Env:connectionString = "Server=172.18.8.8;User Id=sa;Password=sapwd;";
$Env:containerName = "sqlserver2022k8s-mssql-1"
}

It 'Server starts' {
docker compose -f sqlserver2022k8s/compose.yaml up -d;
WaitForLog $Env:containerName "Initialization Completed" -extendedTimeout
}
Expand Down Expand Up @@ -53,6 +56,31 @@ CREATE TABLE dbo.TestTableNotAllowed (
(Invoke-DbaQuery -SqlInstance $instance -Database mydatabase -Query "SELECT OBJECT_ID('dbo.TestTableNotAllowed')").Column1 | Should -BeNullOrEmpty
}

It 'Create a user from configuration' {
$instance = Connect-DbaInstance $Env:connectionString
$instance | Should -Not -BeNullOrEmpty;

$userConfig1 = @{
"MSSQL_LOGIN_NEWUSER" = '{"Login":"newuser", "Password":"MyP@assword", "DefaultDatabase":"mydatabase", "DatabasesRegex":"^mydatabase$", "Permissions": "CONNECT SQL", "Roles":"db_datawriter,db_ddladmin,db_datareader"}'
} | ConvertTo-Json

docker exec $Env:containerName powershell "New-Item -ItemType Directory -Force -Path 'C:\environment.d'; Set-Content -Path 'C:\environment.d\testuser.json' -Value '$userConfig1'"

Get-DbaDbUser -SqlInstance $instance | Should -Not -BeNullOrEmpty

# User should be automatically created
WaitForLog $Env:containerName "Creating database user newuser"

# Remove a role
$userConfig1 = @{
"MSSQL_LOGIN_NEWUSER" = '{"Login":"newuser", "Password":"MyP@assword", "DefaultDatabase":"mydatabase", "DatabasesRegex":"^mydatabase$", "Permissions": "CONNECT SQL", "Roles":"db_datawriter,db_datareader"}'
} | ConvertTo-Json

docker exec $Env:containerName powershell "New-Item -ItemType Directory -Force -Path 'C:\environment.d'; Set-Content -Path 'C:\environment.d\testuser.json' -Value '$userConfig1'"

WaitForLog $Env:containerName "Removing roles 'db_ddladmin'"
}

AfterAll {
docker compose -f sqlserver2022k8s/compose.yaml down;
Remove-Item -Path "$env:BUILD_TEMP\datavolume\data\*", "$env:BUILD_TEMP\datavolume\backup\*" -Recurse -Force
Expand Down

0 comments on commit d0abe6b

Please sign in to comment.