Update readme
- Add a link for the ledger subfolder in sql-server-samples/README.md at master · Pietervanhove/sql-server-samples (github.com) - Change the folder name from “sqlledger” to “ledger” (that’s the official feature name now). - sql-server-samples/README.md at master · Pietervanhove/sql-server-samples (github.com) o Fix grammar in “The demo in this folder showcases the ledger feature in Azure SQL Database. The demo uses the Contoso HR web application.” o Are Az PS 5.6, SqlServer 21.1.18245, Bicep 0.4.63, SSMS 18.9.1 the versions you’ve tested with? These are older versions (the same we used when developing the AE demo). Should we recommend using newer versions? o “The ContosoHR database using General Purpose compute tier, 2 vCores, and the Gen5 hardware generation.” I’m wondering if there is a better/more economical SLO/SKU we can pick, instead of the 2-core Gen 5 database. Of course, Basic/Standard would be very cheap, but we probably should promote the new v-core model. Would serverless be a better option, e.g. “GP_S_Gen5_1”? o If we change the folder name, change sqlledger to ledger in cd "C:\sql-server-samples\samples\features\security\sql-ledger\azure-sql-database\setup" o “Open a new InPrivate browser window.” Are these instructions generic enough to accommodate browsers other than Edge? - sql-server-samples/samples/features/security/contoso-hr-sql-db at master · Pietervanhove/sql-server-samples (github.com) o This is unrelated to ledger. Could you also remove this folder? It was checked in by mistake when we added the AE demo. It is redundant/not needed.
@@ -1,6 +1,7 @@
|
||||
#SQL Security
|
||||
|
||||
<!--placeholder for summary.-->
|
||||
[Ledger Demo](ledger)
|
||||
|
||||
[Always Encrypted with secure enclaves Demos](always-encrypted-with-secure-enclaves)
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
# Contoso HR Security Demo
|
||||
|
||||
This set of samples and demos showcases the benefits of the following features in Azure SQL Database:
|
||||
|
||||
- [Always Encrypted with secure enclaves](https://docs.microsoft.com/azure/azure-sql/database/always-encrypted-with-secure-enclaves-landing)
|
||||
|
||||
## Contents
|
||||
|
||||
1. [Prerequisites](#Prerequisites)
|
||||
2. [Setup](#Setup)
|
||||
3. [Demos](#Demos)
|
||||
|
||||
## Prerequisites
|
||||
Before you begin you need an Azure subscription. If you don't already have an Azure subscription, you can get one for free [here](https://azure.microsoft.com/free/).
|
||||
|
||||
You also need to make sure the following software is installed on your machine:
|
||||
|
||||
1. PowerShell modules:
|
||||
1. Az version 5.6 or later. For details on how to install the Az PowerShell module, see [Install the Azure Az PowerShell module](https://docs.microsoft.com/powershell/azure/install-az-ps). To determine the version the Az module installed on your machine, run the following command from a PowerShell session.
|
||||
|
||||
```powershell
|
||||
Get-InstalledModule -Name Az
|
||||
```
|
||||
|
||||
1. Az.Attestation 0.1.8 or later. For details on how to install the Az.Attestation PowerShell module, see [Install Az.Attestation PowerShell module](https://docs.microsoft.com/azure/attestation/quickstart-powershell#install-azattestation-powershell-module). To determine the version the Az.Attestation module installed on your machine, run the following command from a PowerShell session.
|
||||
|
||||
```powershell
|
||||
Get-InstalledModule -Name Az.Attestation
|
||||
```
|
||||
1. SqlServer version 21.1.18245 or later. For details on how to install the SqlServer PowerShell module, see [Installing or updating the SqlServer module](https://docs.microsoft.com/sql/powershell/download-sql-server-ps-module#installing-or-updating-the-sqlserver-module). To determine the version the SqlServer module installed on your machine, run the following command from a PowerShell session.
|
||||
|
||||
```powershell
|
||||
Get-InstalledModule -Name SqlServer
|
||||
```
|
||||
|
||||
1. [Bicep](https://docs.microsoft.com/azure/azure-resource-manager/templates/bicep-overview) version 0.4.63 or later. You need install Bicep and ensure it can be invoked from PowerShell. The recommended way to achieve that is to [install Bicep manually with PowerShell](https://docs.microsoft.com/azure/azure-resource-manager/templates/bicep-install?tabs=azure-powershell#manual-with-powershell).
|
||||
1. [SQL Server Management Studio](https://msdn.microsoft.com/en-us/library/mt238290.aspx) - version 18.9.1 or later is recommended.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Clone/download the repository.
|
||||
1. Open a PowerShell session.
|
||||
1. In the PowerShell session, change the directory to the setup folder within this demo's directory.
|
||||
1. Run the setup.ps1 PowerShell script.
|
||||
1. When prompted, enter the following information:
|
||||
1. Your Azure subscription id. To determine your subscription id, see [Find your Azure subscription](https://docs.microsoft.com/en-us/azure/media-services/latest/setup-azure-subscription-how-to?tabs=portal).
|
||||
1. The project name. The resource group containing all your demo resources will have that name. The project name will also be used as a prefix for the names of all demo resources. Please use only lowercase letters and numbers for the project name and make sure it is unique.
|
||||
1. The location - it must be the name of an Azure region that supports the [DC-series hardware generation](https://docs.microsoft.com/azure/azure-sql/database/service-tiers-vcore?tabs=azure-portal#dc-series-1) in Azure SQL Database.
|
||||
1. The username and the password of the Azure SQL database server administrator. The setup script will create the server with these admin credentials and it will later use them to connect to the server using SQL authentication for some of the setup steps.
|
||||
1. When prompted, sign in to Azure. Once you sign in, the script will deploy the demo environment using the provided Bicep template, which may take a few minutes. After the deployment completes, the script performs post-deployment setup steps to configure the database and the attestation policy for Always Encrypted with secure enclaves.
|
||||
1. When prompted, sign in to Azure again, to enable the SqlServer PowerShell module to connect to the database.
|
||||
1. Finally, the script outputs the important information about your demo environment.
|
||||
- Database server name (`<project name>server.database.windows.net`)
|
||||
- Database name (`ContosoHR`)
|
||||
- Attestation URL (`https://<project name>attest.<region moniker>.attest.azure.net/attest/SgxEnclave`)
|
||||
- Application URL (`https://<project name>app.azurewebsites.net/`)
|
||||
|
||||
Please copy and save the above information. You will need it for the demo steps.
|
||||
|
||||
## Demos
|
||||
|
||||
- [Always Encrypted with secure enclaves](always-encrypted-with-secure-enclaves/README.md)
|
||||
@@ -1,266 +0,0 @@
|
||||
# Always Encrypted with secure enclaves in Azure SQL Database - Demos
|
||||
|
||||
The below demos showcase [Always Encrypted with secure enclaves](https://docs.microsoft.com/azure/azure-sql/database/always-encrypted-with-secure-enclaves-landing) in Azure SQL Database.
|
||||
|
||||
## Contents
|
||||
|
||||
1. [Prerequisites](#Prerequisites)
|
||||
2. [Demo 1](#demo-1) - a tour of the demo environment.
|
||||
3. [Demo 2](#demo-2) - a short demo of key benefits of secure enclaves.
|
||||
4. [Demo 3](#demo-3) - a longer demo showcasing in-place encryption and rich queries.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The demos assume you have met the prerequisites listed in [Prerequisites](../README.md#prerequisites) and you have set up your demo environment by following the instructions in [Setup](../README.md#setup). Make sure you have the information about your environment, the setup script has produced:
|
||||
|
||||
- The demo resource group name (`<project name>`).
|
||||
- The database server name (`<project name>server.database.windows.net`).
|
||||
- The database name (`ContosoHR`).
|
||||
- The attestation URL (`https://<project name>attest.<region moniker>.attest.azure.net/attest/SgxEnclave`).
|
||||
- The application URL (`https://<project name>app.azurewebsites.net/`).
|
||||
|
||||
## Demo 1
|
||||
|
||||
During this demo, you will take a tour of the demo environment, in which Always Encrypted with secure enclaves is already set up and sensitive data columns in the database are already encrypted.
|
||||
|
||||
### Prepare for the demo
|
||||
Perform the below steps before you show the demo.
|
||||
|
||||
1. Close all running instances of SQL Server Management Studio (SSMS).
|
||||
2. Prepare a new instance of SSMS.
|
||||
1. Start SSMS.
|
||||
2. In the Connect to Server dialog:
|
||||
1. In the main page of the dialog, enter your database server name. Set `Authentication` to `Azure Active Directory – Universal with MFA`. In the `User Name` field, enter your Azure AD username. You should enter the same username, you've used to sign in to Azure, when you set up your demo environment.
|
||||
|
||||

|
||||
|
||||
2. Click Connect.
|
||||
3. When prompted, sign in to Azure.
|
||||
3. Prepare your web browser.
|
||||
1. Open a new tab in the browser and point it to Azure Portal: `https://portal.azure.com`.
|
||||
2. Sign in to Azure if prompted.
|
||||
3. In the `Search` box in the Azure Portal, enter the name of your demo resource group and click `Enter`. In the search results, click on your resource group. You should see the content of your resource group, which should look like this:
|
||||
|
||||

|
||||
|
||||
### Demos steps
|
||||
|
||||
1. Review the content of your demo resource group. It should contain the following resources:
|
||||
|
||||
- `<project name>app`- the app service hosting the Contoso HR web application.
|
||||
- `<project name>attest`- the attestation provider in Microsoft Azure Attestation for attesting the secure enclave for the `ContosoHR` database.
|
||||
- `<project name>identity` - the user-assigned managed identity that was used to deploy the web application.
|
||||
- `<project name>plan` - the app service plan for the web application.
|
||||
- `<project name>server`- the Azure SQL database server in Azure SQL Database.
|
||||
- `<project name>vault` - the key vault in Azure Key Vault, containing the column master key for Always Encrypted.
|
||||
- `ContosoHR` - the database.
|
||||
|
||||
2. Right-click on the `ContosoHR` database in the resource group and open its `Overview` blade in the new tab. Click on `Compute + storage` under `Settings`. Click `Change configuration`. Note that the database is already configured to use the DC-series hardware configuration that supports confidential computing using secure enclaves. Setting the DC-series hardware configuration for a database is required to use Always Encrypted with secure enclaves in the database. For more information, see [Enable Intel SGX for your Azure SQL Database](https://docs.microsoft.com/en-us/azure/azure-sql/database/always-encrypted-enclaves-enable-sgx).
|
||||
|
||||

|
||||
|
||||
3. Close the browser tab for the database. Right-click on the attestation provider in your resource group and open its `Overview` blade in a new tab. Click on `Policy` under `Settings`. Select `SGX-IntelSDK` for `Attestation Type`. This will display the attestation policy configured for Intel Software Guard eXtensions (Intel SGX) enclaves. The policy allows a client driver within an application to verify the secure enclave in Azure SQL Database is a genuine Intel SGX enclave and it runs the genuine SQL library that implements Transact-SQL predicates and cryptographic operations of Always Encrypted. For more information, see [Configure Azure Attestation for your Azure SQL logical server](https://docs.microsoft.com/en-us/azure/azure-sql/database/always-encrypted-enclaves-configure-attestation).
|
||||
|
||||

|
||||
|
||||
4. Close the browser tab for the attestation provider. Right-click on the app service for the Contoso HR web application in your resource group and open its `Overview` blade in a new tab. Click on `Configuration` under `Settings`. In the `Connection strings` section, click `Advanced edit`. This will display the database connection string configured for the web application. There are three important things to call out in the database connection string:
|
||||
|
||||
- `Column Encryption Setting = Enabled` turns the Always Encrypted on in the client driver, allowing it to transparently encrypt query parameters and decrypt queries results.
|
||||
- `Attestation Protocol = AAS` specifies Microsoft Azure Attestation is used for attesting the secure enclave for the `ContosoHR` database.
|
||||
- `Enclave Attestation Url` specifies the URL of the attestation policy in your attestation provider in Microsoft Azure Attestation.
|
||||
|
||||

|
||||
|
||||
5. Close the browser tab for the app service. Right-click on the key vault in your resource group open its `Overview` blade in a new tab.
|
||||
1. Click on `Keys` under `Settings`. You should see the entry for the key, named `CMK` - this is your column master key for Always Encrypted.
|
||||

|
||||
|
||||
2. Click on `Access Policies` under `Settings`. You should see two access policy entries: one for your identity and one for the web app's identity. These policies grant you permissions necessary to perform key management operations and they grant the web app permissions required to decrypt column encryption keys, protecting the data.
|
||||
|
||||
6. Switch to SSMS.
|
||||
1. In Object Explorer, navigate to the `ContosoHR` database. Then go to `Security` > `Always Encrypted Keys`.
|
||||
2. Open the `Column Master Keys` and `Column Encryption Keys` folders. You should see the metadata object, named `CMK1`, for the column master key and the metadata object, named `CEK1`, for the column encryption key.
|
||||
3. Right click on `CMK1` and select `Properties`. Note that the metadata object references the key in the key vault. Also note `Enclave Computations` is set to `Allowed`, which permits the column encryption key, this columns master key protects, to be used in enclave computations.
|
||||
|
||||

|
||||
|
||||
### Key Takeaways
|
||||
|
||||
Always Encrypted with secure enclaves requires specific hardware that is exposed in Azure SQL Database as the DC-series hardware configuration. Microsoft Azure Attestation is a Platform-as-a-Service solution for attestation enclaves in Azure. Enclaves are attested against a policy, you define and control.
|
||||
|
||||
## Demo 2
|
||||
|
||||
This short demo highlights the main benefits of Always Encrypted with secure enclaves. The starting point for the demo is the ContosoHR database the `SSN` and `Salary` columns already encrypted.
|
||||
|
||||
### Prepare for the demo
|
||||
Perform the below steps before you show the demo.
|
||||
|
||||
1. Close all running instances of SQL Server Management Studio (SSMS).
|
||||
2. Prepare a new instance of SSMS.
|
||||
1. Start SSMS.
|
||||
2. In the `Connect to Server` dialog:
|
||||
1. In the main page of the dialog, enter your database server name. Set `Authentication` to `Azure Active Directory – Universal with MFA`. In the `User Name` field, enter your Azure AD username. You should enter the same username, you've used to sign in to Azure, when you set up your demo environment.
|
||||
|
||||

|
||||
|
||||
2. Click the `Options >>` button, select the `Connection Properties` tab and enter the database name (`ContosoHR`).
|
||||
|
||||

|
||||
|
||||
3. Select the `Always Encrypted` tab. Make sure the `Enable Always Encrypted` checkbox is **not** selected.
|
||||
|
||||

|
||||
|
||||
4. Click Connect.
|
||||
5. When prompted, sign in to Azure.
|
||||
3. Configure query windows.
|
||||
1. In Object Explorer, find and select the `ContosoHR` database.
|
||||
|
||||

|
||||
|
||||
2. With the `ContosoHR` database selected, click Ctrl + O. In the `Open File` dialog, navigate to the `tsql-scripts` folder and select `ListAllEmployees.sql`. Do not execute the query yet.
|
||||
3. With the `ContosoHR` database selected, click Ctrl + O. In the `Open File` dialog, navigate to the `tsql-scripts` folder and select `QueryEvents.sql`. Do not execute the query yet.
|
||||
3. Prepare your web browser.
|
||||
1. Open your browser.
|
||||
2. Point the browser to the demo application URL.
|
||||
|
||||

|
||||
|
||||
### Demos steps
|
||||
|
||||
1. Show the Contoso HR web app in the the browser. This application displays employee records and allows you to filter employees by salary or by a portion of the social security number (SSN). Move the salary slider and enter a couple of digits in the search box to filter by salary and SSN.
|
||||
|
||||

|
||||
|
||||
2. Switch to SSMS, select the `ListAllEmployees.sql` tab and click `F5` to execute the query, which shows the content of the `Employees` table, the web application uses as a data store. Although you are a DBA of the database, you cannot see the plaintext data in the `SSN` and `Salary` columns, as those two columns are protected with Always Encrypted.
|
||||
|
||||

|
||||
|
||||
3. Select the `QueryXevents.sql` tab and click `F5` to execute the query. This query retrieves extended events from the `Demo` extended event session, configured in the `ContosoHR` database. Each extended event captures a query the web application has sent to the database.
|
||||
|
||||

|
||||
|
||||
4. Click on the link in the second column of the first row of the result set to see the extended event with the latest query from the application. This will open the extended event in the new tab.
|
||||
1. Review the query statement. Note that the query contains the `WHERE` clause with rich computations on encrypted columns: pattern matching using the `LIKE` predicate on the `SSN` column and the range comparison on the `Salary` column. The query also sorts records (the `ORDER BY` clause) by `SSN` or `Salary`. **Pro Tip:** to make it easier to view the query statement, you can put line brakes in it.
|
||||
|
||||

|
||||
|
||||
2. Locate the value of query parameters: `@SSNSearchPattern`, `@MinSalary`, `@MaxSalary`. Note that the values of the parameters are encrypted – the client driver inside the web app transparently encrypts parameters corresponding to encrypted columns, before sending the query to the database. Not only does not the DBA have access to sensitive data in the database, but the DBA cannot see the plaintext values of query parameters used to process that data.
|
||||
|
||||
### Key Takeaways
|
||||
|
||||
Always Encrypted with secure enclaves allows applications to perform rich queries on sensitive data without revealing the data to potentially malicious insiders, including DBAs in your organization.
|
||||
|
||||
## Demo 3
|
||||
|
||||
The starting point for this demo is the database with no columns encrypted - the data is initially not protected. The demo shows how to reach the following two objectives:
|
||||
|
||||
1. Protect sensitive data in the database by encrypting it in-place.
|
||||
2. Ensure the Contoso HR web application can continue run rich queries on database columns after encrypting the columns.
|
||||
|
||||
During the demo, you will use two instances of SQL Server Management Studio (SSMS):
|
||||
|
||||
- DBA's instance - when using it, you will assume the role of a DBA.
|
||||
- Security Adminsitrator's instance - when using it, you will assume the role of a Security Administrator, who configures Always Encrypted in the database.
|
||||
|
||||
### Prepare for the demo
|
||||
Perform the below steps before you show the demo.
|
||||
|
||||
1. Close all running SSMS instances.
|
||||
2. Prepare DBA's instance of SSMS.
|
||||
1. Start SSMS.
|
||||
2. In the Connect to Server dialog:
|
||||
1. In the main page of the dialog, enter your database server name. Set `Authentication` to `Azure Active Directory – Universal with MFA`. In the `User Name` field, enter your Azure AD username. You should enter the same username, you've used to sign in to Azure, when you set up your demo environment.
|
||||
|
||||

|
||||
|
||||
2. Click the `Options >>` button, select the `Connection Properties` tab and enter the database name(`ContosoHR`).
|
||||
|
||||

|
||||
|
||||
3. Select the `Always Encrypted` tab. Make sure the `Enable Always Encrypted` checkbox is **not** selected.
|
||||
|
||||

|
||||
|
||||
4. Click Connect.
|
||||
5. When prompted, sign in to Azure.
|
||||
3. Configure query windows.
|
||||
1. In Object Explorer, find and select the `ContosoHR` database.
|
||||
|
||||

|
||||
|
||||
2. With the `ContosoHR` database selected, click Ctrl + O. In the `Open File` dialog, navigate to the `tsql-scripts` folder and select `ListAllEmployees.sql`. Do not execute the query yet.
|
||||
3. With the `ContosoHR` database selected, click Ctrl + O. In the `Open File` dialog, navigate to the `tsql-scripts` folder and select `QueryEvents.sql`. Do not execute the query yet.
|
||||
3. Prepare Security Administrator's instance of SSMS.
|
||||
1. Start SSMS.
|
||||
2. In the Connect to Server dialog:
|
||||
1. In the main page of the dialog, enter your database server name. Set `Authentication` to `Azure Active Directory – Universal with MFA`. In the `User Name` field, enter your Azure AD username. You should enter the same username, you've used to sign in to Azure, when you set up your demo environment.
|
||||
|
||||

|
||||
|
||||
2. Click the `Options >>` button, select the `Connection Properties` tab and enter the database name(`ContosoHR`).
|
||||
|
||||

|
||||
|
||||
3. Select the `Always Encrypted` tab. Make sure the `Enable Always Encrypted` checkbox **is** selected. Enter your attestation URL.
|
||||
|
||||

|
||||
|
||||
4. Click Connect.
|
||||
5. When prompted, sign in to Azure.
|
||||
3. Configure query windows.
|
||||
1. In Object Explorer, find and select the `ContosoHR` database.
|
||||
|
||||

|
||||
|
||||
2. With the `ContosoHR` database selected, click Ctrl + O. In the `Open File` dialog, navigate to the `tsql-scripts` folder and select `DecryptColumns.sql`. **Click `F5` to execute the query**, which will decrypt the `SSN` and `Salary` columns in the database.
|
||||
3. With the `ContosoHR` database selected, click Ctrl + O. In the `Open File` dialog, navigate to the `tsql-scripts` folder and select `EncryptColumns.sql`. Do not execute the query yet.
|
||||
4. Prepare your web browser.
|
||||
1. Open your browser.
|
||||
2. Point the browser to the demo application URL.
|
||||
|
||||

|
||||
|
||||
### Demos steps
|
||||
|
||||
1. Show the Contoso HR web app in the the browser. This application displays employee records and allows you to filter employees by salary or by a portion of the social security number (SSN). Move the salary slider and enter a couple of digits in the search box to filter by salary and SSN.
|
||||
|
||||

|
||||
|
||||
2. Switch to DBA's instance of SSMS, select the `ListAllEmployees.sql` tab and click `F5` to execute the query, which shows the content of the `Employees` table, the web application uses as a data store. As a DBA, you can view all sensitive information about employees, including the data stored in the `SSN` and `Salary` columns. A malicious DBA could easily exfiltrate the data by running a simple query like this one.
|
||||
|
||||

|
||||
|
||||
3. Select the `QueryXevents.sql` tab and click `F5` to execute the query. This query retrieves extended events from the `Demo` extended event session, configured in the `ContosoHR` database. Each extended event captures a query the web application has sent to the database.
|
||||
|
||||

|
||||
|
||||
4. Click on the link in the second column of the first row of the result set to see the extended event with the latest query from the application. This will open the extended event in the new tab.
|
||||
1. Review the query statement. Note that the query contains the `WHERE` clause with rich computations on encrypted columns: pattern matching using the `LIKE` predicate on the `SSN` column and the range comparison on the `Salary` column. The query also sorts records (the `ORDER BY` clause) by `SSN` or `Salary`. **Pro Tip:** to make it easier to view the query statement, you can put line brakes in it.
|
||||
|
||||

|
||||
|
||||
2. Locate the value of query parameters: `@SSNSearchPattern`, `@MinSalary`, `@MaxSalary`. Note that the values of the parameters are in plaintext, as the columns, the parameters correspond to, are not encrypted.
|
||||
|
||||
5. Switch to Security Administrator's instance of SSMS, select the `EncryptColumns.sql` tab and click `F5` to execute the query, encrypts the data in the `SSN` and `Salary` columns in place, using the secure enclave.
|
||||
|
||||
6. Switch back to DBA's instance of SSMS, select the `ListAllEmployees.sql` tab and click `F5` to execute the query again. Now the query should show the encrypted data in the `SSN` and `Salary` columns. As both columns are encrypted, the DBA cannot see the data in plaintext.
|
||||
|
||||

|
||||
|
||||
7. In the web browser, move the slider to reset the filter for salary and then re-enter a few digits of an SSN. Confirm the application still can filter employee records by salary and SSN.
|
||||
|
||||
8. Switch to DBA's instance of SSMS, select the `QueryXevents.sql` tab and click `F5` to re-run the query.
|
||||
|
||||
9. Click on the link in the second column of the first row of the result set to see the extended event with the latest query from the application. This will open the extended event in the new tab.
|
||||
1. Review the query statement. Note that the query statement the query sends to the database has not changed - it still contains pattern matching using the `LIKE` predicate on the `SSN` column and the range comparison on the `Salary` column, as well as sorting (the `ORDER BY` clause) by `SSN` or `Salary`. **Pro Tip:** to make it easier to view the query statement, you can put line brakes in it.
|
||||
|
||||

|
||||
|
||||
2. Locate the value of query parameters: `@SSNSearchPattern`, `@MinSalary`, `@MaxSalary`. Note that the values of the parameters are now encrypted – the client driver inside the web app transparently encrypts parameters corresponding to encrypted columns, before sending the query to the database. Not only does not the DBA have access to sensitive data in the database, but the DBA cannot see the plaintext values of query parameters used to process that data.
|
||||
|
||||
### Key Takeaways
|
||||
|
||||
Secure enclaves make it possible to encrypt sensitive data columns in-place, eliminating a need to move the data outside of the database for cryptographic operations.
|
||||
|
||||
The unique benefit of Always Encrypted with secure enclaves is that it allows you to protect your sensitive data from high-privilege users, including DBAs in your organization, and, after you encrypt your data to protect it, your applications can continue running rich queries on encrypted columns.
|
||||
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 394 KiB |
|
Before Width: | Height: | Size: 520 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 63 KiB |
@@ -1,17 +0,0 @@
|
||||
ALTER TABLE [dbo].[Employees]
|
||||
ALTER COLUMN [SSN] [char](11) NOT NULL
|
||||
WITH (ONLINE = ON)
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[Employees]
|
||||
ALTER COLUMN [Salary] [Money] NOT NULL
|
||||
WITH (ONLINE = ON)
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[Employees]
|
||||
ALTER COLUMN [LastName] [nvarchar](50) NOT NULL
|
||||
WITH (ONLINE = ON)
|
||||
GO
|
||||
|
||||
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
|
||||
GO
|
||||
@@ -1,14 +0,0 @@
|
||||
-- Data Owner's script - the user needs access to the keys
|
||||
|
||||
ALTER TABLE [dbo].[Employees]
|
||||
ALTER COLUMN [SSN] [char](11) COLLATE Latin1_General_BIN2
|
||||
ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK1], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL;
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[Employees]
|
||||
ALTER COLUMN [Salary] [Money]
|
||||
ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK1], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL;
|
||||
GO
|
||||
|
||||
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
|
||||
GO
|
||||
@@ -1,18 +0,0 @@
|
||||
SELECT * FROM [dbo].[Employees];
|
||||
|
||||
DECLARE @SSN CHAR(11) = '795-73-9838'
|
||||
SELECT * FROM [dbo].[Employees] WHERE [SSN] = @SSN;
|
||||
GO
|
||||
|
||||
DECLARE @SSNPattern CHAR(11) = '%9838'
|
||||
SELECT * FROM [dbo].[Employees] WHERE [SSN] LIKE @SSNPattern;
|
||||
GO
|
||||
|
||||
DECLARE @MinSalary MONEY = 40000
|
||||
DECLARE @MaxSalary MONEY = 45000
|
||||
SELECT * FROM [dbo].[Employees] WHERE [Salary] > @MinSalary AND [Salary] < @MaxSalary;
|
||||
GO
|
||||
|
||||
DECLARE @LastNamePrefix NVARCHAR(50) = 'Aber%';
|
||||
SELECT * FROM [dbo].[Employees] WHERE [LastName] LIKE @LastNamePrefix;
|
||||
GO
|
||||
@@ -1,55 +0,0 @@
|
||||
DECLARE @ExtendedEventsSessionName sysname = N'Demo';
|
||||
DECLARE @StartTime datetimeoffset;
|
||||
DECLARE @EndTime datetimeoffset;
|
||||
DECLARE @Offset int;
|
||||
|
||||
DROP TABLE IF EXISTS #xmlResults;
|
||||
CREATE TABLE #xmlResults
|
||||
(
|
||||
xeTimeStamp datetimeoffset NOT NULL
|
||||
, xeXML XML NOT NULL
|
||||
);
|
||||
|
||||
SET @StartTime = DATEADD(HOUR, -4, GETDATE()); --modify this to suit your needs
|
||||
SET @EndTime = GETDATE();
|
||||
SET @Offset = DATEDIFF(MINUTE, GETDATE(), GETUTCDATE());
|
||||
SET @StartTime = DATEADD(MINUTE, @Offset, @StartTime);
|
||||
SET @EndTime = DATEADD(MINUTE, @Offset, @EndTime);
|
||||
|
||||
|
||||
DECLARE @target_data xml;
|
||||
SELECT @target_data = CONVERT(xml, target_data)
|
||||
FROM sys.dm_xe_database_sessions AS s
|
||||
JOIN sys.dm_xe_database_session_targets AS t
|
||||
ON t.event_session_address = s.address
|
||||
WHERE s.name = @ExtendedEventsSessionName
|
||||
AND t.target_name = N'ring_buffer';
|
||||
|
||||
|
||||
;WITH src AS
|
||||
(
|
||||
SELECT xeXML = xm.s.query('.')
|
||||
FROM @target_data.nodes('/RingBufferTarget/event') AS xm(s)
|
||||
)
|
||||
INSERT INTO #xmlResults (xeXML, xeTimeStamp)
|
||||
SELECT src.xeXML
|
||||
, [xeTimeStamp] = src.xeXML.value('(/event/@timestamp)[1]', 'datetimeoffset(7)')
|
||||
FROM src;
|
||||
|
||||
DECLARE @xe xml;
|
||||
|
||||
SELECT * FROM (
|
||||
SELECT
|
||||
[TimeStamp] = CONVERT(varchar(30), DATEADD(MINUTE, 0 - @Offset, xr.xeTimeStamp), 120)
|
||||
, [Query] = xr.xeXML.query (N'/event/data[11]/value')
|
||||
FROM #xmlResults xr
|
||||
WHERE xr.xeTimeStamp >= @StartTime
|
||||
AND xr.xeTimeStamp<= @EndTime
|
||||
) AS [t]
|
||||
WHERE
|
||||
CONVERT(nvarchar(max), Query) LIKE '%Employees%'
|
||||
AND CONVERT(nvarchar(max), Query) LIKE '%SSN%'
|
||||
AND CONVERT(nvarchar(max), Query) NOT LIKE '%sp_describe_parameter_encryption%'
|
||||
AND CONVERT(nvarchar(max), Query) NOT LIKE '%COUNT%'
|
||||
ORDER BY [TimeStamp] DESC
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
version= 1.0;
|
||||
authorizationrules
|
||||
{
|
||||
[ type=="x-ms-sgx-is-debuggable", value==false ]
|
||||
&& [ type=="x-ms-sgx-product-id", value==4639 ]
|
||||
&& [ type=="x-ms-sgx-svn", value>= 0 ]
|
||||
&& [ type=="x-ms-sgx-mrsigner", value=="e31c9e505f37a58de09335075fc8591254313eb20bb1a27e5443cc450b6e33e5"]
|
||||
=> permit();
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
IF EXISTS (SELECT *
|
||||
FROM sys.database_event_sessions
|
||||
WHERE name = 'Demo')
|
||||
BEGIN
|
||||
DROP EVENT SESSION Demo
|
||||
ON Database;
|
||||
END
|
||||
go
|
||||
|
||||
CREATE EVENT SESSION [Demo] ON DATABASE
|
||||
ADD EVENT sqlserver.rpc_completed(SET collect_data_stream=(1),collect_statement=(1)
|
||||
ACTION(sqlserver.sql_text)
|
||||
WHERE ([sqlserver].[like_i_sql_unicode_string]([sqlserver].[sql_text],N'%SSN%')AND [package0].[not_equal_unicode_string]([statement],N'exec sp_reset_connection'))
|
||||
)
|
||||
ADD TARGET package0.ring_buffer
|
||||
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
|
||||
GO
|
||||
|
||||
--CREATE EVENT SESSION [Demo] ON DATABASE
|
||||
--ADD EVENT sqlserver.rpc_completed(SET collect_data_stream=(1),collect_statement=(1)
|
||||
-- WHERE ([sqlserver].[equal_i_sql_unicode_string]([sqlserver].[database_name],N'ContosoHR') AND [package0].[not_equal_unicode_string]([statement],N'exec sp_reset_connection')))
|
||||
--ADD TARGET package0.ring_buffer(SET max_memory=(4096))
|
||||
--WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=2 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=ON)
|
||||
--GO
|
||||
|
||||
|
||||
ALTER EVENT SESSION [Demo]
|
||||
ON DATABASE
|
||||
STATE = START; -- STOP;
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
/****** Object: Table [dbo].[Employees] Script Date: 4/7/2021 9:31:31 AM ******/
|
||||
SET ANSI_NULLS ON
|
||||
GO
|
||||
|
||||
SET QUOTED_IDENTIFIER ON
|
||||
GO
|
||||
|
||||
CREATE TABLE [dbo].[Employees](
|
||||
[EmployeeID] [int] IDENTITY(1,1) NOT NULL,
|
||||
[SSN] [char](11) NOT NULL,
|
||||
[FirstName] [nvarchar](50) NOT NULL,
|
||||
[LastName] [nvarchar](50) NOT NULL,
|
||||
[Salary] [money] NOT NULL,
|
||||
CONSTRAINT [PK_dbo.Employees] PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[EmployeeID] ASC
|
||||
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
GO
|
||||
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('795-73-9838', 'Catherine', 'Abel', 31692)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('990-00-6818', 'Kim', 'Abercrombie', 990)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('009-37-3952', 'Frances', 'Adams', 5684)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('708-44-3627', 'Jay', 'Adams', 55415)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('447-62-6279', 'Robert', 'Ahlering', 49744)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('872-78-4732', 'Stanley', 'Alan', 38584)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('898-79-8701', 'Paul', 'Alcorn', 11918)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('561-88-3757', 'Mary', 'Alexander', 17349)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('904-55-0991', 'Michelle', 'Alexander', 70796)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('293-95-6617', 'Marvin', 'Allen', 96956)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('260-99-4784', 'Oscar', 'Alpuerto', 18386)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('605-29-1370', 'Ramona', 'Antrim', 72548)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('731-35-9387', 'Thomas', 'Armstrong', 72180)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('854-76-1401', 'John', 'Arthur', 79054)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('775-20-2697', 'Chris', 'Ashton', 6011)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('117-79-5230', 'Teresa', 'Atkinson', 87089)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('607-41-3750', 'Stephen', 'Ayers', 72344)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('412-66-3694', 'James', 'Bailey', 33950)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('775-63-2547', 'Douglas', 'Baldwin', 89945)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('779-52-1722', 'Wayne', 'Banack', 73236)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('647-03-0271', 'Robert', 'Barker', 23861)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('353-98-6954', 'John', 'Beaver', 75812)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('817-89-8819', 'John', 'Beaver', 19047)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('611-82-6762', 'Edna', 'Benson', 59478)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('665-55-5653', 'Payton', 'Benson', 98459)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('947-37-8651', 'Robert', 'Bernacchi', 78183)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('071-31-7824', 'Robert', 'Bernacchi', 79399)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('610-55-3726', 'Matthias', 'Berndt', 20209)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('590-27-0856', 'Jimmy', 'Bischoff', 24730)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('008-73-9012', 'Mae', 'Black', 60057)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('137-23-1723', 'Donald', 'Blanton', 65301)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('969-53-6095', 'Michael', 'Blythe', 5635)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('222-42-8458', 'Gabriel', 'Bockenkamp', 41020)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('163-08-2988', 'Luis', 'Bonifaz', 85014)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('898-11-0280', 'Cory', 'Booth', 49351)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('432-52-2738', 'Randall', 'Boseman', 24063)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('018-29-9539', 'Cornelius', 'Brandon', 91513)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('472-36-9060', 'Richard', 'Bready', 26084)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('566-87-9214', 'Ted', 'Bremer', 95506)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('771-34-9714', 'Alan', 'Brewer', 35682)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('413-73-7072', 'Walter', 'Brian', 5198)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('497-65-6363', 'Christopher', 'Bright', 24216)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('450-26-2195', 'Willie', 'Brooks', 55078)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('052-78-7929', 'Jo', 'Brown', 17396)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('087-92-6356', 'Robert', 'Brown', 99872)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('048-71-8953', 'Steven', 'Brown', 88633)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('488-68-6075', 'Mary', 'Browning', 59229)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('819-63-3780', 'Michael', 'Brundage', 30996)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('599-61-7739', 'Shirley', 'Bruner', 35872)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('772-36-0661', 'June', 'Brunner', 84642)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('990-78-3760', 'Megan', 'Burke', 76800)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('103-38-5903', 'Karren', 'Burkhardt', 93306)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('146-43-8832', 'Linda', 'Burnett', 56479)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('448-72-5948', 'Jared', 'Bustamante', 7997)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('254-13-4819', 'Barbara', 'Calone', 28720)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('666-45-9926', 'Lindsey', 'Camacho', 11870)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('260-46-2402', 'Frank', 'Campbell', 87501)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('189-92-4702', 'Henry', 'Campen', 30494)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('718-12-8401', 'Chris', 'Cannon', 2324)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('918-66-9747', 'Jane', 'Carmichael', 22620)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('806-97-1958', 'Jovita', 'Carmody', 37601)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('482-61-8230', 'Rob', 'Caron', 16904)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('897-39-6229', 'Andy', 'Carothers', 40261)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('656-79-6279', 'Donna', 'Carreras', 78393)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('745-99-0161', 'Rosmarie', 'Carroll', 98109)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('216-16-4120', 'Raul', 'Casts', 41706)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('102-56-5530', 'Matthew', 'Cavallari', 75290)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('787-23-4125', 'Andrew', 'Cencini', 75121)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('424-55-1778', 'Stacey', 'Cereghino', 25456)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('572-19-0999', 'Forrest', 'Chandler', 49996)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('745-81-6513', 'Lee', 'Chapla', 70991)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('947-66-5585', 'Yao-Qiang', 'Cheng', 72455)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('531-83-4784', 'Nicky', 'Chesnut', 13676)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('109-99-0299', 'Ruth', 'Choin', 55818)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('483-85-6853', 'Anthony', 'Chor', 71421)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('567-39-1024', 'Pei', 'Chow', 57284)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('382-49-7387', 'Jill', 'Christie', 94767)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('336-03-8102', 'Alice', 'Clark', 47963)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('994-22-9926', 'Connie', 'Coffman', 32136)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('129-28-7723', 'John', 'Colon', 82858)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('347-44-2949', 'Scott', 'Colvin', 1121)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('706-66-0382', 'Scott', 'Cooper', 22281)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('500-63-2220', 'Eva', 'Corets', 34410)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('942-15-7859', 'Marlin', 'Coriell', 43154)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('143-78-9971', 'Jack', 'Creasey', 66527)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('372-18-7905', 'Grant', 'Culbertson', 69903)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('153-33-1155', 'Scott', 'Culp', 87717)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('790-69-5423', 'Megan', 'Davis', 69707)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('105-16-8373', 'Alvaro', 'De Matos Miranda Filho', 15198)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('989-18-3523', 'Aidan', 'Delaney', 86115)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('771-07-7325', 'Stefan', 'Delmarco', 50994)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('545-83-9747', 'Prashanth', 'Desai', 97968)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('994-72-1605', 'Bev', 'Desalvo', 76954)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('558-23-5595', 'Brenda', 'Diaz', 4027)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('752-63-1338', 'Blaine', 'Dockter', 12312)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('825-10-8923', 'Cindy', 'Dodd', 82876)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('368-69-8964', 'Patricia', 'Doyle', 97282)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('597-44-1424', 'Gerald', 'Drury', 20153)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('957-28-1545', 'Bart', 'Duncan', 89903)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('187-17-8616', 'Maciej', 'Dusza', 6725)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('194-76-9481', 'Carol', 'Elliott', 49287)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('679-79-8165', 'Shannon', 'Elliott', 94194)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('367-73-8845', 'John', 'Emory', 65560)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('814-03-3691', 'Gail', 'Erickson', 99845)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('214-28-9968', 'Mark', 'Erickson', 95242)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('913-55-6645', 'Ann', 'Evans', 48046)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('763-33-5650', 'John', 'Evans', 59254)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('658-41-8532', 'Twanna', 'Evans', 35364)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('943-41-6011', 'Carolyn', 'Farino', 76201)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('691-30-8623', 'Geri', 'Farrell', 39600)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('361-08-3217', 'François', 'Ferrier', 3704)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('827-51-1487', 'Kathie', 'Flood', 78467)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('483-93-0057', 'John', 'Ford', 77552)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('738-37-1607', 'Garth', 'Fort', 34381)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('822-59-9384', 'Dorothy', 'Fox', 32679)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('309-79-2521', 'Mihail', 'Frintu', 52898)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('814-32-0421', 'Paul', 'Fulton', 1320)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('076-35-8143', 'Michael', 'Galos', 24061)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('620-03-4764', 'Jon', 'Ganio', 70002)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('769-76-3600', 'Dominic', 'Gash', 89479)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('160-92-3129', 'Janet', 'Gates', 49178)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('318-00-6667', 'Janet', 'Gates', 68327)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('982-77-3975', 'Orlando', 'Gee', 53281)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('328-68-1544', 'Darren', 'Gehring', 13353)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('053-51-9173', 'Jim', 'Geist', 91180)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('840-05-6646', 'Guy', 'Gilbert', 3780)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('446-11-2924', 'Janet', 'Gilliat', 89588)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('273-16-2522', 'Mary', 'Gimmi', 53352)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('003-23-9305', 'Jeanie', 'Glenn', 49086)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('878-44-1968', 'Scott', 'Gode', 2744)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('910-05-4138', 'Mete', 'Goktepe', 89053)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('912-33-3174', 'Abigail', 'Gonzalez', 56550)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('058-26-3234', 'Michael', 'Graff', 41144)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('687-28-3396', 'Douglas', 'Groncki', 22262)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('496-75-4904', 'Brian', 'Groth', 35712)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('071-00-8057', 'Erin', 'Hagens', 48197)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('288-05-9705', 'Betty', 'Haines', 6286)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('002-47-6040', 'Jean', 'Handley', 22940)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('936-84-1664', 'Kerim', 'Hanif', 80093)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('216-03-0835', 'John', 'Hanson', 10237)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('525-81-0810', 'Lucy', 'Harrington', 69388)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('331-25-9319', 'Keith', 'Harris', 7729)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('770-01-5105', 'Keith', 'Harris', 67336)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('208-84-9956', 'Roger', 'Harui', 78271)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('633-34-5095', 'Ann', 'Hass', 62689)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('022-89-0200', 'Valerie', 'Hendricks', 10269)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('912-85-8027', 'Cheryl', 'Herring', 95103)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('307-29-4403', 'Ronald', 'Heymsfield', 30421)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('083-68-5072', 'Mike', 'Hines', 35109)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('239-20-6174', 'Matthew', 'Hink', 75140)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('162-43-8489', 'Bob', 'Hodges', 84875)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('717-37-3032', 'David', 'Hodgson', 15920)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('280-15-5623', 'Helge', 'Hoeing', 23680)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('353-00-9496', 'Juanita', 'Holman', 83632)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('162-65-6542', 'Peter', 'Houston', 6335)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('427-43-7296', 'George', 'Huckaby', 90908)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('603-61-0319', 'Joshua', 'Huff', 55166)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('877-01-3415', 'Phyllis', 'Huntsman', 58528)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('391-25-8382', 'Phyllis', 'Huntsman', 86920)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('626-56-2930', 'Lawrence', 'Hurkett', 11698)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('731-19-3470', 'Lucio', 'Iallo', 83202)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('171-33-3481', 'Richard', 'Irwin', 83990)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('828-77-1376', 'Erik', 'Ismert', 7706)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('611-48-4137', 'Eric', 'Jacobsen', 784)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('477-14-7161', 'Jodan', 'Jacobson', 17695)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('738-83-2602', 'Sean', 'Jacobson', 9412)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('589-30-3617', 'Joyce', 'Jarvis', 42556)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('538-28-5108', 'Barry', 'Johnson', 36190)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('661-09-8547', 'Barry', 'Johnson', 80820)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('025-55-7602', 'Brian', 'Johnson', 54767)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('422-34-6020', 'David', 'Johnson', 26695)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('500-92-8728', 'Tom', 'Johnston', 52805)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('170-89-3691', 'Jean', 'Jordan', 68936)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('108-25-0733', 'Peggy', 'Justice', 39764)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('392-44-2253', 'Sandeep', 'Kaliyath', 84549)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('666-10-8497', 'Sandeep', 'Katyal', 27585)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('738-29-5963', 'John', 'Kelly', 31491)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('253-47-6467', 'Robert', 'Kelly', 43239)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('059-47-6363', 'Kevin', 'Kennedy', 18192)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('382-51-9530', 'Mitch', 'Kennedy', 68959)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('480-79-4419', 'Imtiaz', 'Khan', 66870)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('097-39-6667', 'Karan', 'Khanna', 17048)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('625-86-1609', 'Anton', 'Kirilov', 97398)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('109-78-5455', 'Christian', 'Kleinerman', 22492)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('914-28-0431', 'Andrew', 'Kobylinski', 47853)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('428-15-1588', 'Eugene', 'Kogan', 61377)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('612-70-0567', 'Scott', 'Konersmann', 87060)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('025-76-2628', 'Joy', 'Koski', 165)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('920-75-2262', 'Diane', 'Krane', 12316)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('748-12-0172', 'Kay', 'Krane', 13614)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('230-78-1884', 'Kay', 'Krane', 98499)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('121-03-7961', 'Margaret', 'Krupka', 98845)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('993-16-0574', 'Peter', 'Kurniawan', 67823)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('560-17-8321', 'Jeffrey', 'Kurtz', 18840)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('176-23-2126', 'Eric', 'Lang', 39005)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('678-53-5154', 'Elsa', 'Leavitt', 71752)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('950-17-4726', 'Marjorie', 'Lee', 28116)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('649-28-8360', 'Roger', 'Lengel', 75588)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('507-95-7549', 'A.', 'Leonetti', 71639)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('442-99-4943', 'Bonnie', 'Lepro', 9089)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('674-71-8512', 'Elsie', 'Lewin', 93630)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('418-20-4458', 'George', 'Li', 74540)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('986-20-3872', 'Joseph', 'Lique', 96968)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('716-41-6291', 'Paulo', 'Lisboa', 11243)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('475-64-2482', 'Paulo', 'Lisboa', 84392)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('471-03-3608', 'David', 'Liu', 57309)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('440-49-4765', 'Jinghao', 'Liu', 34991)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('321-33-7277', 'Kevin', 'Liu', 20305)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('113-69-0506', 'Sharon', 'Looney', 5368)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('311-21-1551', 'Judy', 'Lundahl', 15667)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('710-73-5330', 'Denise', 'Maccietto', 2258)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('321-14-1319', 'Scott', 'MacDonald', 30158)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('340-75-5874', 'Kathy', 'Marcovecchio', 10228)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('043-85-0648', 'Melissa', 'Marple', 46100)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('253-33-7509', 'Frank', 'Mart¡nez', 46267)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('335-68-4629', 'Chris', 'Maxwell', 92921)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('535-30-6577', 'Sandra', 'Maynard', 60264)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('613-34-9127', 'Walter', 'Mays', 70620)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('754-70-9484', 'Lola', 'McCarthy', 75175)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('758-46-9282', 'Jane', 'McCarty', 78021)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('287-44-2853', 'Yvonne', 'McKay', 38787)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('173-12-0893', 'Nkenge', 'McLin', 27222)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('028-18-1290', 'R. Morgan', 'Mendoza', 80464)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('035-47-1686', 'Helen', 'Meyer', 79306)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('926-47-4349', 'Dylan', 'Miller', 64819)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('947-84-3762', 'Frank', 'Miller', 97091)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('598-00-4792', 'Virginia', 'Miller', 77286)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('069-59-6908', 'Virginia', 'Miller', 57881)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('864-49-8796', 'Neva', 'Mitchell', 36848)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('484-78-0561', 'Joseph', 'Mitzner', 42987)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('684-27-6433', 'Margaret', 'Smith', 46020)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('521-85-5433', 'Laura', 'Steele', 87969)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('239-08-6212', 'Alan', 'Steiner', 71635)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('655-64-2836', 'Alice', 'Steiner', 60544)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('850-56-7206', 'Derik', 'Stenerson', 16798)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('077-42-9130', 'Vassar', 'Stern', 55399)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('094-90-4314', 'Wathalee', 'Steuber', 20296)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('409-83-6433', 'Liza Marie', 'Stevens', 6631)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('351-34-7304', 'Robert', 'Stotka', 88774)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('866-96-8557', 'Kayla', 'Stotler', 19835)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('716-37-0786', 'Ruth', 'Suffin', 38058)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('689-86-1583', 'Elizabeth', 'Sullivan', 98566)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('622-25-6018', 'Michael', 'Sullivan', 9242)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('137-21-0253', 'Brad', 'Sutton', 44883)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('237-99-8262', 'Abraham', 'Swearengin', 85958)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('518-41-6271', 'Julie', 'Taft-Rider', 63622)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('554-31-5202', 'Clarence', 'Tatman', 25188)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('591-44-7136', 'Chad', 'Tedford', 22306)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('069-09-3831', 'Vanessa', 'Tench', 44398)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('523-93-8801', 'Judy', 'Thames', 89067)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('266-03-4963', 'Daniel', 'Thompson', 36910)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('496-54-0726', 'Donald', 'Thompson', 85206)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('984-43-6756', 'Kendra', 'Thompson', 7375)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('047-31-4129', 'Diane', 'Tibbott', 95073)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('217-20-9777', 'Delia', 'Toone', 17369)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('420-28-0429', 'Michael John', 'Troyer', 69381)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('236-75-2355', 'Christie', 'Trujillo', 79299)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('984-20-5166', 'Sairaj', 'Uddin', 41036)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('353-75-0098', 'Sunil', 'Uppal', 23245)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('934-96-8406', 'Jessie', 'Valerio', 62357)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('773-23-3159', 'Gregory', 'Vanderbout', 21434)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('951-08-3331', 'Michael', 'Vanderhyde', 72246)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('856-23-4990', 'Margaret', 'Vanderkamp', 18918)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('359-67-5826', 'Gary', 'Vargas', 37729)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('743-66-8203', 'Nieves', 'Vargas', 61754)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('368-97-5673', 'Ranjit', 'Varkey Chudukatil', 19423)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('890-04-1424', 'Patricia', 'Vasquez', 59489)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('267-37-1036', 'Wanda', 'Vernon', 11749)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('101-14-5907', 'Robert', 'Vessa', 58459)
|
||||
INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES ('148-51-2717', 'Caroline', 'Vicknair', 83361)
|
||||
@@ -1,231 +0,0 @@
|
||||
///////////////////////
|
||||
// Define parameters //
|
||||
///////////////////////
|
||||
|
||||
@description('The project name. The names of all resources will be derived from the project name.')
|
||||
param projectName string
|
||||
|
||||
@description('The object id of the user running the deployment.')
|
||||
param userObjectId string
|
||||
|
||||
@description('The username of the user running the deployment.')
|
||||
param userName string
|
||||
|
||||
@description('The username of the Azure SQL database server administrator for SQL authentication.')
|
||||
param sqlAdminUserName string
|
||||
|
||||
@description('The password of the Azure SQL database server administrator for SQL authentication.')
|
||||
param sqlAdminPassword string
|
||||
|
||||
@description('The IP address the user will connect from to the logical server in Azure SQL Database.')
|
||||
param clientIP string
|
||||
|
||||
@description('The location (the Azure region) for all resources.')
|
||||
param location string = resourceGroup().location
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Create and configure a logical server //
|
||||
////////////////////////////////////////////
|
||||
|
||||
// Create the server
|
||||
var SQLServerName_var = '${projectName}server'
|
||||
resource Server_Name_resource 'Microsoft.Sql/servers@2019-06-01-preview' = {
|
||||
name: SQLServerName_var
|
||||
location: location
|
||||
tags: {}
|
||||
identity: {
|
||||
type: 'SystemAssigned'
|
||||
}
|
||||
properties: {
|
||||
administratorLogin: sqlAdminUserName
|
||||
administratorLoginPassword: sqlAdminPassword
|
||||
//version: 'string' //optional
|
||||
minimalTlsVersion: '1.2'
|
||||
publicNetworkAccess: 'Enabled'
|
||||
}
|
||||
}
|
||||
|
||||
// Allow Azure services and resources to access this server
|
||||
resource Server_Name_AllowAllWindowsAzureIps 'Microsoft.Sql/servers/firewallRules@2015-05-01-preview' = {
|
||||
name: '${Server_Name_resource.name}/AllowAllWindowsAzureIps'
|
||||
properties: {
|
||||
endIpAddress: '0.0.0.0'
|
||||
startIpAddress: '0.0.0.0'
|
||||
}
|
||||
}
|
||||
|
||||
// Allow Client IP to access this server
|
||||
resource Server_Name_AllowClientIP 'Microsoft.Sql/servers/firewallRules@2015-05-01-preview' = {
|
||||
name: '${Server_Name_resource.name}/AllowClientIP'
|
||||
properties: {
|
||||
endIpAddress: clientIP
|
||||
startIpAddress: clientIP
|
||||
}
|
||||
}
|
||||
|
||||
// Make the user an Azure AD administrator for the server, so that the user can connect with universal authentication
|
||||
resource Server_Name_activeDirectory 'Microsoft.Sql/servers/administrators@2019-06-01-preview' = {
|
||||
name: '${Server_Name_resource.name}/activeDirectory'
|
||||
properties: {
|
||||
administratorType: 'ActiveDirectory'
|
||||
login: userName
|
||||
//sid: reference(resourceId('Microsoft.Sql/servers', '${projectName}server'), '2019-06-01-preview', 'Full').identity.principalId
|
||||
sid: userObjectId
|
||||
//tenantId: AAD_TenantId //optional
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Create the ContosoHR database using the DC-series hardware configuration //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
resource Database_Resource 'Microsoft.Sql/servers/databases@2020-08-01-preview' = {
|
||||
name: '${Server_Name_resource.name}/ContosoHR'
|
||||
location: location
|
||||
tags: {}
|
||||
sku: {
|
||||
name: 'GP_DC_2'
|
||||
tier: 'GeneralPurpose'
|
||||
}
|
||||
properties: {}
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// Configure an attestation provider //
|
||||
///////////////////////////////////////
|
||||
|
||||
// Create the attestation provider
|
||||
resource attestationProviderName_resource 'Microsoft.Attestation/attestationProviders@2020-10-01' = {
|
||||
name: '${projectName}attest'
|
||||
location: location
|
||||
properties: {}
|
||||
}
|
||||
|
||||
///////////////////////////////////
|
||||
// Configure the web application //
|
||||
///////////////////////////////////
|
||||
|
||||
// Create an App Service plan
|
||||
resource WebAppServicePlan_Resource 'Microsoft.Web/serverfarms@2021-01-01' = {
|
||||
name: '${projectName}plan'
|
||||
location: location
|
||||
properties: {}
|
||||
sku: {
|
||||
name: 'B1'
|
||||
}
|
||||
}
|
||||
|
||||
// Create the App Service
|
||||
resource WebApp_Resource 'Microsoft.Web/sites@2021-01-01' = {
|
||||
name: '${projectName}app'
|
||||
location: location
|
||||
identity: {
|
||||
type: 'SystemAssigned'
|
||||
}
|
||||
properties: {
|
||||
serverFarmId: WebAppServicePlan_Resource.id
|
||||
}
|
||||
|
||||
//Set the database connection string for the application
|
||||
resource WebAppConnectionString_Resource 'config' = {
|
||||
name: 'connectionstrings'
|
||||
properties: {
|
||||
ContosoHRDatabase: {
|
||||
value: 'Server=tcp:${Server_Name_resource.name}.database.windows.net;Database=ContosoHR;Column Encryption Setting=Enabled; Attestation Protocol = AAS; Enclave Attestation Url=${attestationProviderName_resource.properties.attestUri}; Authentication=Active Directory Managed Identity'
|
||||
type: 'SQLAzure'
|
||||
}
|
||||
}
|
||||
}
|
||||
//Define AppSetting to fetch the correct project from the GitHub Repository
|
||||
resource AppSetting 'config' = {
|
||||
name: 'appsettings'
|
||||
properties: {
|
||||
PROJECT: 'samples/features/security/contoso-hr-sql-db/source/ContosoHR/ContosoHR.csproj'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deploy the application
|
||||
resource sourceControl 'Microsoft.Web/sites/sourcecontrols@2021-01-01' = {
|
||||
name: '${projectName}app/web'
|
||||
properties: {
|
||||
repoUrl: 'https://github.com/Pietervanhove/sql-server-samples.git'
|
||||
branch: 'AESQLDBWithEnclavesDemo'
|
||||
isManualIntegration: true
|
||||
}
|
||||
dependsOn: [
|
||||
Server_Name_resource
|
||||
]
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
// Create and configure a key vault //
|
||||
//////////////////////////////////////
|
||||
|
||||
// Create a key vault and assign key permissions to the user, so that the user can manage the keys
|
||||
resource KeyVault_Resource 'Microsoft.KeyVault/vaults@2019-09-01' = {
|
||||
name: '${projectName}vault'
|
||||
location: location
|
||||
tags: {}
|
||||
properties: {
|
||||
tenantId: subscription().tenantId
|
||||
sku: {
|
||||
family: 'A'
|
||||
name: 'standard'
|
||||
}
|
||||
accessPolicies: [
|
||||
{
|
||||
tenantId: subscription().tenantId
|
||||
objectId: userObjectId
|
||||
permissions: {
|
||||
keys: [
|
||||
'unwrapKey'
|
||||
'wrapKey'
|
||||
'verify'
|
||||
'sign'
|
||||
'get'
|
||||
'list'
|
||||
'create'
|
||||
'delete'
|
||||
'purge'
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// Assign key permissions to the web app
|
||||
resource KeyVaultWebAppAccessPolicy_Resource 'Microsoft.KeyVault/vaults/accessPolicies@2019-09-01' = {
|
||||
name: any('${KeyVault_Resource.name}/add')
|
||||
properties: {
|
||||
accessPolicies: [
|
||||
{
|
||||
tenantId: subscription().tenantId
|
||||
// objectId: reference(resourceId('Microsoft.Web/sites', '${projectName}app'), '2020-12-01', 'Full').resourceId
|
||||
objectId: WebApp_Resource.identity.principalId
|
||||
permissions: {
|
||||
keys: [
|
||||
'unwrapKey'
|
||||
'verify'
|
||||
'get'
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// Create a key
|
||||
resource Key_Resource 'Microsoft.KeyVault/vaults/keys@2019-09-01' = {
|
||||
name: '${KeyVault_Resource.name}/CMK'
|
||||
tags: {}
|
||||
properties: {
|
||||
attributes: {
|
||||
enabled: true
|
||||
}
|
||||
kty: 'RSA'
|
||||
keySize: 4096
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
Import-Module "Az.Resources"
|
||||
|
||||
######################################################################
|
||||
# Prompt the user to enter the values of deployment parameters
|
||||
######################################################################
|
||||
|
||||
$resourceGroupName = Read-Host -Prompt "Enter the resource group name"
|
||||
$subscriptionId = Read-Host -Prompt "Enter your subscription id"
|
||||
|
||||
######################################################################
|
||||
# Sign in to Azure
|
||||
######################################################################
|
||||
|
||||
Connect-AzAccount
|
||||
$context = Set-AzContext -Subscription $subscriptionId
|
||||
|
||||
######################################################################
|
||||
# Delete the resource group and the key vault with purge proteciton on
|
||||
######################################################################
|
||||
|
||||
$location = (Get-AzResourceGroup -Name $resourceGroupName).Location
|
||||
Remove-AzResourceGroup -Name $resourceGroupName
|
||||
Remove-AzKeyVault -VaultName "${resourceGroupName}vault" -InRemovedState -Location $location
|
||||
@@ -1,165 +0,0 @@
|
||||
Import-Module "Az" -MinimumVersion "5.6"
|
||||
Import-Module "Az.Attestation" -MinimumVersion "0.1.8"
|
||||
Import-Module "SqlServer" -MinimumVersion "21.1.18235"
|
||||
|
||||
######################################################################
|
||||
# Prompt the user to enter the values of deployment parameters
|
||||
######################################################################
|
||||
|
||||
$projectName = Read-Host -Prompt "Enter a project name that is used to generate resource names"
|
||||
$subscriptionId = Read-Host -Prompt "Enter your subscription id"
|
||||
$location = Read-Host -Prompt "Enter a region where you want to deploy the demo environment"
|
||||
$sqlAdminUserName = Read-Host -Prompt "Enter the username of the Azure SQL database server administrator for SQL authentication"
|
||||
$sqlAdminPasswordSecureString = Read-Host -Prompt "Enter the password of the Azure SQL database server administrator for SQL authentication" -AsSecureString
|
||||
|
||||
$sqlAdminPassword = (New-Object PSCredential "user",$sqlAdminPasswordSecureString).GetNetworkCredential().Password
|
||||
$clientIP = (Invoke-WebRequest ifconfig.me/ip).Content.Trim()
|
||||
$bicepFile = "azuredeploy.bicep"
|
||||
$projectName = $projectName.ToLower()
|
||||
|
||||
######################################################################
|
||||
# Sign in to Azure
|
||||
######################################################################
|
||||
|
||||
Connect-AzAccount
|
||||
$context = Set-AzContext -Subscription $subscriptionId
|
||||
$userName = $context.Account.Id
|
||||
$userObjectId = $(Get-AzADUser -UserPrincipalName $userName).Id
|
||||
|
||||
######################################################################
|
||||
# Create a resource group
|
||||
######################################################################
|
||||
$resourceGroupName = "${projectName}"
|
||||
New-AzResourceGroup -Name $resourceGroupName -Location $location
|
||||
|
||||
######################################################################
|
||||
# Deploy the resources for the demo environment
|
||||
######################################################################
|
||||
#az deployment group create --name DeployAEWithEnclavesDemo --template-file $bicepFile --resource-group $resourceGroupName --parameters `
|
||||
#projectName=$projectName `
|
||||
#userObjectId=$userObjectId `
|
||||
#userName=$userName `
|
||||
#sqlAdminUserName=$sqlAdminUserName `
|
||||
#sqlAdminPassword=$sqlAdminPassword `
|
||||
#clientIP=$clientIP
|
||||
|
||||
New-AzResourceGroupDeployment `
|
||||
-ResourceGroupName $resourceGroupName `
|
||||
-TemplateFile $bicepFile `
|
||||
-projectName $projectName `
|
||||
-userObjectId $userObjectId `
|
||||
-userName $userName `
|
||||
-sqlAdminUserName $sqlAdminUserName `
|
||||
-sqlAdminPassword $sqlAdminPassword `
|
||||
-clientIP $clientIP
|
||||
|
||||
######################################################################
|
||||
# Populate the database with data
|
||||
######################################################################
|
||||
|
||||
$serverName = "${projectName}server.database.windows.net"
|
||||
$databaseName = "ContosoHR"
|
||||
$queryFile = "PopulateDatabase.sql"
|
||||
$query = Get-Content -path $queryFile -Raw
|
||||
$accessToken = (Get-AzAccessToken -ResourceUrl https://database.windows.net).Token
|
||||
Invoke-Sqlcmd -ServerInstance "tcp:$serverName" -Database $databaseName -AccessToken $accessToken -QueryTimeout 30 -Query $query
|
||||
|
||||
######################################################################
|
||||
# Configure an extended event session to intercept application queries
|
||||
######################################################################
|
||||
|
||||
$queryFile = "CreateXESession.sql"
|
||||
$query = Get-Content -path $queryFile -Raw
|
||||
$accessToken = (Get-AzAccessToken -ResourceUrl https://database.windows.net).Token
|
||||
Invoke-Sqlcmd -ServerInstance "tcp:$serverName" -Database $databaseName -AccessToken $accessToken -QueryTimeout 30 -Query $query
|
||||
|
||||
######################################################################
|
||||
# Grant the web application access to the database
|
||||
######################################################################
|
||||
|
||||
# Create a shadow principal, representing the application, in the database
|
||||
$appName = "${projectName}app"
|
||||
$query = "CREATE USER [$appName] FROM EXTERNAL PROVIDER;"
|
||||
$accessToken = (Get-AzAccessToken -ResourceUrl https://database.windows.net).Token
|
||||
Invoke-Sqlcmd -ServerInstance "tcp:$ServerName" -Database $databaseName -AccessToken $accessToken -QueryTimeout 30 -Query $query
|
||||
|
||||
# Grant the application read access to the database.
|
||||
$query = "EXEC sp_addrolemember 'db_datareader', '$appName';"
|
||||
$accessToken = (Get-AzAccessToken -ResourceUrl https://database.windows.net).Token
|
||||
Invoke-Sqlcmd -ServerInstance "tcp:$serverName" -Database $databaseName -AccessToken $accessToken -QueryTimeout 30 -Query $query
|
||||
|
||||
# Grant the application write access to the database.
|
||||
$query = "EXEC sp_addrolemember 'db_datawriter', '$appName';"
|
||||
$accessToken = (Get-AzAccessToken -ResourceUrl https://database.windows.net).Token
|
||||
Invoke-Sqlcmd -ServerInstance "tcp:$serverName" -Database $databaseName -AccessToken $accessToken -QueryTimeout 30 -Query $query
|
||||
|
||||
# Grant the application access to the key metadata database.
|
||||
$query = "GRANT VIEW ANY COLUMN MASTER KEY DEFINITION TO [$appName];"
|
||||
$accessToken = (Get-AzAccessToken -ResourceUrl https://database.windows.net).Token
|
||||
Invoke-Sqlcmd -ServerInstance "tcp:$serverName" -Database $databaseName -AccessToken $accessToken -QueryTimeout 30 -Query $query
|
||||
|
||||
# Grant the application access to the key metadata database.
|
||||
$query = "GRANT VIEW ANY COLUMN ENCRYPTION KEY DEFINITION TO [$appName];"
|
||||
$accessToken = (Get-AzAccessToken -ResourceUrl https://database.windows.net).Token
|
||||
Invoke-Sqlcmd -ServerInstance "tcp:$serverName" -Database $databaseName -AccessToken $accessToken -QueryTimeout 30 -Query $query
|
||||
|
||||
######################################################################
|
||||
# Configure key metadata in the database
|
||||
######################################################################
|
||||
|
||||
# Get the column master key from Azure Key Vault
|
||||
$keyVaultName = "${projectName}vault"
|
||||
$keyName = "CMK"
|
||||
$key = Get-AzKeyVaultKey -VaultName $keyVaultName -Name $keyName
|
||||
|
||||
# Connect to the database using the SqlServer PowerShell module
|
||||
$connStr = "Data Source=tcp:$serverName;Initial Catalog=$databaseName;User ID=$sqlAdminUserName;Password=$sqlAdminPassword"
|
||||
$database = Get-SqlDatabase -ConnectionString $connStr
|
||||
|
||||
# Sign in to Azure with your email address using the SqlServer PowerShell module
|
||||
Add-SqlAzureAuthenticationContext -Interactive
|
||||
|
||||
# Create a column master key metadata object in the database for the key in Azure Key Vault
|
||||
$cmkName = "CMK1"
|
||||
$cmkSettings = New-SqlAzureKeyVaultColumnMasterKeySettings -KeyURL $key.Key.Kid -AllowEnclaveComputations
|
||||
New-SqlColumnMasterKey -Name $cmkName -InputObject $database -ColumnMasterKeySettings $cmkSettings
|
||||
|
||||
# Create a column encryption key and its metadata object in the database
|
||||
$cekName = "CEK1"
|
||||
New-SqlColumnEncryptionKey -Name $cekName -InputObject $database -ColumnMasterKey $cmkName
|
||||
|
||||
######################################################################
|
||||
# Encrypt database columns
|
||||
######################################################################
|
||||
|
||||
$encryptedColumnSettings = @()
|
||||
$encryptedColumnSettings += New-SqlColumnEncryptionSettings -ColumnName "dbo.Employees.SSN" -EncryptionType "Randomized" -EncryptionKey $cekName
|
||||
$encryptedColumnSettings += New-SqlColumnEncryptionSettings -ColumnName "dbo.Employees.Salary" -EncryptionType "Randomized" -EncryptionKey $cekName
|
||||
Set-SqlColumnEncryption -ColumnEncryptionSettings $encryptedColumnSettings -InputObject $database -LogFileDirectory .
|
||||
|
||||
######################################################################
|
||||
# Configure the attestation policy
|
||||
######################################################################
|
||||
|
||||
$resourceGroupName = "${projectName}"
|
||||
$attestationProviderName = "${projectName}attest"
|
||||
$policyFile = "AttestationPolicy.txt"
|
||||
$teeType = "SgxEnclave"
|
||||
$policyFormat = "Text"
|
||||
$policy=Get-Content -path $policyFile -Raw
|
||||
Set-AzAttestationPolicy -Name $attestationProviderName -ResourceGroupName $resourceGroupName -Tee $teeType -Policy $policy -PolicyFormat $policyFormat
|
||||
|
||||
# Get the attestation URL
|
||||
$attestationProvider = Get-AzAttestation -Name $attestationProviderName -ResourceGroupName $resourceGroupName
|
||||
$attestationUrl = $attestationProvider.AttestUri
|
||||
|
||||
######################################################################
|
||||
# Print parameters for the demo
|
||||
######################################################################
|
||||
|
||||
$app = Get-AzWebApp -Name $appName -ResourceGroupName $resourceGroupName
|
||||
Write-Host -ForegroundColor "green" "Resource group name: $resourceGroupName"
|
||||
Write-Host -ForegroundColor "green" "Database server name: $serverName"
|
||||
Write-Host -ForegroundColor "green" "Database name: $databaseName"
|
||||
Write-Host -ForegroundColor "green" "Attestation URL: $attestationUrl"
|
||||
Write-Host -ForegroundColor "green" "Application URL: https://$($app.HostNames[0].ToString())"
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30907.101
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContosoHR", "ContosoHR\ContosoHR.csproj", "{91C0C152-3656-4460-8C0C-DAE0505E26FC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{91C0C152-3656-4460-8C0C-DAE0505E26FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{91C0C152-3656-4460-8C0C-DAE0505E26FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{91C0C152-3656-4460-8C0C-DAE0505E26FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{91C0C152-3656-4460-8C0C-DAE0505E26FC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {09B03C29-04E6-4C93-9C58-C16B6A907DAE}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<UserSecretsId>54e8ce16-db31-4c81-a83f-e7f742cb59d9</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.Identity" Version="1.4.0" />
|
||||
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.6.1" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="3.0.0" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider" Version="3.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.7" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.7">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.7" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.7">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="5.2.9" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.2" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.2.10" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,18 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ContosoHR.Models
|
||||
{
|
||||
public partial class ContosoHRContext : DbContext
|
||||
{
|
||||
public ContosoHRContext(DbContextOptions<ContosoHRContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual DbSet<Employee> Employees { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ContosoHR.Models;
|
||||
|
||||
namespace ContosoHR.Pages.Employees
|
||||
{
|
||||
public class EditModel : PageModel
|
||||
{
|
||||
private readonly ContosoHR.Models.ContosoHRContext _context;
|
||||
|
||||
public EditModel(ContosoHR.Models.ContosoHRContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
[BindProperty]
|
||||
public Employee Employee { get; set; }
|
||||
|
||||
public async Task<IActionResult> OnGetAsync(int? id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
Employee = await _context.Employees.FirstOrDefaultAsync(m => m.EmployeeId == id);
|
||||
|
||||
if (Employee == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
return Page();
|
||||
}
|
||||
|
||||
// To protect from overposting attacks, enable the specific properties you want to bind to.
|
||||
// For more details, see https://aka.ms/RazorPagesCRUD.
|
||||
public async Task<IActionResult> OnPostAsync()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return Page();
|
||||
}
|
||||
|
||||
_context.Attach(Employee).State = EntityState.Modified;
|
||||
|
||||
try
|
||||
{
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
if (!EmployeeExists(Employee.EmployeeId))
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return RedirectToPage("./Index");
|
||||
}
|
||||
|
||||
private bool EmployeeExists(int id)
|
||||
{
|
||||
return _context.Employees.Any(e => e.EmployeeId == id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
@page
|
||||
@model ContosoHR.Pages.Employees.IndexModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Index";
|
||||
}
|
||||
|
||||
<h1>Index</h1>
|
||||
|
||||
<p>
|
||||
<a asp-page="Create">Create New</a>
|
||||
</p>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
@Html.DisplayNameFor(model => model.Employee[0].Ssn)
|
||||
</th>
|
||||
<th>
|
||||
@Html.DisplayNameFor(model => model.Employee[0].FirstName)
|
||||
</th>
|
||||
<th>
|
||||
@Html.DisplayNameFor(model => model.Employee[0].LastName)
|
||||
</th>
|
||||
<th>
|
||||
@Html.DisplayNameFor(model => model.Employee[0].Salary)
|
||||
</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model.Employee) {
|
||||
<tr>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Ssn)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.FirstName)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.LastName)
|
||||
</td>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Salary)
|
||||
</td>
|
||||
<td>
|
||||
<a asp-page="./Edit" asp-route-id="@item.EmployeeId">Edit</a> |
|
||||
<a asp-page="./Details" asp-route-id="@item.EmployeeId">Details</a> |
|
||||
<a asp-page="./Delete" asp-route-id="@item.EmployeeId">Delete</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ContosoHR.Models;
|
||||
|
||||
namespace ContosoHR.Pages.Employees
|
||||
{
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
private readonly ContosoHR.Models.ContosoHRContext _context;
|
||||
|
||||
public IndexModel(ContosoHR.Models.ContosoHRContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public IList<Employee> Employee { get;set; }
|
||||
|
||||
public async Task OnGetAsync()
|
||||
{
|
||||
Employee = await _context.Employees.ToListAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - Contoso HR</title>
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" asp-area="" asp-page="/Index">Contoso HR</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
|
||||
<ul class="navbar-nav flex-grow-1">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-dark" asp-area="" asp-page="/Employees/Index">Employees</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<div class="container">
|
||||
<main role="main" class="pb-3">
|
||||
@RenderBody()
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer class="border-top footer text-muted">
|
||||
<div class="container">
|
||||
© 2021 - Contoso HR - <a asp-area="" asp-page="/Privacy">Privacy</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
|
||||
@await RenderSectionAsync("Scripts", required: false)
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,95 +0,0 @@
|
||||
using ContosoHR.Models;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider;
|
||||
using Azure.Core;
|
||||
using Azure.Identity;
|
||||
|
||||
namespace ContosoHR
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
InitializeAzureKeyVaultProvider();
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
string s = Configuration.GetConnectionString("ContosoHRDatabase");
|
||||
services.AddDbContext<ContosoHRContext>(options =>
|
||||
options.UseSqlServer(Configuration.GetConnectionString("ContosoHRDatabase")));
|
||||
services.AddControllers();
|
||||
services.AddRazorPages();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Error");
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
endpoints.MapRazorPages();
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize the Azure Key Vault provider for Always Encrypted. Required if column master keys are stored in Azure Key Vault.
|
||||
private void InitializeAzureKeyVaultProvider()
|
||||
{
|
||||
TokenCredential tokenCredential = null;
|
||||
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(Configuration.GetConnectionString("ContosoHRDatabase"));
|
||||
if (builder.Authentication == SqlAuthenticationMethod.ActiveDirectoryManagedIdentity)
|
||||
{
|
||||
// If the application uses a managed identity to talk to Azure SQL Database, use the managed identity for Azure Key Vault too.
|
||||
tokenCredential = new ManagedIdentityCredential();
|
||||
}
|
||||
else {
|
||||
// Assume a managed identity is not available to the app. Instead, use a client id/secret to authenticate to Azure Key Vault.
|
||||
// Fetch client id, secret, tenant id from the configuration.
|
||||
// It is recommended you specify these parameters in secrets.json.
|
||||
// See https://docs.microsoft.com/aspnet/core/security/app-secrets?view=aspnetcore-5.0&tabs=windows on how store secrets in secrets.json.
|
||||
var clientId = Configuration["ClientId"];
|
||||
var secret = Configuration["Secret"];
|
||||
var tenantId = Configuration["TenantId"];
|
||||
tokenCredential = new ClientSecretCredential(tenantId, clientId, secret);
|
||||
}
|
||||
SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider =
|
||||
new SqlColumnEncryptionAzureKeyVaultProvider(tokenCredential);
|
||||
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(
|
||||
customProviders: new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>(capacity: 1, comparer: StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, sqlColumnEncryptionAzureKeyVaultProvider}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"ContosoHRDatabase": "Data Source=.;Initial Catalog=ContosoHR;Column Encryption Setting=Enabled;Attestation Protocol=HGS;Enclave Attestation Url=http://192.168.0.3/Attestation; Integrated Security=true"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||

|
||||
|
||||
# Ledger Azure SQL Database - Demo
|
||||
|
||||
The demo in this folder showcases the [ledger](https://docs.microsoft.com/en-us/azure/azure-sql/database/ledger-overview) feature in Azure SQL Database. The demo uses the Contoso HR web application.
|
||||
|
||||
## Content
|
||||
|
||||
[About this sample](#about-this-sample)
|
||||
[Before you begin](#before-you-begin)
|
||||
[Setup](#setup)
|
||||
[Demo - show the main benefits of the ledger feature](#Demo---show-the-main-benefits-of-the-ledger-feature)
|
||||
[Cleanup](#cleanup)
|
||||
|
||||
## About this sample
|
||||
|
||||
- **Applies to:** Azure SQL Database
|
||||
- **Key features:** Ledger
|
||||
- **Workload:** Human resources (HR) application
|
||||
- **Programming Language:** C#, Transact-SQL
|
||||
- **Authors:** Jakub Szymaszek, Pieter Vanhove
|
||||
- **Update history:**
|
||||
|
||||
## Before you begin
|
||||
|
||||
Before you begin, you need an Azure subscription. If you don't already have an Azure subscription, you can get one for free [here](https://azure.microsoft.com/free/).
|
||||
|
||||
You also need to make sure the following software is installed on your machine:
|
||||
|
||||
1. PowerShell modules:
|
||||
|
||||
1. Az version 7.1.0 or later. For details on how to install the Az PowerShell module, see [Install the Azure Az PowerShell module](https://docs.microsoft.com/powershell/azure/install-az-ps). To determine the version of the Az module installed on your machine, run the following command from a PowerShell session.
|
||||
|
||||
```powershell
|
||||
Get-InstalledModule -Name Az
|
||||
```
|
||||
|
||||
1. SqlServer version 21.1.18256 or later. For details on how to install the SqlServer PowerShell module, see [Installing or updating the SqlServer module](https://docs.microsoft.com/sql/powershell/download-sql-server-ps-module#installing-or-updating-the-sqlserver-module). To determine the version the SqlServer module installed on your machine, run the following command from a PowerShell session.
|
||||
|
||||
```powershell
|
||||
Get-InstalledModule -Name SqlServer
|
||||
```
|
||||
2. [Bicep](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep) version 0.4.1272 or later. You need to install Bicep and ensure it can be invoked from PowerShell. There are several ways to [install Bicep](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/install).
|
||||
3. [SQL Server Management Studio (SSMS)](https://msdn.microsoft.com/en-us/library/mt238290.aspx) - version 18.10 or later is recommended.
|
||||
|
||||
## Setup
|
||||
|
||||
By following the below setup steps, you will create a new resource group and deploy the following resources to your Azure subscription:
|
||||
|
||||
- A logical database server.
|
||||
- The **ContosoHR** database using General Purpose compute tier, 2 vCores, and the Gen5 hardware generation.
|
||||
- A storage account that will be used to store ledger digests.
|
||||
- The Contoso HR web application in Azure Web Apps.
|
||||
|
||||
### Setup steps
|
||||
|
||||
1. Clone/download and unpack the repository.
|
||||
1. Open a PowerShell session.
|
||||
1. In the PowerShell session, change the directory to the setup folder within this demo's directory. For example, if you've unpacked the downloaded repository on a Windows machine in **C:\\**, issue the following command:
|
||||
|
||||
```powershell
|
||||
cd "C:\sql-server-samples\samples\features\security\ledger\azure-sql-database\setup"
|
||||
```
|
||||
|
||||
1. Run the **setup.ps1** PowerShell script.
|
||||
1. When prompted, enter the following information:
|
||||
1. Your Azure subscription id. To determine your subscription id, see [Find your Azure subscription](https://docs.microsoft.com/azure/media-services/latest/setup-azure-subscription-how-to?tabs=portal).
|
||||
1. The project name. The resource group containing all your demo resources will have that name. The project name will also be used as a prefix for the names of all demo resources. Please use only lowercase letters and numbers for the project name and make sure it is unique.
|
||||
1. The location - an Azure region name of your choice. See [Find the Azure geography that meets your needs](https://azure.microsoft.com/en-us/global-infrastructure/geographies/#overview).
|
||||
1. The username and the password of the Azure SQL database server administrator. **Make sure you remember both the username and the password.** You will use it during the demo to match a fictitious attacker's name.
|
||||
1. When prompted, sign in to Azure.
|
||||
1. The script will deploy the demo environment, which may take a few minutes. If you want to monitor the deployment process, go to the [Azure Portal](https://portal.azure.com/) and open the resource group that is used for the demo environment. In the overview tab, click on the link next to **Deployments**.
|
||||
1. Finally, the script outputs the important information about your demo environment.
|
||||
- Database server name (`<project name>server.database.windows.net`)
|
||||
- Database name (`ContosoHR`)
|
||||
- Application URL (`https://<project name>app.azurewebsites.net/`)
|
||||
|
||||
Please copy and save the above information. You will need it for the demo steps.
|
||||
|
||||
## Demo - show the main benefits of the ledger feature
|
||||
### Scenario
|
||||
The HR department of Contoso is using a simple web application to manage the employee's salaries.
|
||||
In this demo you will use 3 different types of users:
|
||||
- Rachel, who works at the HR depermant.
|
||||
- Alice, who is an auditor.
|
||||
- Jay, the DBA of the company. He thinks he should earn more money for the type of work he's doing :)
|
||||
|
||||
Jay wants to maliciously increase his salary. Because he's the DBA of the Contoso database, he thinks he can perform updates in the Employees table without anyone noticing. Unfortunately for Jay, the Employees table is an updatable ledger table, which means his change, along with his identity and the timestamp, have been persisted in a tamper-evident ledger data structures.
|
||||
|
||||
### Prepare for the demo
|
||||
|
||||
Perform the below steps before you show the demo.
|
||||
|
||||
1. Connect to the database
|
||||
1. Start the SQL Server Management Studio.
|
||||
1. In the **Connect to Server** dialog:
|
||||
1. Enter your database server name. Set **Authentication** to **SQL Server Authentication**. Enter the admin username and the admin password.
|
||||
1. Click the **Options >>** button, select the **Connection Properties** tab and enter the database name (**ContosoHR**).
|
||||
|
||||

|
||||
|
||||
1. Click **Connect**.
|
||||
|
||||
1. Prepare a browser window for the HR user.
|
||||
1. Open your browser.
|
||||
1. Point the browser to the demo application URL.
|
||||
1. Log on as rachel@contoso.com. The password is: Password!1
|
||||
1. Leave the ContosoHR tab selected.
|
||||
|
||||
1. Prepare a web browser for the Auditor user.
|
||||
1. Open a new InPrivate browser window.
|
||||
1. Point the browser to the demo application URL.
|
||||
1. Log on as alice@contoso.com. The password is: Password!1
|
||||
1. You should now see 5 tabs. Leave the ContosoHR tab selected.
|
||||
|
||||
1. Open the demo queries in SSMS.
|
||||
1. In Object Explorer, find and select the **ContosoHR** database.
|
||||
|
||||

|
||||
|
||||
1. With the **ContosoHR** database selected, type Ctrl + O. In the **Open File** dialog, navigate to the **setup** folder and select **CreateDatabaseSchema.sql**. Do not execute the query.
|
||||
1. With the **ContosoHR** database selected, type Ctrl + O. In the **Open File** dialog, navigate to the **tsql-scripts** folder and select **UpdateSalary.sql**. Do not execute the query yet.
|
||||
1. With the **ContosoHR** database selected, type Ctrl + O. In the **Open File** dialog, navigate to the **tsql-scripts** folder and select ***ListAllEmployees.sql**. Do not execute the query.
|
||||
|
||||
1. *Optional* - If you've showed this demo before, reseed the database to ensure it contains the original employee data.
|
||||
1. In Object Explorer, find and select the **ContosoHR** database.
|
||||
1. With the **ContosoHR** database selected, click Ctrl + O. In the **Open File** dialog, navigate to the **setup** folder and select **PopulateDatabase.sql**.
|
||||
1. Execute the query.
|
||||
**Note:** for best demo results, wait 10 minutes after reseeding the database. This will ensure the **Employee Ledger Entries** and **Audit Events** tabs in the app (Auditor's browser) do not show reseeding queries.
|
||||
1. You can close the **PopulateDatabase.sql** tab.
|
||||
|
||||
### Demo steps
|
||||
|
||||
1. Show the app and the database.
|
||||
1. Show the Contoso HR web app in the HR user's browser. Click on the **Employees tab**. This application displays employee records, and allows HR staff members to manage employee records.
|
||||

|
||||
1. Switch to SSMS, select the **ListAllEmployees.sql** tab and execute the query, which shows the content of the **Employees** table. The web application uses this table as a data store.
|
||||
|
||||
1. Show how ledger helps investigate tampering by DBAs.
|
||||
1. Point to Jay’s record in the table (row #4). Let's assume Jay is both the DBA of the ContosoHR database as well as an employee of Contoso. Jay wants to maliciously increase his salary.
|
||||
1. Pretending you are Jay, switch to SSMS, select the **UpdateSalary.sql** and execute the query.
|
||||
1. In HR user’s (Rachel's) browser window, refresh the content of the **Contoso HR** tab. Point to Jay’s record to show the HR application shows Jay’s updated salary.
|
||||
1. Switch to SSMS. Select the **CreateDatabaseSchema.sql** tab and show the CREATE TABLE statement for the **Employees** table. (Once SSMS supports scripting ledger tables, generate and show the CREATE TABLE statement for the Employees table instead.) Unfortunately for Jay, the **Employees** table is an updatable ledger table, which means his change, along with his identity and the timestamp, have been persisted in a tamper-evident ledger data structures.
|
||||
1. Switch to auditor’s (Alice's) browser window and select the **Ledger Verifications** tab. Let's assume, a few weeks later, Alice, who is an auditor, performs a routine review of changes in the HR database. As her first step, Alice runs the ledger verification to make sure she can trust the data, she’s going to examine. The result should be "Success" like the screenshot below.
|
||||

|
||||
1. Select the **Employee Ledger** tab. In the **Employee Ledger** tab, Alice can browse the content of the ledger view for the **Employees** table. She notices a suspicious update operation performed by Jay, who will not be able to effectively deny he has updated his salary, because the data in the ledger table has been cryptographically verified as genuine and it clearly shows Jay updated his salary.
|
||||

|
||||
1. Switch to SSMS. Select the **CreateDatabaseSchema.sql** tab and show the stored procedures (that are used by the web application):
|
||||
1. **VerifyLedger** - Explain the sys.sp_verify_database_ledger_from_digest_storage procedure
|
||||
1. **GetEmployeeLedgerEntries** - Explain the view Employees_Ledger and table sys.database_ledger_transactions
|
||||
|
||||
1. Show how ledger helps investigate tampering by malicious application users.
|
||||
1. Switch to HR user’s (Rachel’s) browser to execute a different attack scenario. This time, you will perform an authorized salary change acting as a malicious HR staff member - Rachel. Click the **Employees** tab and find Frances' record in row 3 (you can pick another employee record if you want). Click the **Edit** link for Frances' record, enter a new salary value and click **Save**.
|
||||
1. Switch to Auditor’s browser window. Select and refresh the **Employee Ledger** tab. When Alice, the auditor, performs her next review of changes in the HR database, she again notices a suspicious salary update. However, this time the **User Name** column does not tell Alice who performed the update, because the column contains the managed identity of the web application, not the identity of the application user.
|
||||

|
||||
1. This time, the attacker, Rachel, is out of luck too, because the Contoso HR web application has been instrumented to write all SQL update queries, triggered by its users against the **Employees** table, to an append-only ledger table – **AuditEvents**. Switch to SSMS. Select the **CreateDatabaseSchema.sql** query tab and show the CREATE TABLE statement for the **AuditEvents** table. (Once SSMS supports scripting ledger tables, generate and show the CREATE TABLE statement for the **AuditEvents** table instead.)
|
||||
1. Go back to Auditor’s browser window. When Alice views the content of the **AuditEvents** table, she finds the corresponding Transact-SQL update statement, Rachel triggered. Since Transact-SQL statements are stored in a ledger table, and are therefore protected from tampering, Rachel will be unable to effectively deny she has made the change.
|
||||

|
||||
|
||||
### Key Takeaways
|
||||
|
||||
Ledger makes your data tamper-evident and cryptographically verifiable, which helps ensure non-repudiation, eliminating a need to run laborous manual audits and time-consuming investigations.
|
||||
|
||||
## Cleanup
|
||||
|
||||
To permanently remove all demo resources:
|
||||
|
||||
1. Run the **cleanup.ps1** PowerShell script in the setup folder.
|
||||
1. When prompted, enter your demo resource group name and your subscripton id, and sign in to Azure.
|
||||
1. Confirm you want to delete resource group.
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
@@ -83,6 +83,9 @@ resource Database_Resource 'Microsoft.Sql/servers/databases@2021-08-01-preview'
|
||||
name: 'ContosoHR'
|
||||
parent: Server_Name_resource
|
||||
location: location
|
||||
sku: {
|
||||
name:'GP_S_Gen5_1'
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
@@ -1,5 +1,5 @@
|
||||
Import-Module "Az" -MinimumVersion "5.6"
|
||||
Import-Module "SqlServer" -MinimumVersion "21.1.18235"
|
||||
Import-Module "Az" -MinimumVersion "7.1.0"
|
||||
Import-Module "SqlServer" -MinimumVersion "21.1.18256"
|
||||
|
||||
######################################################################
|
||||
# Prompt the user to enter the values of deployment parameters
|
||||