Een Always Encrypted configureren met behulp van Azure Key Vault
VAN TOEPASSING OP:
Azure SQL Database
Azure SQL Managed Instance
In dit artikel wordt beschreven hoe u gevoelige gegevens in een database in Azure SQL Database beveiligt met gegevensversleuteling met behulp van de wizard Always Encrypted in SQL Server Management Studio (SSMS). Het bevat ook instructies voor het opslaan van elke versleutelingssleutel in Azure Key Vault.
Always Encrypted is een technologie voor gegevensversleuteling waarmee gevoelige data-at-rest op de server, tijdens de verplaatsing tussen client en server en terwijl de gegevens in gebruik zijn, worden beschermd. Always Encrypted zorgt ervoor dat gevoelige gegevens nooit als tekst zonder tekst in het databasesysteem worden weergegeven. Nadat u gegevensversleuteling hebt geconfigureerd, hebben alleen clienttoepassingen of app-servers die toegang hebben tot de sleutels toegang tot niet-versleutelde gegevens. Zie Always Encrypted (database-engine)voor gedetailleerde informatie.
Nadat u de database hebt geconfigureerd voor Always Encrypted, maakt u een clienttoepassing in C# met Visual Studio om te werken met de versleutelde gegevens.
Volg de stappen in dit artikel en leer hoe u een Always Encrypted database kunt instellen in Azure SQL Database of SQL Managed Instance. In dit artikel leert u hoe u de volgende taken uitvoert:
- Gebruik de wizard Always Encrypted in SSMS om de Always Encrypted maken.
- Maak een kolommastersleutel (CMK).
- Maak een kolomversleutelingssleutel (CEK).
- Maak een databasetabel en versleutel kolommen.
- Maak een toepassing die gegevens uit de versleutelde kolommen invoegt, selecteert en wekt weer.
Vereisten
- Een Azure-account en -abonnement. Als u nog geen hebt, kunt u zich aanmelden voor een gratis proefversie.
- Een database in Azure SQL Database of Azure SQL Managed Instance.
- SQL Server Management Studio versie 13.0.700.242 of hoger.
- .NET Framework 4.6 of hoger (op de clientcomputer).
- Visual Studio.
- Azure PowerShell of Azure CLI
Toegang tot clienttoepassing inschakelen
U moet uw clienttoepassing toegang geven tot uw database in SQL Database door een Azure Active Directory-toepassing (Azure AD) in te stellen en de toepassings-id en sleutel te kopiëren die u nodig hebt om uw toepassing te verifiëren.
Als u de toepassings-id en -sleutel wilt op halen, volgt u de stappen in Een toepassing Azure Active Directory service-principalmaken die toegang hebben tot resources.
Een sleutelkluis maken om uw sleutels op te slaan
Nu uw client-app is geconfigureerd en u uw toepassings-id hebt, is het tijd om een sleutelkluis te maken en het toegangsbeleid te configureren, zodat u en uw toepassing toegang hebben tot de geheimen van de kluis (de Always Encrypted-sleutels). De machtigingen create , get, list, sign, verify, wrapKey en unwrapKey zijn vereist voor het maken van een nieuwe kolommastersleutel en voor het instellen van versleuteling met SQL Server Management Studio.
U kunt snel een sleutelkluis maken door het volgende script uit te voeren. Zie Wat is Azure Key Vault? voor een gedetailleerde uitleg van deze opdrachten en meer informatie over het maken en configureren van een sleutelkluis.
Belangrijk
De Module PowerShell Azure Resource Manager (RM) wordt nog steeds ondersteund door Azure SQL Database, maar alle toekomstige ontwikkeling is voor de Az.Sql-module. De AzureRM-module blijft tot ten minste december 2020 bugfixes ontvangen. De argumenten voor de opdrachten in de Az-module en in de AzureRm-modules zijn vrijwel identiek. Zie Introductie van de nieuwe Az-module van Azure PowerShell voor meer informatie over de compatibiliteit van de argumenten.
$subscriptionName = '<subscriptionName>'
$userPrincipalName = '<username@domain.com>'
$applicationId = '<applicationId from AAD application>'
$resourceGroupName = '<resourceGroupName>' # use the same resource group name when creating your SQL Database below
$location = '<datacenterLocation>'
$vaultName = '<vaultName>'
Connect-AzAccount
$subscriptionId = (Get-AzSubscription -SubscriptionName $subscriptionName).Id
Set-AzContext -SubscriptionId $subscriptionId
New-AzResourceGroup -Name $resourceGroupName -Location $location
New-AzKeyVault -VaultName $vaultName -ResourceGroupName $resourceGroupName -Location $location
Set-AzKeyVaultAccessPolicy -VaultName $vaultName -ResourceGroupName $resourceGroupName -PermissionsToKeys create,get,wrapKey,unwrapKey,sign,verify,list -UserPrincipalName $userPrincipalName
Set-AzKeyVaultAccessPolicy -VaultName $vaultName -ResourceGroupName $resourceGroupName -ServicePrincipalName $applicationId -PermissionsToKeys get,wrapKey,unwrapKey,sign,verify,list
Verbinden met SSMS
Open SQL Server Management Studio (SSMS) en maak verbinding met de server of beheerd met uw database.
Open SQL Server Management Studio. (Ga naar Verbinding maken > Database-engine om het venster Verbinding maken met server te openen als deze niet is geopend.)
Voer uw servernaam of exemplaarnaam en referenties in.

