From 05abaaad2bb8747911f6b91e3a0becf0457a08c9 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 24 Jul 2024 16:13:55 +1000 Subject: [PATCH 1/3] Setting a default TLS version for Azure SQL to 1.3 Updated tests and added tests to validate user-specified override Fixes #5042 --- .../AzureSqlExtensions.cs | 1 + .../Azure/AzureBicepResourceTests.cs | 190 ++++++++++++++++++ 2 files changed, 191 insertions(+) diff --git a/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs b/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs index 5f82b686e9..2799170fb4 100644 --- a/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs +++ b/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs @@ -28,6 +28,7 @@ internal static IResourceBuilder PublishAsAzureSqlDatab sqlServer.AssignProperty(x => x.Administrators.Sid, construct.PrincipalIdParameter); sqlServer.AssignProperty(x => x.Administrators.Login, construct.PrincipalNameParameter); sqlServer.AssignProperty(x => x.Administrators.TenantId, "subscription().tenantId"); + sqlServer.AssignProperty(x => x.MinimalTlsVersion, "'1.3'"); sqlServer.Properties.Tags["aspire-resource-name"] = construct.Resource.Name; diff --git a/tests/Aspire.Hosting.Tests/Azure/AzureBicepResourceTests.cs b/tests/Aspire.Hosting.Tests/Azure/AzureBicepResourceTests.cs index 43bdd94c14..32a849d21f 100644 --- a/tests/Aspire.Hosting.Tests/Azure/AzureBicepResourceTests.cs +++ b/tests/Aspire.Hosting.Tests/Azure/AzureBicepResourceTests.cs @@ -1175,6 +1175,108 @@ param principalType string } properties: { version: '12.0' + minimalTlsVersion: '1.3' + publicNetworkAccess: 'Enabled' + administrators: { + administratorType: 'ActiveDirectory' + principalType: principalType + login: principalName + sid: principalId + tenantId: subscription().tenantId + azureADOnlyAuthentication: true + } + } + } + + resource sqlFirewallRule_vcw7qNn72 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = { + parent: sqlServer_lF9QWGqAt + name: 'AllowAllAzureIps' + properties: { + startIpAddress: '0.0.0.0' + endIpAddress: '0.0.0.0' + } + } + + resource sqlFirewallRule_IgqbBC6Hr 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = { + parent: sqlServer_lF9QWGqAt + name: 'fw' + properties: { + startIpAddress: '0.0.0.0' + endIpAddress: '255.255.255.255' + } + } + + resource sqlDatabase_m3U42g9Y8 'Microsoft.Sql/servers/databases@2020-11-01-preview' = { + parent: sqlServer_lF9QWGqAt + name: 'dbName' + location: location + properties: { + } + } + + output sqlServerFqdn string = sqlServer_lF9QWGqAt.properties.fullyQualifiedDomainName + + """; + output.WriteLine(manifest.BicepText); + Assert.Equal(expectedBicep, manifest.BicepText); + } + + [Fact] + public async Task AsAzureSqlDatabaseViaRunModeOverrideProperties() + { + using var builder = TestDistributedApplicationBuilder.Create(); + + var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, sql, _) => + { + azureSqlBuilder.Resource.Outputs["sqlServerFqdn"] = "myserver"; + sql.AssignProperty(s => s.MinimalTlsVersion, "'1.2'"); + }); + sql.AddDatabase("db", "dbName"); + + var manifest = await ManifestUtils.GetManifestWithBicep(sql.Resource); + + Assert.Equal("Server=tcp:myserver,1433;Encrypt=True;Authentication=\"Active Directory Default\"", await sql.Resource.GetConnectionStringAsync(default)); + Assert.Equal("Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\"Active Directory Default\"", sql.Resource.ConnectionStringExpression.ValueExpression); + + var expectedManifest = """ + { + "type": "azure.bicep.v0", + "connectionString": "Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\u0022Active Directory Default\u0022", + "path": "sql.module.bicep", + "params": { + "principalId": "", + "principalName": "", + "principalType": "" + } + } + """; + Assert.Equal(expectedManifest, manifest.ManifestNode.ToString()); + + var expectedBicep = """ + targetScope = 'resourceGroup' + + @description('') + param location string = resourceGroup().location + + @description('') + param principalId string + + @description('') + param principalName string + + @description('') + param principalType string + + + resource sqlServer_lF9QWGqAt 'Microsoft.Sql/servers@2020-11-01-preview' = { + name: toLower(take('sql${uniqueString(resourceGroup().id)}', 24)) + location: location + tags: { + 'aspire-resource-name': 'sql' + } + properties: { + version: '12.0' + minimalTlsVersion: '1.2' publicNetworkAccess: 'Enabled' administrators: { administratorType: 'ActiveDirectory' @@ -1270,6 +1372,94 @@ param principalName string } properties: { version: '12.0' + minimalTlsVersion: '1.3' + publicNetworkAccess: 'Enabled' + administrators: { + administratorType: 'ActiveDirectory' + login: principalName + sid: principalId + tenantId: subscription().tenantId + azureADOnlyAuthentication: true + } + } + } + + resource sqlFirewallRule_vcw7qNn72 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = { + parent: sqlServer_lF9QWGqAt + name: 'AllowAllAzureIps' + properties: { + startIpAddress: '0.0.0.0' + endIpAddress: '0.0.0.0' + } + } + + resource sqlDatabase_m3U42g9Y8 'Microsoft.Sql/servers/databases@2020-11-01-preview' = { + parent: sqlServer_lF9QWGqAt + name: 'dbName' + location: location + properties: { + } + } + + output sqlServerFqdn string = sqlServer_lF9QWGqAt.properties.fullyQualifiedDomainName + + """; + output.WriteLine(manifest.BicepText); + Assert.Equal(expectedBicep, manifest.BicepText); + } + + [Fact] + public async Task AsAzureSqlDatabaseViaPublishModeOverrideProperties() + { + using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish); + + var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, server, _) => + { + azureSqlBuilder.Resource.Outputs["sqlServerFqdn"] = "myserver"; + server.AssignProperty(p => p.MinimalTlsVersion, "'1.2'"); + }); + sql.AddDatabase("db", "dbName"); + + var manifest = await ManifestUtils.GetManifestWithBicep(sql.Resource); + + Assert.Equal("Server=tcp:myserver,1433;Encrypt=True;Authentication=\"Active Directory Default\"", await sql.Resource.GetConnectionStringAsync(default)); + Assert.Equal("Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\"Active Directory Default\"", sql.Resource.ConnectionStringExpression.ValueExpression); + + var expectedManifest = """ + { + "type": "azure.bicep.v0", + "connectionString": "Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\u0022Active Directory Default\u0022", + "path": "sql.module.bicep", + "params": { + "principalId": "", + "principalName": "" + } + } + """; + Assert.Equal(expectedManifest, manifest.ManifestNode.ToString()); + + var expectedBicep = """ + targetScope = 'resourceGroup' + + @description('') + param location string = resourceGroup().location + + @description('') + param principalId string + + @description('') + param principalName string + + + resource sqlServer_lF9QWGqAt 'Microsoft.Sql/servers@2020-11-01-preview' = { + name: toLower(take('sql${uniqueString(resourceGroup().id)}', 24)) + location: location + tags: { + 'aspire-resource-name': 'sql' + } + properties: { + version: '12.0' + minimalTlsVersion: '1.2' publicNetworkAccess: 'Enabled' administrators: { administratorType: 'ActiveDirectory' From b67428b9016ab0c452939cbe8988b8db2e404f4d Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 1 Aug 2024 12:21:20 +1000 Subject: [PATCH 2/3] Simplifying the tests --- .../AzureBicepResourceTests.cs | 210 ++---------------- 1 file changed, 18 insertions(+), 192 deletions(-) diff --git a/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs index b372e64c1b..f8338775de 100644 --- a/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs +++ b/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs @@ -1121,115 +1121,21 @@ param principalType string Assert.Equal(expectedBicep, manifest.BicepText); } - [Fact] - public async Task AsAzureSqlDatabaseViaRunMode() + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task AsAzureSqlDatabaseViaRunMode(bool overrideDefaultTlsVersion) { using var builder = TestDistributedApplicationBuilder.Create(); - var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, _, _) => + var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, sql, _) => { azureSqlBuilder.Resource.Outputs["sqlServerFqdn"] = "myserver"; - }); - sql.AddDatabase("db", "dbName"); - - var manifest = await ManifestUtils.GetManifestWithBicep(sql.Resource); - - Assert.Equal("Server=tcp:myserver,1433;Encrypt=True;Authentication=\"Active Directory Default\"", await sql.Resource.GetConnectionStringAsync(default)); - Assert.Equal("Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\"Active Directory Default\"", sql.Resource.ConnectionStringExpression.ValueExpression); - var expectedManifest = """ + if (overrideDefaultTlsVersion) { - "type": "azure.bicep.v0", - "connectionString": "Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\u0022Active Directory Default\u0022", - "path": "sql.module.bicep", - "params": { - "principalId": "", - "principalName": "", - "principalType": "" - } - } - """; - Assert.Equal(expectedManifest, manifest.ManifestNode.ToString()); - - var expectedBicep = """ - targetScope = 'resourceGroup' - - @description('') - param location string = resourceGroup().location - - @description('') - param principalId string - - @description('') - param principalName string - - @description('') - param principalType string - - - resource sqlServer_lF9QWGqAt 'Microsoft.Sql/servers@2020-11-01-preview' = { - name: toLower(take('sql${uniqueString(resourceGroup().id)}', 24)) - location: location - tags: { - 'aspire-resource-name': 'sql' - } - properties: { - version: '12.0' - minimalTlsVersion: '1.3' - publicNetworkAccess: 'Enabled' - administrators: { - administratorType: 'ActiveDirectory' - principalType: principalType - login: principalName - sid: principalId - tenantId: subscription().tenantId - azureADOnlyAuthentication: true - } - } - } - - resource sqlFirewallRule_vcw7qNn72 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = { - parent: sqlServer_lF9QWGqAt - name: 'AllowAllAzureIps' - properties: { - startIpAddress: '0.0.0.0' - endIpAddress: '0.0.0.0' - } - } - - resource sqlFirewallRule_IgqbBC6Hr 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = { - parent: sqlServer_lF9QWGqAt - name: 'fw' - properties: { - startIpAddress: '0.0.0.0' - endIpAddress: '255.255.255.255' - } + sql.AssignProperty(s => s.MinimalTlsVersion, "'1.2'"); } - - resource sqlDatabase_m3U42g9Y8 'Microsoft.Sql/servers/databases@2020-11-01-preview' = { - parent: sqlServer_lF9QWGqAt - name: 'dbName' - location: location - properties: { - } - } - - output sqlServerFqdn string = sqlServer_lF9QWGqAt.properties.fullyQualifiedDomainName - - """; - output.WriteLine(manifest.BicepText); - Assert.Equal(expectedBicep, manifest.BicepText); - } - - [Fact] - public async Task AsAzureSqlDatabaseViaRunModeOverrideProperties() - { - using var builder = TestDistributedApplicationBuilder.Create(); - - var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, sql, _) => - { - azureSqlBuilder.Resource.Outputs["sqlServerFqdn"] = "myserver"; - sql.AssignProperty(s => s.MinimalTlsVersion, "'1.2'"); }); sql.AddDatabase("db", "dbName"); @@ -1252,7 +1158,7 @@ public async Task AsAzureSqlDatabaseViaRunModeOverrideProperties() """; Assert.Equal(expectedManifest, manifest.ManifestNode.ToString()); - var expectedBicep = """ + var expectedBicep = $$""" targetScope = 'resourceGroup' @description('') @@ -1276,7 +1182,7 @@ param principalType string } properties: { version: '12.0' - minimalTlsVersion: '1.2' + minimalTlsVersion: '{{(overrideDefaultTlsVersion ? "1.2" : "1.3")}}' publicNetworkAccess: 'Enabled' administrators: { administratorType: 'ActiveDirectory' @@ -1322,101 +1228,21 @@ param principalType string Assert.Equal(expectedBicep, manifest.BicepText); } - [Fact] - public async Task AsAzureSqlDatabaseViaPublishMode() + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task AsAzureSqlDatabaseViaPublishMode(bool overrideDefaultTlsVersion) { using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish); - var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, _, _) => + var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, sql, _) => { azureSqlBuilder.Resource.Outputs["sqlServerFqdn"] = "myserver"; - }); - sql.AddDatabase("db", "dbName"); - var manifest = await ManifestUtils.GetManifestWithBicep(sql.Resource); - - Assert.Equal("Server=tcp:myserver,1433;Encrypt=True;Authentication=\"Active Directory Default\"", await sql.Resource.GetConnectionStringAsync(default)); - Assert.Equal("Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\"Active Directory Default\"", sql.Resource.ConnectionStringExpression.ValueExpression); - - var expectedManifest = """ + if (overrideDefaultTlsVersion) { - "type": "azure.bicep.v0", - "connectionString": "Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\u0022Active Directory Default\u0022", - "path": "sql.module.bicep", - "params": { - "principalId": "", - "principalName": "" - } + sql.AssignProperty(s => s.MinimalTlsVersion, "'1.2'"); } - """; - Assert.Equal(expectedManifest, manifest.ManifestNode.ToString()); - - var expectedBicep = """ - targetScope = 'resourceGroup' - - @description('') - param location string = resourceGroup().location - - @description('') - param principalId string - - @description('') - param principalName string - - - resource sqlServer_lF9QWGqAt 'Microsoft.Sql/servers@2020-11-01-preview' = { - name: toLower(take('sql${uniqueString(resourceGroup().id)}', 24)) - location: location - tags: { - 'aspire-resource-name': 'sql' - } - properties: { - version: '12.0' - minimalTlsVersion: '1.3' - publicNetworkAccess: 'Enabled' - administrators: { - administratorType: 'ActiveDirectory' - login: principalName - sid: principalId - tenantId: subscription().tenantId - azureADOnlyAuthentication: true - } - } - } - - resource sqlFirewallRule_vcw7qNn72 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = { - parent: sqlServer_lF9QWGqAt - name: 'AllowAllAzureIps' - properties: { - startIpAddress: '0.0.0.0' - endIpAddress: '0.0.0.0' - } - } - - resource sqlDatabase_m3U42g9Y8 'Microsoft.Sql/servers/databases@2020-11-01-preview' = { - parent: sqlServer_lF9QWGqAt - name: 'dbName' - location: location - properties: { - } - } - - output sqlServerFqdn string = sqlServer_lF9QWGqAt.properties.fullyQualifiedDomainName - - """; - output.WriteLine(manifest.BicepText); - Assert.Equal(expectedBicep, manifest.BicepText); - } - - [Fact] - public async Task AsAzureSqlDatabaseViaPublishModeOverrideProperties() - { - using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish); - - var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, server, _) => - { - azureSqlBuilder.Resource.Outputs["sqlServerFqdn"] = "myserver"; - server.AssignProperty(p => p.MinimalTlsVersion, "'1.2'"); }); sql.AddDatabase("db", "dbName"); @@ -1438,7 +1264,7 @@ public async Task AsAzureSqlDatabaseViaPublishModeOverrideProperties() """; Assert.Equal(expectedManifest, manifest.ManifestNode.ToString()); - var expectedBicep = """ + var expectedBicep = $$""" targetScope = 'resourceGroup' @description('') @@ -1459,7 +1285,7 @@ param principalName string } properties: { version: '12.0' - minimalTlsVersion: '1.2' + minimalTlsVersion: '{{(overrideDefaultTlsVersion ? "1.2" : "1.3")}}' publicNetworkAccess: 'Enabled' administrators: { administratorType: 'ActiveDirectory' From 6d0c51697489e5e02c1c68677175b6cffc3e56a3 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Wed, 21 Aug 2024 19:08:31 -0500 Subject: [PATCH 3/3] Set the default TLS to 1.2 --- src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs | 2 +- .../Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs b/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs index 2799170fb4..9f999dec54 100644 --- a/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs +++ b/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs @@ -28,7 +28,7 @@ internal static IResourceBuilder PublishAsAzureSqlDatab sqlServer.AssignProperty(x => x.Administrators.Sid, construct.PrincipalIdParameter); sqlServer.AssignProperty(x => x.Administrators.Login, construct.PrincipalNameParameter); sqlServer.AssignProperty(x => x.Administrators.TenantId, "subscription().tenantId"); - sqlServer.AssignProperty(x => x.MinimalTlsVersion, "'1.3'"); + sqlServer.AssignProperty(x => x.MinimalTlsVersion, "'1.2'"); sqlServer.Properties.Tags["aspire-resource-name"] = construct.Resource.Name; diff --git a/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs index f8338775de..854af99be2 100644 --- a/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs +++ b/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs @@ -1134,7 +1134,7 @@ public async Task AsAzureSqlDatabaseViaRunMode(bool overrideDefaultTlsVersion) if (overrideDefaultTlsVersion) { - sql.AssignProperty(s => s.MinimalTlsVersion, "'1.2'"); + sql.AssignProperty(s => s.MinimalTlsVersion, "'1.3'"); } }); sql.AddDatabase("db", "dbName"); @@ -1182,7 +1182,7 @@ param principalType string } properties: { version: '12.0' - minimalTlsVersion: '{{(overrideDefaultTlsVersion ? "1.2" : "1.3")}}' + minimalTlsVersion: '{{(overrideDefaultTlsVersion ? "1.3" : "1.2")}}' publicNetworkAccess: 'Enabled' administrators: { administratorType: 'ActiveDirectory' @@ -1241,7 +1241,7 @@ public async Task AsAzureSqlDatabaseViaPublishMode(bool overrideDefaultTlsVersio if (overrideDefaultTlsVersion) { - sql.AssignProperty(s => s.MinimalTlsVersion, "'1.2'"); + sql.AssignProperty(s => s.MinimalTlsVersion, "'1.3'"); } }); sql.AddDatabase("db", "dbName"); @@ -1285,7 +1285,7 @@ param principalName string } properties: { version: '12.0' - minimalTlsVersion: '{{(overrideDefaultTlsVersion ? "1.2" : "1.3")}}' + minimalTlsVersion: '{{(overrideDefaultTlsVersion ? "1.3" : "1.2")}}' publicNetworkAccess: 'Enabled' administrators: { administratorType: 'ActiveDirectory'