diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/script.sql b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/script.sql new file mode 100644 index 00000000..4c0f23e2 --- /dev/null +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/script.sql @@ -0,0 +1,77 @@ +-- TABLES -- +/****** Object: Table [dbo].[RealtimeSensorRecord] ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].RealtimeSensorRecord( + [RecordId] [uniqueidentifier] NOT NULL, + [TurbineId] [varchar](50) NULL, + [SensorType] [varchar](50) NULL, -- + [SensorId] [varchar](50) NULL, + [SensorValue] [real] NULL, + [Timestamp] [datetime] NULL + +PRIMARY KEY CLUSTERED +( + [RecordId] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] +GO + +-- STORE PROCEDURES -- +/* Store procedure that clean up the sensor records table */ +CREATE PROCEDURE [dbo].[TruncateRealtimeSensorRecords] +AS +DECLARE @SQL VARCHAR(2000) +SET @SQL='TRUNCATE TABLE dbo.RealtimeSensorRecord' +EXEC (@SQL); + + +-- Run Model Store Procedure +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +IF OBJECT_ID ( 'RunModel', 'P' ) IS NOT NULL + DROP PROCEDURE RunModel; +GO + +CREATE PROCEDURE [dbo].RunModel + @Result INT = 0 OUTPUT +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @model VARBINARY(max) = ( + SELECT DATA + FROM dbo.models + WHERE id = 1 + ) + + ;WITH predict_input AS ( + SELECT WindSpeedStdDev, TurbineSpeedStdDev, OverallWindDirection, TurbineWindDirection, + WindSpeedAverage, WindTempAverage, GearboxOilLevel, GearboxOilTemp, GeneratorActivePower, + GeneratorSpeed, GeneratorTemp, GeneratorTorque, GridFrequency, GridVoltage, + HydraulicOilPressure, NacelleAngle, PitchAngle, Vibration, TurbineSpeedAverage + FROM + ( + SELECT SensorValue, SensorType, timestamp + FROM RealtimeSensorRecord + GROUP BY SensorValue, SensorType, timestamp + ) d + PIVOT + ( + MAX(SensorValue) + FOR SensorType IN (WindSpeedStdDev, TurbineSpeedStdDev, OverallWindDirection, TurbineWindDirection, + WindSpeedAverage, WindTempAverage, GearboxOilLevel, GearboxOilTemp, GeneratorActivePower, + GeneratorSpeed, GeneratorTemp, GeneratorTorque, GridFrequency, GridVoltage, + HydraulicOilPressure, NacelleAngle, PitchAngle, Vibration, TurbineSpeedAverage) + ) piv + ) + + SELECT @Result = p.output_label + FROM PREDICT(MODEL = @model, DATA = predict_input) WITH (output_label bigint) AS p +END +GO diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/security.sql b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/security.sql new file mode 100644 index 00000000..1370d9b7 --- /dev/null +++ b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/security.sql @@ -0,0 +1,78 @@ +/* Create users using the logins created */ +CREATE USER OperatorUser WITHOUT LOGIN; +CREATE USER DataScientistUser WITHOUT LOGIN; +CREATE USER SecurityUser WITHOUT LOGIN; +CREATE USER TurbineUser WITHOUT LOGIN; + +/* Grand permissions to users */ +GRANT SELECT ON RealtimeSensorRecord TO OperatorUser; +GRANT SELECT ON RealtimeSensorRecord TO DataScientistUser; +GRANT SELECT ON RealtimeSensorRecord TO SecurityUser; +GRANT SELECT, INSERT ON RealtimeSensorRecord TO TurbineUser; + + +-- Mask the last four digits of the serial number (Sensor ID) of the sensor for the Data Scientist +ALTER TABLE RealtimeSensorRecord +ALTER COLUMN SensorId varchar(50) MASKED WITH (FUNCTION = 'partial(34,"XXXX",0)'); +DENY UNMASK TO DataScientistUser; +GO + +/** +* Operator: Can see all events +* Data Scientist: Can see everything BUT Hatch Sensor events +* Security: Can ONLY see HatchSensor events +*/ +ALTER TABLE RealtimeSensorRecord +ALTER COLUMN SensorType sysname +GO + +CREATE SCHEMA Security; +GO + +/** +* Operator: Can see all events +* Data Scientist: Can see everything BUT Hatch Sensor events +* Security: Can ONLY see HatchSensor events +*/ +CREATE FUNCTION Security.fn_securitypredicate(@SensorType AS sysname) +RETURNS TABLE +WITH SCHEMABINDING +AS +RETURN SELECT 1 AS fn_securitypredicate_result + WHERE + USER_NAME() = 'OperatorUser' OR USER_NAME() = 'dbo' OR + (USER_NAME() = 'DataScientistUser' AND @SensorType <> 'HatchSensor') OR + (USER_NAME() = 'SecurityUser' AND @SensorType = 'HatchSensor'); + +CREATE SECURITY POLICY SensorsDataFilter +ADD FILTER PREDICATE Security.fn_securitypredicate(SensorType) +ON dbo.RealtimeSensorRecord +WITH (STATE = ON); + +/* QUERIES FOR TESTING POLICIES */ + +-- Testing basic policy to deny delete +EXECUTE AS USER = 'OperatorUser'; +SELECT * FROM RealtimeSensorRecord; +DELETE FROM RealtimeSensorRecord WHERE SensorType = 'GeneratorTorque'; +REVERT; + +-- Testing the masking for data Data Scientist +EXECUTE AS USER = 'DataScientistUser'; +SELECT TOP 10 * FROM RealtimeSensorRecord; +REVERT; + +-- Testing Row-Level Security policy with Operator that can see all the events +EXECUTE AS USER = 'OperatorUser'; +SELECT * FROM RealtimeSensorRecord; +REVERT; + +-- Testing Row-Level Security policy with DataScientist that can see all the events but HatchSensor +EXECUTE AS USER = 'DataScientistUser'; +SELECT * FROM RealtimeSensorRecord; +REVERT; + +-- Testing Row-Level Security policy with Security that can see only the HatchSensor events +EXECUTE AS USER = 'SecurityUser'; +SELECT * FROM RealtimeSensorRecord; +REVERT; diff --git a/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/turbine-sensor-db-dacpac.zip b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/turbine-sensor-db-dacpac.zip new file mode 100644 index 00000000..eb2266ba Binary files /dev/null and b/samples/demos/azure-sql-edge-demos/Wind Turbine Demo/turbine-sensor-db-dacpac.zip differ