Als het venster Nieuwe firewallregel wordt geopend, meldt u zich aan bij Azure en laat SSMS een nieuwe firewallregel voor u maken.
Een tabel maken
In deze sectie maakt u een tabel voor het opslaan van patiëntgegevens. Deze is in eerste instantie niet versleuteld. U configureert versleuteling in de volgende sectie.
- Vouw Databases uit.
- Klik met de rechtermuisknop op de database en klik op Nieuwe query.
- Plak de volgende Transact-SQL (T-SQL) in het nieuwe queryvenster en voer het uit.
CREATE TABLE [dbo].[Patients](
[PatientId] [int] IDENTITY(1,1),
[SSN] [char](11) NOT NULL,
[FirstName] [nvarchar](50) NULL,
[LastName] [nvarchar](50) NULL,
[MiddleName] [nvarchar](50) NULL,
[StreetAddress] [nvarchar](50) NULL,
[City] [nvarchar](50) NULL,
[ZipCode] [char](5) NULL,
[State] [char](2) NULL,
[BirthDate] [date] NOT NULL
PRIMARY KEY CLUSTERED ([PatientId] ASC) ON [PRIMARY] );
GO
Kolommen versleutelen (Always Encrypted)
SSMS biedt een wizard waarmee u eenvoudig een Always Encrypted configureren door de kolomsleutel, de kolomversleutelingssleutel en versleutelde kolommen voor u in te stellen.
Vouw Databases > Clinic-tabellen > uit.
Klik met de rechtermuisknop op de tabel Patiënten en selecteer Kolommen versleutelen om de wizard Always Encrypted openen:

De Always Encrypted bevat de volgende secties: Kolomselectie, Hoofdsleutelconfiguratie, Validatie en Samenvatting.
Kolomselectie
Klik op Volgende op de pagina Inleiding om de pagina Kolomselectie te openen. Op deze pagina selecteert u welke kolommen u wilt versleutelen, het type versleuteling en welke kolomversleutelingssleutel (CEK) u wilt gebruiken.
Versleutel SSN- en BirthDate-gegevens voor elke patiënt. De SSN-kolom maakt gebruik van deterministische versleuteling, die ondersteuning biedt voor gelijkheidszoekingen, joins en groep op. De kolom BirthDate maakt gebruik van willekeurige versleuteling, die geen ondersteuning biedt voor bewerkingen.
Stel het versleutelingstype voor de kolom SSN in op Deterministisch en de kolom BirthDate op Gerandomiseerd. Klik op Volgende.

