Add complete seed, Always Encrypted cert package, and TEST system DE-Test.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-29 08:30:12 +02:00
co-authored by Cursor
parent dcfcb5289d
commit e45ced8b73
11 changed files with 281 additions and 36 deletions
@@ -152,7 +152,7 @@ CREATE COLUMN MASTER KEY [CMK_ESB_ZertifikatManager]
WITH WITH
( (
KEY_STORE_PROVIDER_NAME = N'MSSQL_CERTIFICATE_STORE', KEY_STORE_PROVIDER_NAME = N'MSSQL_CERTIFICATE_STORE',
KEY_PATH = N'CurrentUser/My/238AC7A32074D5B293C7EFB60E256907CB82C9C6' KEY_PATH = N'CurrentUser/My/95E906CCC9C5F227969877CF3BD46D2AD7168853'
); );
GO GO
@@ -161,7 +161,7 @@ WITH VALUES
( (
COLUMN_MASTER_KEY = [CMK_ESB_ZertifikatManager], COLUMN_MASTER_KEY = [CMK_ESB_ZertifikatManager],
ALGORITHM = 'RSA_OAEP', ALGORITHM = 'RSA_OAEP',
ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F003200330038006100630037006100330032003000370034006400350062003200390033006300370065006600620036003000650032003500360039003000370063006200380032006300390063003600B8FEA92C9873A6A27B4EB33481926ABF719FB0C2EE7DF959AE38D48185CC7286E7779016745253EDB10C769773D03B614995E2373AE9F02428370727C5DF69B902A01EC0B93E8B8D114460455BAC0C1868DAE1A49AAF04480E8A3D05867395CA455CA9FADEF046437B8C25BA7DE945FCB45A50590DA555B1EB860F23B556B72A142992C085E3D4A97E92D2882D6849C6DABCF37653926A8FBC532A115CB9748179BF34DADDE268FD0DC8FF1CFBCB7192D3220238794D6D2FC7C4BDE501BABE5F6BB989853C6B5C510396069F41338CF64236A6D7A4C26F0DF7BBD2A1A5BD3BA2F7D75FECF7BE0AB0C69DDEEAAD72E2849D0A4F9C9A0C25E021A432EE399AA075AB3F0FB9929392D825E1EC991D017022982C17E72CFA9EEDB17DED9FCECF2B8651B72CA87EEAED5473B3806BD4C0A56539703B4EFF38D2889D255B95C9A6F1AD7D22A1FF2F71621B286FCAD8B708810E7BF50D027BF6A0A829422EE599D00CF2D8E6ADB7DE802971A5805073EC2E6F9793E9AEDE30E7B8EC865D50183EB64B9B8286E4A9BFFB98ACDAA9C9D8D149834DE1CA7FEF9C6A54AF4B30BDDF4AC41C36FB0EFD4EE783CEE1546D25A7CA75C549A2FB978907AFBD209197A9D60239F14F4CFAC202F435AA80DBF6A6494AB3E934F86C640DBFBB77879F2FFA8B1C9DD1BF3B14299C12943F57F1948CC5833986918EB7ACABBC1C4D642E1944BB07AB8446 ENCRYPTED_VALUE = 0x017000630075007200720065006E00740075007300650072002F006D0079002F003900350065003900300036006300630063003900630035006600320032003700390036003900380037003700630066003300620064003400360064003200610064003700310036003800380035003300000063875F8F9E6CA28F5C6AB80295C9526F00C6708A9E3D8EEF172189C88A445F21D08CA11BCA77B3460C8F109A0C30B3CF9E3E7007BC4EACE9563591014C6FDE01F15E72F6992C7862F1C22C7E69D00418B26E700F95112E870A17C4510891AE687B522F71A58E70DFAE211F6B233628FB17E87F2837726E4801CB45A2357CE57194239950B19930CE5C8B7AF9A0CFF86AFA52DF97D392C77DE694ECA336A0DBCB6E5157AF8713636D90D121BDA1CBC4909C3A1102BE9FE561321FED761A672D2E534A5C94391704C79D007804DE628961BB2A4744D88E975C8287459F2D7D42F643078CEFF8842DFE4C826CF4B47BE2A59DC65D495F39BE45AA583E2784DE039F
); );
GO GO
@@ -2,13 +2,18 @@
DATABASE: [EsbZertifikatManager] DATABASE: [EsbZertifikatManager]
OBJECTNAME: Seed OBJECTNAME: Seed
ACTION: INSERT ACTION: INSERT
IDX: 001 IDX: 002
DATE: 2026-07-29 DATE: 2026-07-29
USER: CUR USER: CUR
COMMENT: Stammdaten Company (DE/PL/AT) und Environment (TEST2/TEST/PROD). COMMENT: KOMPLETTE Seed-Datei (alles in einem Lauf):
Nach 00_DropExisting / 01_CreateDatabase / 02_CreateSchema. - Company: DE, PL, AT
SonicConnection / SonicContainer / CertificateTarget / SonicCredential - Environment: TEST2, TEST, PROD
manuell pflegen — keine Secrets; Credentials nur via AE/Setup. - SonicConnection: DE-Test (TEST)
- SonicContainer: ct-ZADBService
- CertificateTarget: Platzhalter-Pfad
Keine Credentials (Always Encrypted / Setup-Wizard).
Voraussetzung: 00_DropExisting, 01_CreateDatabase, 02_CreateSchema,
AlwaysEncrypted-Zertifikat importiert (Install-Certificate.ps1).
*/ */
USE [EsbZertifikatManager]; USE [EsbZertifikatManager];
GO GO
@@ -19,6 +24,10 @@ GO
SET QUOTED_IDENTIFIER ON; SET QUOTED_IDENTIFIER ON;
GO GO
/* -------------------------------------------------------------------------- */
/* Company */
/* -------------------------------------------------------------------------- */
IF NOT EXISTS IF NOT EXISTS
( (
SELECT 1 SELECT 1
@@ -79,6 +88,10 @@ BEGIN
END; END;
GO GO
/* -------------------------------------------------------------------------- */
/* Environment */
/* -------------------------------------------------------------------------- */
IF NOT EXISTS IF NOT EXISTS
( (
SELECT 1 SELECT 1
@@ -141,3 +154,175 @@ BEGIN
(N'PROD', N'Production', 3, 1, SYSUTCDATETIME(), SUSER_SNAME()); (N'PROD', N'Production', 3, 1, SYSUTCDATETIME(), SUSER_SNAME());
END; END;
GO GO
/* -------------------------------------------------------------------------- */
/* TEST-System: DE-Test + ct-ZADBService + CertificateTarget */
/* -------------------------------------------------------------------------- */
DECLARE @EnvironmentIdTest [int];
DECLARE @CompanyIdDe [int];
DECLARE @SonicConnectionIdDeTest [int];
DECLARE @SonicContainerId [int];
SELECT @EnvironmentIdTest = environment.[EnvironmentId]
FROM [dbo].[Environment] AS environment
WHERE environment.[EnvironmentCode] = N'TEST';
SELECT @CompanyIdDe = company.[CompanyId]
FROM [dbo].[Company] AS company
WHERE company.[CompanyCode] = N'DE';
IF @EnvironmentIdTest IS NULL
OR @CompanyIdDe IS NULL
BEGIN
THROW 50002,
N'Seed unvollstaendig: Environment TEST oder Company DE fehlt.',
1;
END;
IF NOT EXISTS
(
SELECT 1
FROM [dbo].[SonicConnection] AS connection
WHERE connection.[ConnectionName] = N'DE-Test'
)
BEGIN
INSERT INTO [dbo].[SonicConnection]
(
[EnvironmentId],
[ConnectionName],
[ManagementHost],
[ManagementPort],
[DomainName],
[ConnectionProtocol],
[IsActive],
[CreationDateTime],
[CreatedBy]
)
VALUES
(
@EnvironmentIdTest,
N'DE-Test',
N'dekun-painwbdet',
13070,
N'proalpha-test',
N'tcp',
1,
SYSUTCDATETIME(),
SUSER_SNAME()
);
END;
SELECT @SonicConnectionIdDeTest = connection.[SonicConnectionId]
FROM [dbo].[SonicConnection] AS connection
WHERE connection.[ConnectionName] = N'DE-Test';
IF @SonicConnectionIdDeTest IS NULL
BEGIN
THROW 50003,
N'Seed fehlgeschlagen: SonicConnection DE-Test nicht gefunden.',
1;
END;
IF NOT EXISTS
(
SELECT 1
FROM [dbo].[SonicContainer] AS container
WHERE container.[SonicConnectionId] = @SonicConnectionIdDeTest
AND container.[ContainerName] = N'ct-ZADBService'
)
BEGIN
INSERT INTO [dbo].[SonicContainer]
(
[CompanyId],
[SonicConnectionId],
[ContainerName],
[ContainerDisplayName],
[RestartTimeoutSeconds],
[IsActive],
[CreationDateTime],
[CreatedBy]
)
VALUES
(
@CompanyIdDe,
@SonicConnectionIdDeTest,
N'ct-ZADBService',
N'ZADBService',
180,
1,
SYSUTCDATETIME(),
SUSER_SNAME()
);
END;
SELECT @SonicContainerId = container.[SonicContainerId]
FROM [dbo].[SonicContainer] AS container
WHERE container.[SonicConnectionId] = @SonicConnectionIdDeTest
AND container.[ContainerName] = N'ct-ZADBService';
IF @SonicContainerId IS NULL
BEGIN
THROW 50004,
N'Seed fehlgeschlagen: SonicContainer ct-ZADBService nicht gefunden.',
1;
END;
IF NOT EXISTS
(
SELECT 1
FROM [dbo].[CertificateTarget] AS target
WHERE target.[SonicContainerId] = @SonicContainerId
AND target.[TargetFileName] = N'server.crt'
)
BEGIN
INSERT INTO [dbo].[CertificateTarget]
(
[SonicContainerId],
[TargetDirectory],
[TargetFileName],
[BackupEnabled],
[BackupDirectoryName],
[IsActive],
[CreationDateTime],
[CreatedBy]
)
VALUES
(
@SonicContainerId,
N'C:\ESB\Certificates',
N'server.crt',
1,
N'Backup',
1,
SYSUTCDATETIME(),
SUSER_SNAME()
);
END;
GO
/* Kontrolle */
SELECT
company.[CompanyCode],
environment.[EnvironmentCode],
connection.[ConnectionName],
connection.[ManagementHost],
connection.[ManagementPort],
connection.[DomainName],
container.[ContainerName],
target.[TargetDirectory],
target.[TargetFileName]
FROM [dbo].[SonicConnection] AS connection
INNER JOIN [dbo].[Environment] AS environment
ON environment.[EnvironmentId] = connection.[EnvironmentId]
INNER JOIN [dbo].[SonicContainer] AS container
ON container.[SonicConnectionId] = connection.[SonicConnectionId]
INNER JOIN [dbo].[Company] AS company
ON company.[CompanyId] = container.[CompanyId]
LEFT JOIN [dbo].[CertificateTarget] AS target
ON target.[SonicContainerId] = container.[SonicContainerId]
ORDER BY
environment.[SortOrder],
company.[CompanyCode],
connection.[ConnectionName];
GO
@@ -0,0 +1,41 @@
<#
.SYNOPSIS
Importiert das Always-Encrypted-Zertifikat in CurrentUser\My.
.NOTES
PFX-Passwort (nur Dev): ESB-AE-Dev-Only!
Thumbprint muss mit appsettings AlwaysEncrypted:CertificateThumbprint uebereinstimmen.
#>
$ErrorActionPreference = "Stop"
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$pfxPath = Join-Path $scriptDir "ESB_ZertifikatManager_AE.pfx"
$thumbPath = Join-Path $scriptDir "thumbprint.txt"
if (-not (Test-Path $pfxPath)) {
throw "PFX nicht gefunden: $pfxPath"
}
$expectedThumb = (Get-Content -Path $thumbPath -Raw).Trim()
$password = ConvertTo-SecureString -String "ESB-AE-Dev-Only!" -Force -AsPlainText
$imported = Import-PfxCertificate `
-FilePath $pfxPath `
-CertStoreLocation "Cert:\CurrentUser\My" `
-Password $password `
-Exportable
Write-Host "Zertifikat importiert:"
Write-Host " Subject : $($imported.Subject)"
Write-Host " Thumbprint : $($imported.Thumbprint)"
Write-Host " PrivateKey : $($imported.HasPrivateKey)"
if (-not [string]::Equals(
$imported.Thumbprint,
$expectedThumb,
[System.StringComparison]::OrdinalIgnoreCase)) {
Write-Warning "Thumbprint weicht von thumbprint.txt ab ($expectedThumb)."
}
Write-Host ""
Write-Host "appsettings.json AlwaysEncrypted:CertificateThumbprint ="
Write-Host $imported.Thumbprint
@@ -0,0 +1 @@
0x017000630075007200720065006E00740075007300650072002F006D0079002F003900350065003900300036006300630063003900630035006600320032003700390036003900380037003700630066003300620064003400360064003200610064003700310036003800380035003300000063875F8F9E6CA28F5C6AB80295C9526F00C6708A9E3D8EEF172189C88A445F21D08CA11BCA77B3460C8F109A0C30B3CF9E3E7007BC4EACE9563591014C6FDE01F15E72F6992C7862F1C22C7E69D00418B26E700F95112E870A17C4510891AE687B522F71A58E70DFAE211F6B233628FB17E87F2837726E4801CB45A2357CE57194239950B19930CE5C8B7AF9A0CFF86AFA52DF97D392C77DE694ECA336A0DBCB6E5157AF8713636D90D121BDA1CBC4909C3A1102BE9FE561321FED761A672D2E534A5C94391704C79D007804DE628961BB2A4744D88E975C8287459F2D7D42F643078CEFF8842DFE4C826CF4B47BE2A59DC65D495F39BE45AA583E2784DE039F
@@ -0,0 +1 @@
ESB-AE-Dev-Only!
@@ -0,0 +1 @@
95E906CCC9C5F227969877CF3BD46D2AD7168853
@@ -1,36 +1,46 @@
# Datenbank EsbZertifikatManager # Datenbank EsbZertifikatManager
Schlankes Schema (6 Tabellen) für den ESB Certificate Manager. Schlankes Schema (6 Tabellen) + Always Encrypted.
## Hierarchie ## Einmalige Reihenfolge
- **Company** — DE / PL / AT 1. **Zertifikat importieren** (auf jedem Client-PC):
- **Environment** — TEST2 / TEST / PROD (an `SonicConnection`)
- **SonicConnection** — Management-Host/Port/Domain
- **SonicCredential** — Always-Encrypted-Zugangsdaten (einziger Credential-Speicher)
- **SonicContainer** — Container je Company + Connection
- **CertificateTarget** — Deploy-Pfad/Dateiname (+ lokales File-Backup)
## Deployment (bestehende befüllte DB ersetzen) ```powershell
cd Database\AlwaysEncrypted
.\Install-Certificate.ps1
```
Alles wird gelöscht — keine Migration. - PFX: `ESB_ZertifikatManager_AE.pfx`
- Passwort: siehe `pfx-password.txt` (`ESB-AE-Dev-Only!`)
- Thumbprint: `95E906CCC9C5F227969877CF3BD46D2AD7168853`
1. **Always-Encrypted-Zertifikat** prüfen (Thumbprint aus `appsettings.json``AlwaysEncrypted:CertificateThumbprint`) unter `CurrentUser\My` inkl. privatem Schlüssel. 2. In SSMS:
2. Skripte **in dieser Reihenfolge** in SSMS ausführen:
1. `00_DropExisting.sql` — droppt `EsbZertifkatManager` (Alt) und `EsbZertifikatManager` inkl. CMK/CEK 1. `00_DropExisting.sql`
2. `01_CreateDatabase.sql` — leere Ziel-DB 2. `01_CreateDatabase.sql`
3. `02_CreateSchema.sql` — Always Encrypted (CMK/CEK) + 6 Tabellen 3. `02_CreateSchema.sql` (CMK/CEK + Tabellen)
4. `03_Seed.sql` Company + Environment 4. `03_Seed.sql` (**komplett**: Companies, Environments, DE-Test, Container, Target)
3. Connection String: `Database=EsbZertifikatManager` und `Column Encryption Setting=Enabled`.
4. Connections / Container / Targets manuell anlegen; Credentials **nur** über Setup-Wizard (`SonicCredential`, Always Encrypted). 3. App starten → Einstellungen → System **DE-Test** → Benutzerprofil anlegen → Übernehmen.
5. App neu starten.
## Seed-Inhalt (`03_Seed.sql`)
| Objekt | Werte |
|---|---|
| Company | DE, PL, AT |
| Environment | TEST2, TEST, PROD |
| SonicConnection | DE-Test → `tcp://dekun-painwbdet:13070`, Domain `proalpha-test`, Env TEST |
| SonicContainer | ct-ZADBService (Company DE) |
| CertificateTarget | `C:\ESB\Certificates\server.crt` (Platzhalter) |
| SonicCredential | **nicht** geseedet (Setup-Wizard / AE) |
## Always Encrypted ## Always Encrypted
| Objekt | Name | | Objekt | Name |
|---|---| |---|---|
| Column Master Key | `CMK_ESB_ZertifikatManager` | | CMK | `CMK_ESB_ZertifikatManager``CurrentUser/My/95E906CCC9C5F227969877CF3BD46D2AD7168853` |
| Column Encryption Key | `CEK_ESB_ZertifikatManager` | | CEK | `CEK_ESB_ZertifikatManager` |
| Verschlüsselte Spalten | `SonicCredential.CredentialUserName`, `SonicCredential.CredentialSecret` | | Spalten | `SonicCredential.CredentialUserName`, `CredentialSecret` |
CMK zeigt auf `CurrentUser/My/<Thumbprint>`. Der `ENCRYPTED_VALUE` der CEK gilt nur für dieses Zertifikat — bei neuem Cert CEK in SSMS neu erzeugen und in `02_CreateSchema.sql` ersetzen. Connection String braucht `Column Encryption Setting=Enabled`.
@@ -46,11 +46,11 @@ public sealed class SonicSetupRepository
INNER JOIN [dbo].[Environment] AS environment INNER JOIN [dbo].[Environment] AS environment
ON environment.[EnvironmentId] = ON environment.[EnvironmentId] =
connection.[EnvironmentId] connection.[EnvironmentId]
INNER JOIN [dbo].[SonicContainer] AS container LEFT JOIN [dbo].[SonicContainer] AS container
ON container.[SonicConnectionId] = ON container.[SonicConnectionId] =
connection.[SonicConnectionId] connection.[SonicConnectionId]
WHERE connection.[IsActive] = 1
AND container.[IsActive] = 1 AND container.[IsActive] = 1
WHERE connection.[IsActive] = 1
AND environment.[IsActive] = 1 AND environment.[IsActive] = 1
AND environment.[EnvironmentCode] = AND environment.[EnvironmentCode] =
@EnvironmentCode @EnvironmentCode
@@ -257,8 +257,11 @@ public sealed class SetupCoordinator
systems.Count > 0 systems.Count > 0
? $"{systems.Count} System(e) für " + ? $"{systems.Count} System(e) für " +
$"{_settings.EnvironmentCode} gefunden." $"{_settings.EnvironmentCode} gefunden."
: "Für die gewählte Umgebung wurde " + : $"Für Umgebung '{_settings.EnvironmentCode}' " +
"kein Sonic-System gefunden.", "wurde kein Sonic-System gefunden. " +
"Bitte Database/03_Seed.sql ausführen " +
"(legt DE-Test / ct-ZADBService an) " +
"oder eine SonicConnection in SQL anlegen.",
CredentialsReady = CredentialsReady =
systemExists systemExists
@@ -269,6 +272,9 @@ public sealed class SetupCoordinator
&& credentialExists && credentialExists
? $"System '{selection!.ConnectionName}', " + ? $"System '{selection!.ConnectionName}', " +
$"Profil '{selection.CredentialName}' ausgewählt." $"Profil '{selection.CredentialName}' ausgewählt."
: systems.Count == 0
? "Zuerst ein Sonic-System in SQL anlegen, " +
"dann System und Benutzerprofil wählen."
: "Bitte Sonic-System und Benutzerprofil auswählen." : "Bitte Sonic-System und Benutzerprofil auswählen."
}; };
} }
@@ -11,7 +11,7 @@
"SetupCompleted": true "SetupCompleted": true
}, },
"AlwaysEncrypted": { "AlwaysEncrypted": {
"CertificateThumbprint": "238AC7A32074D5B293C7EFB60E256907CB82C9C6", "CertificateThumbprint": "95E906CCC9C5F227969877CF3BD46D2AD7168853",
"StoreName": "My", "StoreName": "My",
"StoreLocation": "CurrentUser" "StoreLocation": "CurrentUser"
} }