Your TLS Config is Probably Wrong: Five Audit Failures I Keep Finding
Picture a production system where developers proudly demonstrate their “security-first” cloud architecture. HTTP endpoints wide open, TLS 1.0 enabled for “backward compatibility,” self-signed certificates configured “temporarily” for the past eighteen months. When questioned about ISO 27017 compliance, they confidently point to Azure’s built-in security features—completely unaware that those features require actual configuration.
This isn’t an isolated incident. Encryption in transit remains one of the most frequently misconfigured security controls in cloud environments, despite being explicitly required by ISO/IEC 27017 Control CLD 10.1.1 (Cryptography in cloud). The standard is clear: data traveling across networks must be protected with strong cryptographic controls. Yet teams consistently underestimate the gap between Azure’s capabilities and properly configured security.
Let me show you what ISO 27017-compliant encryption in transit actually looks like with Azure Front Door and .NET APIs—and more importantly, the fatal configurations that audit teams flag every single time.
Understanding ISO/IEC 27017 Cryptographic Requirements
ISO/IEC 27017 extends ISO/IEC 27002 specifically for cloud services, with Control CLD 10.1.1 addressing cryptographic controls in cloud environments. This control maps to:
- ISO/IEC 27002 A.10.1.1 (Cryptographic policy) - Establishing organizational policy for cryptographic protection
- ISO/IEC 27002 A.13.2.1 (Information transfer policies) - Protecting information during transmission
- ISO/IEC 27017 CLD 10.1.1 (Cryptography in cloud) - Cloud-specific cryptographic implementation
The standard mandates:
- Strong encryption algorithms - Modern ciphers with proven security (AES-GCM, ChaCha20-Poly1305)
- Current TLS versions - TLS 1.2 minimum, with TLS 1.3 recommended
- Key management - Proper certificate lifecycle management and rotation
- End-to-end protection - Encryption for all network segments, including internal Azure traffic
- Monitoring and verification - Continuous validation of cryptographic configurations
These aren’t suggestions—they’re compliance requirements that auditors verify through configuration reviews and network traffic analysis.
The Fatal Example: What Audit Teams Flag Immediately
The following composite of real-world misconfigurations surfaces repeatedly during ISO 27017 audits. Each represents an actual compliance violation that forces remediation before certification.
Fatal Configuration 1: HTTP Endpoints Exposed
// ❌ FATAL: HTTP endpoint exposed to internet
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
// Binding to HTTP for "testing purposes"
options.ListenAnyIP(80);
options.ListenAnyIP(443, listenOptions =>
{
listenOptions.UseHttps();
});
});
var app = builder.Build();
app.MapControllers();
app.Run();
}
}
Why This Fails Audit:
- Violates ISO/IEC 27002 A.13.2.1 (no encryption for transmitted data)
- Violates ISO/IEC 27017 CLD 10.1.1 (missing cryptographic controls)
- Exposes API to Man-in-the-Middle (MITM) attacks
- Allows credential theft and data interception
- Failed PCI DSS requirement 4.1 if processing payment data
Real Impact: One team lost three months of certification work when auditors discovered a single HTTP health check endpoint exposed during penetration testing.
Fatal Configuration 2: Weak TLS Versions Enabled
// ❌ FATAL: Azure Front Door allowing TLS 1.0/1.1
resource frontDoor 'Microsoft.Cdn/profiles@2023-05-01' = {
name: 'fd-production-api'
location: 'global'
sku: {
name: 'Premium_AzureFrontDoor'
}
}
resource customDomain 'Microsoft.Cdn/profiles/customDomains@2023-05-01' = {
parent: frontDoor
name: 'api-example-com'
properties: {
hostName: 'api.example.com'
tlsSettings: {
// ❌ Allowing deprecated TLS versions
minimumTlsVersion: 'TLS10'
certificateType: 'ManagedCertificate'
}
}
}
Why This Fails Audit:
- TLS 1.0/1.1 deprecated by IETF RFC 8996 (March 2021)
- Vulnerable to POODLE, BEAST, CRIME attacks
- Non-compliant with PCI DSS 3.2.1 (deprecated June 2018)
- Violates ISO/IEC 27017 requirement for “current cryptographic standards”
- Failed NIST SP 800-52 Rev. 2 minimum requirements
Industry Reality: Major browsers removed TLS 1.0/1.1 support in 2020. Any “backward compatibility” argument is obsolete.
Fatal Configuration 3: Self-Signed Certificates in Production
// ❌ FATAL: Accepting self-signed certificates
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("BackendAPI", client =>
{
client.BaseAddress = new Uri("https://backend.internal.example.com");
})
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
// ❌ Disabling certificate validation
ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
});
}
}
Why This Fails Audit:
- Defeats entire purpose of TLS authentication
- Enables man-in-the-middle attacks within Azure network
- Violates ISO/IEC 27002 A.10.1.1 (cryptographic policy)
- No certificate expiration monitoring
- Impossible to revoke compromised certificates
Observed in Practice: Teams deploying microservices with self-signed certificates “temporarily” while waiting for proper certificate infrastructure—which never gets implemented.
Fatal Configuration 4: Missing Certificate Lifecycle Management
// ❌ FATAL: No certificate expiration monitoring
resource frontDoor 'Microsoft.Cdn/profiles@2023-05-01' = {
name: 'fd-production-api'
location: 'global'
sku: {
name: 'Premium_AzureFrontDoor'
}
}
resource customDomain 'Microsoft.Cdn/profiles/customDomains@2023-05-01' = {
parent: frontDoor
name: 'api-example-com'
properties: {
hostName: 'api.example.com'
tlsSettings: {
minimumTlsVersion: 'TLS12'
// ❌ Using custom certificate without monitoring
certificateType: 'CustomerCertificate'
secret: {
id: keyVaultCertificate.id
}
}
}
}
// ❌ No health check for certificate validity
// ❌ No alerting for expiration within 30 days
// ❌ No automated renewal process
Why This Fails Audit:
- No documented certificate lifecycle process
- Violates ISO/IEC 27001 A.12.1.3 (capacity management)
- Risk of production outages due to expired certificates
- No evidence of regular certificate review
Real Incident: A major SaaS provider experienced 6-hour outage when Front Door certificate expired overnight with no monitoring alerts configured.
Fatal Configuration 5: Weak Cipher Suites Enabled
// ❌ FATAL: Allowing weak cipher suites
resource securityPolicy 'Microsoft.Cdn/profiles/securityPolicies@2023-05-01' = {
parent: frontDoor
name: 'default-security-policy'
properties: {
parameters: {
type: 'WebApplicationFirewall'
wafPolicy: {
id: wafPolicy.id
}
}
}
}
// ❌ No cipher suite restriction configuration
// Defaults allow CBC-mode ciphers vulnerable to Lucky13
// Allows RSA key exchange instead of ECDHE (no forward secrecy)
Why This Fails Audit:
- CBC-mode ciphers vulnerable to padding oracle attacks
- Missing AEAD (Authenticated Encryption with Associated Data)
- No PFS (Perfect Forward Secrecy) enforcement
- Violates NIST SP 800-52 Rev. 2 cipher suite recommendations
- Non-compliant with ISO/IEC 27017 “strong encryption” requirement
Audit Finding: Penetration testers successfully negotiated 3DES_EDE_CBC cipher during external assessment.
The Correct Example: ISO 27017-Compliant Configuration
Here’s a production-ready Azure Front Door configuration that passes ISO 27017 audits consistently. This isn’t theoretical—it’s the exact pattern that works across certified environments.
Correct Configuration 1: Azure Front Door with Strict TLS
// ✅ CORRECT: Azure Front Door with ISO 27017-compliant TLS configuration
@description('Azure Front Door profile for production API')
resource frontDoor 'Microsoft.Cdn/profiles@2023-05-01' = {
name: 'fd-production-api-${uniqueString(resourceGroup().id)}'
location: 'global'
sku: {
name: 'Premium_AzureFrontDoor' // Required for WAF and advanced security
}
tags: {
Environment: 'Production'
ISO27017: 'CLD-10.1.1'
CostCenter: 'IT-Security'
}
}
@description('Custom domain with managed certificate and TLS 1.2 minimum')
resource customDomain 'Microsoft.Cdn/profiles/customDomains@2023-05-01' = {
parent: frontDoor
name: 'api-example-com'
properties: {
hostName: 'api.example.com'
tlsSettings: {
// ✅ TLS 1.2 minimum (1.3 when available)
minimumTlsVersion: 'TLS12'
// ✅ Managed certificate with automatic renewal
certificateType: 'ManagedCertificate'
}
}
}
@description('Origin group for backend App Service')
resource originGroup 'Microsoft.Cdn/profiles/originGroups@2023-05-01' = {
parent: frontDoor
name: 'backend-origin-group'
properties: {
loadBalancingSettings: {
sampleSize: 4
successfulSamplesRequired: 3
additionalLatencyInMilliseconds: 50
}
healthProbeSettings: {
// ✅ Health probe over HTTPS
probePath: '/health/ready'
probeRequestType: 'GET'
probeProtocol: 'Https'
probeIntervalInSeconds: 30
}
}
}
@description('Backend origin with HTTPS-only configuration')
resource origin 'Microsoft.Cdn/profiles/originGroups/origins@2023-05-01' = {
parent: originGroup
name: 'app-service-origin'
properties: {
hostName: appService.properties.defaultHostName
httpPort: 80
httpsPort: 443
// ✅ HTTPS-only enforcement
originHostHeader: appService.properties.defaultHostName
priority: 1
weight: 1000
enforceCertificateNameCheck: true // ✅ Validate certificate CN (Common Name) / SAN (Subject Alternative Name)
enabledState: 'Enabled'
}
}
@description('Route with HTTPS redirect and HSTS enforcement')
resource route 'Microsoft.Cdn/profiles/afdEndpoints/routes@2023-05-01' = {
parent: endpoint
name: 'default-route'
properties: {
customDomains: [
{
id: customDomain.id
}
]
originGroup: {
id: originGroup.id
}
// ✅ HTTPS redirect for all HTTP requests
httpsRedirect: 'Enabled'
supportedProtocols: [
'Https' // ✅ HTTPS-only, no HTTP
]
patternsToMatch: [
'/*'
]
forwardingProtocol: 'HttpsOnly' // ✅ Backend communication over HTTPS
linkToDefaultDomain: 'Disabled'
enabledState: 'Enabled'
}
}
@description('Security policy with WAF and HSTS headers')
resource securityPolicy 'Microsoft.Cdn/profiles/securityPolicies@2023-05-01' = {
parent: frontDoor
name: 'default-security-policy'
properties: {
parameters: {
type: 'WebApplicationFirewall'
wafPolicy: {
id: wafPolicy.id
}
associations: [
{
domains: [
{
id: customDomain.id
}
]
patternsToMatch: [
'/*'
]
}
]
}
}
}
@description('Rule set for HSTS header enforcement')
resource ruleSet 'Microsoft.Cdn/profiles/ruleSets@2023-05-01' = {
parent: frontDoor
name: 'SecurityHeaders'
}
@description('HSTS header rule (ISO 27017 compliance)')
resource hstsRule 'Microsoft.Cdn/profiles/ruleSets/rules@2023-05-01' = {
parent: ruleSet
name: 'EnforceHSTS'
properties: {
order: 1
actions: [
{
name: 'ModifyResponseHeader'
parameters: {
typeName: 'DeliveryRuleHeaderActionParameters'
headerAction: 'Append'
headerName: 'Strict-Transport-Security'
// ✅ HSTS: 1 year, include subdomains, preload
value: 'max-age=31536000; includeSubDomains; preload'
}
}
]
}
}
Why This Passes Audit:
- TLS 1.2 minimum enforced via
minimumTlsVersion - Managed certificates with automatic 90-day renewal
- HTTPS-only routing with
httpsRedirectenabled - End-to-end TLS via
forwardingProtocol: HttpsOnly - HSTS (HTTP Strict Transport Security) instructs browsers to use HTTPS exclusively
- Certificate name validation prevents MITM attacks
- Health probes over HTTPS ensure backend TLS validation
Correct Configuration 2: ASP.NET Core HTTPS Enforcement
// ✅ CORRECT: ASP.NET Core with comprehensive HTTPS enforcement
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// ✅ Configure Kestrel for HTTPS-only (production)
builder.WebHost.ConfigureKestrel(options =>
{
if (!builder.Environment.IsDevelopment())
{
// Production: HTTPS only on port 443
options.ListenAnyIP(443, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
// ✅ TLS 1.2 minimum
httpsOptions.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13;
});
});
}
});
// ✅ Configure HTTPS redirection
builder.Services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status308PermanentRedirect;
options.HttpsPort = 443;
});
// ✅ Configure HSTS
builder.Services.AddHsts(options =>
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(365);
});
builder.Services.AddControllers();
var app = builder.Build();
// ✅ HSTS middleware (production only)
if (!app.Environment.IsDevelopment())
{
app.UseHsts();
}
// ✅ HTTPS redirection middleware
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
Key Middleware Configuration:
- UseHsts() - Adds Strict-Transport-Security header (production only)
- UseHttpsRedirection() - Redirects HTTP to HTTPS with 308 status
- SslProtocols - Enforces TLS 1.2/1.3 at Kestrel level
Correct Configuration 3: Secure Backend Service Communication
// ✅ CORRECT: HttpClient with proper certificate validation
services.AddHttpClient("BackendAPI", client =>
{
client.BaseAddress = new Uri("https://backend.internal.example.com");
})
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
// ✅ Default: Validate all certificates
// ServerCertificateCustomValidationCallback NOT SET
// For private CA certificates, install CA cert to trusted store
// Do NOT disable validation
});
Certificate Validation Best Practices:
- Never disable
ServerCertificateCustomValidationCallbackin production - Use Azure Key Vault for private CA certificates
- Install CA certificates to the OS trusted certificate store
- Monitor certificate expiration via Application Insights custom metrics
Correct Configuration 4: Certificate Monitoring
Certificate expiration monitoring prevents the 3 AM outages nobody wants. The core pattern:
public class CertificateExpirationHealthCheck : IHealthCheck
{
private const int WarningThresholdDays = 30;
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context, CancellationToken cancellationToken = default)
{
var daysUntilExpiration = await GetCertificateExpirationDaysAsync(
"https://api.example.com", cancellationToken);
if (daysUntilExpiration < 0)
return HealthCheckResult.Unhealthy("Certificate expired");
if (daysUntilExpiration < WarningThresholdDays)
return HealthCheckResult.Degraded(
$"Certificate expires in {daysUntilExpiration} days");
return HealthCheckResult.Healthy("Certificate valid");
}
private async Task<int> GetCertificateExpirationDaysAsync(
string endpoint, CancellationToken cancellationToken)
{
X509Certificate2? certificate = null;
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) =>
{
certificate = new X509Certificate2(cert!);
return errors == SslPolicyErrors.None; // Still validate!
}
};
using var client = new HttpClient(handler);
await client.GetAsync(endpoint, cancellationToken);
return (certificate!.NotAfter - DateTime.UtcNow).Days;
}
}
Register with a 30-day warning threshold:
builder.Services.AddHealthChecks()
.AddCheck<CertificateExpirationHealthCheck>(
"certificate-expiration",
failureStatus: HealthStatus.Degraded,
tags: ["security", "certificates"]);
app.MapHealthChecks("/health/certificates");
For Application Insights integration, track certificate expiration as a custom metric using a BackgroundService that polls the health check hourly and reports CertificateExpirationDays per endpoint. Configure Azure Monitor alert rules to trigger when the metric drops below 30 days.
Key Components:
- Health check endpoint at
/health/certificatesfor monitoring systems - 30-day warning threshold before expiration
- Custom metrics for dashboard visualization and alerting
ISO 27017 Audit Evidence Requirements
When auditors assess your encryption in transit implementation, they verify:
1. Configuration Documentation
- Bicep/Terraform templates showing TLS 1.2 minimum
- Network diagrams demonstrating end-to-end encryption
- Certificate management procedures (issuance, renewal, revocation)
2. Operational Evidence
- Certificate expiration monitoring dashboards
- Health check logs showing TLS validation
- Incident response procedures for expired certificates
3. Technical Verification
- TLS configuration scans (SSLLabs, testssl.sh)
- Network packet captures showing encrypted traffic
- Cipher suite negotiation logs
Practical Tip: Maintain a compliance documentation folder in your repository with:
- Infrastructure-as-Code templates
- Architecture diagrams
- Runbook for certificate renewal
- Test results from TLS scanning tools
Measuring Compliance: Continuous Validation
ISO 27017 compliance isn’t a one-time configuration—it requires continuous monitoring:
# ✅ TLS configuration validation using testssl.sh
testssl.sh --severity MEDIUM --protocols --ciphers https://api.example.com
# Expected results:
# - TLS 1.2, TLS 1.3 supported
# - TLS 1.0, TLS 1.1 NOT offered
# - Only AEAD cipher suites (AES-GCM, ChaCha20-Poly1305)
# - Perfect Forward Secrecy (ECDHE key exchange)
Key Metrics to Monitor:
- Certificate expiration date (alert at 30 days)
- TLS version negotiation (reject TLS 1.0/1.1)
- Cipher suite usage (block weak ciphers)
- HTTP request count (should be zero if HTTPS redirect works)
- Health check failures related to TLS
Practical Recommendations for .NET Teams
Based on ISO 27017 implementations across multiple environments:
- Use Azure Managed Certificates - Eliminates 90% of certificate lifecycle issues
- Enforce TLS 1.2 Minimum - No exceptions, no “temporary” allowances
- Enable HSTS with Preload - Browser-level HTTPS enforcement
- Monitor Certificate Expiration - 30-day alert threshold minimum
- Test TLS Configuration - Automated SSLLabs scans in CI/CD pipeline
- Document Everything - Auditors want evidence of intentional security design
- End-to-End Encryption - TLS for all communication, including internal Azure traffic
The difference between passing and failing an ISO 27017 audit often comes down to these fundamentals being configured correctly from day one rather than bolted on during pre-audit remediation.
Conclusion: Security Configuration is Not Optional
ISO/IEC 27017 Control CLD 10.1.1 exists because encryption in transit is a non-negotiable security baseline for cloud environments. Azure Front Door provides the technical capabilities to meet these requirements—but capabilities mean nothing without proper configuration.
The fatal examples shown here aren’t theoretical edge cases. They’re real configurations that surface in production systems where teams assumed “cloud = secure” without verifying their implementations. Each represents an audit failure that delayed certification and required expensive remediation.
The correct examples demonstrate that ISO 27017 compliance is achievable with deliberate design:
- Azure Front Door enforcing TLS 1.2 minimum with managed certificates
- ASP.NET Core middleware implementing HTTPS redirection and HSTS
- Certificate lifecycle monitoring with 30-day expiration alerts
- Health checks validating TLS configuration continuously
This isn’t about checkbox compliance—it’s about building systems that protect customer data in transit with cryptographic controls that auditors, penetration testers, and security researchers validate consistently. When encryption in transit is configured correctly from the start, ISO 27017 audits become routine verification rather than stressful remediation exercises.
The tools and configurations are straightforward. The choice to implement them properly is yours.

Comments