Hoofdsleutelconfiguratie
Op de pagina Hoofdsleutelconfiguratie stelt u uw CMK in en selecteert u de sleutelopslagprovider waar de CMK wordt opgeslagen. Op dit moment kunt u een CMK opslaan in het Windows-certificaatopslag, Azure Key Vault of een HSM (Hardware Security Module).
In deze zelfstudie leert u hoe u uw sleutels in uw Azure Key Vault.
- Selecteer Azure Key Vault.
- Selecteer de gewenste sleutelkluis in de vervolgkeuzelijst.
- Klik op Volgende.

Validatie
U kunt de kolommen nu versleutelen of een PowerShell-script opslaan om later uit te voeren. Voor deze zelfstudie selecteert u Doorgaan om nu te voltooien en klikt u op Volgende.
Samenvatting
Controleer of de instellingen juist zijn en klik op Voltooien om de installatie voor de Always Encrypted.

De acties van de wizard controleren
Nadat de wizard is voltooid, wordt uw database ingesteld voor Always Encrypted. De wizard heeft de volgende acties uitgevoerd:
- U hebt een kolommastersleutel gemaakt en deze opgeslagen in Azure Key Vault.
- U hebt een kolomversleutelingssleutel gemaakt en deze opgeslagen in Azure Key Vault.
- De geselecteerde kolommen voor versleuteling geconfigureerd. De tabel Patiënten heeft momenteel geen gegevens, maar bestaande gegevens in de geselecteerde kolommen zijn nu versleuteld.
U kunt het maken van de sleutels in SSMS controleren door Clinic > Security Always Encrypted uit te > breiden.
Een clienttoepassing maken die werkt met de versleutelde gegevens
Nu Always Encrypted is ingesteld, kunt u een toepassing bouwen die invoegingen en selecties uitvoert op de versleutelde kolommen.
Belangrijk
Uw toepassing moet SqlParameter-objecten gebruiken bij het doorgeven van gegevens in platte tekst aan de server met Always Encrypted kolommen. Het doorgeven van letterlijke waarden zonder SqlParameter-objecten leidt tot een uitzondering.
- Open Visual Studio en maak een nieuwe C#-consoletoepassing (Visual Studio 2015 en eerder) of console-app (.NET Framework) (Visual Studio 2017 en hoger). Zorg ervoor dat uw project is ingesteld op .NET Framework 4.6 of hoger.
- Noem het project AlwaysEncryptedConsoleAKVApp en klik op OK.
- Installeer de volgende NuGet-pakketten door naar Tools > NuGet Pakketbeheer > Pakketbeheer Console te gaan.
Voer deze twee regels code uit in Pakketbeheer Console:
Install-Package Microsoft.SqlServer.Management.AlwaysEncrypted.AzureKeyVaultProvider
Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory
Wijzig uw connection string om deze in te Always Encrypted
In deze sectie wordt uitgelegd hoe u Always Encrypted in uw database kunt connection string.
Als u Always Encrypted wilt inschakelen, moet u het trefwoord Kolomversleutelingsinstelling toevoegen aan uw connection string instellen op Ingeschakeld.
U kunt dit rechtstreeks in de connection string of u kunt deze instellen met behulp van SqlConnectionStringBuilder. In de voorbeeldtoepassing in de volgende sectie ziet u hoe u SqlConnectionStringBuilder gebruikt.
Schakel Always Encrypted in de connection string
Voeg het volgende trefwoord toe aan uw connection string.
Column Encryption Setting=Enabled
Schakel Always Encrypted sqlConnectionStringBuilder in
De volgende code laat zien hoe u Always Encrypted inschakelen door SqlConnectionStringBuilder.ColumnEncryptionSetting in te stellen op Ingeschakeld.
// Instantiate a SqlConnectionStringBuilder.
SqlConnectionStringBuilder connStringBuilder = new SqlConnectionStringBuilder("replace with your connection string");
// Enable Always Encrypted.
connStringBuilder.ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Enabled;
De Azure Key Vault registreren
De volgende code laat zien hoe u de provider Azure Key Vault registreren bij het ADO.NET stuurprogramma.
private static ClientCredential _clientCredential;
static void InitializeAzureKeyVaultProvider() {
_clientCredential = new ClientCredential(applicationId, clientKey);
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider = new SqlColumnEncryptionAzureKeyVaultProvider(GetToken);
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> providers = new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
providers.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider);
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(providers);
}
Always Encrypted consoletoepassing maken
In dit voorbeeld wordt het volgende gedemonstreerd:
- Wijzig uw connection string om deze in Always Encrypted.
- Registreer Azure Key Vault als sleutelopslagprovider van de toepassing.
- Voeg gegevens in de versleutelde kolommen in.
- Selecteer een record door te filteren op een specifieke waarde in een versleutelde kolom.
Vervang de inhoud van Program.cs door de volgende code. Vervang de connection string voor de globale connectionString-variabele in de regel die direct voorafgaat aan de methode Main door uw geldige connection string van de Azure Portal. Dit is de enige wijziging die u moet maken in deze code.
Voer de app uit om de Always Encrypted in actie te zien.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.SqlServer.Management.AlwaysEncrypted.AzureKeyVaultProvider;
namespace AlwaysEncryptedConsoleAKVApp {
class Program {
// Update this line with your Clinic database connection string from the Azure portal.
static string connectionString = @"<connection string from the portal>";
static string applicationId = @"<application ID from your AAD application>";
static string clientKey = "<key from your AAD application>";
static void Main(string[] args) {
InitializeAzureKeyVaultProvider();
Console.WriteLine("Signed in as: " + _clientCredential.ClientId);
Console.WriteLine("Original connection string copied from the Azure portal:");
Console.WriteLine(connectionString);
// Create a SqlConnectionStringBuilder.
SqlConnectionStringBuilder connStringBuilder =
new SqlConnectionStringBuilder(connectionString);
// Enable Always Encrypted for the connection.
// This is the only change specific to Always Encrypted
connStringBuilder.ColumnEncryptionSetting =
SqlConnectionColumnEncryptionSetting.Enabled;
Console.WriteLine(Environment.NewLine + "Updated connection string with Always Encrypted enabled:");
Console.WriteLine(connStringBuilder.ConnectionString);
// Update the connection string with a password supplied at runtime.
Console.WriteLine(Environment.NewLine + "Enter server password:");
connStringBuilder.Password = Console.ReadLine();
// Assign the updated connection string to our global variable.
connectionString = connStringBuilder.ConnectionString;
// Delete all records to restart this demo app.
ResetPatientsTable();
// Add sample data to the Patients table.
Console.Write(Environment.NewLine + "Adding sample patient data to the database...");
InsertPatient(new Patient() {
SSN = "999-99-0001",
FirstName = "Orlando",
LastName = "Gee",
BirthDate = DateTime.Parse("01/04/1964")
});
InsertPatient(new Patient() {
SSN = "999-99-0002",
FirstName = "Keith",
LastName = "Harris",
BirthDate = DateTime.Parse("06/20/1977")
});
InsertPatient(new Patient() {
SSN = "999-99-0003",
FirstName = "Donna",
LastName = "Carreras",
BirthDate = DateTime.Parse("02/09/1973")
});
InsertPatient(new Patient() {
SSN = "999-99-0004",
FirstName = "Janet",
LastName = "Gates",
BirthDate = DateTime.Parse("08/31/1985")
});
InsertPatient(new Patient() {
SSN = "999-99-0005",
FirstName = "Lucy",
LastName = "Harrington",
BirthDate = DateTime.Parse("05/06/1993")
});
// Fetch and display all patients.
Console.WriteLine(Environment.NewLine + "All the records currently in the Patients table:");
foreach (Patient patient in SelectAllPatients()) {
Console.WriteLine(patient.FirstName + " " + patient.LastName + "\tSSN: " + patient.SSN + "\tBirthdate: " + patient.BirthDate);
}
// Get patients by SSN.
Console.WriteLine(Environment.NewLine + "Now lets locate records by searching the encrypted SSN column.");
string ssn;
// This very simple validation only checks that the user entered 11 characters.
// In production be sure to check all user input and use the best validation for your specific application.
do {
Console.WriteLine("Please enter a valid SSN (ex. 999-99-0003):");
ssn = Console.ReadLine();
} while (ssn.Length != 11);
// The example allows duplicate SSN entries so we will return all records
// that match the provided value and store the results in selectedPatients.
Patient selectedPatient = SelectPatientBySSN(ssn);
// Check if any records were returned and display our query results.
if (selectedPatient != null) {
Console.WriteLine("Patient found with SSN = " + ssn);
Console.WriteLine(selectedPatient.FirstName + " " + selectedPatient.LastName + "\tSSN: "
+ selectedPatient.SSN + "\tBirthdate: " + selectedPatient.BirthDate);
}
else {
Console.WriteLine("No patients found with SSN = " + ssn);
}
Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
}
private static ClientCredential _clientCredential;
static void InitializeAzureKeyVaultProvider() {
_clientCredential = new ClientCredential(applicationId, clientKey);
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider =
new SqlColumnEncryptionAzureKeyVaultProvider(GetToken);
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> providers =
new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>();
providers.Add(SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider);
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(providers);
}
public async static Task<string> GetToken(string authority, string resource, string scope) {
var authContext = new AuthenticationContext(authority);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, _clientCredential);
if (result == null)
throw new InvalidOperationException("Failed to obtain the access token");
return result.AccessToken;
}
static int InsertPatient(Patient newPatient) {
int returnValue = 0;
string sqlCmdText = @"INSERT INTO [dbo].[Patients] ([SSN], [FirstName], [LastName], [BirthDate])
VALUES (@SSN, @FirstName, @LastName, @BirthDate);";
SqlCommand sqlCmd = new SqlCommand(sqlCmdText);
SqlParameter paramSSN = new SqlParameter(@"@SSN", newPatient.SSN);
paramSSN.DbType = DbType.AnsiStringFixedLength;
paramSSN.Direction = ParameterDirection.Input;
paramSSN.Size = 11;
SqlParameter paramFirstName = new SqlParameter(@"@FirstName", newPatient.FirstName);
paramFirstName.DbType = DbType.String;
paramFirstName.Direction = ParameterDirection.Input;
SqlParameter paramLastName = new SqlParameter(@"@LastName", newPatient.LastName);
paramLastName.DbType = DbType.String;
paramLastName.Direction = ParameterDirection.Input;
SqlParameter paramBirthDate = new SqlParameter(@"@BirthDate", newPatient.BirthDate);
paramBirthDate.SqlDbType = SqlDbType.Date;
paramBirthDate.Direction = ParameterDirection.Input;
sqlCmd.Parameters.Add(paramSSN);
sqlCmd.Parameters.Add(paramFirstName);
sqlCmd.Parameters.Add(paramLastName);
sqlCmd.Parameters.Add(paramBirthDate);
using (sqlCmd.Connection = new SqlConnection(connectionString)) {
try {
sqlCmd.Connection.Open();
sqlCmd.ExecuteNonQuery();
}
catch (Exception ex) {
returnValue = 1;
Console.WriteLine("The following error was encountered: ");
Console.WriteLine(ex.Message);
Console.WriteLine(Environment.NewLine + "Press Enter key to exit");
Console.ReadLine();
Environment.Exit(0);
}
}
return returnValue;
}
static List<Patient> SelectAllPatients() {
List<Patient> patients = new List<Patient>();
SqlCommand sqlCmd = new SqlCommand(
"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients]",
new SqlConnection(connectionString));
using (sqlCmd.Connection = new SqlConnection(connectionString))
using (sqlCmd.Connection = new SqlConnection(connectionString)) {
try {
sqlCmd.Connection.Open();
SqlDataReader reader = sqlCmd.ExecuteReader();
if (reader.HasRows) {
while (reader.Read()) {
patients.Add(new Patient() {
SSN = reader[0].ToString(),
FirstName = reader[1].ToString(),
LastName = reader["LastName"].ToString(),
BirthDate = (DateTime)reader["BirthDate"]
});
}
}
}
catch (Exception ex) {
throw;
}
}
return patients;
}
static Patient SelectPatientBySSN(string ssn) {
Patient patient = new Patient();
SqlCommand sqlCmd = new SqlCommand(
"SELECT [SSN], [FirstName], [LastName], [BirthDate] FROM [dbo].[Patients] WHERE [SSN]=@SSN",
new SqlConnection(connectionString));
SqlParameter paramSSN = new SqlParameter(@"@SSN", ssn);
paramSSN.DbType = DbType.AnsiStringFixedLength;
paramSSN.Direction = ParameterDirection.Input;
paramSSN.Size = 11;
sqlCmd.Parameters.Add(paramSSN);
using (sqlCmd.Connection = new SqlConnection(connectionString)) {
try {
sqlCmd.Connection.Open();
SqlDataReader reader = sqlCmd.ExecuteReader();
if (reader.HasRows) {
while (reader.Read()) {
patient = new Patient() {
SSN = reader[0].ToString(),
FirstName = reader[1].ToString(),
LastName = reader["LastName"].ToString(),
BirthDate = (DateTime)reader["BirthDate"]
};
}
}
else {
patient = null;
}
}
catch (Exception ex) {
throw;
}
}
return patient;
}
// This method simply deletes all records in the Patients table to reset our demo.
static int ResetPatientsTable() {
int returnValue = 0;
SqlCommand sqlCmd = new SqlCommand("DELETE FROM Patients");
using (sqlCmd.Connection = new SqlConnection(connectionString)) {
try {
sqlCmd.Connection.Open();
sqlCmd.ExecuteNonQuery();
}
catch (Exception ex) {
returnValue = 1;
}
}
return returnValue;
}
}
class Patient {
public string SSN { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
}
}
Controleren of de gegevens zijn versleuteld
U kunt snel controleren of de werkelijke gegevens op de server zijn versleuteld door een query uit te voeren op de gegevens van patiënten met SSMS (met behulp van uw huidige verbinding waarbij de instelling voor kolomversleuteling nog niet is ingeschakeld).
Voer de volgende query uit op de database Clinic.
SELECT FirstName, LastName, SSN, BirthDate FROM Patients;
U kunt zien dat de versleutelde kolommen geen niet-versleutelde gegevens bevatten.

Als u SSMS wilt gebruiken voor toegang tot de ongecodeerde gegevens, moet u eerst controleren of de gebruiker de juiste machtigingen heeft voor de Azure Key Vault: get, unwrapKey en verify. Zie Kolommastersleutels maken en opslaan (Always Encrypted)voor gedetailleerde informatie.
Voeg vervolgens de parameter Column Encryption Setting=enabled toe tijdens uw verbinding.
Klik in SSMS met de rechtermuisknop op uw server in Objectverkenner kies Verbinding verbreken.
Klik op > Database-engine verbinden om het venster Verbinding maken met server te openen en klik op Opties.
Klik op Extra verbindingsparameters en typ Instelling voor kolomversleuteling =ingeschakeld.

Voer de volgende query uit op de database Clinic.
SELECT FirstName, LastName, SSN, BirthDate FROM Patients;U kunt nu de niet-versleutelde gegevens in de versleutelde kolommen zien.

Volgende stappen
Nadat uw database is geconfigureerd voor het gebruik van Always Encrypted, kunt u het volgende doen: