security

Practical Application Security for Developers - Part 3: TLS and Secure Communication

A practical guide to TLS 1.3, mTLS, ingress termination, Spring Boot HTTPS, and production hardening.

Reading Time: 5 min readAuthor: DeepTechHub
#security#appsec#tls#mtls#kubernetes
Practical Application Security for Developers - Part 3: TLS and Secure Communication

Practical Application Security for Developers - Part 3: TLS and Secure Communication

In Part 1 we covered symmetric cryptography, and in Part 2 we covered asymmetric cryptography and certificates. This part brings those building blocks together in the place most developers actually meet them: TLS.

You do not implement TLS from scratch. You choose where it terminates, which versions and ciphers are allowed, and how certificates are issued, renewed, and verified.


Why TLS Matters

Every request your application sends crosses infrastructure you do not fully control. TLS gives you three guarantees even on an untrusted network:

ThreatTLS protectionMechanism
EavesdroppingConfidentialitySymmetric encryption after the handshake
TamperingIntegrityAuthenticated record protection
ImpersonationAuthenticationCertificate-based server identity

TLS versus SSL

ProtocolStatus
SSL 2.0Broken
SSL 3.0Broken
TLS 1.0Deprecated
TLS 1.1Deprecated
TLS 1.2Acceptable minimum
TLS 1.3Preferred

Use TLS 1.2 or TLS 1.3. Disable everything older.


How a TLS 1.3 Handshake Works

A simplified TLS 1.3 handshake looks like this:

Why TLS 1.3 Is Better

  • Fewer legacy options to misconfigure
  • Faster handshakes than TLS 1.2
  • Better defaults for modern cipher suites
  • Cleaner path to strong forward secrecy

One-Way TLS versus mTLS

AspectStandard TLSMutual TLS
Server proves identityYesYes
Client proves identityNoYes
Common use caseBrowser to web serverService to service

mTLS becomes useful when internal services must prove who they are without relying on network location alone.


TLS Termination Choices

Where TLS ends matters operationally and architecturally.

StrategyTerminates atBest fit
Edge terminationLoad balancer or CDNSimple public websites
Ingress terminationKubernetes ingress controllerCommon Kubernetes deployments
Re-encryptionIngress and then backend HTTPSCompliance-heavy environments
End-to-end passthroughApplication itselfSensitive internal tooling
Service mesh mTLSSidecars or mesh proxiesZero-trust service environments

For many teams, a sensible default is:

  • Ingress termination for north-south traffic
  • mTLS via service mesh for east-west traffic

Kubernetes TLS with cert-manager and Ingress

A common production setup is cert-manager plus an ingress controller.

ClusterIssuer Example

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: devops@yourcompany.com
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
      - http01:
          ingress:
            class: nginx

Ingress Example

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-gateway
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - api.yourcompany.com
      secretName: api-yourcompany-tls
  rules:
    - host: api.yourcompany.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8080

cert-manager handles issuance and renewal. The ingress controller serves the certificate.


Spring Boot HTTPS

Sometimes the application itself must terminate TLS.

application.properties

server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=${SSL_KEYSTORE_PASSWORD}
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=myapp
server.ssl.enabled-protocols=TLSv1.3,TLSv1.2

Redirect HTTP to HTTPS

import org.apache.catalina.connector.Connector;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class HttpsRedirectConfig {
 
    @Bean
    public TomcatServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        factory.addAdditionalTomcatConnectors(httpConnector());
        return factory;
    }
 
    private Connector httpConnector() {
        Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
        connector.setScheme("http");
        connector.setPort(8080);
        connector.setSecure(false);
        connector.setRedirectPort(8443);
        return connector;
    }
}

Enable Client Certificates for mTLS

server.ssl.client-auth=need
server.ssl.trust-store=classpath:truststore.p12
server.ssl.trust-store-password=${SSL_TRUSTSTORE_PASSWORD}
server.ssl.trust-store-type=PKCS12

Local Development TLS

Running HTTPS locally helps you catch real cookie, CORS, and redirect behavior early.

openssl pkcs12 -export \
  -in server_cert.pem \
  -inkey server_key.pem \
  -CAfile ca/ca_cert.pem \
  -out src/main/resources/keystore.p12 \
  -name localhost \
  -passout pass:devonly

Then point Spring Boot at that keystore in a development profile.


Useful Debugging Commands

# Test TLS 1.3 negotiation
openssl s_client -connect api.yourcompany.com:443 -tls1_3
 
# Check remote certificate dates
echo | openssl s_client -connect api.yourcompany.com:443 2>/dev/null \
  | openssl x509 -noout -dates
 
# Show the certificate chain
openssl s_client -connect api.yourcompany.com:443 -showcerts

For JVM troubleshooting, -Djavax.net.debug=ssl:handshake is still one of the most useful flags you can enable.


Security Hardening Checklist

  • Enforce TLS 1.2 minimum, prefer TLS 1.3
  • Redirect HTTP to HTTPS
  • Use modern cipher suites
  • Automate certificate renewal
  • Monitor certificate expiry
  • Protect private keys and keystore passwords
  • Use HSTS where appropriate
  • Avoid disabling certificate verification in production

Common Mistakes to Avoid

  1. Accepting legacy TLS versions for convenience
  2. Leaving HTTP reachable without redirect
  3. Treating self-signed production certs as acceptable
  4. Forgetting certificate renewal automation
  5. Terminating TLS in too many layers without a reason
  6. Ignoring trust-store problems until production traffic fails

Part 3 Wrap-Up

At this point, the cryptographic pieces from the first three parts should fit together clearly:

  • Part 1 explained symmetric primitives
  • Part 2 explained asymmetric keys and certificates
  • Part 3 showed how TLS uses them in real systems

What's Next

In Part 4, we move up the stack from transport security to token-based identity: JOSE, JWS, JWE, JWK, JWKS, and what secure token validation actually requires.

Continue Learning

Explore more guides and resources to deepen your knowledge.